Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenxpath.c
Go to the documentation of this file.
00001 /* 00002 * xpath.c: XML Path Language implementation 00003 * XPath is a language for addressing parts of an XML document, 00004 * designed to be used by both XSLT and XPointer 00005 *f 00006 * Reference: W3C Recommendation 16 November 1999 00007 * http://www.w3.org/TR/1999/REC-xpath-19991116 00008 * Public reference: 00009 * http://www.w3.org/TR/xpath 00010 * 00011 * See Copyright for the status of this software 00012 * 00013 * Author: daniel@veillard.com 00014 * 00015 */ 00016 00017 #define IN_LIBXML 00018 #include "libxml.h" 00019 00020 #include <string.h> 00021 00022 #ifdef HAVE_SYS_TYPES_H 00023 #include <sys/types.h> 00024 #endif 00025 #ifdef HAVE_MATH_H 00026 #include <math.h> 00027 #endif 00028 #ifdef HAVE_FLOAT_H 00029 #include <float.h> 00030 #endif 00031 #ifdef HAVE_CTYPE_H 00032 #include <ctype.h> 00033 #endif 00034 #ifdef HAVE_SIGNAL_H 00035 #include <signal.h> 00036 #endif 00037 00038 #include <libxml/xmlmemory.h> 00039 #include <libxml/tree.h> 00040 #include <libxml/valid.h> 00041 #include <libxml/xpath.h> 00042 #include <libxml/xpathInternals.h> 00043 #include <libxml/parserInternals.h> 00044 #include <libxml/hash.h> 00045 #ifdef LIBXML_XPTR_ENABLED 00046 #include <libxml/xpointer.h> 00047 #endif 00048 #ifdef LIBXML_DEBUG_ENABLED 00049 #include <libxml/debugXML.h> 00050 #endif 00051 #include <libxml/xmlerror.h> 00052 #include <libxml/threads.h> 00053 #include <libxml/globals.h> 00054 #ifdef LIBXML_PATTERN_ENABLED 00055 #include <libxml/pattern.h> 00056 #endif 00057 00058 #ifdef LIBXML_PATTERN_ENABLED 00059 #define XPATH_STREAMING 00060 #endif 00061 00062 #define TODO \ 00063 xmlGenericError(xmlGenericErrorContext, \ 00064 "Unimplemented block at %s:%d\n", \ 00065 __FILE__, __LINE__); 00066 00067 /* 00068 * XP_OPTIMIZED_NON_ELEM_COMPARISON: 00069 * If defined, this will use xmlXPathCmpNodesExt() instead of 00070 * xmlXPathCmpNodes(). The new function is optimized comparison of 00071 * non-element nodes; actually it will speed up comparison only if 00072 * xmlXPathOrderDocElems() was called in order to index the elements of 00073 * a tree in document order; Libxslt does such an indexing, thus it will 00074 * benefit from this optimization. 00075 */ 00076 #define XP_OPTIMIZED_NON_ELEM_COMPARISON 00077 00078 /* 00079 * XP_OPTIMIZED_FILTER_FIRST: 00080 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]" 00081 * in a way, that it stop evaluation at the first node. 00082 */ 00083 #define XP_OPTIMIZED_FILTER_FIRST 00084 00085 /* 00086 * XP_DEBUG_OBJ_USAGE: 00087 * Internal flag to enable tracking of how much XPath objects have been 00088 * created. 00089 */ 00090 /* #define XP_DEBUG_OBJ_USAGE */ 00091 00092 /* 00093 * TODO: 00094 * There are a few spots where some tests are done which depend upon ascii 00095 * data. These should be enhanced for full UTF8 support (see particularly 00096 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT) 00097 */ 00098 00099 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) 00100 00101 /************************************************************************ 00102 * * 00103 * Floating point stuff * 00104 * * 00105 ************************************************************************/ 00106 00107 #ifndef TRIO_REPLACE_STDIO 00108 #define TRIO_PUBLIC static 00109 #endif 00110 #include "trionan.c" 00111 00112 /* 00113 * The lack of portability of this section of the libc is annoying ! 00114 */ 00115 double xmlXPathNAN = 0; 00116 double xmlXPathPINF = 1; 00117 double xmlXPathNINF = -1; 00118 static double xmlXPathNZERO = 0; /* not exported from headers */ 00119 static int xmlXPathInitialized = 0; 00120 00126 void 00127 xmlXPathInit(void) { 00128 if (xmlXPathInitialized) return; 00129 00130 xmlXPathPINF = trio_pinf(); 00131 xmlXPathNINF = trio_ninf(); 00132 xmlXPathNAN = trio_nan(); 00133 xmlXPathNZERO = trio_nzero(); 00134 00135 xmlXPathInitialized = 1; 00136 } 00137 00148 int 00149 xmlXPathIsNaN(double val) { 00150 return(trio_isnan(val)); 00151 } 00152 00163 int 00164 xmlXPathIsInf(double val) { 00165 return(trio_isinf(val)); 00166 } 00167 00168 #endif /* SCHEMAS or XPATH */ 00169 #ifdef LIBXML_XPATH_ENABLED 00170 00180 static int 00181 xmlXPathGetSign(double val) { 00182 return(trio_signbit(val)); 00183 } 00184 00185 00186 /* 00187 * TODO: when compatibility allows remove all "fake node libxslt" strings 00188 * the test should just be name[0] = ' ' 00189 */ 00190 #ifdef DEBUG_XPATH_EXPRESSION 00191 #define DEBUG_STEP 00192 #define DEBUG_EXPR 00193 #define DEBUG_EVAL_COUNTS 00194 #endif 00195 00196 static xmlNs xmlXPathXMLNamespaceStruct = { 00197 NULL, 00198 XML_NAMESPACE_DECL, 00199 XML_XML_NAMESPACE, 00200 BAD_CAST "xml", 00201 NULL, 00202 NULL 00203 }; 00204 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct; 00205 #ifndef LIBXML_THREAD_ENABLED 00206 /* 00207 * Optimizer is disabled only when threaded apps are detected while 00208 * the library ain't compiled for thread safety. 00209 */ 00210 static int xmlXPathDisableOptimizer = 0; 00211 #endif 00212 00213 /************************************************************************ 00214 * * 00215 * Error handling routines * 00216 * * 00217 ************************************************************************/ 00218 00225 #define XP_ERRORNULL(X) \ 00226 { xmlXPathErr(ctxt, X); return(NULL); } 00227 00228 /* 00229 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError 00230 */ 00231 static const char *xmlXPathErrorMessages[] = { 00232 "Ok\n", 00233 "Number encoding\n", 00234 "Unfinished literal\n", 00235 "Start of literal\n", 00236 "Expected $ for variable reference\n", 00237 "Undefined variable\n", 00238 "Invalid predicate\n", 00239 "Invalid expression\n", 00240 "Missing closing curly brace\n", 00241 "Unregistered function\n", 00242 "Invalid operand\n", 00243 "Invalid type\n", 00244 "Invalid number of arguments\n", 00245 "Invalid context size\n", 00246 "Invalid context position\n", 00247 "Memory allocation error\n", 00248 "Syntax error\n", 00249 "Resource error\n", 00250 "Sub resource error\n", 00251 "Undefined namespace prefix\n", 00252 "Encoding error\n", 00253 "Char out of XML range\n", 00254 "Invalid or incomplete context\n", 00255 "?? Unknown error ??\n" /* Must be last in the list! */ 00256 }; 00257 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \ 00258 sizeof(xmlXPathErrorMessages[0])) - 1) 00259 00266 static void 00267 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra) 00268 { 00269 if (ctxt != NULL) { 00270 if (extra) { 00271 xmlChar buf[200]; 00272 00273 xmlStrPrintf(buf, 200, 00274 BAD_CAST "Memory allocation failed : %s\n", 00275 extra); 00276 ctxt->lastError.message = (char *) xmlStrdup(buf); 00277 } else { 00278 ctxt->lastError.message = (char *) 00279 xmlStrdup(BAD_CAST "Memory allocation failed\n"); 00280 } 00281 ctxt->lastError.domain = XML_FROM_XPATH; 00282 ctxt->lastError.code = XML_ERR_NO_MEMORY; 00283 if (ctxt->error != NULL) 00284 ctxt->error(ctxt->userData, &ctxt->lastError); 00285 } else { 00286 if (extra) 00287 __xmlRaiseError(NULL, NULL, NULL, 00288 NULL, NULL, XML_FROM_XPATH, 00289 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, 00290 extra, NULL, NULL, 0, 0, 00291 "Memory allocation failed : %s\n", extra); 00292 else 00293 __xmlRaiseError(NULL, NULL, NULL, 00294 NULL, NULL, XML_FROM_XPATH, 00295 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, 00296 NULL, NULL, NULL, 0, 0, 00297 "Memory allocation failed\n"); 00298 } 00299 } 00300 00308 static void 00309 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra) 00310 { 00311 if (ctxt == NULL) 00312 xmlXPathErrMemory(NULL, extra); 00313 else { 00314 ctxt->error = XPATH_MEMORY_ERROR; 00315 xmlXPathErrMemory(ctxt->context, extra); 00316 } 00317 } 00318 00326 void 00327 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error) 00328 { 00329 if ((error < 0) || (error > MAXERRNO)) 00330 error = MAXERRNO; 00331 if (ctxt == NULL) { 00332 __xmlRaiseError(NULL, NULL, NULL, 00333 NULL, NULL, XML_FROM_XPATH, 00334 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, 00335 XML_ERR_ERROR, NULL, 0, 00336 NULL, NULL, NULL, 0, 0, 00337 "%s", xmlXPathErrorMessages[error]); 00338 return; 00339 } 00340 ctxt->error = error; 00341 if (ctxt->context == NULL) { 00342 __xmlRaiseError(NULL, NULL, NULL, 00343 NULL, NULL, XML_FROM_XPATH, 00344 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, 00345 XML_ERR_ERROR, NULL, 0, 00346 (const char *) ctxt->base, NULL, NULL, 00347 ctxt->cur - ctxt->base, 0, 00348 "%s", xmlXPathErrorMessages[error]); 00349 return; 00350 } 00351 00352 /* cleanup current last error */ 00353 xmlResetError(&ctxt->context->lastError); 00354 00355 ctxt->context->lastError.domain = XML_FROM_XPATH; 00356 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK - 00357 XPATH_EXPRESSION_OK; 00358 ctxt->context->lastError.level = XML_ERR_ERROR; 00359 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base); 00360 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base; 00361 ctxt->context->lastError.node = ctxt->context->debugNode; 00362 if (ctxt->context->error != NULL) { 00363 ctxt->context->error(ctxt->context->userData, 00364 &ctxt->context->lastError); 00365 } else { 00366 __xmlRaiseError(NULL, NULL, NULL, 00367 NULL, ctxt->context->debugNode, XML_FROM_XPATH, 00368 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, 00369 XML_ERR_ERROR, NULL, 0, 00370 (const char *) ctxt->base, NULL, NULL, 00371 ctxt->cur - ctxt->base, 0, 00372 "%s", xmlXPathErrorMessages[error]); 00373 } 00374 00375 } 00376 00386 void 00387 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED, 00388 int line ATTRIBUTE_UNUSED, int no) { 00389 xmlXPathErr(ctxt, no); 00390 } 00391 00392 /************************************************************************ 00393 * * 00394 * Utilities * 00395 * * 00396 ************************************************************************/ 00397 00403 typedef struct _xmlPointerList xmlPointerList; 00404 typedef xmlPointerList *xmlPointerListPtr; 00405 struct _xmlPointerList { 00406 void **items; 00407 int number; 00408 int size; 00409 }; 00410 /* 00411 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt 00412 * and here, we should make the functions public. 00413 */ 00414 static int 00415 xmlPointerListAddSize(xmlPointerListPtr list, 00416 void *item, 00417 int initialSize) 00418 { 00419 if (list->items == NULL) { 00420 if (initialSize <= 0) 00421 initialSize = 1; 00422 list->items = (void **) xmlMalloc( 00423 initialSize * sizeof(void *)); 00424 if (list->items == NULL) { 00425 xmlXPathErrMemory(NULL, 00426 "xmlPointerListCreate: allocating item\n"); 00427 return(-1); 00428 } 00429 list->number = 0; 00430 list->size = initialSize; 00431 } else if (list->size <= list->number) { 00432 list->size *= 2; 00433 list->items = (void **) xmlRealloc(list->items, 00434 list->size * sizeof(void *)); 00435 if (list->items == NULL) { 00436 xmlXPathErrMemory(NULL, 00437 "xmlPointerListCreate: re-allocating item\n"); 00438 list->size = 0; 00439 return(-1); 00440 } 00441 } 00442 list->items[list->number++] = item; 00443 return(0); 00444 } 00445 00453 static xmlPointerListPtr 00454 xmlPointerListCreate(int initialSize) 00455 { 00456 xmlPointerListPtr ret; 00457 00458 ret = xmlMalloc(sizeof(xmlPointerList)); 00459 if (ret == NULL) { 00460 xmlXPathErrMemory(NULL, 00461 "xmlPointerListCreate: allocating item\n"); 00462 return (NULL); 00463 } 00464 memset(ret, 0, sizeof(xmlPointerList)); 00465 if (initialSize > 0) { 00466 xmlPointerListAddSize(ret, NULL, initialSize); 00467 ret->number = 0; 00468 } 00469 return (ret); 00470 } 00471 00478 static void 00479 xmlPointerListFree(xmlPointerListPtr list) 00480 { 00481 if (list == NULL) 00482 return; 00483 if (list->items != NULL) 00484 xmlFree(list->items); 00485 xmlFree(list); 00486 } 00487 00488 /************************************************************************ 00489 * * 00490 * Parser Types * 00491 * * 00492 ************************************************************************/ 00493 00494 /* 00495 * Types are private: 00496 */ 00497 00498 typedef enum { 00499 XPATH_OP_END=0, 00500 XPATH_OP_AND, 00501 XPATH_OP_OR, 00502 XPATH_OP_EQUAL, 00503 XPATH_OP_CMP, 00504 XPATH_OP_PLUS, 00505 XPATH_OP_MULT, 00506 XPATH_OP_UNION, 00507 XPATH_OP_ROOT, 00508 XPATH_OP_NODE, 00509 XPATH_OP_RESET, /* 10 */ 00510 XPATH_OP_COLLECT, 00511 XPATH_OP_VALUE, /* 12 */ 00512 XPATH_OP_VARIABLE, 00513 XPATH_OP_FUNCTION, 00514 XPATH_OP_ARG, 00515 XPATH_OP_PREDICATE, 00516 XPATH_OP_FILTER, /* 17 */ 00517 XPATH_OP_SORT /* 18 */ 00518 #ifdef LIBXML_XPTR_ENABLED 00519 ,XPATH_OP_RANGETO 00520 #endif 00521 } xmlXPathOp; 00522 00523 typedef enum { 00524 AXIS_ANCESTOR = 1, 00525 AXIS_ANCESTOR_OR_SELF, 00526 AXIS_ATTRIBUTE, 00527 AXIS_CHILD, 00528 AXIS_DESCENDANT, 00529 AXIS_DESCENDANT_OR_SELF, 00530 AXIS_FOLLOWING, 00531 AXIS_FOLLOWING_SIBLING, 00532 AXIS_NAMESPACE, 00533 AXIS_PARENT, 00534 AXIS_PRECEDING, 00535 AXIS_PRECEDING_SIBLING, 00536 AXIS_SELF 00537 } xmlXPathAxisVal; 00538 00539 typedef enum { 00540 NODE_TEST_NONE = 0, 00541 NODE_TEST_TYPE = 1, 00542 NODE_TEST_PI = 2, 00543 NODE_TEST_ALL = 3, 00544 NODE_TEST_NS = 4, 00545 NODE_TEST_NAME = 5 00546 } xmlXPathTestVal; 00547 00548 typedef enum { 00549 NODE_TYPE_NODE = 0, 00550 NODE_TYPE_COMMENT = XML_COMMENT_NODE, 00551 NODE_TYPE_TEXT = XML_TEXT_NODE, 00552 NODE_TYPE_PI = XML_PI_NODE 00553 } xmlXPathTypeVal; 00554 00555 #define XP_REWRITE_DOS_CHILD_ELEM 1 00556 00557 typedef struct _xmlXPathStepOp xmlXPathStepOp; 00558 typedef xmlXPathStepOp *xmlXPathStepOpPtr; 00559 struct _xmlXPathStepOp { 00560 xmlXPathOp op; /* The identifier of the operation */ 00561 int ch1; /* First child */ 00562 int ch2; /* Second child */ 00563 int value; 00564 int value2; 00565 int value3; 00566 void *value4; 00567 void *value5; 00568 void *cache; 00569 void *cacheURI; 00570 int rewriteType; 00571 }; 00572 00573 struct _xmlXPathCompExpr { 00574 int nbStep; /* Number of steps in this expression */ 00575 int maxStep; /* Maximum number of steps allocated */ 00576 xmlXPathStepOp *steps; /* ops for computation of this expression */ 00577 int last; /* index of last step in expression */ 00578 xmlChar *expr; /* the expression being computed */ 00579 xmlDictPtr dict; /* the dictionnary to use if any */ 00580 #ifdef DEBUG_EVAL_COUNTS 00581 int nb; 00582 xmlChar *string; 00583 #endif 00584 #ifdef XPATH_STREAMING 00585 xmlPatternPtr stream; 00586 #endif 00587 }; 00588 00589 /************************************************************************ 00590 * * 00591 * Forward declarations * 00592 * * 00593 ************************************************************************/ 00594 static void 00595 xmlXPathFreeValueTree(xmlNodeSetPtr obj); 00596 static void 00597 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj); 00598 static int 00599 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt, 00600 xmlXPathStepOpPtr op, xmlNodePtr *first); 00601 static int 00602 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt, 00603 xmlXPathStepOpPtr op, 00604 int isPredicate); 00605 00606 /************************************************************************ 00607 * * 00608 * Parser Type functions * 00609 * * 00610 ************************************************************************/ 00611 00619 static xmlXPathCompExprPtr 00620 xmlXPathNewCompExpr(void) { 00621 xmlXPathCompExprPtr cur; 00622 00623 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr)); 00624 if (cur == NULL) { 00625 xmlXPathErrMemory(NULL, "allocating component\n"); 00626 return(NULL); 00627 } 00628 memset(cur, 0, sizeof(xmlXPathCompExpr)); 00629 cur->maxStep = 10; 00630 cur->nbStep = 0; 00631 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep * 00632 sizeof(xmlXPathStepOp)); 00633 if (cur->steps == NULL) { 00634 xmlXPathErrMemory(NULL, "allocating steps\n"); 00635 xmlFree(cur); 00636 return(NULL); 00637 } 00638 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp)); 00639 cur->last = -1; 00640 #ifdef DEBUG_EVAL_COUNTS 00641 cur->nb = 0; 00642 #endif 00643 return(cur); 00644 } 00645 00652 void 00653 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp) 00654 { 00655 xmlXPathStepOpPtr op; 00656 int i; 00657 00658 if (comp == NULL) 00659 return; 00660 if (comp->dict == NULL) { 00661 for (i = 0; i < comp->nbStep; i++) { 00662 op = &comp->steps[i]; 00663 if (op->value4 != NULL) { 00664 if (op->op == XPATH_OP_VALUE) 00665 xmlXPathFreeObject(op->value4); 00666 else 00667 xmlFree(op->value4); 00668 } 00669 if (op->value5 != NULL) 00670 xmlFree(op->value5); 00671 } 00672 } else { 00673 for (i = 0; i < comp->nbStep; i++) { 00674 op = &comp->steps[i]; 00675 if (op->value4 != NULL) { 00676 if (op->op == XPATH_OP_VALUE) 00677 xmlXPathFreeObject(op->value4); 00678 } 00679 } 00680 xmlDictFree(comp->dict); 00681 } 00682 if (comp->steps != NULL) { 00683 xmlFree(comp->steps); 00684 } 00685 #ifdef DEBUG_EVAL_COUNTS 00686 if (comp->string != NULL) { 00687 xmlFree(comp->string); 00688 } 00689 #endif 00690 #ifdef XPATH_STREAMING 00691 if (comp->stream != NULL) { 00692 xmlFreePatternList(comp->stream); 00693 } 00694 #endif 00695 if (comp->expr != NULL) { 00696 xmlFree(comp->expr); 00697 } 00698 00699 xmlFree(comp); 00700 } 00701 00718 static int 00719 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2, 00720 xmlXPathOp op, int value, 00721 int value2, int value3, void *value4, void *value5) { 00722 if (comp->nbStep >= comp->maxStep) { 00723 xmlXPathStepOp *real; 00724 00725 comp->maxStep *= 2; 00726 real = (xmlXPathStepOp *) xmlRealloc(comp->steps, 00727 comp->maxStep * sizeof(xmlXPathStepOp)); 00728 if (real == NULL) { 00729 comp->maxStep /= 2; 00730 xmlXPathErrMemory(NULL, "adding step\n"); 00731 return(-1); 00732 } 00733 comp->steps = real; 00734 } 00735 comp->last = comp->nbStep; 00736 comp->steps[comp->nbStep].rewriteType = 0; 00737 comp->steps[comp->nbStep].ch1 = ch1; 00738 comp->steps[comp->nbStep].ch2 = ch2; 00739 comp->steps[comp->nbStep].op = op; 00740 comp->steps[comp->nbStep].value = value; 00741 comp->steps[comp->nbStep].value2 = value2; 00742 comp->steps[comp->nbStep].value3 = value3; 00743 if ((comp->dict != NULL) && 00744 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) || 00745 (op == XPATH_OP_COLLECT))) { 00746 if (value4 != NULL) { 00747 comp->steps[comp->nbStep].value4 = (xmlChar *) 00748 (void *)xmlDictLookup(comp->dict, value4, -1); 00749 xmlFree(value4); 00750 } else 00751 comp->steps[comp->nbStep].value4 = NULL; 00752 if (value5 != NULL) { 00753 comp->steps[comp->nbStep].value5 = (xmlChar *) 00754 (void *)xmlDictLookup(comp->dict, value5, -1); 00755 xmlFree(value5); 00756 } else 00757 comp->steps[comp->nbStep].value5 = NULL; 00758 } else { 00759 comp->steps[comp->nbStep].value4 = value4; 00760 comp->steps[comp->nbStep].value5 = value5; 00761 } 00762 comp->steps[comp->nbStep].cache = NULL; 00763 return(comp->nbStep++); 00764 } 00765 00773 static void 00774 xmlXPathCompSwap(xmlXPathStepOpPtr op) { 00775 int tmp; 00776 00777 #ifndef LIBXML_THREAD_ENABLED 00778 /* 00779 * Since this manipulates possibly shared variables, this is 00780 * disabled if one detects that the library is used in a multithreaded 00781 * application 00782 */ 00783 if (xmlXPathDisableOptimizer) 00784 return; 00785 #endif 00786 00787 tmp = op->ch1; 00788 op->ch1 = op->ch2; 00789 op->ch2 = tmp; 00790 } 00791 00792 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \ 00793 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \ 00794 (op), (val), (val2), (val3), (val4), (val5)) 00795 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \ 00796 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \ 00797 (op), (val), (val2), (val3), (val4), (val5)) 00798 00799 #define PUSH_LEAVE_EXPR(op, val, val2) \ 00800 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL) 00801 00802 #define PUSH_UNARY_EXPR(op, ch, val, val2) \ 00803 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL) 00804 00805 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \ 00806 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \ 00807 (val), (val2), 0 ,NULL ,NULL) 00808 00809 /************************************************************************ 00810 * * 00811 * XPath object cache structures * 00812 * * 00813 ************************************************************************/ 00814 00815 /* #define XP_DEFAULT_CACHE_ON */ 00816 00817 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL)) 00818 00819 typedef struct _xmlXPathContextCache xmlXPathContextCache; 00820 typedef xmlXPathContextCache *xmlXPathContextCachePtr; 00821 struct _xmlXPathContextCache { 00822 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */ 00823 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */ 00824 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */ 00825 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */ 00826 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */ 00827 int maxNodeset; 00828 int maxString; 00829 int maxBoolean; 00830 int maxNumber; 00831 int maxMisc; 00832 #ifdef XP_DEBUG_OBJ_USAGE 00833 int dbgCachedAll; 00834 int dbgCachedNodeset; 00835 int dbgCachedString; 00836 int dbgCachedBool; 00837 int dbgCachedNumber; 00838 int dbgCachedPoint; 00839 int dbgCachedRange; 00840 int dbgCachedLocset; 00841 int dbgCachedUsers; 00842 int dbgCachedXSLTTree; 00843 int dbgCachedUndefined; 00844 00845 00846 int dbgReusedAll; 00847 int dbgReusedNodeset; 00848 int dbgReusedString; 00849 int dbgReusedBool; 00850 int dbgReusedNumber; 00851 int dbgReusedPoint; 00852 int dbgReusedRange; 00853 int dbgReusedLocset; 00854 int dbgReusedUsers; 00855 int dbgReusedXSLTTree; 00856 int dbgReusedUndefined; 00857 00858 #endif 00859 }; 00860 00861 /************************************************************************ 00862 * * 00863 * Debugging related functions * 00864 * * 00865 ************************************************************************/ 00866 00867 #define STRANGE \ 00868 xmlGenericError(xmlGenericErrorContext, \ 00869 "Internal error at %s:%d\n", \ 00870 __FILE__, __LINE__); 00871 00872 #ifdef LIBXML_DEBUG_ENABLED 00873 static void 00874 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) { 00875 int i; 00876 char shift[100]; 00877 00878 for (i = 0;((i < depth) && (i < 25));i++) 00879 shift[2 * i] = shift[2 * i + 1] = ' '; 00880 shift[2 * i] = shift[2 * i + 1] = 0; 00881 if (cur == NULL) { 00882 fprintf(output, "%s", shift); 00883 fprintf(output, "Node is NULL !\n"); 00884 return; 00885 00886 } 00887 00888 if ((cur->type == XML_DOCUMENT_NODE) || 00889 (cur->type == XML_HTML_DOCUMENT_NODE)) { 00890 fprintf(output, "%s", shift); 00891 fprintf(output, " /\n"); 00892 } else if (cur->type == XML_ATTRIBUTE_NODE) 00893 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth); 00894 else 00895 xmlDebugDumpOneNode(output, cur, depth); 00896 } 00897 static void 00898 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) { 00899 xmlNodePtr tmp; 00900 int i; 00901 char shift[100]; 00902 00903 for (i = 0;((i < depth) && (i < 25));i++) 00904 shift[2 * i] = shift[2 * i + 1] = ' '; 00905 shift[2 * i] = shift[2 * i + 1] = 0; 00906 if (cur == NULL) { 00907 fprintf(output, "%s", shift); 00908 fprintf(output, "Node is NULL !\n"); 00909 return; 00910 00911 } 00912 00913 while (cur != NULL) { 00914 tmp = cur; 00915 cur = cur->next; 00916 xmlDebugDumpOneNode(output, tmp, depth); 00917 } 00918 } 00919 00920 static void 00921 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) { 00922 int i; 00923 char shift[100]; 00924 00925 for (i = 0;((i < depth) && (i < 25));i++) 00926 shift[2 * i] = shift[2 * i + 1] = ' '; 00927 shift[2 * i] = shift[2 * i + 1] = 0; 00928 00929 if (cur == NULL) { 00930 fprintf(output, "%s", shift); 00931 fprintf(output, "NodeSet is NULL !\n"); 00932 return; 00933 00934 } 00935 00936 if (cur != NULL) { 00937 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr); 00938 for (i = 0;i < cur->nodeNr;i++) { 00939 fprintf(output, "%s", shift); 00940 fprintf(output, "%d", i + 1); 00941 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1); 00942 } 00943 } 00944 } 00945 00946 static void 00947 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) { 00948 int i; 00949 char shift[100]; 00950 00951 for (i = 0;((i < depth) && (i < 25));i++) 00952 shift[2 * i] = shift[2 * i + 1] = ' '; 00953 shift[2 * i] = shift[2 * i + 1] = 0; 00954 00955 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) { 00956 fprintf(output, "%s", shift); 00957 fprintf(output, "Value Tree is NULL !\n"); 00958 return; 00959 00960 } 00961 00962 fprintf(output, "%s", shift); 00963 fprintf(output, "%d", i + 1); 00964 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1); 00965 } 00966 #if defined(LIBXML_XPTR_ENABLED) 00967 static void 00968 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) { 00969 int i; 00970 char shift[100]; 00971 00972 for (i = 0;((i < depth) && (i < 25));i++) 00973 shift[2 * i] = shift[2 * i + 1] = ' '; 00974 shift[2 * i] = shift[2 * i + 1] = 0; 00975 00976 if (cur == NULL) { 00977 fprintf(output, "%s", shift); 00978 fprintf(output, "LocationSet is NULL !\n"); 00979 return; 00980 00981 } 00982 00983 for (i = 0;i < cur->locNr;i++) { 00984 fprintf(output, "%s", shift); 00985 fprintf(output, "%d : ", i + 1); 00986 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1); 00987 } 00988 } 00989 #endif /* LIBXML_XPTR_ENABLED */ 00990 00999 void 01000 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) { 01001 int i; 01002 char shift[100]; 01003 01004 if (output == NULL) return; 01005 01006 for (i = 0;((i < depth) && (i < 25));i++) 01007 shift[2 * i] = shift[2 * i + 1] = ' '; 01008 shift[2 * i] = shift[2 * i + 1] = 0; 01009 01010 01011 fprintf(output, "%s", shift); 01012 01013 if (cur == NULL) { 01014 fprintf(output, "Object is empty (NULL)\n"); 01015 return; 01016 } 01017 switch(cur->type) { 01018 case XPATH_UNDEFINED: 01019 fprintf(output, "Object is uninitialized\n"); 01020 break; 01021 case XPATH_NODESET: 01022 fprintf(output, "Object is a Node Set :\n"); 01023 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth); 01024 break; 01025 case XPATH_XSLT_TREE: 01026 fprintf(output, "Object is an XSLT value tree :\n"); 01027 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth); 01028 break; 01029 case XPATH_BOOLEAN: 01030 fprintf(output, "Object is a Boolean : "); 01031 if (cur->boolval) fprintf(output, "true\n"); 01032 else fprintf(output, "false\n"); 01033 break; 01034 case XPATH_NUMBER: 01035 switch (xmlXPathIsInf(cur->floatval)) { 01036 case 1: 01037 fprintf(output, "Object is a number : Infinity\n"); 01038 break; 01039 case -1: 01040 fprintf(output, "Object is a number : -Infinity\n"); 01041 break; 01042 default: 01043 if (xmlXPathIsNaN(cur->floatval)) { 01044 fprintf(output, "Object is a number : NaN\n"); 01045 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) { 01046 fprintf(output, "Object is a number : 0\n"); 01047 } else { 01048 fprintf(output, "Object is a number : %0g\n", cur->floatval); 01049 } 01050 } 01051 break; 01052 case XPATH_STRING: 01053 fprintf(output, "Object is a string : "); 01054 xmlDebugDumpString(output, cur->stringval); 01055 fprintf(output, "\n"); 01056 break; 01057 case XPATH_POINT: 01058 fprintf(output, "Object is a point : index %d in node", cur->index); 01059 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1); 01060 fprintf(output, "\n"); 01061 break; 01062 case XPATH_RANGE: 01063 if ((cur->user2 == NULL) || 01064 ((cur->user2 == cur->user) && (cur->index == cur->index2))) { 01065 fprintf(output, "Object is a collapsed range :\n"); 01066 fprintf(output, "%s", shift); 01067 if (cur->index >= 0) 01068 fprintf(output, "index %d in ", cur->index); 01069 fprintf(output, "node\n"); 01070 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, 01071 depth + 1); 01072 } else { 01073 fprintf(output, "Object is a range :\n"); 01074 fprintf(output, "%s", shift); 01075 fprintf(output, "From "); 01076 if (cur->index >= 0) 01077 fprintf(output, "index %d in ", cur->index); 01078 fprintf(output, "node\n"); 01079 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, 01080 depth + 1); 01081 fprintf(output, "%s", shift); 01082 fprintf(output, "To "); 01083 if (cur->index2 >= 0) 01084 fprintf(output, "index %d in ", cur->index2); 01085 fprintf(output, "node\n"); 01086 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2, 01087 depth + 1); 01088 fprintf(output, "\n"); 01089 } 01090 break; 01091 case XPATH_LOCATIONSET: 01092 #if defined(LIBXML_XPTR_ENABLED) 01093 fprintf(output, "Object is a Location Set:\n"); 01094 xmlXPathDebugDumpLocationSet(output, 01095 (xmlLocationSetPtr) cur->user, depth); 01096 #endif 01097 break; 01098 case XPATH_USERS: 01099 fprintf(output, "Object is user defined\n"); 01100 break; 01101 } 01102 } 01103 01104 static void 01105 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp, 01106 xmlXPathStepOpPtr op, int depth) { 01107 int i; 01108 char shift[100]; 01109 01110 for (i = 0;((i < depth) && (i < 25));i++) 01111 shift[2 * i] = shift[2 * i + 1] = ' '; 01112 shift[2 * i] = shift[2 * i + 1] = 0; 01113 01114 fprintf(output, "%s", shift); 01115 if (op == NULL) { 01116 fprintf(output, "Step is NULL\n"); 01117 return; 01118 } 01119 switch (op->op) { 01120 case XPATH_OP_END: 01121 fprintf(output, "END"); break; 01122 case XPATH_OP_AND: 01123 fprintf(output, "AND"); break; 01124 case XPATH_OP_OR: 01125 fprintf(output, "OR"); break; 01126 case XPATH_OP_EQUAL: 01127 if (op->value) 01128 fprintf(output, "EQUAL ="); 01129 else 01130 fprintf(output, "EQUAL !="); 01131 break; 01132 case XPATH_OP_CMP: 01133 if (op->value) 01134 fprintf(output, "CMP <"); 01135 else 01136 fprintf(output, "CMP >"); 01137 if (!op->value2) 01138 fprintf(output, "="); 01139 break; 01140 case XPATH_OP_PLUS: 01141 if (op->value == 0) 01142 fprintf(output, "PLUS -"); 01143 else if (op->value == 1) 01144 fprintf(output, "PLUS +"); 01145 else if (op->value == 2) 01146 fprintf(output, "PLUS unary -"); 01147 else if (op->value == 3) 01148 fprintf(output, "PLUS unary - -"); 01149 break; 01150 case XPATH_OP_MULT: 01151 if (op->value == 0) 01152 fprintf(output, "MULT *"); 01153 else if (op->value == 1) 01154 fprintf(output, "MULT div"); 01155 else 01156 fprintf(output, "MULT mod"); 01157 break; 01158 case XPATH_OP_UNION: 01159 fprintf(output, "UNION"); break; 01160 case XPATH_OP_ROOT: 01161 fprintf(output, "ROOT"); break; 01162 case XPATH_OP_NODE: 01163 fprintf(output, "NODE"); break; 01164 case XPATH_OP_RESET: 01165 fprintf(output, "RESET"); break; 01166 case XPATH_OP_SORT: 01167 fprintf(output, "SORT"); break; 01168 case XPATH_OP_COLLECT: { 01169 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value; 01170 xmlXPathTestVal test = (xmlXPathTestVal)op->value2; 01171 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3; 01172 const xmlChar *prefix = op->value4; 01173 const xmlChar *name = op->value5; 01174 01175 fprintf(output, "COLLECT "); 01176 switch (axis) { 01177 case AXIS_ANCESTOR: 01178 fprintf(output, " 'ancestors' "); break; 01179 case AXIS_ANCESTOR_OR_SELF: 01180 fprintf(output, " 'ancestors-or-self' "); break; 01181 case AXIS_ATTRIBUTE: 01182 fprintf(output, " 'attributes' "); break; 01183 case AXIS_CHILD: 01184 fprintf(output, " 'child' "); break; 01185 case AXIS_DESCENDANT: 01186 fprintf(output, " 'descendant' "); break; 01187 case AXIS_DESCENDANT_OR_SELF: 01188 fprintf(output, " 'descendant-or-self' "); break; 01189 case AXIS_FOLLOWING: 01190 fprintf(output, " 'following' "); break; 01191 case AXIS_FOLLOWING_SIBLING: 01192 fprintf(output, " 'following-siblings' "); break; 01193 case AXIS_NAMESPACE: 01194 fprintf(output, " 'namespace' "); break; 01195 case AXIS_PARENT: 01196 fprintf(output, " 'parent' "); break; 01197 case AXIS_PRECEDING: 01198 fprintf(output, " 'preceding' "); break; 01199 case AXIS_PRECEDING_SIBLING: 01200 fprintf(output, " 'preceding-sibling' "); break; 01201 case AXIS_SELF: 01202 fprintf(output, " 'self' "); break; 01203 } 01204 switch (test) { 01205 case NODE_TEST_NONE: 01206 fprintf(output, "'none' "); break; 01207 case NODE_TEST_TYPE: 01208 fprintf(output, "'type' "); break; 01209 case NODE_TEST_PI: 01210 fprintf(output, "'PI' "); break; 01211 case NODE_TEST_ALL: 01212 fprintf(output, "'all' "); break; 01213 case NODE_TEST_NS: 01214 fprintf(output, "'namespace' "); break; 01215 case NODE_TEST_NAME: 01216 fprintf(output, "'name' "); break; 01217 } 01218 switch (type) { 01219 case NODE_TYPE_NODE: 01220 fprintf(output, "'node' "); break; 01221 case NODE_TYPE_COMMENT: 01222 fprintf(output, "'comment' "); break; 01223 case NODE_TYPE_TEXT: 01224 fprintf(output, "'text' "); break; 01225 case NODE_TYPE_PI: 01226 fprintf(output, "'PI' "); break; 01227 } 01228 if (prefix != NULL) 01229 fprintf(output, "%s:", prefix); 01230 if (name != NULL) 01231 fprintf(output, "%s", (const char *) name); 01232 break; 01233 01234 } 01235 case XPATH_OP_VALUE: { 01236 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4; 01237 01238 fprintf(output, "ELEM "); 01239 xmlXPathDebugDumpObject(output, object, 0); 01240 goto finish; 01241 } 01242 case XPATH_OP_VARIABLE: { 01243 const xmlChar *prefix = op->value5; 01244 const xmlChar *name = op->value4; 01245 01246 if (prefix != NULL) 01247 fprintf(output, "VARIABLE %s:%s", prefix, name); 01248 else 01249 fprintf(output, "VARIABLE %s", name); 01250 break; 01251 } 01252 case XPATH_OP_FUNCTION: { 01253 int nbargs = op->value; 01254 const xmlChar *prefix = op->value5; 01255 const xmlChar *name = op->value4; 01256 01257 if (prefix != NULL) 01258 fprintf(output, "FUNCTION %s:%s(%d args)", 01259 prefix, name, nbargs); 01260 else 01261 fprintf(output, "FUNCTION %s(%d args)", name, nbargs); 01262 break; 01263 } 01264 case XPATH_OP_ARG: fprintf(output, "ARG"); break; 01265 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break; 01266 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break; 01267 #ifdef LIBXML_XPTR_ENABLED 01268 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break; 01269 #endif 01270 default: 01271 fprintf(output, "UNKNOWN %d\n", op->op); return; 01272 } 01273 fprintf(output, "\n"); 01274 finish: 01275 if (op->ch1 >= 0) 01276 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1); 01277 if (op->ch2 >= 0) 01278 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1); 01279 } 01280 01289 void 01290 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp, 01291 int depth) { 01292 int i; 01293 char shift[100]; 01294 01295 if ((output == NULL) || (comp == NULL)) return; 01296 01297 for (i = 0;((i < depth) && (i < 25));i++) 01298 shift[2 * i] = shift[2 * i + 1] = ' '; 01299 shift[2 * i] = shift[2 * i + 1] = 0; 01300 01301 fprintf(output, "%s", shift); 01302 01303 fprintf(output, "Compiled Expression : %d elements\n", 01304 comp->nbStep); 01305 i = comp->last; 01306 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1); 01307 } 01308 01309 #ifdef XP_DEBUG_OBJ_USAGE 01310 01311 /* 01312 * XPath object usage related debugging variables. 01313 */ 01314 static int xmlXPathDebugObjCounterUndefined = 0; 01315 static int xmlXPathDebugObjCounterNodeset = 0; 01316 static int xmlXPathDebugObjCounterBool = 0; 01317 static int xmlXPathDebugObjCounterNumber = 0; 01318 static int xmlXPathDebugObjCounterString = 0; 01319 static int xmlXPathDebugObjCounterPoint = 0; 01320 static int xmlXPathDebugObjCounterRange = 0; 01321 static int xmlXPathDebugObjCounterLocset = 0; 01322 static int xmlXPathDebugObjCounterUsers = 0; 01323 static int xmlXPathDebugObjCounterXSLTTree = 0; 01324 static int xmlXPathDebugObjCounterAll = 0; 01325 01326 static int xmlXPathDebugObjTotalUndefined = 0; 01327 static int xmlXPathDebugObjTotalNodeset = 0; 01328 static int xmlXPathDebugObjTotalBool = 0; 01329 static int xmlXPathDebugObjTotalNumber = 0; 01330 static int xmlXPathDebugObjTotalString = 0; 01331 static int xmlXPathDebugObjTotalPoint = 0; 01332 static int xmlXPathDebugObjTotalRange = 0; 01333 static int xmlXPathDebugObjTotalLocset = 0; 01334 static int xmlXPathDebugObjTotalUsers = 0; 01335 static int xmlXPathDebugObjTotalXSLTTree = 0; 01336 static int xmlXPathDebugObjTotalAll = 0; 01337 01338 static int xmlXPathDebugObjMaxUndefined = 0; 01339 static int xmlXPathDebugObjMaxNodeset = 0; 01340 static int xmlXPathDebugObjMaxBool = 0; 01341 static int xmlXPathDebugObjMaxNumber = 0; 01342 static int xmlXPathDebugObjMaxString = 0; 01343 static int xmlXPathDebugObjMaxPoint = 0; 01344 static int xmlXPathDebugObjMaxRange = 0; 01345 static int xmlXPathDebugObjMaxLocset = 0; 01346 static int xmlXPathDebugObjMaxUsers = 0; 01347 static int xmlXPathDebugObjMaxXSLTTree = 0; 01348 static int xmlXPathDebugObjMaxAll = 0; 01349 01350 /* REVISIT TODO: Make this static when committing */ 01351 static void 01352 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt) 01353 { 01354 if (ctxt != NULL) { 01355 if (ctxt->cache != NULL) { 01356 xmlXPathContextCachePtr cache = 01357 (xmlXPathContextCachePtr) ctxt->cache; 01358 01359 cache->dbgCachedAll = 0; 01360 cache->dbgCachedNodeset = 0; 01361 cache->dbgCachedString = 0; 01362 cache->dbgCachedBool = 0; 01363 cache->dbgCachedNumber = 0; 01364 cache->dbgCachedPoint = 0; 01365 cache->dbgCachedRange = 0; 01366 cache->dbgCachedLocset = 0; 01367 cache->dbgCachedUsers = 0; 01368 cache->dbgCachedXSLTTree = 0; 01369 cache->dbgCachedUndefined = 0; 01370 01371 cache->dbgReusedAll = 0; 01372 cache->dbgReusedNodeset = 0; 01373 cache->dbgReusedString = 0; 01374 cache->dbgReusedBool = 0; 01375 cache->dbgReusedNumber = 0; 01376 cache->dbgReusedPoint = 0; 01377 cache->dbgReusedRange = 0; 01378 cache->dbgReusedLocset = 0; 01379 cache->dbgReusedUsers = 0; 01380 cache->dbgReusedXSLTTree = 0; 01381 cache->dbgReusedUndefined = 0; 01382 } 01383 } 01384 01385 xmlXPathDebugObjCounterUndefined = 0; 01386 xmlXPathDebugObjCounterNodeset = 0; 01387 xmlXPathDebugObjCounterBool = 0; 01388 xmlXPathDebugObjCounterNumber = 0; 01389 xmlXPathDebugObjCounterString = 0; 01390 xmlXPathDebugObjCounterPoint = 0; 01391 xmlXPathDebugObjCounterRange = 0; 01392 xmlXPathDebugObjCounterLocset = 0; 01393 xmlXPathDebugObjCounterUsers = 0; 01394 xmlXPathDebugObjCounterXSLTTree = 0; 01395 xmlXPathDebugObjCounterAll = 0; 01396 01397 xmlXPathDebugObjTotalUndefined = 0; 01398 xmlXPathDebugObjTotalNodeset = 0; 01399 xmlXPathDebugObjTotalBool = 0; 01400 xmlXPathDebugObjTotalNumber = 0; 01401 xmlXPathDebugObjTotalString = 0; 01402 xmlXPathDebugObjTotalPoint = 0; 01403 xmlXPathDebugObjTotalRange = 0; 01404 xmlXPathDebugObjTotalLocset = 0; 01405 xmlXPathDebugObjTotalUsers = 0; 01406 xmlXPathDebugObjTotalXSLTTree = 0; 01407 xmlXPathDebugObjTotalAll = 0; 01408 01409 xmlXPathDebugObjMaxUndefined = 0; 01410 xmlXPathDebugObjMaxNodeset = 0; 01411 xmlXPathDebugObjMaxBool = 0; 01412 xmlXPathDebugObjMaxNumber = 0; 01413 xmlXPathDebugObjMaxString = 0; 01414 xmlXPathDebugObjMaxPoint = 0; 01415 xmlXPathDebugObjMaxRange = 0; 01416 xmlXPathDebugObjMaxLocset = 0; 01417 xmlXPathDebugObjMaxUsers = 0; 01418 xmlXPathDebugObjMaxXSLTTree = 0; 01419 xmlXPathDebugObjMaxAll = 0; 01420 01421 } 01422 01423 static void 01424 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt, 01425 xmlXPathObjectType objType) 01426 { 01427 int isCached = 0; 01428 01429 if (ctxt != NULL) { 01430 if (ctxt->cache != NULL) { 01431 xmlXPathContextCachePtr cache = 01432 (xmlXPathContextCachePtr) ctxt->cache; 01433 01434 isCached = 1; 01435 01436 cache->dbgReusedAll++; 01437 switch (objType) { 01438 case XPATH_UNDEFINED: 01439 cache->dbgReusedUndefined++; 01440 break; 01441 case XPATH_NODESET: 01442 cache->dbgReusedNodeset++; 01443 break; 01444 case XPATH_BOOLEAN: 01445 cache->dbgReusedBool++; 01446 break; 01447 case XPATH_NUMBER: 01448 cache->dbgReusedNumber++; 01449 break; 01450 case XPATH_STRING: 01451 cache->dbgReusedString++; 01452 break; 01453 case XPATH_POINT: 01454 cache->dbgReusedPoint++; 01455 break; 01456 case XPATH_RANGE: 01457 cache->dbgReusedRange++; 01458 break; 01459 case XPATH_LOCATIONSET: 01460 cache->dbgReusedLocset++; 01461 break; 01462 case XPATH_USERS: 01463 cache->dbgReusedUsers++; 01464 break; 01465 case XPATH_XSLT_TREE: 01466 cache->dbgReusedXSLTTree++; 01467 break; 01468 default: 01469 break; 01470 } 01471 } 01472 } 01473 01474 switch (objType) { 01475 case XPATH_UNDEFINED: 01476 if (! isCached) 01477 xmlXPathDebugObjTotalUndefined++; 01478 xmlXPathDebugObjCounterUndefined++; 01479 if (xmlXPathDebugObjCounterUndefined > 01480 xmlXPathDebugObjMaxUndefined) 01481 xmlXPathDebugObjMaxUndefined = 01482 xmlXPathDebugObjCounterUndefined; 01483 break; 01484 case XPATH_NODESET: 01485 if (! isCached) 01486 xmlXPathDebugObjTotalNodeset++; 01487 xmlXPathDebugObjCounterNodeset++; 01488 if (xmlXPathDebugObjCounterNodeset > 01489 xmlXPathDebugObjMaxNodeset) 01490 xmlXPathDebugObjMaxNodeset = 01491 xmlXPathDebugObjCounterNodeset; 01492 break; 01493 case XPATH_BOOLEAN: 01494 if (! isCached) 01495 xmlXPathDebugObjTotalBool++; 01496 xmlXPathDebugObjCounterBool++; 01497 if (xmlXPathDebugObjCounterBool > 01498 xmlXPathDebugObjMaxBool) 01499 xmlXPathDebugObjMaxBool = 01500 xmlXPathDebugObjCounterBool; 01501 break; 01502 case XPATH_NUMBER: 01503 if (! isCached) 01504 xmlXPathDebugObjTotalNumber++; 01505 xmlXPathDebugObjCounterNumber++; 01506 if (xmlXPathDebugObjCounterNumber > 01507 xmlXPathDebugObjMaxNumber) 01508 xmlXPathDebugObjMaxNumber = 01509 xmlXPathDebugObjCounterNumber; 01510 break; 01511 case XPATH_STRING: 01512 if (! isCached) 01513 xmlXPathDebugObjTotalString++; 01514 xmlXPathDebugObjCounterString++; 01515 if (xmlXPathDebugObjCounterString > 01516 xmlXPathDebugObjMaxString) 01517 xmlXPathDebugObjMaxString = 01518 xmlXPathDebugObjCounterString; 01519 break; 01520 case XPATH_POINT: 01521 if (! isCached) 01522 xmlXPathDebugObjTotalPoint++; 01523 xmlXPathDebugObjCounterPoint++; 01524 if (xmlXPathDebugObjCounterPoint > 01525 xmlXPathDebugObjMaxPoint) 01526 xmlXPathDebugObjMaxPoint = 01527 xmlXPathDebugObjCounterPoint; 01528 break; 01529 case XPATH_RANGE: 01530 if (! isCached) 01531 xmlXPathDebugObjTotalRange++; 01532 xmlXPathDebugObjCounterRange++; 01533 if (xmlXPathDebugObjCounterRange > 01534 xmlXPathDebugObjMaxRange) 01535 xmlXPathDebugObjMaxRange = 01536 xmlXPathDebugObjCounterRange; 01537 break; 01538 case XPATH_LOCATIONSET: 01539 if (! isCached) 01540 xmlXPathDebugObjTotalLocset++; 01541 xmlXPathDebugObjCounterLocset++; 01542 if (xmlXPathDebugObjCounterLocset > 01543 xmlXPathDebugObjMaxLocset) 01544 xmlXPathDebugObjMaxLocset = 01545 xmlXPathDebugObjCounterLocset; 01546 break; 01547 case XPATH_USERS: 01548 if (! isCached) 01549 xmlXPathDebugObjTotalUsers++; 01550 xmlXPathDebugObjCounterUsers++; 01551 if (xmlXPathDebugObjCounterUsers > 01552 xmlXPathDebugObjMaxUsers) 01553 xmlXPathDebugObjMaxUsers = 01554 xmlXPathDebugObjCounterUsers; 01555 break; 01556 case XPATH_XSLT_TREE: 01557 if (! isCached) 01558 xmlXPathDebugObjTotalXSLTTree++; 01559 xmlXPathDebugObjCounterXSLTTree++; 01560 if (xmlXPathDebugObjCounterXSLTTree > 01561 xmlXPathDebugObjMaxXSLTTree) 01562 xmlXPathDebugObjMaxXSLTTree = 01563 xmlXPathDebugObjCounterXSLTTree; 01564 break; 01565 default: 01566 break; 01567 } 01568 if (! isCached) 01569 xmlXPathDebugObjTotalAll++; 01570 xmlXPathDebugObjCounterAll++; 01571 if (xmlXPathDebugObjCounterAll > 01572 xmlXPathDebugObjMaxAll) 01573 xmlXPathDebugObjMaxAll = 01574 xmlXPathDebugObjCounterAll; 01575 } 01576 01577 static void 01578 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt, 01579 xmlXPathObjectType objType) 01580 { 01581 int isCached = 0; 01582 01583 if (ctxt != NULL) { 01584 if (ctxt->cache != NULL) { 01585 xmlXPathContextCachePtr cache = 01586 (xmlXPathContextCachePtr) ctxt->cache; 01587 01588 isCached = 1; 01589 01590 cache->dbgCachedAll++; 01591 switch (objType) { 01592 case XPATH_UNDEFINED: 01593 cache->dbgCachedUndefined++; 01594 break; 01595 case XPATH_NODESET: 01596 cache->dbgCachedNodeset++; 01597 break; 01598 case XPATH_BOOLEAN: 01599 cache->dbgCachedBool++; 01600 break; 01601 case XPATH_NUMBER: 01602 cache->dbgCachedNumber++; 01603 break; 01604 case XPATH_STRING: 01605 cache->dbgCachedString++; 01606 break; 01607 case XPATH_POINT: 01608 cache->dbgCachedPoint++; 01609 break; 01610 case XPATH_RANGE: 01611 cache->dbgCachedRange++; 01612 break; 01613 case XPATH_LOCATIONSET: 01614 cache->dbgCachedLocset++; 01615 break; 01616 case XPATH_USERS: 01617 cache->dbgCachedUsers++; 01618 break; 01619 case XPATH_XSLT_TREE: 01620 cache->dbgCachedXSLTTree++; 01621 break; 01622 default: 01623 break; 01624 } 01625 01626 } 01627 } 01628 switch (objType) { 01629 case XPATH_UNDEFINED: 01630 xmlXPathDebugObjCounterUndefined--; 01631 break; 01632 case XPATH_NODESET: 01633 xmlXPathDebugObjCounterNodeset--; 01634 break; 01635 case XPATH_BOOLEAN: 01636 xmlXPathDebugObjCounterBool--; 01637 break; 01638 case XPATH_NUMBER: 01639 xmlXPathDebugObjCounterNumber--; 01640 break; 01641 case XPATH_STRING: 01642 xmlXPathDebugObjCounterString--; 01643 break; 01644 case XPATH_POINT: 01645 xmlXPathDebugObjCounterPoint--; 01646 break; 01647 case XPATH_RANGE: 01648 xmlXPathDebugObjCounterRange--; 01649 break; 01650 case XPATH_LOCATIONSET: 01651 xmlXPathDebugObjCounterLocset--; 01652 break; 01653 case XPATH_USERS: 01654 xmlXPathDebugObjCounterUsers--; 01655 break; 01656 case XPATH_XSLT_TREE: 01657 xmlXPathDebugObjCounterXSLTTree--; 01658 break; 01659 default: 01660 break; 01661 } 01662 xmlXPathDebugObjCounterAll--; 01663 } 01664 01665 /* REVISIT TODO: Make this static when committing */ 01666 static void 01667 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt) 01668 { 01669 int reqAll, reqNodeset, reqString, reqBool, reqNumber, 01670 reqXSLTTree, reqUndefined; 01671 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0, 01672 caNumber = 0, caXSLTTree = 0, caUndefined = 0; 01673 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0, 01674 reNumber = 0, reXSLTTree = 0, reUndefined = 0; 01675 int leftObjs = xmlXPathDebugObjCounterAll; 01676 01677 reqAll = xmlXPathDebugObjTotalAll; 01678 reqNodeset = xmlXPathDebugObjTotalNodeset; 01679 reqString = xmlXPathDebugObjTotalString; 01680 reqBool = xmlXPathDebugObjTotalBool; 01681 reqNumber = xmlXPathDebugObjTotalNumber; 01682 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree; 01683 reqUndefined = xmlXPathDebugObjTotalUndefined; 01684 01685 printf("# XPath object usage:\n"); 01686 01687 if (ctxt != NULL) { 01688 if (ctxt->cache != NULL) { 01689 xmlXPathContextCachePtr cache = 01690 (xmlXPathContextCachePtr) ctxt->cache; 01691 01692 reAll = cache->dbgReusedAll; 01693 reqAll += reAll; 01694 reNodeset = cache->dbgReusedNodeset; 01695 reqNodeset += reNodeset; 01696 reString = cache->dbgReusedString; 01697 reqString += reString; 01698 reBool = cache->dbgReusedBool; 01699 reqBool += reBool; 01700 reNumber = cache->dbgReusedNumber; 01701 reqNumber += reNumber; 01702 reXSLTTree = cache->dbgReusedXSLTTree; 01703 reqXSLTTree += reXSLTTree; 01704 reUndefined = cache->dbgReusedUndefined; 01705 reqUndefined += reUndefined; 01706 01707 caAll = cache->dbgCachedAll; 01708 caBool = cache->dbgCachedBool; 01709 caNodeset = cache->dbgCachedNodeset; 01710 caString = cache->dbgCachedString; 01711 caNumber = cache->dbgCachedNumber; 01712 caXSLTTree = cache->dbgCachedXSLTTree; 01713 caUndefined = cache->dbgCachedUndefined; 01714 01715 if (cache->nodesetObjs) 01716 leftObjs -= cache->nodesetObjs->number; 01717 if (cache->stringObjs) 01718 leftObjs -= cache->stringObjs->number; 01719 if (cache->booleanObjs) 01720 leftObjs -= cache->booleanObjs->number; 01721 if (cache->numberObjs) 01722 leftObjs -= cache->numberObjs->number; 01723 if (cache->miscObjs) 01724 leftObjs -= cache->miscObjs->number; 01725 } 01726 } 01727 01728 printf("# all\n"); 01729 printf("# total : %d\n", reqAll); 01730 printf("# left : %d\n", leftObjs); 01731 printf("# created: %d\n", xmlXPathDebugObjTotalAll); 01732 printf("# reused : %d\n", reAll); 01733 printf("# max : %d\n", xmlXPathDebugObjMaxAll); 01734 01735 printf("# node-sets\n"); 01736 printf("# total : %d\n", reqNodeset); 01737 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset); 01738 printf("# reused : %d\n", reNodeset); 01739 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset); 01740 01741 printf("# strings\n"); 01742 printf("# total : %d\n", reqString); 01743 printf("# created: %d\n", xmlXPathDebugObjTotalString); 01744 printf("# reused : %d\n", reString); 01745 printf("# max : %d\n", xmlXPathDebugObjMaxString); 01746 01747 printf("# booleans\n"); 01748 printf("# total : %d\n", reqBool); 01749 printf("# created: %d\n", xmlXPathDebugObjTotalBool); 01750 printf("# reused : %d\n", reBool); 01751 printf("# max : %d\n", xmlXPathDebugObjMaxBool); 01752 01753 printf("# numbers\n"); 01754 printf("# total : %d\n", reqNumber); 01755 printf("# created: %d\n", xmlXPathDebugObjTotalNumber); 01756 printf("# reused : %d\n", reNumber); 01757 printf("# max : %d\n", xmlXPathDebugObjMaxNumber); 01758 01759 printf("# XSLT result tree fragments\n"); 01760 printf("# total : %d\n", reqXSLTTree); 01761 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree); 01762 printf("# reused : %d\n", reXSLTTree); 01763 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree); 01764 01765 printf("# undefined\n"); 01766 printf("# total : %d\n", reqUndefined); 01767 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined); 01768 printf("# reused : %d\n", reUndefined); 01769 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined); 01770 01771 } 01772 01773 #endif /* XP_DEBUG_OBJ_USAGE */ 01774 01775 #endif /* LIBXML_DEBUG_ENABLED */ 01776 01777 /************************************************************************ 01778 * * 01779 * XPath object caching * 01780 * * 01781 ************************************************************************/ 01782 01790 static xmlXPathContextCachePtr 01791 xmlXPathNewCache(void) 01792 { 01793 xmlXPathContextCachePtr ret; 01794 01795 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache)); 01796 if (ret == NULL) { 01797 xmlXPathErrMemory(NULL, "creating object cache\n"); 01798 return(NULL); 01799 } 01800 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache)); 01801 ret->maxNodeset = 100; 01802 ret->maxString = 100; 01803 ret->maxBoolean = 100; 01804 ret->maxNumber = 100; 01805 ret->maxMisc = 100; 01806 return(ret); 01807 } 01808 01809 static void 01810 xmlXPathCacheFreeObjectList(xmlPointerListPtr list) 01811 { 01812 int i; 01813 xmlXPathObjectPtr obj; 01814 01815 if (list == NULL) 01816 return; 01817 01818 for (i = 0; i < list->number; i++) { 01819 obj = list->items[i]; 01820 /* 01821 * Note that it is already assured that we don't need to 01822 * look out for namespace nodes in the node-set. 01823 */ 01824 if (obj->nodesetval != NULL) { 01825 if (obj->nodesetval->nodeTab != NULL) 01826 xmlFree(obj->nodesetval->nodeTab); 01827 xmlFree(obj->nodesetval); 01828 } 01829 xmlFree(obj); 01830 #ifdef XP_DEBUG_OBJ_USAGE 01831 xmlXPathDebugObjCounterAll--; 01832 #endif 01833 } 01834 xmlPointerListFree(list); 01835 } 01836 01837 static void 01838 xmlXPathFreeCache(xmlXPathContextCachePtr cache) 01839 { 01840 if (cache == NULL) 01841 return; 01842 if (cache->nodesetObjs) 01843 xmlXPathCacheFreeObjectList(cache->nodesetObjs); 01844 if (cache->stringObjs) 01845 xmlXPathCacheFreeObjectList(cache->stringObjs); 01846 if (cache->booleanObjs) 01847 xmlXPathCacheFreeObjectList(cache->booleanObjs); 01848 if (cache->numberObjs) 01849 xmlXPathCacheFreeObjectList(cache->numberObjs); 01850 if (cache->miscObjs) 01851 xmlXPathCacheFreeObjectList(cache->miscObjs); 01852 xmlFree(cache); 01853 } 01854 01877 int 01878 xmlXPathContextSetCache(xmlXPathContextPtr ctxt, 01879 int active, 01880 int value, 01881 int options) 01882 { 01883 if (ctxt == NULL) 01884 return(-1); 01885 if (active) { 01886 xmlXPathContextCachePtr cache; 01887 01888 if (ctxt->cache == NULL) { 01889 ctxt->cache = xmlXPathNewCache(); 01890 if (ctxt->cache == NULL) 01891 return(-1); 01892 } 01893 cache = (xmlXPathContextCachePtr) ctxt->cache; 01894 if (options == 0) { 01895 if (value < 0) 01896 value = 100; 01897 cache->maxNodeset = value; 01898 cache->maxString = value; 01899 cache->maxNumber = value; 01900 cache->maxBoolean = value; 01901 cache->maxMisc = value; 01902 } 01903 } else if (ctxt->cache != NULL) { 01904 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache); 01905 ctxt->cache = NULL; 01906 } 01907 return(0); 01908 } 01909 01920 static xmlXPathObjectPtr 01921 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val) 01922 { 01923 if ((ctxt != NULL) && (ctxt->cache != NULL)) { 01924 xmlXPathContextCachePtr cache = 01925 (xmlXPathContextCachePtr) ctxt->cache; 01926 01927 if ((cache->miscObjs != NULL) && 01928 (cache->miscObjs->number != 0)) 01929 { 01930 xmlXPathObjectPtr ret; 01931 01932 ret = (xmlXPathObjectPtr) 01933 cache->miscObjs->items[--cache->miscObjs->number]; 01934 ret->type = XPATH_NODESET; 01935 ret->nodesetval = val; 01936 #ifdef XP_DEBUG_OBJ_USAGE 01937 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 01938 #endif 01939 return(ret); 01940 } 01941 } 01942 01943 return(xmlXPathWrapNodeSet(val)); 01944 01945 } 01946 01957 static xmlXPathObjectPtr 01958 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val) 01959 { 01960 if ((ctxt != NULL) && (ctxt->cache != NULL)) { 01961 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 01962 01963 if ((cache->stringObjs != NULL) && 01964 (cache->stringObjs->number != 0)) 01965 { 01966 01967 xmlXPathObjectPtr ret; 01968 01969 ret = (xmlXPathObjectPtr) 01970 cache->stringObjs->items[--cache->stringObjs->number]; 01971 ret->type = XPATH_STRING; 01972 ret->stringval = val; 01973 #ifdef XP_DEBUG_OBJ_USAGE 01974 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 01975 #endif 01976 return(ret); 01977 } else if ((cache->miscObjs != NULL) && 01978 (cache->miscObjs->number != 0)) 01979 { 01980 xmlXPathObjectPtr ret; 01981 /* 01982 * Fallback to misc-cache. 01983 */ 01984 ret = (xmlXPathObjectPtr) 01985 cache->miscObjs->items[--cache->miscObjs->number]; 01986 01987 ret->type = XPATH_STRING; 01988 ret->stringval = val; 01989 #ifdef XP_DEBUG_OBJ_USAGE 01990 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 01991 #endif 01992 return(ret); 01993 } 01994 } 01995 return(xmlXPathWrapString(val)); 01996 } 01997 02009 static xmlXPathObjectPtr 02010 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val) 02011 { 02012 if ((ctxt != NULL) && (ctxt->cache)) { 02013 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 02014 02015 if ((cache->nodesetObjs != NULL) && 02016 (cache->nodesetObjs->number != 0)) 02017 { 02018 xmlXPathObjectPtr ret; 02019 /* 02020 * Use the nodset-cache. 02021 */ 02022 ret = (xmlXPathObjectPtr) 02023 cache->nodesetObjs->items[--cache->nodesetObjs->number]; 02024 ret->type = XPATH_NODESET; 02025 ret->boolval = 0; 02026 if (val) { 02027 if ((ret->nodesetval->nodeMax == 0) || 02028 (val->type == XML_NAMESPACE_DECL)) 02029 { 02030 xmlXPathNodeSetAddUnique(ret->nodesetval, val); 02031 } else { 02032 ret->nodesetval->nodeTab[0] = val; 02033 ret->nodesetval->nodeNr = 1; 02034 } 02035 } 02036 #ifdef XP_DEBUG_OBJ_USAGE 02037 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 02038 #endif 02039 return(ret); 02040 } else if ((cache->miscObjs != NULL) && 02041 (cache->miscObjs->number != 0)) 02042 { 02043 xmlXPathObjectPtr ret; 02044 /* 02045 * Fallback to misc-cache. 02046 */ 02047 02048 ret = (xmlXPathObjectPtr) 02049 cache->miscObjs->items[--cache->miscObjs->number]; 02050 02051 ret->type = XPATH_NODESET; 02052 ret->boolval = 0; 02053 ret->nodesetval = xmlXPathNodeSetCreate(val); 02054 #ifdef XP_DEBUG_OBJ_USAGE 02055 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 02056 #endif 02057 return(ret); 02058 } 02059 } 02060 return(xmlXPathNewNodeSet(val)); 02061 } 02062 02073 static xmlXPathObjectPtr 02074 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val) 02075 { 02076 if ((ctxt != NULL) && (ctxt->cache)) { 02077 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 02078 02079 if ((cache->stringObjs != NULL) && 02080 (cache->stringObjs->number != 0)) 02081 { 02082 xmlXPathObjectPtr ret; 02083 02084 ret = (xmlXPathObjectPtr) 02085 cache->stringObjs->items[--cache->stringObjs->number]; 02086 02087 ret->type = XPATH_STRING; 02088 ret->stringval = xmlStrdup(BAD_CAST val); 02089 #ifdef XP_DEBUG_OBJ_USAGE 02090 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 02091 #endif 02092 return(ret); 02093 } else if ((cache->miscObjs != NULL) && 02094 (cache->miscObjs->number != 0)) 02095 { 02096 xmlXPathObjectPtr ret; 02097 02098 ret = (xmlXPathObjectPtr) 02099 cache->miscObjs->items[--cache->miscObjs->number]; 02100 02101 ret->type = XPATH_STRING; 02102 ret->stringval = xmlStrdup(BAD_CAST val); 02103 #ifdef XP_DEBUG_OBJ_USAGE 02104 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 02105 #endif 02106 return(ret); 02107 } 02108 } 02109 return(xmlXPathNewCString(val)); 02110 } 02111 02122 static xmlXPathObjectPtr 02123 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val) 02124 { 02125 if ((ctxt != NULL) && (ctxt->cache)) { 02126 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 02127 02128 if ((cache->stringObjs != NULL) && 02129 (cache->stringObjs->number != 0)) 02130 { 02131 xmlXPathObjectPtr ret; 02132 02133 ret = (xmlXPathObjectPtr) 02134 cache->stringObjs->items[--cache->stringObjs->number]; 02135 ret->type = XPATH_STRING; 02136 if (val != NULL) 02137 ret->stringval = xmlStrdup(val); 02138 else 02139 ret->stringval = xmlStrdup((const xmlChar *)""); 02140 #ifdef XP_DEBUG_OBJ_USAGE 02141 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 02142 #endif 02143 return(ret); 02144 } else if ((cache->miscObjs != NULL) && 02145 (cache->miscObjs->number != 0)) 02146 { 02147 xmlXPathObjectPtr ret; 02148 02149 ret = (xmlXPathObjectPtr) 02150 cache->miscObjs->items[--cache->miscObjs->number]; 02151 02152 ret->type = XPATH_STRING; 02153 if (val != NULL) 02154 ret->stringval = xmlStrdup(val); 02155 else 02156 ret->stringval = xmlStrdup((const xmlChar *)""); 02157 #ifdef XP_DEBUG_OBJ_USAGE 02158 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 02159 #endif 02160 return(ret); 02161 } 02162 } 02163 return(xmlXPathNewString(val)); 02164 } 02165 02176 static xmlXPathObjectPtr 02177 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val) 02178 { 02179 if ((ctxt != NULL) && (ctxt->cache)) { 02180 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 02181 02182 if ((cache->booleanObjs != NULL) && 02183 (cache->booleanObjs->number != 0)) 02184 { 02185 xmlXPathObjectPtr ret; 02186 02187 ret = (xmlXPathObjectPtr) 02188 cache->booleanObjs->items[--cache->booleanObjs->number]; 02189 ret->type = XPATH_BOOLEAN; 02190 ret->boolval = (val != 0); 02191 #ifdef XP_DEBUG_OBJ_USAGE 02192 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN); 02193 #endif 02194 return(ret); 02195 } else if ((cache->miscObjs != NULL) && 02196 (cache->miscObjs->number != 0)) 02197 { 02198 xmlXPathObjectPtr ret; 02199 02200 ret = (xmlXPathObjectPtr) 02201 cache->miscObjs->items[--cache->miscObjs->number]; 02202 02203 ret->type = XPATH_BOOLEAN; 02204 ret->boolval = (val != 0); 02205 #ifdef XP_DEBUG_OBJ_USAGE 02206 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN); 02207 #endif 02208 return(ret); 02209 } 02210 } 02211 return(xmlXPathNewBoolean(val)); 02212 } 02213 02224 static xmlXPathObjectPtr 02225 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val) 02226 { 02227 if ((ctxt != NULL) && (ctxt->cache)) { 02228 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 02229 02230 if ((cache->numberObjs != NULL) && 02231 (cache->numberObjs->number != 0)) 02232 { 02233 xmlXPathObjectPtr ret; 02234 02235 ret = (xmlXPathObjectPtr) 02236 cache->numberObjs->items[--cache->numberObjs->number]; 02237 ret->type = XPATH_NUMBER; 02238 ret->floatval = val; 02239 #ifdef XP_DEBUG_OBJ_USAGE 02240 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER); 02241 #endif 02242 return(ret); 02243 } else if ((cache->miscObjs != NULL) && 02244 (cache->miscObjs->number != 0)) 02245 { 02246 xmlXPathObjectPtr ret; 02247 02248 ret = (xmlXPathObjectPtr) 02249 cache->miscObjs->items[--cache->miscObjs->number]; 02250 02251 ret->type = XPATH_NUMBER; 02252 ret->floatval = val; 02253 #ifdef XP_DEBUG_OBJ_USAGE 02254 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER); 02255 #endif 02256 return(ret); 02257 } 02258 } 02259 return(xmlXPathNewFloat(val)); 02260 } 02261 02274 static xmlXPathObjectPtr 02275 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 02276 xmlChar *res = NULL; 02277 02278 if (val == NULL) 02279 return(xmlXPathCacheNewCString(ctxt, "")); 02280 02281 switch (val->type) { 02282 case XPATH_UNDEFINED: 02283 #ifdef DEBUG_EXPR 02284 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n"); 02285 #endif 02286 break; 02287 case XPATH_NODESET: 02288 case XPATH_XSLT_TREE: 02289 res = xmlXPathCastNodeSetToString(val->nodesetval); 02290 break; 02291 case XPATH_STRING: 02292 return(val); 02293 case XPATH_BOOLEAN: 02294 res = xmlXPathCastBooleanToString(val->boolval); 02295 break; 02296 case XPATH_NUMBER: 02297 res = xmlXPathCastNumberToString(val->floatval); 02298 break; 02299 case XPATH_USERS: 02300 case XPATH_POINT: 02301 case XPATH_RANGE: 02302 case XPATH_LOCATIONSET: 02303 TODO; 02304 break; 02305 } 02306 xmlXPathReleaseObject(ctxt, val); 02307 if (res == NULL) 02308 return(xmlXPathCacheNewCString(ctxt, "")); 02309 return(xmlXPathCacheWrapString(ctxt, res)); 02310 } 02311 02322 static xmlXPathObjectPtr 02323 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) 02324 { 02325 if (val == NULL) 02326 return(NULL); 02327 02328 if (XP_HAS_CACHE(ctxt)) { 02329 switch (val->type) { 02330 case XPATH_NODESET: 02331 return(xmlXPathCacheWrapNodeSet(ctxt, 02332 xmlXPathNodeSetMerge(NULL, val->nodesetval))); 02333 case XPATH_STRING: 02334 return(xmlXPathCacheNewString(ctxt, val->stringval)); 02335 case XPATH_BOOLEAN: 02336 return(xmlXPathCacheNewBoolean(ctxt, val->boolval)); 02337 case XPATH_NUMBER: 02338 return(xmlXPathCacheNewFloat(ctxt, val->floatval)); 02339 default: 02340 break; 02341 } 02342 } 02343 return(xmlXPathObjectCopy(val)); 02344 } 02345 02357 static xmlXPathObjectPtr 02358 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 02359 xmlXPathObjectPtr ret; 02360 02361 if (val == NULL) 02362 return(xmlXPathCacheNewBoolean(ctxt, 0)); 02363 if (val->type == XPATH_BOOLEAN) 02364 return(val); 02365 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val)); 02366 xmlXPathReleaseObject(ctxt, val); 02367 return(ret); 02368 } 02369 02381 static xmlXPathObjectPtr 02382 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 02383 xmlXPathObjectPtr ret; 02384 02385 if (val == NULL) 02386 return(xmlXPathCacheNewFloat(ctxt, 0.0)); 02387 if (val->type == XPATH_NUMBER) 02388 return(val); 02389 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val)); 02390 xmlXPathReleaseObject(ctxt, val); 02391 return(ret); 02392 } 02393 02394 /************************************************************************ 02395 * * 02396 * Parser stacks related functions and macros * 02397 * * 02398 ************************************************************************/ 02399 02408 xmlXPathObjectPtr 02409 valuePop(xmlXPathParserContextPtr ctxt) 02410 { 02411 xmlXPathObjectPtr ret; 02412 02413 if ((ctxt == NULL) || (ctxt->valueNr <= 0)) 02414 return (NULL); 02415 ctxt->valueNr--; 02416 if (ctxt->valueNr > 0) 02417 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1]; 02418 else 02419 ctxt->value = NULL; 02420 ret = ctxt->valueTab[ctxt->valueNr]; 02421 ctxt->valueTab[ctxt->valueNr] = NULL; 02422 return (ret); 02423 } 02433 int 02434 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value) 02435 { 02436 if ((ctxt == NULL) || (value == NULL)) return(-1); 02437 if (ctxt->valueNr >= ctxt->valueMax) { 02438 xmlXPathObjectPtr *tmp; 02439 02440 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab, 02441 2 * ctxt->valueMax * 02442 sizeof(ctxt->valueTab[0])); 02443 if (tmp == NULL) { 02444 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); 02445 return (0); 02446 } 02447 ctxt->valueMax *= 2; 02448 ctxt->valueTab = tmp; 02449 } 02450 ctxt->valueTab[ctxt->valueNr] = value; 02451 ctxt->value = value; 02452 return (ctxt->valueNr++); 02453 } 02454 02464 int 02465 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) { 02466 xmlXPathObjectPtr obj; 02467 int ret; 02468 02469 obj = valuePop(ctxt); 02470 if (obj == NULL) { 02471 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 02472 return(0); 02473 } 02474 if (obj->type != XPATH_BOOLEAN) 02475 ret = xmlXPathCastToBoolean(obj); 02476 else 02477 ret = obj->boolval; 02478 xmlXPathReleaseObject(ctxt->context, obj); 02479 return(ret); 02480 } 02481 02491 double 02492 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) { 02493 xmlXPathObjectPtr obj; 02494 double ret; 02495 02496 obj = valuePop(ctxt); 02497 if (obj == NULL) { 02498 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 02499 return(0); 02500 } 02501 if (obj->type != XPATH_NUMBER) 02502 ret = xmlXPathCastToNumber(obj); 02503 else 02504 ret = obj->floatval; 02505 xmlXPathReleaseObject(ctxt->context, obj); 02506 return(ret); 02507 } 02508 02518 xmlChar * 02519 xmlXPathPopString (xmlXPathParserContextPtr ctxt) { 02520 xmlXPathObjectPtr obj; 02521 xmlChar * ret; 02522 02523 obj = valuePop(ctxt); 02524 if (obj == NULL) { 02525 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 02526 return(NULL); 02527 } 02528 ret = xmlXPathCastToString(obj); /* this does required strdup */ 02529 /* TODO: needs refactoring somewhere else */ 02530 if (obj->stringval == ret) 02531 obj->stringval = NULL; 02532 xmlXPathReleaseObject(ctxt->context, obj); 02533 return(ret); 02534 } 02535 02545 xmlNodeSetPtr 02546 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) { 02547 xmlXPathObjectPtr obj; 02548 xmlNodeSetPtr ret; 02549 02550 if (ctxt == NULL) return(NULL); 02551 if (ctxt->value == NULL) { 02552 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 02553 return(NULL); 02554 } 02555 if (!xmlXPathStackIsNodeSet(ctxt)) { 02556 xmlXPathSetTypeError(ctxt); 02557 return(NULL); 02558 } 02559 obj = valuePop(ctxt); 02560 ret = obj->nodesetval; 02561 #if 0 02562 /* to fix memory leak of not clearing obj->user */ 02563 if (obj->boolval && obj->user != NULL) 02564 xmlFreeNodeList((xmlNodePtr) obj->user); 02565 #endif 02566 obj->nodesetval = NULL; 02567 xmlXPathReleaseObject(ctxt->context, obj); 02568 return(ret); 02569 } 02570 02580 void * 02581 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) { 02582 xmlXPathObjectPtr obj; 02583 void * ret; 02584 02585 if ((ctxt == NULL) || (ctxt->value == NULL)) { 02586 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 02587 return(NULL); 02588 } 02589 if (ctxt->value->type != XPATH_USERS) { 02590 xmlXPathSetTypeError(ctxt); 02591 return(NULL); 02592 } 02593 obj = valuePop(ctxt); 02594 ret = obj->user; 02595 obj->user = NULL; 02596 xmlXPathReleaseObject(ctxt->context, obj); 02597 return(ret); 02598 } 02599 02600 /* 02601 * Macros for accessing the content. Those should be used only by the parser, 02602 * and not exported. 02603 * 02604 * Dirty macros, i.e. one need to make assumption on the context to use them 02605 * 02606 * CUR_PTR return the current pointer to the xmlChar to be parsed. 02607 * CUR returns the current xmlChar value, i.e. a 8 bit value 02608 * in ISO-Latin or UTF-8. 02609 * This should be used internally by the parser 02610 * only to compare to ASCII values otherwise it would break when 02611 * running with UTF-8 encoding. 02612 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only 02613 * to compare on ASCII based substring. 02614 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined 02615 * strings within the parser. 02616 * CURRENT Returns the current char value, with the full decoding of 02617 * UTF-8 if we are using this mode. It returns an int. 02618 * NEXT Skip to the next character, this does the proper decoding 02619 * in UTF-8 mode. It also pop-up unfinished entities on the fly. 02620 * It returns the pointer to the current xmlChar. 02621 */ 02622 02623 #define CUR (*ctxt->cur) 02624 #define SKIP(val) ctxt->cur += (val) 02625 #define NXT(val) ctxt->cur[(val)] 02626 #define CUR_PTR ctxt->cur 02627 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l) 02628 02629 #define COPY_BUF(l,b,i,v) \ 02630 if (l == 1) b[i++] = (xmlChar) v; \ 02631 else i += xmlCopyChar(l,&b[i],v) 02632 02633 #define NEXTL(l) ctxt->cur += l 02634 02635 #define SKIP_BLANKS \ 02636 while (IS_BLANK_CH(*(ctxt->cur))) NEXT 02637 02638 #define CURRENT (*ctxt->cur) 02639 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur) 02640 02641 02642 #ifndef DBL_DIG 02643 #define DBL_DIG 16 02644 #endif 02645 #ifndef DBL_EPSILON 02646 #define DBL_EPSILON 1E-9 02647 #endif 02648 02649 #define UPPER_DOUBLE 1E9 02650 #define LOWER_DOUBLE 1E-5 02651 #define LOWER_DOUBLE_EXP 5 02652 02653 #define INTEGER_DIGITS DBL_DIG 02654 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP)) 02655 #define EXPONENT_DIGITS (3 + 2) 02656 02665 static void 02666 xmlXPathFormatNumber(double number, char buffer[], int buffersize) 02667 { 02668 switch (xmlXPathIsInf(number)) { 02669 case 1: 02670 if (buffersize > (int)sizeof("Infinity")) 02671 snprintf(buffer, buffersize, "Infinity"); 02672 break; 02673 case -1: 02674 if (buffersize > (int)sizeof("-Infinity")) 02675 snprintf(buffer, buffersize, "-Infinity"); 02676 break; 02677 default: 02678 if (xmlXPathIsNaN(number)) { 02679 if (buffersize > (int)sizeof("NaN")) 02680 snprintf(buffer, buffersize, "NaN"); 02681 } else if (number == 0 && xmlXPathGetSign(number) != 0) { 02682 snprintf(buffer, buffersize, "0"); 02683 } else if (number == ((int) number)) { 02684 char work[30]; 02685 char *ptr, *cur; 02686 int value = (int) number; 02687 02688 ptr = &buffer[0]; 02689 if (value == 0) { 02690 *ptr++ = '0'; 02691 } else { 02692 snprintf(work, 29, "%d", value); 02693 cur = &work[0]; 02694 while ((*cur) && (ptr - buffer < buffersize)) { 02695 *ptr++ = *cur++; 02696 } 02697 } 02698 if (ptr - buffer < buffersize) { 02699 *ptr = 0; 02700 } else if (buffersize > 0) { 02701 ptr--; 02702 *ptr = 0; 02703 } 02704 } else { 02705 /* 02706 For the dimension of work, 02707 DBL_DIG is number of significant digits 02708 EXPONENT is only needed for "scientific notation" 02709 3 is sign, decimal point, and terminating zero 02710 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction 02711 Note that this dimension is slightly (a few characters) 02712 larger than actually necessary. 02713 */ 02714 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP]; 02715 int integer_place, fraction_place; 02716 char *ptr; 02717 char *after_fraction; 02718 double absolute_value; 02719 int size; 02720 02721 absolute_value = fabs(number); 02722 02723 /* 02724 * First choose format - scientific or regular floating point. 02725 * In either case, result is in work, and after_fraction points 02726 * just past the fractional part. 02727 */ 02728 if ( ((absolute_value > UPPER_DOUBLE) || 02729 (absolute_value < LOWER_DOUBLE)) && 02730 (absolute_value != 0.0) ) { 02731 /* Use scientific notation */ 02732 integer_place = DBL_DIG + EXPONENT_DIGITS + 1; 02733 fraction_place = DBL_DIG - 1; 02734 size = snprintf(work, sizeof(work),"%*.*e", 02735 integer_place, fraction_place, number); 02736 while ((size > 0) && (work[size] != 'e')) size--; 02737 02738 } 02739 else { 02740 /* Use regular notation */ 02741 if (absolute_value > 0.0) { 02742 integer_place = (int)log10(absolute_value); 02743 if (integer_place > 0) 02744 fraction_place = DBL_DIG - integer_place - 1; 02745 else 02746 fraction_place = DBL_DIG - integer_place; 02747 } else { 02748 fraction_place = 1; 02749 } 02750 size = snprintf(work, sizeof(work), "%0.*f", 02751 fraction_place, number); 02752 } 02753 02754 /* Remove fractional trailing zeroes */ 02755 after_fraction = work + size; 02756 ptr = after_fraction; 02757 while (*(--ptr) == '0') 02758 ; 02759 if (*ptr != '.') 02760 ptr++; 02761 while ((*ptr++ = *after_fraction++) != 0); 02762 02763 /* Finally copy result back to caller */ 02764 size = strlen(work) + 1; 02765 if (size > buffersize) { 02766 work[buffersize - 1] = 0; 02767 size = buffersize; 02768 } 02769 memmove(buffer, work, size); 02770 } 02771 break; 02772 } 02773 } 02774 02775 02776 /************************************************************************ 02777 * * 02778 * Routines to handle NodeSets * 02779 * * 02780 ************************************************************************/ 02781 02795 long 02796 xmlXPathOrderDocElems(xmlDocPtr doc) { 02797 long count = 0; 02798 xmlNodePtr cur; 02799 02800 if (doc == NULL) 02801 return(-1); 02802 cur = doc->children; 02803 while (cur != NULL) { 02804 if (cur->type == XML_ELEMENT_NODE) { 02805 cur->content = (void *) (-(++count)); 02806 if (cur->children != NULL) { 02807 cur = cur->children; 02808 continue; 02809 } 02810 } 02811 if (cur->next != NULL) { 02812 cur = cur->next; 02813 continue; 02814 } 02815 do { 02816 cur = cur->parent; 02817 if (cur == NULL) 02818 break; 02819 if (cur == (xmlNodePtr) doc) { 02820 cur = NULL; 02821 break; 02822 } 02823 if (cur->next != NULL) { 02824 cur = cur->next; 02825 break; 02826 } 02827 } while (cur != NULL); 02828 } 02829 return(count); 02830 } 02831 02842 int 02843 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) { 02844 int depth1, depth2; 02845 int attr1 = 0, attr2 = 0; 02846 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL; 02847 xmlNodePtr cur, root; 02848 02849 if ((node1 == NULL) || (node2 == NULL)) 02850 return(-2); 02851 /* 02852 * a couple of optimizations which will avoid computations in most cases 02853 */ 02854 if (node1 == node2) /* trivial case */ 02855 return(0); 02856 if (node1->type == XML_ATTRIBUTE_NODE) { 02857 attr1 = 1; 02858 attrNode1 = node1; 02859 node1 = node1->parent; 02860 } 02861 if (node2->type == XML_ATTRIBUTE_NODE) { 02862 attr2 = 1; 02863 attrNode2 = node2; 02864 node2 = node2->parent; 02865 } 02866 if (node1 == node2) { 02867 if (attr1 == attr2) { 02868 /* not required, but we keep attributes in order */ 02869 if (attr1 != 0) { 02870 cur = attrNode2->prev; 02871 while (cur != NULL) { 02872 if (cur == attrNode1) 02873 return (1); 02874 cur = cur->prev; 02875 } 02876 return (-1); 02877 } 02878 return(0); 02879 } 02880 if (attr2 == 1) 02881 return(1); 02882 return(-1); 02883 } 02884 if ((node1->type == XML_NAMESPACE_DECL) || 02885 (node2->type == XML_NAMESPACE_DECL)) 02886 return(1); 02887 if (node1 == node2->prev) 02888 return(1); 02889 if (node1 == node2->next) 02890 return(-1); 02891 02892 /* 02893 * Speedup using document order if availble. 02894 */ 02895 if ((node1->type == XML_ELEMENT_NODE) && 02896 (node2->type == XML_ELEMENT_NODE) && 02897 (0 > (long) node1->content) && 02898 (0 > (long) node2->content) && 02899 (node1->doc == node2->doc)) { 02900 long l1, l2; 02901 02902 l1 = -((long) node1->content); 02903 l2 = -((long) node2->content); 02904 if (l1 < l2) 02905 return(1); 02906 if (l1 > l2) 02907 return(-1); 02908 } 02909 02910 /* 02911 * compute depth to root 02912 */ 02913 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) { 02914 if (cur == node1) 02915 return(1); 02916 depth2++; 02917 } 02918 root = cur; 02919 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) { 02920 if (cur == node2) 02921 return(-1); 02922 depth1++; 02923 } 02924 /* 02925 * Distinct document (or distinct entities :-( ) case. 02926 */ 02927 if (root != cur) { 02928 return(-2); 02929 } 02930 /* 02931 * get the nearest common ancestor. 02932 */ 02933 while (depth1 > depth2) { 02934 depth1--; 02935 node1 = node1->parent; 02936 } 02937 while (depth2 > depth1) { 02938 depth2--; 02939 node2 = node2->parent; 02940 } 02941 while (node1->parent != node2->parent) { 02942 node1 = node1->parent; 02943 node2 = node2->parent; 02944 /* should not happen but just in case ... */ 02945 if ((node1 == NULL) || (node2 == NULL)) 02946 return(-2); 02947 } 02948 /* 02949 * Find who's first. 02950 */ 02951 if (node1 == node2->prev) 02952 return(1); 02953 if (node1 == node2->next) 02954 return(-1); 02955 /* 02956 * Speedup using document order if availble. 02957 */ 02958 if ((node1->type == XML_ELEMENT_NODE) && 02959 (node2->type == XML_ELEMENT_NODE) && 02960 (0 > (long) node1->content) && 02961 (0 > (long) node2->content) && 02962 (node1->doc == node2->doc)) { 02963 long l1, l2; 02964 02965 l1 = -((long) node1->content); 02966 l2 = -((long) node2->content); 02967 if (l1 < l2) 02968 return(1); 02969 if (l1 > l2) 02970 return(-1); 02971 } 02972 02973 for (cur = node1->next;cur != NULL;cur = cur->next) 02974 if (cur == node2) 02975 return(1); 02976 return(-1); /* assume there is no sibling list corruption */ 02977 } 02978 02979 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 02980 02991 static int 02992 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) { 02993 int depth1, depth2; 02994 int misc = 0, precedence1 = 0, precedence2 = 0; 02995 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL; 02996 xmlNodePtr cur, root; 02997 long l1, l2; 02998 02999 if ((node1 == NULL) || (node2 == NULL)) 03000 return(-2); 03001 03002 if (node1 == node2) 03003 return(0); 03004 03005 /* 03006 * a couple of optimizations which will avoid computations in most cases 03007 */ 03008 switch (node1->type) { 03009 case XML_ELEMENT_NODE: 03010 if (node2->type == XML_ELEMENT_NODE) { 03011 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */ 03012 (0 > (long) node2->content) && 03013 (node1->doc == node2->doc)) 03014 { 03015 l1 = -((long) node1->content); 03016 l2 = -((long) node2->content); 03017 if (l1 < l2) 03018 return(1); 03019 if (l1 > l2) 03020 return(-1); 03021 } else 03022 goto turtle_comparison; 03023 } 03024 break; 03025 case XML_ATTRIBUTE_NODE: 03026 precedence1 = 1; /* element is owner */ 03027 miscNode1 = node1; 03028 node1 = node1->parent; 03029 misc = 1; 03030 break; 03031 case XML_TEXT_NODE: 03032 case XML_CDATA_SECTION_NODE: 03033 case XML_COMMENT_NODE: 03034 case XML_PI_NODE: { 03035 miscNode1 = node1; 03036 /* 03037 * Find nearest element node. 03038 */ 03039 if (node1->prev != NULL) { 03040 do { 03041 node1 = node1->prev; 03042 if (node1->type == XML_ELEMENT_NODE) { 03043 precedence1 = 3; /* element in prev-sibl axis */ 03044 break; 03045 } 03046 if (node1->prev == NULL) { 03047 precedence1 = 2; /* element is parent */ 03048 /* 03049 * URGENT TODO: Are there any cases, where the 03050 * parent of such a node is not an element node? 03051 */ 03052 node1 = node1->parent; 03053 break; 03054 } 03055 } while (1); 03056 } else { 03057 precedence1 = 2; /* element is parent */ 03058 node1 = node1->parent; 03059 } 03060 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) || 03061 (0 <= (long) node1->content)) { 03062 /* 03063 * Fallback for whatever case. 03064 */ 03065 node1 = miscNode1; 03066 precedence1 = 0; 03067 } else 03068 misc = 1; 03069 } 03070 break; 03071 case XML_NAMESPACE_DECL: 03072 /* 03073 * TODO: why do we return 1 for namespace nodes? 03074 */ 03075 return(1); 03076 default: 03077 break; 03078 } 03079 switch (node2->type) { 03080 case XML_ELEMENT_NODE: 03081 break; 03082 case XML_ATTRIBUTE_NODE: 03083 precedence2 = 1; /* element is owner */ 03084 miscNode2 = node2; 03085 node2 = node2->parent; 03086 misc = 1; 03087 break; 03088 case XML_TEXT_NODE: 03089 case XML_CDATA_SECTION_NODE: 03090 case XML_COMMENT_NODE: 03091 case XML_PI_NODE: { 03092 miscNode2 = node2; 03093 if (node2->prev != NULL) { 03094 do { 03095 node2 = node2->prev; 03096 if (node2->type == XML_ELEMENT_NODE) { 03097 precedence2 = 3; /* element in prev-sibl axis */ 03098 break; 03099 } 03100 if (node2->prev == NULL) { 03101 precedence2 = 2; /* element is parent */ 03102 node2 = node2->parent; 03103 break; 03104 } 03105 } while (1); 03106 } else { 03107 precedence2 = 2; /* element is parent */ 03108 node2 = node2->parent; 03109 } 03110 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) || 03111 (0 <= (long) node1->content)) 03112 { 03113 node2 = miscNode2; 03114 precedence2 = 0; 03115 } else 03116 misc = 1; 03117 } 03118 break; 03119 case XML_NAMESPACE_DECL: 03120 return(1); 03121 default: 03122 break; 03123 } 03124 if (misc) { 03125 if (node1 == node2) { 03126 if (precedence1 == precedence2) { 03127 /* 03128 * The ugly case; but normally there aren't many 03129 * adjacent non-element nodes around. 03130 */ 03131 cur = miscNode2->prev; 03132 while (cur != NULL) { 03133 if (cur == miscNode1) 03134 return(1); 03135 if (cur->type == XML_ELEMENT_NODE) 03136 return(-1); 03137 cur = cur->prev; 03138 } 03139 return (-1); 03140 } else { 03141 /* 03142 * Evaluate based on higher precedence wrt to the element. 03143 * TODO: This assumes attributes are sorted before content. 03144 * Is this 100% correct? 03145 */ 03146 if (precedence1 < precedence2) 03147 return(1); 03148 else 03149 return(-1); 03150 } 03151 } 03152 /* 03153 * Special case: One of the helper-elements is contained by the other. 03154 * <foo> 03155 * <node2> 03156 * <node1>Text-1(precedence1 == 2)</node1> 03157 * </node2> 03158 * Text-6(precedence2 == 3) 03159 * </foo> 03160 */ 03161 if ((precedence2 == 3) && (precedence1 > 1)) { 03162 cur = node1->parent; 03163 while (cur) { 03164 if (cur == node2) 03165 return(1); 03166 cur = cur->parent; 03167 } 03168 } 03169 if ((precedence1 == 3) && (precedence2 > 1)) { 03170 cur = node2->parent; 03171 while (cur) { 03172 if (cur == node1) 03173 return(-1); 03174 cur = cur->parent; 03175 } 03176 } 03177 } 03178 03179 /* 03180 * Speedup using document order if availble. 03181 */ 03182 if ((node1->type == XML_ELEMENT_NODE) && 03183 (node2->type == XML_ELEMENT_NODE) && 03184 (0 > (long) node1->content) && 03185 (0 > (long) node2->content) && 03186 (node1->doc == node2->doc)) { 03187 03188 l1 = -((long) node1->content); 03189 l2 = -((long) node2->content); 03190 if (l1 < l2) 03191 return(1); 03192 if (l1 > l2) 03193 return(-1); 03194 } 03195 03196 turtle_comparison: 03197 03198 if (node1 == node2->prev) 03199 return(1); 03200 if (node1 == node2->next) 03201 return(-1); 03202 /* 03203 * compute depth to root 03204 */ 03205 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) { 03206 if (cur == node1) 03207 return(1); 03208 depth2++; 03209 } 03210 root = cur; 03211 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) { 03212 if (cur == node2) 03213 return(-1); 03214 depth1++; 03215 } 03216 /* 03217 * Distinct document (or distinct entities :-( ) case. 03218 */ 03219 if (root != cur) { 03220 return(-2); 03221 } 03222 /* 03223 * get the nearest common ancestor. 03224 */ 03225 while (depth1 > depth2) { 03226 depth1--; 03227 node1 = node1->parent; 03228 } 03229 while (depth2 > depth1) { 03230 depth2--; 03231 node2 = node2->parent; 03232 } 03233 while (node1->parent != node2->parent) { 03234 node1 = node1->parent; 03235 node2 = node2->parent; 03236 /* should not happen but just in case ... */ 03237 if ((node1 == NULL) || (node2 == NULL)) 03238 return(-2); 03239 } 03240 /* 03241 * Find who's first. 03242 */ 03243 if (node1 == node2->prev) 03244 return(1); 03245 if (node1 == node2->next) 03246 return(-1); 03247 /* 03248 * Speedup using document order if availble. 03249 */ 03250 if ((node1->type == XML_ELEMENT_NODE) && 03251 (node2->type == XML_ELEMENT_NODE) && 03252 (0 > (long) node1->content) && 03253 (0 > (long) node2->content) && 03254 (node1->doc == node2->doc)) { 03255 03256 l1 = -((long) node1->content); 03257 l2 = -((long) node2->content); 03258 if (l1 < l2) 03259 return(1); 03260 if (l1 > l2) 03261 return(-1); 03262 } 03263 03264 for (cur = node1->next;cur != NULL;cur = cur->next) 03265 if (cur == node2) 03266 return(1); 03267 return(-1); /* assume there is no sibling list corruption */ 03268 } 03269 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */ 03270 03277 void 03278 xmlXPathNodeSetSort(xmlNodeSetPtr set) { 03279 int i, j, incr, len; 03280 xmlNodePtr tmp; 03281 03282 if (set == NULL) 03283 return; 03284 03285 /* Use Shell's sort to sort the node-set */ 03286 len = set->nodeNr; 03287 for (incr = len / 2; incr > 0; incr /= 2) { 03288 for (i = incr; i < len; i++) { 03289 j = i - incr; 03290 while (j >= 0) { 03291 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 03292 if (xmlXPathCmpNodesExt(set->nodeTab[j], 03293 set->nodeTab[j + incr]) == -1) 03294 #else 03295 if (xmlXPathCmpNodes(set->nodeTab[j], 03296 set->nodeTab[j + incr]) == -1) 03297 #endif 03298 { 03299 tmp = set->nodeTab[j]; 03300 set->nodeTab[j] = set->nodeTab[j + incr]; 03301 set->nodeTab[j + incr] = tmp; 03302 j -= incr; 03303 } else 03304 break; 03305 } 03306 } 03307 } 03308 } 03309 03310 #define XML_NODESET_DEFAULT 10 03311 03322 static xmlNodePtr 03323 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) { 03324 xmlNsPtr cur; 03325 03326 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) 03327 return(NULL); 03328 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) 03329 return((xmlNodePtr) ns); 03330 03331 /* 03332 * Allocate a new Namespace and fill the fields. 03333 */ 03334 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); 03335 if (cur == NULL) { 03336 xmlXPathErrMemory(NULL, "duplicating namespace\n"); 03337 return(NULL); 03338 } 03339 memset(cur, 0, sizeof(xmlNs)); 03340 cur->type = XML_NAMESPACE_DECL; 03341 if (ns->href != NULL) 03342 cur->href = xmlStrdup(ns->href); 03343 if (ns->prefix != NULL) 03344 cur->prefix = xmlStrdup(ns->prefix); 03345 cur->next = (xmlNsPtr) node; 03346 return((xmlNodePtr) cur); 03347 } 03348 03357 void 03358 xmlXPathNodeSetFreeNs(xmlNsPtr ns) { 03359 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) 03360 return; 03361 03362 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) { 03363 if (ns->href != NULL) 03364 xmlFree((xmlChar *)ns->href); 03365 if (ns->prefix != NULL) 03366 xmlFree((xmlChar *)ns->prefix); 03367 xmlFree(ns); 03368 } 03369 } 03370 03379 xmlNodeSetPtr 03380 xmlXPathNodeSetCreate(xmlNodePtr val) { 03381 xmlNodeSetPtr ret; 03382 03383 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet)); 03384 if (ret == NULL) { 03385 xmlXPathErrMemory(NULL, "creating nodeset\n"); 03386 return(NULL); 03387 } 03388 memset(ret, 0 , (size_t) sizeof(xmlNodeSet)); 03389 if (val != NULL) { 03390 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 03391 sizeof(xmlNodePtr)); 03392 if (ret->nodeTab == NULL) { 03393 xmlXPathErrMemory(NULL, "creating nodeset\n"); 03394 xmlFree(ret); 03395 return(NULL); 03396 } 03397 memset(ret->nodeTab, 0 , 03398 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 03399 ret->nodeMax = XML_NODESET_DEFAULT; 03400 if (val->type == XML_NAMESPACE_DECL) { 03401 xmlNsPtr ns = (xmlNsPtr) val; 03402 03403 ret->nodeTab[ret->nodeNr++] = 03404 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 03405 } else 03406 ret->nodeTab[ret->nodeNr++] = val; 03407 } 03408 return(ret); 03409 } 03410 03419 static xmlNodeSetPtr 03420 xmlXPathNodeSetCreateSize(int size) { 03421 xmlNodeSetPtr ret; 03422 03423 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet)); 03424 if (ret == NULL) { 03425 xmlXPathErrMemory(NULL, "creating nodeset\n"); 03426 return(NULL); 03427 } 03428 memset(ret, 0 , (size_t) sizeof(xmlNodeSet)); 03429 if (size < XML_NODESET_DEFAULT) 03430 size = XML_NODESET_DEFAULT; 03431 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr)); 03432 if (ret->nodeTab == NULL) { 03433 xmlXPathErrMemory(NULL, "creating nodeset\n"); 03434 xmlFree(ret); 03435 return(NULL); 03436 } 03437 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr)); 03438 ret->nodeMax = size; 03439 return(ret); 03440 } 03441 03451 int 03452 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) { 03453 int i; 03454 03455 if ((cur == NULL) || (val == NULL)) return(0); 03456 if (val->type == XML_NAMESPACE_DECL) { 03457 for (i = 0; i < cur->nodeNr; i++) { 03458 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) { 03459 xmlNsPtr ns1, ns2; 03460 03461 ns1 = (xmlNsPtr) val; 03462 ns2 = (xmlNsPtr) cur->nodeTab[i]; 03463 if (ns1 == ns2) 03464 return(1); 03465 if ((ns1->next != NULL) && (ns2->next == ns1->next) && 03466 (xmlStrEqual(ns1->prefix, ns2->prefix))) 03467 return(1); 03468 } 03469 } 03470 } else { 03471 for (i = 0; i < cur->nodeNr; i++) { 03472 if (cur->nodeTab[i] == val) 03473 return(1); 03474 } 03475 } 03476 return(0); 03477 } 03478 03487 void 03488 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) { 03489 int i; 03490 03491 03492 if ((cur == NULL) || (ns == NULL) || (node == NULL) || 03493 (ns->type != XML_NAMESPACE_DECL) || 03494 (node->type != XML_ELEMENT_NODE)) 03495 return; 03496 03497 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 03498 /* 03499 * prevent duplicates 03500 */ 03501 for (i = 0;i < cur->nodeNr;i++) { 03502 if ((cur->nodeTab[i] != NULL) && 03503 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) && 03504 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) && 03505 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix))) 03506 return; 03507 } 03508 03509 /* 03510 * grow the nodeTab if needed 03511 */ 03512 if (cur->nodeMax == 0) { 03513 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 03514 sizeof(xmlNodePtr)); 03515 if (cur->nodeTab == NULL) { 03516 xmlXPathErrMemory(NULL, "growing nodeset\n"); 03517 return; 03518 } 03519 memset(cur->nodeTab, 0 , 03520 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 03521 cur->nodeMax = XML_NODESET_DEFAULT; 03522 } else if (cur->nodeNr == cur->nodeMax) { 03523 xmlNodePtr *temp; 03524 03525 cur->nodeMax *= 2; 03526 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 03527 sizeof(xmlNodePtr)); 03528 if (temp == NULL) { 03529 xmlXPathErrMemory(NULL, "growing nodeset\n"); 03530 return; 03531 } 03532 cur->nodeTab = temp; 03533 } 03534 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns); 03535 } 03536 03544 void 03545 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) { 03546 int i; 03547 03548 if ((cur == NULL) || (val == NULL)) return; 03549 03550 #if 0 03551 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' ')) 03552 return; /* an XSLT fake node */ 03553 #endif 03554 03555 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 03556 /* 03557 * prevent duplcates 03558 */ 03559 for (i = 0;i < cur->nodeNr;i++) 03560 if (cur->nodeTab[i] == val) return; 03561 03562 /* 03563 * grow the nodeTab if needed 03564 */ 03565 if (cur->nodeMax == 0) { 03566 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 03567 sizeof(xmlNodePtr)); 03568 if (cur->nodeTab == NULL) { 03569 xmlXPathErrMemory(NULL, "growing nodeset\n"); 03570 return; 03571 } 03572 memset(cur->nodeTab, 0 , 03573 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 03574 cur->nodeMax = XML_NODESET_DEFAULT; 03575 } else if (cur->nodeNr == cur->nodeMax) { 03576 xmlNodePtr *temp; 03577 03578 cur->nodeMax *= 2; 03579 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 03580 sizeof(xmlNodePtr)); 03581 if (temp == NULL) { 03582 xmlXPathErrMemory(NULL, "growing nodeset\n"); 03583 return; 03584 } 03585 cur->nodeTab = temp; 03586 } 03587 if (val->type == XML_NAMESPACE_DECL) { 03588 xmlNsPtr ns = (xmlNsPtr) val; 03589 03590 cur->nodeTab[cur->nodeNr++] = 03591 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 03592 } else 03593 cur->nodeTab[cur->nodeNr++] = val; 03594 } 03595 03604 void 03605 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) { 03606 if ((cur == NULL) || (val == NULL)) return; 03607 03608 #if 0 03609 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' ')) 03610 return; /* an XSLT fake node */ 03611 #endif 03612 03613 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 03614 /* 03615 * grow the nodeTab if needed 03616 */ 03617 if (cur->nodeMax == 0) { 03618 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 03619 sizeof(xmlNodePtr)); 03620 if (cur->nodeTab == NULL) { 03621 xmlXPathErrMemory(NULL, "growing nodeset\n"); 03622 return; 03623 } 03624 memset(cur->nodeTab, 0 , 03625 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 03626 cur->nodeMax = XML_NODESET_DEFAULT; 03627 } else if (cur->nodeNr == cur->nodeMax) { 03628 xmlNodePtr *temp; 03629 03630 cur->nodeMax *= 2; 03631 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 03632 sizeof(xmlNodePtr)); 03633 if (temp == NULL) { 03634 xmlXPathErrMemory(NULL, "growing nodeset\n"); 03635 return; 03636 } 03637 cur->nodeTab = temp; 03638 } 03639 if (val->type == XML_NAMESPACE_DECL) { 03640 xmlNsPtr ns = (xmlNsPtr) val; 03641 03642 cur->nodeTab[cur->nodeNr++] = 03643 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 03644 } else 03645 cur->nodeTab[cur->nodeNr++] = val; 03646 } 03647 03658 xmlNodeSetPtr 03659 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) { 03660 int i, j, initNr, skip; 03661 xmlNodePtr n1, n2; 03662 03663 if (val2 == NULL) return(val1); 03664 if (val1 == NULL) { 03665 val1 = xmlXPathNodeSetCreate(NULL); 03666 if (val1 == NULL) 03667 return (NULL); 03668 #if 0 03669 /* 03670 * TODO: The optimization won't work in every case, since 03671 * those nasty namespace nodes need to be added with 03672 * xmlXPathNodeSetDupNs() to the set; thus a pure 03673 * memcpy is not possible. 03674 * If there was a flag on the nodesetval, indicating that 03675 * some temporary nodes are in, that would be helpfull. 03676 */ 03677 /* 03678 * Optimization: Create an equally sized node-set 03679 * and memcpy the content. 03680 */ 03681 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr); 03682 if (val1 == NULL) 03683 return(NULL); 03684 if (val2->nodeNr != 0) { 03685 if (val2->nodeNr == 1) 03686 *(val1->nodeTab) = *(val2->nodeTab); 03687 else { 03688 memcpy(val1->nodeTab, val2->nodeTab, 03689 val2->nodeNr * sizeof(xmlNodePtr)); 03690 } 03691 val1->nodeNr = val2->nodeNr; 03692 } 03693 return(val1); 03694 #endif 03695 } 03696 03697 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 03698 initNr = val1->nodeNr; 03699 03700 for (i = 0;i < val2->nodeNr;i++) { 03701 n2 = val2->nodeTab[i]; 03702 /* 03703 * check against duplicates 03704 */ 03705 skip = 0; 03706 for (j = 0; j < initNr; j++) { 03707 n1 = val1->nodeTab[j]; 03708 if (n1 == n2) { 03709 skip = 1; 03710 break; 03711 } else if ((n1->type == XML_NAMESPACE_DECL) && 03712 (n2->type == XML_NAMESPACE_DECL)) { 03713 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) && 03714 (xmlStrEqual(((xmlNsPtr) n1)->prefix, 03715 ((xmlNsPtr) n2)->prefix))) 03716 { 03717 skip = 1; 03718 break; 03719 } 03720 } 03721 } 03722 if (skip) 03723 continue; 03724 03725 /* 03726 * grow the nodeTab if needed 03727 */ 03728 if (val1->nodeMax == 0) { 03729 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 03730 sizeof(xmlNodePtr)); 03731 if (val1->nodeTab == NULL) { 03732 xmlXPathErrMemory(NULL, "merging nodeset\n"); 03733 return(NULL); 03734 } 03735 memset(val1->nodeTab, 0 , 03736 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 03737 val1->nodeMax = XML_NODESET_DEFAULT; 03738 } else if (val1->nodeNr == val1->nodeMax) { 03739 xmlNodePtr *temp; 03740 03741 val1->nodeMax *= 2; 03742 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 03743 sizeof(xmlNodePtr)); 03744 if (temp == NULL) { 03745 xmlXPathErrMemory(NULL, "merging nodeset\n"); 03746 return(NULL); 03747 } 03748 val1->nodeTab = temp; 03749 } 03750 if (n2->type == XML_NAMESPACE_DECL) { 03751 xmlNsPtr ns = (xmlNsPtr) n2; 03752 03753 val1->nodeTab[val1->nodeNr++] = 03754 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 03755 } else 03756 val1->nodeTab[val1->nodeNr++] = n2; 03757 } 03758 03759 return(val1); 03760 } 03761 03762 #if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */ 03763 03773 static xmlNodeSetPtr 03774 xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) { 03775 int i; 03776 03777 if (val2 == NULL) return(val1); 03778 if (val1 == NULL) { 03779 val1 = xmlXPathNodeSetCreate(NULL); 03780 } 03781 if (val1 == NULL) 03782 return (NULL); 03783 03784 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 03785 03786 for (i = 0;i < val2->nodeNr;i++) { 03787 /* 03788 * grow the nodeTab if needed 03789 */ 03790 if (val1->nodeMax == 0) { 03791 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 03792 sizeof(xmlNodePtr)); 03793 if (val1->nodeTab == NULL) { 03794 xmlXPathErrMemory(NULL, "merging nodeset\n"); 03795 return(NULL); 03796 } 03797 memset(val1->nodeTab, 0 , 03798 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 03799 val1->nodeMax = XML_NODESET_DEFAULT; 03800 } else if (val1->nodeNr == val1->nodeMax) { 03801 xmlNodePtr *temp; 03802 03803 val1->nodeMax *= 2; 03804 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 03805 sizeof(xmlNodePtr)); 03806 if (temp == NULL) { 03807 xmlXPathErrMemory(NULL, "merging nodeset\n"); 03808 return(NULL); 03809 } 03810 val1->nodeTab = temp; 03811 } 03812 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) { 03813 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i]; 03814 03815 val1->nodeTab[val1->nodeNr++] = 03816 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 03817 } else 03818 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i]; 03819 } 03820 03821 return(val1); 03822 } 03823 #endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */ 03824 03837 static xmlNodeSetPtr 03838 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2, 03839 int hasNullEntries) 03840 { 03841 if ((set1 == NULL) && (hasNullEntries == 0)) { 03842 /* 03843 * Note that doing a memcpy of the list, namespace nodes are 03844 * just assigned to set1, since set2 is cleared anyway. 03845 */ 03846 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr); 03847 if (set1 == NULL) 03848 return(NULL); 03849 if (set2->nodeNr != 0) { 03850 memcpy(set1->nodeTab, set2->nodeTab, 03851 set2->nodeNr * sizeof(xmlNodePtr)); 03852 set1->nodeNr = set2->nodeNr; 03853 } 03854 } else { 03855 int i, j, initNbSet1; 03856 xmlNodePtr n1, n2; 03857 03858 if (set1 == NULL) 03859 set1 = xmlXPathNodeSetCreate(NULL); 03860 if (set1 == NULL) 03861 return (NULL); 03862 03863 initNbSet1 = set1->nodeNr; 03864 for (i = 0;i < set2->nodeNr;i++) { 03865 n2 = set2->nodeTab[i]; 03866 /* 03867 * Skip NULLed entries. 03868 */ 03869 if (n2 == NULL) 03870 continue; 03871 /* 03872 * Skip duplicates. 03873 */ 03874 for (j = 0; j < initNbSet1; j++) { 03875 n1 = set1->nodeTab[j]; 03876 if (n1 == n2) { 03877 goto skip_node; 03878 } else if ((n1->type == XML_NAMESPACE_DECL) && 03879 (n2->type == XML_NAMESPACE_DECL)) 03880 { 03881 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) && 03882 (xmlStrEqual(((xmlNsPtr) n1)->prefix, 03883 ((xmlNsPtr) n2)->prefix))) 03884 { 03885 /* 03886 * Free the namespace node. 03887 */ 03888 set2->nodeTab[i] = NULL; 03889 xmlXPathNodeSetFreeNs((xmlNsPtr) n2); 03890 goto skip_node; 03891 } 03892 } 03893 } 03894 /* 03895 * grow the nodeTab if needed 03896 */ 03897 if (set1->nodeMax == 0) { 03898 set1->nodeTab = (xmlNodePtr *) xmlMalloc( 03899 XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); 03900 if (set1->nodeTab == NULL) { 03901 xmlXPathErrMemory(NULL, "merging nodeset\n"); 03902 return(NULL); 03903 } 03904 memset(set1->nodeTab, 0, 03905 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 03906 set1->nodeMax = XML_NODESET_DEFAULT; 03907 } else if (set1->nodeNr >= set1->nodeMax) { 03908 xmlNodePtr *temp; 03909 03910 set1->nodeMax *= 2; 03911 temp = (xmlNodePtr *) xmlRealloc( 03912 set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr)); 03913 if (temp == NULL) { 03914 xmlXPathErrMemory(NULL, "merging nodeset\n"); 03915 return(NULL); 03916 } 03917 set1->nodeTab = temp; 03918 } 03919 if (n2->type == XML_NAMESPACE_DECL) { 03920 xmlNsPtr ns = (xmlNsPtr) n2; 03921 03922 set1->nodeTab[set1->nodeNr++] = 03923 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 03924 } else 03925 set1->nodeTab[set1->nodeNr++] = n2; 03926 skip_node: 03927 {} 03928 } 03929 } 03930 set2->nodeNr = 0; 03931 return(set1); 03932 } 03933 03946 static xmlNodeSetPtr 03947 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2, 03948 int hasNullEntries) 03949 { 03950 if (set2 == NULL) 03951 return(set1); 03952 if ((set1 == NULL) && (hasNullEntries == 0)) { 03953 /* 03954 * Note that doing a memcpy of the list, namespace nodes are 03955 * just assigned to set1, since set2 is cleared anyway. 03956 */ 03957 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr); 03958 if (set1 == NULL) 03959 return(NULL); 03960 if (set2->nodeNr != 0) { 03961 memcpy(set1->nodeTab, set2->nodeTab, 03962 set2->nodeNr * sizeof(xmlNodePtr)); 03963 set1->nodeNr = set2->nodeNr; 03964 } 03965 } else { 03966 int i; 03967 xmlNodePtr n2; 03968 03969 if (set1 == NULL) 03970 set1 = xmlXPathNodeSetCreate(NULL); 03971 if (set1 == NULL) 03972 return (NULL); 03973 03974 for (i = 0;i < set2->nodeNr;i++) { 03975 n2 = set2->nodeTab[i]; 03976 /* 03977 * Skip NULLed entries. 03978 */ 03979 if (n2 == NULL) 03980 continue; 03981 if (set1->nodeMax == 0) { 03982 set1->nodeTab = (xmlNodePtr *) xmlMalloc( 03983 XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); 03984 if (set1->nodeTab == NULL) { 03985 xmlXPathErrMemory(NULL, "merging nodeset\n"); 03986 return(NULL); 03987 } 03988 memset(set1->nodeTab, 0, 03989 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 03990 set1->nodeMax = XML_NODESET_DEFAULT; 03991 } else if (set1->nodeNr >= set1->nodeMax) { 03992 xmlNodePtr *temp; 03993 03994 set1->nodeMax *= 2; 03995 temp = (xmlNodePtr *) xmlRealloc( 03996 set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr)); 03997 if (temp == NULL) { 03998 xmlXPathErrMemory(NULL, "merging nodeset\n"); 03999 return(NULL); 04000 } 04001 set1->nodeTab = temp; 04002 } 04003 set1->nodeTab[set1->nodeNr++] = n2; 04004 } 04005 } 04006 set2->nodeNr = 0; 04007 return(set1); 04008 } 04009 04017 void 04018 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) { 04019 int i; 04020 04021 if (cur == NULL) return; 04022 if (val == NULL) return; 04023 04024 /* 04025 * find node in nodeTab 04026 */ 04027 for (i = 0;i < cur->nodeNr;i++) 04028 if (cur->nodeTab[i] == val) break; 04029 04030 if (i >= cur->nodeNr) { /* not found */ 04031 #ifdef DEBUG 04032 xmlGenericError(xmlGenericErrorContext, 04033 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n", 04034 val->name); 04035 #endif 04036 return; 04037 } 04038 if ((cur->nodeTab[i] != NULL) && 04039 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL)) 04040 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]); 04041 cur->nodeNr--; 04042 for (;i < cur->nodeNr;i++) 04043 cur->nodeTab[i] = cur->nodeTab[i + 1]; 04044 cur->nodeTab[cur->nodeNr] = NULL; 04045 } 04046 04054 void 04055 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) { 04056 if (cur == NULL) return; 04057 if (val >= cur->nodeNr) return; 04058 if ((cur->nodeTab[val] != NULL) && 04059 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL)) 04060 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]); 04061 cur->nodeNr--; 04062 for (;val < cur->nodeNr;val++) 04063 cur->nodeTab[val] = cur->nodeTab[val + 1]; 04064 cur->nodeTab[cur->nodeNr] = NULL; 04065 } 04066 04073 void 04074 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) { 04075 if (obj == NULL) return; 04076 if (obj->nodeTab != NULL) { 04077 int i; 04078 04079 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 04080 for (i = 0;i < obj->nodeNr;i++) 04081 if ((obj->nodeTab[i] != NULL) && 04082 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL)) 04083 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]); 04084 xmlFree(obj->nodeTab); 04085 } 04086 xmlFree(obj); 04087 } 04088 04097 static void 04098 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes) 04099 { 04100 if ((set == NULL) || (set->nodeNr <= 0)) 04101 return; 04102 else if (hasNsNodes) { 04103 int i; 04104 xmlNodePtr node; 04105 04106 for (i = 0; i < set->nodeNr; i++) { 04107 node = set->nodeTab[i]; 04108 if ((node != NULL) && 04109 (node->type == XML_NAMESPACE_DECL)) 04110 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 04111 } 04112 } 04113 set->nodeNr = 0; 04114 } 04115 04125 static void 04126 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes) 04127 { 04128 if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr)) 04129 return; 04130 else if ((hasNsNodes)) { 04131 int i; 04132 xmlNodePtr node; 04133 04134 for (i = pos; i < set->nodeNr; i++) { 04135 node = set->nodeTab[i]; 04136 if ((node != NULL) && 04137 (node->type == XML_NAMESPACE_DECL)) 04138 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 04139 } 04140 } 04141 set->nodeNr = pos; 04142 } 04143 04151 static void 04152 xmlXPathFreeValueTree(xmlNodeSetPtr obj) { 04153 int i; 04154 04155 if (obj == NULL) return; 04156 04157 if (obj->nodeTab != NULL) { 04158 for (i = 0;i < obj->nodeNr;i++) { 04159 if (obj->nodeTab[i] != NULL) { 04160 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) { 04161 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]); 04162 } else { 04163 xmlFreeNodeList(obj->nodeTab[i]); 04164 } 04165 } 04166 } 04167 xmlFree(obj->nodeTab); 04168 } 04169 xmlFree(obj); 04170 } 04171 04172 #if defined(DEBUG) || defined(DEBUG_STEP) 04173 04180 void 04181 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) { 04182 int i; 04183 04184 if (output == NULL) output = xmlGenericErrorContext; 04185 if (obj == NULL) { 04186 fprintf(output, "NodeSet == NULL !\n"); 04187 return; 04188 } 04189 if (obj->nodeNr == 0) { 04190 fprintf(output, "NodeSet is empty\n"); 04191 return; 04192 } 04193 if (obj->nodeTab == NULL) { 04194 fprintf(output, " nodeTab == NULL !\n"); 04195 return; 04196 } 04197 for (i = 0; i < obj->nodeNr; i++) { 04198 if (obj->nodeTab[i] == NULL) { 04199 fprintf(output, " NULL !\n"); 04200 return; 04201 } 04202 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) || 04203 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE)) 04204 fprintf(output, " /"); 04205 else if (obj->nodeTab[i]->name == NULL) 04206 fprintf(output, " noname!"); 04207 else fprintf(output, " %s", obj->nodeTab[i]->name); 04208 } 04209 fprintf(output, "\n"); 04210 } 04211 #endif 04212 04222 xmlXPathObjectPtr 04223 xmlXPathNewNodeSet(xmlNodePtr val) { 04224 xmlXPathObjectPtr ret; 04225 04226 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 04227 if (ret == NULL) { 04228 xmlXPathErrMemory(NULL, "creating nodeset\n"); 04229 return(NULL); 04230 } 04231 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 04232 ret->type = XPATH_NODESET; 04233 ret->boolval = 0; 04234 ret->nodesetval = xmlXPathNodeSetCreate(val); 04235 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 04236 #ifdef XP_DEBUG_OBJ_USAGE 04237 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET); 04238 #endif 04239 return(ret); 04240 } 04241 04251 xmlXPathObjectPtr 04252 xmlXPathNewValueTree(xmlNodePtr val) { 04253 xmlXPathObjectPtr ret; 04254 04255 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 04256 if (ret == NULL) { 04257 xmlXPathErrMemory(NULL, "creating result value tree\n"); 04258 return(NULL); 04259 } 04260 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 04261 ret->type = XPATH_XSLT_TREE; 04262 ret->boolval = 1; 04263 ret->user = (void *) val; 04264 ret->nodesetval = xmlXPathNodeSetCreate(val); 04265 #ifdef XP_DEBUG_OBJ_USAGE 04266 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE); 04267 #endif 04268 return(ret); 04269 } 04270 04280 xmlXPathObjectPtr 04281 xmlXPathNewNodeSetList(xmlNodeSetPtr val) 04282 { 04283 xmlXPathObjectPtr ret; 04284 int i; 04285 04286 if (val == NULL) 04287 ret = NULL; 04288 else if (val->nodeTab == NULL) 04289 ret = xmlXPathNewNodeSet(NULL); 04290 else { 04291 ret = xmlXPathNewNodeSet(val->nodeTab[0]); 04292 if (ret) 04293 for (i = 1; i < val->nodeNr; ++i) 04294 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]); 04295 } 04296 04297 return (ret); 04298 } 04299 04308 xmlXPathObjectPtr 04309 xmlXPathWrapNodeSet(xmlNodeSetPtr val) { 04310 xmlXPathObjectPtr ret; 04311 04312 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 04313 if (ret == NULL) { 04314 xmlXPathErrMemory(NULL, "creating node set object\n"); 04315 return(NULL); 04316 } 04317 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 04318 ret->type = XPATH_NODESET; 04319 ret->nodesetval = val; 04320 #ifdef XP_DEBUG_OBJ_USAGE 04321 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET); 04322 #endif 04323 return(ret); 04324 } 04325 04333 void 04334 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) { 04335 if (obj == NULL) return; 04336 #ifdef XP_DEBUG_OBJ_USAGE 04337 xmlXPathDebugObjUsageReleased(NULL, obj->type); 04338 #endif 04339 xmlFree(obj); 04340 } 04341 04353 xmlNodeSetPtr 04354 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 04355 xmlNodeSetPtr ret; 04356 int i, l1; 04357 xmlNodePtr cur; 04358 04359 if (xmlXPathNodeSetIsEmpty(nodes2)) 04360 return(nodes1); 04361 04362 ret = xmlXPathNodeSetCreate(NULL); 04363 if (xmlXPathNodeSetIsEmpty(nodes1)) 04364 return(ret); 04365 04366 l1 = xmlXPathNodeSetGetLength(nodes1); 04367 04368 for (i = 0; i < l1; i++) { 04369 cur = xmlXPathNodeSetItem(nodes1, i); 04370 if (!xmlXPathNodeSetContains(nodes2, cur)) 04371 xmlXPathNodeSetAddUnique(ret, cur); 04372 } 04373 return(ret); 04374 } 04375 04387 xmlNodeSetPtr 04388 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 04389 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL); 04390 int i, l1; 04391 xmlNodePtr cur; 04392 04393 if (ret == NULL) 04394 return(ret); 04395 if (xmlXPathNodeSetIsEmpty(nodes1)) 04396 return(ret); 04397 if (xmlXPathNodeSetIsEmpty(nodes2)) 04398 return(ret); 04399 04400 l1 = xmlXPathNodeSetGetLength(nodes1); 04401 04402 for (i = 0; i < l1; i++) { 04403 cur = xmlXPathNodeSetItem(nodes1, i); 04404 if (xmlXPathNodeSetContains(nodes2, cur)) 04405 xmlXPathNodeSetAddUnique(ret, cur); 04406 } 04407 return(ret); 04408 } 04409 04420 xmlNodeSetPtr 04421 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) { 04422 xmlNodeSetPtr ret; 04423 xmlHashTablePtr hash; 04424 int i, l; 04425 xmlChar * strval; 04426 xmlNodePtr cur; 04427 04428 if (xmlXPathNodeSetIsEmpty(nodes)) 04429 return(nodes); 04430 04431 ret = xmlXPathNodeSetCreate(NULL); 04432 if (ret == NULL) 04433 return(ret); 04434 l = xmlXPathNodeSetGetLength(nodes); 04435 hash = xmlHashCreate (l); 04436 for (i = 0; i < l; i++) { 04437 cur = xmlXPathNodeSetItem(nodes, i); 04438 strval = xmlXPathCastNodeToString(cur); 04439 if (xmlHashLookup(hash, strval) == NULL) { 04440 xmlHashAddEntry(hash, strval, strval); 04441 xmlXPathNodeSetAddUnique(ret, cur); 04442 } else { 04443 xmlFree(strval); 04444 } 04445 } 04446 xmlHashFree(hash, (xmlHashDeallocator) xmlFree); 04447 return(ret); 04448 } 04449 04462 xmlNodeSetPtr 04463 xmlXPathDistinct (xmlNodeSetPtr nodes) { 04464 if (xmlXPathNodeSetIsEmpty(nodes)) 04465 return(nodes); 04466 04467 xmlXPathNodeSetSort(nodes); 04468 return(xmlXPathDistinctSorted(nodes)); 04469 } 04470 04482 int 04483 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 04484 int i, l; 04485 xmlNodePtr cur; 04486 04487 if (xmlXPathNodeSetIsEmpty(nodes1) || 04488 xmlXPathNodeSetIsEmpty(nodes2)) 04489 return(0); 04490 04491 l = xmlXPathNodeSetGetLength(nodes1); 04492 for (i = 0; i < l; i++) { 04493 cur = xmlXPathNodeSetItem(nodes1, i); 04494 if (xmlXPathNodeSetContains(nodes2, cur)) 04495 return(1); 04496 } 04497 return(0); 04498 } 04499 04512 xmlNodeSetPtr 04513 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { 04514 int i, l; 04515 xmlNodePtr cur; 04516 xmlNodeSetPtr ret; 04517 04518 if (node == NULL) 04519 return(nodes); 04520 04521 ret = xmlXPathNodeSetCreate(NULL); 04522 if (ret == NULL) 04523 return(ret); 04524 if (xmlXPathNodeSetIsEmpty(nodes) || 04525 (!xmlXPathNodeSetContains(nodes, node))) 04526 return(ret); 04527 04528 l = xmlXPathNodeSetGetLength(nodes); 04529 for (i = 0; i < l; i++) { 04530 cur = xmlXPathNodeSetItem(nodes, i); 04531 if (cur == node) 04532 break; 04533 xmlXPathNodeSetAddUnique(ret, cur); 04534 } 04535 return(ret); 04536 } 04537 04552 xmlNodeSetPtr 04553 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) { 04554 xmlXPathNodeSetSort(nodes); 04555 return(xmlXPathNodeLeadingSorted(nodes, node)); 04556 } 04557 04570 xmlNodeSetPtr 04571 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 04572 if (xmlXPathNodeSetIsEmpty(nodes2)) 04573 return(nodes1); 04574 return(xmlXPathNodeLeadingSorted(nodes1, 04575 xmlXPathNodeSetItem(nodes2, 1))); 04576 } 04577 04592 xmlNodeSetPtr 04593 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 04594 if (xmlXPathNodeSetIsEmpty(nodes2)) 04595 return(nodes1); 04596 if (xmlXPathNodeSetIsEmpty(nodes1)) 04597 return(xmlXPathNodeSetCreate(NULL)); 04598 xmlXPathNodeSetSort(nodes1); 04599 xmlXPathNodeSetSort(nodes2); 04600 return(xmlXPathNodeLeadingSorted(nodes1, 04601 xmlXPathNodeSetItem(nodes2, 1))); 04602 } 04603 04616 xmlNodeSetPtr 04617 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { 04618 int i, l; 04619 xmlNodePtr cur; 04620 xmlNodeSetPtr ret; 04621 04622 if (node == NULL) 04623 return(nodes); 04624 04625 ret = xmlXPathNodeSetCreate(NULL); 04626 if (ret == NULL) 04627 return(ret); 04628 if (xmlXPathNodeSetIsEmpty(nodes) || 04629 (!xmlXPathNodeSetContains(nodes, node))) 04630 return(ret); 04631 04632 l = xmlXPathNodeSetGetLength(nodes); 04633 for (i = l - 1; i >= 0; i--) { 04634 cur = xmlXPathNodeSetItem(nodes, i); 04635 if (cur == node) 04636 break; 04637 xmlXPathNodeSetAddUnique(ret, cur); 04638 } 04639 xmlXPathNodeSetSort(ret); /* bug 413451 */ 04640 return(ret); 04641 } 04642 04657 xmlNodeSetPtr 04658 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) { 04659 xmlXPathNodeSetSort(nodes); 04660 return(xmlXPathNodeTrailingSorted(nodes, node)); 04661 } 04662 04675 xmlNodeSetPtr 04676 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 04677 if (xmlXPathNodeSetIsEmpty(nodes2)) 04678 return(nodes1); 04679 return(xmlXPathNodeTrailingSorted(nodes1, 04680 xmlXPathNodeSetItem(nodes2, 0))); 04681 } 04682 04697 xmlNodeSetPtr 04698 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 04699 if (xmlXPathNodeSetIsEmpty(nodes2)) 04700 return(nodes1); 04701 if (xmlXPathNodeSetIsEmpty(nodes1)) 04702 return(xmlXPathNodeSetCreate(NULL)); 04703 xmlXPathNodeSetSort(nodes1); 04704 xmlXPathNodeSetSort(nodes2); 04705 return(xmlXPathNodeTrailingSorted(nodes1, 04706 xmlXPathNodeSetItem(nodes2, 0))); 04707 } 04708 04709 /************************************************************************ 04710 * * 04711 * Routines to handle extra functions * 04712 * * 04713 ************************************************************************/ 04714 04725 int 04726 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name, 04727 xmlXPathFunction f) { 04728 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f)); 04729 } 04730 04742 int 04743 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name, 04744 const xmlChar *ns_uri, xmlXPathFunction f) { 04745 if (ctxt == NULL) 04746 return(-1); 04747 if (name == NULL) 04748 return(-1); 04749 04750 if (ctxt->funcHash == NULL) 04751 ctxt->funcHash = xmlHashCreate(0); 04752 if (ctxt->funcHash == NULL) 04753 return(-1); 04754 if (f == NULL) 04755 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL)); 04756 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f))); 04757 } 04758 04767 void 04768 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt, 04769 xmlXPathFuncLookupFunc f, 04770 void *funcCtxt) { 04771 if (ctxt == NULL) 04772 return; 04773 ctxt->funcLookupFunc = f; 04774 ctxt->funcLookupData = funcCtxt; 04775 } 04776 04787 xmlXPathFunction 04788 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { 04789 if (ctxt == NULL) 04790 return (NULL); 04791 04792 if (ctxt->funcLookupFunc != NULL) { 04793 xmlXPathFunction ret; 04794 xmlXPathFuncLookupFunc f; 04795 04796 f = ctxt->funcLookupFunc; 04797 ret = f(ctxt->funcLookupData, name, NULL); 04798 if (ret != NULL) 04799 return(ret); 04800 } 04801 return(xmlXPathFunctionLookupNS(ctxt, name, NULL)); 04802 } 04803 04815 xmlXPathFunction 04816 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name, 04817 const xmlChar *ns_uri) { 04818 xmlXPathFunction ret; 04819 04820 if (ctxt == NULL) 04821 return(NULL); 04822 if (name == NULL) 04823 return(NULL); 04824 04825 if (ctxt->funcLookupFunc != NULL) { 04826 xmlXPathFuncLookupFunc f; 04827 04828 f = ctxt->funcLookupFunc; 04829 ret = f(ctxt->funcLookupData, name, ns_uri); 04830 if (ret != NULL) 04831 return(ret); 04832 } 04833 04834 if (ctxt->funcHash == NULL) 04835 return(NULL); 04836 04837 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri); 04838 return(ret); 04839 } 04840 04847 void 04848 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) { 04849 if (ctxt == NULL) 04850 return; 04851 04852 xmlHashFree(ctxt->funcHash, NULL); 04853 ctxt->funcHash = NULL; 04854 } 04855 04856 /************************************************************************ 04857 * * 04858 * Routines to handle Variables * 04859 * * 04860 ************************************************************************/ 04861 04873 int 04874 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name, 04875 xmlXPathObjectPtr value) { 04876 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value)); 04877 } 04878 04891 int 04892 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name, 04893 const xmlChar *ns_uri, 04894 xmlXPathObjectPtr value) { 04895 if (ctxt == NULL) 04896 return(-1); 04897 if (name == NULL) 04898 return(-1); 04899 04900 if (ctxt->varHash == NULL) 04901 ctxt->varHash = xmlHashCreate(0); 04902 if (ctxt->varHash == NULL) 04903 return(-1); 04904 if (value == NULL) 04905 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri, 04906 (xmlHashDeallocator)xmlXPathFreeObject)); 04907 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri, 04908 (void *) value, 04909 (xmlHashDeallocator)xmlXPathFreeObject)); 04910 } 04911 04920 void 04921 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt, 04922 xmlXPathVariableLookupFunc f, void *data) { 04923 if (ctxt == NULL) 04924 return; 04925 ctxt->varLookupFunc = f; 04926 ctxt->varLookupData = data; 04927 } 04928 04939 xmlXPathObjectPtr 04940 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { 04941 if (ctxt == NULL) 04942 return(NULL); 04943 04944 if (ctxt->varLookupFunc != NULL) { 04945 xmlXPathObjectPtr ret; 04946 04947 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc) 04948 (ctxt->varLookupData, name, NULL); 04949 return(ret); 04950 } 04951 return(xmlXPathVariableLookupNS(ctxt, name, NULL)); 04952 } 04953 04965 xmlXPathObjectPtr 04966 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name, 04967 const xmlChar *ns_uri) { 04968 if (ctxt == NULL) 04969 return(NULL); 04970 04971 if (ctxt->varLookupFunc != NULL) { 04972 xmlXPathObjectPtr ret; 04973 04974 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc) 04975 (ctxt->varLookupData, name, ns_uri); 04976 if (ret != NULL) return(ret); 04977 } 04978 04979 if (ctxt->varHash == NULL) 04980 return(NULL); 04981 if (name == NULL) 04982 return(NULL); 04983 04984 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr) 04985 xmlHashLookup2(ctxt->varHash, name, ns_uri))); 04986 } 04987 04994 void 04995 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) { 04996 if (ctxt == NULL) 04997 return; 04998 04999 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject); 05000 ctxt->varHash = NULL; 05001 } 05002 05014 int 05015 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix, 05016 const xmlChar *ns_uri) { 05017 if (ctxt == NULL) 05018 return(-1); 05019 if (prefix == NULL) 05020 return(-1); 05021 if (prefix[0] == 0) 05022 return(-1); 05023 05024 if (ctxt->nsHash == NULL) 05025 ctxt->nsHash = xmlHashCreate(10); 05026 if (ctxt->nsHash == NULL) 05027 return(-1); 05028 if (ns_uri == NULL) 05029 return(xmlHashRemoveEntry(ctxt->nsHash, prefix, 05030 (xmlHashDeallocator)xmlFree)); 05031 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri), 05032 (xmlHashDeallocator)xmlFree)); 05033 } 05034 05045 const xmlChar * 05046 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) { 05047 if (ctxt == NULL) 05048 return(NULL); 05049 if (prefix == NULL) 05050 return(NULL); 05051 05052 #ifdef XML_XML_NAMESPACE 05053 if (xmlStrEqual(prefix, (const xmlChar *) "xml")) 05054 return(XML_XML_NAMESPACE); 05055 #endif 05056 05057 if (ctxt->namespaces != NULL) { 05058 int i; 05059 05060 for (i = 0;i < ctxt->nsNr;i++) { 05061 if ((ctxt->namespaces[i] != NULL) && 05062 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix))) 05063 return(ctxt->namespaces[i]->href); 05064 } 05065 } 05066 05067 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix)); 05068 } 05069 05076 void 05077 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) { 05078 if (ctxt == NULL) 05079 return; 05080 05081 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree); 05082 ctxt->nsHash = NULL; 05083 } 05084 05085 /************************************************************************ 05086 * * 05087 * Routines to handle Values * 05088 * * 05089 ************************************************************************/ 05090 05091 /* Allocations are terrible, one needs to optimize all this !!! */ 05092 05101 xmlXPathObjectPtr 05102 xmlXPathNewFloat(double val) { 05103 xmlXPathObjectPtr ret; 05104 05105 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 05106 if (ret == NULL) { 05107 xmlXPathErrMemory(NULL, "creating float object\n"); 05108 return(NULL); 05109 } 05110 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 05111 ret->type = XPATH_NUMBER; 05112 ret->floatval = val; 05113 #ifdef XP_DEBUG_OBJ_USAGE 05114 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER); 05115 #endif 05116 return(ret); 05117 } 05118 05127 xmlXPathObjectPtr 05128 xmlXPathNewBoolean(int val) { 05129 xmlXPathObjectPtr ret; 05130 05131 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 05132 if (ret == NULL) { 05133 xmlXPathErrMemory(NULL, "creating boolean object\n"); 05134 return(NULL); 05135 } 05136 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 05137 ret->type = XPATH_BOOLEAN; 05138 ret->boolval = (val != 0); 05139 #ifdef XP_DEBUG_OBJ_USAGE 05140 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN); 05141 #endif 05142 return(ret); 05143 } 05144 05153 xmlXPathObjectPtr 05154 xmlXPathNewString(const xmlChar *val) { 05155 xmlXPathObjectPtr ret; 05156 05157 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 05158 if (ret == NULL) { 05159 xmlXPathErrMemory(NULL, "creating string object\n"); 05160 return(NULL); 05161 } 05162 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 05163 ret->type = XPATH_STRING; 05164 if (val != NULL) 05165 ret->stringval = xmlStrdup(val); 05166 else 05167 ret->stringval = xmlStrdup((const xmlChar *)""); 05168 #ifdef XP_DEBUG_OBJ_USAGE 05169 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); 05170 #endif 05171 return(ret); 05172 } 05173 05182 xmlXPathObjectPtr 05183 xmlXPathWrapString (xmlChar *val) { 05184 xmlXPathObjectPtr ret; 05185 05186 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 05187 if (ret == NULL) { 05188 xmlXPathErrMemory(NULL, "creating string object\n"); 05189 return(NULL); 05190 } 05191 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 05192 ret->type = XPATH_STRING; 05193 ret->stringval = val; 05194 #ifdef XP_DEBUG_OBJ_USAGE 05195 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); 05196 #endif 05197 return(ret); 05198 } 05199 05208 xmlXPathObjectPtr 05209 xmlXPathNewCString(const char *val) { 05210 xmlXPathObjectPtr ret; 05211 05212 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 05213 if (ret == NULL) { 05214 xmlXPathErrMemory(NULL, "creating string object\n"); 05215 return(NULL); 05216 } 05217 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 05218 ret->type = XPATH_STRING; 05219 ret->stringval = xmlStrdup(BAD_CAST val); 05220 #ifdef XP_DEBUG_OBJ_USAGE 05221 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); 05222 #endif 05223 return(ret); 05224 } 05225 05234 xmlXPathObjectPtr 05235 xmlXPathWrapCString (char * val) { 05236 return(xmlXPathWrapString((xmlChar *)(val))); 05237 } 05238 05247 xmlXPathObjectPtr 05248 xmlXPathWrapExternal (void *val) { 05249 xmlXPathObjectPtr ret; 05250 05251 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 05252 if (ret == NULL) { 05253 xmlXPathErrMemory(NULL, "creating user object\n"); 05254 return(NULL); 05255 } 05256 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 05257 ret->type = XPATH_USERS; 05258 ret->user = val; 05259 #ifdef XP_DEBUG_OBJ_USAGE 05260 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS); 05261 #endif 05262 return(ret); 05263 } 05264 05273 xmlXPathObjectPtr 05274 xmlXPathObjectCopy(xmlXPathObjectPtr val) { 05275 xmlXPathObjectPtr ret; 05276 05277 if (val == NULL) 05278 return(NULL); 05279 05280 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 05281 if (ret == NULL) { 05282 xmlXPathErrMemory(NULL, "copying object\n"); 05283 return(NULL); 05284 } 05285 memcpy(ret, val , (size_t) sizeof(xmlXPathObject)); 05286 #ifdef XP_DEBUG_OBJ_USAGE 05287 xmlXPathDebugObjUsageRequested(NULL, val->type); 05288 #endif 05289 switch (val->type) { 05290 case XPATH_BOOLEAN: 05291 case XPATH_NUMBER: 05292 case XPATH_POINT: 05293 case XPATH_RANGE: 05294 break; 05295 case XPATH_STRING: 05296 ret->stringval = xmlStrdup(val->stringval); 05297 break; 05298 case XPATH_XSLT_TREE: 05299 #if 0 05300 /* 05301 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that 05302 this previous handling is no longer correct, and can cause some serious 05303 problems (ref. bug 145547) 05304 */ 05305 if ((val->nodesetval != NULL) && 05306 (val->nodesetval->nodeTab != NULL)) { 05307 xmlNodePtr cur, tmp; 05308 xmlDocPtr top; 05309 05310 ret->boolval = 1; 05311 top = xmlNewDoc(NULL); 05312 top->name = (char *) 05313 xmlStrdup(val->nodesetval->nodeTab[0]->name); 05314 ret->user = top; 05315 if (top != NULL) { 05316 top->doc = top; 05317 cur = val->nodesetval->nodeTab[0]->children; 05318 while (cur != NULL) { 05319 tmp = xmlDocCopyNode(cur, top, 1); 05320 xmlAddChild((xmlNodePtr) top, tmp); 05321 cur = cur->next; 05322 } 05323 } 05324 05325 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top); 05326 } else 05327 ret->nodesetval = xmlXPathNodeSetCreate(NULL); 05328 /* Deallocate the copied tree value */ 05329 break; 05330 #endif 05331 case XPATH_NODESET: 05332 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval); 05333 /* Do not deallocate the copied tree value */ 05334 ret->boolval = 0; 05335 break; 05336 case XPATH_LOCATIONSET: 05337 #ifdef LIBXML_XPTR_ENABLED 05338 { 05339 xmlLocationSetPtr loc = val->user; 05340 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc); 05341 break; 05342 } 05343 #endif 05344 case XPATH_USERS: 05345 ret->user = val->user; 05346 break; 05347 case XPATH_UNDEFINED: 05348 xmlGenericError(xmlGenericErrorContext, 05349 "xmlXPathObjectCopy: unsupported type %d\n", 05350 val->type); 05351 break; 05352 } 05353 return(ret); 05354 } 05355 05362 void 05363 xmlXPathFreeObject(xmlXPathObjectPtr obj) { 05364 if (obj == NULL) return; 05365 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) { 05366 if (obj->boolval) { 05367 #if 0 05368 if (obj->user != NULL) { 05369 xmlXPathFreeNodeSet(obj->nodesetval); 05370 xmlFreeNodeList((xmlNodePtr) obj->user); 05371 } else 05372 #endif 05373 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */ 05374 if (obj->nodesetval != NULL) 05375 xmlXPathFreeValueTree(obj->nodesetval); 05376 } else { 05377 if (obj->nodesetval != NULL) 05378 xmlXPathFreeNodeSet(obj->nodesetval); 05379 } 05380 #ifdef LIBXML_XPTR_ENABLED 05381 } else if (obj->type == XPATH_LOCATIONSET) { 05382 if (obj->user != NULL) 05383 xmlXPtrFreeLocationSet(obj->user); 05384 #endif 05385 } else if (obj->type == XPATH_STRING) { 05386 if (obj->stringval != NULL) 05387 xmlFree(obj->stringval); 05388 } 05389 #ifdef XP_DEBUG_OBJ_USAGE 05390 xmlXPathDebugObjUsageReleased(NULL, obj->type); 05391 #endif 05392 xmlFree(obj); 05393 } 05394 05402 static void 05403 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj) 05404 { 05405 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \ 05406 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \ 05407 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj; 05408 05409 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n)) 05410 05411 if (obj == NULL) 05412 return; 05413 if ((ctxt == NULL) || (ctxt->cache == NULL)) { 05414 xmlXPathFreeObject(obj); 05415 } else { 05416 xmlXPathContextCachePtr cache = 05417 (xmlXPathContextCachePtr) ctxt->cache; 05418 05419 switch (obj->type) { 05420 case XPATH_NODESET: 05421 case XPATH_XSLT_TREE: 05422 if (obj->nodesetval != NULL) { 05423 if (obj->boolval) { 05424 /* 05425 * It looks like the @boolval is used for 05426 * evaluation if this an XSLT Result Tree Fragment. 05427 * TODO: Check if this assumption is correct. 05428 */ 05429 obj->type = XPATH_XSLT_TREE; /* just for debugging */ 05430 xmlXPathFreeValueTree(obj->nodesetval); 05431 obj->nodesetval = NULL; 05432 } else if ((obj->nodesetval->nodeMax <= 40) && 05433 (XP_CACHE_WANTS(cache->nodesetObjs, 05434 cache->maxNodeset))) 05435 { 05436 XP_CACHE_ADD(cache->nodesetObjs, obj); 05437 goto obj_cached; 05438 } else { 05439 xmlXPathFreeNodeSet(obj->nodesetval); 05440 obj->nodesetval = NULL; 05441 } 05442 } 05443 break; 05444 case XPATH_STRING: 05445 if (obj->stringval != NULL) 05446 xmlFree(obj->stringval); 05447 05448 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) { 05449 XP_CACHE_ADD(cache->stringObjs, obj); 05450 goto obj_cached; 05451 } 05452 break; 05453 case XPATH_BOOLEAN: 05454 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) { 05455 XP_CACHE_ADD(cache->booleanObjs, obj); 05456 goto obj_cached; 05457 } 05458 break; 05459 case XPATH_NUMBER: 05460 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) { 05461 XP_CACHE_ADD(cache->numberObjs, obj); 05462 goto obj_cached; 05463 } 05464 break; 05465 #ifdef LIBXML_XPTR_ENABLED 05466 case XPATH_LOCATIONSET: 05467 if (obj->user != NULL) { 05468 xmlXPtrFreeLocationSet(obj->user); 05469 } 05470 goto free_obj; 05471 #endif 05472 default: 05473 goto free_obj; 05474 } 05475 05476 /* 05477 * Fallback to adding to the misc-objects slot. 05478 */ 05479 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) { 05480 XP_CACHE_ADD(cache->miscObjs, obj); 05481 } else 05482 goto free_obj; 05483 05484 obj_cached: 05485 05486 #ifdef XP_DEBUG_OBJ_USAGE 05487 xmlXPathDebugObjUsageReleased(ctxt, obj->type); 05488 #endif 05489 05490 if (obj->nodesetval != NULL) { 05491 xmlNodeSetPtr tmpset = obj->nodesetval; 05492 05493 /* 05494 * TODO: Due to those nasty ns-nodes, we need to traverse 05495 * the list and free the ns-nodes. 05496 * URGENT TODO: Check if it's actually slowing things down. 05497 * Maybe we shouldn't try to preserve the list. 05498 */ 05499 if (tmpset->nodeNr > 1) { 05500 int i; 05501 xmlNodePtr node; 05502 05503 for (i = 0; i < tmpset->nodeNr; i++) { 05504 node = tmpset->nodeTab[i]; 05505 if ((node != NULL) && 05506 (node->type == XML_NAMESPACE_DECL)) 05507 { 05508 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 05509 } 05510 } 05511 } else if (tmpset->nodeNr == 1) { 05512 if ((tmpset->nodeTab[0] != NULL) && 05513 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL)) 05514 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]); 05515 } 05516 tmpset->nodeNr = 0; 05517 memset(obj, 0, sizeof(xmlXPathObject)); 05518 obj->nodesetval = tmpset; 05519 } else 05520 memset(obj, 0, sizeof(xmlXPathObject)); 05521 05522 return; 05523 05524 free_obj: 05525 /* 05526 * Cache is full; free the object. 05527 */ 05528 if (obj->nodesetval != NULL) 05529 xmlXPathFreeNodeSet(obj->nodesetval); 05530 #ifdef XP_DEBUG_OBJ_USAGE 05531 xmlXPathDebugObjUsageReleased(NULL, obj->type); 05532 #endif 05533 xmlFree(obj); 05534 } 05535 return; 05536 } 05537 05538 05539 /************************************************************************ 05540 * * 05541 * Type Casting Routines * 05542 * * 05543 ************************************************************************/ 05544 05553 xmlChar * 05554 xmlXPathCastBooleanToString (int val) { 05555 xmlChar *ret; 05556 if (val) 05557 ret = xmlStrdup((const xmlChar *) "true"); 05558 else 05559 ret = xmlStrdup((const xmlChar *) "false"); 05560 return(ret); 05561 } 05562 05571 xmlChar * 05572 xmlXPathCastNumberToString (double val) { 05573 xmlChar *ret; 05574 switch (xmlXPathIsInf(val)) { 05575 case 1: 05576 ret = xmlStrdup((const xmlChar *) "Infinity"); 05577 break; 05578 case -1: 05579 ret = xmlStrdup((const xmlChar *) "-Infinity"); 05580 break; 05581 default: 05582 if (xmlXPathIsNaN(val)) { 05583 ret = xmlStrdup((const xmlChar *) "NaN"); 05584 } else if (val == 0 && xmlXPathGetSign(val) != 0) { 05585 ret = xmlStrdup((const xmlChar *) "0"); 05586 } else { 05587 /* could be improved */ 05588 char buf[100]; 05589 xmlXPathFormatNumber(val, buf, 99); 05590 buf[99] = 0; 05591 ret = xmlStrdup((const xmlChar *) buf); 05592 } 05593 } 05594 return(ret); 05595 } 05596 05605 xmlChar * 05606 xmlXPathCastNodeToString (xmlNodePtr node) { 05607 xmlChar *ret; 05608 if ((ret = xmlNodeGetContent(node)) == NULL) 05609 ret = xmlStrdup((const xmlChar *) ""); 05610 return(ret); 05611 } 05612 05621 xmlChar * 05622 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) { 05623 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL)) 05624 return(xmlStrdup((const xmlChar *) "")); 05625 05626 if (ns->nodeNr > 1) 05627 xmlXPathNodeSetSort(ns); 05628 return(xmlXPathCastNodeToString(ns->nodeTab[0])); 05629 } 05630 05640 xmlChar * 05641 xmlXPathCastToString(xmlXPathObjectPtr val) { 05642 xmlChar *ret = NULL; 05643 05644 if (val == NULL) 05645 return(xmlStrdup((const xmlChar *) "")); 05646 switch (val->type) { 05647 case XPATH_UNDEFINED: 05648 #ifdef DEBUG_EXPR 05649 xmlGenericError(xmlGenericErrorContext, "String: undefined\n"); 05650 #endif 05651 ret = xmlStrdup((const xmlChar *) ""); 05652 break; 05653 case XPATH_NODESET: 05654 case XPATH_XSLT_TREE: 05655 ret = xmlXPathCastNodeSetToString(val->nodesetval); 05656 break; 05657 case XPATH_STRING: 05658 return(xmlStrdup(val->stringval)); 05659 case XPATH_BOOLEAN: 05660 ret = xmlXPathCastBooleanToString(val->boolval); 05661 break; 05662 case XPATH_NUMBER: { 05663 ret = xmlXPathCastNumberToString(val->floatval); 05664 break; 05665 } 05666 case XPATH_USERS: 05667 case XPATH_POINT: 05668 case XPATH_RANGE: 05669 case XPATH_LOCATIONSET: 05670 TODO 05671 ret = xmlStrdup((const xmlChar *) ""); 05672 break; 05673 } 05674 return(ret); 05675 } 05676 05686 xmlXPathObjectPtr 05687 xmlXPathConvertString(xmlXPathObjectPtr val) { 05688 xmlChar *res = NULL; 05689 05690 if (val == NULL) 05691 return(xmlXPathNewCString("")); 05692 05693 switch (val->type) { 05694 case XPATH_UNDEFINED: 05695 #ifdef DEBUG_EXPR 05696 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n"); 05697 #endif 05698 break; 05699 case XPATH_NODESET: 05700 case XPATH_XSLT_TREE: 05701 res = xmlXPathCastNodeSetToString(val->nodesetval); 05702 break; 05703 case XPATH_STRING: 05704 return(val); 05705 case XPATH_BOOLEAN: 05706 res = xmlXPathCastBooleanToString(val->boolval); 05707 break; 05708 case XPATH_NUMBER: 05709 res = xmlXPathCastNumberToString(val->floatval); 05710 break; 05711 case XPATH_USERS: 05712 case XPATH_POINT: 05713 case XPATH_RANGE: 05714 case XPATH_LOCATIONSET: 05715 TODO; 05716 break; 05717 } 05718 xmlXPathFreeObject(val); 05719 if (res == NULL) 05720 return(xmlXPathNewCString("")); 05721 return(xmlXPathWrapString(res)); 05722 } 05723 05732 double 05733 xmlXPathCastBooleanToNumber(int val) { 05734 if (val) 05735 return(1.0); 05736 return(0.0); 05737 } 05738 05747 double 05748 xmlXPathCastStringToNumber(const xmlChar * val) { 05749 return(xmlXPathStringEvalNumber(val)); 05750 } 05751 05760 double 05761 xmlXPathCastNodeToNumber (xmlNodePtr node) { 05762 xmlChar *strval; 05763 double ret; 05764 05765 if (node == NULL) 05766 return(xmlXPathNAN); 05767 strval = xmlXPathCastNodeToString(node); 05768 if (strval == NULL) 05769 return(xmlXPathNAN); 05770 ret = xmlXPathCastStringToNumber(strval); 05771 xmlFree(strval); 05772 05773 return(ret); 05774 } 05775 05784 double 05785 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) { 05786 xmlChar *str; 05787 double ret; 05788 05789 if (ns == NULL) 05790 return(xmlXPathNAN); 05791 str = xmlXPathCastNodeSetToString(ns); 05792 ret = xmlXPathCastStringToNumber(str); 05793 xmlFree(str); 05794 return(ret); 05795 } 05796 05805 double 05806 xmlXPathCastToNumber(xmlXPathObjectPtr val) { 05807 double ret = 0.0; 05808 05809 if (val == NULL) 05810 return(xmlXPathNAN); 05811 switch (val->type) { 05812 case XPATH_UNDEFINED: 05813 #ifdef DEGUB_EXPR 05814 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n"); 05815 #endif 05816 ret = xmlXPathNAN; 05817 break; 05818 case XPATH_NODESET: 05819 case XPATH_XSLT_TREE: 05820 ret = xmlXPathCastNodeSetToNumber(val->nodesetval); 05821 break; 05822 case XPATH_STRING: 05823 ret = xmlXPathCastStringToNumber(val->stringval); 05824 break; 05825 case XPATH_NUMBER: 05826 ret = val->floatval; 05827 break; 05828 case XPATH_BOOLEAN: 05829 ret = xmlXPathCastBooleanToNumber(val->boolval); 05830 break; 05831 case XPATH_USERS: 05832 case XPATH_POINT: 05833 case XPATH_RANGE: 05834 case XPATH_LOCATIONSET: 05835 TODO; 05836 ret = xmlXPathNAN; 05837 break; 05838 } 05839 return(ret); 05840 } 05841 05851 xmlXPathObjectPtr 05852 xmlXPathConvertNumber(xmlXPathObjectPtr val) { 05853 xmlXPathObjectPtr ret; 05854 05855 if (val == NULL) 05856 return(xmlXPathNewFloat(0.0)); 05857 if (val->type == XPATH_NUMBER) 05858 return(val); 05859 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val)); 05860 xmlXPathFreeObject(val); 05861 return(ret); 05862 } 05863 05872 int 05873 xmlXPathCastNumberToBoolean (double val) { 05874 if (xmlXPathIsNaN(val) || (val == 0.0)) 05875 return(0); 05876 return(1); 05877 } 05878 05887 int 05888 xmlXPathCastStringToBoolean (const xmlChar *val) { 05889 if ((val == NULL) || (xmlStrlen(val) == 0)) 05890 return(0); 05891 return(1); 05892 } 05893 05902 int 05903 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) { 05904 if ((ns == NULL) || (ns->nodeNr == 0)) 05905 return(0); 05906 return(1); 05907 } 05908 05917 int 05918 xmlXPathCastToBoolean (xmlXPathObjectPtr val) { 05919 int ret = 0; 05920 05921 if (val == NULL) 05922 return(0); 05923 switch (val->type) { 05924 case XPATH_UNDEFINED: 05925 #ifdef DEBUG_EXPR 05926 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n"); 05927 #endif 05928 ret = 0; 05929 break; 05930 case XPATH_NODESET: 05931 case XPATH_XSLT_TREE: 05932 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval); 05933 break; 05934 case XPATH_STRING: 05935 ret = xmlXPathCastStringToBoolean(val->stringval); 05936 break; 05937 case XPATH_NUMBER: 05938 ret = xmlXPathCastNumberToBoolean(val->floatval); 05939 break; 05940 case XPATH_BOOLEAN: 05941 ret = val->boolval; 05942 break; 05943 case XPATH_USERS: 05944 case XPATH_POINT: 05945 case XPATH_RANGE: 05946 case XPATH_LOCATIONSET: 05947 TODO; 05948 ret = 0; 05949 break; 05950 } 05951 return(ret); 05952 } 05953 05954 05964 xmlXPathObjectPtr 05965 xmlXPathConvertBoolean(xmlXPathObjectPtr val) { 05966 xmlXPathObjectPtr ret; 05967 05968 if (val == NULL) 05969 return(xmlXPathNewBoolean(0)); 05970 if (val->type == XPATH_BOOLEAN) 05971 return(val); 05972 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val)); 05973 xmlXPathFreeObject(val); 05974 return(ret); 05975 } 05976 05977 /************************************************************************ 05978 * * 05979 * Routines to handle XPath contexts * 05980 * * 05981 ************************************************************************/ 05982 05991 xmlXPathContextPtr 05992 xmlXPathNewContext(xmlDocPtr doc) { 05993 xmlXPathContextPtr ret; 05994 05995 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext)); 05996 if (ret == NULL) { 05997 xmlXPathErrMemory(NULL, "creating context\n"); 05998 return(NULL); 05999 } 06000 memset(ret, 0 , (size_t) sizeof(xmlXPathContext)); 06001 ret->doc = doc; 06002 ret->node = NULL; 06003 06004 ret->varHash = NULL; 06005 06006 ret->nb_types = 0; 06007 ret->max_types = 0; 06008 ret->types = NULL; 06009 06010 ret->funcHash = xmlHashCreate(0); 06011 06012 ret->nb_axis = 0; 06013 ret->max_axis = 0; 06014 ret->axis = NULL; 06015 06016 ret->nsHash = NULL; 06017 ret->user = NULL; 06018 06019 ret->contextSize = -1; 06020 ret->proximityPosition = -1; 06021 06022 #ifdef XP_DEFAULT_CACHE_ON 06023 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) { 06024 xmlXPathFreeContext(ret); 06025 return(NULL); 06026 } 06027 #endif 06028 06029 xmlXPathRegisterAllFunctions(ret); 06030 06031 return(ret); 06032 } 06033 06040 void 06041 xmlXPathFreeContext(xmlXPathContextPtr ctxt) { 06042 if (ctxt == NULL) return; 06043 06044 if (ctxt->cache != NULL) 06045 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache); 06046 xmlXPathRegisteredNsCleanup(ctxt); 06047 xmlXPathRegisteredFuncsCleanup(ctxt); 06048 xmlXPathRegisteredVariablesCleanup(ctxt); 06049 xmlResetError(&ctxt->lastError); 06050 xmlFree(ctxt); 06051 } 06052 06053 /************************************************************************ 06054 * * 06055 * Routines to handle XPath parser contexts * 06056 * * 06057 ************************************************************************/ 06058 06059 #define CHECK_CTXT(ctxt) \ 06060 if (ctxt == NULL) { \ 06061 __xmlRaiseError(NULL, NULL, NULL, \ 06062 NULL, NULL, XML_FROM_XPATH, \ 06063 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \ 06064 __FILE__, __LINE__, \ 06065 NULL, NULL, NULL, 0, 0, \ 06066 "NULL context pointer\n"); \ 06067 return(NULL); \ 06068 } \ 06069 06070 #define CHECK_CTXT_NEG(ctxt) \ 06071 if (ctxt == NULL) { \ 06072 __xmlRaiseError(NULL, NULL, NULL, \ 06073 NULL, NULL, XML_FROM_XPATH, \ 06074 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \ 06075 __FILE__, __LINE__, \ 06076 NULL, NULL, NULL, 0, 0, \ 06077 "NULL context pointer\n"); \ 06078 return(-1); \ 06079 } \ 06080 06081 06082 #define CHECK_CONTEXT(ctxt) \ 06083 if ((ctxt == NULL) || (ctxt->doc == NULL) || \ 06084 (ctxt->doc->children == NULL)) { \ 06085 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \ 06086 return(NULL); \ 06087 } 06088 06089 06099 xmlXPathParserContextPtr 06100 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) { 06101 xmlXPathParserContextPtr ret; 06102 06103 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext)); 06104 if (ret == NULL) { 06105 xmlXPathErrMemory(ctxt, "creating parser context\n"); 06106 return(NULL); 06107 } 06108 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext)); 06109 ret->cur = ret->base = str; 06110 ret->context = ctxt; 06111 06112 ret->comp = xmlXPathNewCompExpr(); 06113 if (ret->comp == NULL) { 06114 xmlFree(ret->valueTab); 06115 xmlFree(ret); 06116 return(NULL); 06117 } 06118 if ((ctxt != NULL) && (ctxt->dict != NULL)) { 06119 ret->comp->dict = ctxt->dict; 06120 xmlDictReference(ret->comp->dict); 06121 } 06122 06123 return(ret); 06124 } 06125 06135 static xmlXPathParserContextPtr 06136 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) { 06137 xmlXPathParserContextPtr ret; 06138 06139 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext)); 06140 if (ret == NULL) { 06141 xmlXPathErrMemory(ctxt, "creating evaluation context\n"); 06142 return(NULL); 06143 } 06144 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext)); 06145 06146 /* Allocate the value stack */ 06147 ret->valueTab = (xmlXPathObjectPtr *) 06148 xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); 06149 if (ret->valueTab == NULL) { 06150 xmlFree(ret); 06151 xmlXPathErrMemory(ctxt, "creating evaluation context\n"); 06152 return(NULL); 06153 } 06154 ret->valueNr = 0; 06155 ret->valueMax = 10; 06156 ret->value = NULL; 06157 06158 ret->context = ctxt; 06159 ret->comp = comp; 06160 06161 return(ret); 06162 } 06163 06170 void 06171 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) { 06172 if (ctxt->valueTab != NULL) { 06173 xmlFree(ctxt->valueTab); 06174 } 06175 if (ctxt->comp != NULL) { 06176 #ifdef XPATH_STREAMING 06177 if (ctxt->comp->stream != NULL) { 06178 xmlFreePatternList(ctxt->comp->stream); 06179 ctxt->comp->stream = NULL; 06180 } 06181 #endif 06182 xmlXPathFreeCompExpr(ctxt->comp); 06183 } 06184 xmlFree(ctxt); 06185 } 06186 06187 /************************************************************************ 06188 * * 06189 * The implicit core function library * 06190 * * 06191 ************************************************************************/ 06192 06202 static unsigned int 06203 xmlXPathNodeValHash(xmlNodePtr node) { 06204 int len = 2; 06205 const xmlChar * string = NULL; 06206 xmlNodePtr tmp = NULL; 06207 unsigned int ret = 0; 06208 06209 if (node == NULL) 06210 return(0); 06211 06212 if (node->type == XML_DOCUMENT_NODE) { 06213 tmp = xmlDocGetRootElement((xmlDocPtr) node); 06214 if (tmp == NULL) 06215 node = node->children; 06216 else 06217 node = tmp; 06218 06219 if (node == NULL) 06220 return(0); 06221 } 06222 06223 switch (node->type) { 06224 case XML_COMMENT_NODE: 06225 case XML_PI_NODE: 06226 case XML_CDATA_SECTION_NODE: 06227 case XML_TEXT_NODE: 06228 string = node->content; 06229 if (string == NULL) 06230 return(0); 06231 if (string[0] == 0) 06232 return(0); 06233 return(((unsigned int) string[0]) + 06234 (((unsigned int) string[1]) << 8)); 06235 case XML_NAMESPACE_DECL: 06236 string = ((xmlNsPtr)node)->href; 06237 if (string == NULL) 06238 return(0); 06239 if (string[0] == 0) 06240 return(0); 06241 return(((unsigned int) string[0]) + 06242 (((unsigned int) string[1]) << 8)); 06243 case XML_ATTRIBUTE_NODE: 06244 tmp = ((xmlAttrPtr) node)->children; 06245 break; 06246 case XML_ELEMENT_NODE: 06247 tmp = node->children; 06248 break; 06249 default: 06250 return(0); 06251 } 06252 while (tmp != NULL) { 06253 switch (tmp->type) { 06254 case XML_COMMENT_NODE: 06255 case XML_PI_NODE: 06256 case XML_CDATA_SECTION_NODE: 06257 case XML_TEXT_NODE: 06258 string = tmp->content; 06259 break; 06260 case XML_NAMESPACE_DECL: 06261 string = ((xmlNsPtr)tmp)->href; 06262 break; 06263 default: 06264 break; 06265 } 06266 if ((string != NULL) && (string[0] != 0)) { 06267 if (len == 1) { 06268 return(ret + (((unsigned int) string[0]) << 8)); 06269 } 06270 if (string[1] == 0) { 06271 len = 1; 06272 ret = (unsigned int) string[0]; 06273 } else { 06274 return(((unsigned int) string[0]) + 06275 (((unsigned int) string[1]) << 8)); 06276 } 06277 } 06278 /* 06279 * Skip to next node 06280 */ 06281 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) { 06282 if (tmp->children->type != XML_ENTITY_DECL) { 06283 tmp = tmp->children; 06284 continue; 06285 } 06286 } 06287 if (tmp == node) 06288 break; 06289 06290 if (tmp->next != NULL) { 06291 tmp = tmp->next; 06292 continue; 06293 } 06294 06295 do { 06296 tmp = tmp->parent; 06297 if (tmp == NULL) 06298 break; 06299 if (tmp == node) { 06300 tmp = NULL; 06301 break; 06302 } 06303 if (tmp->next != NULL) { 06304 tmp = tmp->next; 06305 break; 06306 } 06307 } while (tmp != NULL); 06308 } 06309 return(ret); 06310 } 06311 06321 static unsigned int 06322 xmlXPathStringHash(const xmlChar * string) { 06323 if (string == NULL) 06324 return((unsigned int) 0); 06325 if (string[0] == 0) 06326 return(0); 06327 return(((unsigned int) string[0]) + 06328 (((unsigned int) string[1]) << 8)); 06329 } 06330 06353 static int 06354 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict, 06355 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) { 06356 int i, ret = 0; 06357 xmlNodeSetPtr ns; 06358 xmlChar *str2; 06359 06360 if ((f == NULL) || (arg == NULL) || 06361 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) { 06362 xmlXPathReleaseObject(ctxt->context, arg); 06363 xmlXPathReleaseObject(ctxt->context, f); 06364 return(0); 06365 } 06366 ns = arg->nodesetval; 06367 if (ns != NULL) { 06368 for (i = 0;i < ns->nodeNr;i++) { 06369 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 06370 if (str2 != NULL) { 06371 valuePush(ctxt, 06372 xmlXPathCacheNewString(ctxt->context, str2)); 06373 xmlFree(str2); 06374 xmlXPathNumberFunction(ctxt, 1); 06375 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f)); 06376 ret = xmlXPathCompareValues(ctxt, inf, strict); 06377 if (ret) 06378 break; 06379 } 06380 } 06381 } 06382 xmlXPathReleaseObject(ctxt->context, arg); 06383 xmlXPathReleaseObject(ctxt->context, f); 06384 return(ret); 06385 } 06386 06408 static int 06409 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict, 06410 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) { 06411 int i, ret = 0; 06412 xmlNodeSetPtr ns; 06413 xmlChar *str2; 06414 06415 if ((s == NULL) || (arg == NULL) || 06416 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) { 06417 xmlXPathReleaseObject(ctxt->context, arg); 06418 xmlXPathReleaseObject(ctxt->context, s); 06419 return(0); 06420 } 06421 ns = arg->nodesetval; 06422 if (ns != NULL) { 06423 for (i = 0;i < ns->nodeNr;i++) { 06424 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 06425 if (str2 != NULL) { 06426 valuePush(ctxt, 06427 xmlXPathCacheNewString(ctxt->context, str2)); 06428 xmlFree(str2); 06429 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s)); 06430 ret = xmlXPathCompareValues(ctxt, inf, strict); 06431 if (ret) 06432 break; 06433 } 06434 } 06435 } 06436 xmlXPathReleaseObject(ctxt->context, arg); 06437 xmlXPathReleaseObject(ctxt->context, s); 06438 return(ret); 06439 } 06440 06469 static int 06470 xmlXPathCompareNodeSets(int inf, int strict, 06471 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) { 06472 int i, j, init = 0; 06473 double val1; 06474 double *values2; 06475 int ret = 0; 06476 xmlNodeSetPtr ns1; 06477 xmlNodeSetPtr ns2; 06478 06479 if ((arg1 == NULL) || 06480 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) { 06481 xmlXPathFreeObject(arg2); 06482 return(0); 06483 } 06484 if ((arg2 == NULL) || 06485 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) { 06486 xmlXPathFreeObject(arg1); 06487 xmlXPathFreeObject(arg2); 06488 return(0); 06489 } 06490 06491 ns1 = arg1->nodesetval; 06492 ns2 = arg2->nodesetval; 06493 06494 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) { 06495 xmlXPathFreeObject(arg1); 06496 xmlXPathFreeObject(arg2); 06497 return(0); 06498 } 06499 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) { 06500 xmlXPathFreeObject(arg1); 06501 xmlXPathFreeObject(arg2); 06502 return(0); 06503 } 06504 06505 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double)); 06506 if (values2 == NULL) { 06507 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 06508 xmlXPathFreeObject(arg1); 06509 xmlXPathFreeObject(arg2); 06510 return(0); 06511 } 06512 for (i = 0;i < ns1->nodeNr;i++) { 06513 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]); 06514 if (xmlXPathIsNaN(val1)) 06515 continue; 06516 for (j = 0;j < ns2->nodeNr;j++) { 06517 if (init == 0) { 06518 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]); 06519 } 06520 if (xmlXPathIsNaN(values2[j])) 06521 continue; 06522 if (inf && strict) 06523 ret = (val1 < values2[j]); 06524 else if (inf && !strict) 06525 ret = (val1 <= values2[j]); 06526 else if (!inf && strict) 06527 ret = (val1 > values2[j]); 06528 else if (!inf && !strict) 06529 ret = (val1 >= values2[j]); 06530 if (ret) 06531 break; 06532 } 06533 if (ret) 06534 break; 06535 init = 1; 06536 } 06537 xmlFree(values2); 06538 xmlXPathFreeObject(arg1); 06539 xmlXPathFreeObject(arg2); 06540 return(ret); 06541 } 06542 06564 static int 06565 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict, 06566 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) { 06567 if ((val == NULL) || (arg == NULL) || 06568 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 06569 return(0); 06570 06571 switch(val->type) { 06572 case XPATH_NUMBER: 06573 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val)); 06574 case XPATH_NODESET: 06575 case XPATH_XSLT_TREE: 06576 return(xmlXPathCompareNodeSets(inf, strict, arg, val)); 06577 case XPATH_STRING: 06578 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val)); 06579 case XPATH_BOOLEAN: 06580 valuePush(ctxt, arg); 06581 xmlXPathBooleanFunction(ctxt, 1); 06582 valuePush(ctxt, val); 06583 return(xmlXPathCompareValues(ctxt, inf, strict)); 06584 default: 06585 TODO 06586 } 06587 return(0); 06588 } 06589 06604 static int 06605 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq) 06606 { 06607 int i; 06608 xmlNodeSetPtr ns; 06609 xmlChar *str2; 06610 unsigned int hash; 06611 06612 if ((str == NULL) || (arg == NULL) || 06613 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 06614 return (0); 06615 ns = arg->nodesetval; 06616 /* 06617 * A NULL nodeset compared with a string is always false 06618 * (since there is no node equal, and no node not equal) 06619 */ 06620 if ((ns == NULL) || (ns->nodeNr <= 0) ) 06621 return (0); 06622 hash = xmlXPathStringHash(str); 06623 for (i = 0; i < ns->nodeNr; i++) { 06624 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) { 06625 str2 = xmlNodeGetContent(ns->nodeTab[i]); 06626 if ((str2 != NULL) && (xmlStrEqual(str, str2))) { 06627 xmlFree(str2); 06628 if (neq) 06629 continue; 06630 return (1); 06631 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) { 06632 if (neq) 06633 continue; 06634 return (1); 06635 } else if (neq) { 06636 if (str2 != NULL) 06637 xmlFree(str2); 06638 return (1); 06639 } 06640 if (str2 != NULL) 06641 xmlFree(str2); 06642 } else if (neq) 06643 return (1); 06644 } 06645 return (0); 06646 } 06647 06663 static int 06664 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt, 06665 xmlXPathObjectPtr arg, double f, int neq) { 06666 int i, ret=0; 06667 xmlNodeSetPtr ns; 06668 xmlChar *str2; 06669 xmlXPathObjectPtr val; 06670 double v; 06671 06672 if ((arg == NULL) || 06673 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 06674 return(0); 06675 06676 ns = arg->nodesetval; 06677 if (ns != NULL) { 06678 for (i=0;i<ns->nodeNr;i++) { 06679 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 06680 if (str2 != NULL) { 06681 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2)); 06682 xmlFree(str2); 06683 xmlXPathNumberFunction(ctxt, 1); 06684 val = valuePop(ctxt); 06685 v = val->floatval; 06686 xmlXPathReleaseObject(ctxt->context, val); 06687 if (!xmlXPathIsNaN(v)) { 06688 if ((!neq) && (v==f)) { 06689 ret = 1; 06690 break; 06691 } else if ((neq) && (v!=f)) { 06692 ret = 1; 06693 break; 06694 } 06695 } else { /* NaN is unequal to any value */ 06696 if (neq) 06697 ret = 1; 06698 } 06699 } 06700 } 06701 } 06702 06703 return(ret); 06704 } 06705 06706 06724 static int 06725 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) { 06726 int i, j; 06727 unsigned int *hashs1; 06728 unsigned int *hashs2; 06729 xmlChar **values1; 06730 xmlChar **values2; 06731 int ret = 0; 06732 xmlNodeSetPtr ns1; 06733 xmlNodeSetPtr ns2; 06734 06735 if ((arg1 == NULL) || 06736 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) 06737 return(0); 06738 if ((arg2 == NULL) || 06739 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) 06740 return(0); 06741 06742 ns1 = arg1->nodesetval; 06743 ns2 = arg2->nodesetval; 06744 06745 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) 06746 return(0); 06747 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) 06748 return(0); 06749 06750 /* 06751 * for equal, check if there is a node pertaining to both sets 06752 */ 06753 if (neq == 0) 06754 for (i = 0;i < ns1->nodeNr;i++) 06755 for (j = 0;j < ns2->nodeNr;j++) 06756 if (ns1->nodeTab[i] == ns2->nodeTab[j]) 06757 return(1); 06758 06759 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *)); 06760 if (values1 == NULL) { 06761 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 06762 return(0); 06763 } 06764 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int)); 06765 if (hashs1 == NULL) { 06766 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 06767 xmlFree(values1); 06768 return(0); 06769 } 06770 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *)); 06771 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *)); 06772 if (values2 == NULL) { 06773 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 06774 xmlFree(hashs1); 06775 xmlFree(values1); 06776 return(0); 06777 } 06778 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int)); 06779 if (hashs2 == NULL) { 06780 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 06781 xmlFree(hashs1); 06782 xmlFree(values1); 06783 xmlFree(values2); 06784 return(0); 06785 } 06786 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *)); 06787 for (i = 0;i < ns1->nodeNr;i++) { 06788 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]); 06789 for (j = 0;j < ns2->nodeNr;j++) { 06790 if (i == 0) 06791 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]); 06792 if (hashs1[i] != hashs2[j]) { 06793 if (neq) { 06794 ret = 1; 06795 break; 06796 } 06797 } 06798 else { 06799 if (values1[i] == NULL) 06800 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]); 06801 if (values2[j] == NULL) 06802 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]); 06803 ret = xmlStrEqual(values1[i], values2[j]) ^ neq; 06804 if (ret) 06805 break; 06806 } 06807 } 06808 if (ret) 06809 break; 06810 } 06811 for (i = 0;i < ns1->nodeNr;i++) 06812 if (values1[i] != NULL) 06813 xmlFree(values1[i]); 06814 for (j = 0;j < ns2->nodeNr;j++) 06815 if (values2[j] != NULL) 06816 xmlFree(values2[j]); 06817 xmlFree(values1); 06818 xmlFree(values2); 06819 xmlFree(hashs1); 06820 xmlFree(hashs2); 06821 return(ret); 06822 } 06823 06824 static int 06825 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt, 06826 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) { 06827 int ret = 0; 06828 /* 06829 *At this point we are assured neither arg1 nor arg2 06830 *is a nodeset, so we can just pick the appropriate routine. 06831 */ 06832 switch (arg1->type) { 06833 case XPATH_UNDEFINED: 06834 #ifdef DEBUG_EXPR 06835 xmlGenericError(xmlGenericErrorContext, 06836 "Equal: undefined\n"); 06837 #endif 06838 break; 06839 case XPATH_BOOLEAN: 06840 switch (arg2->type) { 06841 case XPATH_UNDEFINED: 06842 #ifdef DEBUG_EXPR 06843 xmlGenericError(xmlGenericErrorContext, 06844 "Equal: undefined\n"); 06845 #endif 06846 break; 06847 case XPATH_BOOLEAN: 06848 #ifdef DEBUG_EXPR 06849 xmlGenericError(xmlGenericErrorContext, 06850 "Equal: %d boolean %d \n", 06851 arg1->boolval, arg2->boolval); 06852 #endif 06853 ret = (arg1->boolval == arg2->boolval); 06854 break; 06855 case XPATH_NUMBER: 06856 ret = (arg1->boolval == 06857 xmlXPathCastNumberToBoolean(arg2->floatval)); 06858 break; 06859 case XPATH_STRING: 06860 if ((arg2->stringval == NULL) || 06861 (arg2->stringval[0] == 0)) ret = 0; 06862 else 06863 ret = 1; 06864 ret = (arg1->boolval == ret); 06865 break; 06866 case XPATH_USERS: 06867 case XPATH_POINT: 06868 case XPATH_RANGE: 06869 case XPATH_LOCATIONSET: 06870 TODO 06871 break; 06872 case XPATH_NODESET: 06873 case XPATH_XSLT_TREE: 06874 break; 06875 } 06876 break; 06877 case XPATH_NUMBER: 06878 switch (arg2->type) { 06879 case XPATH_UNDEFINED: 06880 #ifdef DEBUG_EXPR 06881 xmlGenericError(xmlGenericErrorContext, 06882 "Equal: undefined\n"); 06883 #endif 06884 break; 06885 case XPATH_BOOLEAN: 06886 ret = (arg2->boolval== 06887 xmlXPathCastNumberToBoolean(arg1->floatval)); 06888 break; 06889 case XPATH_STRING: 06890 valuePush(ctxt, arg2); 06891 xmlXPathNumberFunction(ctxt, 1); 06892 arg2 = valuePop(ctxt); 06893 /* no break on purpose */ 06894 case XPATH_NUMBER: 06895 /* Hand check NaN and Infinity equalities */ 06896 if (xmlXPathIsNaN(arg1->floatval) || 06897 xmlXPathIsNaN(arg2->floatval)) { 06898 ret = 0; 06899 } else if (xmlXPathIsInf(arg1->floatval) == 1) { 06900 if (xmlXPathIsInf(arg2->floatval) == 1) 06901 ret = 1; 06902 else 06903 ret = 0; 06904 } else if (xmlXPathIsInf(arg1->floatval) == -1) { 06905 if (xmlXPathIsInf(arg2->floatval) == -1) 06906 ret = 1; 06907 else 06908 ret = 0; 06909 } else if (xmlXPathIsInf(arg2->floatval) == 1) { 06910 if (xmlXPathIsInf(arg1->floatval) == 1) 06911 ret = 1; 06912 else 06913 ret = 0; 06914 } else if (xmlXPathIsInf(arg2->floatval) == -1) { 06915 if (xmlXPathIsInf(arg1->floatval) == -1) 06916 ret = 1; 06917 else 06918 ret = 0; 06919 } else { 06920 ret = (arg1->floatval == arg2->floatval); 06921 } 06922 break; 06923 case XPATH_USERS: 06924 case XPATH_POINT: 06925 case XPATH_RANGE: 06926 case XPATH_LOCATIONSET: 06927 TODO 06928 break; 06929 case XPATH_NODESET: 06930 case XPATH_XSLT_TREE: 06931 break; 06932 } 06933 break; 06934 case XPATH_STRING: 06935 switch (arg2->type) { 06936 case XPATH_UNDEFINED: 06937 #ifdef DEBUG_EXPR 06938 xmlGenericError(xmlGenericErrorContext, 06939 "Equal: undefined\n"); 06940 #endif 06941 break; 06942 case XPATH_BOOLEAN: 06943 if ((arg1->stringval == NULL) || 06944 (arg1->stringval[0] == 0)) ret = 0; 06945 else 06946 ret = 1; 06947 ret = (arg2->boolval == ret); 06948 break; 06949 case XPATH_STRING: 06950 ret = xmlStrEqual(arg1->stringval, arg2->stringval); 06951 break; 06952 case XPATH_NUMBER: 06953 valuePush(ctxt, arg1); 06954 xmlXPathNumberFunction(ctxt, 1); 06955 arg1 = valuePop(ctxt); 06956 /* Hand check NaN and Infinity equalities */ 06957 if (xmlXPathIsNaN(arg1->floatval) || 06958 xmlXPathIsNaN(arg2->floatval)) { 06959 ret = 0; 06960 } else if (xmlXPathIsInf(arg1->floatval) == 1) { 06961 if (xmlXPathIsInf(arg2->floatval) == 1) 06962 ret = 1; 06963 else 06964 ret = 0; 06965 } else if (xmlXPathIsInf(arg1->floatval) == -1) { 06966 if (xmlXPathIsInf(arg2->floatval) == -1) 06967 ret = 1; 06968 else 06969 ret = 0; 06970 } else if (xmlXPathIsInf(arg2->floatval) == 1) { 06971 if (xmlXPathIsInf(arg1->floatval) == 1) 06972 ret = 1; 06973 else 06974 ret = 0; 06975 } else if (xmlXPathIsInf(arg2->floatval) == -1) { 06976 if (xmlXPathIsInf(arg1->floatval) == -1) 06977 ret = 1; 06978 else 06979 ret = 0; 06980 } else { 06981 ret = (arg1->floatval == arg2->floatval); 06982 } 06983 break; 06984 case XPATH_USERS: 06985 case XPATH_POINT: 06986 case XPATH_RANGE: 06987 case XPATH_LOCATIONSET: 06988 TODO 06989 break; 06990 case XPATH_NODESET: 06991 case XPATH_XSLT_TREE: 06992 break; 06993 } 06994 break; 06995 case XPATH_USERS: 06996 case XPATH_POINT: 06997 case XPATH_RANGE: 06998 case XPATH_LOCATIONSET: 06999 TODO 07000 break; 07001 case XPATH_NODESET: 07002 case XPATH_XSLT_TREE: 07003 break; 07004 } 07005 xmlXPathReleaseObject(ctxt->context, arg1); 07006 xmlXPathReleaseObject(ctxt->context, arg2); 07007 return(ret); 07008 } 07009 07018 int 07019 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) { 07020 xmlXPathObjectPtr arg1, arg2, argtmp; 07021 int ret = 0; 07022 07023 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); 07024 arg2 = valuePop(ctxt); 07025 arg1 = valuePop(ctxt); 07026 if ((arg1 == NULL) || (arg2 == NULL)) { 07027 if (arg1 != NULL) 07028 xmlXPathReleaseObject(ctxt->context, arg1); 07029 else 07030 xmlXPathReleaseObject(ctxt->context, arg2); 07031 XP_ERROR0(XPATH_INVALID_OPERAND); 07032 } 07033 07034 if (arg1 == arg2) { 07035 #ifdef DEBUG_EXPR 07036 xmlGenericError(xmlGenericErrorContext, 07037 "Equal: by pointer\n"); 07038 #endif 07039 xmlXPathFreeObject(arg1); 07040 return(1); 07041 } 07042 07043 /* 07044 *If either argument is a nodeset, it's a 'special case' 07045 */ 07046 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 07047 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 07048 /* 07049 *Hack it to assure arg1 is the nodeset 07050 */ 07051 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) { 07052 argtmp = arg2; 07053 arg2 = arg1; 07054 arg1 = argtmp; 07055 } 07056 switch (arg2->type) { 07057 case XPATH_UNDEFINED: 07058 #ifdef DEBUG_EXPR 07059 xmlGenericError(xmlGenericErrorContext, 07060 "Equal: undefined\n"); 07061 #endif 07062 break; 07063 case XPATH_NODESET: 07064 case XPATH_XSLT_TREE: 07065 ret = xmlXPathEqualNodeSets(arg1, arg2, 0); 07066 break; 07067 case XPATH_BOOLEAN: 07068 if ((arg1->nodesetval == NULL) || 07069 (arg1->nodesetval->nodeNr == 0)) ret = 0; 07070 else 07071 ret = 1; 07072 ret = (ret == arg2->boolval); 07073 break; 07074 case XPATH_NUMBER: 07075 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0); 07076 break; 07077 case XPATH_STRING: 07078 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0); 07079 break; 07080 case XPATH_USERS: 07081 case XPATH_POINT: 07082 case XPATH_RANGE: 07083 case XPATH_LOCATIONSET: 07084 TODO 07085 break; 07086 } 07087 xmlXPathReleaseObject(ctxt->context, arg1); 07088 xmlXPathReleaseObject(ctxt->context, arg2); 07089 return(ret); 07090 } 07091 07092 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2)); 07093 } 07094 07103 int 07104 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) { 07105 xmlXPathObjectPtr arg1, arg2, argtmp; 07106 int ret = 0; 07107 07108 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); 07109 arg2 = valuePop(ctxt); 07110 arg1 = valuePop(ctxt); 07111 if ((arg1 == NULL) || (arg2 == NULL)) { 07112 if (arg1 != NULL) 07113 xmlXPathReleaseObject(ctxt->context, arg1); 07114 else 07115 xmlXPathReleaseObject(ctxt->context, arg2); 07116 XP_ERROR0(XPATH_INVALID_OPERAND); 07117 } 07118 07119 if (arg1 == arg2) { 07120 #ifdef DEBUG_EXPR 07121 xmlGenericError(xmlGenericErrorContext, 07122 "NotEqual: by pointer\n"); 07123 #endif 07124 xmlXPathReleaseObject(ctxt->context, arg1); 07125 return(0); 07126 } 07127 07128 /* 07129 *If either argument is a nodeset, it's a 'special case' 07130 */ 07131 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 07132 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 07133 /* 07134 *Hack it to assure arg1 is the nodeset 07135 */ 07136 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) { 07137 argtmp = arg2; 07138 arg2 = arg1; 07139 arg1 = argtmp; 07140 } 07141 switch (arg2->type) { 07142 case XPATH_UNDEFINED: 07143 #ifdef DEBUG_EXPR 07144 xmlGenericError(xmlGenericErrorContext, 07145 "NotEqual: undefined\n"); 07146 #endif 07147 break; 07148 case XPATH_NODESET: 07149 case XPATH_XSLT_TREE: 07150 ret = xmlXPathEqualNodeSets(arg1, arg2, 1); 07151 break; 07152 case XPATH_BOOLEAN: 07153 if ((arg1->nodesetval == NULL) || 07154 (arg1->nodesetval->nodeNr == 0)) ret = 0; 07155 else 07156 ret = 1; 07157 ret = (ret != arg2->boolval); 07158 break; 07159 case XPATH_NUMBER: 07160 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1); 07161 break; 07162 case XPATH_STRING: 07163 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1); 07164 break; 07165 case XPATH_USERS: 07166 case XPATH_POINT: 07167 case XPATH_RANGE: 07168 case XPATH_LOCATIONSET: 07169 TODO 07170 break; 07171 } 07172 xmlXPathReleaseObject(ctxt->context, arg1); 07173 xmlXPathReleaseObject(ctxt->context, arg2); 07174 return(ret); 07175 } 07176 07177 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2)); 07178 } 07179 07204 int 07205 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) { 07206 int ret = 0, arg1i = 0, arg2i = 0; 07207 xmlXPathObjectPtr arg1, arg2; 07208 07209 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); 07210 arg2 = valuePop(ctxt); 07211 arg1 = valuePop(ctxt); 07212 if ((arg1 == NULL) || (arg2 == NULL)) { 07213 if (arg1 != NULL) 07214 xmlXPathReleaseObject(ctxt->context, arg1); 07215 else 07216 xmlXPathReleaseObject(ctxt->context, arg2); 07217 XP_ERROR0(XPATH_INVALID_OPERAND); 07218 } 07219 07220 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 07221 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 07222 /* 07223 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments 07224 * are not freed from within this routine; they will be freed from the 07225 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue 07226 */ 07227 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) && 07228 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){ 07229 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2); 07230 } else { 07231 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 07232 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict, 07233 arg1, arg2); 07234 } else { 07235 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict, 07236 arg2, arg1); 07237 } 07238 } 07239 return(ret); 07240 } 07241 07242 if (arg1->type != XPATH_NUMBER) { 07243 valuePush(ctxt, arg1); 07244 xmlXPathNumberFunction(ctxt, 1); 07245 arg1 = valuePop(ctxt); 07246 } 07247 if (arg1->type != XPATH_NUMBER) { 07248 xmlXPathFreeObject(arg1); 07249 xmlXPathFreeObject(arg2); 07250 XP_ERROR0(XPATH_INVALID_OPERAND); 07251 } 07252 if (arg2->type != XPATH_NUMBER) { 07253 valuePush(ctxt, arg2); 07254 xmlXPathNumberFunction(ctxt, 1); 07255 arg2 = valuePop(ctxt); 07256 } 07257 if (arg2->type != XPATH_NUMBER) { 07258 xmlXPathReleaseObject(ctxt->context, arg1); 07259 xmlXPathReleaseObject(ctxt->context, arg2); 07260 XP_ERROR0(XPATH_INVALID_OPERAND); 07261 } 07262 /* 07263 * Add tests for infinity and nan 07264 * => feedback on 3.4 for Inf and NaN 07265 */ 07266 /* Hand check NaN and Infinity comparisons */ 07267 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) { 07268 ret=0; 07269 } else { 07270 arg1i=xmlXPathIsInf(arg1->floatval); 07271 arg2i=xmlXPathIsInf(arg2->floatval); 07272 if (inf && strict) { 07273 if ((arg1i == -1 && arg2i != -1) || 07274 (arg2i == 1 && arg1i != 1)) { 07275 ret = 1; 07276 } else if (arg1i == 0 && arg2i == 0) { 07277 ret = (arg1->floatval < arg2->floatval); 07278 } else { 07279 ret = 0; 07280 } 07281 } 07282 else if (inf && !strict) { 07283 if (arg1i == -1 || arg2i == 1) { 07284 ret = 1; 07285 } else if (arg1i == 0 && arg2i == 0) { 07286 ret = (arg1->floatval <= arg2->floatval); 07287 } else { 07288 ret = 0; 07289 } 07290 } 07291 else if (!inf && strict) { 07292 if ((arg1i == 1 && arg2i != 1) || 07293 (arg2i == -1 && arg1i != -1)) { 07294 ret = 1; 07295 } else if (arg1i == 0 && arg2i == 0) { 07296 ret = (arg1->floatval > arg2->floatval); 07297 } else { 07298 ret = 0; 07299 } 07300 } 07301 else if (!inf && !strict) { 07302 if (arg1i == 1 || arg2i == -1) { 07303 ret = 1; 07304 } else if (arg1i == 0 && arg2i == 0) { 07305 ret = (arg1->floatval >= arg2->floatval); 07306 } else { 07307 ret = 0; 07308 } 07309 } 07310 } 07311 xmlXPathReleaseObject(ctxt->context, arg1); 07312 xmlXPathReleaseObject(ctxt->context, arg2); 07313 return(ret); 07314 } 07315 07324 void 07325 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) { 07326 if ((ctxt == NULL) || (ctxt->context == NULL)) return; 07327 CAST_TO_NUMBER; 07328 CHECK_TYPE(XPATH_NUMBER); 07329 if (xmlXPathIsNaN(ctxt->value->floatval)) 07330 ctxt->value->floatval=xmlXPathNAN; 07331 else if (xmlXPathIsInf(ctxt->value->floatval) == 1) 07332 ctxt->value->floatval=xmlXPathNINF; 07333 else if (xmlXPathIsInf(ctxt->value->floatval) == -1) 07334 ctxt->value->floatval=xmlXPathPINF; 07335 else if (ctxt->value->floatval == 0) { 07336 if (xmlXPathGetSign(ctxt->value->floatval) == 0) 07337 ctxt->value->floatval = xmlXPathNZERO; 07338 else 07339 ctxt->value->floatval = 0; 07340 } 07341 else 07342 ctxt->value->floatval = - ctxt->value->floatval; 07343 } 07344 07353 void 07354 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) { 07355 xmlXPathObjectPtr arg; 07356 double val; 07357 07358 arg = valuePop(ctxt); 07359 if (arg == NULL) 07360 XP_ERROR(XPATH_INVALID_OPERAND); 07361 val = xmlXPathCastToNumber(arg); 07362 xmlXPathReleaseObject(ctxt->context, arg); 07363 CAST_TO_NUMBER; 07364 CHECK_TYPE(XPATH_NUMBER); 07365 ctxt->value->floatval += val; 07366 } 07367 07376 void 07377 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) { 07378 xmlXPathObjectPtr arg; 07379 double val; 07380 07381 arg = valuePop(ctxt); 07382 if (arg == NULL) 07383 XP_ERROR(XPATH_INVALID_OPERAND); 07384 val = xmlXPathCastToNumber(arg); 07385 xmlXPathReleaseObject(ctxt->context, arg); 07386 CAST_TO_NUMBER; 07387 CHECK_TYPE(XPATH_NUMBER); 07388 ctxt->value->floatval -= val; 07389 } 07390 07399 void 07400 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) { 07401 xmlXPathObjectPtr arg; 07402 double val; 07403 07404 arg = valuePop(ctxt); 07405 if (arg == NULL) 07406 XP_ERROR(XPATH_INVALID_OPERAND); 07407 val = xmlXPathCastToNumber(arg); 07408 xmlXPathReleaseObject(ctxt->context, arg); 07409 CAST_TO_NUMBER; 07410 CHECK_TYPE(XPATH_NUMBER); 07411 ctxt->value->floatval *= val; 07412 } 07413 07422 void 07423 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) { 07424 xmlXPathObjectPtr arg; 07425 double val; 07426 07427 arg = valuePop(ctxt); 07428 if (arg == NULL) 07429 XP_ERROR(XPATH_INVALID_OPERAND); 07430 val = xmlXPathCastToNumber(arg); 07431 xmlXPathReleaseObject(ctxt->context, arg); 07432 CAST_TO_NUMBER; 07433 CHECK_TYPE(XPATH_NUMBER); 07434 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval)) 07435 ctxt->value->floatval = xmlXPathNAN; 07436 else if (val == 0 && xmlXPathGetSign(val) != 0) { 07437 if (ctxt->value->floatval == 0) 07438 ctxt->value->floatval = xmlXPathNAN; 07439 else if (ctxt->value->floatval > 0) 07440 ctxt->value->floatval = xmlXPathNINF; 07441 else if (ctxt->value->floatval < 0) 07442 ctxt->value->floatval = xmlXPathPINF; 07443 } 07444 else if (val == 0) { 07445 if (ctxt->value->floatval == 0) 07446 ctxt->value->floatval = xmlXPathNAN; 07447 else if (ctxt->value->floatval > 0) 07448 ctxt->value->floatval = xmlXPathPINF; 07449 else if (ctxt->value->floatval < 0) 07450 ctxt->value->floatval = xmlXPathNINF; 07451 } else 07452 ctxt->value->floatval /= val; 07453 } 07454 07463 void 07464 xmlXPathModValues(xmlXPathParserContextPtr ctxt) { 07465 xmlXPathObjectPtr arg; 07466 double arg1, arg2; 07467 07468 arg = valuePop(ctxt); 07469 if (arg == NULL) 07470 XP_ERROR(XPATH_INVALID_OPERAND); 07471 arg2 = xmlXPathCastToNumber(arg); 07472 xmlXPathReleaseObject(ctxt->context, arg); 07473 CAST_TO_NUMBER; 07474 CHECK_TYPE(XPATH_NUMBER); 07475 arg1 = ctxt->value->floatval; 07476 if (arg2 == 0) 07477 ctxt->value->floatval = xmlXPathNAN; 07478 else { 07479 ctxt->value->floatval = fmod(arg1, arg2); 07480 } 07481 } 07482 07483 /************************************************************************ 07484 * * 07485 * The traversal functions * 07486 * * 07487 ************************************************************************/ 07488 07489 /* 07490 * A traversal function enumerates nodes along an axis. 07491 * Initially it must be called with NULL, and it indicates 07492 * termination on the axis by returning NULL. 07493 */ 07494 typedef xmlNodePtr (*xmlXPathTraversalFunction) 07495 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur); 07496 07497 /* 07498 * xmlXPathTraversalFunctionExt: 07499 * A traversal function enumerates nodes along an axis. 07500 * Initially it must be called with NULL, and it indicates 07501 * termination on the axis by returning NULL. 07502 * The context node of the traversal is specified via @contextNode. 07503 */ 07504 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt) 07505 (xmlNodePtr cur, xmlNodePtr contextNode); 07506 07507 /* 07508 * xmlXPathNodeSetMergeFunction: 07509 * Used for merging node sets in xmlXPathCollectAndTest(). 07510 */ 07511 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction) 07512 (xmlNodeSetPtr, xmlNodeSetPtr, int); 07513 07514 07525 xmlNodePtr 07526 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 07527 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 07528 if (cur == NULL) 07529 return(ctxt->context->node); 07530 return(NULL); 07531 } 07532 07543 xmlNodePtr 07544 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 07545 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 07546 if (cur == NULL) { 07547 if (ctxt->context->node == NULL) return(NULL); 07548 switch (ctxt->context->node->type) { 07549 case XML_ELEMENT_NODE: 07550 case XML_TEXT_NODE: 07551 case XML_CDATA_SECTION_NODE: 07552 case XML_ENTITY_REF_NODE: 07553 case XML_ENTITY_NODE: 07554 case XML_PI_NODE: 07555 case XML_COMMENT_NODE: 07556 case XML_NOTATION_NODE: 07557 case XML_DTD_NODE: 07558 return(ctxt->context->node->children); 07559 case XML_DOCUMENT_NODE: 07560 case XML_DOCUMENT_TYPE_NODE: 07561 case XML_DOCUMENT_FRAG_NODE: 07562 case XML_HTML_DOCUMENT_NODE: 07563 #ifdef LIBXML_DOCB_ENABLED 07564 case XML_DOCB_DOCUMENT_NODE: 07565 #endif 07566 return(((xmlDocPtr) ctxt->context->node)->children); 07567 case XML_ELEMENT_DECL: 07568 case XML_ATTRIBUTE_DECL: 07569 case XML_ENTITY_DECL: 07570 case XML_ATTRIBUTE_NODE: 07571 case XML_NAMESPACE_DECL: 07572 case XML_XINCLUDE_START: 07573 case XML_XINCLUDE_END: 07574 return(NULL); 07575 } 07576 return(NULL); 07577 } 07578 if ((cur->type == XML_DOCUMENT_NODE) || 07579 (cur->type == XML_HTML_DOCUMENT_NODE)) 07580 return(NULL); 07581 return(cur->next); 07582 } 07583 07594 static xmlNodePtr 07595 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 07596 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 07597 if (cur == NULL) { 07598 cur = ctxt->context->node; 07599 if (cur == NULL) return(NULL); 07600 /* 07601 * Get the first element child. 07602 */ 07603 switch (cur->type) { 07604 case XML_ELEMENT_NODE: 07605 case XML_DOCUMENT_FRAG_NODE: 07606 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */ 07607 case XML_ENTITY_NODE: 07608 cur = cur->children; 07609 if (cur != NULL) { 07610 if (cur->type == XML_ELEMENT_NODE) 07611 return(cur); 07612 do { 07613 cur = cur->next; 07614 } while ((cur != NULL) && 07615 (cur->type != XML_ELEMENT_NODE)); 07616 return(cur); 07617 } 07618 return(NULL); 07619 case XML_DOCUMENT_NODE: 07620 case XML_HTML_DOCUMENT_NODE: 07621 #ifdef LIBXML_DOCB_ENABLED 07622 case XML_DOCB_DOCUMENT_NODE: 07623 #endif 07624 return(xmlDocGetRootElement((xmlDocPtr) cur)); 07625 default: 07626 return(NULL); 07627 } 07628 return(NULL); 07629 } 07630 /* 07631 * Get the next sibling element node. 07632 */ 07633 switch (cur->type) { 07634 case XML_ELEMENT_NODE: 07635 case XML_TEXT_NODE: 07636 case XML_ENTITY_REF_NODE: 07637 case XML_ENTITY_NODE: 07638 case XML_CDATA_SECTION_NODE: 07639 case XML_PI_NODE: 07640 case XML_COMMENT_NODE: 07641 case XML_XINCLUDE_END: 07642 break; 07643 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */ 07644 default: 07645 return(NULL); 07646 } 07647 if (cur->next != NULL) { 07648 if (cur->next->type == XML_ELEMENT_NODE) 07649 return(cur->next); 07650 cur = cur->next; 07651 do { 07652 cur = cur->next; 07653 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE)); 07654 return(cur); 07655 } 07656 return(NULL); 07657 } 07658 07671 static xmlNodePtr 07672 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur, 07673 xmlNodePtr contextNode) 07674 { 07675 if (cur == NULL) { 07676 if (contextNode == NULL) 07677 return(NULL); 07678 switch (contextNode->type) { 07679 case XML_ELEMENT_NODE: 07680 case XML_XINCLUDE_START: 07681 case XML_DOCUMENT_FRAG_NODE: 07682 case XML_DOCUMENT_NODE: 07683 #ifdef LIBXML_DOCB_ENABLED 07684 case XML_DOCB_DOCUMENT_NODE: 07685 #endif 07686 case XML_HTML_DOCUMENT_NODE: 07687 return(contextNode); 07688 default: 07689 return(NULL); 07690 } 07691 return(NULL); 07692 } else { 07693 xmlNodePtr start = cur; 07694 07695 while (cur != NULL) { 07696 switch (cur->type) { 07697 case XML_ELEMENT_NODE: 07698 /* TODO: OK to have XInclude here? */ 07699 case XML_XINCLUDE_START: 07700 case XML_DOCUMENT_FRAG_NODE: 07701 if (cur != start) 07702 return(cur); 07703 if (cur->children != NULL) { 07704 cur = cur->children; 07705 continue; 07706 } 07707 break; 07708 /* Not sure if we need those here. */ 07709 case XML_DOCUMENT_NODE: 07710 #ifdef LIBXML_DOCB_ENABLED 07711 case XML_DOCB_DOCUMENT_NODE: 07712 #endif 07713 case XML_HTML_DOCUMENT_NODE: 07714 if (cur != start) 07715 return(cur); 07716 return(xmlDocGetRootElement((xmlDocPtr) cur)); 07717 default: 07718 break; 07719 } 07720 07721 next_sibling: 07722 if ((cur == NULL) || (cur == contextNode)) 07723 return(NULL); 07724 if (cur->next != NULL) { 07725 cur = cur->next; 07726 } else { 07727 cur = cur->parent; 07728 goto next_sibling; 07729 } 07730 } 07731 } 07732 return(NULL); 07733 } 07734 07746 xmlNodePtr 07747 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 07748 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 07749 if (cur == NULL) { 07750 if (ctxt->context->node == NULL) 07751 return(NULL); 07752 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 07753 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 07754 return(NULL); 07755 07756 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc) 07757 return(ctxt->context->doc->children); 07758 return(ctxt->context->node->children); 07759 } 07760 07761 if (cur->children != NULL) { 07762 /* 07763 * Do not descend on entities declarations 07764 */ 07765 if (cur->children->type != XML_ENTITY_DECL) { 07766 cur = cur->children; 07767 /* 07768 * Skip DTDs 07769 */ 07770 if (cur->type != XML_DTD_NODE) 07771 return(cur); 07772 } 07773 } 07774 07775 if (cur == ctxt->context->node) return(NULL); 07776 07777 while (cur->next != NULL) { 07778 cur = cur->next; 07779 if ((cur->type != XML_ENTITY_DECL) && 07780 (cur->type != XML_DTD_NODE)) 07781 return(cur); 07782 } 07783 07784 do { 07785 cur = cur->parent; 07786 if (cur == NULL) break; 07787 if (cur == ctxt->context->node) return(NULL); 07788 if (cur->next != NULL) { 07789 cur = cur->next; 07790 return(cur); 07791 } 07792 } while (cur != NULL); 07793 return(cur); 07794 } 07795 07809 xmlNodePtr 07810 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 07811 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 07812 if (cur == NULL) { 07813 if (ctxt->context->node == NULL) 07814 return(NULL); 07815 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 07816 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 07817 return(NULL); 07818 return(ctxt->context->node); 07819 } 07820 07821 return(xmlXPathNextDescendant(ctxt, cur)); 07822 } 07823 07834 xmlNodePtr 07835 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 07836 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 07837 /* 07838 * the parent of an attribute or namespace node is the element 07839 * to which the attribute or namespace node is attached 07840 * Namespace handling !!! 07841 */ 07842 if (cur == NULL) { 07843 if (ctxt->context->node == NULL) return(NULL); 07844 switch (ctxt->context->node->type) { 07845 case XML_ELEMENT_NODE: 07846 case XML_TEXT_NODE: 07847 case XML_CDATA_SECTION_NODE: 07848 case XML_ENTITY_REF_NODE: 07849 case XML_ENTITY_NODE: 07850 case XML_PI_NODE: 07851 case XML_COMMENT_NODE: 07852 case XML_NOTATION_NODE: 07853 case XML_DTD_NODE: 07854 case XML_ELEMENT_DECL: 07855 case XML_ATTRIBUTE_DECL: 07856 case XML_XINCLUDE_START: 07857 case XML_XINCLUDE_END: 07858 case XML_ENTITY_DECL: 07859 if (ctxt->context->node->parent == NULL) 07860 return((xmlNodePtr) ctxt->context->doc); 07861 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) && 07862 ((ctxt->context->node->parent->name[0] == ' ') || 07863 (xmlStrEqual(ctxt->context->node->parent->name, 07864 BAD_CAST "fake node libxslt")))) 07865 return(NULL); 07866 return(ctxt->context->node->parent); 07867 case XML_ATTRIBUTE_NODE: { 07868 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node; 07869 07870 return(att->parent); 07871 } 07872 case XML_DOCUMENT_NODE: 07873 case XML_DOCUMENT_TYPE_NODE: 07874 case XML_DOCUMENT_FRAG_NODE: 07875 case XML_HTML_DOCUMENT_NODE: 07876 #ifdef LIBXML_DOCB_ENABLED 07877 case XML_DOCB_DOCUMENT_NODE: 07878 #endif 07879 return(NULL); 07880 case XML_NAMESPACE_DECL: { 07881 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; 07882 07883 if ((ns->next != NULL) && 07884 (ns->next->type != XML_NAMESPACE_DECL)) 07885 return((xmlNodePtr) ns->next); 07886 return(NULL); 07887 } 07888 } 07889 } 07890 return(NULL); 07891 } 07892 07907 xmlNodePtr 07908 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 07909 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 07910 /* 07911 * the parent of an attribute or namespace node is the element 07912 * to which the attribute or namespace node is attached 07913 * !!!!!!!!!!!!! 07914 */ 07915 if (cur == NULL) { 07916 if (ctxt->context->node == NULL) return(NULL); 07917 switch (ctxt->context->node->type) { 07918 case XML_ELEMENT_NODE: 07919 case XML_TEXT_NODE: 07920 case XML_CDATA_SECTION_NODE: 07921 case XML_ENTITY_REF_NODE: 07922 case XML_ENTITY_NODE: 07923 case XML_PI_NODE: 07924 case XML_COMMENT_NODE: 07925 case XML_DTD_NODE: 07926 case XML_ELEMENT_DECL: 07927 case XML_ATTRIBUTE_DECL: 07928 case XML_ENTITY_DECL: 07929 case XML_NOTATION_NODE: 07930 case XML_XINCLUDE_START: 07931 case XML_XINCLUDE_END: 07932 if (ctxt->context->node->parent == NULL) 07933 return((xmlNodePtr) ctxt->context->doc); 07934 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) && 07935 ((ctxt->context->node->parent->name[0] == ' ') || 07936 (xmlStrEqual(ctxt->context->node->parent->name, 07937 BAD_CAST "fake node libxslt")))) 07938 return(NULL); 07939 return(ctxt->context->node->parent); 07940 case XML_ATTRIBUTE_NODE: { 07941 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node; 07942 07943 return(tmp->parent); 07944 } 07945 case XML_DOCUMENT_NODE: 07946 case XML_DOCUMENT_TYPE_NODE: 07947 case XML_DOCUMENT_FRAG_NODE: 07948 case XML_HTML_DOCUMENT_NODE: 07949 #ifdef LIBXML_DOCB_ENABLED 07950 case XML_DOCB_DOCUMENT_NODE: 07951 #endif 07952 return(NULL); 07953 case XML_NAMESPACE_DECL: { 07954 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; 07955 07956 if ((ns->next != NULL) && 07957 (ns->next->type != XML_NAMESPACE_DECL)) 07958 return((xmlNodePtr) ns->next); 07959 /* Bad, how did that namespace end up here ? */ 07960 return(NULL); 07961 } 07962 } 07963 return(NULL); 07964 } 07965 if (cur == ctxt->context->doc->children) 07966 return((xmlNodePtr) ctxt->context->doc); 07967 if (cur == (xmlNodePtr) ctxt->context->doc) 07968 return(NULL); 07969 switch (cur->type) { 07970 case XML_ELEMENT_NODE: 07971 case XML_TEXT_NODE: 07972 case XML_CDATA_SECTION_NODE: 07973 case XML_ENTITY_REF_NODE: 07974 case XML_ENTITY_NODE: 07975 case XML_PI_NODE: 07976 case XML_COMMENT_NODE: 07977 case XML_NOTATION_NODE: 07978 case XML_DTD_NODE: 07979 case XML_ELEMENT_DECL: 07980 case XML_ATTRIBUTE_DECL: 07981 case XML_ENTITY_DECL: 07982 case XML_XINCLUDE_START: 07983 case XML_XINCLUDE_END: 07984 if (cur->parent == NULL) 07985 return(NULL); 07986 if ((cur->parent->type == XML_ELEMENT_NODE) && 07987 ((cur->parent->name[0] == ' ') || 07988 (xmlStrEqual(cur->parent->name, 07989 BAD_CAST "fake node libxslt")))) 07990 return(NULL); 07991 return(cur->parent); 07992 case XML_ATTRIBUTE_NODE: { 07993 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node; 07994 07995 return(att->parent); 07996 } 07997 case XML_NAMESPACE_DECL: { 07998 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; 07999 08000 if ((ns->next != NULL) && 08001 (ns->next->type != XML_NAMESPACE_DECL)) 08002 return((xmlNodePtr) ns->next); 08003 /* Bad, how did that namespace end up here ? */ 08004 return(NULL); 08005 } 08006 case XML_DOCUMENT_NODE: 08007 case XML_DOCUMENT_TYPE_NODE: 08008 case XML_DOCUMENT_FRAG_NODE: 08009 case XML_HTML_DOCUMENT_NODE: 08010 #ifdef LIBXML_DOCB_ENABLED 08011 case XML_DOCB_DOCUMENT_NODE: 08012 #endif 08013 return(NULL); 08014 } 08015 return(NULL); 08016 } 08017 08031 xmlNodePtr 08032 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 08033 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 08034 if (cur == NULL) 08035 return(ctxt->context->node); 08036 return(xmlXPathNextAncestor(ctxt, cur)); 08037 } 08038 08050 xmlNodePtr 08051 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 08052 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 08053 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 08054 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 08055 return(NULL); 08056 if (cur == (xmlNodePtr) ctxt->context->doc) 08057 return(NULL); 08058 if (cur == NULL) 08059 return(ctxt->context->node->next); 08060 return(cur->next); 08061 } 08062 08075 xmlNodePtr 08076 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 08077 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 08078 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 08079 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 08080 return(NULL); 08081 if (cur == (xmlNodePtr) ctxt->context->doc) 08082 return(NULL); 08083 if (cur == NULL) 08084 return(ctxt->context->node->prev); 08085 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) { 08086 cur = cur->prev; 08087 if (cur == NULL) 08088 return(ctxt->context->node->prev); 08089 } 08090 return(cur->prev); 08091 } 08092 08106 xmlNodePtr 08107 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 08108 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 08109 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) && 08110 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL)) 08111 return(cur->children); 08112 08113 if (cur == NULL) { 08114 cur = ctxt->context->node; 08115 if (cur->type == XML_NAMESPACE_DECL) 08116 return(NULL); 08117 if (cur->type == XML_ATTRIBUTE_NODE) 08118 cur = cur->parent; 08119 } 08120 if (cur == NULL) return(NULL) ; /* ERROR */ 08121 if (cur->next != NULL) return(cur->next) ; 08122 do { 08123 cur = cur->parent; 08124 if (cur == NULL) break; 08125 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL); 08126 if (cur->next != NULL) return(cur->next); 08127 } while (cur != NULL); 08128 return(cur); 08129 } 08130 08131 /* 08132 * xmlXPathIsAncestor: 08133 * @ancestor: the ancestor node 08134 * @node: the current node 08135 * 08136 * Check that @ancestor is a @node's ancestor 08137 * 08138 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise. 08139 */ 08140 static int 08141 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) { 08142 if ((ancestor == NULL) || (node == NULL)) return(0); 08143 /* nodes need to be in the same document */ 08144 if (ancestor->doc != node->doc) return(0); 08145 /* avoid searching if ancestor or node is the root node */ 08146 if (ancestor == (xmlNodePtr) node->doc) return(1); 08147 if (node == (xmlNodePtr) ancestor->doc) return(0); 08148 while (node->parent != NULL) { 08149 if (node->parent == ancestor) 08150 return(1); 08151 node = node->parent; 08152 } 08153 return(0); 08154 } 08155 08169 xmlNodePtr 08170 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) 08171 { 08172 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 08173 if (cur == NULL) { 08174 cur = ctxt->context->node; 08175 if (cur->type == XML_NAMESPACE_DECL) 08176 return(NULL); 08177 if (cur->type == XML_ATTRIBUTE_NODE) 08178 return(cur->parent); 08179 } 08180 if (cur == NULL) 08181 return (NULL); 08182 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) 08183 cur = cur->prev; 08184 do { 08185 if (cur->prev != NULL) { 08186 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ; 08187 return (cur); 08188 } 08189 08190 cur = cur->parent; 08191 if (cur == NULL) 08192 return (NULL); 08193 if (cur == ctxt->context->doc->children) 08194 return (NULL); 08195 } while (xmlXPathIsAncestor(cur, ctxt->context->node)); 08196 return (cur); 08197 } 08198 08214 static xmlNodePtr 08215 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt, 08216 xmlNodePtr cur) 08217 { 08218 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 08219 if (cur == NULL) { 08220 cur = ctxt->context->node; 08221 if (cur == NULL) 08222 return (NULL); 08223 if (cur->type == XML_NAMESPACE_DECL) 08224 return (NULL); 08225 ctxt->ancestor = cur->parent; 08226 } 08227 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) 08228 cur = cur->prev; 08229 while (cur->prev == NULL) { 08230 cur = cur->parent; 08231 if (cur == NULL) 08232 return (NULL); 08233 if (cur == ctxt->context->doc->children) 08234 return (NULL); 08235 if (cur != ctxt->ancestor) 08236 return (cur); 08237 ctxt->ancestor = cur->parent; 08238 } 08239 cur = cur->prev; 08240 while (cur->last != NULL) 08241 cur = cur->last; 08242 return (cur); 08243 } 08244 08259 xmlNodePtr 08260 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 08261 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 08262 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL); 08263 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) { 08264 if (ctxt->context->tmpNsList != NULL) 08265 xmlFree(ctxt->context->tmpNsList); 08266 ctxt->context->tmpNsList = 08267 xmlGetNsList(ctxt->context->doc, ctxt->context->node); 08268 ctxt->context->tmpNsNr = 0; 08269 if (ctxt->context->tmpNsList != NULL) { 08270 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) { 08271 ctxt->context->tmpNsNr++; 08272 } 08273 } 08274 return((xmlNodePtr) xmlXPathXMLNamespace); 08275 } 08276 if (ctxt->context->tmpNsNr > 0) { 08277 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr]; 08278 } else { 08279 if (ctxt->context->tmpNsList != NULL) 08280 xmlFree(ctxt->context->tmpNsList); 08281 ctxt->context->tmpNsList = NULL; 08282 return(NULL); 08283 } 08284 } 08285 08296 xmlNodePtr 08297 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 08298 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 08299 if (ctxt->context->node == NULL) 08300 return(NULL); 08301 if (ctxt->context->node->type != XML_ELEMENT_NODE) 08302 return(NULL); 08303 if (cur == NULL) { 08304 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc) 08305 return(NULL); 08306 return((xmlNodePtr)ctxt->context->node->properties); 08307 } 08308 return((xmlNodePtr)cur->next); 08309 } 08310 08311 /************************************************************************ 08312 * * 08313 * NodeTest Functions * 08314 * * 08315 ************************************************************************/ 08316 08317 #define IS_FUNCTION 200 08318 08319 08320 /************************************************************************ 08321 * * 08322 * Implicit tree core function library * 08323 * * 08324 ************************************************************************/ 08325 08332 void 08333 xmlXPathRoot(xmlXPathParserContextPtr ctxt) { 08334 if ((ctxt == NULL) || (ctxt->context == NULL)) 08335 return; 08336 ctxt->context->node = (xmlNodePtr) ctxt->context->doc; 08337 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 08338 ctxt->context->node)); 08339 } 08340 08341 /************************************************************************ 08342 * * 08343 * The explicit core function library * 08344 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib * 08345 * * 08346 ************************************************************************/ 08347 08348 08358 void 08359 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) { 08360 CHECK_ARITY(0); 08361 if (ctxt->context->contextSize >= 0) { 08362 valuePush(ctxt, 08363 xmlXPathCacheNewFloat(ctxt->context, 08364 (double) ctxt->context->contextSize)); 08365 #ifdef DEBUG_EXPR 08366 xmlGenericError(xmlGenericErrorContext, 08367 "last() : %d\n", ctxt->context->contextSize); 08368 #endif 08369 } else { 08370 XP_ERROR(XPATH_INVALID_CTXT_SIZE); 08371 } 08372 } 08373 08385 void 08386 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) { 08387 CHECK_ARITY(0); 08388 if (ctxt->context->proximityPosition >= 0) { 08389 valuePush(ctxt, 08390 xmlXPathCacheNewFloat(ctxt->context, 08391 (double) ctxt->context->proximityPosition)); 08392 #ifdef DEBUG_EXPR 08393 xmlGenericError(xmlGenericErrorContext, "position() : %d\n", 08394 ctxt->context->proximityPosition); 08395 #endif 08396 } else { 08397 XP_ERROR(XPATH_INVALID_CTXT_POSITION); 08398 } 08399 } 08400 08409 void 08410 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) { 08411 xmlXPathObjectPtr cur; 08412 08413 CHECK_ARITY(1); 08414 if ((ctxt->value == NULL) || 08415 ((ctxt->value->type != XPATH_NODESET) && 08416 (ctxt->value->type != XPATH_XSLT_TREE))) 08417 XP_ERROR(XPATH_INVALID_TYPE); 08418 cur = valuePop(ctxt); 08419 08420 if ((cur == NULL) || (cur->nodesetval == NULL)) 08421 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0)); 08422 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) { 08423 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 08424 (double) cur->nodesetval->nodeNr)); 08425 } else { 08426 if ((cur->nodesetval->nodeNr != 1) || 08427 (cur->nodesetval->nodeTab == NULL)) { 08428 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0)); 08429 } else { 08430 xmlNodePtr tmp; 08431 int i = 0; 08432 08433 tmp = cur->nodesetval->nodeTab[0]; 08434 if (tmp != NULL) { 08435 tmp = tmp->children; 08436 while (tmp != NULL) { 08437 tmp = tmp->next; 08438 i++; 08439 } 08440 } 08441 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i)); 08442 } 08443 } 08444 xmlXPathReleaseObject(ctxt->context, cur); 08445 } 08446 08456 static xmlNodeSetPtr 08457 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) { 08458 xmlNodeSetPtr ret; 08459 const xmlChar *cur = ids; 08460 xmlChar *ID; 08461 xmlAttrPtr attr; 08462 xmlNodePtr elem = NULL; 08463 08464 if (ids == NULL) return(NULL); 08465 08466 ret = xmlXPathNodeSetCreate(NULL); 08467 if (ret == NULL) 08468 return(ret); 08469 08470 while (IS_BLANK_CH(*cur)) cur++; 08471 while (*cur != 0) { 08472 while ((!IS_BLANK_CH(*cur)) && (*cur != 0)) 08473 cur++; 08474 08475 ID = xmlStrndup(ids, cur - ids); 08476 if (ID != NULL) { 08477 /* 08478 * We used to check the fact that the value passed 08479 * was an NCName, but this generated much troubles for 08480 * me and Aleksey Sanin, people blatantly violated that 08481 * constaint, like Visa3D spec. 08482 * if (xmlValidateNCName(ID, 1) == 0) 08483 */ 08484 attr = xmlGetID(doc, ID); 08485 if (attr != NULL) { 08486 if (attr->type == XML_ATTRIBUTE_NODE) 08487 elem = attr->parent; 08488 else if (attr->type == XML_ELEMENT_NODE) 08489 elem = (xmlNodePtr) attr; 08490 else 08491 elem = NULL; 08492 if (elem != NULL) 08493 xmlXPathNodeSetAdd(ret, elem); 08494 } 08495 xmlFree(ID); 08496 } 08497 08498 while (IS_BLANK_CH(*cur)) cur++; 08499 ids = cur; 08500 } 08501 return(ret); 08502 } 08503 08522 void 08523 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) { 08524 xmlChar *tokens; 08525 xmlNodeSetPtr ret; 08526 xmlXPathObjectPtr obj; 08527 08528 CHECK_ARITY(1); 08529 obj = valuePop(ctxt); 08530 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 08531 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) { 08532 xmlNodeSetPtr ns; 08533 int i; 08534 08535 ret = xmlXPathNodeSetCreate(NULL); 08536 /* 08537 * FIXME -- in an out-of-memory condition this will behave badly. 08538 * The solution is not clear -- we already popped an item from 08539 * ctxt, so the object is in a corrupt state. 08540 */ 08541 08542 if (obj->nodesetval != NULL) { 08543 for (i = 0; i < obj->nodesetval->nodeNr; i++) { 08544 tokens = 08545 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]); 08546 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens); 08547 ret = xmlXPathNodeSetMerge(ret, ns); 08548 xmlXPathFreeNodeSet(ns); 08549 if (tokens != NULL) 08550 xmlFree(tokens); 08551 } 08552 } 08553 xmlXPathReleaseObject(ctxt->context, obj); 08554 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret)); 08555 return; 08556 } 08557 obj = xmlXPathCacheConvertString(ctxt->context, obj); 08558 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval); 08559 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret)); 08560 xmlXPathReleaseObject(ctxt->context, obj); 08561 return; 08562 } 08563 08577 void 08578 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) { 08579 xmlXPathObjectPtr cur; 08580 08581 if (ctxt == NULL) return; 08582 08583 if (nargs == 0) { 08584 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 08585 ctxt->context->node)); 08586 nargs = 1; 08587 } 08588 08589 CHECK_ARITY(1); 08590 if ((ctxt->value == NULL) || 08591 ((ctxt->value->type != XPATH_NODESET) && 08592 (ctxt->value->type != XPATH_XSLT_TREE))) 08593 XP_ERROR(XPATH_INVALID_TYPE); 08594 cur = valuePop(ctxt); 08595 08596 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 08597 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 08598 } else { 08599 int i = 0; /* Should be first in document order !!!!! */ 08600 switch (cur->nodesetval->nodeTab[i]->type) { 08601 case XML_ELEMENT_NODE: 08602 case XML_ATTRIBUTE_NODE: 08603 case XML_PI_NODE: 08604 if (cur->nodesetval->nodeTab[i]->name[0] == ' ') 08605 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 08606 else 08607 valuePush(ctxt, 08608 xmlXPathCacheNewString(ctxt->context, 08609 cur->nodesetval->nodeTab[i]->name)); 08610 break; 08611 case XML_NAMESPACE_DECL: 08612 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 08613 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix)); 08614 break; 08615 default: 08616 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 08617 } 08618 } 08619 xmlXPathReleaseObject(ctxt->context, cur); 08620 } 08621 08636 void 08637 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) { 08638 xmlXPathObjectPtr cur; 08639 08640 if (ctxt == NULL) return; 08641 08642 if (nargs == 0) { 08643 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 08644 ctxt->context->node)); 08645 nargs = 1; 08646 } 08647 CHECK_ARITY(1); 08648 if ((ctxt->value == NULL) || 08649 ((ctxt->value->type != XPATH_NODESET) && 08650 (ctxt->value->type != XPATH_XSLT_TREE))) 08651 XP_ERROR(XPATH_INVALID_TYPE); 08652 cur = valuePop(ctxt); 08653 08654 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 08655 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 08656 } else { 08657 int i = 0; /* Should be first in document order !!!!! */ 08658 switch (cur->nodesetval->nodeTab[i]->type) { 08659 case XML_ELEMENT_NODE: 08660 case XML_ATTRIBUTE_NODE: 08661 if (cur->nodesetval->nodeTab[i]->ns == NULL) 08662 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 08663 else 08664 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 08665 cur->nodesetval->nodeTab[i]->ns->href)); 08666 break; 08667 default: 08668 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 08669 } 08670 } 08671 xmlXPathReleaseObject(ctxt->context, cur); 08672 } 08673 08696 static void 08697 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) 08698 { 08699 xmlXPathObjectPtr cur; 08700 08701 if (nargs == 0) { 08702 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 08703 ctxt->context->node)); 08704 nargs = 1; 08705 } 08706 08707 CHECK_ARITY(1); 08708 if ((ctxt->value == NULL) || 08709 ((ctxt->value->type != XPATH_NODESET) && 08710 (ctxt->value->type != XPATH_XSLT_TREE))) 08711 XP_ERROR(XPATH_INVALID_TYPE); 08712 cur = valuePop(ctxt); 08713 08714 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 08715 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 08716 } else { 08717 int i = 0; /* Should be first in document order !!!!! */ 08718 08719 switch (cur->nodesetval->nodeTab[i]->type) { 08720 case XML_ELEMENT_NODE: 08721 case XML_ATTRIBUTE_NODE: 08722 if (cur->nodesetval->nodeTab[i]->name[0] == ' ') 08723 valuePush(ctxt, 08724 xmlXPathCacheNewCString(ctxt->context, "")); 08725 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) || 08726 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) { 08727 valuePush(ctxt, 08728 xmlXPathCacheNewString(ctxt->context, 08729 cur->nodesetval->nodeTab[i]->name)); 08730 } else { 08731 xmlChar *fullname; 08732 08733 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name, 08734 cur->nodesetval->nodeTab[i]->ns->prefix, 08735 NULL, 0); 08736 if (fullname == cur->nodesetval->nodeTab[i]->name) 08737 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name); 08738 if (fullname == NULL) { 08739 XP_ERROR(XPATH_MEMORY_ERROR); 08740 } 08741 valuePush(ctxt, xmlXPathCacheWrapString( 08742 ctxt->context, fullname)); 08743 } 08744 break; 08745 default: 08746 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 08747 cur->nodesetval->nodeTab[i])); 08748 xmlXPathLocalNameFunction(ctxt, 1); 08749 } 08750 } 08751 xmlXPathReleaseObject(ctxt->context, cur); 08752 } 08753 08754 08791 void 08792 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) { 08793 xmlXPathObjectPtr cur; 08794 08795 if (ctxt == NULL) return; 08796 if (nargs == 0) { 08797 valuePush(ctxt, 08798 xmlXPathCacheWrapString(ctxt->context, 08799 xmlXPathCastNodeToString(ctxt->context->node))); 08800 return; 08801 } 08802 08803 CHECK_ARITY(1); 08804 cur = valuePop(ctxt); 08805 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 08806 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur)); 08807 } 08808 08821 void 08822 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) { 08823 xmlXPathObjectPtr cur; 08824 08825 if (nargs == 0) { 08826 if ((ctxt == NULL) || (ctxt->context == NULL)) 08827 return; 08828 if (ctxt->context->node == NULL) { 08829 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0)); 08830 } else { 08831 xmlChar *content; 08832 08833 content = xmlXPathCastNodeToString(ctxt->context->node); 08834 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 08835 xmlUTF8Strlen(content))); 08836 xmlFree(content); 08837 } 08838 return; 08839 } 08840 CHECK_ARITY(1); 08841 CAST_TO_STRING; 08842 CHECK_TYPE(XPATH_STRING); 08843 cur = valuePop(ctxt); 08844 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 08845 xmlUTF8Strlen(cur->stringval))); 08846 xmlXPathReleaseObject(ctxt->context, cur); 08847 } 08848 08858 void 08859 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) { 08860 xmlXPathObjectPtr cur, newobj; 08861 xmlChar *tmp; 08862 08863 if (ctxt == NULL) return; 08864 if (nargs < 2) { 08865 CHECK_ARITY(2); 08866 } 08867 08868 CAST_TO_STRING; 08869 cur = valuePop(ctxt); 08870 if ((cur == NULL) || (cur->type != XPATH_STRING)) { 08871 xmlXPathReleaseObject(ctxt->context, cur); 08872 return; 08873 } 08874 nargs--; 08875 08876 while (nargs > 0) { 08877 CAST_TO_STRING; 08878 newobj = valuePop(ctxt); 08879 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) { 08880 xmlXPathReleaseObject(ctxt->context, newobj); 08881 xmlXPathReleaseObject(ctxt->context, cur); 08882 XP_ERROR(XPATH_INVALID_TYPE); 08883 } 08884 tmp = xmlStrcat(newobj->stringval, cur->stringval); 08885 newobj->stringval = cur->stringval; 08886 cur->stringval = tmp; 08887 xmlXPathReleaseObject(ctxt->context, newobj); 08888 nargs--; 08889 } 08890 valuePush(ctxt, cur); 08891 } 08892 08903 void 08904 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) { 08905 xmlXPathObjectPtr hay, needle; 08906 08907 CHECK_ARITY(2); 08908 CAST_TO_STRING; 08909 CHECK_TYPE(XPATH_STRING); 08910 needle = valuePop(ctxt); 08911 CAST_TO_STRING; 08912 hay = valuePop(ctxt); 08913 08914 if ((hay == NULL) || (hay->type != XPATH_STRING)) { 08915 xmlXPathReleaseObject(ctxt->context, hay); 08916 xmlXPathReleaseObject(ctxt->context, needle); 08917 XP_ERROR(XPATH_INVALID_TYPE); 08918 } 08919 if (xmlStrstr(hay->stringval, needle->stringval)) 08920 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); 08921 else 08922 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); 08923 xmlXPathReleaseObject(ctxt->context, hay); 08924 xmlXPathReleaseObject(ctxt->context, needle); 08925 } 08926 08937 void 08938 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) { 08939 xmlXPathObjectPtr hay, needle; 08940 int n; 08941 08942 CHECK_ARITY(2); 08943 CAST_TO_STRING; 08944 CHECK_TYPE(XPATH_STRING); 08945 needle = valuePop(ctxt); 08946 CAST_TO_STRING; 08947 hay = valuePop(ctxt); 08948 08949 if ((hay == NULL) || (hay->type != XPATH_STRING)) { 08950 xmlXPathReleaseObject(ctxt->context, hay); 08951 xmlXPathReleaseObject(ctxt->context, needle); 08952 XP_ERROR(XPATH_INVALID_TYPE); 08953 } 08954 n = xmlStrlen(needle->stringval); 08955 if (xmlStrncmp(hay->stringval, needle->stringval, n)) 08956 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); 08957 else 08958 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); 08959 xmlXPathReleaseObject(ctxt->context, hay); 08960 xmlXPathReleaseObject(ctxt->context, needle); 08961 } 08962 08991 void 08992 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) { 08993 xmlXPathObjectPtr str, start, len; 08994 double le=0, in; 08995 int i, l, m; 08996 xmlChar *ret; 08997 08998 if (nargs < 2) { 08999 CHECK_ARITY(2); 09000 } 09001 if (nargs > 3) { 09002 CHECK_ARITY(3); 09003 } 09004 /* 09005 * take care of possible last (position) argument 09006 */ 09007 if (nargs == 3) { 09008 CAST_TO_NUMBER; 09009 CHECK_TYPE(XPATH_NUMBER); 09010 len = valuePop(ctxt); 09011 le = len->floatval; 09012 xmlXPathReleaseObject(ctxt->context, len); 09013 } 09014 09015 CAST_TO_NUMBER; 09016 CHECK_TYPE(XPATH_NUMBER); 09017 start = valuePop(ctxt); 09018 in = start->floatval; 09019 xmlXPathReleaseObject(ctxt->context, start); 09020 CAST_TO_STRING; 09021 CHECK_TYPE(XPATH_STRING); 09022 str = valuePop(ctxt); 09023 m = xmlUTF8Strlen((const unsigned char *)str->stringval); 09024 09025 /* 09026 * If last pos not present, calculate last position 09027 */ 09028 if (nargs != 3) { 09029 le = (double)m; 09030 if (in < 1.0) 09031 in = 1.0; 09032 } 09033 09034 /* Need to check for the special cases where either 09035 * the index is NaN, the length is NaN, or both 09036 * arguments are infinity (relying on Inf + -Inf = NaN) 09037 */ 09038 if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) { 09039 /* 09040 * To meet the requirements of the spec, the arguments 09041 * must be converted to integer format before 09042 * initial index calculations are done 09043 * 09044 * First we go to integer form, rounding up 09045 * and checking for special cases 09046 */ 09047 i = (int) in; 09048 if (((double)i)+0.5 <= in) i++; 09049 09050 if (xmlXPathIsInf(le) == 1) { 09051 l = m; 09052 if (i < 1) 09053 i = 1; 09054 } 09055 else if (xmlXPathIsInf(le) == -1 || le < 0.0) 09056 l = 0; 09057 else { 09058 l = (int) le; 09059 if (((double)l)+0.5 <= le) l++; 09060 } 09061 09062 /* Now we normalize inidices */ 09063 i -= 1; 09064 l += i; 09065 if (i < 0) 09066 i = 0; 09067 if (l > m) 09068 l = m; 09069 09070 /* number of chars to copy */ 09071 l -= i; 09072 09073 ret = xmlUTF8Strsub(str->stringval, i, l); 09074 } 09075 else { 09076 ret = NULL; 09077 } 09078 if (ret == NULL) 09079 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 09080 else { 09081 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret)); 09082 xmlFree(ret); 09083 } 09084 xmlXPathReleaseObject(ctxt->context, str); 09085 } 09086 09100 void 09101 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) { 09102 xmlXPathObjectPtr str; 09103 xmlXPathObjectPtr find; 09104 xmlBufferPtr target; 09105 const xmlChar *point; 09106 int offset; 09107 09108 CHECK_ARITY(2); 09109 CAST_TO_STRING; 09110 find = valuePop(ctxt); 09111 CAST_TO_STRING; 09112 str = valuePop(ctxt); 09113 09114 target = xmlBufferCreate(); 09115 if (target) { 09116 point = xmlStrstr(str->stringval, find->stringval); 09117 if (point) { 09118 offset = (int)(point - str->stringval); 09119 xmlBufferAdd(target, str->stringval, offset); 09120 } 09121 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 09122 xmlBufferContent(target))); 09123 xmlBufferFree(target); 09124 } 09125 xmlXPathReleaseObject(ctxt->context, str); 09126 xmlXPathReleaseObject(ctxt->context, find); 09127 } 09128 09143 void 09144 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) { 09145 xmlXPathObjectPtr str; 09146 xmlXPathObjectPtr find; 09147 xmlBufferPtr target; 09148 const xmlChar *point; 09149 int offset; 09150 09151 CHECK_ARITY(2); 09152 CAST_TO_STRING; 09153 find = valuePop(ctxt); 09154 CAST_TO_STRING; 09155 str = valuePop(ctxt); 09156 09157 target = xmlBufferCreate(); 09158 if (target) { 09159 point = xmlStrstr(str->stringval, find->stringval); 09160 if (point) { 09161 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval); 09162 xmlBufferAdd(target, &str->stringval[offset], 09163 xmlStrlen(str->stringval) - offset); 09164 } 09165 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 09166 xmlBufferContent(target))); 09167 xmlBufferFree(target); 09168 } 09169 xmlXPathReleaseObject(ctxt->context, str); 09170 xmlXPathReleaseObject(ctxt->context, find); 09171 } 09172 09187 void 09188 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) { 09189 xmlXPathObjectPtr obj = NULL; 09190 xmlChar *source = NULL; 09191 xmlBufferPtr target; 09192 xmlChar blank; 09193 09194 if (ctxt == NULL) return; 09195 if (nargs == 0) { 09196 /* Use current context node */ 09197 valuePush(ctxt, 09198 xmlXPathCacheWrapString(ctxt->context, 09199 xmlXPathCastNodeToString(ctxt->context->node))); 09200 nargs = 1; 09201 } 09202 09203 CHECK_ARITY(1); 09204 CAST_TO_STRING; 09205 CHECK_TYPE(XPATH_STRING); 09206 obj = valuePop(ctxt); 09207 source = obj->stringval; 09208 09209 target = xmlBufferCreate(); 09210 if (target && source) { 09211 09212 /* Skip leading whitespaces */ 09213 while (IS_BLANK_CH(*source)) 09214 source++; 09215 09216 /* Collapse intermediate whitespaces, and skip trailing whitespaces */ 09217 blank = 0; 09218 while (*source) { 09219 if (IS_BLANK_CH(*source)) { 09220 blank = 0x20; 09221 } else { 09222 if (blank) { 09223 xmlBufferAdd(target, &blank, 1); 09224 blank = 0; 09225 } 09226 xmlBufferAdd(target, source, 1); 09227 } 09228 source++; 09229 } 09230 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 09231 xmlBufferContent(target))); 09232 xmlBufferFree(target); 09233 } 09234 xmlXPathReleaseObject(ctxt->context, obj); 09235 } 09236 09258 void 09259 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) { 09260 xmlXPathObjectPtr str; 09261 xmlXPathObjectPtr from; 09262 xmlXPathObjectPtr to; 09263 xmlBufferPtr target; 09264 int offset, max; 09265 xmlChar ch; 09266 const xmlChar *point; 09267 xmlChar *cptr; 09268 09269 CHECK_ARITY(3); 09270 09271 CAST_TO_STRING; 09272 to = valuePop(ctxt); 09273 CAST_TO_STRING; 09274 from = valuePop(ctxt); 09275 CAST_TO_STRING; 09276 str = valuePop(ctxt); 09277 09278 target = xmlBufferCreate(); 09279 if (target) { 09280 max = xmlUTF8Strlen(to->stringval); 09281 for (cptr = str->stringval; (ch=*cptr); ) { 09282 offset = xmlUTF8Strloc(from->stringval, cptr); 09283 if (offset >= 0) { 09284 if (offset < max) { 09285 point = xmlUTF8Strpos(to->stringval, offset); 09286 if (point) 09287 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1)); 09288 } 09289 } else 09290 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1)); 09291 09292 /* Step to next character in input */ 09293 cptr++; 09294 if ( ch & 0x80 ) { 09295 /* if not simple ascii, verify proper format */ 09296 if ( (ch & 0xc0) != 0xc0 ) { 09297 xmlGenericError(xmlGenericErrorContext, 09298 "xmlXPathTranslateFunction: Invalid UTF8 string\n"); 09299 break; 09300 } 09301 /* then skip over remaining bytes for this char */ 09302 while ( (ch <<= 1) & 0x80 ) 09303 if ( (*cptr++ & 0xc0) != 0x80 ) { 09304 xmlGenericError(xmlGenericErrorContext, 09305 "xmlXPathTranslateFunction: Invalid UTF8 string\n"); 09306 break; 09307 } 09308 if (ch & 0x80) /* must have had error encountered */ 09309 break; 09310 } 09311 } 09312 } 09313 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 09314 xmlBufferContent(target))); 09315 xmlBufferFree(target); 09316 xmlXPathReleaseObject(ctxt->context, str); 09317 xmlXPathReleaseObject(ctxt->context, from); 09318 xmlXPathReleaseObject(ctxt->context, to); 09319 } 09320 09334 void 09335 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) { 09336 xmlXPathObjectPtr cur; 09337 09338 CHECK_ARITY(1); 09339 cur = valuePop(ctxt); 09340 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 09341 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur); 09342 valuePush(ctxt, cur); 09343 } 09344 09355 void 09356 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) { 09357 CHECK_ARITY(1); 09358 CAST_TO_BOOLEAN; 09359 CHECK_TYPE(XPATH_BOOLEAN); 09360 ctxt->value->boolval = ! ctxt->value->boolval; 09361 } 09362 09371 void 09372 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) { 09373 CHECK_ARITY(0); 09374 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); 09375 } 09376 09385 void 09386 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) { 09387 CHECK_ARITY(0); 09388 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); 09389 } 09390 09412 void 09413 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) { 09414 xmlXPathObjectPtr val = NULL; 09415 const xmlChar *theLang = NULL; 09416 const xmlChar *lang; 09417 int ret = 0; 09418 int i; 09419 09420 CHECK_ARITY(1); 09421 CAST_TO_STRING; 09422 CHECK_TYPE(XPATH_STRING); 09423 val = valuePop(ctxt); 09424 lang = val->stringval; 09425 theLang = xmlNodeGetLang(ctxt->context->node); 09426 if ((theLang != NULL) && (lang != NULL)) { 09427 for (i = 0;lang[i] != 0;i++) 09428 if (toupper(lang[i]) != toupper(theLang[i])) 09429 goto not_equal; 09430 if ((theLang[i] == 0) || (theLang[i] == '-')) 09431 ret = 1; 09432 } 09433 not_equal: 09434 if (theLang != NULL) 09435 xmlFree((void *)theLang); 09436 09437 xmlXPathReleaseObject(ctxt->context, val); 09438 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret)); 09439 } 09440 09449 void 09450 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) { 09451 xmlXPathObjectPtr cur; 09452 double res; 09453 09454 if (ctxt == NULL) return; 09455 if (nargs == 0) { 09456 if (ctxt->context->node == NULL) { 09457 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0)); 09458 } else { 09459 xmlChar* content = xmlNodeGetContent(ctxt->context->node); 09460 09461 res = xmlXPathStringEvalNumber(content); 09462 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res)); 09463 xmlFree(content); 09464 } 09465 return; 09466 } 09467 09468 CHECK_ARITY(1); 09469 cur = valuePop(ctxt); 09470 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur)); 09471 } 09472 09483 void 09484 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) { 09485 xmlXPathObjectPtr cur; 09486 int i; 09487 double res = 0.0; 09488 09489 CHECK_ARITY(1); 09490 if ((ctxt->value == NULL) || 09491 ((ctxt->value->type != XPATH_NODESET) && 09492 (ctxt->value->type != XPATH_XSLT_TREE))) 09493 XP_ERROR(XPATH_INVALID_TYPE); 09494 cur = valuePop(ctxt); 09495 09496 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) { 09497 for (i = 0; i < cur->nodesetval->nodeNr; i++) { 09498 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]); 09499 } 09500 } 09501 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res)); 09502 xmlXPathReleaseObject(ctxt->context, cur); 09503 } 09504 09505 /* 09506 * To assure working code on multiple platforms, we want to only depend 09507 * upon the characteristic truncation of converting a floating point value 09508 * to an integer. Unfortunately, because of the different storage sizes 09509 * of our internal floating point value (double) and integer (int), we 09510 * can't directly convert (see bug 301162). This macro is a messy 09511 * 'workaround' 09512 */ 09513 #define XTRUNC(f, v) \ 09514 f = fmod((v), INT_MAX); \ 09515 f = (v) - (f) + (double)((int)(f)); 09516 09527 void 09528 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) { 09529 double f; 09530 09531 CHECK_ARITY(1); 09532 CAST_TO_NUMBER; 09533 CHECK_TYPE(XPATH_NUMBER); 09534 09535 XTRUNC(f, ctxt->value->floatval); 09536 if (f != ctxt->value->floatval) { 09537 if (ctxt->value->floatval > 0) 09538 ctxt->value->floatval = f; 09539 else 09540 ctxt->value->floatval = f - 1; 09541 } 09542 } 09543 09554 void 09555 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) { 09556 double f; 09557 09558 CHECK_ARITY(1); 09559 CAST_TO_NUMBER; 09560 CHECK_TYPE(XPATH_NUMBER); 09561 09562 #if 0 09563 ctxt->value->floatval = ceil(ctxt->value->floatval); 09564 #else 09565 XTRUNC(f, ctxt->value->floatval); 09566 if (f != ctxt->value->floatval) { 09567 if (ctxt->value->floatval > 0) 09568 ctxt->value->floatval = f + 1; 09569 else { 09570 if (ctxt->value->floatval < 0 && f == 0) 09571 ctxt->value->floatval = xmlXPathNZERO; 09572 else 09573 ctxt->value->floatval = f; 09574 } 09575 09576 } 09577 #endif 09578 } 09579 09591 void 09592 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) { 09593 double f; 09594 09595 CHECK_ARITY(1); 09596 CAST_TO_NUMBER; 09597 CHECK_TYPE(XPATH_NUMBER); 09598 09599 if ((xmlXPathIsNaN(ctxt->value->floatval)) || 09600 (xmlXPathIsInf(ctxt->value->floatval) == 1) || 09601 (xmlXPathIsInf(ctxt->value->floatval) == -1) || 09602 (ctxt->value->floatval == 0.0)) 09603 return; 09604 09605 XTRUNC(f, ctxt->value->floatval); 09606 if (ctxt->value->floatval < 0) { 09607 if (ctxt->value->floatval < f - 0.5) 09608 ctxt->value->floatval = f - 1; 09609 else 09610 ctxt->value->floatval = f; 09611 if (ctxt->value->floatval == 0) 09612 ctxt->value->floatval = xmlXPathNZERO; 09613 } else { 09614 if (ctxt->value->floatval < f + 0.5) 09615 ctxt->value->floatval = f; 09616 else 09617 ctxt->value->floatval = f + 1; 09618 } 09619 } 09620 09621 /************************************************************************ 09622 * * 09623 * The Parser * 09624 * * 09625 ************************************************************************/ 09626 09627 /* 09628 * a few forward declarations since we use a recursive call based 09629 * implementation. 09630 */ 09631 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort); 09632 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter); 09633 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt); 09634 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt); 09635 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, 09636 int qualified); 09637 09650 static int 09651 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) { 09652 unsigned char c; 09653 unsigned int val; 09654 const xmlChar *cur; 09655 09656 if (ctxt == NULL) 09657 return(0); 09658 cur = ctxt->cur; 09659 09660 /* 09661 * We are supposed to handle UTF8, check it's valid 09662 * From rfc2044: encoding of the Unicode values on UTF-8: 09663 * 09664 * UCS-4 range (hex.) UTF-8 octet sequence (binary) 09665 * 0000 0000-0000 007F 0xxxxxxx 09666 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx 09667 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx 09668 * 09669 * Check for the 0x110000 limit too 09670 */ 09671 c = *cur; 09672 if (c & 0x80) { 09673 if ((cur[1] & 0xc0) != 0x80) 09674 goto encoding_error; 09675 if ((c & 0xe0) == 0xe0) { 09676 09677 if ((cur[2] & 0xc0) != 0x80) 09678 goto encoding_error; 09679 if ((c & 0xf0) == 0xf0) { 09680 if (((c & 0xf8) != 0xf0) || 09681 ((cur[3] & 0xc0) != 0x80)) 09682 goto encoding_error; 09683 /* 4-byte code */ 09684 *len = 4; 09685 val = (cur[0] & 0x7) << 18; 09686 val |= (cur[1] & 0x3f) << 12; 09687 val |= (cur[2] & 0x3f) << 6; 09688 val |= cur[3] & 0x3f; 09689 } else { 09690 /* 3-byte code */ 09691 *len = 3; 09692 val = (cur[0] & 0xf) << 12; 09693 val |= (cur[1] & 0x3f) << 6; 09694 val |= cur[2] & 0x3f; 09695 } 09696 } else { 09697 /* 2-byte code */ 09698 *len = 2; 09699 val = (cur[0] & 0x1f) << 6; 09700 val |= cur[1] & 0x3f; 09701 } 09702 if (!IS_CHAR(val)) { 09703 XP_ERROR0(XPATH_INVALID_CHAR_ERROR); 09704 } 09705 return(val); 09706 } else { 09707 /* 1-byte code */ 09708 *len = 1; 09709 return((int) *cur); 09710 } 09711 encoding_error: 09712 /* 09713 * If we detect an UTF8 error that probably means that the 09714 * input encoding didn't get properly advertised in the 09715 * declaration header. Report the error and switch the encoding 09716 * to ISO-Latin-1 (if you don't like this policy, just declare the 09717 * encoding !) 09718 */ 09719 *len = 0; 09720 XP_ERROR0(XPATH_ENCODING_ERROR); 09721 } 09722 09737 xmlChar * 09738 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) { 09739 const xmlChar *in; 09740 xmlChar *ret; 09741 int count = 0; 09742 09743 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL); 09744 /* 09745 * Accelerator for simple ASCII names 09746 */ 09747 in = ctxt->cur; 09748 if (((*in >= 0x61) && (*in <= 0x7A)) || 09749 ((*in >= 0x41) && (*in <= 0x5A)) || 09750 (*in == '_')) { 09751 in++; 09752 while (((*in >= 0x61) && (*in <= 0x7A)) || 09753 ((*in >= 0x41) && (*in <= 0x5A)) || 09754 ((*in >= 0x30) && (*in <= 0x39)) || 09755 (*in == '_') || (*in == '.') || 09756 (*in == '-')) 09757 in++; 09758 if ((*in == ' ') || (*in == '>') || (*in == '/') || 09759 (*in == '[') || (*in == ']') || (*in == ':') || 09760 (*in == '@') || (*in == '*')) { 09761 count = in - ctxt->cur; 09762 if (count == 0) 09763 return(NULL); 09764 ret = xmlStrndup(ctxt->cur, count); 09765 ctxt->cur = in; 09766 return(ret); 09767 } 09768 } 09769 return(xmlXPathParseNameComplex(ctxt, 0)); 09770 } 09771 09772 09790 static xmlChar * 09791 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) { 09792 xmlChar *ret = NULL; 09793 09794 *prefix = NULL; 09795 ret = xmlXPathParseNCName(ctxt); 09796 if (ret && CUR == ':') { 09797 *prefix = ret; 09798 NEXT; 09799 ret = xmlXPathParseNCName(ctxt); 09800 } 09801 return(ret); 09802 } 09803 09818 xmlChar * 09819 xmlXPathParseName(xmlXPathParserContextPtr ctxt) { 09820 const xmlChar *in; 09821 xmlChar *ret; 09822 int count = 0; 09823 09824 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL); 09825 /* 09826 * Accelerator for simple ASCII names 09827 */ 09828 in = ctxt->cur; 09829 if (((*in >= 0x61) && (*in <= 0x7A)) || 09830 ((*in >= 0x41) && (*in <= 0x5A)) || 09831 (*in == '_') || (*in == ':')) { 09832 in++; 09833 while (((*in >= 0x61) && (*in <= 0x7A)) || 09834 ((*in >= 0x41) && (*in <= 0x5A)) || 09835 ((*in >= 0x30) && (*in <= 0x39)) || 09836 (*in == '_') || (*in == '-') || 09837 (*in == ':') || (*in == '.')) 09838 in++; 09839 if ((*in > 0) && (*in < 0x80)) { 09840 count = in - ctxt->cur; 09841 ret = xmlStrndup(ctxt->cur, count); 09842 ctxt->cur = in; 09843 return(ret); 09844 } 09845 } 09846 return(xmlXPathParseNameComplex(ctxt, 1)); 09847 } 09848 09849 static xmlChar * 09850 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) { 09851 xmlChar buf[XML_MAX_NAMELEN + 5]; 09852 int len = 0, l; 09853 int c; 09854 09855 /* 09856 * Handler for more complex cases 09857 */ 09858 c = CUR_CHAR(l); 09859 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */ 09860 (c == '[') || (c == ']') || (c == '@') || /* accelerators */ 09861 (c == '*') || /* accelerators */ 09862 (!IS_LETTER(c) && (c != '_') && 09863 ((qualified) && (c != ':')))) { 09864 return(NULL); 09865 } 09866 09867 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */ 09868 ((IS_LETTER(c)) || (IS_DIGIT(c)) || 09869 (c == '.') || (c == '-') || 09870 (c == '_') || ((qualified) && (c == ':')) || 09871 (IS_COMBINING(c)) || 09872 (IS_EXTENDER(c)))) { 09873 COPY_BUF(l,buf,len,c); 09874 NEXTL(l); 09875 c = CUR_CHAR(l); 09876 if (len >= XML_MAX_NAMELEN) { 09877 /* 09878 * Okay someone managed to make a huge name, so he's ready to pay 09879 * for the processing speed. 09880 */ 09881 xmlChar *buffer; 09882 int max = len * 2; 09883 09884 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar)); 09885 if (buffer == NULL) { 09886 XP_ERRORNULL(XPATH_MEMORY_ERROR); 09887 } 09888 memcpy(buffer, buf, len); 09889 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */ 09890 (c == '.') || (c == '-') || 09891 (c == '_') || ((qualified) && (c == ':')) || 09892 (IS_COMBINING(c)) || 09893 (IS_EXTENDER(c))) { 09894 if (len + 10 > max) { 09895 max *= 2; 09896 buffer = (xmlChar *) xmlRealloc(buffer, 09897 max * sizeof(xmlChar)); 09898 if (buffer == NULL) { 09899 XP_ERRORNULL(XPATH_MEMORY_ERROR); 09900 } 09901 } 09902 COPY_BUF(l,buffer,len,c); 09903 NEXTL(l); 09904 c = CUR_CHAR(l); 09905 } 09906 buffer[len] = 0; 09907 return(buffer); 09908 } 09909 } 09910 if (len == 0) 09911 return(NULL); 09912 return(xmlStrndup(buf, len)); 09913 } 09914 09915 #define MAX_FRAC 20 09916 09917 /* 09918 * These are used as divisors for the fractional part of a number. 09919 * Since the table includes 1.0 (representing '0' fractional digits), 09920 * it must be dimensioned at MAX_FRAC+1 (bug 133921) 09921 */ 09922 static double my_pow10[MAX_FRAC+1] = { 09923 1.0, 10.0, 100.0, 1000.0, 10000.0, 09924 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0, 09925 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0, 09926 100000000000000.0, 09927 1000000000000000.0, 10000000000000000.0, 100000000000000000.0, 09928 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0 09929 }; 09930 09947 double 09948 xmlXPathStringEvalNumber(const xmlChar *str) { 09949 const xmlChar *cur = str; 09950 double ret; 09951 int ok = 0; 09952 int isneg = 0; 09953 int exponent = 0; 09954 int is_exponent_negative = 0; 09955 #ifdef __GNUC__ 09956 unsigned long tmp = 0; 09957 double temp; 09958 #endif 09959 if (cur == NULL) return(0); 09960 while (IS_BLANK_CH(*cur)) cur++; 09961 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) { 09962 return(xmlXPathNAN); 09963 } 09964 if (*cur == '-') { 09965 isneg = 1; 09966 cur++; 09967 } 09968 09969 #ifdef __GNUC__ 09970 /* 09971 * tmp/temp is a workaround against a gcc compiler bug 09972 * http://veillard.com/gcc.bug 09973 */ 09974 ret = 0; 09975 while ((*cur >= '0') && (*cur <= '9')) { 09976 ret = ret * 10; 09977 tmp = (*cur - '0'); 09978 ok = 1; 09979 cur++; 09980 temp = (double) tmp; 09981 ret = ret + temp; 09982 } 09983 #else 09984 ret = 0; 09985 while ((*cur >= '0') && (*cur <= '9')) { 09986 ret = ret * 10 + (*cur - '0'); 09987 ok = 1; 09988 cur++; 09989 } 09990 #endif 09991 09992 if (*cur == '.') { 09993 int v, frac = 0; 09994 double fraction = 0; 09995 09996 cur++; 09997 if (((*cur < '0') || (*cur > '9')) && (!ok)) { 09998 return(xmlXPathNAN); 09999 } 10000 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) { 10001 v = (*cur - '0'); 10002 fraction = fraction * 10 + v; 10003 frac = frac + 1; 10004 cur++; 10005 } 10006 fraction /= my_pow10[frac]; 10007 ret = ret + fraction; 10008 while ((*cur >= '0') && (*cur <= '9')) 10009 cur++; 10010 } 10011 if ((*cur == 'e') || (*cur == 'E')) { 10012 cur++; 10013 if (*cur == '-') { 10014 is_exponent_negative = 1; 10015 cur++; 10016 } else if (*cur == '+') { 10017 cur++; 10018 } 10019 while ((*cur >= '0') && (*cur <= '9')) { 10020 exponent = exponent * 10 + (*cur - '0'); 10021 cur++; 10022 } 10023 } 10024 while (IS_BLANK_CH(*cur)) cur++; 10025 if (*cur != 0) return(xmlXPathNAN); 10026 if (isneg) ret = -ret; 10027 if (is_exponent_negative) exponent = -exponent; 10028 ret *= pow(10.0, (double)exponent); 10029 return(ret); 10030 } 10031 10043 static void 10044 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt) 10045 { 10046 double ret = 0.0; 10047 double mult = 1; 10048 int ok = 0; 10049 int exponent = 0; 10050 int is_exponent_negative = 0; 10051 #ifdef __GNUC__ 10052 unsigned long tmp = 0; 10053 double temp; 10054 #endif 10055 10056 CHECK_ERROR; 10057 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) { 10058 XP_ERROR(XPATH_NUMBER_ERROR); 10059 } 10060 #ifdef __GNUC__ 10061 /* 10062 * tmp/temp is a workaround against a gcc compiler bug 10063 * http://veillard.com/gcc.bug 10064 */ 10065 ret = 0; 10066 while ((CUR >= '0') && (CUR <= '9')) { 10067 ret = ret * 10; 10068 tmp = (CUR - '0'); 10069 ok = 1; 10070 NEXT; 10071 temp = (double) tmp; 10072 ret = ret + temp; 10073 } 10074 #else 10075 ret = 0; 10076 while ((CUR >= '0') && (CUR <= '9')) { 10077 ret = ret * 10 + (CUR - '0'); 10078 ok = 1; 10079 NEXT; 10080 } 10081 #endif 10082 if (CUR == '.') { 10083 int v, frac = 0; 10084 double fraction = 0; 10085 10086 NEXT; 10087 if (((CUR < '0') || (CUR > '9')) && (!ok)) { 10088 XP_ERROR(XPATH_NUMBER_ERROR); 10089 } 10090 while ((CUR >= '0') && (CUR <= '9') && (frac < MAX_FRAC)) { 10091 v = (CUR - '0'); 10092 fraction = fraction * 10 + v; 10093 frac = frac + 1; 10094 NEXT; 10095 } 10096 fraction /= my_pow10[frac]; 10097 ret = ret + fraction; 10098 while ((CUR >= '0') && (CUR <= '9')) 10099 NEXT; 10100 } 10101 if ((CUR == 'e') || (CUR == 'E')) { 10102 NEXT; 10103 if (CUR == '-') { 10104 is_exponent_negative = 1; 10105 NEXT; 10106 } else if (CUR == '+') { 10107 NEXT; 10108 } 10109 while ((CUR >= '0') && (CUR <= '9')) { 10110 exponent = exponent * 10 + (CUR - '0'); 10111 NEXT; 10112 } 10113 if (is_exponent_negative) 10114 exponent = -exponent; 10115 ret *= pow(10.0, (double) exponent); 10116 } 10117 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, 10118 xmlXPathCacheNewFloat(ctxt->context, ret), NULL); 10119 } 10120 10132 static xmlChar * 10133 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) { 10134 const xmlChar *q; 10135 xmlChar *ret = NULL; 10136 10137 if (CUR == '"') { 10138 NEXT; 10139 q = CUR_PTR; 10140 while ((IS_CHAR_CH(CUR)) && (CUR != '"')) 10141 NEXT; 10142 if (!IS_CHAR_CH(CUR)) { 10143 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR); 10144 } else { 10145 ret = xmlStrndup(q, CUR_PTR - q); 10146 NEXT; 10147 } 10148 } else if (CUR == '\'') { 10149 NEXT; 10150 q = CUR_PTR; 10151 while ((IS_CHAR_CH(CUR)) && (CUR != '\'')) 10152 NEXT; 10153 if (!IS_CHAR_CH(CUR)) { 10154 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR); 10155 } else { 10156 ret = xmlStrndup(q, CUR_PTR - q); 10157 NEXT; 10158 } 10159 } else { 10160 XP_ERRORNULL(XPATH_START_LITERAL_ERROR); 10161 } 10162 return(ret); 10163 } 10164 10176 static void 10177 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) { 10178 const xmlChar *q; 10179 xmlChar *ret = NULL; 10180 10181 if (CUR == '"') { 10182 NEXT; 10183 q = CUR_PTR; 10184 while ((IS_CHAR_CH(CUR)) && (CUR != '"')) 10185 NEXT; 10186 if (!IS_CHAR_CH(CUR)) { 10187 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR); 10188 } else { 10189 ret = xmlStrndup(q, CUR_PTR - q); 10190 NEXT; 10191 } 10192 } else if (CUR == '\'') { 10193 NEXT; 10194 q = CUR_PTR; 10195 while ((IS_CHAR_CH(CUR)) && (CUR != '\'')) 10196 NEXT; 10197 if (!IS_CHAR_CH(CUR)) { 10198 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR); 10199 } else { 10200 ret = xmlStrndup(q, CUR_PTR - q); 10201 NEXT; 10202 } 10203 } else { 10204 XP_ERROR(XPATH_START_LITERAL_ERROR); 10205 } 10206 if (ret == NULL) return; 10207 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, 10208 xmlXPathCacheNewString(ctxt->context, ret), NULL); 10209 xmlFree(ret); 10210 } 10211 10229 static void 10230 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) { 10231 xmlChar *name; 10232 xmlChar *prefix; 10233 10234 SKIP_BLANKS; 10235 if (CUR != '$') { 10236 XP_ERROR(XPATH_VARIABLE_REF_ERROR); 10237 } 10238 NEXT; 10239 name = xmlXPathParseQName(ctxt, &prefix); 10240 if (name == NULL) { 10241 XP_ERROR(XPATH_VARIABLE_REF_ERROR); 10242 } 10243 ctxt->comp->last = -1; 10244 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, 10245 name, prefix); 10246 SKIP_BLANKS; 10247 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) { 10248 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR); 10249 } 10250 } 10251 10265 int 10266 xmlXPathIsNodeType(const xmlChar *name) { 10267 if (name == NULL) 10268 return(0); 10269 10270 if (xmlStrEqual(name, BAD_CAST "node")) 10271 return(1); 10272 if (xmlStrEqual(name, BAD_CAST "text")) 10273 return(1); 10274 if (xmlStrEqual(name, BAD_CAST "comment")) 10275 return(1); 10276 if (xmlStrEqual(name, BAD_CAST "processing-instruction")) 10277 return(1); 10278 return(0); 10279 } 10280 10291 static void 10292 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) { 10293 xmlChar *name; 10294 xmlChar *prefix; 10295 int nbargs = 0; 10296 int sort = 1; 10297 10298 name = xmlXPathParseQName(ctxt, &prefix); 10299 if (name == NULL) { 10300 xmlFree(prefix); 10301 XP_ERROR(XPATH_EXPR_ERROR); 10302 } 10303 SKIP_BLANKS; 10304 #ifdef DEBUG_EXPR 10305 if (prefix == NULL) 10306 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n", 10307 name); 10308 else 10309 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n", 10310 prefix, name); 10311 #endif 10312 10313 if (CUR != '(') { 10314 XP_ERROR(XPATH_EXPR_ERROR); 10315 } 10316 NEXT; 10317 SKIP_BLANKS; 10318 10319 /* 10320 * Optimization for count(): we don't need the node-set to be sorted. 10321 */ 10322 if ((prefix == NULL) && (name[0] == 'c') && 10323 xmlStrEqual(name, BAD_CAST "count")) 10324 { 10325 sort = 0; 10326 } 10327 ctxt->comp->last = -1; 10328 if (CUR != ')') { 10329 while (CUR != 0) { 10330 int op1 = ctxt->comp->last; 10331 ctxt->comp->last = -1; 10332 xmlXPathCompileExpr(ctxt, sort); 10333 if (ctxt->error != XPATH_EXPRESSION_OK) { 10334 xmlFree(name); 10335 xmlFree(prefix); 10336 return; 10337 } 10338 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0); 10339 nbargs++; 10340 if (CUR == ')') break; 10341 if (CUR != ',') { 10342 XP_ERROR(XPATH_EXPR_ERROR); 10343 } 10344 NEXT; 10345 SKIP_BLANKS; 10346 } 10347 } 10348 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, 10349 name, prefix); 10350 NEXT; 10351 SKIP_BLANKS; 10352 } 10353 10366 static void 10367 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) { 10368 SKIP_BLANKS; 10369 if (CUR == '$') xmlXPathCompVariableReference(ctxt); 10370 else if (CUR == '(') { 10371 NEXT; 10372 SKIP_BLANKS; 10373 xmlXPathCompileExpr(ctxt, 1); 10374 CHECK_ERROR; 10375 if (CUR != ')') { 10376 XP_ERROR(XPATH_EXPR_ERROR); 10377 } 10378 NEXT; 10379 SKIP_BLANKS; 10380 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) { 10381 xmlXPathCompNumber(ctxt); 10382 } else if ((CUR == '\'') || (CUR == '"')) { 10383 xmlXPathCompLiteral(ctxt); 10384 } else { 10385 xmlXPathCompFunctionCall(ctxt); 10386 } 10387 SKIP_BLANKS; 10388 } 10389 10405 static void 10406 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) { 10407 xmlXPathCompPrimaryExpr(ctxt); 10408 CHECK_ERROR; 10409 SKIP_BLANKS; 10410 10411 while (CUR == '[') { 10412 xmlXPathCompPredicate(ctxt, 1); 10413 SKIP_BLANKS; 10414 } 10415 10416 10417 } 10418 10436 static xmlChar * 10437 xmlXPathScanName(xmlXPathParserContextPtr ctxt) { 10438 int len = 0, l; 10439 int c; 10440 const xmlChar *cur; 10441 xmlChar *ret; 10442 10443 cur = ctxt->cur; 10444 10445 c = CUR_CHAR(l); 10446 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */ 10447 (!IS_LETTER(c) && (c != '_') && 10448 (c != ':'))) { 10449 return(NULL); 10450 } 10451 10452 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */ 10453 ((IS_LETTER(c)) || (IS_DIGIT(c)) || 10454 (c == '.') || (c == '-') || 10455 (c == '_') || (c == ':') || 10456 (IS_COMBINING(c)) || 10457 (IS_EXTENDER(c)))) { 10458 len += l; 10459 NEXTL(l); 10460 c = CUR_CHAR(l); 10461 } 10462 ret = xmlStrndup(cur, ctxt->cur - cur); 10463 ctxt->cur = cur; 10464 return(ret); 10465 } 10466 10485 static void 10486 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) { 10487 int lc = 1; /* Should we branch to LocationPath ? */ 10488 xmlChar *name = NULL; /* we may have to preparse a name to find out */ 10489 10490 SKIP_BLANKS; 10491 if ((CUR == '$') || (CUR == '(') || 10492 (IS_ASCII_DIGIT(CUR)) || 10493 (CUR == '\'') || (CUR == '"') || 10494 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) { 10495 lc = 0; 10496 } else if (CUR == '*') { 10497 /* relative or absolute location path */ 10498 lc = 1; 10499 } else if (CUR == '/') { 10500 /* relative or absolute location path */ 10501 lc = 1; 10502 } else if (CUR == '@') { 10503 /* relative abbreviated attribute location path */ 10504 lc = 1; 10505 } else if (CUR == '.') { 10506 /* relative abbreviated attribute location path */ 10507 lc = 1; 10508 } else { 10509 /* 10510 * Problem is finding if we have a name here whether it's: 10511 * - a nodetype 10512 * - a function call in which case it's followed by '(' 10513 * - an axis in which case it's followed by ':' 10514 * - a element name 10515 * We do an a priori analysis here rather than having to 10516 * maintain parsed token content through the recursive function 10517 * calls. This looks uglier but makes the code easier to 10518 * read/write/debug. 10519 */ 10520 SKIP_BLANKS; 10521 name = xmlXPathScanName(ctxt); 10522 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) { 10523 #ifdef DEBUG_STEP 10524 xmlGenericError(xmlGenericErrorContext, 10525 "PathExpr: Axis\n"); 10526 #endif 10527 lc = 1; 10528 xmlFree(name); 10529 } else if (name != NULL) { 10530 int len =xmlStrlen(name); 10531 10532 10533 while (NXT(len) != 0) { 10534 if (NXT(len) == '/') { 10535 /* element name */ 10536 #ifdef DEBUG_STEP 10537 xmlGenericError(xmlGenericErrorContext, 10538 "PathExpr: AbbrRelLocation\n"); 10539 #endif 10540 lc = 1; 10541 break; 10542 } else if (IS_BLANK_CH(NXT(len))) { 10543 /* ignore blanks */ 10544 ; 10545 } else if (NXT(len) == ':') { 10546 #ifdef DEBUG_STEP 10547 xmlGenericError(xmlGenericErrorContext, 10548 "PathExpr: AbbrRelLocation\n"); 10549 #endif 10550 lc = 1; 10551 break; 10552 } else if ((NXT(len) == '(')) { 10553 /* Note Type or Function */ 10554 if (xmlXPathIsNodeType(name)) { 10555 #ifdef DEBUG_STEP 10556 xmlGenericError(xmlGenericErrorContext, 10557 "PathExpr: Type search\n"); 10558 #endif 10559 lc = 1; 10560 } else { 10561 #ifdef DEBUG_STEP 10562 xmlGenericError(xmlGenericErrorContext, 10563 "PathExpr: function call\n"); 10564 #endif 10565 lc = 0; 10566 } 10567 break; 10568 } else if ((NXT(len) == '[')) { 10569 /* element name */ 10570 #ifdef DEBUG_STEP 10571 xmlGenericError(xmlGenericErrorContext, 10572 "PathExpr: AbbrRelLocation\n"); 10573 #endif 10574 lc = 1; 10575 break; 10576 } else if ((NXT(len) == '<') || (NXT(len) == '>') || 10577 (NXT(len) == '=')) { 10578 lc = 1; 10579 break; 10580 } else { 10581 lc = 1; 10582 break; 10583 } 10584 len++; 10585 } 10586 if (NXT(len) == 0) { 10587 #ifdef DEBUG_STEP 10588 xmlGenericError(xmlGenericErrorContext, 10589 "PathExpr: AbbrRelLocation\n"); 10590 #endif 10591 /* element name */ 10592 lc = 1; 10593 } 10594 xmlFree(name); 10595 } else { 10596 /* make sure all cases are covered explicitly */ 10597 XP_ERROR(XPATH_EXPR_ERROR); 10598 } 10599 } 10600 10601 if (lc) { 10602 if (CUR == '/') { 10603 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0); 10604 } else { 10605 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0); 10606 } 10607 xmlXPathCompLocationPath(ctxt); 10608 } else { 10609 xmlXPathCompFilterExpr(ctxt); 10610 CHECK_ERROR; 10611 if ((CUR == '/') && (NXT(1) == '/')) { 10612 SKIP(2); 10613 SKIP_BLANKS; 10614 10615 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 10616 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 10617 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0); 10618 10619 xmlXPathCompRelativeLocationPath(ctxt); 10620 } else if (CUR == '/') { 10621 xmlXPathCompRelativeLocationPath(ctxt); 10622 } 10623 } 10624 SKIP_BLANKS; 10625 } 10626 10637 static void 10638 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) { 10639 xmlXPathCompPathExpr(ctxt); 10640 CHECK_ERROR; 10641 SKIP_BLANKS; 10642 while (CUR == '|') { 10643 int op1 = ctxt->comp->last; 10644 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0); 10645 10646 NEXT; 10647 SKIP_BLANKS; 10648 xmlXPathCompPathExpr(ctxt); 10649 10650 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0); 10651 10652 SKIP_BLANKS; 10653 } 10654 } 10655 10666 static void 10667 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) { 10668 int minus = 0; 10669 int found = 0; 10670 10671 SKIP_BLANKS; 10672 while (CUR == '-') { 10673 minus = 1 - minus; 10674 found = 1; 10675 NEXT; 10676 SKIP_BLANKS; 10677 } 10678 10679 xmlXPathCompUnionExpr(ctxt); 10680 CHECK_ERROR; 10681 if (found) { 10682 if (minus) 10683 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0); 10684 else 10685 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0); 10686 } 10687 } 10688 10702 static void 10703 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) { 10704 xmlXPathCompUnaryExpr(ctxt); 10705 CHECK_ERROR; 10706 SKIP_BLANKS; 10707 while ((CUR == '*') || 10708 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) || 10709 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) { 10710 int op = -1; 10711 int op1 = ctxt->comp->last; 10712 10713 if (CUR == '*') { 10714 op = 0; 10715 NEXT; 10716 } else if (CUR == 'd') { 10717 op = 1; 10718 SKIP(3); 10719 } else if (CUR == 'm') { 10720 op = 2; 10721 SKIP(3); 10722 } 10723 SKIP_BLANKS; 10724 xmlXPathCompUnaryExpr(ctxt); 10725 CHECK_ERROR; 10726 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0); 10727 SKIP_BLANKS; 10728 } 10729 } 10730 10742 static void 10743 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) { 10744 10745 xmlXPathCompMultiplicativeExpr(ctxt); 10746 CHECK_ERROR; 10747 SKIP_BLANKS; 10748 while ((CUR == '+') || (CUR == '-')) { 10749 int plus; 10750 int op1 = ctxt->comp->last; 10751 10752 if (CUR == '+') plus = 1; 10753 else plus = 0; 10754 NEXT; 10755 SKIP_BLANKS; 10756 xmlXPathCompMultiplicativeExpr(ctxt); 10757 CHECK_ERROR; 10758 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0); 10759 SKIP_BLANKS; 10760 } 10761 } 10762 10781 static void 10782 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) { 10783 xmlXPathCompAdditiveExpr(ctxt); 10784 CHECK_ERROR; 10785 SKIP_BLANKS; 10786 while ((CUR == '<') || 10787 (CUR == '>') || 10788 ((CUR == '<') && (NXT(1) == '=')) || 10789 ((CUR == '>') && (NXT(1) == '='))) { 10790 int inf, strict; 10791 int op1 = ctxt->comp->last; 10792 10793 if (CUR == '<') inf = 1; 10794 else inf = 0; 10795 if (NXT(1) == '=') strict = 0; 10796 else strict = 1; 10797 NEXT; 10798 if (!strict) NEXT; 10799 SKIP_BLANKS; 10800 xmlXPathCompAdditiveExpr(ctxt); 10801 CHECK_ERROR; 10802 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict); 10803 SKIP_BLANKS; 10804 } 10805 } 10806 10823 static void 10824 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) { 10825 xmlXPathCompRelationalExpr(ctxt); 10826 CHECK_ERROR; 10827 SKIP_BLANKS; 10828 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) { 10829 int eq; 10830 int op1 = ctxt->comp->last; 10831 10832 if (CUR == '=') eq = 1; 10833 else eq = 0; 10834 NEXT; 10835 if (!eq) NEXT; 10836 SKIP_BLANKS; 10837 xmlXPathCompRelationalExpr(ctxt); 10838 CHECK_ERROR; 10839 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0); 10840 SKIP_BLANKS; 10841 } 10842 } 10843 10854 static void 10855 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) { 10856 xmlXPathCompEqualityExpr(ctxt); 10857 CHECK_ERROR; 10858 SKIP_BLANKS; 10859 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) { 10860 int op1 = ctxt->comp->last; 10861 SKIP(3); 10862 SKIP_BLANKS; 10863 xmlXPathCompEqualityExpr(ctxt); 10864 CHECK_ERROR; 10865 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0); 10866 SKIP_BLANKS; 10867 } 10868 } 10869 10880 static void 10881 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) { 10882 xmlXPathCompAndExpr(ctxt); 10883 CHECK_ERROR; 10884 SKIP_BLANKS; 10885 while ((CUR == 'o') && (NXT(1) == 'r')) { 10886 int op1 = ctxt->comp->last; 10887 SKIP(2); 10888 SKIP_BLANKS; 10889 xmlXPathCompAndExpr(ctxt); 10890 CHECK_ERROR; 10891 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0); 10892 SKIP_BLANKS; 10893 } 10894 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) { 10895 /* more ops could be optimized too */ 10896 /* 10897 * This is the main place to eliminate sorting for 10898 * operations which don't require a sorted node-set. 10899 * E.g. count(). 10900 */ 10901 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0); 10902 } 10903 } 10904 10915 static void 10916 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) { 10917 int op1 = ctxt->comp->last; 10918 10919 SKIP_BLANKS; 10920 if (CUR != '[') { 10921 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); 10922 } 10923 NEXT; 10924 SKIP_BLANKS; 10925 10926 ctxt->comp->last = -1; 10927 /* 10928 * This call to xmlXPathCompileExpr() will deactivate sorting 10929 * of the predicate result. 10930 * TODO: Sorting is still activated for filters, since I'm not 10931 * sure if needed. Normally sorting should not be needed, since 10932 * a filter can only diminish the number of items in a sequence, 10933 * but won't change its order; so if the initial sequence is sorted, 10934 * subsequent sorting is not needed. 10935 */ 10936 if (! filter) 10937 xmlXPathCompileExpr(ctxt, 0); 10938 else 10939 xmlXPathCompileExpr(ctxt, 1); 10940 CHECK_ERROR; 10941 10942 if (CUR != ']') { 10943 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); 10944 } 10945 10946 if (filter) 10947 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0); 10948 else 10949 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0); 10950 10951 NEXT; 10952 SKIP_BLANKS; 10953 } 10954 10976 static xmlChar * 10977 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test, 10978 xmlXPathTypeVal *type, const xmlChar **prefix, 10979 xmlChar *name) { 10980 int blanks; 10981 10982 if ((test == NULL) || (type == NULL) || (prefix == NULL)) { 10983 STRANGE; 10984 return(NULL); 10985 } 10986 *type = (xmlXPathTypeVal) 0; 10987 *test = (xmlXPathTestVal) 0; 10988 *prefix = NULL; 10989 SKIP_BLANKS; 10990 10991 if ((name == NULL) && (CUR == '*')) { 10992 /* 10993 * All elements 10994 */ 10995 NEXT; 10996 *test = NODE_TEST_ALL; 10997 return(NULL); 10998 } 10999 11000 if (name == NULL) 11001 name = xmlXPathParseNCName(ctxt); 11002 if (name == NULL) { 11003 XP_ERRORNULL(XPATH_EXPR_ERROR); 11004 } 11005 11006 blanks = IS_BLANK_CH(CUR); 11007 SKIP_BLANKS; 11008 if (CUR == '(') { 11009 NEXT; 11010 /* 11011 * NodeType or PI search 11012 */ 11013 if (xmlStrEqual(name, BAD_CAST "comment")) 11014 *type = NODE_TYPE_COMMENT; 11015 else if (xmlStrEqual(name, BAD_CAST "node")) 11016 *type = NODE_TYPE_NODE; 11017 else if (xmlStrEqual(name, BAD_CAST "processing-instruction")) 11018 *type = NODE_TYPE_PI; 11019 else if (xmlStrEqual(name, BAD_CAST "text")) 11020 *type = NODE_TYPE_TEXT; 11021 else { 11022 if (name != NULL) 11023 xmlFree(name); 11024 XP_ERRORNULL(XPATH_EXPR_ERROR); 11025 } 11026 11027 *test = NODE_TEST_TYPE; 11028 11029 SKIP_BLANKS; 11030 if (*type == NODE_TYPE_PI) { 11031 /* 11032 * Specific case: search a PI by name. 11033 */ 11034 if (name != NULL) 11035 xmlFree(name); 11036 name = NULL; 11037 if (CUR != ')') { 11038 name = xmlXPathParseLiteral(ctxt); 11039 CHECK_ERROR NULL; 11040 *test = NODE_TEST_PI; 11041 SKIP_BLANKS; 11042 } 11043 } 11044 if (CUR != ')') { 11045 if (name != NULL) 11046 xmlFree(name); 11047 XP_ERRORNULL(XPATH_UNCLOSED_ERROR); 11048 } 11049 NEXT; 11050 return(name); 11051 } 11052 *test = NODE_TEST_NAME; 11053 if ((!blanks) && (CUR == ':')) { 11054 NEXT; 11055 11056 /* 11057 * Since currently the parser context don't have a 11058 * namespace list associated: 11059 * The namespace name for this prefix can be computed 11060 * only at evaluation time. The compilation is done 11061 * outside of any context. 11062 */ 11063 #if 0 11064 *prefix = xmlXPathNsLookup(ctxt->context, name); 11065 if (name != NULL) 11066 xmlFree(name); 11067 if (*prefix == NULL) { 11068 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); 11069 } 11070 #else 11071 *prefix = name; 11072 #endif 11073 11074 if (CUR == '*') { 11075 /* 11076 * All elements 11077 */ 11078 NEXT; 11079 *test = NODE_TEST_ALL; 11080 return(NULL); 11081 } 11082 11083 name = xmlXPathParseNCName(ctxt); 11084 if (name == NULL) { 11085 XP_ERRORNULL(XPATH_EXPR_ERROR); 11086 } 11087 } 11088 return(name); 11089 } 11090 11111 static xmlXPathAxisVal 11112 xmlXPathIsAxisName(const xmlChar *name) { 11113 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0; 11114 switch (name[0]) { 11115 case 'a': 11116 if (xmlStrEqual(name, BAD_CAST "ancestor")) 11117 ret = AXIS_ANCESTOR; 11118 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self")) 11119 ret = AXIS_ANCESTOR_OR_SELF; 11120 if (xmlStrEqual(name, BAD_CAST "attribute")) 11121 ret = AXIS_ATTRIBUTE; 11122 break; 11123 case 'c': 11124 if (xmlStrEqual(name, BAD_CAST "child")) 11125 ret = AXIS_CHILD; 11126 break; 11127 case 'd': 11128 if (xmlStrEqual(name, BAD_CAST "descendant")) 11129 ret = AXIS_DESCENDANT; 11130 if (xmlStrEqual(name, BAD_CAST "descendant-or-self")) 11131 ret = AXIS_DESCENDANT_OR_SELF; 11132 break; 11133 case 'f': 11134 if (xmlStrEqual(name, BAD_CAST "following")) 11135 ret = AXIS_FOLLOWING; 11136 if (xmlStrEqual(name, BAD_CAST "following-sibling")) 11137 ret = AXIS_FOLLOWING_SIBLING; 11138 break; 11139 case 'n': 11140 if (xmlStrEqual(name, BAD_CAST "namespace")) 11141 ret = AXIS_NAMESPACE; 11142 break; 11143 case 'p': 11144 if (xmlStrEqual(name, BAD_CAST "parent")) 11145 ret = AXIS_PARENT; 11146 if (xmlStrEqual(name, BAD_CAST "preceding")) 11147 ret = AXIS_PRECEDING; 11148 if (xmlStrEqual(name, BAD_CAST "preceding-sibling")) 11149 ret = AXIS_PRECEDING_SIBLING; 11150 break; 11151 case 's': 11152 if (xmlStrEqual(name, BAD_CAST "self")) 11153 ret = AXIS_SELF; 11154 break; 11155 } 11156 return(ret); 11157 } 11158 11191 static void 11192 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) { 11193 #ifdef LIBXML_XPTR_ENABLED 11194 int rangeto = 0; 11195 int op2 = -1; 11196 #endif 11197 11198 SKIP_BLANKS; 11199 if ((CUR == '.') && (NXT(1) == '.')) { 11200 SKIP(2); 11201 SKIP_BLANKS; 11202 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT, 11203 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11204 } else if (CUR == '.') { 11205 NEXT; 11206 SKIP_BLANKS; 11207 } else { 11208 xmlChar *name = NULL; 11209 const xmlChar *prefix = NULL; 11210 xmlXPathTestVal test = (xmlXPathTestVal) 0; 11211 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0; 11212 xmlXPathTypeVal type = (xmlXPathTypeVal) 0; 11213 int op1; 11214 11215 /* 11216 * The modification needed for XPointer change to the production 11217 */ 11218 #ifdef LIBXML_XPTR_ENABLED 11219 if (ctxt->xptr) { 11220 name = xmlXPathParseNCName(ctxt); 11221 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) { 11222 op2 = ctxt->comp->last; 11223 xmlFree(name); 11224 SKIP_BLANKS; 11225 if (CUR != '(') { 11226 XP_ERROR(XPATH_EXPR_ERROR); 11227 } 11228 NEXT; 11229 SKIP_BLANKS; 11230 11231 xmlXPathCompileExpr(ctxt, 1); 11232 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */ 11233 CHECK_ERROR; 11234 11235 SKIP_BLANKS; 11236 if (CUR != ')') { 11237 XP_ERROR(XPATH_EXPR_ERROR); 11238 } 11239 NEXT; 11240 rangeto = 1; 11241 goto eval_predicates; 11242 } 11243 } 11244 #endif 11245 if (CUR == '*') { 11246 axis = AXIS_CHILD; 11247 } else { 11248 if (name == NULL) 11249 name = xmlXPathParseNCName(ctxt); 11250 if (name != NULL) { 11251 axis = xmlXPathIsAxisName(name); 11252 if (axis != 0) { 11253 SKIP_BLANKS; 11254 if ((CUR == ':') && (NXT(1) == ':')) { 11255 SKIP(2); 11256 xmlFree(name); 11257 name = NULL; 11258 } else { 11259 /* an element name can conflict with an axis one :-\ */ 11260 axis = AXIS_CHILD; 11261 } 11262 } else { 11263 axis = AXIS_CHILD; 11264 } 11265 } else if (CUR == '@') { 11266 NEXT; 11267 axis = AXIS_ATTRIBUTE; 11268 } else { 11269 axis = AXIS_CHILD; 11270 } 11271 } 11272 11273 if (ctxt->error != XPATH_EXPRESSION_OK) { 11274 xmlFree(name); 11275 return; 11276 } 11277 11278 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name); 11279 if (test == 0) 11280 return; 11281 11282 if ((prefix != NULL) && (ctxt->context != NULL) && 11283 (ctxt->context->flags & XML_XPATH_CHECKNS)) { 11284 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) { 11285 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR); 11286 } 11287 } 11288 #ifdef DEBUG_STEP 11289 xmlGenericError(xmlGenericErrorContext, 11290 "Basis : computing new set\n"); 11291 #endif 11292 11293 #ifdef DEBUG_STEP 11294 xmlGenericError(xmlGenericErrorContext, "Basis : "); 11295 if (ctxt->value == NULL) 11296 xmlGenericError(xmlGenericErrorContext, "no value\n"); 11297 else if (ctxt->value->nodesetval == NULL) 11298 xmlGenericError(xmlGenericErrorContext, "Empty\n"); 11299 else 11300 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval); 11301 #endif 11302 11303 #ifdef LIBXML_XPTR_ENABLED 11304 eval_predicates: 11305 #endif 11306 op1 = ctxt->comp->last; 11307 ctxt->comp->last = -1; 11308 11309 SKIP_BLANKS; 11310 while (CUR == '[') { 11311 xmlXPathCompPredicate(ctxt, 0); 11312 } 11313 11314 #ifdef LIBXML_XPTR_ENABLED 11315 if (rangeto) { 11316 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0); 11317 } else 11318 #endif 11319 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis, 11320 test, type, (void *)prefix, (void *)name); 11321 11322 } 11323 #ifdef DEBUG_STEP 11324 xmlGenericError(xmlGenericErrorContext, "Step : "); 11325 if (ctxt->value == NULL) 11326 xmlGenericError(xmlGenericErrorContext, "no value\n"); 11327 else if (ctxt->value->nodesetval == NULL) 11328 xmlGenericError(xmlGenericErrorContext, "Empty\n"); 11329 else 11330 xmlGenericErrorContextNodeSet(xmlGenericErrorContext, 11331 ctxt->value->nodesetval); 11332 #endif 11333 } 11334 11346 static void 11347 xmlXPathCompRelativeLocationPath 11348 (xmlXPathParserContextPtr ctxt) { 11349 SKIP_BLANKS; 11350 if ((CUR == '/') && (NXT(1) == '/')) { 11351 SKIP(2); 11352 SKIP_BLANKS; 11353 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 11354 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11355 } else if (CUR == '/') { 11356 NEXT; 11357 SKIP_BLANKS; 11358 } 11359 xmlXPathCompStep(ctxt); 11360 CHECK_ERROR; 11361 SKIP_BLANKS; 11362 while (CUR == '/') { 11363 if ((CUR == '/') && (NXT(1) == '/')) { 11364 SKIP(2); 11365 SKIP_BLANKS; 11366 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 11367 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11368 xmlXPathCompStep(ctxt); 11369 } else if (CUR == '/') { 11370 NEXT; 11371 SKIP_BLANKS; 11372 xmlXPathCompStep(ctxt); 11373 } 11374 SKIP_BLANKS; 11375 } 11376 } 11377 11399 static void 11400 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) { 11401 SKIP_BLANKS; 11402 if (CUR != '/') { 11403 xmlXPathCompRelativeLocationPath(ctxt); 11404 } else { 11405 while (CUR == '/') { 11406 if ((CUR == '/') && (NXT(1) == '/')) { 11407 SKIP(2); 11408 SKIP_BLANKS; 11409 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 11410 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11411 xmlXPathCompRelativeLocationPath(ctxt); 11412 } else if (CUR == '/') { 11413 NEXT; 11414 SKIP_BLANKS; 11415 if ((CUR != 0 ) && 11416 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') || 11417 (CUR == '@') || (CUR == '*'))) 11418 xmlXPathCompRelativeLocationPath(ctxt); 11419 } 11420 CHECK_ERROR; 11421 } 11422 } 11423 } 11424 11425 /************************************************************************ 11426 * * 11427 * XPath precompiled expression evaluation * 11428 * * 11429 ************************************************************************/ 11430 11431 static int 11432 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op); 11433 11434 #ifdef DEBUG_STEP 11435 static void 11436 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op, 11437 int nbNodes) 11438 { 11439 xmlGenericError(xmlGenericErrorContext, "new step : "); 11440 switch (op->value) { 11441 case AXIS_ANCESTOR: 11442 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' "); 11443 break; 11444 case AXIS_ANCESTOR_OR_SELF: 11445 xmlGenericError(xmlGenericErrorContext, 11446 "axis 'ancestors-or-self' "); 11447 break; 11448 case AXIS_ATTRIBUTE: 11449 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' "); 11450 break; 11451 case AXIS_CHILD: 11452 xmlGenericError(xmlGenericErrorContext, "axis 'child' "); 11453 break; 11454 case AXIS_DESCENDANT: 11455 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' "); 11456 break; 11457 case AXIS_DESCENDANT_OR_SELF: 11458 xmlGenericError(xmlGenericErrorContext, 11459 "axis 'descendant-or-self' "); 11460 break; 11461 case AXIS_FOLLOWING: 11462 xmlGenericError(xmlGenericErrorContext, "axis 'following' "); 11463 break; 11464 case AXIS_FOLLOWING_SIBLING: 11465 xmlGenericError(xmlGenericErrorContext, 11466 "axis 'following-siblings' "); 11467 break; 11468 case AXIS_NAMESPACE: 11469 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' "); 11470 break; 11471 case AXIS_PARENT: 11472 xmlGenericError(xmlGenericErrorContext, "axis 'parent' "); 11473 break; 11474 case AXIS_PRECEDING: 11475 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' "); 11476 break; 11477 case AXIS_PRECEDING_SIBLING: 11478 xmlGenericError(xmlGenericErrorContext, 11479 "axis 'preceding-sibling' "); 11480 break; 11481 case AXIS_SELF: 11482 xmlGenericError(xmlGenericErrorContext, "axis 'self' "); 11483 break; 11484 } 11485 xmlGenericError(xmlGenericErrorContext, 11486 " context contains %d nodes\n", nbNodes); 11487 switch (op->value2) { 11488 case NODE_TEST_NONE: 11489 xmlGenericError(xmlGenericErrorContext, 11490 " searching for none !!!\n"); 11491 break; 11492 case NODE_TEST_TYPE: 11493 xmlGenericError(xmlGenericErrorContext, 11494 " searching for type %d\n", op->value3); 11495 break; 11496 case NODE_TEST_PI: 11497 xmlGenericError(xmlGenericErrorContext, 11498 " searching for PI !!!\n"); 11499 break; 11500 case NODE_TEST_ALL: 11501 xmlGenericError(xmlGenericErrorContext, 11502 " searching for *\n"); 11503 break; 11504 case NODE_TEST_NS: 11505 xmlGenericError(xmlGenericErrorContext, 11506 " searching for namespace %s\n", 11507 op->value5); 11508 break; 11509 case NODE_TEST_NAME: 11510 xmlGenericError(xmlGenericErrorContext, 11511 " searching for name %s\n", op->value5); 11512 if (op->value4) 11513 xmlGenericError(xmlGenericErrorContext, 11514 " with namespace %s\n", op->value4); 11515 break; 11516 } 11517 xmlGenericError(xmlGenericErrorContext, "Testing : "); 11518 } 11519 #endif /* DEBUG_STEP */ 11520 11521 static int 11522 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt, 11523 xmlXPathStepOpPtr op, 11524 xmlNodeSetPtr set, 11525 int contextSize, 11526 int hasNsNodes) 11527 { 11528 if (op->ch1 != -1) { 11529 xmlXPathCompExprPtr comp = ctxt->comp; 11530 /* 11531 * Process inner predicates first. 11532 */ 11533 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) { 11534 /* 11535 * TODO: raise an internal error. 11536 */ 11537 } 11538 contextSize = xmlXPathCompOpEvalPredicate(ctxt, 11539 &comp->steps[op->ch1], set, contextSize, hasNsNodes); 11540 CHECK_ERROR0; 11541 if (contextSize <= 0) 11542 return(0); 11543 } 11544 if (op->ch2 != -1) { 11545 xmlXPathContextPtr xpctxt = ctxt->context; 11546 xmlNodePtr contextNode, oldContextNode; 11547 xmlDocPtr oldContextDoc; 11548 int i, res, contextPos = 0, newContextSize; 11549 xmlXPathStepOpPtr exprOp; 11550 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL; 11551 11552 #ifdef LIBXML_XPTR_ENABLED 11553 /* 11554 * URGENT TODO: Check the following: 11555 * We don't expect location sets if evaluating prediates, right? 11556 * Only filters should expect location sets, right? 11557 */ 11558 #endif 11559 /* 11560 * SPEC XPath 1.0: 11561 * "For each node in the node-set to be filtered, the 11562 * PredicateExpr is evaluated with that node as the 11563 * context node, with the number of nodes in the 11564 * node-set as the context size, and with the proximity 11565 * position of the node in the node-set with respect to 11566 * the axis as the context position;" 11567 * @oldset is the node-set" to be filtered. 11568 * 11569 * SPEC XPath 1.0: 11570 * "only predicates change the context position and 11571 * context size (see [2.4 Predicates])." 11572 * Example: 11573 * node-set context pos 11574 * nA 1 11575 * nB 2 11576 * nC 3 11577 * After applying predicate [position() > 1] : 11578 * node-set context pos 11579 * nB 1 11580 * nC 2 11581 */ 11582 oldContextNode = xpctxt->node; 11583 oldContextDoc = xpctxt->doc; 11584 /* 11585 * Get the expression of this predicate. 11586 */ 11587 exprOp = &ctxt->comp->steps[op->ch2]; 11588 newContextSize = 0; 11589 for (i = 0; i < set->nodeNr; i++) { 11590 if (set->nodeTab[i] == NULL) 11591 continue; 11592 11593 contextNode = set->nodeTab[i]; 11594 xpctxt->node = contextNode; 11595 xpctxt->contextSize = contextSize; 11596 xpctxt->proximityPosition = ++contextPos; 11597 11598 /* 11599 * Also set the xpath document in case things like 11600 * key() are evaluated in the predicate. 11601 */ 11602 if ((contextNode->type != XML_NAMESPACE_DECL) && 11603 (contextNode->doc != NULL)) 11604 xpctxt->doc = contextNode->doc; 11605 /* 11606 * Evaluate the predicate expression with 1 context node 11607 * at a time; this node is packaged into a node set; this 11608 * node set is handed over to the evaluation mechanism. 11609 */ 11610 if (contextObj == NULL) 11611 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode); 11612 else 11613 xmlXPathNodeSetAddUnique(contextObj->nodesetval, 11614 contextNode); 11615 11616 valuePush(ctxt, contextObj); 11617 11618 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1); 11619 11620 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) { 11621 xmlXPathNodeSetClear(set, hasNsNodes); 11622 newContextSize = 0; 11623 goto evaluation_exit; 11624 } 11625 11626 if (res != 0) { 11627 newContextSize++; 11628 } else { 11629 /* 11630 * Remove the entry from the initial node set. 11631 */ 11632 set->nodeTab[i] = NULL; 11633 if (contextNode->type == XML_NAMESPACE_DECL) 11634 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode); 11635 } 11636 if (ctxt->value == contextObj) { 11637 /* 11638 * Don't free the temporary XPath object holding the 11639 * context node, in order to avoid massive recreation 11640 * inside this loop. 11641 */ 11642 valuePop(ctxt); 11643 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes); 11644 } else { 11645 /* 11646 * TODO: The object was lost in the evaluation machinery. 11647 * Can this happen? Maybe in internal-error cases. 11648 */ 11649 contextObj = NULL; 11650 } 11651 } 11652 11653 if (contextObj != NULL) { 11654 if (ctxt->value == contextObj) 11655 valuePop(ctxt); 11656 xmlXPathReleaseObject(xpctxt, contextObj); 11657 } 11658 evaluation_exit: 11659 if (exprRes != NULL) 11660 xmlXPathReleaseObject(ctxt->context, exprRes); 11661 /* 11662 * Reset/invalidate the context. 11663 */ 11664 xpctxt->node = oldContextNode; 11665 xpctxt->doc = oldContextDoc; 11666 xpctxt->contextSize = -1; 11667 xpctxt->proximityPosition = -1; 11668 return(newContextSize); 11669 } 11670 return(contextSize); 11671 } 11672 11673 static int 11674 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt, 11675 xmlXPathStepOpPtr op, 11676 xmlNodeSetPtr set, 11677 int contextSize, 11678 int minPos, 11679 int maxPos, 11680 int hasNsNodes) 11681 { 11682 if (op->ch1 != -1) { 11683 xmlXPathCompExprPtr comp = ctxt->comp; 11684 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) { 11685 /* 11686 * TODO: raise an internal error. 11687 */ 11688 } 11689 contextSize = xmlXPathCompOpEvalPredicate(ctxt, 11690 &comp->steps[op->ch1], set, contextSize, hasNsNodes); 11691 CHECK_ERROR0; 11692 if (contextSize <= 0) 11693 return(0); 11694 } 11695 /* 11696 * Check if the node set contains a sufficient number of nodes for 11697 * the requested range. 11698 */ 11699 if (contextSize < minPos) { 11700 xmlXPathNodeSetClear(set, hasNsNodes); 11701 return(0); 11702 } 11703 if (op->ch2 == -1) { 11704 /* 11705 * TODO: Can this ever happen? 11706 */ 11707 return (contextSize); 11708 } else { 11709 xmlDocPtr oldContextDoc; 11710 int i, pos = 0, newContextSize = 0, contextPos = 0, res; 11711 xmlXPathStepOpPtr exprOp; 11712 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL; 11713 xmlNodePtr oldContextNode, contextNode = NULL; 11714 xmlXPathContextPtr xpctxt = ctxt->context; 11715 11716 #ifdef LIBXML_XPTR_ENABLED 11717 /* 11718 * URGENT TODO: Check the following: 11719 * We don't expect location sets if evaluating prediates, right? 11720 * Only filters should expect location sets, right? 11721 */ 11722 #endif /* LIBXML_XPTR_ENABLED */ 11723 11724 /* 11725 * Save old context. 11726 */ 11727 oldContextNode = xpctxt->node; 11728 oldContextDoc = xpctxt->doc; 11729 /* 11730 * Get the expression of this predicate. 11731 */ 11732 exprOp = &ctxt->comp->steps[op->ch2]; 11733 for (i = 0; i < set->nodeNr; i++) { 11734 if (set->nodeTab[i] == NULL) 11735 continue; 11736 11737 contextNode = set->nodeTab[i]; 11738 xpctxt->node = contextNode; 11739 xpctxt->contextSize = contextSize; 11740 xpctxt->proximityPosition = ++contextPos; 11741 11742 /* 11743 * Initialize the new set. 11744 * Also set the xpath document in case things like 11745 * key() evaluation are attempted on the predicate 11746 */ 11747 if ((contextNode->type != XML_NAMESPACE_DECL) && 11748 (contextNode->doc != NULL)) 11749 xpctxt->doc = contextNode->doc; 11750 /* 11751 * Evaluate the predicate expression with 1 context node 11752 * at a time; this node is packaged into a node set; this 11753 * node set is handed over to the evaluation mechanism. 11754 */ 11755 if (contextObj == NULL) 11756 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode); 11757 else 11758 xmlXPathNodeSetAddUnique(contextObj->nodesetval, 11759 contextNode); 11760 11761 valuePush(ctxt, contextObj); 11762 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1); 11763 11764 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) { 11765 xmlXPathObjectPtr tmp; 11766 /* pop the result */ 11767 tmp = valuePop(ctxt); 11768 xmlXPathReleaseObject(xpctxt, tmp); 11769 /* then pop off contextObj, which will be freed later */ 11770 valuePop(ctxt); 11771 goto evaluation_error; 11772 } 11773 11774 if (res) 11775 pos++; 11776 11777 if (res && (pos >= minPos) && (pos <= maxPos)) { 11778 /* 11779 * Fits in the requested range. 11780 */ 11781 newContextSize++; 11782 if (minPos == maxPos) { 11783 /* 11784 * Only 1 node was requested. 11785 */ 11786 if (contextNode->type == XML_NAMESPACE_DECL) { 11787 /* 11788 * As always: take care of those nasty 11789 * namespace nodes. 11790 */ 11791 set->nodeTab[i] = NULL; 11792 } 11793 xmlXPathNodeSetClear(set, hasNsNodes); 11794 set->nodeNr = 1; 11795 set->nodeTab[0] = contextNode; 11796 goto evaluation_exit; 11797 } 11798 if (pos == maxPos) { 11799 /* 11800 * We are done. 11801 */ 11802 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes); 11803 goto evaluation_exit; 11804 } 11805 } else { 11806 /* 11807 * Remove the entry from the initial node set. 11808 */ 11809 set->nodeTab[i] = NULL; 11810 if (contextNode->type == XML_NAMESPACE_DECL) 11811 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode); 11812 } 11813 if (exprRes != NULL) { 11814 xmlXPathReleaseObject(ctxt->context, exprRes); 11815 exprRes = NULL; 11816 } 11817 if (ctxt->value == contextObj) { 11818 /* 11819 * Don't free the temporary XPath object holding the 11820 * context node, in order to avoid massive recreation 11821 * inside this loop. 11822 */ 11823 valuePop(ctxt); 11824 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes); 11825 } else { 11826 /* 11827 * The object was lost in the evaluation machinery. 11828 * Can this happen? Maybe in case of internal-errors. 11829 */ 11830 contextObj = NULL; 11831 } 11832 } 11833 goto evaluation_exit; 11834 11835 evaluation_error: 11836 xmlXPathNodeSetClear(set, hasNsNodes); 11837 newContextSize = 0; 11838 11839 evaluation_exit: 11840 if (contextObj != NULL) { 11841 if (ctxt->value == contextObj) 11842 valuePop(ctxt); 11843 xmlXPathReleaseObject(xpctxt, contextObj); 11844 } 11845 if (exprRes != NULL) 11846 xmlXPathReleaseObject(ctxt->context, exprRes); 11847 /* 11848 * Reset/invalidate the context. 11849 */ 11850 xpctxt->node = oldContextNode; 11851 xpctxt->doc = oldContextDoc; 11852 xpctxt->contextSize = -1; 11853 xpctxt->proximityPosition = -1; 11854 return(newContextSize); 11855 } 11856 return(contextSize); 11857 } 11858 11859 static int 11860 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt, 11861 xmlXPathStepOpPtr op, 11862 int *maxPos) 11863 { 11864 11865 xmlXPathStepOpPtr exprOp; 11866 11867 /* 11868 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet! 11869 */ 11870 11871 /* 11872 * If not -1, then ch1 will point to: 11873 * 1) For predicates (XPATH_OP_PREDICATE): 11874 * - an inner predicate operator 11875 * 2) For filters (XPATH_OP_FILTER): 11876 * - an inner filter operater OR 11877 * - an expression selecting the node set. 11878 * E.g. "key('a', 'b')" or "(//foo | //bar)". 11879 */ 11880 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER)) 11881 return(0); 11882 11883 if (op->ch2 != -1) { 11884 exprOp = &ctxt->comp->steps[op->ch2]; 11885 } else 11886 return(0); 11887 11888 if ((exprOp != NULL) && 11889 (exprOp->op == XPATH_OP_VALUE) && 11890 (exprOp->value4 != NULL) && 11891 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER)) 11892 { 11893 /* 11894 * We have a "[n]" predicate here. 11895 * TODO: Unfortunately this simplistic test here is not 11896 * able to detect a position() predicate in compound 11897 * expressions like "[@attr = 'a" and position() = 1], 11898 * and even not the usage of position() in 11899 * "[position() = 1]"; thus - obviously - a position-range, 11900 * like it "[position() < 5]", is also not detected. 11901 * Maybe we could rewrite the AST to ease the optimization. 11902 */ 11903 *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval; 11904 11905 if (((xmlXPathObjectPtr) exprOp->value4)->floatval == 11906 (float) *maxPos) 11907 { 11908 return(1); 11909 } 11910 } 11911 return(0); 11912 } 11913 11914 static int 11915 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, 11916 xmlXPathStepOpPtr op, 11917 xmlNodePtr * first, xmlNodePtr * last, 11918 int toBool) 11919 { 11920 11921 #define XP_TEST_HIT \ 11922 if (hasAxisRange != 0) { \ 11923 if (++pos == maxPos) { \ 11924 addNode(seq, cur); \ 11925 goto axis_range_end; } \ 11926 } else { \ 11927 addNode(seq, cur); \ 11928 if (breakOnFirstHit) goto first_hit; } 11929 11930 #define XP_TEST_HIT_NS \ 11931 if (hasAxisRange != 0) { \ 11932 if (++pos == maxPos) { \ 11933 hasNsNodes = 1; \ 11934 xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \ 11935 goto axis_range_end; } \ 11936 } else { \ 11937 hasNsNodes = 1; \ 11938 xmlXPathNodeSetAddNs(seq, \ 11939 xpctxt->node, (xmlNsPtr) cur); \ 11940 if (breakOnFirstHit) goto first_hit; } 11941 11942 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value; 11943 xmlXPathTestVal test = (xmlXPathTestVal) op->value2; 11944 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3; 11945 const xmlChar *prefix = op->value4; 11946 const xmlChar *name = op->value5; 11947 const xmlChar *URI = NULL; 11948 11949 #ifdef DEBUG_STEP 11950 int nbMatches = 0, prevMatches = 0; 11951 #endif 11952 int total = 0, hasNsNodes = 0; 11953 /* The popped object holding the context nodes */ 11954 xmlXPathObjectPtr obj; 11955 /* The set of context nodes for the node tests */ 11956 xmlNodeSetPtr contextSeq; 11957 int contextIdx; 11958 xmlNodePtr contextNode; 11959 /* The context node for a compound traversal */ 11960 xmlNodePtr outerContextNode; 11961 /* The final resulting node set wrt to all context nodes */ 11962 xmlNodeSetPtr outSeq; 11963 /* 11964 * The temporary resulting node set wrt 1 context node. 11965 * Used to feed predicate evaluation. 11966 */ 11967 xmlNodeSetPtr seq; 11968 xmlNodePtr cur; 11969 /* First predicate operator */ 11970 xmlXPathStepOpPtr predOp; 11971 int maxPos; /* The requested position() (when a "[n]" predicate) */ 11972 int hasPredicateRange, hasAxisRange, pos, size, newSize; 11973 int breakOnFirstHit; 11974 11975 xmlXPathTraversalFunction next = NULL; 11976 /* compound axis traversal */ 11977 xmlXPathTraversalFunctionExt outerNext = NULL; 11978 void (*addNode) (xmlNodeSetPtr, xmlNodePtr); 11979 xmlXPathNodeSetMergeFunction mergeAndClear; 11980 xmlNodePtr oldContextNode; 11981 xmlXPathContextPtr xpctxt = ctxt->context; 11982 11983 11984 CHECK_TYPE0(XPATH_NODESET); 11985 obj = valuePop(ctxt); 11986 /* 11987 * Setup namespaces. 11988 */ 11989 if (prefix != NULL) { 11990 URI = xmlXPathNsLookup(xpctxt, prefix); 11991 if (URI == NULL) { 11992 xmlXPathReleaseObject(xpctxt, obj); 11993 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); 11994 } 11995 } 11996 /* 11997 * Setup axis. 11998 * 11999 * MAYBE FUTURE TODO: merging optimizations: 12000 * - If the nodes to be traversed wrt to the initial nodes and 12001 * the current axis cannot overlap, then we could avoid searching 12002 * for duplicates during the merge. 12003 * But the question is how/when to evaluate if they cannot overlap. 12004 * Example: if we know that for two initial nodes, the one is 12005 * not in the ancestor-or-self axis of the other, then we could safely 12006 * avoid a duplicate-aware merge, if the axis to be traversed is e.g. 12007 * the descendant-or-self axis. 12008 */ 12009 mergeAndClear = xmlXPathNodeSetMergeAndClear; 12010 switch (axis) { 12011 case AXIS_ANCESTOR: 12012 first = NULL; 12013 next = xmlXPathNextAncestor; 12014 break; 12015 case AXIS_ANCESTOR_OR_SELF: 12016 first = NULL; 12017 next = xmlXPathNextAncestorOrSelf; 12018 break; 12019 case AXIS_ATTRIBUTE: 12020 first = NULL; 12021 last = NULL; 12022 next = xmlXPathNextAttribute; 12023 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12024 break; 12025 case AXIS_CHILD: 12026 last = NULL; 12027 if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) { 12028 /* 12029 * This iterator will give us only nodes which can 12030 * hold element nodes. 12031 */ 12032 outerNext = xmlXPathNextDescendantOrSelfElemParent; 12033 } 12034 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) && 12035 (type == NODE_TYPE_NODE)) 12036 { 12037 /* 12038 * Optimization if an element node type is 'element'. 12039 */ 12040 next = xmlXPathNextChildElement; 12041 } else 12042 next = xmlXPathNextChild; 12043 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12044 break; 12045 case AXIS_DESCENDANT: 12046 last = NULL; 12047 next = xmlXPathNextDescendant; 12048 break; 12049 case AXIS_DESCENDANT_OR_SELF: 12050 last = NULL; 12051 next = xmlXPathNextDescendantOrSelf; 12052 break; 12053 case AXIS_FOLLOWING: 12054 last = NULL; 12055 next = xmlXPathNextFollowing; 12056 break; 12057 case AXIS_FOLLOWING_SIBLING: 12058 last = NULL; 12059 next = xmlXPathNextFollowingSibling; 12060 break; 12061 case AXIS_NAMESPACE: 12062 first = NULL; 12063 last = NULL; 12064 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; 12065 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12066 break; 12067 case AXIS_PARENT: 12068 first = NULL; 12069 next = xmlXPathNextParent; 12070 break; 12071 case AXIS_PRECEDING: 12072 first = NULL; 12073 next = xmlXPathNextPrecedingInternal; 12074 break; 12075 case AXIS_PRECEDING_SIBLING: 12076 first = NULL; 12077 next = xmlXPathNextPrecedingSibling; 12078 break; 12079 case AXIS_SELF: 12080 first = NULL; 12081 last = NULL; 12082 next = xmlXPathNextSelf; 12083 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12084 break; 12085 } 12086 12087 #ifdef DEBUG_STEP 12088 xmlXPathDebugDumpStepAxis(op, 12089 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0); 12090 #endif 12091 12092 if (next == NULL) { 12093 xmlXPathReleaseObject(xpctxt, obj); 12094 return(0); 12095 } 12096 contextSeq = obj->nodesetval; 12097 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) { 12098 xmlXPathReleaseObject(xpctxt, obj); 12099 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL)); 12100 return(0); 12101 } 12102 /* 12103 * Predicate optimization --------------------------------------------- 12104 * If this step has a last predicate, which contains a position(), 12105 * then we'll optimize (although not exactly "position()", but only 12106 * the short-hand form, i.e., "[n]". 12107 * 12108 * Example - expression "/foo[parent::bar][1]": 12109 * 12110 * COLLECT 'child' 'name' 'node' foo -- op (we are here) 12111 * ROOT -- op->ch1 12112 * PREDICATE -- op->ch2 (predOp) 12113 * PREDICATE -- predOp->ch1 = [parent::bar] 12114 * SORT 12115 * COLLECT 'parent' 'name' 'node' bar 12116 * NODE 12117 * ELEM Object is a number : 1 -- predOp->ch2 = [1] 12118 * 12119 */ 12120 maxPos = 0; 12121 predOp = NULL; 12122 hasPredicateRange = 0; 12123 hasAxisRange = 0; 12124 if (op->ch2 != -1) { 12125 /* 12126 * There's at least one predicate. 16 == XPATH_OP_PREDICATE 12127 */ 12128 predOp = &ctxt->comp->steps[op->ch2]; 12129 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) { 12130 if (predOp->ch1 != -1) { 12131 /* 12132 * Use the next inner predicate operator. 12133 */ 12134 predOp = &ctxt->comp->steps[predOp->ch1]; 12135 hasPredicateRange = 1; 12136 } else { 12137 /* 12138 * There's no other predicate than the [n] predicate. 12139 */ 12140 predOp = NULL; 12141 hasAxisRange = 1; 12142 } 12143 } 12144 } 12145 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0; 12146 /* 12147 * Axis traversal ----------------------------------------------------- 12148 */ 12149 /* 12150 * 2.3 Node Tests 12151 * - For the attribute axis, the principal node type is attribute. 12152 * - For the namespace axis, the principal node type is namespace. 12153 * - For other axes, the principal node type is element. 12154 * 12155 * A node test * is true for any node of the 12156 * principal node type. For example, child::* will 12157 * select all element children of the context node 12158 */ 12159 oldContextNode = xpctxt->node; 12160 addNode = xmlXPathNodeSetAddUnique; 12161 outSeq = NULL; 12162 seq = NULL; 12163 outerContextNode = NULL; 12164 contextNode = NULL; 12165 contextIdx = 0; 12166 12167 12168 while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) { 12169 if (outerNext != NULL) { 12170 /* 12171 * This is a compound traversal. 12172 */ 12173 if (contextNode == NULL) { 12174 /* 12175 * Set the context for the outer traversal. 12176 */ 12177 outerContextNode = contextSeq->nodeTab[contextIdx++]; 12178 contextNode = outerNext(NULL, outerContextNode); 12179 } else 12180 contextNode = outerNext(contextNode, outerContextNode); 12181 if (contextNode == NULL) 12182 continue; 12183 /* 12184 * Set the context for the main traversal. 12185 */ 12186 xpctxt->node = contextNode; 12187 } else 12188 xpctxt->node = contextSeq->nodeTab[contextIdx++]; 12189 12190 if (seq == NULL) { 12191 seq = xmlXPathNodeSetCreate(NULL); 12192 if (seq == NULL) { 12193 total = 0; 12194 goto error; 12195 } 12196 } 12197 /* 12198 * Traverse the axis and test the nodes. 12199 */ 12200 pos = 0; 12201 cur = NULL; 12202 hasNsNodes = 0; 12203 do { 12204 cur = next(ctxt, cur); 12205 if (cur == NULL) 12206 break; 12207 12208 /* 12209 * QUESTION TODO: What does the "first" and "last" stuff do? 12210 */ 12211 if ((first != NULL) && (*first != NULL)) { 12212 if (*first == cur) 12213 break; 12214 if (((total % 256) == 0) && 12215 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 12216 (xmlXPathCmpNodesExt(*first, cur) >= 0)) 12217 #else 12218 (xmlXPathCmpNodes(*first, cur) >= 0)) 12219 #endif 12220 { 12221 break; 12222 } 12223 } 12224 if ((last != NULL) && (*last != NULL)) { 12225 if (*last == cur) 12226 break; 12227 if (((total % 256) == 0) && 12228 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 12229 (xmlXPathCmpNodesExt(cur, *last) >= 0)) 12230 #else 12231 (xmlXPathCmpNodes(cur, *last) >= 0)) 12232 #endif 12233 { 12234 break; 12235 } 12236 } 12237 12238 total++; 12239 12240 #ifdef DEBUG_STEP 12241 xmlGenericError(xmlGenericErrorContext, " %s", cur->name); 12242 #endif 12243 12244 switch (test) { 12245 case NODE_TEST_NONE: 12246 total = 0; 12247 STRANGE 12248 goto error; 12249 case NODE_TEST_TYPE: 12250 /* 12251 * TODO: Don't we need to use 12252 * xmlXPathNodeSetAddNs() for namespace nodes here? 12253 * Surprisingly, some c14n tests fail, if we do this. 12254 */ 12255 if (type == NODE_TYPE_NODE) { 12256 switch (cur->type) { 12257 case XML_DOCUMENT_NODE: 12258 case XML_HTML_DOCUMENT_NODE: 12259 #ifdef LIBXML_DOCB_ENABLED 12260 case XML_DOCB_DOCUMENT_NODE: 12261 #endif 12262 case XML_ELEMENT_NODE: 12263 case XML_ATTRIBUTE_NODE: 12264 case XML_PI_NODE: 12265 case XML_COMMENT_NODE: 12266 case XML_CDATA_SECTION_NODE: 12267 case XML_TEXT_NODE: 12268 case XML_NAMESPACE_DECL: 12269 XP_TEST_HIT 12270 break; 12271 default: 12272 break; 12273 } 12274 } else if (cur->type == type) { 12275 if (type == XML_NAMESPACE_DECL) 12276 XP_TEST_HIT_NS 12277 else 12278 XP_TEST_HIT 12279 } else if ((type == NODE_TYPE_TEXT) && 12280 (cur->type == XML_CDATA_SECTION_NODE)) 12281 { 12282 XP_TEST_HIT 12283 } 12284 break; 12285 case NODE_TEST_PI: 12286 if ((cur->type == XML_PI_NODE) && 12287 ((name == NULL) || xmlStrEqual(name, cur->name))) 12288 { 12289 XP_TEST_HIT 12290 } 12291 break; 12292 case NODE_TEST_ALL: 12293 if (axis == AXIS_ATTRIBUTE) { 12294 if (cur->type == XML_ATTRIBUTE_NODE) 12295 { 12296 XP_TEST_HIT 12297 } 12298 } else if (axis == AXIS_NAMESPACE) { 12299 if (cur->type == XML_NAMESPACE_DECL) 12300 { 12301 XP_TEST_HIT_NS 12302 } 12303 } else { 12304 if (cur->type == XML_ELEMENT_NODE) { 12305 if (prefix == NULL) 12306 { 12307 XP_TEST_HIT 12308 12309 } else if ((cur->ns != NULL) && 12310 (xmlStrEqual(URI, cur->ns->href))) 12311 { 12312 XP_TEST_HIT 12313 } 12314 } 12315 } 12316 break; 12317 case NODE_TEST_NS:{ 12318 TODO; 12319 break; 12320 } 12321 case NODE_TEST_NAME: 12322 if (axis == AXIS_ATTRIBUTE) { 12323 if (cur->type != XML_ATTRIBUTE_NODE) 12324 break; 12325 } else if (axis == AXIS_NAMESPACE) { 12326 if (cur->type != XML_NAMESPACE_DECL) 12327 break; 12328 } else { 12329 if (cur->type != XML_ELEMENT_NODE) 12330 break; 12331 } 12332 switch (cur->type) { 12333 case XML_ELEMENT_NODE: 12334 if (xmlStrEqual(name, cur->name)) { 12335 if (prefix == NULL) { 12336 if (cur->ns == NULL) 12337 { 12338 XP_TEST_HIT 12339 } 12340 } else { 12341 if ((cur->ns != NULL) && 12342 (xmlStrEqual(URI, cur->ns->href))) 12343 { 12344 XP_TEST_HIT 12345 } 12346 } 12347 } 12348 break; 12349 case XML_ATTRIBUTE_NODE:{ 12350 xmlAttrPtr attr = (xmlAttrPtr) cur; 12351 12352 if (xmlStrEqual(name, attr->name)) { 12353 if (prefix == NULL) { 12354 if ((attr->ns == NULL) || 12355 (attr->ns->prefix == NULL)) 12356 { 12357 XP_TEST_HIT 12358 } 12359 } else { 12360 if ((attr->ns != NULL) && 12361 (xmlStrEqual(URI, 12362 attr->ns->href))) 12363 { 12364 XP_TEST_HIT 12365 } 12366 } 12367 } 12368 break; 12369 } 12370 case XML_NAMESPACE_DECL: 12371 if (cur->type == XML_NAMESPACE_DECL) { 12372 xmlNsPtr ns = (xmlNsPtr) cur; 12373 12374 if ((ns->prefix != NULL) && (name != NULL) 12375 && (xmlStrEqual(ns->prefix, name))) 12376 { 12377 XP_TEST_HIT_NS 12378 } 12379 } 12380 break; 12381 default: 12382 break; 12383 } 12384 break; 12385 } /* switch(test) */ 12386 } while (cur != NULL); 12387 12388 goto apply_predicates; 12389 12390 axis_range_end: /* ----------------------------------------------------- */ 12391 /* 12392 * We have a "/foo[n]", and position() = n was reached. 12393 * Note that we can have as well "/foo/::parent::foo[1]", so 12394 * a duplicate-aware merge is still needed. 12395 * Merge with the result. 12396 */ 12397 if (outSeq == NULL) { 12398 outSeq = seq; 12399 seq = NULL; 12400 } else 12401 outSeq = mergeAndClear(outSeq, seq, 0); 12402 /* 12403 * Break if only a true/false result was requested. 12404 */ 12405 if (toBool) 12406 break; 12407 continue; 12408 12409 first_hit: /* ---------------------------------------------------------- */ 12410 /* 12411 * Break if only a true/false result was requested and 12412 * no predicates existed and a node test succeeded. 12413 */ 12414 if (outSeq == NULL) { 12415 outSeq = seq; 12416 seq = NULL; 12417 } else 12418 outSeq = mergeAndClear(outSeq, seq, 0); 12419 break; 12420 12421 #ifdef DEBUG_STEP 12422 if (seq != NULL) 12423 nbMatches += seq->nodeNr; 12424 #endif 12425 12426 apply_predicates: /* --------------------------------------------------- */ 12427 /* 12428 * Apply predicates. 12429 */ 12430 if ((predOp != NULL) && (seq->nodeNr > 0)) { 12431 /* 12432 * E.g. when we have a "/foo[some expression][n]". 12433 */ 12434 /* 12435 * QUESTION TODO: The old predicate evaluation took into 12436 * account location-sets. 12437 * (E.g. ctxt->value->type == XPATH_LOCATIONSET) 12438 * Do we expect such a set here? 12439 * All what I learned now from the evaluation semantics 12440 * does not indicate that a location-set will be processed 12441 * here, so this looks OK. 12442 */ 12443 /* 12444 * Iterate over all predicates, starting with the outermost 12445 * predicate. 12446 * TODO: Problem: we cannot execute the inner predicates first 12447 * since we cannot go back *up* the operator tree! 12448 * Options we have: 12449 * 1) Use of recursive functions (like is it currently done 12450 * via xmlXPathCompOpEval()) 12451 * 2) Add a predicate evaluation information stack to the 12452 * context struct 12453 * 3) Change the way the operators are linked; we need a 12454 * "parent" field on xmlXPathStepOp 12455 * 12456 * For the moment, I'll try to solve this with a recursive 12457 * function: xmlXPathCompOpEvalPredicate(). 12458 */ 12459 size = seq->nodeNr; 12460 if (hasPredicateRange != 0) 12461 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt, 12462 predOp, seq, size, maxPos, maxPos, hasNsNodes); 12463 else 12464 newSize = xmlXPathCompOpEvalPredicate(ctxt, 12465 predOp, seq, size, hasNsNodes); 12466 12467 if (ctxt->error != XPATH_EXPRESSION_OK) { 12468 total = 0; 12469 goto error; 12470 } 12471 /* 12472 * Add the filtered set of nodes to the result node set. 12473 */ 12474 if (newSize == 0) { 12475 /* 12476 * The predicates filtered all nodes out. 12477 */ 12478 xmlXPathNodeSetClear(seq, hasNsNodes); 12479 } else if (seq->nodeNr > 0) { 12480 /* 12481 * Add to result set. 12482 */ 12483 if (outSeq == NULL) { 12484 if (size != newSize) { 12485 /* 12486 * We need to merge and clear here, since 12487 * the sequence will contained NULLed entries. 12488 */ 12489 outSeq = mergeAndClear(NULL, seq, 1); 12490 } else { 12491 outSeq = seq; 12492 seq = NULL; 12493 } 12494 } else 12495 outSeq = mergeAndClear(outSeq, seq, 12496 (size != newSize) ? 1: 0); 12497 /* 12498 * Break if only a true/false result was requested. 12499 */ 12500 if (toBool) 12501 break; 12502 } 12503 } else if (seq->nodeNr > 0) { 12504 /* 12505 * Add to result set. 12506 */ 12507 if (outSeq == NULL) { 12508 outSeq = seq; 12509 seq = NULL; 12510 } else { 12511 outSeq = mergeAndClear(outSeq, seq, 0); 12512 } 12513 } 12514 } 12515 12516 error: 12517 if ((obj->boolval) && (obj->user != NULL)) { 12518 /* 12519 * QUESTION TODO: What does this do and why? 12520 * TODO: Do we have to do this also for the "error" 12521 * cleanup further down? 12522 */ 12523 ctxt->value->boolval = 1; 12524 ctxt->value->user = obj->user; 12525 obj->user = NULL; 12526 obj->boolval = 0; 12527 } 12528 xmlXPathReleaseObject(xpctxt, obj); 12529 12530 /* 12531 * Ensure we return at least an emtpy set. 12532 */ 12533 if (outSeq == NULL) { 12534 if ((seq != NULL) && (seq->nodeNr == 0)) 12535 outSeq = seq; 12536 else 12537 outSeq = xmlXPathNodeSetCreate(NULL); 12538 /* XXX what if xmlXPathNodeSetCreate returned NULL here? */ 12539 } 12540 if ((seq != NULL) && (seq != outSeq)) { 12541 xmlXPathFreeNodeSet(seq); 12542 } 12543 /* 12544 * Hand over the result. Better to push the set also in 12545 * case of errors. 12546 */ 12547 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq)); 12548 /* 12549 * Reset the context node. 12550 */ 12551 xpctxt->node = oldContextNode; 12552 12553 #ifdef DEBUG_STEP 12554 xmlGenericError(xmlGenericErrorContext, 12555 "\nExamined %d nodes, found %d nodes at that step\n", 12556 total, nbMatches); 12557 #endif 12558 12559 return(total); 12560 } 12561 12562 static int 12563 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt, 12564 xmlXPathStepOpPtr op, xmlNodePtr * first); 12565 12577 static int 12578 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt, 12579 xmlXPathStepOpPtr op, xmlNodePtr * first) 12580 { 12581 int total = 0, cur; 12582 xmlXPathCompExprPtr comp; 12583 xmlXPathObjectPtr arg1, arg2; 12584 12585 CHECK_ERROR0; 12586 comp = ctxt->comp; 12587 switch (op->op) { 12588 case XPATH_OP_END: 12589 return (0); 12590 case XPATH_OP_UNION: 12591 total = 12592 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1], 12593 first); 12594 CHECK_ERROR0; 12595 if ((ctxt->value != NULL) 12596 && (ctxt->value->type == XPATH_NODESET) 12597 && (ctxt->value->nodesetval != NULL) 12598 && (ctxt->value->nodesetval->nodeNr >= 1)) { 12599 /* 12600 * limit tree traversing to first node in the result 12601 */ 12602 /* 12603 * OPTIMIZE TODO: This implicitely sorts 12604 * the result, even if not needed. E.g. if the argument 12605 * of the count() function, no sorting is needed. 12606 * OPTIMIZE TODO: How do we know if the node-list wasn't 12607 * aready sorted? 12608 */ 12609 if (ctxt->value->nodesetval->nodeNr > 1) 12610 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12611 *first = ctxt->value->nodesetval->nodeTab[0]; 12612 } 12613 cur = 12614 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2], 12615 first); 12616 CHECK_ERROR0; 12617 CHECK_TYPE0(XPATH_NODESET); 12618 arg2 = valuePop(ctxt); 12619 12620 CHECK_TYPE0(XPATH_NODESET); 12621 arg1 = valuePop(ctxt); 12622 12623 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 12624 arg2->nodesetval); 12625 valuePush(ctxt, arg1); 12626 xmlXPathReleaseObject(ctxt->context, arg2); 12627 /* optimizer */ 12628 if (total > cur) 12629 xmlXPathCompSwap(op); 12630 return (total + cur); 12631 case XPATH_OP_ROOT: 12632 xmlXPathRoot(ctxt); 12633 return (0); 12634 case XPATH_OP_NODE: 12635 if (op->ch1 != -1) 12636 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12637 CHECK_ERROR0; 12638 if (op->ch2 != -1) 12639 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12640 CHECK_ERROR0; 12641 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 12642 ctxt->context->node)); 12643 return (total); 12644 case XPATH_OP_RESET: 12645 if (op->ch1 != -1) 12646 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12647 CHECK_ERROR0; 12648 if (op->ch2 != -1) 12649 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12650 CHECK_ERROR0; 12651 ctxt->context->node = NULL; 12652 return (total); 12653 case XPATH_OP_COLLECT:{ 12654 if (op->ch1 == -1) 12655 return (total); 12656 12657 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12658 CHECK_ERROR0; 12659 12660 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0); 12661 return (total); 12662 } 12663 case XPATH_OP_VALUE: 12664 valuePush(ctxt, 12665 xmlXPathCacheObjectCopy(ctxt->context, 12666 (xmlXPathObjectPtr) op->value4)); 12667 return (0); 12668 case XPATH_OP_SORT: 12669 if (op->ch1 != -1) 12670 total += 12671 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1], 12672 first); 12673 CHECK_ERROR0; 12674 if ((ctxt->value != NULL) 12675 && (ctxt->value->type == XPATH_NODESET) 12676 && (ctxt->value->nodesetval != NULL) 12677 && (ctxt->value->nodesetval->nodeNr > 1)) 12678 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12679 return (total); 12680 #ifdef XP_OPTIMIZED_FILTER_FIRST 12681 case XPATH_OP_FILTER: 12682 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first); 12683 return (total); 12684 #endif 12685 default: 12686 return (xmlXPathCompOpEval(ctxt, op)); 12687 } 12688 } 12689 12701 static int 12702 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op, 12703 xmlNodePtr * last) 12704 { 12705 int total = 0, cur; 12706 xmlXPathCompExprPtr comp; 12707 xmlXPathObjectPtr arg1, arg2; 12708 xmlNodePtr bak; 12709 xmlDocPtr bakd; 12710 int pp; 12711 int cs; 12712 12713 CHECK_ERROR0; 12714 comp = ctxt->comp; 12715 switch (op->op) { 12716 case XPATH_OP_END: 12717 return (0); 12718 case XPATH_OP_UNION: 12719 bakd = ctxt->context->doc; 12720 bak = ctxt->context->node; 12721 pp = ctxt->context->proximityPosition; 12722 cs = ctxt->context->contextSize; 12723 total = 12724 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last); 12725 CHECK_ERROR0; 12726 if ((ctxt->value != NULL) 12727 && (ctxt->value->type == XPATH_NODESET) 12728 && (ctxt->value->nodesetval != NULL) 12729 && (ctxt->value->nodesetval->nodeNr >= 1)) { 12730 /* 12731 * limit tree traversing to first node in the result 12732 */ 12733 if (ctxt->value->nodesetval->nodeNr > 1) 12734 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12735 *last = 12736 ctxt->value->nodesetval->nodeTab[ctxt->value-> 12737 nodesetval->nodeNr - 12738 1]; 12739 } 12740 ctxt->context->doc = bakd; 12741 ctxt->context->node = bak; 12742 ctxt->context->proximityPosition = pp; 12743 ctxt->context->contextSize = cs; 12744 cur = 12745 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last); 12746 CHECK_ERROR0; 12747 if ((ctxt->value != NULL) 12748 && (ctxt->value->type == XPATH_NODESET) 12749 && (ctxt->value->nodesetval != NULL) 12750 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */ 12751 } 12752 CHECK_TYPE0(XPATH_NODESET); 12753 arg2 = valuePop(ctxt); 12754 12755 CHECK_TYPE0(XPATH_NODESET); 12756 arg1 = valuePop(ctxt); 12757 12758 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 12759 arg2->nodesetval); 12760 valuePush(ctxt, arg1); 12761 xmlXPathReleaseObject(ctxt->context, arg2); 12762 /* optimizer */ 12763 if (total > cur) 12764 xmlXPathCompSwap(op); 12765 return (total + cur); 12766 case XPATH_OP_ROOT: 12767 xmlXPathRoot(ctxt); 12768 return (0); 12769 case XPATH_OP_NODE: 12770 if (op->ch1 != -1) 12771 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12772 CHECK_ERROR0; 12773 if (op->ch2 != -1) 12774 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12775 CHECK_ERROR0; 12776 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 12777 ctxt->context->node)); 12778 return (total); 12779 case XPATH_OP_RESET: 12780 if (op->ch1 != -1) 12781 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12782 CHECK_ERROR0; 12783 if (op->ch2 != -1) 12784 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12785 CHECK_ERROR0; 12786 ctxt->context->node = NULL; 12787 return (total); 12788 case XPATH_OP_COLLECT:{ 12789 if (op->ch1 == -1) 12790 return (0); 12791 12792 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12793 CHECK_ERROR0; 12794 12795 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0); 12796 return (total); 12797 } 12798 case XPATH_OP_VALUE: 12799 valuePush(ctxt, 12800 xmlXPathCacheObjectCopy(ctxt->context, 12801 (xmlXPathObjectPtr) op->value4)); 12802 return (0); 12803 case XPATH_OP_SORT: 12804 if (op->ch1 != -1) 12805 total += 12806 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], 12807 last); 12808 CHECK_ERROR0; 12809 if ((ctxt->value != NULL) 12810 && (ctxt->value->type == XPATH_NODESET) 12811 && (ctxt->value->nodesetval != NULL) 12812 && (ctxt->value->nodesetval->nodeNr > 1)) 12813 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12814 return (total); 12815 default: 12816 return (xmlXPathCompOpEval(ctxt, op)); 12817 } 12818 } 12819 12820 #ifdef XP_OPTIMIZED_FILTER_FIRST 12821 static int 12822 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt, 12823 xmlXPathStepOpPtr op, xmlNodePtr * first) 12824 { 12825 int total = 0; 12826 xmlXPathCompExprPtr comp; 12827 xmlXPathObjectPtr res; 12828 xmlXPathObjectPtr obj; 12829 xmlNodeSetPtr oldset; 12830 xmlNodePtr oldnode; 12831 xmlDocPtr oldDoc; 12832 int i; 12833 12834 CHECK_ERROR0; 12835 comp = ctxt->comp; 12836 /* 12837 * Optimization for ()[last()] selection i.e. the last elem 12838 */ 12839 if ((op->ch1 != -1) && (op->ch2 != -1) && 12840 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 12841 (comp->steps[op->ch2].op == XPATH_OP_SORT)) { 12842 int f = comp->steps[op->ch2].ch1; 12843 12844 if ((f != -1) && 12845 (comp->steps[f].op == XPATH_OP_FUNCTION) && 12846 (comp->steps[f].value5 == NULL) && 12847 (comp->steps[f].value == 0) && 12848 (comp->steps[f].value4 != NULL) && 12849 (xmlStrEqual 12850 (comp->steps[f].value4, BAD_CAST "last"))) { 12851 xmlNodePtr last = NULL; 12852 12853 total += 12854 xmlXPathCompOpEvalLast(ctxt, 12855 &comp->steps[op->ch1], 12856 &last); 12857 CHECK_ERROR0; 12858 /* 12859 * The nodeset should be in document order, 12860 * Keep only the last value 12861 */ 12862 if ((ctxt->value != NULL) && 12863 (ctxt->value->type == XPATH_NODESET) && 12864 (ctxt->value->nodesetval != NULL) && 12865 (ctxt->value->nodesetval->nodeTab != NULL) && 12866 (ctxt->value->nodesetval->nodeNr > 1)) { 12867 ctxt->value->nodesetval->nodeTab[0] = 12868 ctxt->value->nodesetval->nodeTab[ctxt-> 12869 value-> 12870 nodesetval-> 12871 nodeNr - 12872 1]; 12873 ctxt->value->nodesetval->nodeNr = 1; 12874 *first = *(ctxt->value->nodesetval->nodeTab); 12875 } 12876 return (total); 12877 } 12878 } 12879 12880 if (op->ch1 != -1) 12881 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12882 CHECK_ERROR0; 12883 if (op->ch2 == -1) 12884 return (total); 12885 if (ctxt->value == NULL) 12886 return (total); 12887 12888 #ifdef LIBXML_XPTR_ENABLED 12889 oldnode = ctxt->context->node; 12890 /* 12891 * Hum are we filtering the result of an XPointer expression 12892 */ 12893 if (ctxt->value->type == XPATH_LOCATIONSET) { 12894 xmlXPathObjectPtr tmp = NULL; 12895 xmlLocationSetPtr newlocset = NULL; 12896 xmlLocationSetPtr oldlocset; 12897 12898 /* 12899 * Extract the old locset, and then evaluate the result of the 12900 * expression for all the element in the locset. use it to grow 12901 * up a new locset. 12902 */ 12903 CHECK_TYPE0(XPATH_LOCATIONSET); 12904 obj = valuePop(ctxt); 12905 oldlocset = obj->user; 12906 ctxt->context->node = NULL; 12907 12908 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) { 12909 ctxt->context->contextSize = 0; 12910 ctxt->context->proximityPosition = 0; 12911 if (op->ch2 != -1) 12912 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12913 res = valuePop(ctxt); 12914 if (res != NULL) { 12915 xmlXPathReleaseObject(ctxt->context, res); 12916 } 12917 valuePush(ctxt, obj); 12918 CHECK_ERROR0; 12919 return (total); 12920 } 12921 newlocset = xmlXPtrLocationSetCreate(NULL); 12922 12923 for (i = 0; i < oldlocset->locNr; i++) { 12924 /* 12925 * Run the evaluation with a node list made of a 12926 * single item in the nodelocset. 12927 */ 12928 ctxt->context->node = oldlocset->locTab[i]->user; 12929 ctxt->context->contextSize = oldlocset->locNr; 12930 ctxt->context->proximityPosition = i + 1; 12931 if (tmp == NULL) { 12932 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 12933 ctxt->context->node); 12934 } else { 12935 xmlXPathNodeSetAddUnique(tmp->nodesetval, 12936 ctxt->context->node); 12937 } 12938 valuePush(ctxt, tmp); 12939 if (op->ch2 != -1) 12940 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12941 if (ctxt->error != XPATH_EXPRESSION_OK) { 12942 xmlXPathFreeObject(obj); 12943 return(0); 12944 } 12945 /* 12946 * The result of the evaluation need to be tested to 12947 * decided whether the filter succeeded or not 12948 */ 12949 res = valuePop(ctxt); 12950 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 12951 xmlXPtrLocationSetAdd(newlocset, 12952 xmlXPathCacheObjectCopy(ctxt->context, 12953 oldlocset->locTab[i])); 12954 } 12955 /* 12956 * Cleanup 12957 */ 12958 if (res != NULL) { 12959 xmlXPathReleaseObject(ctxt->context, res); 12960 } 12961 if (ctxt->value == tmp) { 12962 valuePop(ctxt); 12963 xmlXPathNodeSetClear(tmp->nodesetval, 1); 12964 /* 12965 * REVISIT TODO: Don't create a temporary nodeset 12966 * for everly iteration. 12967 */ 12968 /* OLD: xmlXPathFreeObject(res); */ 12969 } else 12970 tmp = NULL; 12971 ctxt->context->node = NULL; 12972 /* 12973 * Only put the first node in the result, then leave. 12974 */ 12975 if (newlocset->locNr > 0) { 12976 *first = (xmlNodePtr) oldlocset->locTab[i]->user; 12977 break; 12978 } 12979 } 12980 if (tmp != NULL) { 12981 xmlXPathReleaseObject(ctxt->context, tmp); 12982 } 12983 /* 12984 * The result is used as the new evaluation locset. 12985 */ 12986 xmlXPathReleaseObject(ctxt->context, obj); 12987 ctxt->context->node = NULL; 12988 ctxt->context->contextSize = -1; 12989 ctxt->context->proximityPosition = -1; 12990 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset)); 12991 ctxt->context->node = oldnode; 12992 return (total); 12993 } 12994 #endif /* LIBXML_XPTR_ENABLED */ 12995 12996 /* 12997 * Extract the old set, and then evaluate the result of the 12998 * expression for all the element in the set. use it to grow 12999 * up a new set. 13000 */ 13001 CHECK_TYPE0(XPATH_NODESET); 13002 obj = valuePop(ctxt); 13003 oldset = obj->nodesetval; 13004 13005 oldnode = ctxt->context->node; 13006 oldDoc = ctxt->context->doc; 13007 ctxt->context->node = NULL; 13008 13009 if ((oldset == NULL) || (oldset->nodeNr == 0)) { 13010 ctxt->context->contextSize = 0; 13011 ctxt->context->proximityPosition = 0; 13012 /* QUESTION TODO: Why was this code commented out? 13013 if (op->ch2 != -1) 13014 total += 13015 xmlXPathCompOpEval(ctxt, 13016 &comp->steps[op->ch2]); 13017 CHECK_ERROR0; 13018 res = valuePop(ctxt); 13019 if (res != NULL) 13020 xmlXPathFreeObject(res); 13021 */ 13022 valuePush(ctxt, obj); 13023 ctxt->context->node = oldnode; 13024 CHECK_ERROR0; 13025 } else { 13026 xmlNodeSetPtr newset; 13027 xmlXPathObjectPtr tmp = NULL; 13028 /* 13029 * Initialize the new set. 13030 * Also set the xpath document in case things like 13031 * key() evaluation are attempted on the predicate 13032 */ 13033 newset = xmlXPathNodeSetCreate(NULL); 13034 /* XXX what if xmlXPathNodeSetCreate returned NULL? */ 13035 13036 for (i = 0; i < oldset->nodeNr; i++) { 13037 /* 13038 * Run the evaluation with a node list made of 13039 * a single item in the nodeset. 13040 */ 13041 ctxt->context->node = oldset->nodeTab[i]; 13042 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) && 13043 (oldset->nodeTab[i]->doc != NULL)) 13044 ctxt->context->doc = oldset->nodeTab[i]->doc; 13045 if (tmp == NULL) { 13046 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13047 ctxt->context->node); 13048 } else { 13049 xmlXPathNodeSetAddUnique(tmp->nodesetval, 13050 ctxt->context->node); 13051 } 13052 valuePush(ctxt, tmp); 13053 ctxt->context->contextSize = oldset->nodeNr; 13054 ctxt->context->proximityPosition = i + 1; 13055 if (op->ch2 != -1) 13056 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13057 if (ctxt->error != XPATH_EXPRESSION_OK) { 13058 xmlXPathFreeNodeSet(newset); 13059 xmlXPathFreeObject(obj); 13060 return(0); 13061 } 13062 /* 13063 * The result of the evaluation needs to be tested to 13064 * decide whether the filter succeeded or not 13065 */ 13066 res = valuePop(ctxt); 13067 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 13068 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]); 13069 } 13070 /* 13071 * Cleanup 13072 */ 13073 if (res != NULL) { 13074 xmlXPathReleaseObject(ctxt->context, res); 13075 } 13076 if (ctxt->value == tmp) { 13077 valuePop(ctxt); 13078 /* 13079 * Don't free the temporary nodeset 13080 * in order to avoid massive recreation inside this 13081 * loop. 13082 */ 13083 xmlXPathNodeSetClear(tmp->nodesetval, 1); 13084 } else 13085 tmp = NULL; 13086 ctxt->context->node = NULL; 13087 /* 13088 * Only put the first node in the result, then leave. 13089 */ 13090 if (newset->nodeNr > 0) { 13091 *first = *(newset->nodeTab); 13092 break; 13093 } 13094 } 13095 if (tmp != NULL) { 13096 xmlXPathReleaseObject(ctxt->context, tmp); 13097 } 13098 /* 13099 * The result is used as the new evaluation set. 13100 */ 13101 xmlXPathReleaseObject(ctxt->context, obj); 13102 ctxt->context->node = NULL; 13103 ctxt->context->contextSize = -1; 13104 ctxt->context->proximityPosition = -1; 13105 /* may want to move this past the '}' later */ 13106 ctxt->context->doc = oldDoc; 13107 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset)); 13108 } 13109 ctxt->context->node = oldnode; 13110 return(total); 13111 } 13112 #endif /* XP_OPTIMIZED_FILTER_FIRST */ 13113 13122 static int 13123 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) 13124 { 13125 int total = 0; 13126 int equal, ret; 13127 xmlXPathCompExprPtr comp; 13128 xmlXPathObjectPtr arg1, arg2; 13129 xmlNodePtr bak; 13130 xmlDocPtr bakd; 13131 int pp; 13132 int cs; 13133 13134 CHECK_ERROR0; 13135 comp = ctxt->comp; 13136 switch (op->op) { 13137 case XPATH_OP_END: 13138 return (0); 13139 case XPATH_OP_AND: 13140 bakd = ctxt->context->doc; 13141 bak = ctxt->context->node; 13142 pp = ctxt->context->proximityPosition; 13143 cs = ctxt->context->contextSize; 13144 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13145 CHECK_ERROR0; 13146 xmlXPathBooleanFunction(ctxt, 1); 13147 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0)) 13148 return (total); 13149 arg2 = valuePop(ctxt); 13150 ctxt->context->doc = bakd; 13151 ctxt->context->node = bak; 13152 ctxt->context->proximityPosition = pp; 13153 ctxt->context->contextSize = cs; 13154 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13155 if (ctxt->error) { 13156 xmlXPathFreeObject(arg2); 13157 return(0); 13158 } 13159 xmlXPathBooleanFunction(ctxt, 1); 13160 arg1 = valuePop(ctxt); 13161 arg1->boolval &= arg2->boolval; 13162 valuePush(ctxt, arg1); 13163 xmlXPathReleaseObject(ctxt->context, arg2); 13164 return (total); 13165 case XPATH_OP_OR: 13166 bakd = ctxt->context->doc; 13167 bak = ctxt->context->node; 13168 pp = ctxt->context->proximityPosition; 13169 cs = ctxt->context->contextSize; 13170 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13171 CHECK_ERROR0; 13172 xmlXPathBooleanFunction(ctxt, 1); 13173 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1)) 13174 return (total); 13175 arg2 = valuePop(ctxt); 13176 ctxt->context->doc = bakd; 13177 ctxt->context->node = bak; 13178 ctxt->context->proximityPosition = pp; 13179 ctxt->context->contextSize = cs; 13180 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13181 if (ctxt->error) { 13182 xmlXPathFreeObject(arg2); 13183 return(0); 13184 } 13185 xmlXPathBooleanFunction(ctxt, 1); 13186 arg1 = valuePop(ctxt); 13187 arg1->boolval |= arg2->boolval; 13188 valuePush(ctxt, arg1); 13189 xmlXPathReleaseObject(ctxt->context, arg2); 13190 return (total); 13191 case XPATH_OP_EQUAL: 13192 bakd = ctxt->context->doc; 13193 bak = ctxt->context->node; 13194 pp = ctxt->context->proximityPosition; 13195 cs = ctxt->context->contextSize; 13196 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13197 CHECK_ERROR0; 13198 ctxt->context->doc = bakd; 13199 ctxt->context->node = bak; 13200 ctxt->context->proximityPosition = pp; 13201 ctxt->context->contextSize = cs; 13202 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13203 CHECK_ERROR0; 13204 if (op->value) 13205 equal = xmlXPathEqualValues(ctxt); 13206 else 13207 equal = xmlXPathNotEqualValues(ctxt); 13208 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal)); 13209 return (total); 13210 case XPATH_OP_CMP: 13211 bakd = ctxt->context->doc; 13212 bak = ctxt->context->node; 13213 pp = ctxt->context->proximityPosition; 13214 cs = ctxt->context->contextSize; 13215 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13216 CHECK_ERROR0; 13217 ctxt->context->doc = bakd; 13218 ctxt->context->node = bak; 13219 ctxt->context->proximityPosition = pp; 13220 ctxt->context->contextSize = cs; 13221 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13222 CHECK_ERROR0; 13223 ret = xmlXPathCompareValues(ctxt, op->value, op->value2); 13224 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret)); 13225 return (total); 13226 case XPATH_OP_PLUS: 13227 bakd = ctxt->context->doc; 13228 bak = ctxt->context->node; 13229 pp = ctxt->context->proximityPosition; 13230 cs = ctxt->context->contextSize; 13231 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13232 CHECK_ERROR0; 13233 if (op->ch2 != -1) { 13234 ctxt->context->doc = bakd; 13235 ctxt->context->node = bak; 13236 ctxt->context->proximityPosition = pp; 13237 ctxt->context->contextSize = cs; 13238 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13239 } 13240 CHECK_ERROR0; 13241 if (op->value == 0) 13242 xmlXPathSubValues(ctxt); 13243 else if (op->value == 1) 13244 xmlXPathAddValues(ctxt); 13245 else if (op->value == 2) 13246 xmlXPathValueFlipSign(ctxt); 13247 else if (op->value == 3) { 13248 CAST_TO_NUMBER; 13249 CHECK_TYPE0(XPATH_NUMBER); 13250 } 13251 return (total); 13252 case XPATH_OP_MULT: 13253 bakd = ctxt->context->doc; 13254 bak = ctxt->context->node; 13255 pp = ctxt->context->proximityPosition; 13256 cs = ctxt->context->contextSize; 13257 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13258 CHECK_ERROR0; 13259 ctxt->context->doc = bakd; 13260 ctxt->context->node = bak; 13261 ctxt->context->proximityPosition = pp; 13262 ctxt->context->contextSize = cs; 13263 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13264 CHECK_ERROR0; 13265 if (op->value == 0) 13266 xmlXPathMultValues(ctxt); 13267 else if (op->value == 1) 13268 xmlXPathDivValues(ctxt); 13269 else if (op->value == 2) 13270 xmlXPathModValues(ctxt); 13271 return (total); 13272 case XPATH_OP_UNION: 13273 bakd = ctxt->context->doc; 13274 bak = ctxt->context->node; 13275 pp = ctxt->context->proximityPosition; 13276 cs = ctxt->context->contextSize; 13277 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13278 CHECK_ERROR0; 13279 ctxt->context->doc = bakd; 13280 ctxt->context->node = bak; 13281 ctxt->context->proximityPosition = pp; 13282 ctxt->context->contextSize = cs; 13283 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13284 CHECK_ERROR0; 13285 CHECK_TYPE0(XPATH_NODESET); 13286 arg2 = valuePop(ctxt); 13287 13288 CHECK_TYPE0(XPATH_NODESET); 13289 arg1 = valuePop(ctxt); 13290 13291 if ((arg1->nodesetval == NULL) || 13292 ((arg2->nodesetval != NULL) && 13293 (arg2->nodesetval->nodeNr != 0))) 13294 { 13295 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 13296 arg2->nodesetval); 13297 } 13298 13299 valuePush(ctxt, arg1); 13300 xmlXPathReleaseObject(ctxt->context, arg2); 13301 return (total); 13302 case XPATH_OP_ROOT: 13303 xmlXPathRoot(ctxt); 13304 return (total); 13305 case XPATH_OP_NODE: 13306 if (op->ch1 != -1) 13307 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13308 CHECK_ERROR0; 13309 if (op->ch2 != -1) 13310 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13311 CHECK_ERROR0; 13312 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 13313 ctxt->context->node)); 13314 return (total); 13315 case XPATH_OP_RESET: 13316 if (op->ch1 != -1) 13317 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13318 CHECK_ERROR0; 13319 if (op->ch2 != -1) 13320 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13321 CHECK_ERROR0; 13322 ctxt->context->node = NULL; 13323 return (total); 13324 case XPATH_OP_COLLECT:{ 13325 if (op->ch1 == -1) 13326 return (total); 13327 13328 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13329 CHECK_ERROR0; 13330 13331 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0); 13332 return (total); 13333 } 13334 case XPATH_OP_VALUE: 13335 valuePush(ctxt, 13336 xmlXPathCacheObjectCopy(ctxt->context, 13337 (xmlXPathObjectPtr) op->value4)); 13338 return (total); 13339 case XPATH_OP_VARIABLE:{ 13340 xmlXPathObjectPtr val; 13341 13342 if (op->ch1 != -1) 13343 total += 13344 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13345 if (op->value5 == NULL) { 13346 val = xmlXPathVariableLookup(ctxt->context, op->value4); 13347 if (val == NULL) { 13348 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR; 13349 return(0); 13350 } 13351 valuePush(ctxt, val); 13352 } else { 13353 const xmlChar *URI; 13354 13355 URI = xmlXPathNsLookup(ctxt->context, op->value5); 13356 if (URI == NULL) { 13357 xmlGenericError(xmlGenericErrorContext, 13358 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n", 13359 (char *) op->value4, (char *)op->value5); 13360 return (total); 13361 } 13362 val = xmlXPathVariableLookupNS(ctxt->context, 13363 op->value4, URI); 13364 if (val == NULL) { 13365 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR; 13366 return(0); 13367 } 13368 valuePush(ctxt, val); 13369 } 13370 return (total); 13371 } 13372 case XPATH_OP_FUNCTION:{ 13373 xmlXPathFunction func; 13374 const xmlChar *oldFunc, *oldFuncURI; 13375 int i; 13376 13377 if (op->ch1 != -1) 13378 total += 13379 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13380 if (ctxt->valueNr < op->value) { 13381 xmlGenericError(xmlGenericErrorContext, 13382 "xmlXPathCompOpEval: parameter error\n"); 13383 ctxt->error = XPATH_INVALID_OPERAND; 13384 return (total); 13385 } 13386 for (i = 0; i < op->value; i++) 13387 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) { 13388 xmlGenericError(xmlGenericErrorContext, 13389 "xmlXPathCompOpEval: parameter error\n"); 13390 ctxt->error = XPATH_INVALID_OPERAND; 13391 return (total); 13392 } 13393 if (op->cache != NULL) 13394 XML_CAST_FPTR(func) = op->cache; 13395 else { 13396 const xmlChar *URI = NULL; 13397 13398 if (op->value5 == NULL) 13399 func = 13400 xmlXPathFunctionLookup(ctxt->context, 13401 op->value4); 13402 else { 13403 URI = xmlXPathNsLookup(ctxt->context, op->value5); 13404 if (URI == NULL) { 13405 xmlGenericError(xmlGenericErrorContext, 13406 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n", 13407 (char *)op->value4, (char *)op->value5); 13408 return (total); 13409 } 13410 func = xmlXPathFunctionLookupNS(ctxt->context, 13411 op->value4, URI); 13412 } 13413 if (func == NULL) { 13414 xmlGenericError(xmlGenericErrorContext, 13415 "xmlXPathCompOpEval: function %s not found\n", 13416 (char *)op->value4); 13417 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR); 13418 } 13419 op->cache = XML_CAST_FPTR(func); 13420 op->cacheURI = (void *) URI; 13421 } 13422 oldFunc = ctxt->context->function; 13423 oldFuncURI = ctxt->context->functionURI; 13424 ctxt->context->function = op->value4; 13425 ctxt->context->functionURI = op->cacheURI; 13426 func(ctxt, op->value); 13427 ctxt->context->function = oldFunc; 13428 ctxt->context->functionURI = oldFuncURI; 13429 return (total); 13430 } 13431 case XPATH_OP_ARG: 13432 bakd = ctxt->context->doc; 13433 bak = ctxt->context->node; 13434 pp = ctxt->context->proximityPosition; 13435 cs = ctxt->context->contextSize; 13436 if (op->ch1 != -1) 13437 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13438 ctxt->context->contextSize = cs; 13439 ctxt->context->proximityPosition = pp; 13440 ctxt->context->node = bak; 13441 ctxt->context->doc = bakd; 13442 CHECK_ERROR0; 13443 if (op->ch2 != -1) { 13444 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13445 ctxt->context->doc = bakd; 13446 ctxt->context->node = bak; 13447 CHECK_ERROR0; 13448 } 13449 return (total); 13450 case XPATH_OP_PREDICATE: 13451 case XPATH_OP_FILTER:{ 13452 xmlXPathObjectPtr res; 13453 xmlXPathObjectPtr obj, tmp; 13454 xmlNodeSetPtr newset = NULL; 13455 xmlNodeSetPtr oldset; 13456 xmlNodePtr oldnode; 13457 xmlDocPtr oldDoc; 13458 int i; 13459 13460 /* 13461 * Optimization for ()[1] selection i.e. the first elem 13462 */ 13463 if ((op->ch1 != -1) && (op->ch2 != -1) && 13464 #ifdef XP_OPTIMIZED_FILTER_FIRST 13465 /* 13466 * FILTER TODO: Can we assume that the inner processing 13467 * will result in an ordered list if we have an 13468 * XPATH_OP_FILTER? 13469 * What about an additional field or flag on 13470 * xmlXPathObject like @sorted ? This way we wouln'd need 13471 * to assume anything, so it would be more robust and 13472 * easier to optimize. 13473 */ 13474 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */ 13475 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */ 13476 #else 13477 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 13478 #endif 13479 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */ 13480 xmlXPathObjectPtr val; 13481 13482 val = comp->steps[op->ch2].value4; 13483 if ((val != NULL) && (val->type == XPATH_NUMBER) && 13484 (val->floatval == 1.0)) { 13485 xmlNodePtr first = NULL; 13486 13487 total += 13488 xmlXPathCompOpEvalFirst(ctxt, 13489 &comp->steps[op->ch1], 13490 &first); 13491 CHECK_ERROR0; 13492 /* 13493 * The nodeset should be in document order, 13494 * Keep only the first value 13495 */ 13496 if ((ctxt->value != NULL) && 13497 (ctxt->value->type == XPATH_NODESET) && 13498 (ctxt->value->nodesetval != NULL) && 13499 (ctxt->value->nodesetval->nodeNr > 1)) 13500 ctxt->value->nodesetval->nodeNr = 1; 13501 return (total); 13502 } 13503 } 13504 /* 13505 * Optimization for ()[last()] selection i.e. the last elem 13506 */ 13507 if ((op->ch1 != -1) && (op->ch2 != -1) && 13508 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 13509 (comp->steps[op->ch2].op == XPATH_OP_SORT)) { 13510 int f = comp->steps[op->ch2].ch1; 13511 13512 if ((f != -1) && 13513 (comp->steps[f].op == XPATH_OP_FUNCTION) && 13514 (comp->steps[f].value5 == NULL) && 13515 (comp->steps[f].value == 0) && 13516 (comp->steps[f].value4 != NULL) && 13517 (xmlStrEqual 13518 (comp->steps[f].value4, BAD_CAST "last"))) { 13519 xmlNodePtr last = NULL; 13520 13521 total += 13522 xmlXPathCompOpEvalLast(ctxt, 13523 &comp->steps[op->ch1], 13524 &last); 13525 CHECK_ERROR0; 13526 /* 13527 * The nodeset should be in document order, 13528 * Keep only the last value 13529 */ 13530 if ((ctxt->value != NULL) && 13531 (ctxt->value->type == XPATH_NODESET) && 13532 (ctxt->value->nodesetval != NULL) && 13533 (ctxt->value->nodesetval->nodeTab != NULL) && 13534 (ctxt->value->nodesetval->nodeNr > 1)) { 13535 ctxt->value->nodesetval->nodeTab[0] = 13536 ctxt->value->nodesetval->nodeTab[ctxt-> 13537 value-> 13538 nodesetval-> 13539 nodeNr - 13540 1]; 13541 ctxt->value->nodesetval->nodeNr = 1; 13542 } 13543 return (total); 13544 } 13545 } 13546 /* 13547 * Process inner predicates first. 13548 * Example "index[parent::book][1]": 13549 * ... 13550 * PREDICATE <-- we are here "[1]" 13551 * PREDICATE <-- process "[parent::book]" first 13552 * SORT 13553 * COLLECT 'parent' 'name' 'node' book 13554 * NODE 13555 * ELEM Object is a number : 1 13556 */ 13557 if (op->ch1 != -1) 13558 total += 13559 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13560 CHECK_ERROR0; 13561 if (op->ch2 == -1) 13562 return (total); 13563 if (ctxt->value == NULL) 13564 return (total); 13565 13566 oldnode = ctxt->context->node; 13567 13568 #ifdef LIBXML_XPTR_ENABLED 13569 /* 13570 * Hum are we filtering the result of an XPointer expression 13571 */ 13572 if (ctxt->value->type == XPATH_LOCATIONSET) { 13573 xmlLocationSetPtr newlocset = NULL; 13574 xmlLocationSetPtr oldlocset; 13575 13576 /* 13577 * Extract the old locset, and then evaluate the result of the 13578 * expression for all the element in the locset. use it to grow 13579 * up a new locset. 13580 */ 13581 CHECK_TYPE0(XPATH_LOCATIONSET); 13582 obj = valuePop(ctxt); 13583 oldlocset = obj->user; 13584 ctxt->context->node = NULL; 13585 13586 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) { 13587 ctxt->context->contextSize = 0; 13588 ctxt->context->proximityPosition = 0; 13589 if (op->ch2 != -1) 13590 total += 13591 xmlXPathCompOpEval(ctxt, 13592 &comp->steps[op->ch2]); 13593 res = valuePop(ctxt); 13594 if (res != NULL) { 13595 xmlXPathReleaseObject(ctxt->context, res); 13596 } 13597 valuePush(ctxt, obj); 13598 CHECK_ERROR0; 13599 return (total); 13600 } 13601 newlocset = xmlXPtrLocationSetCreate(NULL); 13602 13603 for (i = 0; i < oldlocset->locNr; i++) { 13604 /* 13605 * Run the evaluation with a node list made of a 13606 * single item in the nodelocset. 13607 */ 13608 ctxt->context->node = oldlocset->locTab[i]->user; 13609 ctxt->context->contextSize = oldlocset->locNr; 13610 ctxt->context->proximityPosition = i + 1; 13611 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13612 ctxt->context->node); 13613 valuePush(ctxt, tmp); 13614 13615 if (op->ch2 != -1) 13616 total += 13617 xmlXPathCompOpEval(ctxt, 13618 &comp->steps[op->ch2]); 13619 if (ctxt->error != XPATH_EXPRESSION_OK) { 13620 xmlXPathFreeObject(obj); 13621 return(0); 13622 } 13623 13624 /* 13625 * The result of the evaluation need to be tested to 13626 * decided whether the filter succeeded or not 13627 */ 13628 res = valuePop(ctxt); 13629 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 13630 xmlXPtrLocationSetAdd(newlocset, 13631 xmlXPathObjectCopy 13632 (oldlocset->locTab[i])); 13633 } 13634 13635 /* 13636 * Cleanup 13637 */ 13638 if (res != NULL) { 13639 xmlXPathReleaseObject(ctxt->context, res); 13640 } 13641 if (ctxt->value == tmp) { 13642 res = valuePop(ctxt); 13643 xmlXPathReleaseObject(ctxt->context, res); 13644 } 13645 13646 ctxt->context->node = NULL; 13647 } 13648 13649 /* 13650 * The result is used as the new evaluation locset. 13651 */ 13652 xmlXPathReleaseObject(ctxt->context, obj); 13653 ctxt->context->node = NULL; 13654 ctxt->context->contextSize = -1; 13655 ctxt->context->proximityPosition = -1; 13656 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset)); 13657 ctxt->context->node = oldnode; 13658 return (total); 13659 } 13660 #endif /* LIBXML_XPTR_ENABLED */ 13661 13662 /* 13663 * Extract the old set, and then evaluate the result of the 13664 * expression for all the element in the set. use it to grow 13665 * up a new set. 13666 */ 13667 CHECK_TYPE0(XPATH_NODESET); 13668 obj = valuePop(ctxt); 13669 oldset = obj->nodesetval; 13670 13671 oldnode = ctxt->context->node; 13672 oldDoc = ctxt->context->doc; 13673 ctxt->context->node = NULL; 13674 13675 if ((oldset == NULL) || (oldset->nodeNr == 0)) { 13676 ctxt->context->contextSize = 0; 13677 ctxt->context->proximityPosition = 0; 13678 /* 13679 if (op->ch2 != -1) 13680 total += 13681 xmlXPathCompOpEval(ctxt, 13682 &comp->steps[op->ch2]); 13683 CHECK_ERROR0; 13684 res = valuePop(ctxt); 13685 if (res != NULL) 13686 xmlXPathFreeObject(res); 13687 */ 13688 valuePush(ctxt, obj); 13689 ctxt->context->node = oldnode; 13690 CHECK_ERROR0; 13691 } else { 13692 tmp = NULL; 13693 /* 13694 * Initialize the new set. 13695 * Also set the xpath document in case things like 13696 * key() evaluation are attempted on the predicate 13697 */ 13698 newset = xmlXPathNodeSetCreate(NULL); 13699 /* 13700 * SPEC XPath 1.0: 13701 * "For each node in the node-set to be filtered, the 13702 * PredicateExpr is evaluated with that node as the 13703 * context node, with the number of nodes in the 13704 * node-set as the context size, and with the proximity 13705 * position of the node in the node-set with respect to 13706 * the axis as the context position;" 13707 * @oldset is the node-set" to be filtered. 13708 * 13709 * SPEC XPath 1.0: 13710 * "only predicates change the context position and 13711 * context size (see [2.4 Predicates])." 13712 * Example: 13713 * node-set context pos 13714 * nA 1 13715 * nB 2 13716 * nC 3 13717 * After applying predicate [position() > 1] : 13718 * node-set context pos 13719 * nB 1 13720 * nC 2 13721 * 13722 * removed the first node in the node-set, then 13723 * the context position of the 13724 */ 13725 for (i = 0; i < oldset->nodeNr; i++) { 13726 /* 13727 * Run the evaluation with a node list made of 13728 * a single item in the nodeset. 13729 */ 13730 ctxt->context->node = oldset->nodeTab[i]; 13731 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) && 13732 (oldset->nodeTab[i]->doc != NULL)) 13733 ctxt->context->doc = oldset->nodeTab[i]->doc; 13734 if (tmp == NULL) { 13735 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13736 ctxt->context->node); 13737 } else { 13738 xmlXPathNodeSetAddUnique(tmp->nodesetval, 13739 ctxt->context->node); 13740 } 13741 valuePush(ctxt, tmp); 13742 ctxt->context->contextSize = oldset->nodeNr; 13743 ctxt->context->proximityPosition = i + 1; 13744 /* 13745 * Evaluate the predicate against the context node. 13746 * Can/should we optimize position() predicates 13747 * here (e.g. "[1]")? 13748 */ 13749 if (op->ch2 != -1) 13750 total += 13751 xmlXPathCompOpEval(ctxt, 13752 &comp->steps[op->ch2]); 13753 if (ctxt->error != XPATH_EXPRESSION_OK) { 13754 xmlXPathFreeNodeSet(newset); 13755 xmlXPathFreeObject(obj); 13756 return(0); 13757 } 13758 13759 /* 13760 * The result of the evaluation needs to be tested to 13761 * decide whether the filter succeeded or not 13762 */ 13763 /* 13764 * OPTIMIZE TODO: Can we use 13765 * xmlXPathNodeSetAdd*Unique()* instead? 13766 */ 13767 res = valuePop(ctxt); 13768 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 13769 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]); 13770 } 13771 13772 /* 13773 * Cleanup 13774 */ 13775 if (res != NULL) { 13776 xmlXPathReleaseObject(ctxt->context, res); 13777 } 13778 if (ctxt->value == tmp) { 13779 valuePop(ctxt); 13780 xmlXPathNodeSetClear(tmp->nodesetval, 1); 13781 /* 13782 * Don't free the temporary nodeset 13783 * in order to avoid massive recreation inside this 13784 * loop. 13785 */ 13786 } else 13787 tmp = NULL; 13788 ctxt->context->node = NULL; 13789 } 13790 if (tmp != NULL) 13791 xmlXPathReleaseObject(ctxt->context, tmp); 13792 /* 13793 * The result is used as the new evaluation set. 13794 */ 13795 xmlXPathReleaseObject(ctxt->context, obj); 13796 ctxt->context->node = NULL; 13797 ctxt->context->contextSize = -1; 13798 ctxt->context->proximityPosition = -1; 13799 /* may want to move this past the '}' later */ 13800 ctxt->context->doc = oldDoc; 13801 valuePush(ctxt, 13802 xmlXPathCacheWrapNodeSet(ctxt->context, newset)); 13803 } 13804 ctxt->context->node = oldnode; 13805 return (total); 13806 } 13807 case XPATH_OP_SORT: 13808 if (op->ch1 != -1) 13809 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13810 CHECK_ERROR0; 13811 if ((ctxt->value != NULL) && 13812 (ctxt->value->type == XPATH_NODESET) && 13813 (ctxt->value->nodesetval != NULL) && 13814 (ctxt->value->nodesetval->nodeNr > 1)) 13815 { 13816 xmlXPathNodeSetSort(ctxt->value->nodesetval); 13817 } 13818 return (total); 13819 #ifdef LIBXML_XPTR_ENABLED 13820 case XPATH_OP_RANGETO:{ 13821 xmlXPathObjectPtr range; 13822 xmlXPathObjectPtr res, obj; 13823 xmlXPathObjectPtr tmp; 13824 xmlLocationSetPtr newlocset = NULL; 13825 xmlLocationSetPtr oldlocset; 13826 xmlNodeSetPtr oldset; 13827 int i, j; 13828 13829 if (op->ch1 != -1) 13830 total += 13831 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13832 if (op->ch2 == -1) 13833 return (total); 13834 13835 if (ctxt->value->type == XPATH_LOCATIONSET) { 13836 /* 13837 * Extract the old locset, and then evaluate the result of the 13838 * expression for all the element in the locset. use it to grow 13839 * up a new locset. 13840 */ 13841 CHECK_TYPE0(XPATH_LOCATIONSET); 13842 obj = valuePop(ctxt); 13843 oldlocset = obj->user; 13844 13845 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) { 13846 ctxt->context->node = NULL; 13847 ctxt->context->contextSize = 0; 13848 ctxt->context->proximityPosition = 0; 13849 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]); 13850 res = valuePop(ctxt); 13851 if (res != NULL) { 13852 xmlXPathReleaseObject(ctxt->context, res); 13853 } 13854 valuePush(ctxt, obj); 13855 CHECK_ERROR0; 13856 return (total); 13857 } 13858 newlocset = xmlXPtrLocationSetCreate(NULL); 13859 13860 for (i = 0; i < oldlocset->locNr; i++) { 13861 /* 13862 * Run the evaluation with a node list made of a 13863 * single item in the nodelocset. 13864 */ 13865 ctxt->context->node = oldlocset->locTab[i]->user; 13866 ctxt->context->contextSize = oldlocset->locNr; 13867 ctxt->context->proximityPosition = i + 1; 13868 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13869 ctxt->context->node); 13870 valuePush(ctxt, tmp); 13871 13872 if (op->ch2 != -1) 13873 total += 13874 xmlXPathCompOpEval(ctxt, 13875 &comp->steps[op->ch2]); 13876 if (ctxt->error != XPATH_EXPRESSION_OK) { 13877 xmlXPathFreeObject(obj); 13878 return(0); 13879 } 13880 13881 res = valuePop(ctxt); 13882 if (res->type == XPATH_LOCATIONSET) { 13883 xmlLocationSetPtr rloc = 13884 (xmlLocationSetPtr)res->user; 13885 for (j=0; j<rloc->locNr; j++) { 13886 range = xmlXPtrNewRange( 13887 oldlocset->locTab[i]->user, 13888 oldlocset->locTab[i]->index, 13889 rloc->locTab[j]->user2, 13890 rloc->locTab[j]->index2); 13891 if (range != NULL) { 13892 xmlXPtrLocationSetAdd(newlocset, range); 13893 } 13894 } 13895 } else { 13896 range = xmlXPtrNewRangeNodeObject( 13897 (xmlNodePtr)oldlocset->locTab[i]->user, res); 13898 if (range != NULL) { 13899 xmlXPtrLocationSetAdd(newlocset,range); 13900 } 13901 } 13902 13903 /* 13904 * Cleanup 13905 */ 13906 if (res != NULL) { 13907 xmlXPathReleaseObject(ctxt->context, res); 13908 } 13909 if (ctxt->value == tmp) { 13910 res = valuePop(ctxt); 13911 xmlXPathReleaseObject(ctxt->context, res); 13912 } 13913 13914 ctxt->context->node = NULL; 13915 } 13916 } else { /* Not a location set */ 13917 CHECK_TYPE0(XPATH_NODESET); 13918 obj = valuePop(ctxt); 13919 oldset = obj->nodesetval; 13920 ctxt->context->node = NULL; 13921 13922 newlocset = xmlXPtrLocationSetCreate(NULL); 13923 13924 if (oldset != NULL) { 13925 for (i = 0; i < oldset->nodeNr; i++) { 13926 /* 13927 * Run the evaluation with a node list made of a single item 13928 * in the nodeset. 13929 */ 13930 ctxt->context->node = oldset->nodeTab[i]; 13931 /* 13932 * OPTIMIZE TODO: Avoid recreation for every iteration. 13933 */ 13934 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13935 ctxt->context->node); 13936 valuePush(ctxt, tmp); 13937 13938 if (op->ch2 != -1) 13939 total += 13940 xmlXPathCompOpEval(ctxt, 13941 &comp->steps[op->ch2]); 13942 if (ctxt->error != XPATH_EXPRESSION_OK) { 13943 xmlXPathFreeObject(obj); 13944 return(0); 13945 } 13946 13947 res = valuePop(ctxt); 13948 range = 13949 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i], 13950 res); 13951 if (range != NULL) { 13952 xmlXPtrLocationSetAdd(newlocset, range); 13953 } 13954 13955 /* 13956 * Cleanup 13957 */ 13958 if (res != NULL) { 13959 xmlXPathReleaseObject(ctxt->context, res); 13960 } 13961 if (ctxt->value == tmp) { 13962 res = valuePop(ctxt); 13963 xmlXPathReleaseObject(ctxt->context, res); 13964 } 13965 13966 ctxt->context->node = NULL; 13967 } 13968 } 13969 } 13970 13971 /* 13972 * The result is used as the new evaluation set. 13973 */ 13974 xmlXPathReleaseObject(ctxt->context, obj); 13975 ctxt->context->node = NULL; 13976 ctxt->context->contextSize = -1; 13977 ctxt->context->proximityPosition = -1; 13978 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset)); 13979 return (total); 13980 } 13981 #endif /* LIBXML_XPTR_ENABLED */ 13982 } 13983 xmlGenericError(xmlGenericErrorContext, 13984 "XPath: unknown precompiled operation %d\n", op->op); 13985 return (total); 13986 } 13987 13996 static int 13997 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt, 13998 xmlXPathStepOpPtr op, 13999 int isPredicate) 14000 { 14001 xmlXPathObjectPtr resObj = NULL; 14002 14003 start: 14004 /* comp = ctxt->comp; */ 14005 switch (op->op) { 14006 case XPATH_OP_END: 14007 return (0); 14008 case XPATH_OP_VALUE: 14009 resObj = (xmlXPathObjectPtr) op->value4; 14010 if (isPredicate) 14011 return(xmlXPathEvaluatePredicateResult(ctxt, resObj)); 14012 return(xmlXPathCastToBoolean(resObj)); 14013 case XPATH_OP_SORT: 14014 /* 14015 * We don't need sorting for boolean results. Skip this one. 14016 */ 14017 if (op->ch1 != -1) { 14018 op = &ctxt->comp->steps[op->ch1]; 14019 goto start; 14020 } 14021 return(0); 14022 case XPATH_OP_COLLECT: 14023 if (op->ch1 == -1) 14024 return(0); 14025 14026 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]); 14027 if (ctxt->error != XPATH_EXPRESSION_OK) 14028 return(-1); 14029 14030 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1); 14031 if (ctxt->error != XPATH_EXPRESSION_OK) 14032 return(-1); 14033 14034 resObj = valuePop(ctxt); 14035 if (resObj == NULL) 14036 return(-1); 14037 break; 14038 default: 14039 /* 14040 * Fallback to call xmlXPathCompOpEval(). 14041 */ 14042 xmlXPathCompOpEval(ctxt, op); 14043 if (ctxt->error != XPATH_EXPRESSION_OK) 14044 return(-1); 14045 14046 resObj = valuePop(ctxt); 14047 if (resObj == NULL) 14048 return(-1); 14049 break; 14050 } 14051 14052 if (resObj) { 14053 int res; 14054 14055 if (resObj->type == XPATH_BOOLEAN) { 14056 res = resObj->boolval; 14057 } else if (isPredicate) { 14058 /* 14059 * For predicates a result of type "number" is handled 14060 * differently: 14061 * SPEC XPath 1.0: 14062 * "If the result is a number, the result will be converted 14063 * to true if the number is equal to the context position 14064 * and will be converted to false otherwise;" 14065 */ 14066 res = xmlXPathEvaluatePredicateResult(ctxt, resObj); 14067 } else { 14068 res = xmlXPathCastToBoolean(resObj); 14069 } 14070 xmlXPathReleaseObject(ctxt->context, resObj); 14071 return(res); 14072 } 14073 14074 return(0); 14075 } 14076 14077 #ifdef XPATH_STREAMING 14078 14084 static int 14085 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp, 14086 xmlXPathObjectPtr *resultSeq, int toBool) 14087 { 14088 int max_depth, min_depth; 14089 int from_root; 14090 int ret, depth; 14091 int eval_all_nodes; 14092 xmlNodePtr cur = NULL, limit = NULL; 14093 xmlStreamCtxtPtr patstream = NULL; 14094 14095 int nb_nodes = 0; 14096 14097 if ((ctxt == NULL) || (comp == NULL)) 14098 return(-1); 14099 max_depth = xmlPatternMaxDepth(comp); 14100 if (max_depth == -1) 14101 return(-1); 14102 if (max_depth == -2) 14103 max_depth = 10000; 14104 min_depth = xmlPatternMinDepth(comp); 14105 if (min_depth == -1) 14106 return(-1); 14107 from_root = xmlPatternFromRoot(comp); 14108 if (from_root < 0) 14109 return(-1); 14110 #if 0 14111 printf("stream eval: depth %d from root %d\n", max_depth, from_root); 14112 #endif 14113 14114 if (! toBool) { 14115 if (resultSeq == NULL) 14116 return(-1); 14117 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL); 14118 if (*resultSeq == NULL) 14119 return(-1); 14120 } 14121 14122 /* 14123 * handle the special cases of "/" amd "." being matched 14124 */ 14125 if (min_depth == 0) { 14126 if (from_root) { 14127 /* Select "/" */ 14128 if (toBool) 14129 return(1); 14130 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, 14131 (xmlNodePtr) ctxt->doc); 14132 } else { 14133 /* Select "self::node()" */ 14134 if (toBool) 14135 return(1); 14136 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node); 14137 } 14138 } 14139 if (max_depth == 0) { 14140 return(0); 14141 } 14142 14143 if (from_root) { 14144 cur = (xmlNodePtr)ctxt->doc; 14145 } else if (ctxt->node != NULL) { 14146 switch (ctxt->node->type) { 14147 case XML_ELEMENT_NODE: 14148 case XML_DOCUMENT_NODE: 14149 case XML_DOCUMENT_FRAG_NODE: 14150 case XML_HTML_DOCUMENT_NODE: 14151 #ifdef LIBXML_DOCB_ENABLED 14152 case XML_DOCB_DOCUMENT_NODE: 14153 #endif 14154 cur = ctxt->node; 14155 break; 14156 case XML_ATTRIBUTE_NODE: 14157 case XML_TEXT_NODE: 14158 case XML_CDATA_SECTION_NODE: 14159 case XML_ENTITY_REF_NODE: 14160 case XML_ENTITY_NODE: 14161 case XML_PI_NODE: 14162 case XML_COMMENT_NODE: 14163 case XML_NOTATION_NODE: 14164 case XML_DTD_NODE: 14165 case XML_DOCUMENT_TYPE_NODE: 14166 case XML_ELEMENT_DECL: 14167 case XML_ATTRIBUTE_DECL: 14168 case XML_ENTITY_DECL: 14169 case XML_NAMESPACE_DECL: 14170 case XML_XINCLUDE_START: 14171 case XML_XINCLUDE_END: 14172 break; 14173 } 14174 limit = cur; 14175 } 14176 if (cur == NULL) { 14177 return(0); 14178 } 14179 14180 patstream = xmlPatternGetStreamCtxt(comp); 14181 if (patstream == NULL) { 14182 /* 14183 * QUESTION TODO: Is this an error? 14184 */ 14185 return(0); 14186 } 14187 14188 eval_all_nodes = xmlStreamWantsAnyNode(patstream); 14189 14190 if (from_root) { 14191 ret = xmlStreamPush(patstream, NULL, NULL); 14192 if (ret < 0) { 14193 } else if (ret == 1) { 14194 if (toBool) 14195 goto return_1; 14196 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur); 14197 } 14198 } 14199 depth = 0; 14200 goto scan_children; 14201 next_node: 14202 do { 14203 nb_nodes++; 14204 14205 switch (cur->type) { 14206 case XML_ELEMENT_NODE: 14207 case XML_TEXT_NODE: 14208 case XML_CDATA_SECTION_NODE: 14209 case XML_COMMENT_NODE: 14210 case XML_PI_NODE: 14211 if (cur->type == XML_ELEMENT_NODE) { 14212 ret = xmlStreamPush(patstream, cur->name, 14213 (cur->ns ? cur->ns->href : NULL)); 14214 } else if (eval_all_nodes) 14215 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type); 14216 else 14217 break; 14218 14219 if (ret < 0) { 14220 /* NOP. */ 14221 } else if (ret == 1) { 14222 if (toBool) 14223 goto return_1; 14224 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur); 14225 } 14226 if ((cur->children == NULL) || (depth >= max_depth)) { 14227 ret = xmlStreamPop(patstream); 14228 while (cur->next != NULL) { 14229 cur = cur->next; 14230 if ((cur->type != XML_ENTITY_DECL) && 14231 (cur->type != XML_DTD_NODE)) 14232 goto next_node; 14233 } 14234 } 14235 default: 14236 break; 14237 } 14238 14239 scan_children: 14240 if ((cur->children != NULL) && (depth < max_depth)) { 14241 /* 14242 * Do not descend on entities declarations 14243 */ 14244 if (cur->children->type != XML_ENTITY_DECL) { 14245 cur = cur->children; 14246 depth++; 14247 /* 14248 * Skip DTDs 14249 */ 14250 if (cur->type != XML_DTD_NODE) 14251 continue; 14252 } 14253 } 14254 14255 if (cur == limit) 14256 break; 14257 14258 while (cur->next != NULL) { 14259 cur = cur->next; 14260 if ((cur->type != XML_ENTITY_DECL) && 14261 (cur->type != XML_DTD_NODE)) 14262 goto next_node; 14263 } 14264 14265 do { 14266 cur = cur->parent; 14267 depth--; 14268 if ((cur == NULL) || (cur == limit)) 14269 goto done; 14270 if (cur->type == XML_ELEMENT_NODE) { 14271 ret = xmlStreamPop(patstream); 14272 } else if ((eval_all_nodes) && 14273 ((cur->type == XML_TEXT_NODE) || 14274 (cur->type == XML_CDATA_SECTION_NODE) || 14275 (cur->type == XML_COMMENT_NODE) || 14276 (cur->type == XML_PI_NODE))) 14277 { 14278 ret = xmlStreamPop(patstream); 14279 } 14280 if (cur->next != NULL) { 14281 cur = cur->next; 14282 break; 14283 } 14284 } while (cur != NULL); 14285 14286 } while ((cur != NULL) && (depth >= 0)); 14287 14288 done: 14289 14290 #if 0 14291 printf("stream eval: checked %d nodes selected %d\n", 14292 nb_nodes, retObj->nodesetval->nodeNr); 14293 #endif 14294 14295 if (patstream) 14296 xmlFreeStreamCtxt(patstream); 14297 return(0); 14298 14299 return_1: 14300 if (patstream) 14301 xmlFreeStreamCtxt(patstream); 14302 return(1); 14303 } 14304 #endif /* XPATH_STREAMING */ 14305 14313 static int 14314 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool) 14315 { 14316 xmlXPathCompExprPtr comp; 14317 14318 if ((ctxt == NULL) || (ctxt->comp == NULL)) 14319 return(-1); 14320 14321 if (ctxt->valueTab == NULL) { 14322 /* Allocate the value stack */ 14323 ctxt->valueTab = (xmlXPathObjectPtr *) 14324 xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); 14325 if (ctxt->valueTab == NULL) { 14326 xmlXPathPErrMemory(ctxt, "creating evaluation context\n"); 14327 xmlFree(ctxt); 14328 } 14329 ctxt->valueNr = 0; 14330 ctxt->valueMax = 10; 14331 ctxt->value = NULL; 14332 } 14333 #ifdef XPATH_STREAMING 14334 if (ctxt->comp->stream) { 14335 int res; 14336 14337 if (toBool) { 14338 /* 14339 * Evaluation to boolean result. 14340 */ 14341 res = xmlXPathRunStreamEval(ctxt->context, 14342 ctxt->comp->stream, NULL, 1); 14343 if (res != -1) 14344 return(res); 14345 } else { 14346 xmlXPathObjectPtr resObj = NULL; 14347 14348 /* 14349 * Evaluation to a sequence. 14350 */ 14351 res = xmlXPathRunStreamEval(ctxt->context, 14352 ctxt->comp->stream, &resObj, 0); 14353 14354 if ((res != -1) && (resObj != NULL)) { 14355 valuePush(ctxt, resObj); 14356 return(0); 14357 } 14358 if (resObj != NULL) 14359 xmlXPathReleaseObject(ctxt->context, resObj); 14360 } 14361 /* 14362 * QUESTION TODO: This falls back to normal XPath evaluation 14363 * if res == -1. Is this intended? 14364 */ 14365 } 14366 #endif 14367 comp = ctxt->comp; 14368 if (comp->last < 0) { 14369 xmlGenericError(xmlGenericErrorContext, 14370 "xmlXPathRunEval: last is less than zero\n"); 14371 return(-1); 14372 } 14373 if (toBool) 14374 return(xmlXPathCompOpEvalToBoolean(ctxt, 14375 &comp->steps[comp->last], 0)); 14376 else 14377 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]); 14378 14379 return(0); 14380 } 14381 14382 /************************************************************************ 14383 * * 14384 * Public interfaces * 14385 * * 14386 ************************************************************************/ 14387 14404 int 14405 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) { 14406 if ((ctxt == NULL) || (res == NULL)) return(0); 14407 switch (res->type) { 14408 case XPATH_BOOLEAN: 14409 return(res->boolval); 14410 case XPATH_NUMBER: 14411 return(res->floatval == ctxt->proximityPosition); 14412 case XPATH_NODESET: 14413 case XPATH_XSLT_TREE: 14414 if (res->nodesetval == NULL) 14415 return(0); 14416 return(res->nodesetval->nodeNr != 0); 14417 case XPATH_STRING: 14418 return((res->stringval != NULL) && 14419 (xmlStrlen(res->stringval) != 0)); 14420 default: 14421 STRANGE 14422 } 14423 return(0); 14424 } 14425 14442 int 14443 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt, 14444 xmlXPathObjectPtr res) { 14445 if ((ctxt == NULL) || (res == NULL)) return(0); 14446 switch (res->type) { 14447 case XPATH_BOOLEAN: 14448 return(res->boolval); 14449 case XPATH_NUMBER: 14450 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200)) 14451 return((res->floatval == ctxt->context->proximityPosition) && 14452 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/ 14453 #else 14454 return(res->floatval == ctxt->context->proximityPosition); 14455 #endif 14456 case XPATH_NODESET: 14457 case XPATH_XSLT_TREE: 14458 if (res->nodesetval == NULL) 14459 return(0); 14460 return(res->nodesetval->nodeNr != 0); 14461 case XPATH_STRING: 14462 return((res->stringval != NULL) && (res->stringval[0] != 0)); 14463 #ifdef LIBXML_XPTR_ENABLED 14464 case XPATH_LOCATIONSET:{ 14465 xmlLocationSetPtr ptr = res->user; 14466 if (ptr == NULL) 14467 return(0); 14468 return (ptr->locNr != 0); 14469 } 14470 #endif 14471 default: 14472 STRANGE 14473 } 14474 return(0); 14475 } 14476 14477 #ifdef XPATH_STREAMING 14478 14487 static xmlXPathCompExprPtr 14488 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { 14489 /* 14490 * Optimization: use streaming patterns when the XPath expression can 14491 * be compiled to a stream lookup 14492 */ 14493 xmlPatternPtr stream; 14494 xmlXPathCompExprPtr comp; 14495 xmlDictPtr dict = NULL; 14496 const xmlChar **namespaces = NULL; 14497 xmlNsPtr ns; 14498 int i, j; 14499 14500 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) && 14501 (!xmlStrchr(str, '@'))) { 14502 const xmlChar *tmp; 14503 14504 /* 14505 * We don't try to handle expressions using the verbose axis 14506 * specifiers ("::"), just the simplied form at this point. 14507 * Additionally, if there is no list of namespaces available and 14508 * there's a ":" in the expression, indicating a prefixed QName, 14509 * then we won't try to compile either. xmlPatterncompile() needs 14510 * to have a list of namespaces at compilation time in order to 14511 * compile prefixed name tests. 14512 */ 14513 tmp = xmlStrchr(str, ':'); 14514 if ((tmp != NULL) && 14515 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':'))) 14516 return(NULL); 14517 14518 if (ctxt != NULL) { 14519 dict = ctxt->dict; 14520 if (ctxt->nsNr > 0) { 14521 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*)); 14522 if (namespaces == NULL) { 14523 xmlXPathErrMemory(ctxt, "allocating namespaces array\n"); 14524 return(NULL); 14525 } 14526 for (i = 0, j = 0; (j < ctxt->nsNr); j++) { 14527 ns = ctxt->namespaces[j]; 14528 namespaces[i++] = ns->href; 14529 namespaces[i++] = ns->prefix; 14530 } 14531 namespaces[i++] = NULL; 14532 namespaces[i] = NULL; 14533 } 14534 } 14535 14536 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, 14537 &namespaces[0]); 14538 if (namespaces != NULL) { 14539 xmlFree((xmlChar **)namespaces); 14540 } 14541 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) { 14542 comp = xmlXPathNewCompExpr(); 14543 if (comp == NULL) { 14544 xmlXPathErrMemory(ctxt, "allocating streamable expression\n"); 14545 return(NULL); 14546 } 14547 comp->stream = stream; 14548 comp->dict = dict; 14549 if (comp->dict) 14550 xmlDictReference(comp->dict); 14551 return(comp); 14552 } 14553 xmlFreePattern(stream); 14554 } 14555 return(NULL); 14556 } 14557 #endif /* XPATH_STREAMING */ 14558 14559 static int 14560 xmlXPathCanRewriteDosExpression(xmlChar *expr) 14561 { 14562 if (expr == NULL) 14563 return(0); 14564 do { 14565 if ((*expr == '/') && (*(++expr) == '/')) 14566 return(1); 14567 } while (*expr++); 14568 return(0); 14569 } 14570 static void 14571 xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op) 14572 { 14573 /* 14574 * Try to rewrite "descendant-or-self::node()/foo" to an optimized 14575 * internal representation. 14576 */ 14577 if (op->ch1 != -1) { 14578 if ((op->op == XPATH_OP_COLLECT /* 11 */) && 14579 ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) && 14580 ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) && 14581 ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */)) 14582 { 14583 /* 14584 * This is a "child::foo" 14585 */ 14586 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1]; 14587 14588 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) && 14589 (prevop->ch1 != -1) && 14590 ((xmlXPathAxisVal) prevop->value == 14591 AXIS_DESCENDANT_OR_SELF) && 14592 (prevop->ch2 == -1) && 14593 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) && 14594 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) && 14595 (comp->steps[prevop->ch1].op == XPATH_OP_ROOT)) 14596 { 14597 /* 14598 * This is a "/descendant-or-self::node()" without predicates. 14599 * Eliminate it. 14600 */ 14601 op->ch1 = prevop->ch1; 14602 op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM; 14603 } 14604 } 14605 if (op->ch1 != -1) 14606 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]); 14607 } 14608 if (op->ch2 != -1) 14609 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]); 14610 } 14611 14622 xmlXPathCompExprPtr 14623 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { 14624 xmlXPathParserContextPtr pctxt; 14625 xmlXPathCompExprPtr comp; 14626 14627 #ifdef XPATH_STREAMING 14628 comp = xmlXPathTryStreamCompile(ctxt, str); 14629 if (comp != NULL) 14630 return(comp); 14631 #endif 14632 14633 xmlXPathInit(); 14634 14635 pctxt = xmlXPathNewParserContext(str, ctxt); 14636 if (pctxt == NULL) 14637 return NULL; 14638 xmlXPathCompileExpr(pctxt, 1); 14639 14640 if( pctxt->error != XPATH_EXPRESSION_OK ) 14641 { 14642 xmlXPathFreeParserContext(pctxt); 14643 return(NULL); 14644 } 14645 14646 if (*pctxt->cur != 0) { 14647 /* 14648 * aleksey: in some cases this line prints *second* error message 14649 * (see bug #78858) and probably this should be fixed. 14650 * However, we are not sure that all error messages are printed 14651 * out in other places. It's not critical so we leave it as-is for now 14652 */ 14653 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR); 14654 comp = NULL; 14655 } else { 14656 comp = pctxt->comp; 14657 pctxt->comp = NULL; 14658 } 14659 xmlXPathFreeParserContext(pctxt); 14660 14661 if (comp != NULL) { 14662 comp->expr = xmlStrdup(str); 14663 #ifdef DEBUG_EVAL_COUNTS 14664 comp->string = xmlStrdup(str); 14665 comp->nb = 0; 14666 #endif 14667 if ((comp->expr != NULL) && 14668 (comp->nbStep > 2) && 14669 (comp->last >= 0) && 14670 (xmlXPathCanRewriteDosExpression(comp->expr) == 1)) 14671 { 14672 xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]); 14673 } 14674 } 14675 return(comp); 14676 } 14677 14687 xmlXPathCompExprPtr 14688 xmlXPathCompile(const xmlChar *str) { 14689 return(xmlXPathCtxtCompile(NULL, str)); 14690 } 14691 14705 static int 14706 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp, 14707 xmlXPathContextPtr ctxt, 14708 xmlXPathObjectPtr *resObj, 14709 int toBool) 14710 { 14711 xmlXPathParserContextPtr pctxt; 14712 #ifndef LIBXML_THREAD_ENABLED 14713 static int reentance = 0; 14714 #endif 14715 int res; 14716 14717 CHECK_CTXT_NEG(ctxt) 14718 14719 if (comp == NULL) 14720 return(-1); 14721 xmlXPathInit(); 14722 14723 #ifndef LIBXML_THREAD_ENABLED 14724 reentance++; 14725 if (reentance > 1) 14726 xmlXPathDisableOptimizer = 1; 14727 #endif 14728 14729 #ifdef DEBUG_EVAL_COUNTS 14730 comp->nb++; 14731 if ((comp->string != NULL) && (comp->nb > 100)) { 14732 fprintf(stderr, "100 x %s\n", comp->string); 14733 comp->nb = 0; 14734 } 14735 #endif 14736 pctxt = xmlXPathCompParserContext(comp, ctxt); 14737 res = xmlXPathRunEval(pctxt, toBool); 14738 14739 if (resObj) { 14740 if (pctxt->value == NULL) { 14741 xmlGenericError(xmlGenericErrorContext, 14742 "xmlXPathCompiledEval: evaluation failed\n"); 14743 *resObj = NULL; 14744 } else { 14745 *resObj = valuePop(pctxt); 14746 } 14747 } 14748 14749 /* 14750 * Pop all remaining objects from the stack. 14751 */ 14752 if (pctxt->valueNr > 0) { 14753 xmlXPathObjectPtr tmp; 14754 int stack = 0; 14755 14756 do { 14757 tmp = valuePop(pctxt); 14758 if (tmp != NULL) { 14759 stack++; 14760 xmlXPathReleaseObject(ctxt, tmp); 14761 } 14762 } while (tmp != NULL); 14763 if ((stack != 0) && 14764 ((toBool) || ((resObj) && (*resObj)))) 14765 { 14766 xmlGenericError(xmlGenericErrorContext, 14767 "xmlXPathCompiledEval: %d objects left on the stack.\n", 14768 stack); 14769 } 14770 } 14771 14772 if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) { 14773 xmlXPathFreeObject(*resObj); 14774 *resObj = NULL; 14775 } 14776 pctxt->comp = NULL; 14777 xmlXPathFreeParserContext(pctxt); 14778 #ifndef LIBXML_THREAD_ENABLED 14779 reentance--; 14780 #endif 14781 14782 return(res); 14783 } 14784 14795 xmlXPathObjectPtr 14796 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) 14797 { 14798 xmlXPathObjectPtr res = NULL; 14799 14800 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0); 14801 return(res); 14802 } 14803 14815 int 14816 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp, 14817 xmlXPathContextPtr ctxt) 14818 { 14819 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1)); 14820 } 14821 14829 void 14830 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) { 14831 #ifdef XPATH_STREAMING 14832 xmlXPathCompExprPtr comp; 14833 #endif 14834 14835 if (ctxt == NULL) return; 14836 14837 #ifdef XPATH_STREAMING 14838 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base); 14839 if (comp != NULL) { 14840 if (ctxt->comp != NULL) 14841 xmlXPathFreeCompExpr(ctxt->comp); 14842 ctxt->comp = comp; 14843 if (ctxt->cur != NULL) 14844 while (*ctxt->cur != 0) ctxt->cur++; 14845 } else 14846 #endif 14847 { 14848 xmlXPathCompileExpr(ctxt, 1); 14849 /* 14850 * In this scenario the expression string will sit in ctxt->base. 14851 */ 14852 if ((ctxt->error == XPATH_EXPRESSION_OK) && 14853 (ctxt->comp != NULL) && 14854 (ctxt->base != NULL) && 14855 (ctxt->comp->nbStep > 2) && 14856 (ctxt->comp->last >= 0) && 14857 (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1)) 14858 { 14859 xmlXPathRewriteDOSExpression(ctxt->comp, 14860 &ctxt->comp->steps[ctxt->comp->last]); 14861 } 14862 } 14863 CHECK_ERROR; 14864 xmlXPathRunEval(ctxt, 0); 14865 } 14866 14877 xmlXPathObjectPtr 14878 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) { 14879 xmlXPathParserContextPtr ctxt; 14880 xmlXPathObjectPtr res, tmp, init = NULL; 14881 int stack = 0; 14882 14883 CHECK_CTXT(ctx) 14884 14885 xmlXPathInit(); 14886 14887 ctxt = xmlXPathNewParserContext(str, ctx); 14888 if (ctxt == NULL) 14889 return NULL; 14890 xmlXPathEvalExpr(ctxt); 14891 14892 if (ctxt->value == NULL) { 14893 xmlGenericError(xmlGenericErrorContext, 14894 "xmlXPathEval: evaluation failed\n"); 14895 res = NULL; 14896 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL) 14897 #ifdef XPATH_STREAMING 14898 && (ctxt->comp->stream == NULL) 14899 #endif 14900 ) { 14901 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR); 14902 res = NULL; 14903 } else { 14904 res = valuePop(ctxt); 14905 } 14906 14907 do { 14908 tmp = valuePop(ctxt); 14909 if (tmp != NULL) { 14910 if (tmp != init) 14911 stack++; 14912 xmlXPathReleaseObject(ctx, tmp); 14913 } 14914 } while (tmp != NULL); 14915 if ((stack != 0) && (res != NULL)) { 14916 xmlGenericError(xmlGenericErrorContext, 14917 "xmlXPathEval: %d object left on the stack\n", 14918 stack); 14919 } 14920 if (ctxt->error != XPATH_EXPRESSION_OK) { 14921 xmlXPathFreeObject(res); 14922 res = NULL; 14923 } 14924 14925 xmlXPathFreeParserContext(ctxt); 14926 return(res); 14927 } 14928 14939 xmlXPathObjectPtr 14940 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) { 14941 xmlXPathParserContextPtr pctxt; 14942 xmlXPathObjectPtr res, tmp; 14943 int stack = 0; 14944 14945 CHECK_CTXT(ctxt) 14946 14947 xmlXPathInit(); 14948 14949 pctxt = xmlXPathNewParserContext(str, ctxt); 14950 if (pctxt == NULL) 14951 return NULL; 14952 xmlXPathEvalExpr(pctxt); 14953 14954 if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) { 14955 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR); 14956 res = NULL; 14957 } else { 14958 res = valuePop(pctxt); 14959 } 14960 do { 14961 tmp = valuePop(pctxt); 14962 if (tmp != NULL) { 14963 xmlXPathReleaseObject(ctxt, tmp); 14964 stack++; 14965 } 14966 } while (tmp != NULL); 14967 if ((stack != 0) && (res != NULL)) { 14968 xmlGenericError(xmlGenericErrorContext, 14969 "xmlXPathEvalExpression: %d object left on the stack\n", 14970 stack); 14971 } 14972 xmlXPathFreeParserContext(pctxt); 14973 return(res); 14974 } 14975 14976 /************************************************************************ 14977 * * 14978 * Extra functions not pertaining to the XPath spec * 14979 * * 14980 ************************************************************************/ 15029 static void 15030 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) { 15031 xmlXPathObjectPtr str; 15032 int escape_reserved; 15033 xmlBufferPtr target; 15034 xmlChar *cptr; 15035 xmlChar escape[4]; 15036 15037 CHECK_ARITY(2); 15038 15039 escape_reserved = xmlXPathPopBoolean(ctxt); 15040 15041 CAST_TO_STRING; 15042 str = valuePop(ctxt); 15043 15044 target = xmlBufferCreate(); 15045 15046 escape[0] = '%'; 15047 escape[3] = 0; 15048 15049 if (target) { 15050 for (cptr = str->stringval; *cptr; cptr++) { 15051 if ((*cptr >= 'A' && *cptr <= 'Z') || 15052 (*cptr >= 'a' && *cptr <= 'z') || 15053 (*cptr >= '0' && *cptr <= '9') || 15054 *cptr == '-' || *cptr == '_' || *cptr == '.' || 15055 *cptr == '!' || *cptr == '~' || *cptr == '*' || 15056 *cptr == '\''|| *cptr == '(' || *cptr == ')' || 15057 (*cptr == '%' && 15058 ((cptr[1] >= 'A' && cptr[1] <= 'F') || 15059 (cptr[1] >= 'a' && cptr[1] <= 'f') || 15060 (cptr[1] >= '0' && cptr[1] <= '9')) && 15061 ((cptr[2] >= 'A' && cptr[2] <= 'F') || 15062 (cptr[2] >= 'a' && cptr[2] <= 'f') || 15063 (cptr[2] >= '0' && cptr[2] <= '9'))) || 15064 (!escape_reserved && 15065 (*cptr == ';' || *cptr == '/' || *cptr == '?' || 15066 *cptr == ':' || *cptr == '@' || *cptr == '&' || 15067 *cptr == '=' || *cptr == '+' || *cptr == '$' || 15068 *cptr == ','))) { 15069 xmlBufferAdd(target, cptr, 1); 15070 } else { 15071 if ((*cptr >> 4) < 10) 15072 escape[1] = '0' + (*cptr >> 4); 15073 else 15074 escape[1] = 'A' - 10 + (*cptr >> 4); 15075 if ((*cptr & 0xF) < 10) 15076 escape[2] = '0' + (*cptr & 0xF); 15077 else 15078 escape[2] = 'A' - 10 + (*cptr & 0xF); 15079 15080 xmlBufferAdd(target, &escape[0], 3); 15081 } 15082 } 15083 } 15084 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 15085 xmlBufferContent(target))); 15086 xmlBufferFree(target); 15087 xmlXPathReleaseObject(ctxt->context, str); 15088 } 15089 15096 void 15097 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt) 15098 { 15099 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean", 15100 xmlXPathBooleanFunction); 15101 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling", 15102 xmlXPathCeilingFunction); 15103 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count", 15104 xmlXPathCountFunction); 15105 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat", 15106 xmlXPathConcatFunction); 15107 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains", 15108 xmlXPathContainsFunction); 15109 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id", 15110 xmlXPathIdFunction); 15111 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false", 15112 xmlXPathFalseFunction); 15113 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor", 15114 xmlXPathFloorFunction); 15115 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last", 15116 xmlXPathLastFunction); 15117 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang", 15118 xmlXPathLangFunction); 15119 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name", 15120 xmlXPathLocalNameFunction); 15121 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not", 15122 xmlXPathNotFunction); 15123 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name", 15124 xmlXPathNameFunction); 15125 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri", 15126 xmlXPathNamespaceURIFunction); 15127 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space", 15128 xmlXPathNormalizeFunction); 15129 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number", 15130 xmlXPathNumberFunction); 15131 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position", 15132 xmlXPathPositionFunction); 15133 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round", 15134 xmlXPathRoundFunction); 15135 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string", 15136 xmlXPathStringFunction); 15137 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length", 15138 xmlXPathStringLengthFunction); 15139 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with", 15140 xmlXPathStartsWithFunction); 15141 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring", 15142 xmlXPathSubstringFunction); 15143 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before", 15144 xmlXPathSubstringBeforeFunction); 15145 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after", 15146 xmlXPathSubstringAfterFunction); 15147 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum", 15148 xmlXPathSumFunction); 15149 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true", 15150 xmlXPathTrueFunction); 15151 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate", 15152 xmlXPathTranslateFunction); 15153 15154 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri", 15155 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions", 15156 xmlXPathEscapeUriFunction); 15157 } 15158 15159 #endif /* LIBXML_XPATH_ENABLED */ 15160 #define bottom_xpath 15161 #include "elfgcchack.h" Generated on Fri May 25 2012 04:33:37 for ReactOS by
1.7.6.1
|