xpath.c revision 47881284aeaeeb93b3444419adeffc9e11ed1093
1/* 2 * xpath.c: XML Path Language implementation 3 * XPath is a language for addressing parts of an XML document, 4 * designed to be used by both XSLT and XPointer 5 *f 6 * Reference: W3C Recommendation 16 November 1999 7 * http://www.w3.org/TR/1999/REC-xpath-19991116 8 * Public reference: 9 * http://www.w3.org/TR/xpath 10 * 11 * See Copyright for the status of this software 12 * 13 * Author: daniel@veillard.com 14 * 15 */ 16 17#define IN_LIBXML 18#include "libxml.h" 19 20#include <string.h> 21 22#ifdef HAVE_SYS_TYPES_H 23#include <sys/types.h> 24#endif 25#ifdef HAVE_MATH_H 26#include <math.h> 27#endif 28#ifdef HAVE_FLOAT_H 29#include <float.h> 30#endif 31#ifdef HAVE_CTYPE_H 32#include <ctype.h> 33#endif 34#ifdef HAVE_SIGNAL_H 35#include <signal.h> 36#endif 37 38#include <libxml/xmlmemory.h> 39#include <libxml/tree.h> 40#include <libxml/valid.h> 41#include <libxml/xpath.h> 42#include <libxml/xpathInternals.h> 43#include <libxml/parserInternals.h> 44#include <libxml/hash.h> 45#ifdef LIBXML_XPTR_ENABLED 46#include <libxml/xpointer.h> 47#endif 48#ifdef LIBXML_DEBUG_ENABLED 49#include <libxml/debugXML.h> 50#endif 51#include <libxml/xmlerror.h> 52#include <libxml/threads.h> 53#include <libxml/globals.h> 54#ifdef LIBXML_PATTERN_ENABLED 55#include <libxml/pattern.h> 56#endif 57 58#include "buf.h" 59 60#ifdef LIBXML_PATTERN_ENABLED 61#define XPATH_STREAMING 62#endif 63 64#define TODO \ 65 xmlGenericError(xmlGenericErrorContext, \ 66 "Unimplemented block at %s:%d\n", \ 67 __FILE__, __LINE__); 68 69/** 70 * WITH_TIM_SORT: 71 * 72 * Use the Timsort algorithm provided in timsort.h to sort 73 * nodeset as this is a great improvement over the old Shell sort 74 * used in xmlXPathNodeSetSort() 75 */ 76#define WITH_TIM_SORT 77 78/* 79* XP_OPTIMIZED_NON_ELEM_COMPARISON: 80* If defined, this will use xmlXPathCmpNodesExt() instead of 81* xmlXPathCmpNodes(). The new function is optimized comparison of 82* non-element nodes; actually it will speed up comparison only if 83* xmlXPathOrderDocElems() was called in order to index the elements of 84* a tree in document order; Libxslt does such an indexing, thus it will 85* benefit from this optimization. 86*/ 87#define XP_OPTIMIZED_NON_ELEM_COMPARISON 88 89/* 90* XP_OPTIMIZED_FILTER_FIRST: 91* If defined, this will optimize expressions like "key('foo', 'val')[b][1]" 92* in a way, that it stop evaluation at the first node. 93*/ 94#define XP_OPTIMIZED_FILTER_FIRST 95 96/* 97* XP_DEBUG_OBJ_USAGE: 98* Internal flag to enable tracking of how much XPath objects have been 99* created. 100*/ 101/* #define XP_DEBUG_OBJ_USAGE */ 102 103/* 104 * XPATH_MAX_STEPS: 105 * when compiling an XPath expression we arbitrary limit the maximum 106 * number of step operation in the compiled expression. 1000000 is 107 * an insanely large value which should never be reached under normal 108 * circumstances 109 */ 110#define XPATH_MAX_STEPS 1000000 111 112/* 113 * XPATH_MAX_STACK_DEPTH: 114 * when evaluating an XPath expression we arbitrary limit the maximum 115 * number of object allowed to be pushed on the stack. 1000000 is 116 * an insanely large value which should never be reached under normal 117 * circumstances 118 */ 119#define XPATH_MAX_STACK_DEPTH 1000000 120 121/* 122 * XPATH_MAX_NODESET_LENGTH: 123 * when evaluating an XPath expression nodesets are created and we 124 * arbitrary limit the maximum length of those node set. 10000000 is 125 * an insanely large value which should never be reached under normal 126 * circumstances, one would first need to construct an in memory tree 127 * with more than 10 millions nodes. 128 */ 129#define XPATH_MAX_NODESET_LENGTH 10000000 130 131/* 132 * TODO: 133 * There are a few spots where some tests are done which depend upon ascii 134 * data. These should be enhanced for full UTF8 support (see particularly 135 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT) 136 */ 137 138/* 139 * Wrapper for the Timsort argorithm from timsort.h 140 */ 141#ifdef WITH_TIM_SORT 142#define SORT_NAME libxml_domnode 143#define SORT_TYPE xmlNodePtr 144/** 145 * wrap_cmp: 146 * @x: a node 147 * @y: another node 148 * 149 * Comparison function for the Timsort implementation 150 * 151 * Returns -2 in case of error -1 if first point < second point, 0 if 152 * it's the same node, +1 otherwise 153 */ 154static 155int wrap_cmp( xmlNodePtr x, xmlNodePtr y ); 156#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 157 static int xmlXPathCmpNodesExt(xmlNodePtr, xmlNodePtr); 158 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y ) 159 { 160 int res = xmlXPathCmpNodesExt(x, y); 161 return res == -2 ? res : -res; 162 } 163#else 164 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y ) 165 { 166 int res = xmlXPathCmpNodes(x, y); 167 return res == -2 ? res : -res; 168 } 169#endif 170#define SORT_CMP(x, y) (wrap_cmp(x, y)) 171#include "timsort.h" 172#endif /* WITH_TIM_SORT */ 173 174#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) 175 176/************************************************************************ 177 * * 178 * Floating point stuff * 179 * * 180 ************************************************************************/ 181 182#ifndef TRIO_REPLACE_STDIO 183#define TRIO_PUBLIC static 184#endif 185#include "trionan.c" 186 187/* 188 * The lack of portability of this section of the libc is annoying ! 189 */ 190double xmlXPathNAN = 0; 191double xmlXPathPINF = 1; 192double xmlXPathNINF = -1; 193static double xmlXPathNZERO = 0; /* not exported from headers */ 194static int xmlXPathInitialized = 0; 195 196/** 197 * xmlXPathInit: 198 * 199 * Initialize the XPath environment 200 */ 201void 202xmlXPathInit(void) { 203 if (xmlXPathInitialized) return; 204 205 xmlXPathPINF = trio_pinf(); 206 xmlXPathNINF = trio_ninf(); 207 xmlXPathNAN = trio_nan(); 208 xmlXPathNZERO = trio_nzero(); 209 210 xmlXPathInitialized = 1; 211} 212 213/** 214 * xmlXPathIsNaN: 215 * @val: a double value 216 * 217 * Provides a portable isnan() function to detect whether a double 218 * is a NotaNumber. Based on trio code 219 * http://sourceforge.net/projects/ctrio/ 220 * 221 * Returns 1 if the value is a NaN, 0 otherwise 222 */ 223int 224xmlXPathIsNaN(double val) { 225 return(trio_isnan(val)); 226} 227 228/** 229 * xmlXPathIsInf: 230 * @val: a double value 231 * 232 * Provides a portable isinf() function to detect whether a double 233 * is a +Infinite or -Infinite. Based on trio code 234 * http://sourceforge.net/projects/ctrio/ 235 * 236 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise 237 */ 238int 239xmlXPathIsInf(double val) { 240 return(trio_isinf(val)); 241} 242 243#endif /* SCHEMAS or XPATH */ 244#ifdef LIBXML_XPATH_ENABLED 245/** 246 * xmlXPathGetSign: 247 * @val: a double value 248 * 249 * Provides a portable function to detect the sign of a double 250 * Modified from trio code 251 * http://sourceforge.net/projects/ctrio/ 252 * 253 * Returns 1 if the value is Negative, 0 if positive 254 */ 255static int 256xmlXPathGetSign(double val) { 257 return(trio_signbit(val)); 258} 259 260 261/* 262 * TODO: when compatibility allows remove all "fake node libxslt" strings 263 * the test should just be name[0] = ' ' 264 */ 265#ifdef DEBUG_XPATH_EXPRESSION 266#define DEBUG_STEP 267#define DEBUG_EXPR 268#define DEBUG_EVAL_COUNTS 269#endif 270 271static xmlNs xmlXPathXMLNamespaceStruct = { 272 NULL, 273 XML_NAMESPACE_DECL, 274 XML_XML_NAMESPACE, 275 BAD_CAST "xml", 276 NULL, 277 NULL 278}; 279static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct; 280#ifndef LIBXML_THREAD_ENABLED 281/* 282 * Optimizer is disabled only when threaded apps are detected while 283 * the library ain't compiled for thread safety. 284 */ 285static int xmlXPathDisableOptimizer = 0; 286#endif 287 288/************************************************************************ 289 * * 290 * Error handling routines * 291 * * 292 ************************************************************************/ 293 294/** 295 * XP_ERRORNULL: 296 * @X: the error code 297 * 298 * Macro to raise an XPath error and return NULL. 299 */ 300#define XP_ERRORNULL(X) \ 301 { xmlXPathErr(ctxt, X); return(NULL); } 302 303/* 304 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError 305 */ 306static const char *xmlXPathErrorMessages[] = { 307 "Ok\n", 308 "Number encoding\n", 309 "Unfinished literal\n", 310 "Start of literal\n", 311 "Expected $ for variable reference\n", 312 "Undefined variable\n", 313 "Invalid predicate\n", 314 "Invalid expression\n", 315 "Missing closing curly brace\n", 316 "Unregistered function\n", 317 "Invalid operand\n", 318 "Invalid type\n", 319 "Invalid number of arguments\n", 320 "Invalid context size\n", 321 "Invalid context position\n", 322 "Memory allocation error\n", 323 "Syntax error\n", 324 "Resource error\n", 325 "Sub resource error\n", 326 "Undefined namespace prefix\n", 327 "Encoding error\n", 328 "Char out of XML range\n", 329 "Invalid or incomplete context\n", 330 "Stack usage errror\n", 331 "Forbidden variable\n", 332 "?? Unknown error ??\n" /* Must be last in the list! */ 333}; 334#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \ 335 sizeof(xmlXPathErrorMessages[0])) - 1) 336/** 337 * xmlXPathErrMemory: 338 * @ctxt: an XPath context 339 * @extra: extra informations 340 * 341 * Handle a redefinition of attribute error 342 */ 343static void 344xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra) 345{ 346 if (ctxt != NULL) { 347 if (extra) { 348 xmlChar buf[200]; 349 350 xmlStrPrintf(buf, 200, 351 BAD_CAST "Memory allocation failed : %s\n", 352 extra); 353 ctxt->lastError.message = (char *) xmlStrdup(buf); 354 } else { 355 ctxt->lastError.message = (char *) 356 xmlStrdup(BAD_CAST "Memory allocation failed\n"); 357 } 358 ctxt->lastError.domain = XML_FROM_XPATH; 359 ctxt->lastError.code = XML_ERR_NO_MEMORY; 360 if (ctxt->error != NULL) 361 ctxt->error(ctxt->userData, &ctxt->lastError); 362 } else { 363 if (extra) 364 __xmlRaiseError(NULL, NULL, NULL, 365 NULL, NULL, XML_FROM_XPATH, 366 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, 367 extra, NULL, NULL, 0, 0, 368 "Memory allocation failed : %s\n", extra); 369 else 370 __xmlRaiseError(NULL, NULL, NULL, 371 NULL, NULL, XML_FROM_XPATH, 372 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, 373 NULL, NULL, NULL, 0, 0, 374 "Memory allocation failed\n"); 375 } 376} 377 378/** 379 * xmlXPathPErrMemory: 380 * @ctxt: an XPath parser context 381 * @extra: extra informations 382 * 383 * Handle a redefinition of attribute error 384 */ 385static void 386xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra) 387{ 388 if (ctxt == NULL) 389 xmlXPathErrMemory(NULL, extra); 390 else { 391 ctxt->error = XPATH_MEMORY_ERROR; 392 xmlXPathErrMemory(ctxt->context, extra); 393 } 394} 395 396/** 397 * xmlXPathErr: 398 * @ctxt: a XPath parser context 399 * @error: the error code 400 * 401 * Handle an XPath error 402 */ 403void 404xmlXPathErr(xmlXPathParserContextPtr ctxt, int error) 405{ 406 if ((error < 0) || (error > MAXERRNO)) 407 error = MAXERRNO; 408 if (ctxt == NULL) { 409 __xmlRaiseError(NULL, NULL, NULL, 410 NULL, NULL, XML_FROM_XPATH, 411 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, 412 XML_ERR_ERROR, NULL, 0, 413 NULL, NULL, NULL, 0, 0, 414 "%s", xmlXPathErrorMessages[error]); 415 return; 416 } 417 ctxt->error = error; 418 if (ctxt->context == NULL) { 419 __xmlRaiseError(NULL, NULL, NULL, 420 NULL, NULL, XML_FROM_XPATH, 421 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, 422 XML_ERR_ERROR, NULL, 0, 423 (const char *) ctxt->base, NULL, NULL, 424 ctxt->cur - ctxt->base, 0, 425 "%s", xmlXPathErrorMessages[error]); 426 return; 427 } 428 429 /* cleanup current last error */ 430 xmlResetError(&ctxt->context->lastError); 431 432 ctxt->context->lastError.domain = XML_FROM_XPATH; 433 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK - 434 XPATH_EXPRESSION_OK; 435 ctxt->context->lastError.level = XML_ERR_ERROR; 436 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base); 437 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base; 438 ctxt->context->lastError.node = ctxt->context->debugNode; 439 if (ctxt->context->error != NULL) { 440 ctxt->context->error(ctxt->context->userData, 441 &ctxt->context->lastError); 442 } else { 443 __xmlRaiseError(NULL, NULL, NULL, 444 NULL, ctxt->context->debugNode, XML_FROM_XPATH, 445 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, 446 XML_ERR_ERROR, NULL, 0, 447 (const char *) ctxt->base, NULL, NULL, 448 ctxt->cur - ctxt->base, 0, 449 "%s", xmlXPathErrorMessages[error]); 450 } 451 452} 453 454/** 455 * xmlXPatherror: 456 * @ctxt: the XPath Parser context 457 * @file: the file name 458 * @line: the line number 459 * @no: the error number 460 * 461 * Formats an error message. 462 */ 463void 464xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED, 465 int line ATTRIBUTE_UNUSED, int no) { 466 xmlXPathErr(ctxt, no); 467} 468 469/************************************************************************ 470 * * 471 * Utilities * 472 * * 473 ************************************************************************/ 474 475/** 476 * xsltPointerList: 477 * 478 * Pointer-list for various purposes. 479 */ 480typedef struct _xmlPointerList xmlPointerList; 481typedef xmlPointerList *xmlPointerListPtr; 482struct _xmlPointerList { 483 void **items; 484 int number; 485 int size; 486}; 487/* 488* TODO: Since such a list-handling is used in xmlschemas.c and libxslt 489* and here, we should make the functions public. 490*/ 491static int 492xmlPointerListAddSize(xmlPointerListPtr list, 493 void *item, 494 int initialSize) 495{ 496 if (list->items == NULL) { 497 if (initialSize <= 0) 498 initialSize = 1; 499 list->items = (void **) xmlMalloc(initialSize * sizeof(void *)); 500 if (list->items == NULL) { 501 xmlXPathErrMemory(NULL, 502 "xmlPointerListCreate: allocating item\n"); 503 return(-1); 504 } 505 list->number = 0; 506 list->size = initialSize; 507 } else if (list->size <= list->number) { 508 if (list->size > 50000000) { 509 xmlXPathErrMemory(NULL, 510 "xmlPointerListAddSize: re-allocating item\n"); 511 return(-1); 512 } 513 list->size *= 2; 514 list->items = (void **) xmlRealloc(list->items, 515 list->size * sizeof(void *)); 516 if (list->items == NULL) { 517 xmlXPathErrMemory(NULL, 518 "xmlPointerListAddSize: re-allocating item\n"); 519 list->size = 0; 520 return(-1); 521 } 522 } 523 list->items[list->number++] = item; 524 return(0); 525} 526 527/** 528 * xsltPointerListCreate: 529 * 530 * Creates an xsltPointerList structure. 531 * 532 * Returns a xsltPointerList structure or NULL in case of an error. 533 */ 534static xmlPointerListPtr 535xmlPointerListCreate(int initialSize) 536{ 537 xmlPointerListPtr ret; 538 539 ret = xmlMalloc(sizeof(xmlPointerList)); 540 if (ret == NULL) { 541 xmlXPathErrMemory(NULL, 542 "xmlPointerListCreate: allocating item\n"); 543 return (NULL); 544 } 545 memset(ret, 0, sizeof(xmlPointerList)); 546 if (initialSize > 0) { 547 xmlPointerListAddSize(ret, NULL, initialSize); 548 ret->number = 0; 549 } 550 return (ret); 551} 552 553/** 554 * xsltPointerListFree: 555 * 556 * Frees the xsltPointerList structure. This does not free 557 * the content of the list. 558 */ 559static void 560xmlPointerListFree(xmlPointerListPtr list) 561{ 562 if (list == NULL) 563 return; 564 if (list->items != NULL) 565 xmlFree(list->items); 566 xmlFree(list); 567} 568 569/************************************************************************ 570 * * 571 * Parser Types * 572 * * 573 ************************************************************************/ 574 575/* 576 * Types are private: 577 */ 578 579typedef enum { 580 XPATH_OP_END=0, 581 XPATH_OP_AND, 582 XPATH_OP_OR, 583 XPATH_OP_EQUAL, 584 XPATH_OP_CMP, 585 XPATH_OP_PLUS, 586 XPATH_OP_MULT, 587 XPATH_OP_UNION, 588 XPATH_OP_ROOT, 589 XPATH_OP_NODE, 590 XPATH_OP_RESET, /* 10 */ 591 XPATH_OP_COLLECT, 592 XPATH_OP_VALUE, /* 12 */ 593 XPATH_OP_VARIABLE, 594 XPATH_OP_FUNCTION, 595 XPATH_OP_ARG, 596 XPATH_OP_PREDICATE, 597 XPATH_OP_FILTER, /* 17 */ 598 XPATH_OP_SORT /* 18 */ 599#ifdef LIBXML_XPTR_ENABLED 600 ,XPATH_OP_RANGETO 601#endif 602} xmlXPathOp; 603 604typedef enum { 605 AXIS_ANCESTOR = 1, 606 AXIS_ANCESTOR_OR_SELF, 607 AXIS_ATTRIBUTE, 608 AXIS_CHILD, 609 AXIS_DESCENDANT, 610 AXIS_DESCENDANT_OR_SELF, 611 AXIS_FOLLOWING, 612 AXIS_FOLLOWING_SIBLING, 613 AXIS_NAMESPACE, 614 AXIS_PARENT, 615 AXIS_PRECEDING, 616 AXIS_PRECEDING_SIBLING, 617 AXIS_SELF 618} xmlXPathAxisVal; 619 620typedef enum { 621 NODE_TEST_NONE = 0, 622 NODE_TEST_TYPE = 1, 623 NODE_TEST_PI = 2, 624 NODE_TEST_ALL = 3, 625 NODE_TEST_NS = 4, 626 NODE_TEST_NAME = 5 627} xmlXPathTestVal; 628 629typedef enum { 630 NODE_TYPE_NODE = 0, 631 NODE_TYPE_COMMENT = XML_COMMENT_NODE, 632 NODE_TYPE_TEXT = XML_TEXT_NODE, 633 NODE_TYPE_PI = XML_PI_NODE 634} xmlXPathTypeVal; 635 636typedef struct _xmlXPathStepOp xmlXPathStepOp; 637typedef xmlXPathStepOp *xmlXPathStepOpPtr; 638struct _xmlXPathStepOp { 639 xmlXPathOp op; /* The identifier of the operation */ 640 int ch1; /* First child */ 641 int ch2; /* Second child */ 642 int value; 643 int value2; 644 int value3; 645 void *value4; 646 void *value5; 647 void *cache; 648 void *cacheURI; 649}; 650 651struct _xmlXPathCompExpr { 652 int nbStep; /* Number of steps in this expression */ 653 int maxStep; /* Maximum number of steps allocated */ 654 xmlXPathStepOp *steps; /* ops for computation of this expression */ 655 int last; /* index of last step in expression */ 656 xmlChar *expr; /* the expression being computed */ 657 xmlDictPtr dict; /* the dictionnary to use if any */ 658#ifdef DEBUG_EVAL_COUNTS 659 int nb; 660 xmlChar *string; 661#endif 662#ifdef XPATH_STREAMING 663 xmlPatternPtr stream; 664#endif 665}; 666 667/************************************************************************ 668 * * 669 * Forward declarations * 670 * * 671 ************************************************************************/ 672static void 673xmlXPathFreeValueTree(xmlNodeSetPtr obj); 674static void 675xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj); 676static int 677xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt, 678 xmlXPathStepOpPtr op, xmlNodePtr *first); 679static int 680xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt, 681 xmlXPathStepOpPtr op, 682 int isPredicate); 683 684/************************************************************************ 685 * * 686 * Parser Type functions * 687 * * 688 ************************************************************************/ 689 690/** 691 * xmlXPathNewCompExpr: 692 * 693 * Create a new Xpath component 694 * 695 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error 696 */ 697static xmlXPathCompExprPtr 698xmlXPathNewCompExpr(void) { 699 xmlXPathCompExprPtr cur; 700 701 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr)); 702 if (cur == NULL) { 703 xmlXPathErrMemory(NULL, "allocating component\n"); 704 return(NULL); 705 } 706 memset(cur, 0, sizeof(xmlXPathCompExpr)); 707 cur->maxStep = 10; 708 cur->nbStep = 0; 709 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep * 710 sizeof(xmlXPathStepOp)); 711 if (cur->steps == NULL) { 712 xmlXPathErrMemory(NULL, "allocating steps\n"); 713 xmlFree(cur); 714 return(NULL); 715 } 716 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp)); 717 cur->last = -1; 718#ifdef DEBUG_EVAL_COUNTS 719 cur->nb = 0; 720#endif 721 return(cur); 722} 723 724/** 725 * xmlXPathFreeCompExpr: 726 * @comp: an XPATH comp 727 * 728 * Free up the memory allocated by @comp 729 */ 730void 731xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp) 732{ 733 xmlXPathStepOpPtr op; 734 int i; 735 736 if (comp == NULL) 737 return; 738 if (comp->dict == NULL) { 739 for (i = 0; i < comp->nbStep; i++) { 740 op = &comp->steps[i]; 741 if (op->value4 != NULL) { 742 if (op->op == XPATH_OP_VALUE) 743 xmlXPathFreeObject(op->value4); 744 else 745 xmlFree(op->value4); 746 } 747 if (op->value5 != NULL) 748 xmlFree(op->value5); 749 } 750 } else { 751 for (i = 0; i < comp->nbStep; i++) { 752 op = &comp->steps[i]; 753 if (op->value4 != NULL) { 754 if (op->op == XPATH_OP_VALUE) 755 xmlXPathFreeObject(op->value4); 756 } 757 } 758 xmlDictFree(comp->dict); 759 } 760 if (comp->steps != NULL) { 761 xmlFree(comp->steps); 762 } 763#ifdef DEBUG_EVAL_COUNTS 764 if (comp->string != NULL) { 765 xmlFree(comp->string); 766 } 767#endif 768#ifdef XPATH_STREAMING 769 if (comp->stream != NULL) { 770 xmlFreePatternList(comp->stream); 771 } 772#endif 773 if (comp->expr != NULL) { 774 xmlFree(comp->expr); 775 } 776 777 xmlFree(comp); 778} 779 780/** 781 * xmlXPathCompExprAdd: 782 * @comp: the compiled expression 783 * @ch1: first child index 784 * @ch2: second child index 785 * @op: an op 786 * @value: the first int value 787 * @value2: the second int value 788 * @value3: the third int value 789 * @value4: the first string value 790 * @value5: the second string value 791 * 792 * Add a step to an XPath Compiled Expression 793 * 794 * Returns -1 in case of failure, the index otherwise 795 */ 796static int 797xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2, 798 xmlXPathOp op, int value, 799 int value2, int value3, void *value4, void *value5) { 800 if (comp->nbStep >= comp->maxStep) { 801 xmlXPathStepOp *real; 802 803 if (comp->maxStep >= XPATH_MAX_STEPS) { 804 xmlXPathErrMemory(NULL, "adding step\n"); 805 return(-1); 806 } 807 comp->maxStep *= 2; 808 real = (xmlXPathStepOp *) xmlRealloc(comp->steps, 809 comp->maxStep * sizeof(xmlXPathStepOp)); 810 if (real == NULL) { 811 comp->maxStep /= 2; 812 xmlXPathErrMemory(NULL, "adding step\n"); 813 return(-1); 814 } 815 comp->steps = real; 816 } 817 comp->last = comp->nbStep; 818 comp->steps[comp->nbStep].ch1 = ch1; 819 comp->steps[comp->nbStep].ch2 = ch2; 820 comp->steps[comp->nbStep].op = op; 821 comp->steps[comp->nbStep].value = value; 822 comp->steps[comp->nbStep].value2 = value2; 823 comp->steps[comp->nbStep].value3 = value3; 824 if ((comp->dict != NULL) && 825 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) || 826 (op == XPATH_OP_COLLECT))) { 827 if (value4 != NULL) { 828 comp->steps[comp->nbStep].value4 = (xmlChar *) 829 (void *)xmlDictLookup(comp->dict, value4, -1); 830 xmlFree(value4); 831 } else 832 comp->steps[comp->nbStep].value4 = NULL; 833 if (value5 != NULL) { 834 comp->steps[comp->nbStep].value5 = (xmlChar *) 835 (void *)xmlDictLookup(comp->dict, value5, -1); 836 xmlFree(value5); 837 } else 838 comp->steps[comp->nbStep].value5 = NULL; 839 } else { 840 comp->steps[comp->nbStep].value4 = value4; 841 comp->steps[comp->nbStep].value5 = value5; 842 } 843 comp->steps[comp->nbStep].cache = NULL; 844 return(comp->nbStep++); 845} 846 847/** 848 * xmlXPathCompSwap: 849 * @comp: the compiled expression 850 * @op: operation index 851 * 852 * Swaps 2 operations in the compiled expression 853 */ 854static void 855xmlXPathCompSwap(xmlXPathStepOpPtr op) { 856 int tmp; 857 858#ifndef LIBXML_THREAD_ENABLED 859 /* 860 * Since this manipulates possibly shared variables, this is 861 * disabled if one detects that the library is used in a multithreaded 862 * application 863 */ 864 if (xmlXPathDisableOptimizer) 865 return; 866#endif 867 868 tmp = op->ch1; 869 op->ch1 = op->ch2; 870 op->ch2 = tmp; 871} 872 873#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \ 874 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \ 875 (op), (val), (val2), (val3), (val4), (val5)) 876#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \ 877 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \ 878 (op), (val), (val2), (val3), (val4), (val5)) 879 880#define PUSH_LEAVE_EXPR(op, val, val2) \ 881xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL) 882 883#define PUSH_UNARY_EXPR(op, ch, val, val2) \ 884xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL) 885 886#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \ 887xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \ 888 (val), (val2), 0 ,NULL ,NULL) 889 890/************************************************************************ 891 * * 892 * XPath object cache structures * 893 * * 894 ************************************************************************/ 895 896/* #define XP_DEFAULT_CACHE_ON */ 897 898#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL)) 899 900typedef struct _xmlXPathContextCache xmlXPathContextCache; 901typedef xmlXPathContextCache *xmlXPathContextCachePtr; 902struct _xmlXPathContextCache { 903 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */ 904 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */ 905 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */ 906 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */ 907 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */ 908 int maxNodeset; 909 int maxString; 910 int maxBoolean; 911 int maxNumber; 912 int maxMisc; 913#ifdef XP_DEBUG_OBJ_USAGE 914 int dbgCachedAll; 915 int dbgCachedNodeset; 916 int dbgCachedString; 917 int dbgCachedBool; 918 int dbgCachedNumber; 919 int dbgCachedPoint; 920 int dbgCachedRange; 921 int dbgCachedLocset; 922 int dbgCachedUsers; 923 int dbgCachedXSLTTree; 924 int dbgCachedUndefined; 925 926 927 int dbgReusedAll; 928 int dbgReusedNodeset; 929 int dbgReusedString; 930 int dbgReusedBool; 931 int dbgReusedNumber; 932 int dbgReusedPoint; 933 int dbgReusedRange; 934 int dbgReusedLocset; 935 int dbgReusedUsers; 936 int dbgReusedXSLTTree; 937 int dbgReusedUndefined; 938 939#endif 940}; 941 942/************************************************************************ 943 * * 944 * Debugging related functions * 945 * * 946 ************************************************************************/ 947 948#define STRANGE \ 949 xmlGenericError(xmlGenericErrorContext, \ 950 "Internal error at %s:%d\n", \ 951 __FILE__, __LINE__); 952 953#ifdef LIBXML_DEBUG_ENABLED 954static void 955xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) { 956 int i; 957 char shift[100]; 958 959 for (i = 0;((i < depth) && (i < 25));i++) 960 shift[2 * i] = shift[2 * i + 1] = ' '; 961 shift[2 * i] = shift[2 * i + 1] = 0; 962 if (cur == NULL) { 963 fprintf(output, "%s", shift); 964 fprintf(output, "Node is NULL !\n"); 965 return; 966 967 } 968 969 if ((cur->type == XML_DOCUMENT_NODE) || 970 (cur->type == XML_HTML_DOCUMENT_NODE)) { 971 fprintf(output, "%s", shift); 972 fprintf(output, " /\n"); 973 } else if (cur->type == XML_ATTRIBUTE_NODE) 974 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth); 975 else 976 xmlDebugDumpOneNode(output, cur, depth); 977} 978static void 979xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) { 980 xmlNodePtr tmp; 981 int i; 982 char shift[100]; 983 984 for (i = 0;((i < depth) && (i < 25));i++) 985 shift[2 * i] = shift[2 * i + 1] = ' '; 986 shift[2 * i] = shift[2 * i + 1] = 0; 987 if (cur == NULL) { 988 fprintf(output, "%s", shift); 989 fprintf(output, "Node is NULL !\n"); 990 return; 991 992 } 993 994 while (cur != NULL) { 995 tmp = cur; 996 cur = cur->next; 997 xmlDebugDumpOneNode(output, tmp, depth); 998 } 999} 1000 1001static void 1002xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) { 1003 int i; 1004 char shift[100]; 1005 1006 for (i = 0;((i < depth) && (i < 25));i++) 1007 shift[2 * i] = shift[2 * i + 1] = ' '; 1008 shift[2 * i] = shift[2 * i + 1] = 0; 1009 1010 if (cur == NULL) { 1011 fprintf(output, "%s", shift); 1012 fprintf(output, "NodeSet is NULL !\n"); 1013 return; 1014 1015 } 1016 1017 if (cur != NULL) { 1018 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr); 1019 for (i = 0;i < cur->nodeNr;i++) { 1020 fprintf(output, "%s", shift); 1021 fprintf(output, "%d", i + 1); 1022 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1); 1023 } 1024 } 1025} 1026 1027static void 1028xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) { 1029 int i; 1030 char shift[100]; 1031 1032 for (i = 0;((i < depth) && (i < 25));i++) 1033 shift[2 * i] = shift[2 * i + 1] = ' '; 1034 shift[2 * i] = shift[2 * i + 1] = 0; 1035 1036 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) { 1037 fprintf(output, "%s", shift); 1038 fprintf(output, "Value Tree is NULL !\n"); 1039 return; 1040 1041 } 1042 1043 fprintf(output, "%s", shift); 1044 fprintf(output, "%d", i + 1); 1045 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1); 1046} 1047#if defined(LIBXML_XPTR_ENABLED) 1048static void 1049xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) { 1050 int i; 1051 char shift[100]; 1052 1053 for (i = 0;((i < depth) && (i < 25));i++) 1054 shift[2 * i] = shift[2 * i + 1] = ' '; 1055 shift[2 * i] = shift[2 * i + 1] = 0; 1056 1057 if (cur == NULL) { 1058 fprintf(output, "%s", shift); 1059 fprintf(output, "LocationSet is NULL !\n"); 1060 return; 1061 1062 } 1063 1064 for (i = 0;i < cur->locNr;i++) { 1065 fprintf(output, "%s", shift); 1066 fprintf(output, "%d : ", i + 1); 1067 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1); 1068 } 1069} 1070#endif /* LIBXML_XPTR_ENABLED */ 1071 1072/** 1073 * xmlXPathDebugDumpObject: 1074 * @output: the FILE * to dump the output 1075 * @cur: the object to inspect 1076 * @depth: indentation level 1077 * 1078 * Dump the content of the object for debugging purposes 1079 */ 1080void 1081xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) { 1082 int i; 1083 char shift[100]; 1084 1085 if (output == NULL) return; 1086 1087 for (i = 0;((i < depth) && (i < 25));i++) 1088 shift[2 * i] = shift[2 * i + 1] = ' '; 1089 shift[2 * i] = shift[2 * i + 1] = 0; 1090 1091 1092 fprintf(output, "%s", shift); 1093 1094 if (cur == NULL) { 1095 fprintf(output, "Object is empty (NULL)\n"); 1096 return; 1097 } 1098 switch(cur->type) { 1099 case XPATH_UNDEFINED: 1100 fprintf(output, "Object is uninitialized\n"); 1101 break; 1102 case XPATH_NODESET: 1103 fprintf(output, "Object is a Node Set :\n"); 1104 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth); 1105 break; 1106 case XPATH_XSLT_TREE: 1107 fprintf(output, "Object is an XSLT value tree :\n"); 1108 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth); 1109 break; 1110 case XPATH_BOOLEAN: 1111 fprintf(output, "Object is a Boolean : "); 1112 if (cur->boolval) fprintf(output, "true\n"); 1113 else fprintf(output, "false\n"); 1114 break; 1115 case XPATH_NUMBER: 1116 switch (xmlXPathIsInf(cur->floatval)) { 1117 case 1: 1118 fprintf(output, "Object is a number : Infinity\n"); 1119 break; 1120 case -1: 1121 fprintf(output, "Object is a number : -Infinity\n"); 1122 break; 1123 default: 1124 if (xmlXPathIsNaN(cur->floatval)) { 1125 fprintf(output, "Object is a number : NaN\n"); 1126 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) { 1127 fprintf(output, "Object is a number : 0\n"); 1128 } else { 1129 fprintf(output, "Object is a number : %0g\n", cur->floatval); 1130 } 1131 } 1132 break; 1133 case XPATH_STRING: 1134 fprintf(output, "Object is a string : "); 1135 xmlDebugDumpString(output, cur->stringval); 1136 fprintf(output, "\n"); 1137 break; 1138 case XPATH_POINT: 1139 fprintf(output, "Object is a point : index %d in node", cur->index); 1140 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1); 1141 fprintf(output, "\n"); 1142 break; 1143 case XPATH_RANGE: 1144 if ((cur->user2 == NULL) || 1145 ((cur->user2 == cur->user) && (cur->index == cur->index2))) { 1146 fprintf(output, "Object is a collapsed range :\n"); 1147 fprintf(output, "%s", shift); 1148 if (cur->index >= 0) 1149 fprintf(output, "index %d in ", cur->index); 1150 fprintf(output, "node\n"); 1151 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, 1152 depth + 1); 1153 } else { 1154 fprintf(output, "Object is a range :\n"); 1155 fprintf(output, "%s", shift); 1156 fprintf(output, "From "); 1157 if (cur->index >= 0) 1158 fprintf(output, "index %d in ", cur->index); 1159 fprintf(output, "node\n"); 1160 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, 1161 depth + 1); 1162 fprintf(output, "%s", shift); 1163 fprintf(output, "To "); 1164 if (cur->index2 >= 0) 1165 fprintf(output, "index %d in ", cur->index2); 1166 fprintf(output, "node\n"); 1167 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2, 1168 depth + 1); 1169 fprintf(output, "\n"); 1170 } 1171 break; 1172 case XPATH_LOCATIONSET: 1173#if defined(LIBXML_XPTR_ENABLED) 1174 fprintf(output, "Object is a Location Set:\n"); 1175 xmlXPathDebugDumpLocationSet(output, 1176 (xmlLocationSetPtr) cur->user, depth); 1177#endif 1178 break; 1179 case XPATH_USERS: 1180 fprintf(output, "Object is user defined\n"); 1181 break; 1182 } 1183} 1184 1185static void 1186xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp, 1187 xmlXPathStepOpPtr op, int depth) { 1188 int i; 1189 char shift[100]; 1190 1191 for (i = 0;((i < depth) && (i < 25));i++) 1192 shift[2 * i] = shift[2 * i + 1] = ' '; 1193 shift[2 * i] = shift[2 * i + 1] = 0; 1194 1195 fprintf(output, "%s", shift); 1196 if (op == NULL) { 1197 fprintf(output, "Step is NULL\n"); 1198 return; 1199 } 1200 switch (op->op) { 1201 case XPATH_OP_END: 1202 fprintf(output, "END"); break; 1203 case XPATH_OP_AND: 1204 fprintf(output, "AND"); break; 1205 case XPATH_OP_OR: 1206 fprintf(output, "OR"); break; 1207 case XPATH_OP_EQUAL: 1208 if (op->value) 1209 fprintf(output, "EQUAL ="); 1210 else 1211 fprintf(output, "EQUAL !="); 1212 break; 1213 case XPATH_OP_CMP: 1214 if (op->value) 1215 fprintf(output, "CMP <"); 1216 else 1217 fprintf(output, "CMP >"); 1218 if (!op->value2) 1219 fprintf(output, "="); 1220 break; 1221 case XPATH_OP_PLUS: 1222 if (op->value == 0) 1223 fprintf(output, "PLUS -"); 1224 else if (op->value == 1) 1225 fprintf(output, "PLUS +"); 1226 else if (op->value == 2) 1227 fprintf(output, "PLUS unary -"); 1228 else if (op->value == 3) 1229 fprintf(output, "PLUS unary - -"); 1230 break; 1231 case XPATH_OP_MULT: 1232 if (op->value == 0) 1233 fprintf(output, "MULT *"); 1234 else if (op->value == 1) 1235 fprintf(output, "MULT div"); 1236 else 1237 fprintf(output, "MULT mod"); 1238 break; 1239 case XPATH_OP_UNION: 1240 fprintf(output, "UNION"); break; 1241 case XPATH_OP_ROOT: 1242 fprintf(output, "ROOT"); break; 1243 case XPATH_OP_NODE: 1244 fprintf(output, "NODE"); break; 1245 case XPATH_OP_RESET: 1246 fprintf(output, "RESET"); break; 1247 case XPATH_OP_SORT: 1248 fprintf(output, "SORT"); break; 1249 case XPATH_OP_COLLECT: { 1250 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value; 1251 xmlXPathTestVal test = (xmlXPathTestVal)op->value2; 1252 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3; 1253 const xmlChar *prefix = op->value4; 1254 const xmlChar *name = op->value5; 1255 1256 fprintf(output, "COLLECT "); 1257 switch (axis) { 1258 case AXIS_ANCESTOR: 1259 fprintf(output, " 'ancestors' "); break; 1260 case AXIS_ANCESTOR_OR_SELF: 1261 fprintf(output, " 'ancestors-or-self' "); break; 1262 case AXIS_ATTRIBUTE: 1263 fprintf(output, " 'attributes' "); break; 1264 case AXIS_CHILD: 1265 fprintf(output, " 'child' "); break; 1266 case AXIS_DESCENDANT: 1267 fprintf(output, " 'descendant' "); break; 1268 case AXIS_DESCENDANT_OR_SELF: 1269 fprintf(output, " 'descendant-or-self' "); break; 1270 case AXIS_FOLLOWING: 1271 fprintf(output, " 'following' "); break; 1272 case AXIS_FOLLOWING_SIBLING: 1273 fprintf(output, " 'following-siblings' "); break; 1274 case AXIS_NAMESPACE: 1275 fprintf(output, " 'namespace' "); break; 1276 case AXIS_PARENT: 1277 fprintf(output, " 'parent' "); break; 1278 case AXIS_PRECEDING: 1279 fprintf(output, " 'preceding' "); break; 1280 case AXIS_PRECEDING_SIBLING: 1281 fprintf(output, " 'preceding-sibling' "); break; 1282 case AXIS_SELF: 1283 fprintf(output, " 'self' "); break; 1284 } 1285 switch (test) { 1286 case NODE_TEST_NONE: 1287 fprintf(output, "'none' "); break; 1288 case NODE_TEST_TYPE: 1289 fprintf(output, "'type' "); break; 1290 case NODE_TEST_PI: 1291 fprintf(output, "'PI' "); break; 1292 case NODE_TEST_ALL: 1293 fprintf(output, "'all' "); break; 1294 case NODE_TEST_NS: 1295 fprintf(output, "'namespace' "); break; 1296 case NODE_TEST_NAME: 1297 fprintf(output, "'name' "); break; 1298 } 1299 switch (type) { 1300 case NODE_TYPE_NODE: 1301 fprintf(output, "'node' "); break; 1302 case NODE_TYPE_COMMENT: 1303 fprintf(output, "'comment' "); break; 1304 case NODE_TYPE_TEXT: 1305 fprintf(output, "'text' "); break; 1306 case NODE_TYPE_PI: 1307 fprintf(output, "'PI' "); break; 1308 } 1309 if (prefix != NULL) 1310 fprintf(output, "%s:", prefix); 1311 if (name != NULL) 1312 fprintf(output, "%s", (const char *) name); 1313 break; 1314 1315 } 1316 case XPATH_OP_VALUE: { 1317 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4; 1318 1319 fprintf(output, "ELEM "); 1320 xmlXPathDebugDumpObject(output, object, 0); 1321 goto finish; 1322 } 1323 case XPATH_OP_VARIABLE: { 1324 const xmlChar *prefix = op->value5; 1325 const xmlChar *name = op->value4; 1326 1327 if (prefix != NULL) 1328 fprintf(output, "VARIABLE %s:%s", prefix, name); 1329 else 1330 fprintf(output, "VARIABLE %s", name); 1331 break; 1332 } 1333 case XPATH_OP_FUNCTION: { 1334 int nbargs = op->value; 1335 const xmlChar *prefix = op->value5; 1336 const xmlChar *name = op->value4; 1337 1338 if (prefix != NULL) 1339 fprintf(output, "FUNCTION %s:%s(%d args)", 1340 prefix, name, nbargs); 1341 else 1342 fprintf(output, "FUNCTION %s(%d args)", name, nbargs); 1343 break; 1344 } 1345 case XPATH_OP_ARG: fprintf(output, "ARG"); break; 1346 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break; 1347 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break; 1348#ifdef LIBXML_XPTR_ENABLED 1349 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break; 1350#endif 1351 default: 1352 fprintf(output, "UNKNOWN %d\n", op->op); return; 1353 } 1354 fprintf(output, "\n"); 1355finish: 1356 if (op->ch1 >= 0) 1357 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1); 1358 if (op->ch2 >= 0) 1359 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1); 1360} 1361 1362/** 1363 * xmlXPathDebugDumpCompExpr: 1364 * @output: the FILE * for the output 1365 * @comp: the precompiled XPath expression 1366 * @depth: the indentation level. 1367 * 1368 * Dumps the tree of the compiled XPath expression. 1369 */ 1370void 1371xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp, 1372 int depth) { 1373 int i; 1374 char shift[100]; 1375 1376 if ((output == NULL) || (comp == NULL)) return; 1377 1378 for (i = 0;((i < depth) && (i < 25));i++) 1379 shift[2 * i] = shift[2 * i + 1] = ' '; 1380 shift[2 * i] = shift[2 * i + 1] = 0; 1381 1382 fprintf(output, "%s", shift); 1383 1384 fprintf(output, "Compiled Expression : %d elements\n", 1385 comp->nbStep); 1386 i = comp->last; 1387 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1); 1388} 1389 1390#ifdef XP_DEBUG_OBJ_USAGE 1391 1392/* 1393* XPath object usage related debugging variables. 1394*/ 1395static int xmlXPathDebugObjCounterUndefined = 0; 1396static int xmlXPathDebugObjCounterNodeset = 0; 1397static int xmlXPathDebugObjCounterBool = 0; 1398static int xmlXPathDebugObjCounterNumber = 0; 1399static int xmlXPathDebugObjCounterString = 0; 1400static int xmlXPathDebugObjCounterPoint = 0; 1401static int xmlXPathDebugObjCounterRange = 0; 1402static int xmlXPathDebugObjCounterLocset = 0; 1403static int xmlXPathDebugObjCounterUsers = 0; 1404static int xmlXPathDebugObjCounterXSLTTree = 0; 1405static int xmlXPathDebugObjCounterAll = 0; 1406 1407static int xmlXPathDebugObjTotalUndefined = 0; 1408static int xmlXPathDebugObjTotalNodeset = 0; 1409static int xmlXPathDebugObjTotalBool = 0; 1410static int xmlXPathDebugObjTotalNumber = 0; 1411static int xmlXPathDebugObjTotalString = 0; 1412static int xmlXPathDebugObjTotalPoint = 0; 1413static int xmlXPathDebugObjTotalRange = 0; 1414static int xmlXPathDebugObjTotalLocset = 0; 1415static int xmlXPathDebugObjTotalUsers = 0; 1416static int xmlXPathDebugObjTotalXSLTTree = 0; 1417static int xmlXPathDebugObjTotalAll = 0; 1418 1419static int xmlXPathDebugObjMaxUndefined = 0; 1420static int xmlXPathDebugObjMaxNodeset = 0; 1421static int xmlXPathDebugObjMaxBool = 0; 1422static int xmlXPathDebugObjMaxNumber = 0; 1423static int xmlXPathDebugObjMaxString = 0; 1424static int xmlXPathDebugObjMaxPoint = 0; 1425static int xmlXPathDebugObjMaxRange = 0; 1426static int xmlXPathDebugObjMaxLocset = 0; 1427static int xmlXPathDebugObjMaxUsers = 0; 1428static int xmlXPathDebugObjMaxXSLTTree = 0; 1429static int xmlXPathDebugObjMaxAll = 0; 1430 1431/* REVISIT TODO: Make this static when committing */ 1432static void 1433xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt) 1434{ 1435 if (ctxt != NULL) { 1436 if (ctxt->cache != NULL) { 1437 xmlXPathContextCachePtr cache = 1438 (xmlXPathContextCachePtr) ctxt->cache; 1439 1440 cache->dbgCachedAll = 0; 1441 cache->dbgCachedNodeset = 0; 1442 cache->dbgCachedString = 0; 1443 cache->dbgCachedBool = 0; 1444 cache->dbgCachedNumber = 0; 1445 cache->dbgCachedPoint = 0; 1446 cache->dbgCachedRange = 0; 1447 cache->dbgCachedLocset = 0; 1448 cache->dbgCachedUsers = 0; 1449 cache->dbgCachedXSLTTree = 0; 1450 cache->dbgCachedUndefined = 0; 1451 1452 cache->dbgReusedAll = 0; 1453 cache->dbgReusedNodeset = 0; 1454 cache->dbgReusedString = 0; 1455 cache->dbgReusedBool = 0; 1456 cache->dbgReusedNumber = 0; 1457 cache->dbgReusedPoint = 0; 1458 cache->dbgReusedRange = 0; 1459 cache->dbgReusedLocset = 0; 1460 cache->dbgReusedUsers = 0; 1461 cache->dbgReusedXSLTTree = 0; 1462 cache->dbgReusedUndefined = 0; 1463 } 1464 } 1465 1466 xmlXPathDebugObjCounterUndefined = 0; 1467 xmlXPathDebugObjCounterNodeset = 0; 1468 xmlXPathDebugObjCounterBool = 0; 1469 xmlXPathDebugObjCounterNumber = 0; 1470 xmlXPathDebugObjCounterString = 0; 1471 xmlXPathDebugObjCounterPoint = 0; 1472 xmlXPathDebugObjCounterRange = 0; 1473 xmlXPathDebugObjCounterLocset = 0; 1474 xmlXPathDebugObjCounterUsers = 0; 1475 xmlXPathDebugObjCounterXSLTTree = 0; 1476 xmlXPathDebugObjCounterAll = 0; 1477 1478 xmlXPathDebugObjTotalUndefined = 0; 1479 xmlXPathDebugObjTotalNodeset = 0; 1480 xmlXPathDebugObjTotalBool = 0; 1481 xmlXPathDebugObjTotalNumber = 0; 1482 xmlXPathDebugObjTotalString = 0; 1483 xmlXPathDebugObjTotalPoint = 0; 1484 xmlXPathDebugObjTotalRange = 0; 1485 xmlXPathDebugObjTotalLocset = 0; 1486 xmlXPathDebugObjTotalUsers = 0; 1487 xmlXPathDebugObjTotalXSLTTree = 0; 1488 xmlXPathDebugObjTotalAll = 0; 1489 1490 xmlXPathDebugObjMaxUndefined = 0; 1491 xmlXPathDebugObjMaxNodeset = 0; 1492 xmlXPathDebugObjMaxBool = 0; 1493 xmlXPathDebugObjMaxNumber = 0; 1494 xmlXPathDebugObjMaxString = 0; 1495 xmlXPathDebugObjMaxPoint = 0; 1496 xmlXPathDebugObjMaxRange = 0; 1497 xmlXPathDebugObjMaxLocset = 0; 1498 xmlXPathDebugObjMaxUsers = 0; 1499 xmlXPathDebugObjMaxXSLTTree = 0; 1500 xmlXPathDebugObjMaxAll = 0; 1501 1502} 1503 1504static void 1505xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt, 1506 xmlXPathObjectType objType) 1507{ 1508 int isCached = 0; 1509 1510 if (ctxt != NULL) { 1511 if (ctxt->cache != NULL) { 1512 xmlXPathContextCachePtr cache = 1513 (xmlXPathContextCachePtr) ctxt->cache; 1514 1515 isCached = 1; 1516 1517 cache->dbgReusedAll++; 1518 switch (objType) { 1519 case XPATH_UNDEFINED: 1520 cache->dbgReusedUndefined++; 1521 break; 1522 case XPATH_NODESET: 1523 cache->dbgReusedNodeset++; 1524 break; 1525 case XPATH_BOOLEAN: 1526 cache->dbgReusedBool++; 1527 break; 1528 case XPATH_NUMBER: 1529 cache->dbgReusedNumber++; 1530 break; 1531 case XPATH_STRING: 1532 cache->dbgReusedString++; 1533 break; 1534 case XPATH_POINT: 1535 cache->dbgReusedPoint++; 1536 break; 1537 case XPATH_RANGE: 1538 cache->dbgReusedRange++; 1539 break; 1540 case XPATH_LOCATIONSET: 1541 cache->dbgReusedLocset++; 1542 break; 1543 case XPATH_USERS: 1544 cache->dbgReusedUsers++; 1545 break; 1546 case XPATH_XSLT_TREE: 1547 cache->dbgReusedXSLTTree++; 1548 break; 1549 default: 1550 break; 1551 } 1552 } 1553 } 1554 1555 switch (objType) { 1556 case XPATH_UNDEFINED: 1557 if (! isCached) 1558 xmlXPathDebugObjTotalUndefined++; 1559 xmlXPathDebugObjCounterUndefined++; 1560 if (xmlXPathDebugObjCounterUndefined > 1561 xmlXPathDebugObjMaxUndefined) 1562 xmlXPathDebugObjMaxUndefined = 1563 xmlXPathDebugObjCounterUndefined; 1564 break; 1565 case XPATH_NODESET: 1566 if (! isCached) 1567 xmlXPathDebugObjTotalNodeset++; 1568 xmlXPathDebugObjCounterNodeset++; 1569 if (xmlXPathDebugObjCounterNodeset > 1570 xmlXPathDebugObjMaxNodeset) 1571 xmlXPathDebugObjMaxNodeset = 1572 xmlXPathDebugObjCounterNodeset; 1573 break; 1574 case XPATH_BOOLEAN: 1575 if (! isCached) 1576 xmlXPathDebugObjTotalBool++; 1577 xmlXPathDebugObjCounterBool++; 1578 if (xmlXPathDebugObjCounterBool > 1579 xmlXPathDebugObjMaxBool) 1580 xmlXPathDebugObjMaxBool = 1581 xmlXPathDebugObjCounterBool; 1582 break; 1583 case XPATH_NUMBER: 1584 if (! isCached) 1585 xmlXPathDebugObjTotalNumber++; 1586 xmlXPathDebugObjCounterNumber++; 1587 if (xmlXPathDebugObjCounterNumber > 1588 xmlXPathDebugObjMaxNumber) 1589 xmlXPathDebugObjMaxNumber = 1590 xmlXPathDebugObjCounterNumber; 1591 break; 1592 case XPATH_STRING: 1593 if (! isCached) 1594 xmlXPathDebugObjTotalString++; 1595 xmlXPathDebugObjCounterString++; 1596 if (xmlXPathDebugObjCounterString > 1597 xmlXPathDebugObjMaxString) 1598 xmlXPathDebugObjMaxString = 1599 xmlXPathDebugObjCounterString; 1600 break; 1601 case XPATH_POINT: 1602 if (! isCached) 1603 xmlXPathDebugObjTotalPoint++; 1604 xmlXPathDebugObjCounterPoint++; 1605 if (xmlXPathDebugObjCounterPoint > 1606 xmlXPathDebugObjMaxPoint) 1607 xmlXPathDebugObjMaxPoint = 1608 xmlXPathDebugObjCounterPoint; 1609 break; 1610 case XPATH_RANGE: 1611 if (! isCached) 1612 xmlXPathDebugObjTotalRange++; 1613 xmlXPathDebugObjCounterRange++; 1614 if (xmlXPathDebugObjCounterRange > 1615 xmlXPathDebugObjMaxRange) 1616 xmlXPathDebugObjMaxRange = 1617 xmlXPathDebugObjCounterRange; 1618 break; 1619 case XPATH_LOCATIONSET: 1620 if (! isCached) 1621 xmlXPathDebugObjTotalLocset++; 1622 xmlXPathDebugObjCounterLocset++; 1623 if (xmlXPathDebugObjCounterLocset > 1624 xmlXPathDebugObjMaxLocset) 1625 xmlXPathDebugObjMaxLocset = 1626 xmlXPathDebugObjCounterLocset; 1627 break; 1628 case XPATH_USERS: 1629 if (! isCached) 1630 xmlXPathDebugObjTotalUsers++; 1631 xmlXPathDebugObjCounterUsers++; 1632 if (xmlXPathDebugObjCounterUsers > 1633 xmlXPathDebugObjMaxUsers) 1634 xmlXPathDebugObjMaxUsers = 1635 xmlXPathDebugObjCounterUsers; 1636 break; 1637 case XPATH_XSLT_TREE: 1638 if (! isCached) 1639 xmlXPathDebugObjTotalXSLTTree++; 1640 xmlXPathDebugObjCounterXSLTTree++; 1641 if (xmlXPathDebugObjCounterXSLTTree > 1642 xmlXPathDebugObjMaxXSLTTree) 1643 xmlXPathDebugObjMaxXSLTTree = 1644 xmlXPathDebugObjCounterXSLTTree; 1645 break; 1646 default: 1647 break; 1648 } 1649 if (! isCached) 1650 xmlXPathDebugObjTotalAll++; 1651 xmlXPathDebugObjCounterAll++; 1652 if (xmlXPathDebugObjCounterAll > 1653 xmlXPathDebugObjMaxAll) 1654 xmlXPathDebugObjMaxAll = 1655 xmlXPathDebugObjCounterAll; 1656} 1657 1658static void 1659xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt, 1660 xmlXPathObjectType objType) 1661{ 1662 int isCached = 0; 1663 1664 if (ctxt != NULL) { 1665 if (ctxt->cache != NULL) { 1666 xmlXPathContextCachePtr cache = 1667 (xmlXPathContextCachePtr) ctxt->cache; 1668 1669 isCached = 1; 1670 1671 cache->dbgCachedAll++; 1672 switch (objType) { 1673 case XPATH_UNDEFINED: 1674 cache->dbgCachedUndefined++; 1675 break; 1676 case XPATH_NODESET: 1677 cache->dbgCachedNodeset++; 1678 break; 1679 case XPATH_BOOLEAN: 1680 cache->dbgCachedBool++; 1681 break; 1682 case XPATH_NUMBER: 1683 cache->dbgCachedNumber++; 1684 break; 1685 case XPATH_STRING: 1686 cache->dbgCachedString++; 1687 break; 1688 case XPATH_POINT: 1689 cache->dbgCachedPoint++; 1690 break; 1691 case XPATH_RANGE: 1692 cache->dbgCachedRange++; 1693 break; 1694 case XPATH_LOCATIONSET: 1695 cache->dbgCachedLocset++; 1696 break; 1697 case XPATH_USERS: 1698 cache->dbgCachedUsers++; 1699 break; 1700 case XPATH_XSLT_TREE: 1701 cache->dbgCachedXSLTTree++; 1702 break; 1703 default: 1704 break; 1705 } 1706 1707 } 1708 } 1709 switch (objType) { 1710 case XPATH_UNDEFINED: 1711 xmlXPathDebugObjCounterUndefined--; 1712 break; 1713 case XPATH_NODESET: 1714 xmlXPathDebugObjCounterNodeset--; 1715 break; 1716 case XPATH_BOOLEAN: 1717 xmlXPathDebugObjCounterBool--; 1718 break; 1719 case XPATH_NUMBER: 1720 xmlXPathDebugObjCounterNumber--; 1721 break; 1722 case XPATH_STRING: 1723 xmlXPathDebugObjCounterString--; 1724 break; 1725 case XPATH_POINT: 1726 xmlXPathDebugObjCounterPoint--; 1727 break; 1728 case XPATH_RANGE: 1729 xmlXPathDebugObjCounterRange--; 1730 break; 1731 case XPATH_LOCATIONSET: 1732 xmlXPathDebugObjCounterLocset--; 1733 break; 1734 case XPATH_USERS: 1735 xmlXPathDebugObjCounterUsers--; 1736 break; 1737 case XPATH_XSLT_TREE: 1738 xmlXPathDebugObjCounterXSLTTree--; 1739 break; 1740 default: 1741 break; 1742 } 1743 xmlXPathDebugObjCounterAll--; 1744} 1745 1746/* REVISIT TODO: Make this static when committing */ 1747static void 1748xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt) 1749{ 1750 int reqAll, reqNodeset, reqString, reqBool, reqNumber, 1751 reqXSLTTree, reqUndefined; 1752 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0, 1753 caNumber = 0, caXSLTTree = 0, caUndefined = 0; 1754 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0, 1755 reNumber = 0, reXSLTTree = 0, reUndefined = 0; 1756 int leftObjs = xmlXPathDebugObjCounterAll; 1757 1758 reqAll = xmlXPathDebugObjTotalAll; 1759 reqNodeset = xmlXPathDebugObjTotalNodeset; 1760 reqString = xmlXPathDebugObjTotalString; 1761 reqBool = xmlXPathDebugObjTotalBool; 1762 reqNumber = xmlXPathDebugObjTotalNumber; 1763 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree; 1764 reqUndefined = xmlXPathDebugObjTotalUndefined; 1765 1766 printf("# XPath object usage:\n"); 1767 1768 if (ctxt != NULL) { 1769 if (ctxt->cache != NULL) { 1770 xmlXPathContextCachePtr cache = 1771 (xmlXPathContextCachePtr) ctxt->cache; 1772 1773 reAll = cache->dbgReusedAll; 1774 reqAll += reAll; 1775 reNodeset = cache->dbgReusedNodeset; 1776 reqNodeset += reNodeset; 1777 reString = cache->dbgReusedString; 1778 reqString += reString; 1779 reBool = cache->dbgReusedBool; 1780 reqBool += reBool; 1781 reNumber = cache->dbgReusedNumber; 1782 reqNumber += reNumber; 1783 reXSLTTree = cache->dbgReusedXSLTTree; 1784 reqXSLTTree += reXSLTTree; 1785 reUndefined = cache->dbgReusedUndefined; 1786 reqUndefined += reUndefined; 1787 1788 caAll = cache->dbgCachedAll; 1789 caBool = cache->dbgCachedBool; 1790 caNodeset = cache->dbgCachedNodeset; 1791 caString = cache->dbgCachedString; 1792 caNumber = cache->dbgCachedNumber; 1793 caXSLTTree = cache->dbgCachedXSLTTree; 1794 caUndefined = cache->dbgCachedUndefined; 1795 1796 if (cache->nodesetObjs) 1797 leftObjs -= cache->nodesetObjs->number; 1798 if (cache->stringObjs) 1799 leftObjs -= cache->stringObjs->number; 1800 if (cache->booleanObjs) 1801 leftObjs -= cache->booleanObjs->number; 1802 if (cache->numberObjs) 1803 leftObjs -= cache->numberObjs->number; 1804 if (cache->miscObjs) 1805 leftObjs -= cache->miscObjs->number; 1806 } 1807 } 1808 1809 printf("# all\n"); 1810 printf("# total : %d\n", reqAll); 1811 printf("# left : %d\n", leftObjs); 1812 printf("# created: %d\n", xmlXPathDebugObjTotalAll); 1813 printf("# reused : %d\n", reAll); 1814 printf("# max : %d\n", xmlXPathDebugObjMaxAll); 1815 1816 printf("# node-sets\n"); 1817 printf("# total : %d\n", reqNodeset); 1818 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset); 1819 printf("# reused : %d\n", reNodeset); 1820 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset); 1821 1822 printf("# strings\n"); 1823 printf("# total : %d\n", reqString); 1824 printf("# created: %d\n", xmlXPathDebugObjTotalString); 1825 printf("# reused : %d\n", reString); 1826 printf("# max : %d\n", xmlXPathDebugObjMaxString); 1827 1828 printf("# booleans\n"); 1829 printf("# total : %d\n", reqBool); 1830 printf("# created: %d\n", xmlXPathDebugObjTotalBool); 1831 printf("# reused : %d\n", reBool); 1832 printf("# max : %d\n", xmlXPathDebugObjMaxBool); 1833 1834 printf("# numbers\n"); 1835 printf("# total : %d\n", reqNumber); 1836 printf("# created: %d\n", xmlXPathDebugObjTotalNumber); 1837 printf("# reused : %d\n", reNumber); 1838 printf("# max : %d\n", xmlXPathDebugObjMaxNumber); 1839 1840 printf("# XSLT result tree fragments\n"); 1841 printf("# total : %d\n", reqXSLTTree); 1842 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree); 1843 printf("# reused : %d\n", reXSLTTree); 1844 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree); 1845 1846 printf("# undefined\n"); 1847 printf("# total : %d\n", reqUndefined); 1848 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined); 1849 printf("# reused : %d\n", reUndefined); 1850 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined); 1851 1852} 1853 1854#endif /* XP_DEBUG_OBJ_USAGE */ 1855 1856#endif /* LIBXML_DEBUG_ENABLED */ 1857 1858/************************************************************************ 1859 * * 1860 * XPath object caching * 1861 * * 1862 ************************************************************************/ 1863 1864/** 1865 * xmlXPathNewCache: 1866 * 1867 * Create a new object cache 1868 * 1869 * Returns the xmlXPathCache just allocated. 1870 */ 1871static xmlXPathContextCachePtr 1872xmlXPathNewCache(void) 1873{ 1874 xmlXPathContextCachePtr ret; 1875 1876 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache)); 1877 if (ret == NULL) { 1878 xmlXPathErrMemory(NULL, "creating object cache\n"); 1879 return(NULL); 1880 } 1881 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache)); 1882 ret->maxNodeset = 100; 1883 ret->maxString = 100; 1884 ret->maxBoolean = 100; 1885 ret->maxNumber = 100; 1886 ret->maxMisc = 100; 1887 return(ret); 1888} 1889 1890static void 1891xmlXPathCacheFreeObjectList(xmlPointerListPtr list) 1892{ 1893 int i; 1894 xmlXPathObjectPtr obj; 1895 1896 if (list == NULL) 1897 return; 1898 1899 for (i = 0; i < list->number; i++) { 1900 obj = list->items[i]; 1901 /* 1902 * Note that it is already assured that we don't need to 1903 * look out for namespace nodes in the node-set. 1904 */ 1905 if (obj->nodesetval != NULL) { 1906 if (obj->nodesetval->nodeTab != NULL) 1907 xmlFree(obj->nodesetval->nodeTab); 1908 xmlFree(obj->nodesetval); 1909 } 1910 xmlFree(obj); 1911#ifdef XP_DEBUG_OBJ_USAGE 1912 xmlXPathDebugObjCounterAll--; 1913#endif 1914 } 1915 xmlPointerListFree(list); 1916} 1917 1918static void 1919xmlXPathFreeCache(xmlXPathContextCachePtr cache) 1920{ 1921 if (cache == NULL) 1922 return; 1923 if (cache->nodesetObjs) 1924 xmlXPathCacheFreeObjectList(cache->nodesetObjs); 1925 if (cache->stringObjs) 1926 xmlXPathCacheFreeObjectList(cache->stringObjs); 1927 if (cache->booleanObjs) 1928 xmlXPathCacheFreeObjectList(cache->booleanObjs); 1929 if (cache->numberObjs) 1930 xmlXPathCacheFreeObjectList(cache->numberObjs); 1931 if (cache->miscObjs) 1932 xmlXPathCacheFreeObjectList(cache->miscObjs); 1933 xmlFree(cache); 1934} 1935 1936/** 1937 * xmlXPathContextSetCache: 1938 * 1939 * @ctxt: the XPath context 1940 * @active: enables/disables (creates/frees) the cache 1941 * @value: a value with semantics dependant on @options 1942 * @options: options (currently only the value 0 is used) 1943 * 1944 * Creates/frees an object cache on the XPath context. 1945 * If activates XPath objects (xmlXPathObject) will be cached internally 1946 * to be reused. 1947 * @options: 1948 * 0: This will set the XPath object caching: 1949 * @value: 1950 * This will set the maximum number of XPath objects 1951 * to be cached per slot 1952 * There are 5 slots for: node-set, string, number, boolean, and 1953 * misc objects. Use <0 for the default number (100). 1954 * Other values for @options have currently no effect. 1955 * 1956 * Returns 0 if the setting succeeded, and -1 on API or internal errors. 1957 */ 1958int 1959xmlXPathContextSetCache(xmlXPathContextPtr ctxt, 1960 int active, 1961 int value, 1962 int options) 1963{ 1964 if (ctxt == NULL) 1965 return(-1); 1966 if (active) { 1967 xmlXPathContextCachePtr cache; 1968 1969 if (ctxt->cache == NULL) { 1970 ctxt->cache = xmlXPathNewCache(); 1971 if (ctxt->cache == NULL) 1972 return(-1); 1973 } 1974 cache = (xmlXPathContextCachePtr) ctxt->cache; 1975 if (options == 0) { 1976 if (value < 0) 1977 value = 100; 1978 cache->maxNodeset = value; 1979 cache->maxString = value; 1980 cache->maxNumber = value; 1981 cache->maxBoolean = value; 1982 cache->maxMisc = value; 1983 } 1984 } else if (ctxt->cache != NULL) { 1985 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache); 1986 ctxt->cache = NULL; 1987 } 1988 return(0); 1989} 1990 1991/** 1992 * xmlXPathCacheWrapNodeSet: 1993 * @ctxt: the XPath context 1994 * @val: the NodePtr value 1995 * 1996 * This is the cached version of xmlXPathWrapNodeSet(). 1997 * Wrap the Nodeset @val in a new xmlXPathObjectPtr 1998 * 1999 * Returns the created or reused object. 2000 */ 2001static xmlXPathObjectPtr 2002xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val) 2003{ 2004 if ((ctxt != NULL) && (ctxt->cache != NULL)) { 2005 xmlXPathContextCachePtr cache = 2006 (xmlXPathContextCachePtr) ctxt->cache; 2007 2008 if ((cache->miscObjs != NULL) && 2009 (cache->miscObjs->number != 0)) 2010 { 2011 xmlXPathObjectPtr ret; 2012 2013 ret = (xmlXPathObjectPtr) 2014 cache->miscObjs->items[--cache->miscObjs->number]; 2015 ret->type = XPATH_NODESET; 2016 ret->nodesetval = val; 2017#ifdef XP_DEBUG_OBJ_USAGE 2018 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 2019#endif 2020 return(ret); 2021 } 2022 } 2023 2024 return(xmlXPathWrapNodeSet(val)); 2025 2026} 2027 2028/** 2029 * xmlXPathCacheWrapString: 2030 * @ctxt: the XPath context 2031 * @val: the xmlChar * value 2032 * 2033 * This is the cached version of xmlXPathWrapString(). 2034 * Wraps the @val string into an XPath object. 2035 * 2036 * Returns the created or reused object. 2037 */ 2038static xmlXPathObjectPtr 2039xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val) 2040{ 2041 if ((ctxt != NULL) && (ctxt->cache != NULL)) { 2042 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2043 2044 if ((cache->stringObjs != NULL) && 2045 (cache->stringObjs->number != 0)) 2046 { 2047 2048 xmlXPathObjectPtr ret; 2049 2050 ret = (xmlXPathObjectPtr) 2051 cache->stringObjs->items[--cache->stringObjs->number]; 2052 ret->type = XPATH_STRING; 2053 ret->stringval = val; 2054#ifdef XP_DEBUG_OBJ_USAGE 2055 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2056#endif 2057 return(ret); 2058 } else if ((cache->miscObjs != NULL) && 2059 (cache->miscObjs->number != 0)) 2060 { 2061 xmlXPathObjectPtr ret; 2062 /* 2063 * Fallback to misc-cache. 2064 */ 2065 ret = (xmlXPathObjectPtr) 2066 cache->miscObjs->items[--cache->miscObjs->number]; 2067 2068 ret->type = XPATH_STRING; 2069 ret->stringval = val; 2070#ifdef XP_DEBUG_OBJ_USAGE 2071 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2072#endif 2073 return(ret); 2074 } 2075 } 2076 return(xmlXPathWrapString(val)); 2077} 2078 2079/** 2080 * xmlXPathCacheNewNodeSet: 2081 * @ctxt: the XPath context 2082 * @val: the NodePtr value 2083 * 2084 * This is the cached version of xmlXPathNewNodeSet(). 2085 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize 2086 * it with the single Node @val 2087 * 2088 * Returns the created or reused object. 2089 */ 2090static xmlXPathObjectPtr 2091xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val) 2092{ 2093 if ((ctxt != NULL) && (ctxt->cache)) { 2094 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2095 2096 if ((cache->nodesetObjs != NULL) && 2097 (cache->nodesetObjs->number != 0)) 2098 { 2099 xmlXPathObjectPtr ret; 2100 /* 2101 * Use the nodset-cache. 2102 */ 2103 ret = (xmlXPathObjectPtr) 2104 cache->nodesetObjs->items[--cache->nodesetObjs->number]; 2105 ret->type = XPATH_NODESET; 2106 ret->boolval = 0; 2107 if (val) { 2108 if ((ret->nodesetval->nodeMax == 0) || 2109 (val->type == XML_NAMESPACE_DECL)) 2110 { 2111 xmlXPathNodeSetAddUnique(ret->nodesetval, val); 2112 } else { 2113 ret->nodesetval->nodeTab[0] = val; 2114 ret->nodesetval->nodeNr = 1; 2115 } 2116 } 2117#ifdef XP_DEBUG_OBJ_USAGE 2118 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 2119#endif 2120 return(ret); 2121 } else if ((cache->miscObjs != NULL) && 2122 (cache->miscObjs->number != 0)) 2123 { 2124 xmlXPathObjectPtr ret; 2125 /* 2126 * Fallback to misc-cache. 2127 */ 2128 2129 ret = (xmlXPathObjectPtr) 2130 cache->miscObjs->items[--cache->miscObjs->number]; 2131 2132 ret->type = XPATH_NODESET; 2133 ret->boolval = 0; 2134 ret->nodesetval = xmlXPathNodeSetCreate(val); 2135 if (ret->nodesetval == NULL) { 2136 ctxt->lastError.domain = XML_FROM_XPATH; 2137 ctxt->lastError.code = XML_ERR_NO_MEMORY; 2138 return(NULL); 2139 } 2140#ifdef XP_DEBUG_OBJ_USAGE 2141 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 2142#endif 2143 return(ret); 2144 } 2145 } 2146 return(xmlXPathNewNodeSet(val)); 2147} 2148 2149/** 2150 * xmlXPathCacheNewCString: 2151 * @ctxt: the XPath context 2152 * @val: the char * value 2153 * 2154 * This is the cached version of xmlXPathNewCString(). 2155 * Acquire an xmlXPathObjectPtr of type string and of value @val 2156 * 2157 * Returns the created or reused object. 2158 */ 2159static xmlXPathObjectPtr 2160xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val) 2161{ 2162 if ((ctxt != NULL) && (ctxt->cache)) { 2163 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2164 2165 if ((cache->stringObjs != NULL) && 2166 (cache->stringObjs->number != 0)) 2167 { 2168 xmlXPathObjectPtr ret; 2169 2170 ret = (xmlXPathObjectPtr) 2171 cache->stringObjs->items[--cache->stringObjs->number]; 2172 2173 ret->type = XPATH_STRING; 2174 ret->stringval = xmlStrdup(BAD_CAST val); 2175#ifdef XP_DEBUG_OBJ_USAGE 2176 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2177#endif 2178 return(ret); 2179 } else if ((cache->miscObjs != NULL) && 2180 (cache->miscObjs->number != 0)) 2181 { 2182 xmlXPathObjectPtr ret; 2183 2184 ret = (xmlXPathObjectPtr) 2185 cache->miscObjs->items[--cache->miscObjs->number]; 2186 2187 ret->type = XPATH_STRING; 2188 ret->stringval = xmlStrdup(BAD_CAST val); 2189#ifdef XP_DEBUG_OBJ_USAGE 2190 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2191#endif 2192 return(ret); 2193 } 2194 } 2195 return(xmlXPathNewCString(val)); 2196} 2197 2198/** 2199 * xmlXPathCacheNewString: 2200 * @ctxt: the XPath context 2201 * @val: the xmlChar * value 2202 * 2203 * This is the cached version of xmlXPathNewString(). 2204 * Acquire an xmlXPathObjectPtr of type string and of value @val 2205 * 2206 * Returns the created or reused object. 2207 */ 2208static xmlXPathObjectPtr 2209xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val) 2210{ 2211 if ((ctxt != NULL) && (ctxt->cache)) { 2212 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2213 2214 if ((cache->stringObjs != NULL) && 2215 (cache->stringObjs->number != 0)) 2216 { 2217 xmlXPathObjectPtr ret; 2218 2219 ret = (xmlXPathObjectPtr) 2220 cache->stringObjs->items[--cache->stringObjs->number]; 2221 ret->type = XPATH_STRING; 2222 if (val != NULL) 2223 ret->stringval = xmlStrdup(val); 2224 else 2225 ret->stringval = xmlStrdup((const xmlChar *)""); 2226#ifdef XP_DEBUG_OBJ_USAGE 2227 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2228#endif 2229 return(ret); 2230 } else if ((cache->miscObjs != NULL) && 2231 (cache->miscObjs->number != 0)) 2232 { 2233 xmlXPathObjectPtr ret; 2234 2235 ret = (xmlXPathObjectPtr) 2236 cache->miscObjs->items[--cache->miscObjs->number]; 2237 2238 ret->type = XPATH_STRING; 2239 if (val != NULL) 2240 ret->stringval = xmlStrdup(val); 2241 else 2242 ret->stringval = xmlStrdup((const xmlChar *)""); 2243#ifdef XP_DEBUG_OBJ_USAGE 2244 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2245#endif 2246 return(ret); 2247 } 2248 } 2249 return(xmlXPathNewString(val)); 2250} 2251 2252/** 2253 * xmlXPathCacheNewBoolean: 2254 * @ctxt: the XPath context 2255 * @val: the boolean value 2256 * 2257 * This is the cached version of xmlXPathNewBoolean(). 2258 * Acquires an xmlXPathObjectPtr of type boolean and of value @val 2259 * 2260 * Returns the created or reused object. 2261 */ 2262static xmlXPathObjectPtr 2263xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val) 2264{ 2265 if ((ctxt != NULL) && (ctxt->cache)) { 2266 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2267 2268 if ((cache->booleanObjs != NULL) && 2269 (cache->booleanObjs->number != 0)) 2270 { 2271 xmlXPathObjectPtr ret; 2272 2273 ret = (xmlXPathObjectPtr) 2274 cache->booleanObjs->items[--cache->booleanObjs->number]; 2275 ret->type = XPATH_BOOLEAN; 2276 ret->boolval = (val != 0); 2277#ifdef XP_DEBUG_OBJ_USAGE 2278 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN); 2279#endif 2280 return(ret); 2281 } else if ((cache->miscObjs != NULL) && 2282 (cache->miscObjs->number != 0)) 2283 { 2284 xmlXPathObjectPtr ret; 2285 2286 ret = (xmlXPathObjectPtr) 2287 cache->miscObjs->items[--cache->miscObjs->number]; 2288 2289 ret->type = XPATH_BOOLEAN; 2290 ret->boolval = (val != 0); 2291#ifdef XP_DEBUG_OBJ_USAGE 2292 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN); 2293#endif 2294 return(ret); 2295 } 2296 } 2297 return(xmlXPathNewBoolean(val)); 2298} 2299 2300/** 2301 * xmlXPathCacheNewFloat: 2302 * @ctxt: the XPath context 2303 * @val: the double value 2304 * 2305 * This is the cached version of xmlXPathNewFloat(). 2306 * Acquires an xmlXPathObjectPtr of type double and of value @val 2307 * 2308 * Returns the created or reused object. 2309 */ 2310static xmlXPathObjectPtr 2311xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val) 2312{ 2313 if ((ctxt != NULL) && (ctxt->cache)) { 2314 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2315 2316 if ((cache->numberObjs != NULL) && 2317 (cache->numberObjs->number != 0)) 2318 { 2319 xmlXPathObjectPtr ret; 2320 2321 ret = (xmlXPathObjectPtr) 2322 cache->numberObjs->items[--cache->numberObjs->number]; 2323 ret->type = XPATH_NUMBER; 2324 ret->floatval = val; 2325#ifdef XP_DEBUG_OBJ_USAGE 2326 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER); 2327#endif 2328 return(ret); 2329 } else if ((cache->miscObjs != NULL) && 2330 (cache->miscObjs->number != 0)) 2331 { 2332 xmlXPathObjectPtr ret; 2333 2334 ret = (xmlXPathObjectPtr) 2335 cache->miscObjs->items[--cache->miscObjs->number]; 2336 2337 ret->type = XPATH_NUMBER; 2338 ret->floatval = val; 2339#ifdef XP_DEBUG_OBJ_USAGE 2340 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER); 2341#endif 2342 return(ret); 2343 } 2344 } 2345 return(xmlXPathNewFloat(val)); 2346} 2347 2348/** 2349 * xmlXPathCacheConvertString: 2350 * @ctxt: the XPath context 2351 * @val: an XPath object 2352 * 2353 * This is the cached version of xmlXPathConvertString(). 2354 * Converts an existing object to its string() equivalent 2355 * 2356 * Returns a created or reused object, the old one is freed (cached) 2357 * (or the operation is done directly on @val) 2358 */ 2359 2360static xmlXPathObjectPtr 2361xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 2362 xmlChar *res = NULL; 2363 2364 if (val == NULL) 2365 return(xmlXPathCacheNewCString(ctxt, "")); 2366 2367 switch (val->type) { 2368 case XPATH_UNDEFINED: 2369#ifdef DEBUG_EXPR 2370 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n"); 2371#endif 2372 break; 2373 case XPATH_NODESET: 2374 case XPATH_XSLT_TREE: 2375 res = xmlXPathCastNodeSetToString(val->nodesetval); 2376 break; 2377 case XPATH_STRING: 2378 return(val); 2379 case XPATH_BOOLEAN: 2380 res = xmlXPathCastBooleanToString(val->boolval); 2381 break; 2382 case XPATH_NUMBER: 2383 res = xmlXPathCastNumberToString(val->floatval); 2384 break; 2385 case XPATH_USERS: 2386 case XPATH_POINT: 2387 case XPATH_RANGE: 2388 case XPATH_LOCATIONSET: 2389 TODO; 2390 break; 2391 } 2392 xmlXPathReleaseObject(ctxt, val); 2393 if (res == NULL) 2394 return(xmlXPathCacheNewCString(ctxt, "")); 2395 return(xmlXPathCacheWrapString(ctxt, res)); 2396} 2397 2398/** 2399 * xmlXPathCacheObjectCopy: 2400 * @ctxt: the XPath context 2401 * @val: the original object 2402 * 2403 * This is the cached version of xmlXPathObjectCopy(). 2404 * Acquire a copy of a given object 2405 * 2406 * Returns a created or reused created object. 2407 */ 2408static xmlXPathObjectPtr 2409xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) 2410{ 2411 if (val == NULL) 2412 return(NULL); 2413 2414 if (XP_HAS_CACHE(ctxt)) { 2415 switch (val->type) { 2416 case XPATH_NODESET: 2417 return(xmlXPathCacheWrapNodeSet(ctxt, 2418 xmlXPathNodeSetMerge(NULL, val->nodesetval))); 2419 case XPATH_STRING: 2420 return(xmlXPathCacheNewString(ctxt, val->stringval)); 2421 case XPATH_BOOLEAN: 2422 return(xmlXPathCacheNewBoolean(ctxt, val->boolval)); 2423 case XPATH_NUMBER: 2424 return(xmlXPathCacheNewFloat(ctxt, val->floatval)); 2425 default: 2426 break; 2427 } 2428 } 2429 return(xmlXPathObjectCopy(val)); 2430} 2431 2432/** 2433 * xmlXPathCacheConvertBoolean: 2434 * @ctxt: the XPath context 2435 * @val: an XPath object 2436 * 2437 * This is the cached version of xmlXPathConvertBoolean(). 2438 * Converts an existing object to its boolean() equivalent 2439 * 2440 * Returns a created or reused object, the old one is freed (or the operation 2441 * is done directly on @val) 2442 */ 2443static xmlXPathObjectPtr 2444xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 2445 xmlXPathObjectPtr ret; 2446 2447 if (val == NULL) 2448 return(xmlXPathCacheNewBoolean(ctxt, 0)); 2449 if (val->type == XPATH_BOOLEAN) 2450 return(val); 2451 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val)); 2452 xmlXPathReleaseObject(ctxt, val); 2453 return(ret); 2454} 2455 2456/** 2457 * xmlXPathCacheConvertNumber: 2458 * @ctxt: the XPath context 2459 * @val: an XPath object 2460 * 2461 * This is the cached version of xmlXPathConvertNumber(). 2462 * Converts an existing object to its number() equivalent 2463 * 2464 * Returns a created or reused object, the old one is freed (or the operation 2465 * is done directly on @val) 2466 */ 2467static xmlXPathObjectPtr 2468xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 2469 xmlXPathObjectPtr ret; 2470 2471 if (val == NULL) 2472 return(xmlXPathCacheNewFloat(ctxt, 0.0)); 2473 if (val->type == XPATH_NUMBER) 2474 return(val); 2475 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val)); 2476 xmlXPathReleaseObject(ctxt, val); 2477 return(ret); 2478} 2479 2480/************************************************************************ 2481 * * 2482 * Parser stacks related functions and macros * 2483 * * 2484 ************************************************************************/ 2485 2486/** 2487 * xmlXPathSetFrame: 2488 * @ctxt: an XPath parser context 2489 * 2490 * Set the callee evaluation frame 2491 * 2492 * Returns the previous frame value to be restored once done 2493 */ 2494static int 2495xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) { 2496 int ret; 2497 2498 if (ctxt == NULL) 2499 return(0); 2500 ret = ctxt->valueFrame; 2501 ctxt->valueFrame = ctxt->valueNr; 2502 return(ret); 2503} 2504 2505/** 2506 * xmlXPathPopFrame: 2507 * @ctxt: an XPath parser context 2508 * @frame: the previous frame value 2509 * 2510 * Remove the callee evaluation frame 2511 */ 2512static void 2513xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) { 2514 if (ctxt == NULL) 2515 return; 2516 if (ctxt->valueNr < ctxt->valueFrame) { 2517 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR); 2518 } 2519 ctxt->valueFrame = frame; 2520} 2521 2522/** 2523 * valuePop: 2524 * @ctxt: an XPath evaluation context 2525 * 2526 * Pops the top XPath object from the value stack 2527 * 2528 * Returns the XPath object just removed 2529 */ 2530xmlXPathObjectPtr 2531valuePop(xmlXPathParserContextPtr ctxt) 2532{ 2533 xmlXPathObjectPtr ret; 2534 2535 if ((ctxt == NULL) || (ctxt->valueNr <= 0)) 2536 return (NULL); 2537 2538 if (ctxt->valueNr <= ctxt->valueFrame) { 2539 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR); 2540 return (NULL); 2541 } 2542 2543 ctxt->valueNr--; 2544 if (ctxt->valueNr > 0) 2545 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1]; 2546 else 2547 ctxt->value = NULL; 2548 ret = ctxt->valueTab[ctxt->valueNr]; 2549 ctxt->valueTab[ctxt->valueNr] = NULL; 2550 return (ret); 2551} 2552/** 2553 * valuePush: 2554 * @ctxt: an XPath evaluation context 2555 * @value: the XPath object 2556 * 2557 * Pushes a new XPath object on top of the value stack 2558 * 2559 * returns the number of items on the value stack 2560 */ 2561int 2562valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value) 2563{ 2564 if ((ctxt == NULL) || (value == NULL)) return(-1); 2565 if (ctxt->valueNr >= ctxt->valueMax) { 2566 xmlXPathObjectPtr *tmp; 2567 2568 if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) { 2569 xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n"); 2570 ctxt->error = XPATH_MEMORY_ERROR; 2571 return (0); 2572 } 2573 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab, 2574 2 * ctxt->valueMax * 2575 sizeof(ctxt->valueTab[0])); 2576 if (tmp == NULL) { 2577 xmlXPathErrMemory(NULL, "pushing value\n"); 2578 ctxt->error = XPATH_MEMORY_ERROR; 2579 return (0); 2580 } 2581 ctxt->valueMax *= 2; 2582 ctxt->valueTab = tmp; 2583 } 2584 ctxt->valueTab[ctxt->valueNr] = value; 2585 ctxt->value = value; 2586 return (ctxt->valueNr++); 2587} 2588 2589/** 2590 * xmlXPathPopBoolean: 2591 * @ctxt: an XPath parser context 2592 * 2593 * Pops a boolean from the stack, handling conversion if needed. 2594 * Check error with #xmlXPathCheckError. 2595 * 2596 * Returns the boolean 2597 */ 2598int 2599xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) { 2600 xmlXPathObjectPtr obj; 2601 int ret; 2602 2603 obj = valuePop(ctxt); 2604 if (obj == NULL) { 2605 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2606 return(0); 2607 } 2608 if (obj->type != XPATH_BOOLEAN) 2609 ret = xmlXPathCastToBoolean(obj); 2610 else 2611 ret = obj->boolval; 2612 xmlXPathReleaseObject(ctxt->context, obj); 2613 return(ret); 2614} 2615 2616/** 2617 * xmlXPathPopNumber: 2618 * @ctxt: an XPath parser context 2619 * 2620 * Pops a number from the stack, handling conversion if needed. 2621 * Check error with #xmlXPathCheckError. 2622 * 2623 * Returns the number 2624 */ 2625double 2626xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) { 2627 xmlXPathObjectPtr obj; 2628 double ret; 2629 2630 obj = valuePop(ctxt); 2631 if (obj == NULL) { 2632 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2633 return(0); 2634 } 2635 if (obj->type != XPATH_NUMBER) 2636 ret = xmlXPathCastToNumber(obj); 2637 else 2638 ret = obj->floatval; 2639 xmlXPathReleaseObject(ctxt->context, obj); 2640 return(ret); 2641} 2642 2643/** 2644 * xmlXPathPopString: 2645 * @ctxt: an XPath parser context 2646 * 2647 * Pops a string from the stack, handling conversion if needed. 2648 * Check error with #xmlXPathCheckError. 2649 * 2650 * Returns the string 2651 */ 2652xmlChar * 2653xmlXPathPopString (xmlXPathParserContextPtr ctxt) { 2654 xmlXPathObjectPtr obj; 2655 xmlChar * ret; 2656 2657 obj = valuePop(ctxt); 2658 if (obj == NULL) { 2659 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2660 return(NULL); 2661 } 2662 ret = xmlXPathCastToString(obj); /* this does required strdup */ 2663 /* TODO: needs refactoring somewhere else */ 2664 if (obj->stringval == ret) 2665 obj->stringval = NULL; 2666 xmlXPathReleaseObject(ctxt->context, obj); 2667 return(ret); 2668} 2669 2670/** 2671 * xmlXPathPopNodeSet: 2672 * @ctxt: an XPath parser context 2673 * 2674 * Pops a node-set from the stack, handling conversion if needed. 2675 * Check error with #xmlXPathCheckError. 2676 * 2677 * Returns the node-set 2678 */ 2679xmlNodeSetPtr 2680xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) { 2681 xmlXPathObjectPtr obj; 2682 xmlNodeSetPtr ret; 2683 2684 if (ctxt == NULL) return(NULL); 2685 if (ctxt->value == NULL) { 2686 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2687 return(NULL); 2688 } 2689 if (!xmlXPathStackIsNodeSet(ctxt)) { 2690 xmlXPathSetTypeError(ctxt); 2691 return(NULL); 2692 } 2693 obj = valuePop(ctxt); 2694 ret = obj->nodesetval; 2695#if 0 2696 /* to fix memory leak of not clearing obj->user */ 2697 if (obj->boolval && obj->user != NULL) 2698 xmlFreeNodeList((xmlNodePtr) obj->user); 2699#endif 2700 obj->nodesetval = NULL; 2701 xmlXPathReleaseObject(ctxt->context, obj); 2702 return(ret); 2703} 2704 2705/** 2706 * xmlXPathPopExternal: 2707 * @ctxt: an XPath parser context 2708 * 2709 * Pops an external object from the stack, handling conversion if needed. 2710 * Check error with #xmlXPathCheckError. 2711 * 2712 * Returns the object 2713 */ 2714void * 2715xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) { 2716 xmlXPathObjectPtr obj; 2717 void * ret; 2718 2719 if ((ctxt == NULL) || (ctxt->value == NULL)) { 2720 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2721 return(NULL); 2722 } 2723 if (ctxt->value->type != XPATH_USERS) { 2724 xmlXPathSetTypeError(ctxt); 2725 return(NULL); 2726 } 2727 obj = valuePop(ctxt); 2728 ret = obj->user; 2729 obj->user = NULL; 2730 xmlXPathReleaseObject(ctxt->context, obj); 2731 return(ret); 2732} 2733 2734/* 2735 * Macros for accessing the content. Those should be used only by the parser, 2736 * and not exported. 2737 * 2738 * Dirty macros, i.e. one need to make assumption on the context to use them 2739 * 2740 * CUR_PTR return the current pointer to the xmlChar to be parsed. 2741 * CUR returns the current xmlChar value, i.e. a 8 bit value 2742 * in ISO-Latin or UTF-8. 2743 * This should be used internally by the parser 2744 * only to compare to ASCII values otherwise it would break when 2745 * running with UTF-8 encoding. 2746 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only 2747 * to compare on ASCII based substring. 2748 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined 2749 * strings within the parser. 2750 * CURRENT Returns the current char value, with the full decoding of 2751 * UTF-8 if we are using this mode. It returns an int. 2752 * NEXT Skip to the next character, this does the proper decoding 2753 * in UTF-8 mode. It also pop-up unfinished entities on the fly. 2754 * It returns the pointer to the current xmlChar. 2755 */ 2756 2757#define CUR (*ctxt->cur) 2758#define SKIP(val) ctxt->cur += (val) 2759#define NXT(val) ctxt->cur[(val)] 2760#define CUR_PTR ctxt->cur 2761#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l) 2762 2763#define COPY_BUF(l,b,i,v) \ 2764 if (l == 1) b[i++] = (xmlChar) v; \ 2765 else i += xmlCopyChar(l,&b[i],v) 2766 2767#define NEXTL(l) ctxt->cur += l 2768 2769#define SKIP_BLANKS \ 2770 while (IS_BLANK_CH(*(ctxt->cur))) NEXT 2771 2772#define CURRENT (*ctxt->cur) 2773#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur) 2774 2775 2776#ifndef DBL_DIG 2777#define DBL_DIG 16 2778#endif 2779#ifndef DBL_EPSILON 2780#define DBL_EPSILON 1E-9 2781#endif 2782 2783#define UPPER_DOUBLE 1E9 2784#define LOWER_DOUBLE 1E-5 2785#define LOWER_DOUBLE_EXP 5 2786 2787#define INTEGER_DIGITS DBL_DIG 2788#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP)) 2789#define EXPONENT_DIGITS (3 + 2) 2790 2791/** 2792 * xmlXPathFormatNumber: 2793 * @number: number to format 2794 * @buffer: output buffer 2795 * @buffersize: size of output buffer 2796 * 2797 * Convert the number into a string representation. 2798 */ 2799static void 2800xmlXPathFormatNumber(double number, char buffer[], int buffersize) 2801{ 2802 switch (xmlXPathIsInf(number)) { 2803 case 1: 2804 if (buffersize > (int)sizeof("Infinity")) 2805 snprintf(buffer, buffersize, "Infinity"); 2806 break; 2807 case -1: 2808 if (buffersize > (int)sizeof("-Infinity")) 2809 snprintf(buffer, buffersize, "-Infinity"); 2810 break; 2811 default: 2812 if (xmlXPathIsNaN(number)) { 2813 if (buffersize > (int)sizeof("NaN")) 2814 snprintf(buffer, buffersize, "NaN"); 2815 } else if (number == 0 && xmlXPathGetSign(number) != 0) { 2816 snprintf(buffer, buffersize, "0"); 2817 } else if (number == ((int) number)) { 2818 char work[30]; 2819 char *ptr, *cur; 2820 int value = (int) number; 2821 2822 ptr = &buffer[0]; 2823 if (value == 0) { 2824 *ptr++ = '0'; 2825 } else { 2826 snprintf(work, 29, "%d", value); 2827 cur = &work[0]; 2828 while ((*cur) && (ptr - buffer < buffersize)) { 2829 *ptr++ = *cur++; 2830 } 2831 } 2832 if (ptr - buffer < buffersize) { 2833 *ptr = 0; 2834 } else if (buffersize > 0) { 2835 ptr--; 2836 *ptr = 0; 2837 } 2838 } else { 2839 /* 2840 For the dimension of work, 2841 DBL_DIG is number of significant digits 2842 EXPONENT is only needed for "scientific notation" 2843 3 is sign, decimal point, and terminating zero 2844 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction 2845 Note that this dimension is slightly (a few characters) 2846 larger than actually necessary. 2847 */ 2848 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP]; 2849 int integer_place, fraction_place; 2850 char *ptr; 2851 char *after_fraction; 2852 double absolute_value; 2853 int size; 2854 2855 absolute_value = fabs(number); 2856 2857 /* 2858 * First choose format - scientific or regular floating point. 2859 * In either case, result is in work, and after_fraction points 2860 * just past the fractional part. 2861 */ 2862 if ( ((absolute_value > UPPER_DOUBLE) || 2863 (absolute_value < LOWER_DOUBLE)) && 2864 (absolute_value != 0.0) ) { 2865 /* Use scientific notation */ 2866 integer_place = DBL_DIG + EXPONENT_DIGITS + 1; 2867 fraction_place = DBL_DIG - 1; 2868 size = snprintf(work, sizeof(work),"%*.*e", 2869 integer_place, fraction_place, number); 2870 while ((size > 0) && (work[size] != 'e')) size--; 2871 2872 } 2873 else { 2874 /* Use regular notation */ 2875 if (absolute_value > 0.0) { 2876 integer_place = (int)log10(absolute_value); 2877 if (integer_place > 0) 2878 fraction_place = DBL_DIG - integer_place - 1; 2879 else 2880 fraction_place = DBL_DIG - integer_place; 2881 } else { 2882 fraction_place = 1; 2883 } 2884 size = snprintf(work, sizeof(work), "%0.*f", 2885 fraction_place, number); 2886 } 2887 2888 /* Remove fractional trailing zeroes */ 2889 after_fraction = work + size; 2890 ptr = after_fraction; 2891 while (*(--ptr) == '0') 2892 ; 2893 if (*ptr != '.') 2894 ptr++; 2895 while ((*ptr++ = *after_fraction++) != 0); 2896 2897 /* Finally copy result back to caller */ 2898 size = strlen(work) + 1; 2899 if (size > buffersize) { 2900 work[buffersize - 1] = 0; 2901 size = buffersize; 2902 } 2903 memmove(buffer, work, size); 2904 } 2905 break; 2906 } 2907} 2908 2909 2910/************************************************************************ 2911 * * 2912 * Routines to handle NodeSets * 2913 * * 2914 ************************************************************************/ 2915 2916/** 2917 * xmlXPathOrderDocElems: 2918 * @doc: an input document 2919 * 2920 * Call this routine to speed up XPath computation on static documents. 2921 * This stamps all the element nodes with the document order 2922 * Like for line information, the order is kept in the element->content 2923 * field, the value stored is actually - the node number (starting at -1) 2924 * to be able to differentiate from line numbers. 2925 * 2926 * Returns the number of elements found in the document or -1 in case 2927 * of error. 2928 */ 2929long 2930xmlXPathOrderDocElems(xmlDocPtr doc) { 2931 long count = 0; 2932 xmlNodePtr cur; 2933 2934 if (doc == NULL) 2935 return(-1); 2936 cur = doc->children; 2937 while (cur != NULL) { 2938 if (cur->type == XML_ELEMENT_NODE) { 2939 cur->content = (void *) (-(++count)); 2940 if (cur->children != NULL) { 2941 cur = cur->children; 2942 continue; 2943 } 2944 } 2945 if (cur->next != NULL) { 2946 cur = cur->next; 2947 continue; 2948 } 2949 do { 2950 cur = cur->parent; 2951 if (cur == NULL) 2952 break; 2953 if (cur == (xmlNodePtr) doc) { 2954 cur = NULL; 2955 break; 2956 } 2957 if (cur->next != NULL) { 2958 cur = cur->next; 2959 break; 2960 } 2961 } while (cur != NULL); 2962 } 2963 return(count); 2964} 2965 2966/** 2967 * xmlXPathCmpNodes: 2968 * @node1: the first node 2969 * @node2: the second node 2970 * 2971 * Compare two nodes w.r.t document order 2972 * 2973 * Returns -2 in case of error 1 if first point < second point, 0 if 2974 * it's the same node, -1 otherwise 2975 */ 2976int 2977xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) { 2978 int depth1, depth2; 2979 int attr1 = 0, attr2 = 0; 2980 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL; 2981 xmlNodePtr cur, root; 2982 2983 if ((node1 == NULL) || (node2 == NULL)) 2984 return(-2); 2985 /* 2986 * a couple of optimizations which will avoid computations in most cases 2987 */ 2988 if (node1 == node2) /* trivial case */ 2989 return(0); 2990 if (node1->type == XML_ATTRIBUTE_NODE) { 2991 attr1 = 1; 2992 attrNode1 = node1; 2993 node1 = node1->parent; 2994 } 2995 if (node2->type == XML_ATTRIBUTE_NODE) { 2996 attr2 = 1; 2997 attrNode2 = node2; 2998 node2 = node2->parent; 2999 } 3000 if (node1 == node2) { 3001 if (attr1 == attr2) { 3002 /* not required, but we keep attributes in order */ 3003 if (attr1 != 0) { 3004 cur = attrNode2->prev; 3005 while (cur != NULL) { 3006 if (cur == attrNode1) 3007 return (1); 3008 cur = cur->prev; 3009 } 3010 return (-1); 3011 } 3012 return(0); 3013 } 3014 if (attr2 == 1) 3015 return(1); 3016 return(-1); 3017 } 3018 if ((node1->type == XML_NAMESPACE_DECL) || 3019 (node2->type == XML_NAMESPACE_DECL)) 3020 return(1); 3021 if (node1 == node2->prev) 3022 return(1); 3023 if (node1 == node2->next) 3024 return(-1); 3025 3026 /* 3027 * Speedup using document order if availble. 3028 */ 3029 if ((node1->type == XML_ELEMENT_NODE) && 3030 (node2->type == XML_ELEMENT_NODE) && 3031 (0 > (long) node1->content) && 3032 (0 > (long) node2->content) && 3033 (node1->doc == node2->doc)) { 3034 long l1, l2; 3035 3036 l1 = -((long) node1->content); 3037 l2 = -((long) node2->content); 3038 if (l1 < l2) 3039 return(1); 3040 if (l1 > l2) 3041 return(-1); 3042 } 3043 3044 /* 3045 * compute depth to root 3046 */ 3047 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) { 3048 if (cur == node1) 3049 return(1); 3050 depth2++; 3051 } 3052 root = cur; 3053 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) { 3054 if (cur == node2) 3055 return(-1); 3056 depth1++; 3057 } 3058 /* 3059 * Distinct document (or distinct entities :-( ) case. 3060 */ 3061 if (root != cur) { 3062 return(-2); 3063 } 3064 /* 3065 * get the nearest common ancestor. 3066 */ 3067 while (depth1 > depth2) { 3068 depth1--; 3069 node1 = node1->parent; 3070 } 3071 while (depth2 > depth1) { 3072 depth2--; 3073 node2 = node2->parent; 3074 } 3075 while (node1->parent != node2->parent) { 3076 node1 = node1->parent; 3077 node2 = node2->parent; 3078 /* should not happen but just in case ... */ 3079 if ((node1 == NULL) || (node2 == NULL)) 3080 return(-2); 3081 } 3082 /* 3083 * Find who's first. 3084 */ 3085 if (node1 == node2->prev) 3086 return(1); 3087 if (node1 == node2->next) 3088 return(-1); 3089 /* 3090 * Speedup using document order if availble. 3091 */ 3092 if ((node1->type == XML_ELEMENT_NODE) && 3093 (node2->type == XML_ELEMENT_NODE) && 3094 (0 > (long) node1->content) && 3095 (0 > (long) node2->content) && 3096 (node1->doc == node2->doc)) { 3097 long l1, l2; 3098 3099 l1 = -((long) node1->content); 3100 l2 = -((long) node2->content); 3101 if (l1 < l2) 3102 return(1); 3103 if (l1 > l2) 3104 return(-1); 3105 } 3106 3107 for (cur = node1->next;cur != NULL;cur = cur->next) 3108 if (cur == node2) 3109 return(1); 3110 return(-1); /* assume there is no sibling list corruption */ 3111} 3112 3113#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 3114/** 3115 * xmlXPathCmpNodesExt: 3116 * @node1: the first node 3117 * @node2: the second node 3118 * 3119 * Compare two nodes w.r.t document order. 3120 * This one is optimized for handling of non-element nodes. 3121 * 3122 * Returns -2 in case of error 1 if first point < second point, 0 if 3123 * it's the same node, -1 otherwise 3124 */ 3125static int 3126xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) { 3127 int depth1, depth2; 3128 int misc = 0, precedence1 = 0, precedence2 = 0; 3129 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL; 3130 xmlNodePtr cur, root; 3131 long l1, l2; 3132 3133 if ((node1 == NULL) || (node2 == NULL)) 3134 return(-2); 3135 3136 if (node1 == node2) 3137 return(0); 3138 3139 /* 3140 * a couple of optimizations which will avoid computations in most cases 3141 */ 3142 switch (node1->type) { 3143 case XML_ELEMENT_NODE: 3144 if (node2->type == XML_ELEMENT_NODE) { 3145 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */ 3146 (0 > (long) node2->content) && 3147 (node1->doc == node2->doc)) 3148 { 3149 l1 = -((long) node1->content); 3150 l2 = -((long) node2->content); 3151 if (l1 < l2) 3152 return(1); 3153 if (l1 > l2) 3154 return(-1); 3155 } else 3156 goto turtle_comparison; 3157 } 3158 break; 3159 case XML_ATTRIBUTE_NODE: 3160 precedence1 = 1; /* element is owner */ 3161 miscNode1 = node1; 3162 node1 = node1->parent; 3163 misc = 1; 3164 break; 3165 case XML_TEXT_NODE: 3166 case XML_CDATA_SECTION_NODE: 3167 case XML_COMMENT_NODE: 3168 case XML_PI_NODE: { 3169 miscNode1 = node1; 3170 /* 3171 * Find nearest element node. 3172 */ 3173 if (node1->prev != NULL) { 3174 do { 3175 node1 = node1->prev; 3176 if (node1->type == XML_ELEMENT_NODE) { 3177 precedence1 = 3; /* element in prev-sibl axis */ 3178 break; 3179 } 3180 if (node1->prev == NULL) { 3181 precedence1 = 2; /* element is parent */ 3182 /* 3183 * URGENT TODO: Are there any cases, where the 3184 * parent of such a node is not an element node? 3185 */ 3186 node1 = node1->parent; 3187 break; 3188 } 3189 } while (1); 3190 } else { 3191 precedence1 = 2; /* element is parent */ 3192 node1 = node1->parent; 3193 } 3194 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) || 3195 (0 <= (long) node1->content)) { 3196 /* 3197 * Fallback for whatever case. 3198 */ 3199 node1 = miscNode1; 3200 precedence1 = 0; 3201 } else 3202 misc = 1; 3203 } 3204 break; 3205 case XML_NAMESPACE_DECL: 3206 /* 3207 * TODO: why do we return 1 for namespace nodes? 3208 */ 3209 return(1); 3210 default: 3211 break; 3212 } 3213 switch (node2->type) { 3214 case XML_ELEMENT_NODE: 3215 break; 3216 case XML_ATTRIBUTE_NODE: 3217 precedence2 = 1; /* element is owner */ 3218 miscNode2 = node2; 3219 node2 = node2->parent; 3220 misc = 1; 3221 break; 3222 case XML_TEXT_NODE: 3223 case XML_CDATA_SECTION_NODE: 3224 case XML_COMMENT_NODE: 3225 case XML_PI_NODE: { 3226 miscNode2 = node2; 3227 if (node2->prev != NULL) { 3228 do { 3229 node2 = node2->prev; 3230 if (node2->type == XML_ELEMENT_NODE) { 3231 precedence2 = 3; /* element in prev-sibl axis */ 3232 break; 3233 } 3234 if (node2->prev == NULL) { 3235 precedence2 = 2; /* element is parent */ 3236 node2 = node2->parent; 3237 break; 3238 } 3239 } while (1); 3240 } else { 3241 precedence2 = 2; /* element is parent */ 3242 node2 = node2->parent; 3243 } 3244 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) || 3245 (0 <= (long) node1->content)) 3246 { 3247 node2 = miscNode2; 3248 precedence2 = 0; 3249 } else 3250 misc = 1; 3251 } 3252 break; 3253 case XML_NAMESPACE_DECL: 3254 return(1); 3255 default: 3256 break; 3257 } 3258 if (misc) { 3259 if (node1 == node2) { 3260 if (precedence1 == precedence2) { 3261 /* 3262 * The ugly case; but normally there aren't many 3263 * adjacent non-element nodes around. 3264 */ 3265 cur = miscNode2->prev; 3266 while (cur != NULL) { 3267 if (cur == miscNode1) 3268 return(1); 3269 if (cur->type == XML_ELEMENT_NODE) 3270 return(-1); 3271 cur = cur->prev; 3272 } 3273 return (-1); 3274 } else { 3275 /* 3276 * Evaluate based on higher precedence wrt to the element. 3277 * TODO: This assumes attributes are sorted before content. 3278 * Is this 100% correct? 3279 */ 3280 if (precedence1 < precedence2) 3281 return(1); 3282 else 3283 return(-1); 3284 } 3285 } 3286 /* 3287 * Special case: One of the helper-elements is contained by the other. 3288 * <foo> 3289 * <node2> 3290 * <node1>Text-1(precedence1 == 2)</node1> 3291 * </node2> 3292 * Text-6(precedence2 == 3) 3293 * </foo> 3294 */ 3295 if ((precedence2 == 3) && (precedence1 > 1)) { 3296 cur = node1->parent; 3297 while (cur) { 3298 if (cur == node2) 3299 return(1); 3300 cur = cur->parent; 3301 } 3302 } 3303 if ((precedence1 == 3) && (precedence2 > 1)) { 3304 cur = node2->parent; 3305 while (cur) { 3306 if (cur == node1) 3307 return(-1); 3308 cur = cur->parent; 3309 } 3310 } 3311 } 3312 3313 /* 3314 * Speedup using document order if availble. 3315 */ 3316 if ((node1->type == XML_ELEMENT_NODE) && 3317 (node2->type == XML_ELEMENT_NODE) && 3318 (0 > (long) node1->content) && 3319 (0 > (long) node2->content) && 3320 (node1->doc == node2->doc)) { 3321 3322 l1 = -((long) node1->content); 3323 l2 = -((long) node2->content); 3324 if (l1 < l2) 3325 return(1); 3326 if (l1 > l2) 3327 return(-1); 3328 } 3329 3330turtle_comparison: 3331 3332 if (node1 == node2->prev) 3333 return(1); 3334 if (node1 == node2->next) 3335 return(-1); 3336 /* 3337 * compute depth to root 3338 */ 3339 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) { 3340 if (cur == node1) 3341 return(1); 3342 depth2++; 3343 } 3344 root = cur; 3345 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) { 3346 if (cur == node2) 3347 return(-1); 3348 depth1++; 3349 } 3350 /* 3351 * Distinct document (or distinct entities :-( ) case. 3352 */ 3353 if (root != cur) { 3354 return(-2); 3355 } 3356 /* 3357 * get the nearest common ancestor. 3358 */ 3359 while (depth1 > depth2) { 3360 depth1--; 3361 node1 = node1->parent; 3362 } 3363 while (depth2 > depth1) { 3364 depth2--; 3365 node2 = node2->parent; 3366 } 3367 while (node1->parent != node2->parent) { 3368 node1 = node1->parent; 3369 node2 = node2->parent; 3370 /* should not happen but just in case ... */ 3371 if ((node1 == NULL) || (node2 == NULL)) 3372 return(-2); 3373 } 3374 /* 3375 * Find who's first. 3376 */ 3377 if (node1 == node2->prev) 3378 return(1); 3379 if (node1 == node2->next) 3380 return(-1); 3381 /* 3382 * Speedup using document order if availble. 3383 */ 3384 if ((node1->type == XML_ELEMENT_NODE) && 3385 (node2->type == XML_ELEMENT_NODE) && 3386 (0 > (long) node1->content) && 3387 (0 > (long) node2->content) && 3388 (node1->doc == node2->doc)) { 3389 3390 l1 = -((long) node1->content); 3391 l2 = -((long) node2->content); 3392 if (l1 < l2) 3393 return(1); 3394 if (l1 > l2) 3395 return(-1); 3396 } 3397 3398 for (cur = node1->next;cur != NULL;cur = cur->next) 3399 if (cur == node2) 3400 return(1); 3401 return(-1); /* assume there is no sibling list corruption */ 3402} 3403#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */ 3404 3405/** 3406 * xmlXPathNodeSetSort: 3407 * @set: the node set 3408 * 3409 * Sort the node set in document order 3410 */ 3411void 3412xmlXPathNodeSetSort(xmlNodeSetPtr set) { 3413#ifndef WITH_TIM_SORT 3414 int i, j, incr, len; 3415 xmlNodePtr tmp; 3416#endif 3417 3418 if (set == NULL) 3419 return; 3420 3421#ifndef WITH_TIM_SORT 3422 /* 3423 * Use the old Shell's sort implementation to sort the node-set 3424 * Timsort ought to be quite faster 3425 */ 3426 len = set->nodeNr; 3427 for (incr = len / 2; incr > 0; incr /= 2) { 3428 for (i = incr; i < len; i++) { 3429 j = i - incr; 3430 while (j >= 0) { 3431#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 3432 if (xmlXPathCmpNodesExt(set->nodeTab[j], 3433 set->nodeTab[j + incr]) == -1) 3434#else 3435 if (xmlXPathCmpNodes(set->nodeTab[j], 3436 set->nodeTab[j + incr]) == -1) 3437#endif 3438 { 3439 tmp = set->nodeTab[j]; 3440 set->nodeTab[j] = set->nodeTab[j + incr]; 3441 set->nodeTab[j + incr] = tmp; 3442 j -= incr; 3443 } else 3444 break; 3445 } 3446 } 3447 } 3448#else /* WITH_TIM_SORT */ 3449 libxml_domnode_tim_sort(set->nodeTab, set->nodeNr); 3450#endif /* WITH_TIM_SORT */ 3451} 3452 3453#define XML_NODESET_DEFAULT 10 3454/** 3455 * xmlXPathNodeSetDupNs: 3456 * @node: the parent node of the namespace XPath node 3457 * @ns: the libxml namespace declaration node. 3458 * 3459 * Namespace node in libxml don't match the XPath semantic. In a node set 3460 * the namespace nodes are duplicated and the next pointer is set to the 3461 * parent node in the XPath semantic. 3462 * 3463 * Returns the newly created object. 3464 */ 3465static xmlNodePtr 3466xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) { 3467 xmlNsPtr cur; 3468 3469 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) 3470 return(NULL); 3471 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) 3472 return((xmlNodePtr) ns); 3473 3474 /* 3475 * Allocate a new Namespace and fill the fields. 3476 */ 3477 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); 3478 if (cur == NULL) { 3479 xmlXPathErrMemory(NULL, "duplicating namespace\n"); 3480 return(NULL); 3481 } 3482 memset(cur, 0, sizeof(xmlNs)); 3483 cur->type = XML_NAMESPACE_DECL; 3484 if (ns->href != NULL) 3485 cur->href = xmlStrdup(ns->href); 3486 if (ns->prefix != NULL) 3487 cur->prefix = xmlStrdup(ns->prefix); 3488 cur->next = (xmlNsPtr) node; 3489 return((xmlNodePtr) cur); 3490} 3491 3492/** 3493 * xmlXPathNodeSetFreeNs: 3494 * @ns: the XPath namespace node found in a nodeset. 3495 * 3496 * Namespace nodes in libxml don't match the XPath semantic. In a node set 3497 * the namespace nodes are duplicated and the next pointer is set to the 3498 * parent node in the XPath semantic. Check if such a node needs to be freed 3499 */ 3500void 3501xmlXPathNodeSetFreeNs(xmlNsPtr ns) { 3502 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) 3503 return; 3504 3505 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) { 3506 if (ns->href != NULL) 3507 xmlFree((xmlChar *)ns->href); 3508 if (ns->prefix != NULL) 3509 xmlFree((xmlChar *)ns->prefix); 3510 xmlFree(ns); 3511 } 3512} 3513 3514/** 3515 * xmlXPathNodeSetCreate: 3516 * @val: an initial xmlNodePtr, or NULL 3517 * 3518 * Create a new xmlNodeSetPtr of type double and of value @val 3519 * 3520 * Returns the newly created object. 3521 */ 3522xmlNodeSetPtr 3523xmlXPathNodeSetCreate(xmlNodePtr val) { 3524 xmlNodeSetPtr ret; 3525 3526 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet)); 3527 if (ret == NULL) { 3528 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3529 return(NULL); 3530 } 3531 memset(ret, 0 , (size_t) sizeof(xmlNodeSet)); 3532 if (val != NULL) { 3533 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3534 sizeof(xmlNodePtr)); 3535 if (ret->nodeTab == NULL) { 3536 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3537 xmlFree(ret); 3538 return(NULL); 3539 } 3540 memset(ret->nodeTab, 0 , 3541 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3542 ret->nodeMax = XML_NODESET_DEFAULT; 3543 if (val->type == XML_NAMESPACE_DECL) { 3544 xmlNsPtr ns = (xmlNsPtr) val; 3545 3546 ret->nodeTab[ret->nodeNr++] = 3547 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3548 } else 3549 ret->nodeTab[ret->nodeNr++] = val; 3550 } 3551 return(ret); 3552} 3553 3554/** 3555 * xmlXPathNodeSetCreateSize: 3556 * @size: the initial size of the set 3557 * 3558 * Create a new xmlNodeSetPtr of type double and of value @val 3559 * 3560 * Returns the newly created object. 3561 */ 3562static xmlNodeSetPtr 3563xmlXPathNodeSetCreateSize(int size) { 3564 xmlNodeSetPtr ret; 3565 3566 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet)); 3567 if (ret == NULL) { 3568 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3569 return(NULL); 3570 } 3571 memset(ret, 0 , (size_t) sizeof(xmlNodeSet)); 3572 if (size < XML_NODESET_DEFAULT) 3573 size = XML_NODESET_DEFAULT; 3574 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr)); 3575 if (ret->nodeTab == NULL) { 3576 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3577 xmlFree(ret); 3578 return(NULL); 3579 } 3580 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr)); 3581 ret->nodeMax = size; 3582 return(ret); 3583} 3584 3585/** 3586 * xmlXPathNodeSetContains: 3587 * @cur: the node-set 3588 * @val: the node 3589 * 3590 * checks whether @cur contains @val 3591 * 3592 * Returns true (1) if @cur contains @val, false (0) otherwise 3593 */ 3594int 3595xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) { 3596 int i; 3597 3598 if ((cur == NULL) || (val == NULL)) return(0); 3599 if (val->type == XML_NAMESPACE_DECL) { 3600 for (i = 0; i < cur->nodeNr; i++) { 3601 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) { 3602 xmlNsPtr ns1, ns2; 3603 3604 ns1 = (xmlNsPtr) val; 3605 ns2 = (xmlNsPtr) cur->nodeTab[i]; 3606 if (ns1 == ns2) 3607 return(1); 3608 if ((ns1->next != NULL) && (ns2->next == ns1->next) && 3609 (xmlStrEqual(ns1->prefix, ns2->prefix))) 3610 return(1); 3611 } 3612 } 3613 } else { 3614 for (i = 0; i < cur->nodeNr; i++) { 3615 if (cur->nodeTab[i] == val) 3616 return(1); 3617 } 3618 } 3619 return(0); 3620} 3621 3622/** 3623 * xmlXPathNodeSetAddNs: 3624 * @cur: the initial node set 3625 * @node: the hosting node 3626 * @ns: a the namespace node 3627 * 3628 * add a new namespace node to an existing NodeSet 3629 * 3630 * Returns 0 in case of success and -1 in case of error 3631 */ 3632int 3633xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) { 3634 int i; 3635 3636 3637 if ((cur == NULL) || (ns == NULL) || (node == NULL) || 3638 (ns->type != XML_NAMESPACE_DECL) || 3639 (node->type != XML_ELEMENT_NODE)) 3640 return(-1); 3641 3642 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3643 /* 3644 * prevent duplicates 3645 */ 3646 for (i = 0;i < cur->nodeNr;i++) { 3647 if ((cur->nodeTab[i] != NULL) && 3648 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) && 3649 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) && 3650 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix))) 3651 return(0); 3652 } 3653 3654 /* 3655 * grow the nodeTab if needed 3656 */ 3657 if (cur->nodeMax == 0) { 3658 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3659 sizeof(xmlNodePtr)); 3660 if (cur->nodeTab == NULL) { 3661 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3662 return(-1); 3663 } 3664 memset(cur->nodeTab, 0 , 3665 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3666 cur->nodeMax = XML_NODESET_DEFAULT; 3667 } else if (cur->nodeNr == cur->nodeMax) { 3668 xmlNodePtr *temp; 3669 3670 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 3671 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n"); 3672 return(-1); 3673 } 3674 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 * 3675 sizeof(xmlNodePtr)); 3676 if (temp == NULL) { 3677 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3678 return(-1); 3679 } 3680 cur->nodeMax *= 2; 3681 cur->nodeTab = temp; 3682 } 3683 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns); 3684 return(0); 3685} 3686 3687/** 3688 * xmlXPathNodeSetAdd: 3689 * @cur: the initial node set 3690 * @val: a new xmlNodePtr 3691 * 3692 * add a new xmlNodePtr to an existing NodeSet 3693 * 3694 * Returns 0 in case of success, and -1 in case of error 3695 */ 3696int 3697xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) { 3698 int i; 3699 3700 if ((cur == NULL) || (val == NULL)) return(-1); 3701 3702 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3703 /* 3704 * prevent duplcates 3705 */ 3706 for (i = 0;i < cur->nodeNr;i++) 3707 if (cur->nodeTab[i] == val) return(0); 3708 3709 /* 3710 * grow the nodeTab if needed 3711 */ 3712 if (cur->nodeMax == 0) { 3713 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3714 sizeof(xmlNodePtr)); 3715 if (cur->nodeTab == NULL) { 3716 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3717 return(-1); 3718 } 3719 memset(cur->nodeTab, 0 , 3720 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3721 cur->nodeMax = XML_NODESET_DEFAULT; 3722 } else if (cur->nodeNr == cur->nodeMax) { 3723 xmlNodePtr *temp; 3724 3725 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 3726 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n"); 3727 return(-1); 3728 } 3729 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 * 3730 sizeof(xmlNodePtr)); 3731 if (temp == NULL) { 3732 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3733 return(-1); 3734 } 3735 cur->nodeMax *= 2; 3736 cur->nodeTab = temp; 3737 } 3738 if (val->type == XML_NAMESPACE_DECL) { 3739 xmlNsPtr ns = (xmlNsPtr) val; 3740 3741 cur->nodeTab[cur->nodeNr++] = 3742 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3743 } else 3744 cur->nodeTab[cur->nodeNr++] = val; 3745 return(0); 3746} 3747 3748/** 3749 * xmlXPathNodeSetAddUnique: 3750 * @cur: the initial node set 3751 * @val: a new xmlNodePtr 3752 * 3753 * add a new xmlNodePtr to an existing NodeSet, optimized version 3754 * when we are sure the node is not already in the set. 3755 * 3756 * Returns 0 in case of success and -1 in case of failure 3757 */ 3758int 3759xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) { 3760 if ((cur == NULL) || (val == NULL)) return(-1); 3761 3762 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3763 /* 3764 * grow the nodeTab if needed 3765 */ 3766 if (cur->nodeMax == 0) { 3767 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3768 sizeof(xmlNodePtr)); 3769 if (cur->nodeTab == NULL) { 3770 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3771 return(-1); 3772 } 3773 memset(cur->nodeTab, 0 , 3774 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3775 cur->nodeMax = XML_NODESET_DEFAULT; 3776 } else if (cur->nodeNr == cur->nodeMax) { 3777 xmlNodePtr *temp; 3778 3779 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 3780 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n"); 3781 return(-1); 3782 } 3783 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 * 3784 sizeof(xmlNodePtr)); 3785 if (temp == NULL) { 3786 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3787 return(-1); 3788 } 3789 cur->nodeTab = temp; 3790 cur->nodeMax *= 2; 3791 } 3792 if (val->type == XML_NAMESPACE_DECL) { 3793 xmlNsPtr ns = (xmlNsPtr) val; 3794 3795 cur->nodeTab[cur->nodeNr++] = 3796 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3797 } else 3798 cur->nodeTab[cur->nodeNr++] = val; 3799 return(0); 3800} 3801 3802/** 3803 * xmlXPathNodeSetMerge: 3804 * @val1: the first NodeSet or NULL 3805 * @val2: the second NodeSet 3806 * 3807 * Merges two nodesets, all nodes from @val2 are added to @val1 3808 * if @val1 is NULL, a new set is created and copied from @val2 3809 * 3810 * Returns @val1 once extended or NULL in case of error. 3811 */ 3812xmlNodeSetPtr 3813xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) { 3814 int i, j, initNr, skip; 3815 xmlNodePtr n1, n2; 3816 3817 if (val2 == NULL) return(val1); 3818 if (val1 == NULL) { 3819 val1 = xmlXPathNodeSetCreate(NULL); 3820 if (val1 == NULL) 3821 return (NULL); 3822#if 0 3823 /* 3824 * TODO: The optimization won't work in every case, since 3825 * those nasty namespace nodes need to be added with 3826 * xmlXPathNodeSetDupNs() to the set; thus a pure 3827 * memcpy is not possible. 3828 * If there was a flag on the nodesetval, indicating that 3829 * some temporary nodes are in, that would be helpfull. 3830 */ 3831 /* 3832 * Optimization: Create an equally sized node-set 3833 * and memcpy the content. 3834 */ 3835 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr); 3836 if (val1 == NULL) 3837 return(NULL); 3838 if (val2->nodeNr != 0) { 3839 if (val2->nodeNr == 1) 3840 *(val1->nodeTab) = *(val2->nodeTab); 3841 else { 3842 memcpy(val1->nodeTab, val2->nodeTab, 3843 val2->nodeNr * sizeof(xmlNodePtr)); 3844 } 3845 val1->nodeNr = val2->nodeNr; 3846 } 3847 return(val1); 3848#endif 3849 } 3850 3851 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3852 initNr = val1->nodeNr; 3853 3854 for (i = 0;i < val2->nodeNr;i++) { 3855 n2 = val2->nodeTab[i]; 3856 /* 3857 * check against duplicates 3858 */ 3859 skip = 0; 3860 for (j = 0; j < initNr; j++) { 3861 n1 = val1->nodeTab[j]; 3862 if (n1 == n2) { 3863 skip = 1; 3864 break; 3865 } else if ((n1->type == XML_NAMESPACE_DECL) && 3866 (n2->type == XML_NAMESPACE_DECL)) { 3867 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) && 3868 (xmlStrEqual(((xmlNsPtr) n1)->prefix, 3869 ((xmlNsPtr) n2)->prefix))) 3870 { 3871 skip = 1; 3872 break; 3873 } 3874 } 3875 } 3876 if (skip) 3877 continue; 3878 3879 /* 3880 * grow the nodeTab if needed 3881 */ 3882 if (val1->nodeMax == 0) { 3883 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3884 sizeof(xmlNodePtr)); 3885 if (val1->nodeTab == NULL) { 3886 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3887 return(NULL); 3888 } 3889 memset(val1->nodeTab, 0 , 3890 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3891 val1->nodeMax = XML_NODESET_DEFAULT; 3892 } else if (val1->nodeNr == val1->nodeMax) { 3893 xmlNodePtr *temp; 3894 3895 if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 3896 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n"); 3897 return(NULL); 3898 } 3899 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 * 3900 sizeof(xmlNodePtr)); 3901 if (temp == NULL) { 3902 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3903 return(NULL); 3904 } 3905 val1->nodeTab = temp; 3906 val1->nodeMax *= 2; 3907 } 3908 if (n2->type == XML_NAMESPACE_DECL) { 3909 xmlNsPtr ns = (xmlNsPtr) n2; 3910 3911 val1->nodeTab[val1->nodeNr++] = 3912 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3913 } else 3914 val1->nodeTab[val1->nodeNr++] = n2; 3915 } 3916 3917 return(val1); 3918} 3919 3920 3921/** 3922 * xmlXPathNodeSetMergeAndClear: 3923 * @set1: the first NodeSet or NULL 3924 * @set2: the second NodeSet 3925 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes 3926 * 3927 * Merges two nodesets, all nodes from @set2 are added to @set1 3928 * if @set1 is NULL, a new set is created and copied from @set2. 3929 * Checks for duplicate nodes. Clears set2. 3930 * 3931 * Returns @set1 once extended or NULL in case of error. 3932 */ 3933static xmlNodeSetPtr 3934xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2, 3935 int hasNullEntries) 3936{ 3937 if ((set1 == NULL) && (hasNullEntries == 0)) { 3938 /* 3939 * Note that doing a memcpy of the list, namespace nodes are 3940 * just assigned to set1, since set2 is cleared anyway. 3941 */ 3942 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr); 3943 if (set1 == NULL) 3944 return(NULL); 3945 if (set2->nodeNr != 0) { 3946 memcpy(set1->nodeTab, set2->nodeTab, 3947 set2->nodeNr * sizeof(xmlNodePtr)); 3948 set1->nodeNr = set2->nodeNr; 3949 } 3950 } else { 3951 int i, j, initNbSet1; 3952 xmlNodePtr n1, n2; 3953 3954 if (set1 == NULL) 3955 set1 = xmlXPathNodeSetCreate(NULL); 3956 if (set1 == NULL) 3957 return (NULL); 3958 3959 initNbSet1 = set1->nodeNr; 3960 for (i = 0;i < set2->nodeNr;i++) { 3961 n2 = set2->nodeTab[i]; 3962 /* 3963 * Skip NULLed entries. 3964 */ 3965 if (n2 == NULL) 3966 continue; 3967 /* 3968 * Skip duplicates. 3969 */ 3970 for (j = 0; j < initNbSet1; j++) { 3971 n1 = set1->nodeTab[j]; 3972 if (n1 == n2) { 3973 goto skip_node; 3974 } else if ((n1->type == XML_NAMESPACE_DECL) && 3975 (n2->type == XML_NAMESPACE_DECL)) 3976 { 3977 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) && 3978 (xmlStrEqual(((xmlNsPtr) n1)->prefix, 3979 ((xmlNsPtr) n2)->prefix))) 3980 { 3981 /* 3982 * Free the namespace node. 3983 */ 3984 set2->nodeTab[i] = NULL; 3985 xmlXPathNodeSetFreeNs((xmlNsPtr) n2); 3986 goto skip_node; 3987 } 3988 } 3989 } 3990 /* 3991 * grow the nodeTab if needed 3992 */ 3993 if (set1->nodeMax == 0) { 3994 set1->nodeTab = (xmlNodePtr *) xmlMalloc( 3995 XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); 3996 if (set1->nodeTab == NULL) { 3997 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3998 return(NULL); 3999 } 4000 memset(set1->nodeTab, 0, 4001 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 4002 set1->nodeMax = XML_NODESET_DEFAULT; 4003 } else if (set1->nodeNr >= set1->nodeMax) { 4004 xmlNodePtr *temp; 4005 4006 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 4007 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n"); 4008 return(NULL); 4009 } 4010 temp = (xmlNodePtr *) xmlRealloc( 4011 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr)); 4012 if (temp == NULL) { 4013 xmlXPathErrMemory(NULL, "merging nodeset\n"); 4014 return(NULL); 4015 } 4016 set1->nodeTab = temp; 4017 set1->nodeMax *= 2; 4018 } 4019 if (n2->type == XML_NAMESPACE_DECL) { 4020 xmlNsPtr ns = (xmlNsPtr) n2; 4021 4022 set1->nodeTab[set1->nodeNr++] = 4023 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 4024 } else 4025 set1->nodeTab[set1->nodeNr++] = n2; 4026skip_node: 4027 {} 4028 } 4029 } 4030 set2->nodeNr = 0; 4031 return(set1); 4032} 4033 4034/** 4035 * xmlXPathNodeSetMergeAndClearNoDupls: 4036 * @set1: the first NodeSet or NULL 4037 * @set2: the second NodeSet 4038 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes 4039 * 4040 * Merges two nodesets, all nodes from @set2 are added to @set1 4041 * if @set1 is NULL, a new set is created and copied from @set2. 4042 * Doesn't chack for duplicate nodes. Clears set2. 4043 * 4044 * Returns @set1 once extended or NULL in case of error. 4045 */ 4046static xmlNodeSetPtr 4047xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2, 4048 int hasNullEntries) 4049{ 4050 if (set2 == NULL) 4051 return(set1); 4052 if ((set1 == NULL) && (hasNullEntries == 0)) { 4053 /* 4054 * Note that doing a memcpy of the list, namespace nodes are 4055 * just assigned to set1, since set2 is cleared anyway. 4056 */ 4057 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr); 4058 if (set1 == NULL) 4059 return(NULL); 4060 if (set2->nodeNr != 0) { 4061 memcpy(set1->nodeTab, set2->nodeTab, 4062 set2->nodeNr * sizeof(xmlNodePtr)); 4063 set1->nodeNr = set2->nodeNr; 4064 } 4065 } else { 4066 int i; 4067 xmlNodePtr n2; 4068 4069 if (set1 == NULL) 4070 set1 = xmlXPathNodeSetCreate(NULL); 4071 if (set1 == NULL) 4072 return (NULL); 4073 4074 for (i = 0;i < set2->nodeNr;i++) { 4075 n2 = set2->nodeTab[i]; 4076 /* 4077 * Skip NULLed entries. 4078 */ 4079 if (n2 == NULL) 4080 continue; 4081 if (set1->nodeMax == 0) { 4082 set1->nodeTab = (xmlNodePtr *) xmlMalloc( 4083 XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); 4084 if (set1->nodeTab == NULL) { 4085 xmlXPathErrMemory(NULL, "merging nodeset\n"); 4086 return(NULL); 4087 } 4088 memset(set1->nodeTab, 0, 4089 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 4090 set1->nodeMax = XML_NODESET_DEFAULT; 4091 } else if (set1->nodeNr >= set1->nodeMax) { 4092 xmlNodePtr *temp; 4093 4094 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 4095 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n"); 4096 return(NULL); 4097 } 4098 temp = (xmlNodePtr *) xmlRealloc( 4099 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr)); 4100 if (temp == NULL) { 4101 xmlXPathErrMemory(NULL, "merging nodeset\n"); 4102 return(NULL); 4103 } 4104 set1->nodeTab = temp; 4105 set1->nodeMax *= 2; 4106 } 4107 set1->nodeTab[set1->nodeNr++] = n2; 4108 } 4109 } 4110 set2->nodeNr = 0; 4111 return(set1); 4112} 4113 4114/** 4115 * xmlXPathNodeSetDel: 4116 * @cur: the initial node set 4117 * @val: an xmlNodePtr 4118 * 4119 * Removes an xmlNodePtr from an existing NodeSet 4120 */ 4121void 4122xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) { 4123 int i; 4124 4125 if (cur == NULL) return; 4126 if (val == NULL) return; 4127 4128 /* 4129 * find node in nodeTab 4130 */ 4131 for (i = 0;i < cur->nodeNr;i++) 4132 if (cur->nodeTab[i] == val) break; 4133 4134 if (i >= cur->nodeNr) { /* not found */ 4135#ifdef DEBUG 4136 xmlGenericError(xmlGenericErrorContext, 4137 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n", 4138 val->name); 4139#endif 4140 return; 4141 } 4142 if ((cur->nodeTab[i] != NULL) && 4143 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL)) 4144 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]); 4145 cur->nodeNr--; 4146 for (;i < cur->nodeNr;i++) 4147 cur->nodeTab[i] = cur->nodeTab[i + 1]; 4148 cur->nodeTab[cur->nodeNr] = NULL; 4149} 4150 4151/** 4152 * xmlXPathNodeSetRemove: 4153 * @cur: the initial node set 4154 * @val: the index to remove 4155 * 4156 * Removes an entry from an existing NodeSet list. 4157 */ 4158void 4159xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) { 4160 if (cur == NULL) return; 4161 if (val >= cur->nodeNr) return; 4162 if ((cur->nodeTab[val] != NULL) && 4163 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL)) 4164 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]); 4165 cur->nodeNr--; 4166 for (;val < cur->nodeNr;val++) 4167 cur->nodeTab[val] = cur->nodeTab[val + 1]; 4168 cur->nodeTab[cur->nodeNr] = NULL; 4169} 4170 4171/** 4172 * xmlXPathFreeNodeSet: 4173 * @obj: the xmlNodeSetPtr to free 4174 * 4175 * Free the NodeSet compound (not the actual nodes !). 4176 */ 4177void 4178xmlXPathFreeNodeSet(xmlNodeSetPtr obj) { 4179 if (obj == NULL) return; 4180 if (obj->nodeTab != NULL) { 4181 int i; 4182 4183 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 4184 for (i = 0;i < obj->nodeNr;i++) 4185 if ((obj->nodeTab[i] != NULL) && 4186 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL)) 4187 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]); 4188 xmlFree(obj->nodeTab); 4189 } 4190 xmlFree(obj); 4191} 4192 4193/** 4194 * xmlXPathNodeSetClear: 4195 * @set: the node set to clear 4196 * 4197 * Clears the list from all temporary XPath objects (e.g. namespace nodes 4198 * are feed), but does *not* free the list itself. Sets the length of the 4199 * list to 0. 4200 */ 4201static void 4202xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes) 4203{ 4204 if ((set == NULL) || (set->nodeNr <= 0)) 4205 return; 4206 else if (hasNsNodes) { 4207 int i; 4208 xmlNodePtr node; 4209 4210 for (i = 0; i < set->nodeNr; i++) { 4211 node = set->nodeTab[i]; 4212 if ((node != NULL) && 4213 (node->type == XML_NAMESPACE_DECL)) 4214 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 4215 } 4216 } 4217 set->nodeNr = 0; 4218} 4219 4220/** 4221 * xmlXPathNodeSetClearFromPos: 4222 * @set: the node set to be cleared 4223 * @pos: the start position to clear from 4224 * 4225 * Clears the list from temporary XPath objects (e.g. namespace nodes 4226 * are feed) starting with the entry at @pos, but does *not* free the list 4227 * itself. Sets the length of the list to @pos. 4228 */ 4229static void 4230xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes) 4231{ 4232 if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr)) 4233 return; 4234 else if ((hasNsNodes)) { 4235 int i; 4236 xmlNodePtr node; 4237 4238 for (i = pos; i < set->nodeNr; i++) { 4239 node = set->nodeTab[i]; 4240 if ((node != NULL) && 4241 (node->type == XML_NAMESPACE_DECL)) 4242 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 4243 } 4244 } 4245 set->nodeNr = pos; 4246} 4247 4248/** 4249 * xmlXPathFreeValueTree: 4250 * @obj: the xmlNodeSetPtr to free 4251 * 4252 * Free the NodeSet compound and the actual tree, this is different 4253 * from xmlXPathFreeNodeSet() 4254 */ 4255static void 4256xmlXPathFreeValueTree(xmlNodeSetPtr obj) { 4257 int i; 4258 4259 if (obj == NULL) return; 4260 4261 if (obj->nodeTab != NULL) { 4262 for (i = 0;i < obj->nodeNr;i++) { 4263 if (obj->nodeTab[i] != NULL) { 4264 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) { 4265 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]); 4266 } else { 4267 xmlFreeNodeList(obj->nodeTab[i]); 4268 } 4269 } 4270 } 4271 xmlFree(obj->nodeTab); 4272 } 4273 xmlFree(obj); 4274} 4275 4276#if defined(DEBUG) || defined(DEBUG_STEP) 4277/** 4278 * xmlGenericErrorContextNodeSet: 4279 * @output: a FILE * for the output 4280 * @obj: the xmlNodeSetPtr to display 4281 * 4282 * Quick display of a NodeSet 4283 */ 4284void 4285xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) { 4286 int i; 4287 4288 if (output == NULL) output = xmlGenericErrorContext; 4289 if (obj == NULL) { 4290 fprintf(output, "NodeSet == NULL !\n"); 4291 return; 4292 } 4293 if (obj->nodeNr == 0) { 4294 fprintf(output, "NodeSet is empty\n"); 4295 return; 4296 } 4297 if (obj->nodeTab == NULL) { 4298 fprintf(output, " nodeTab == NULL !\n"); 4299 return; 4300 } 4301 for (i = 0; i < obj->nodeNr; i++) { 4302 if (obj->nodeTab[i] == NULL) { 4303 fprintf(output, " NULL !\n"); 4304 return; 4305 } 4306 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) || 4307 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE)) 4308 fprintf(output, " /"); 4309 else if (obj->nodeTab[i]->name == NULL) 4310 fprintf(output, " noname!"); 4311 else fprintf(output, " %s", obj->nodeTab[i]->name); 4312 } 4313 fprintf(output, "\n"); 4314} 4315#endif 4316 4317/** 4318 * xmlXPathNewNodeSet: 4319 * @val: the NodePtr value 4320 * 4321 * Create a new xmlXPathObjectPtr of type NodeSet and initialize 4322 * it with the single Node @val 4323 * 4324 * Returns the newly created object. 4325 */ 4326xmlXPathObjectPtr 4327xmlXPathNewNodeSet(xmlNodePtr val) { 4328 xmlXPathObjectPtr ret; 4329 4330 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4331 if (ret == NULL) { 4332 xmlXPathErrMemory(NULL, "creating nodeset\n"); 4333 return(NULL); 4334 } 4335 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4336 ret->type = XPATH_NODESET; 4337 ret->boolval = 0; 4338 ret->nodesetval = xmlXPathNodeSetCreate(val); 4339 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 4340#ifdef XP_DEBUG_OBJ_USAGE 4341 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET); 4342#endif 4343 return(ret); 4344} 4345 4346/** 4347 * xmlXPathNewValueTree: 4348 * @val: the NodePtr value 4349 * 4350 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize 4351 * it with the tree root @val 4352 * 4353 * Returns the newly created object. 4354 */ 4355xmlXPathObjectPtr 4356xmlXPathNewValueTree(xmlNodePtr val) { 4357 xmlXPathObjectPtr ret; 4358 4359 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4360 if (ret == NULL) { 4361 xmlXPathErrMemory(NULL, "creating result value tree\n"); 4362 return(NULL); 4363 } 4364 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4365 ret->type = XPATH_XSLT_TREE; 4366 ret->boolval = 1; 4367 ret->user = (void *) val; 4368 ret->nodesetval = xmlXPathNodeSetCreate(val); 4369#ifdef XP_DEBUG_OBJ_USAGE 4370 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE); 4371#endif 4372 return(ret); 4373} 4374 4375/** 4376 * xmlXPathNewNodeSetList: 4377 * @val: an existing NodeSet 4378 * 4379 * Create a new xmlXPathObjectPtr of type NodeSet and initialize 4380 * it with the Nodeset @val 4381 * 4382 * Returns the newly created object. 4383 */ 4384xmlXPathObjectPtr 4385xmlXPathNewNodeSetList(xmlNodeSetPtr val) 4386{ 4387 xmlXPathObjectPtr ret; 4388 int i; 4389 4390 if (val == NULL) 4391 ret = NULL; 4392 else if (val->nodeTab == NULL) 4393 ret = xmlXPathNewNodeSet(NULL); 4394 else { 4395 ret = xmlXPathNewNodeSet(val->nodeTab[0]); 4396 if (ret) { 4397 for (i = 1; i < val->nodeNr; ++i) { 4398 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]) 4399 < 0) break; 4400 } 4401 } 4402 } 4403 4404 return (ret); 4405} 4406 4407/** 4408 * xmlXPathWrapNodeSet: 4409 * @val: the NodePtr value 4410 * 4411 * Wrap the Nodeset @val in a new xmlXPathObjectPtr 4412 * 4413 * Returns the newly created object. 4414 */ 4415xmlXPathObjectPtr 4416xmlXPathWrapNodeSet(xmlNodeSetPtr val) { 4417 xmlXPathObjectPtr ret; 4418 4419 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4420 if (ret == NULL) { 4421 xmlXPathErrMemory(NULL, "creating node set object\n"); 4422 return(NULL); 4423 } 4424 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4425 ret->type = XPATH_NODESET; 4426 ret->nodesetval = val; 4427#ifdef XP_DEBUG_OBJ_USAGE 4428 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET); 4429#endif 4430 return(ret); 4431} 4432 4433/** 4434 * xmlXPathFreeNodeSetList: 4435 * @obj: an existing NodeSetList object 4436 * 4437 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in 4438 * the list contrary to xmlXPathFreeObject(). 4439 */ 4440void 4441xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) { 4442 if (obj == NULL) return; 4443#ifdef XP_DEBUG_OBJ_USAGE 4444 xmlXPathDebugObjUsageReleased(NULL, obj->type); 4445#endif 4446 xmlFree(obj); 4447} 4448 4449/** 4450 * xmlXPathDifference: 4451 * @nodes1: a node-set 4452 * @nodes2: a node-set 4453 * 4454 * Implements the EXSLT - Sets difference() function: 4455 * node-set set:difference (node-set, node-set) 4456 * 4457 * Returns the difference between the two node sets, or nodes1 if 4458 * nodes2 is empty 4459 */ 4460xmlNodeSetPtr 4461xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4462 xmlNodeSetPtr ret; 4463 int i, l1; 4464 xmlNodePtr cur; 4465 4466 if (xmlXPathNodeSetIsEmpty(nodes2)) 4467 return(nodes1); 4468 4469 ret = xmlXPathNodeSetCreate(NULL); 4470 if (xmlXPathNodeSetIsEmpty(nodes1)) 4471 return(ret); 4472 4473 l1 = xmlXPathNodeSetGetLength(nodes1); 4474 4475 for (i = 0; i < l1; i++) { 4476 cur = xmlXPathNodeSetItem(nodes1, i); 4477 if (!xmlXPathNodeSetContains(nodes2, cur)) { 4478 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) 4479 break; 4480 } 4481 } 4482 return(ret); 4483} 4484 4485/** 4486 * xmlXPathIntersection: 4487 * @nodes1: a node-set 4488 * @nodes2: a node-set 4489 * 4490 * Implements the EXSLT - Sets intersection() function: 4491 * node-set set:intersection (node-set, node-set) 4492 * 4493 * Returns a node set comprising the nodes that are within both the 4494 * node sets passed as arguments 4495 */ 4496xmlNodeSetPtr 4497xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4498 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL); 4499 int i, l1; 4500 xmlNodePtr cur; 4501 4502 if (ret == NULL) 4503 return(ret); 4504 if (xmlXPathNodeSetIsEmpty(nodes1)) 4505 return(ret); 4506 if (xmlXPathNodeSetIsEmpty(nodes2)) 4507 return(ret); 4508 4509 l1 = xmlXPathNodeSetGetLength(nodes1); 4510 4511 for (i = 0; i < l1; i++) { 4512 cur = xmlXPathNodeSetItem(nodes1, i); 4513 if (xmlXPathNodeSetContains(nodes2, cur)) { 4514 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) 4515 break; 4516 } 4517 } 4518 return(ret); 4519} 4520 4521/** 4522 * xmlXPathDistinctSorted: 4523 * @nodes: a node-set, sorted by document order 4524 * 4525 * Implements the EXSLT - Sets distinct() function: 4526 * node-set set:distinct (node-set) 4527 * 4528 * Returns a subset of the nodes contained in @nodes, or @nodes if 4529 * it is empty 4530 */ 4531xmlNodeSetPtr 4532xmlXPathDistinctSorted (xmlNodeSetPtr nodes) { 4533 xmlNodeSetPtr ret; 4534 xmlHashTablePtr hash; 4535 int i, l; 4536 xmlChar * strval; 4537 xmlNodePtr cur; 4538 4539 if (xmlXPathNodeSetIsEmpty(nodes)) 4540 return(nodes); 4541 4542 ret = xmlXPathNodeSetCreate(NULL); 4543 if (ret == NULL) 4544 return(ret); 4545 l = xmlXPathNodeSetGetLength(nodes); 4546 hash = xmlHashCreate (l); 4547 for (i = 0; i < l; i++) { 4548 cur = xmlXPathNodeSetItem(nodes, i); 4549 strval = xmlXPathCastNodeToString(cur); 4550 if (xmlHashLookup(hash, strval) == NULL) { 4551 xmlHashAddEntry(hash, strval, strval); 4552 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) 4553 break; 4554 } else { 4555 xmlFree(strval); 4556 } 4557 } 4558 xmlHashFree(hash, (xmlHashDeallocator) xmlFree); 4559 return(ret); 4560} 4561 4562/** 4563 * xmlXPathDistinct: 4564 * @nodes: a node-set 4565 * 4566 * Implements the EXSLT - Sets distinct() function: 4567 * node-set set:distinct (node-set) 4568 * @nodes is sorted by document order, then #exslSetsDistinctSorted 4569 * is called with the sorted node-set 4570 * 4571 * Returns a subset of the nodes contained in @nodes, or @nodes if 4572 * it is empty 4573 */ 4574xmlNodeSetPtr 4575xmlXPathDistinct (xmlNodeSetPtr nodes) { 4576 if (xmlXPathNodeSetIsEmpty(nodes)) 4577 return(nodes); 4578 4579 xmlXPathNodeSetSort(nodes); 4580 return(xmlXPathDistinctSorted(nodes)); 4581} 4582 4583/** 4584 * xmlXPathHasSameNodes: 4585 * @nodes1: a node-set 4586 * @nodes2: a node-set 4587 * 4588 * Implements the EXSLT - Sets has-same-nodes function: 4589 * boolean set:has-same-node(node-set, node-set) 4590 * 4591 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0) 4592 * otherwise 4593 */ 4594int 4595xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4596 int i, l; 4597 xmlNodePtr cur; 4598 4599 if (xmlXPathNodeSetIsEmpty(nodes1) || 4600 xmlXPathNodeSetIsEmpty(nodes2)) 4601 return(0); 4602 4603 l = xmlXPathNodeSetGetLength(nodes1); 4604 for (i = 0; i < l; i++) { 4605 cur = xmlXPathNodeSetItem(nodes1, i); 4606 if (xmlXPathNodeSetContains(nodes2, cur)) 4607 return(1); 4608 } 4609 return(0); 4610} 4611 4612/** 4613 * xmlXPathNodeLeadingSorted: 4614 * @nodes: a node-set, sorted by document order 4615 * @node: a node 4616 * 4617 * Implements the EXSLT - Sets leading() function: 4618 * node-set set:leading (node-set, node-set) 4619 * 4620 * Returns the nodes in @nodes that precede @node in document order, 4621 * @nodes if @node is NULL or an empty node-set if @nodes 4622 * doesn't contain @node 4623 */ 4624xmlNodeSetPtr 4625xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { 4626 int i, l; 4627 xmlNodePtr cur; 4628 xmlNodeSetPtr ret; 4629 4630 if (node == NULL) 4631 return(nodes); 4632 4633 ret = xmlXPathNodeSetCreate(NULL); 4634 if (ret == NULL) 4635 return(ret); 4636 if (xmlXPathNodeSetIsEmpty(nodes) || 4637 (!xmlXPathNodeSetContains(nodes, node))) 4638 return(ret); 4639 4640 l = xmlXPathNodeSetGetLength(nodes); 4641 for (i = 0; i < l; i++) { 4642 cur = xmlXPathNodeSetItem(nodes, i); 4643 if (cur == node) 4644 break; 4645 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) 4646 break; 4647 } 4648 return(ret); 4649} 4650 4651/** 4652 * xmlXPathNodeLeading: 4653 * @nodes: a node-set 4654 * @node: a node 4655 * 4656 * Implements the EXSLT - Sets leading() function: 4657 * node-set set:leading (node-set, node-set) 4658 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted 4659 * is called. 4660 * 4661 * Returns the nodes in @nodes that precede @node in document order, 4662 * @nodes if @node is NULL or an empty node-set if @nodes 4663 * doesn't contain @node 4664 */ 4665xmlNodeSetPtr 4666xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) { 4667 xmlXPathNodeSetSort(nodes); 4668 return(xmlXPathNodeLeadingSorted(nodes, node)); 4669} 4670 4671/** 4672 * xmlXPathLeadingSorted: 4673 * @nodes1: a node-set, sorted by document order 4674 * @nodes2: a node-set, sorted by document order 4675 * 4676 * Implements the EXSLT - Sets leading() function: 4677 * node-set set:leading (node-set, node-set) 4678 * 4679 * Returns the nodes in @nodes1 that precede the first node in @nodes2 4680 * in document order, @nodes1 if @nodes2 is NULL or empty or 4681 * an empty node-set if @nodes1 doesn't contain @nodes2 4682 */ 4683xmlNodeSetPtr 4684xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4685 if (xmlXPathNodeSetIsEmpty(nodes2)) 4686 return(nodes1); 4687 return(xmlXPathNodeLeadingSorted(nodes1, 4688 xmlXPathNodeSetItem(nodes2, 1))); 4689} 4690 4691/** 4692 * xmlXPathLeading: 4693 * @nodes1: a node-set 4694 * @nodes2: a node-set 4695 * 4696 * Implements the EXSLT - Sets leading() function: 4697 * node-set set:leading (node-set, node-set) 4698 * @nodes1 and @nodes2 are sorted by document order, then 4699 * #exslSetsLeadingSorted is called. 4700 * 4701 * Returns the nodes in @nodes1 that precede the first node in @nodes2 4702 * in document order, @nodes1 if @nodes2 is NULL or empty or 4703 * an empty node-set if @nodes1 doesn't contain @nodes2 4704 */ 4705xmlNodeSetPtr 4706xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4707 if (xmlXPathNodeSetIsEmpty(nodes2)) 4708 return(nodes1); 4709 if (xmlXPathNodeSetIsEmpty(nodes1)) 4710 return(xmlXPathNodeSetCreate(NULL)); 4711 xmlXPathNodeSetSort(nodes1); 4712 xmlXPathNodeSetSort(nodes2); 4713 return(xmlXPathNodeLeadingSorted(nodes1, 4714 xmlXPathNodeSetItem(nodes2, 1))); 4715} 4716 4717/** 4718 * xmlXPathNodeTrailingSorted: 4719 * @nodes: a node-set, sorted by document order 4720 * @node: a node 4721 * 4722 * Implements the EXSLT - Sets trailing() function: 4723 * node-set set:trailing (node-set, node-set) 4724 * 4725 * Returns the nodes in @nodes that follow @node in document order, 4726 * @nodes if @node is NULL or an empty node-set if @nodes 4727 * doesn't contain @node 4728 */ 4729xmlNodeSetPtr 4730xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { 4731 int i, l; 4732 xmlNodePtr cur; 4733 xmlNodeSetPtr ret; 4734 4735 if (node == NULL) 4736 return(nodes); 4737 4738 ret = xmlXPathNodeSetCreate(NULL); 4739 if (ret == NULL) 4740 return(ret); 4741 if (xmlXPathNodeSetIsEmpty(nodes) || 4742 (!xmlXPathNodeSetContains(nodes, node))) 4743 return(ret); 4744 4745 l = xmlXPathNodeSetGetLength(nodes); 4746 for (i = l - 1; i >= 0; i--) { 4747 cur = xmlXPathNodeSetItem(nodes, i); 4748 if (cur == node) 4749 break; 4750 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) 4751 break; 4752 } 4753 xmlXPathNodeSetSort(ret); /* bug 413451 */ 4754 return(ret); 4755} 4756 4757/** 4758 * xmlXPathNodeTrailing: 4759 * @nodes: a node-set 4760 * @node: a node 4761 * 4762 * Implements the EXSLT - Sets trailing() function: 4763 * node-set set:trailing (node-set, node-set) 4764 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted 4765 * is called. 4766 * 4767 * Returns the nodes in @nodes that follow @node in document order, 4768 * @nodes if @node is NULL or an empty node-set if @nodes 4769 * doesn't contain @node 4770 */ 4771xmlNodeSetPtr 4772xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) { 4773 xmlXPathNodeSetSort(nodes); 4774 return(xmlXPathNodeTrailingSorted(nodes, node)); 4775} 4776 4777/** 4778 * xmlXPathTrailingSorted: 4779 * @nodes1: a node-set, sorted by document order 4780 * @nodes2: a node-set, sorted by document order 4781 * 4782 * Implements the EXSLT - Sets trailing() function: 4783 * node-set set:trailing (node-set, node-set) 4784 * 4785 * Returns the nodes in @nodes1 that follow the first node in @nodes2 4786 * in document order, @nodes1 if @nodes2 is NULL or empty or 4787 * an empty node-set if @nodes1 doesn't contain @nodes2 4788 */ 4789xmlNodeSetPtr 4790xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4791 if (xmlXPathNodeSetIsEmpty(nodes2)) 4792 return(nodes1); 4793 return(xmlXPathNodeTrailingSorted(nodes1, 4794 xmlXPathNodeSetItem(nodes2, 0))); 4795} 4796 4797/** 4798 * xmlXPathTrailing: 4799 * @nodes1: a node-set 4800 * @nodes2: a node-set 4801 * 4802 * Implements the EXSLT - Sets trailing() function: 4803 * node-set set:trailing (node-set, node-set) 4804 * @nodes1 and @nodes2 are sorted by document order, then 4805 * #xmlXPathTrailingSorted is called. 4806 * 4807 * Returns the nodes in @nodes1 that follow the first node in @nodes2 4808 * in document order, @nodes1 if @nodes2 is NULL or empty or 4809 * an empty node-set if @nodes1 doesn't contain @nodes2 4810 */ 4811xmlNodeSetPtr 4812xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4813 if (xmlXPathNodeSetIsEmpty(nodes2)) 4814 return(nodes1); 4815 if (xmlXPathNodeSetIsEmpty(nodes1)) 4816 return(xmlXPathNodeSetCreate(NULL)); 4817 xmlXPathNodeSetSort(nodes1); 4818 xmlXPathNodeSetSort(nodes2); 4819 return(xmlXPathNodeTrailingSorted(nodes1, 4820 xmlXPathNodeSetItem(nodes2, 0))); 4821} 4822 4823/************************************************************************ 4824 * * 4825 * Routines to handle extra functions * 4826 * * 4827 ************************************************************************/ 4828 4829/** 4830 * xmlXPathRegisterFunc: 4831 * @ctxt: the XPath context 4832 * @name: the function name 4833 * @f: the function implementation or NULL 4834 * 4835 * Register a new function. If @f is NULL it unregisters the function 4836 * 4837 * Returns 0 in case of success, -1 in case of error 4838 */ 4839int 4840xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name, 4841 xmlXPathFunction f) { 4842 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f)); 4843} 4844 4845/** 4846 * xmlXPathRegisterFuncNS: 4847 * @ctxt: the XPath context 4848 * @name: the function name 4849 * @ns_uri: the function namespace URI 4850 * @f: the function implementation or NULL 4851 * 4852 * Register a new function. If @f is NULL it unregisters the function 4853 * 4854 * Returns 0 in case of success, -1 in case of error 4855 */ 4856int 4857xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name, 4858 const xmlChar *ns_uri, xmlXPathFunction f) { 4859 if (ctxt == NULL) 4860 return(-1); 4861 if (name == NULL) 4862 return(-1); 4863 4864 if (ctxt->funcHash == NULL) 4865 ctxt->funcHash = xmlHashCreate(0); 4866 if (ctxt->funcHash == NULL) 4867 return(-1); 4868 if (f == NULL) 4869 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL)); 4870 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f))); 4871} 4872 4873/** 4874 * xmlXPathRegisterFuncLookup: 4875 * @ctxt: the XPath context 4876 * @f: the lookup function 4877 * @funcCtxt: the lookup data 4878 * 4879 * Registers an external mechanism to do function lookup. 4880 */ 4881void 4882xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt, 4883 xmlXPathFuncLookupFunc f, 4884 void *funcCtxt) { 4885 if (ctxt == NULL) 4886 return; 4887 ctxt->funcLookupFunc = f; 4888 ctxt->funcLookupData = funcCtxt; 4889} 4890 4891/** 4892 * xmlXPathFunctionLookup: 4893 * @ctxt: the XPath context 4894 * @name: the function name 4895 * 4896 * Search in the Function array of the context for the given 4897 * function. 4898 * 4899 * Returns the xmlXPathFunction or NULL if not found 4900 */ 4901xmlXPathFunction 4902xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { 4903 if (ctxt == NULL) 4904 return (NULL); 4905 4906 if (ctxt->funcLookupFunc != NULL) { 4907 xmlXPathFunction ret; 4908 xmlXPathFuncLookupFunc f; 4909 4910 f = ctxt->funcLookupFunc; 4911 ret = f(ctxt->funcLookupData, name, NULL); 4912 if (ret != NULL) 4913 return(ret); 4914 } 4915 return(xmlXPathFunctionLookupNS(ctxt, name, NULL)); 4916} 4917 4918/** 4919 * xmlXPathFunctionLookupNS: 4920 * @ctxt: the XPath context 4921 * @name: the function name 4922 * @ns_uri: the function namespace URI 4923 * 4924 * Search in the Function array of the context for the given 4925 * function. 4926 * 4927 * Returns the xmlXPathFunction or NULL if not found 4928 */ 4929xmlXPathFunction 4930xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name, 4931 const xmlChar *ns_uri) { 4932 xmlXPathFunction ret; 4933 4934 if (ctxt == NULL) 4935 return(NULL); 4936 if (name == NULL) 4937 return(NULL); 4938 4939 if (ctxt->funcLookupFunc != NULL) { 4940 xmlXPathFuncLookupFunc f; 4941 4942 f = ctxt->funcLookupFunc; 4943 ret = f(ctxt->funcLookupData, name, ns_uri); 4944 if (ret != NULL) 4945 return(ret); 4946 } 4947 4948 if (ctxt->funcHash == NULL) 4949 return(NULL); 4950 4951 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri); 4952 return(ret); 4953} 4954 4955/** 4956 * xmlXPathRegisteredFuncsCleanup: 4957 * @ctxt: the XPath context 4958 * 4959 * Cleanup the XPath context data associated to registered functions 4960 */ 4961void 4962xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) { 4963 if (ctxt == NULL) 4964 return; 4965 4966 xmlHashFree(ctxt->funcHash, NULL); 4967 ctxt->funcHash = NULL; 4968} 4969 4970/************************************************************************ 4971 * * 4972 * Routines to handle Variables * 4973 * * 4974 ************************************************************************/ 4975 4976/** 4977 * xmlXPathRegisterVariable: 4978 * @ctxt: the XPath context 4979 * @name: the variable name 4980 * @value: the variable value or NULL 4981 * 4982 * Register a new variable value. If @value is NULL it unregisters 4983 * the variable 4984 * 4985 * Returns 0 in case of success, -1 in case of error 4986 */ 4987int 4988xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name, 4989 xmlXPathObjectPtr value) { 4990 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value)); 4991} 4992 4993/** 4994 * xmlXPathRegisterVariableNS: 4995 * @ctxt: the XPath context 4996 * @name: the variable name 4997 * @ns_uri: the variable namespace URI 4998 * @value: the variable value or NULL 4999 * 5000 * Register a new variable value. If @value is NULL it unregisters 5001 * the variable 5002 * 5003 * Returns 0 in case of success, -1 in case of error 5004 */ 5005int 5006xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name, 5007 const xmlChar *ns_uri, 5008 xmlXPathObjectPtr value) { 5009 if (ctxt == NULL) 5010 return(-1); 5011 if (name == NULL) 5012 return(-1); 5013 5014 if (ctxt->varHash == NULL) 5015 ctxt->varHash = xmlHashCreate(0); 5016 if (ctxt->varHash == NULL) 5017 return(-1); 5018 if (value == NULL) 5019 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri, 5020 (xmlHashDeallocator)xmlXPathFreeObject)); 5021 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri, 5022 (void *) value, 5023 (xmlHashDeallocator)xmlXPathFreeObject)); 5024} 5025 5026/** 5027 * xmlXPathRegisterVariableLookup: 5028 * @ctxt: the XPath context 5029 * @f: the lookup function 5030 * @data: the lookup data 5031 * 5032 * register an external mechanism to do variable lookup 5033 */ 5034void 5035xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt, 5036 xmlXPathVariableLookupFunc f, void *data) { 5037 if (ctxt == NULL) 5038 return; 5039 ctxt->varLookupFunc = f; 5040 ctxt->varLookupData = data; 5041} 5042 5043/** 5044 * xmlXPathVariableLookup: 5045 * @ctxt: the XPath context 5046 * @name: the variable name 5047 * 5048 * Search in the Variable array of the context for the given 5049 * variable value. 5050 * 5051 * Returns a copy of the value or NULL if not found 5052 */ 5053xmlXPathObjectPtr 5054xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { 5055 if (ctxt == NULL) 5056 return(NULL); 5057 5058 if (ctxt->varLookupFunc != NULL) { 5059 xmlXPathObjectPtr ret; 5060 5061 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc) 5062 (ctxt->varLookupData, name, NULL); 5063 return(ret); 5064 } 5065 return(xmlXPathVariableLookupNS(ctxt, name, NULL)); 5066} 5067 5068/** 5069 * xmlXPathVariableLookupNS: 5070 * @ctxt: the XPath context 5071 * @name: the variable name 5072 * @ns_uri: the variable namespace URI 5073 * 5074 * Search in the Variable array of the context for the given 5075 * variable value. 5076 * 5077 * Returns the a copy of the value or NULL if not found 5078 */ 5079xmlXPathObjectPtr 5080xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name, 5081 const xmlChar *ns_uri) { 5082 if (ctxt == NULL) 5083 return(NULL); 5084 5085 if (ctxt->varLookupFunc != NULL) { 5086 xmlXPathObjectPtr ret; 5087 5088 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc) 5089 (ctxt->varLookupData, name, ns_uri); 5090 if (ret != NULL) return(ret); 5091 } 5092 5093 if (ctxt->varHash == NULL) 5094 return(NULL); 5095 if (name == NULL) 5096 return(NULL); 5097 5098 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr) 5099 xmlHashLookup2(ctxt->varHash, name, ns_uri))); 5100} 5101 5102/** 5103 * xmlXPathRegisteredVariablesCleanup: 5104 * @ctxt: the XPath context 5105 * 5106 * Cleanup the XPath context data associated to registered variables 5107 */ 5108void 5109xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) { 5110 if (ctxt == NULL) 5111 return; 5112 5113 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject); 5114 ctxt->varHash = NULL; 5115} 5116 5117/** 5118 * xmlXPathRegisterNs: 5119 * @ctxt: the XPath context 5120 * @prefix: the namespace prefix cannot be NULL or empty string 5121 * @ns_uri: the namespace name 5122 * 5123 * Register a new namespace. If @ns_uri is NULL it unregisters 5124 * the namespace 5125 * 5126 * Returns 0 in case of success, -1 in case of error 5127 */ 5128int 5129xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix, 5130 const xmlChar *ns_uri) { 5131 if (ctxt == NULL) 5132 return(-1); 5133 if (prefix == NULL) 5134 return(-1); 5135 if (prefix[0] == 0) 5136 return(-1); 5137 5138 if (ctxt->nsHash == NULL) 5139 ctxt->nsHash = xmlHashCreate(10); 5140 if (ctxt->nsHash == NULL) 5141 return(-1); 5142 if (ns_uri == NULL) 5143 return(xmlHashRemoveEntry(ctxt->nsHash, prefix, 5144 (xmlHashDeallocator)xmlFree)); 5145 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri), 5146 (xmlHashDeallocator)xmlFree)); 5147} 5148 5149/** 5150 * xmlXPathNsLookup: 5151 * @ctxt: the XPath context 5152 * @prefix: the namespace prefix value 5153 * 5154 * Search in the namespace declaration array of the context for the given 5155 * namespace name associated to the given prefix 5156 * 5157 * Returns the value or NULL if not found 5158 */ 5159const xmlChar * 5160xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) { 5161 if (ctxt == NULL) 5162 return(NULL); 5163 if (prefix == NULL) 5164 return(NULL); 5165 5166#ifdef XML_XML_NAMESPACE 5167 if (xmlStrEqual(prefix, (const xmlChar *) "xml")) 5168 return(XML_XML_NAMESPACE); 5169#endif 5170 5171 if (ctxt->namespaces != NULL) { 5172 int i; 5173 5174 for (i = 0;i < ctxt->nsNr;i++) { 5175 if ((ctxt->namespaces[i] != NULL) && 5176 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix))) 5177 return(ctxt->namespaces[i]->href); 5178 } 5179 } 5180 5181 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix)); 5182} 5183 5184/** 5185 * xmlXPathRegisteredNsCleanup: 5186 * @ctxt: the XPath context 5187 * 5188 * Cleanup the XPath context data associated to registered variables 5189 */ 5190void 5191xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) { 5192 if (ctxt == NULL) 5193 return; 5194 5195 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree); 5196 ctxt->nsHash = NULL; 5197} 5198 5199/************************************************************************ 5200 * * 5201 * Routines to handle Values * 5202 * * 5203 ************************************************************************/ 5204 5205/* Allocations are terrible, one needs to optimize all this !!! */ 5206 5207/** 5208 * xmlXPathNewFloat: 5209 * @val: the double value 5210 * 5211 * Create a new xmlXPathObjectPtr of type double and of value @val 5212 * 5213 * Returns the newly created object. 5214 */ 5215xmlXPathObjectPtr 5216xmlXPathNewFloat(double val) { 5217 xmlXPathObjectPtr ret; 5218 5219 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5220 if (ret == NULL) { 5221 xmlXPathErrMemory(NULL, "creating float object\n"); 5222 return(NULL); 5223 } 5224 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5225 ret->type = XPATH_NUMBER; 5226 ret->floatval = val; 5227#ifdef XP_DEBUG_OBJ_USAGE 5228 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER); 5229#endif 5230 return(ret); 5231} 5232 5233/** 5234 * xmlXPathNewBoolean: 5235 * @val: the boolean value 5236 * 5237 * Create a new xmlXPathObjectPtr of type boolean and of value @val 5238 * 5239 * Returns the newly created object. 5240 */ 5241xmlXPathObjectPtr 5242xmlXPathNewBoolean(int val) { 5243 xmlXPathObjectPtr ret; 5244 5245 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5246 if (ret == NULL) { 5247 xmlXPathErrMemory(NULL, "creating boolean object\n"); 5248 return(NULL); 5249 } 5250 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5251 ret->type = XPATH_BOOLEAN; 5252 ret->boolval = (val != 0); 5253#ifdef XP_DEBUG_OBJ_USAGE 5254 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN); 5255#endif 5256 return(ret); 5257} 5258 5259/** 5260 * xmlXPathNewString: 5261 * @val: the xmlChar * value 5262 * 5263 * Create a new xmlXPathObjectPtr of type string and of value @val 5264 * 5265 * Returns the newly created object. 5266 */ 5267xmlXPathObjectPtr 5268xmlXPathNewString(const xmlChar *val) { 5269 xmlXPathObjectPtr ret; 5270 5271 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5272 if (ret == NULL) { 5273 xmlXPathErrMemory(NULL, "creating string object\n"); 5274 return(NULL); 5275 } 5276 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5277 ret->type = XPATH_STRING; 5278 if (val != NULL) 5279 ret->stringval = xmlStrdup(val); 5280 else 5281 ret->stringval = xmlStrdup((const xmlChar *)""); 5282#ifdef XP_DEBUG_OBJ_USAGE 5283 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); 5284#endif 5285 return(ret); 5286} 5287 5288/** 5289 * xmlXPathWrapString: 5290 * @val: the xmlChar * value 5291 * 5292 * Wraps the @val string into an XPath object. 5293 * 5294 * Returns the newly created object. 5295 */ 5296xmlXPathObjectPtr 5297xmlXPathWrapString (xmlChar *val) { 5298 xmlXPathObjectPtr ret; 5299 5300 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5301 if (ret == NULL) { 5302 xmlXPathErrMemory(NULL, "creating string object\n"); 5303 return(NULL); 5304 } 5305 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5306 ret->type = XPATH_STRING; 5307 ret->stringval = val; 5308#ifdef XP_DEBUG_OBJ_USAGE 5309 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); 5310#endif 5311 return(ret); 5312} 5313 5314/** 5315 * xmlXPathNewCString: 5316 * @val: the char * value 5317 * 5318 * Create a new xmlXPathObjectPtr of type string and of value @val 5319 * 5320 * Returns the newly created object. 5321 */ 5322xmlXPathObjectPtr 5323xmlXPathNewCString(const char *val) { 5324 xmlXPathObjectPtr ret; 5325 5326 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5327 if (ret == NULL) { 5328 xmlXPathErrMemory(NULL, "creating string object\n"); 5329 return(NULL); 5330 } 5331 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5332 ret->type = XPATH_STRING; 5333 ret->stringval = xmlStrdup(BAD_CAST val); 5334#ifdef XP_DEBUG_OBJ_USAGE 5335 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); 5336#endif 5337 return(ret); 5338} 5339 5340/** 5341 * xmlXPathWrapCString: 5342 * @val: the char * value 5343 * 5344 * Wraps a string into an XPath object. 5345 * 5346 * Returns the newly created object. 5347 */ 5348xmlXPathObjectPtr 5349xmlXPathWrapCString (char * val) { 5350 return(xmlXPathWrapString((xmlChar *)(val))); 5351} 5352 5353/** 5354 * xmlXPathWrapExternal: 5355 * @val: the user data 5356 * 5357 * Wraps the @val data into an XPath object. 5358 * 5359 * Returns the newly created object. 5360 */ 5361xmlXPathObjectPtr 5362xmlXPathWrapExternal (void *val) { 5363 xmlXPathObjectPtr ret; 5364 5365 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5366 if (ret == NULL) { 5367 xmlXPathErrMemory(NULL, "creating user object\n"); 5368 return(NULL); 5369 } 5370 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5371 ret->type = XPATH_USERS; 5372 ret->user = val; 5373#ifdef XP_DEBUG_OBJ_USAGE 5374 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS); 5375#endif 5376 return(ret); 5377} 5378 5379/** 5380 * xmlXPathObjectCopy: 5381 * @val: the original object 5382 * 5383 * allocate a new copy of a given object 5384 * 5385 * Returns the newly created object. 5386 */ 5387xmlXPathObjectPtr 5388xmlXPathObjectCopy(xmlXPathObjectPtr val) { 5389 xmlXPathObjectPtr ret; 5390 5391 if (val == NULL) 5392 return(NULL); 5393 5394 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5395 if (ret == NULL) { 5396 xmlXPathErrMemory(NULL, "copying object\n"); 5397 return(NULL); 5398 } 5399 memcpy(ret, val , (size_t) sizeof(xmlXPathObject)); 5400#ifdef XP_DEBUG_OBJ_USAGE 5401 xmlXPathDebugObjUsageRequested(NULL, val->type); 5402#endif 5403 switch (val->type) { 5404 case XPATH_BOOLEAN: 5405 case XPATH_NUMBER: 5406 case XPATH_POINT: 5407 case XPATH_RANGE: 5408 break; 5409 case XPATH_STRING: 5410 ret->stringval = xmlStrdup(val->stringval); 5411 break; 5412 case XPATH_XSLT_TREE: 5413#if 0 5414/* 5415 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that 5416 this previous handling is no longer correct, and can cause some serious 5417 problems (ref. bug 145547) 5418*/ 5419 if ((val->nodesetval != NULL) && 5420 (val->nodesetval->nodeTab != NULL)) { 5421 xmlNodePtr cur, tmp; 5422 xmlDocPtr top; 5423 5424 ret->boolval = 1; 5425 top = xmlNewDoc(NULL); 5426 top->name = (char *) 5427 xmlStrdup(val->nodesetval->nodeTab[0]->name); 5428 ret->user = top; 5429 if (top != NULL) { 5430 top->doc = top; 5431 cur = val->nodesetval->nodeTab[0]->children; 5432 while (cur != NULL) { 5433 tmp = xmlDocCopyNode(cur, top, 1); 5434 xmlAddChild((xmlNodePtr) top, tmp); 5435 cur = cur->next; 5436 } 5437 } 5438 5439 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top); 5440 } else 5441 ret->nodesetval = xmlXPathNodeSetCreate(NULL); 5442 /* Deallocate the copied tree value */ 5443 break; 5444#endif 5445 case XPATH_NODESET: 5446 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval); 5447 /* Do not deallocate the copied tree value */ 5448 ret->boolval = 0; 5449 break; 5450 case XPATH_LOCATIONSET: 5451#ifdef LIBXML_XPTR_ENABLED 5452 { 5453 xmlLocationSetPtr loc = val->user; 5454 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc); 5455 break; 5456 } 5457#endif 5458 case XPATH_USERS: 5459 ret->user = val->user; 5460 break; 5461 case XPATH_UNDEFINED: 5462 xmlGenericError(xmlGenericErrorContext, 5463 "xmlXPathObjectCopy: unsupported type %d\n", 5464 val->type); 5465 break; 5466 } 5467 return(ret); 5468} 5469 5470/** 5471 * xmlXPathFreeObject: 5472 * @obj: the object to free 5473 * 5474 * Free up an xmlXPathObjectPtr object. 5475 */ 5476void 5477xmlXPathFreeObject(xmlXPathObjectPtr obj) { 5478 if (obj == NULL) return; 5479 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) { 5480 if (obj->boolval) { 5481#if 0 5482 if (obj->user != NULL) { 5483 xmlXPathFreeNodeSet(obj->nodesetval); 5484 xmlFreeNodeList((xmlNodePtr) obj->user); 5485 } else 5486#endif 5487 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */ 5488 if (obj->nodesetval != NULL) 5489 xmlXPathFreeValueTree(obj->nodesetval); 5490 } else { 5491 if (obj->nodesetval != NULL) 5492 xmlXPathFreeNodeSet(obj->nodesetval); 5493 } 5494#ifdef LIBXML_XPTR_ENABLED 5495 } else if (obj->type == XPATH_LOCATIONSET) { 5496 if (obj->user != NULL) 5497 xmlXPtrFreeLocationSet(obj->user); 5498#endif 5499 } else if (obj->type == XPATH_STRING) { 5500 if (obj->stringval != NULL) 5501 xmlFree(obj->stringval); 5502 } 5503#ifdef XP_DEBUG_OBJ_USAGE 5504 xmlXPathDebugObjUsageReleased(NULL, obj->type); 5505#endif 5506 xmlFree(obj); 5507} 5508 5509/** 5510 * xmlXPathReleaseObject: 5511 * @obj: the xmlXPathObjectPtr to free or to cache 5512 * 5513 * Depending on the state of the cache this frees the given 5514 * XPath object or stores it in the cache. 5515 */ 5516static void 5517xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj) 5518{ 5519#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \ 5520 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \ 5521 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj; 5522 5523#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n)) 5524 5525 if (obj == NULL) 5526 return; 5527 if ((ctxt == NULL) || (ctxt->cache == NULL)) { 5528 xmlXPathFreeObject(obj); 5529 } else { 5530 xmlXPathContextCachePtr cache = 5531 (xmlXPathContextCachePtr) ctxt->cache; 5532 5533 switch (obj->type) { 5534 case XPATH_NODESET: 5535 case XPATH_XSLT_TREE: 5536 if (obj->nodesetval != NULL) { 5537 if (obj->boolval) { 5538 /* 5539 * It looks like the @boolval is used for 5540 * evaluation if this an XSLT Result Tree Fragment. 5541 * TODO: Check if this assumption is correct. 5542 */ 5543 obj->type = XPATH_XSLT_TREE; /* just for debugging */ 5544 xmlXPathFreeValueTree(obj->nodesetval); 5545 obj->nodesetval = NULL; 5546 } else if ((obj->nodesetval->nodeMax <= 40) && 5547 (XP_CACHE_WANTS(cache->nodesetObjs, 5548 cache->maxNodeset))) 5549 { 5550 XP_CACHE_ADD(cache->nodesetObjs, obj); 5551 goto obj_cached; 5552 } else { 5553 xmlXPathFreeNodeSet(obj->nodesetval); 5554 obj->nodesetval = NULL; 5555 } 5556 } 5557 break; 5558 case XPATH_STRING: 5559 if (obj->stringval != NULL) 5560 xmlFree(obj->stringval); 5561 5562 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) { 5563 XP_CACHE_ADD(cache->stringObjs, obj); 5564 goto obj_cached; 5565 } 5566 break; 5567 case XPATH_BOOLEAN: 5568 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) { 5569 XP_CACHE_ADD(cache->booleanObjs, obj); 5570 goto obj_cached; 5571 } 5572 break; 5573 case XPATH_NUMBER: 5574 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) { 5575 XP_CACHE_ADD(cache->numberObjs, obj); 5576 goto obj_cached; 5577 } 5578 break; 5579#ifdef LIBXML_XPTR_ENABLED 5580 case XPATH_LOCATIONSET: 5581 if (obj->user != NULL) { 5582 xmlXPtrFreeLocationSet(obj->user); 5583 } 5584 goto free_obj; 5585#endif 5586 default: 5587 goto free_obj; 5588 } 5589 5590 /* 5591 * Fallback to adding to the misc-objects slot. 5592 */ 5593 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) { 5594 XP_CACHE_ADD(cache->miscObjs, obj); 5595 } else 5596 goto free_obj; 5597 5598obj_cached: 5599 5600#ifdef XP_DEBUG_OBJ_USAGE 5601 xmlXPathDebugObjUsageReleased(ctxt, obj->type); 5602#endif 5603 5604 if (obj->nodesetval != NULL) { 5605 xmlNodeSetPtr tmpset = obj->nodesetval; 5606 5607 /* 5608 * TODO: Due to those nasty ns-nodes, we need to traverse 5609 * the list and free the ns-nodes. 5610 * URGENT TODO: Check if it's actually slowing things down. 5611 * Maybe we shouldn't try to preserve the list. 5612 */ 5613 if (tmpset->nodeNr > 1) { 5614 int i; 5615 xmlNodePtr node; 5616 5617 for (i = 0; i < tmpset->nodeNr; i++) { 5618 node = tmpset->nodeTab[i]; 5619 if ((node != NULL) && 5620 (node->type == XML_NAMESPACE_DECL)) 5621 { 5622 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 5623 } 5624 } 5625 } else if (tmpset->nodeNr == 1) { 5626 if ((tmpset->nodeTab[0] != NULL) && 5627 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL)) 5628 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]); 5629 } 5630 tmpset->nodeNr = 0; 5631 memset(obj, 0, sizeof(xmlXPathObject)); 5632 obj->nodesetval = tmpset; 5633 } else 5634 memset(obj, 0, sizeof(xmlXPathObject)); 5635 5636 return; 5637 5638free_obj: 5639 /* 5640 * Cache is full; free the object. 5641 */ 5642 if (obj->nodesetval != NULL) 5643 xmlXPathFreeNodeSet(obj->nodesetval); 5644#ifdef XP_DEBUG_OBJ_USAGE 5645 xmlXPathDebugObjUsageReleased(NULL, obj->type); 5646#endif 5647 xmlFree(obj); 5648 } 5649 return; 5650} 5651 5652 5653/************************************************************************ 5654 * * 5655 * Type Casting Routines * 5656 * * 5657 ************************************************************************/ 5658 5659/** 5660 * xmlXPathCastBooleanToString: 5661 * @val: a boolean 5662 * 5663 * Converts a boolean to its string value. 5664 * 5665 * Returns a newly allocated string. 5666 */ 5667xmlChar * 5668xmlXPathCastBooleanToString (int val) { 5669 xmlChar *ret; 5670 if (val) 5671 ret = xmlStrdup((const xmlChar *) "true"); 5672 else 5673 ret = xmlStrdup((const xmlChar *) "false"); 5674 return(ret); 5675} 5676 5677/** 5678 * xmlXPathCastNumberToString: 5679 * @val: a number 5680 * 5681 * Converts a number to its string value. 5682 * 5683 * Returns a newly allocated string. 5684 */ 5685xmlChar * 5686xmlXPathCastNumberToString (double val) { 5687 xmlChar *ret; 5688 switch (xmlXPathIsInf(val)) { 5689 case 1: 5690 ret = xmlStrdup((const xmlChar *) "Infinity"); 5691 break; 5692 case -1: 5693 ret = xmlStrdup((const xmlChar *) "-Infinity"); 5694 break; 5695 default: 5696 if (xmlXPathIsNaN(val)) { 5697 ret = xmlStrdup((const xmlChar *) "NaN"); 5698 } else if (val == 0 && xmlXPathGetSign(val) != 0) { 5699 ret = xmlStrdup((const xmlChar *) "0"); 5700 } else { 5701 /* could be improved */ 5702 char buf[100]; 5703 xmlXPathFormatNumber(val, buf, 99); 5704 buf[99] = 0; 5705 ret = xmlStrdup((const xmlChar *) buf); 5706 } 5707 } 5708 return(ret); 5709} 5710 5711/** 5712 * xmlXPathCastNodeToString: 5713 * @node: a node 5714 * 5715 * Converts a node to its string value. 5716 * 5717 * Returns a newly allocated string. 5718 */ 5719xmlChar * 5720xmlXPathCastNodeToString (xmlNodePtr node) { 5721xmlChar *ret; 5722 if ((ret = xmlNodeGetContent(node)) == NULL) 5723 ret = xmlStrdup((const xmlChar *) ""); 5724 return(ret); 5725} 5726 5727/** 5728 * xmlXPathCastNodeSetToString: 5729 * @ns: a node-set 5730 * 5731 * Converts a node-set to its string value. 5732 * 5733 * Returns a newly allocated string. 5734 */ 5735xmlChar * 5736xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) { 5737 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL)) 5738 return(xmlStrdup((const xmlChar *) "")); 5739 5740 if (ns->nodeNr > 1) 5741 xmlXPathNodeSetSort(ns); 5742 return(xmlXPathCastNodeToString(ns->nodeTab[0])); 5743} 5744 5745/** 5746 * xmlXPathCastToString: 5747 * @val: an XPath object 5748 * 5749 * Converts an existing object to its string() equivalent 5750 * 5751 * Returns the allocated string value of the object, NULL in case of error. 5752 * It's up to the caller to free the string memory with xmlFree(). 5753 */ 5754xmlChar * 5755xmlXPathCastToString(xmlXPathObjectPtr val) { 5756 xmlChar *ret = NULL; 5757 5758 if (val == NULL) 5759 return(xmlStrdup((const xmlChar *) "")); 5760 switch (val->type) { 5761 case XPATH_UNDEFINED: 5762#ifdef DEBUG_EXPR 5763 xmlGenericError(xmlGenericErrorContext, "String: undefined\n"); 5764#endif 5765 ret = xmlStrdup((const xmlChar *) ""); 5766 break; 5767 case XPATH_NODESET: 5768 case XPATH_XSLT_TREE: 5769 ret = xmlXPathCastNodeSetToString(val->nodesetval); 5770 break; 5771 case XPATH_STRING: 5772 return(xmlStrdup(val->stringval)); 5773 case XPATH_BOOLEAN: 5774 ret = xmlXPathCastBooleanToString(val->boolval); 5775 break; 5776 case XPATH_NUMBER: { 5777 ret = xmlXPathCastNumberToString(val->floatval); 5778 break; 5779 } 5780 case XPATH_USERS: 5781 case XPATH_POINT: 5782 case XPATH_RANGE: 5783 case XPATH_LOCATIONSET: 5784 TODO 5785 ret = xmlStrdup((const xmlChar *) ""); 5786 break; 5787 } 5788 return(ret); 5789} 5790 5791/** 5792 * xmlXPathConvertString: 5793 * @val: an XPath object 5794 * 5795 * Converts an existing object to its string() equivalent 5796 * 5797 * Returns the new object, the old one is freed (or the operation 5798 * is done directly on @val) 5799 */ 5800xmlXPathObjectPtr 5801xmlXPathConvertString(xmlXPathObjectPtr val) { 5802 xmlChar *res = NULL; 5803 5804 if (val == NULL) 5805 return(xmlXPathNewCString("")); 5806 5807 switch (val->type) { 5808 case XPATH_UNDEFINED: 5809#ifdef DEBUG_EXPR 5810 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n"); 5811#endif 5812 break; 5813 case XPATH_NODESET: 5814 case XPATH_XSLT_TREE: 5815 res = xmlXPathCastNodeSetToString(val->nodesetval); 5816 break; 5817 case XPATH_STRING: 5818 return(val); 5819 case XPATH_BOOLEAN: 5820 res = xmlXPathCastBooleanToString(val->boolval); 5821 break; 5822 case XPATH_NUMBER: 5823 res = xmlXPathCastNumberToString(val->floatval); 5824 break; 5825 case XPATH_USERS: 5826 case XPATH_POINT: 5827 case XPATH_RANGE: 5828 case XPATH_LOCATIONSET: 5829 TODO; 5830 break; 5831 } 5832 xmlXPathFreeObject(val); 5833 if (res == NULL) 5834 return(xmlXPathNewCString("")); 5835 return(xmlXPathWrapString(res)); 5836} 5837 5838/** 5839 * xmlXPathCastBooleanToNumber: 5840 * @val: a boolean 5841 * 5842 * Converts a boolean to its number value 5843 * 5844 * Returns the number value 5845 */ 5846double 5847xmlXPathCastBooleanToNumber(int val) { 5848 if (val) 5849 return(1.0); 5850 return(0.0); 5851} 5852 5853/** 5854 * xmlXPathCastStringToNumber: 5855 * @val: a string 5856 * 5857 * Converts a string to its number value 5858 * 5859 * Returns the number value 5860 */ 5861double 5862xmlXPathCastStringToNumber(const xmlChar * val) { 5863 return(xmlXPathStringEvalNumber(val)); 5864} 5865 5866/** 5867 * xmlXPathCastNodeToNumber: 5868 * @node: a node 5869 * 5870 * Converts a node to its number value 5871 * 5872 * Returns the number value 5873 */ 5874double 5875xmlXPathCastNodeToNumber (xmlNodePtr node) { 5876 xmlChar *strval; 5877 double ret; 5878 5879 if (node == NULL) 5880 return(xmlXPathNAN); 5881 strval = xmlXPathCastNodeToString(node); 5882 if (strval == NULL) 5883 return(xmlXPathNAN); 5884 ret = xmlXPathCastStringToNumber(strval); 5885 xmlFree(strval); 5886 5887 return(ret); 5888} 5889 5890/** 5891 * xmlXPathCastNodeSetToNumber: 5892 * @ns: a node-set 5893 * 5894 * Converts a node-set to its number value 5895 * 5896 * Returns the number value 5897 */ 5898double 5899xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) { 5900 xmlChar *str; 5901 double ret; 5902 5903 if (ns == NULL) 5904 return(xmlXPathNAN); 5905 str = xmlXPathCastNodeSetToString(ns); 5906 ret = xmlXPathCastStringToNumber(str); 5907 xmlFree(str); 5908 return(ret); 5909} 5910 5911/** 5912 * xmlXPathCastToNumber: 5913 * @val: an XPath object 5914 * 5915 * Converts an XPath object to its number value 5916 * 5917 * Returns the number value 5918 */ 5919double 5920xmlXPathCastToNumber(xmlXPathObjectPtr val) { 5921 double ret = 0.0; 5922 5923 if (val == NULL) 5924 return(xmlXPathNAN); 5925 switch (val->type) { 5926 case XPATH_UNDEFINED: 5927#ifdef DEGUB_EXPR 5928 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n"); 5929#endif 5930 ret = xmlXPathNAN; 5931 break; 5932 case XPATH_NODESET: 5933 case XPATH_XSLT_TREE: 5934 ret = xmlXPathCastNodeSetToNumber(val->nodesetval); 5935 break; 5936 case XPATH_STRING: 5937 ret = xmlXPathCastStringToNumber(val->stringval); 5938 break; 5939 case XPATH_NUMBER: 5940 ret = val->floatval; 5941 break; 5942 case XPATH_BOOLEAN: 5943 ret = xmlXPathCastBooleanToNumber(val->boolval); 5944 break; 5945 case XPATH_USERS: 5946 case XPATH_POINT: 5947 case XPATH_RANGE: 5948 case XPATH_LOCATIONSET: 5949 TODO; 5950 ret = xmlXPathNAN; 5951 break; 5952 } 5953 return(ret); 5954} 5955 5956/** 5957 * xmlXPathConvertNumber: 5958 * @val: an XPath object 5959 * 5960 * Converts an existing object to its number() equivalent 5961 * 5962 * Returns the new object, the old one is freed (or the operation 5963 * is done directly on @val) 5964 */ 5965xmlXPathObjectPtr 5966xmlXPathConvertNumber(xmlXPathObjectPtr val) { 5967 xmlXPathObjectPtr ret; 5968 5969 if (val == NULL) 5970 return(xmlXPathNewFloat(0.0)); 5971 if (val->type == XPATH_NUMBER) 5972 return(val); 5973 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val)); 5974 xmlXPathFreeObject(val); 5975 return(ret); 5976} 5977 5978/** 5979 * xmlXPathCastNumberToBoolean: 5980 * @val: a number 5981 * 5982 * Converts a number to its boolean value 5983 * 5984 * Returns the boolean value 5985 */ 5986int 5987xmlXPathCastNumberToBoolean (double val) { 5988 if (xmlXPathIsNaN(val) || (val == 0.0)) 5989 return(0); 5990 return(1); 5991} 5992 5993/** 5994 * xmlXPathCastStringToBoolean: 5995 * @val: a string 5996 * 5997 * Converts a string to its boolean value 5998 * 5999 * Returns the boolean value 6000 */ 6001int 6002xmlXPathCastStringToBoolean (const xmlChar *val) { 6003 if ((val == NULL) || (xmlStrlen(val) == 0)) 6004 return(0); 6005 return(1); 6006} 6007 6008/** 6009 * xmlXPathCastNodeSetToBoolean: 6010 * @ns: a node-set 6011 * 6012 * Converts a node-set to its boolean value 6013 * 6014 * Returns the boolean value 6015 */ 6016int 6017xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) { 6018 if ((ns == NULL) || (ns->nodeNr == 0)) 6019 return(0); 6020 return(1); 6021} 6022 6023/** 6024 * xmlXPathCastToBoolean: 6025 * @val: an XPath object 6026 * 6027 * Converts an XPath object to its boolean value 6028 * 6029 * Returns the boolean value 6030 */ 6031int 6032xmlXPathCastToBoolean (xmlXPathObjectPtr val) { 6033 int ret = 0; 6034 6035 if (val == NULL) 6036 return(0); 6037 switch (val->type) { 6038 case XPATH_UNDEFINED: 6039#ifdef DEBUG_EXPR 6040 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n"); 6041#endif 6042 ret = 0; 6043 break; 6044 case XPATH_NODESET: 6045 case XPATH_XSLT_TREE: 6046 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval); 6047 break; 6048 case XPATH_STRING: 6049 ret = xmlXPathCastStringToBoolean(val->stringval); 6050 break; 6051 case XPATH_NUMBER: 6052 ret = xmlXPathCastNumberToBoolean(val->floatval); 6053 break; 6054 case XPATH_BOOLEAN: 6055 ret = val->boolval; 6056 break; 6057 case XPATH_USERS: 6058 case XPATH_POINT: 6059 case XPATH_RANGE: 6060 case XPATH_LOCATIONSET: 6061 TODO; 6062 ret = 0; 6063 break; 6064 } 6065 return(ret); 6066} 6067 6068 6069/** 6070 * xmlXPathConvertBoolean: 6071 * @val: an XPath object 6072 * 6073 * Converts an existing object to its boolean() equivalent 6074 * 6075 * Returns the new object, the old one is freed (or the operation 6076 * is done directly on @val) 6077 */ 6078xmlXPathObjectPtr 6079xmlXPathConvertBoolean(xmlXPathObjectPtr val) { 6080 xmlXPathObjectPtr ret; 6081 6082 if (val == NULL) 6083 return(xmlXPathNewBoolean(0)); 6084 if (val->type == XPATH_BOOLEAN) 6085 return(val); 6086 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val)); 6087 xmlXPathFreeObject(val); 6088 return(ret); 6089} 6090 6091/************************************************************************ 6092 * * 6093 * Routines to handle XPath contexts * 6094 * * 6095 ************************************************************************/ 6096 6097/** 6098 * xmlXPathNewContext: 6099 * @doc: the XML document 6100 * 6101 * Create a new xmlXPathContext 6102 * 6103 * Returns the xmlXPathContext just allocated. The caller will need to free it. 6104 */ 6105xmlXPathContextPtr 6106xmlXPathNewContext(xmlDocPtr doc) { 6107 xmlXPathContextPtr ret; 6108 6109 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext)); 6110 if (ret == NULL) { 6111 xmlXPathErrMemory(NULL, "creating context\n"); 6112 return(NULL); 6113 } 6114 memset(ret, 0 , (size_t) sizeof(xmlXPathContext)); 6115 ret->doc = doc; 6116 ret->node = NULL; 6117 6118 ret->varHash = NULL; 6119 6120 ret->nb_types = 0; 6121 ret->max_types = 0; 6122 ret->types = NULL; 6123 6124 ret->funcHash = xmlHashCreate(0); 6125 6126 ret->nb_axis = 0; 6127 ret->max_axis = 0; 6128 ret->axis = NULL; 6129 6130 ret->nsHash = NULL; 6131 ret->user = NULL; 6132 6133 ret->contextSize = -1; 6134 ret->proximityPosition = -1; 6135 6136#ifdef XP_DEFAULT_CACHE_ON 6137 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) { 6138 xmlXPathFreeContext(ret); 6139 return(NULL); 6140 } 6141#endif 6142 6143 xmlXPathRegisterAllFunctions(ret); 6144 6145 return(ret); 6146} 6147 6148/** 6149 * xmlXPathFreeContext: 6150 * @ctxt: the context to free 6151 * 6152 * Free up an xmlXPathContext 6153 */ 6154void 6155xmlXPathFreeContext(xmlXPathContextPtr ctxt) { 6156 if (ctxt == NULL) return; 6157 6158 if (ctxt->cache != NULL) 6159 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache); 6160 xmlXPathRegisteredNsCleanup(ctxt); 6161 xmlXPathRegisteredFuncsCleanup(ctxt); 6162 xmlXPathRegisteredVariablesCleanup(ctxt); 6163 xmlResetError(&ctxt->lastError); 6164 xmlFree(ctxt); 6165} 6166 6167/************************************************************************ 6168 * * 6169 * Routines to handle XPath parser contexts * 6170 * * 6171 ************************************************************************/ 6172 6173#define CHECK_CTXT(ctxt) \ 6174 if (ctxt == NULL) { \ 6175 __xmlRaiseError(NULL, NULL, NULL, \ 6176 NULL, NULL, XML_FROM_XPATH, \ 6177 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \ 6178 __FILE__, __LINE__, \ 6179 NULL, NULL, NULL, 0, 0, \ 6180 "NULL context pointer\n"); \ 6181 return(NULL); \ 6182 } \ 6183 6184#define CHECK_CTXT_NEG(ctxt) \ 6185 if (ctxt == NULL) { \ 6186 __xmlRaiseError(NULL, NULL, NULL, \ 6187 NULL, NULL, XML_FROM_XPATH, \ 6188 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \ 6189 __FILE__, __LINE__, \ 6190 NULL, NULL, NULL, 0, 0, \ 6191 "NULL context pointer\n"); \ 6192 return(-1); \ 6193 } \ 6194 6195 6196#define CHECK_CONTEXT(ctxt) \ 6197 if ((ctxt == NULL) || (ctxt->doc == NULL) || \ 6198 (ctxt->doc->children == NULL)) { \ 6199 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \ 6200 return(NULL); \ 6201 } 6202 6203 6204/** 6205 * xmlXPathNewParserContext: 6206 * @str: the XPath expression 6207 * @ctxt: the XPath context 6208 * 6209 * Create a new xmlXPathParserContext 6210 * 6211 * Returns the xmlXPathParserContext just allocated. 6212 */ 6213xmlXPathParserContextPtr 6214xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) { 6215 xmlXPathParserContextPtr ret; 6216 6217 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext)); 6218 if (ret == NULL) { 6219 xmlXPathErrMemory(ctxt, "creating parser context\n"); 6220 return(NULL); 6221 } 6222 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext)); 6223 ret->cur = ret->base = str; 6224 ret->context = ctxt; 6225 6226 ret->comp = xmlXPathNewCompExpr(); 6227 if (ret->comp == NULL) { 6228 xmlFree(ret->valueTab); 6229 xmlFree(ret); 6230 return(NULL); 6231 } 6232 if ((ctxt != NULL) && (ctxt->dict != NULL)) { 6233 ret->comp->dict = ctxt->dict; 6234 xmlDictReference(ret->comp->dict); 6235 } 6236 6237 return(ret); 6238} 6239 6240/** 6241 * xmlXPathCompParserContext: 6242 * @comp: the XPath compiled expression 6243 * @ctxt: the XPath context 6244 * 6245 * Create a new xmlXPathParserContext when processing a compiled expression 6246 * 6247 * Returns the xmlXPathParserContext just allocated. 6248 */ 6249static xmlXPathParserContextPtr 6250xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) { 6251 xmlXPathParserContextPtr ret; 6252 6253 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext)); 6254 if (ret == NULL) { 6255 xmlXPathErrMemory(ctxt, "creating evaluation context\n"); 6256 return(NULL); 6257 } 6258 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext)); 6259 6260 /* Allocate the value stack */ 6261 ret->valueTab = (xmlXPathObjectPtr *) 6262 xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); 6263 if (ret->valueTab == NULL) { 6264 xmlFree(ret); 6265 xmlXPathErrMemory(ctxt, "creating evaluation context\n"); 6266 return(NULL); 6267 } 6268 ret->valueNr = 0; 6269 ret->valueMax = 10; 6270 ret->value = NULL; 6271 ret->valueFrame = 0; 6272 6273 ret->context = ctxt; 6274 ret->comp = comp; 6275 6276 return(ret); 6277} 6278 6279/** 6280 * xmlXPathFreeParserContext: 6281 * @ctxt: the context to free 6282 * 6283 * Free up an xmlXPathParserContext 6284 */ 6285void 6286xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) { 6287 if (ctxt->valueTab != NULL) { 6288 xmlFree(ctxt->valueTab); 6289 } 6290 if (ctxt->comp != NULL) { 6291#ifdef XPATH_STREAMING 6292 if (ctxt->comp->stream != NULL) { 6293 xmlFreePatternList(ctxt->comp->stream); 6294 ctxt->comp->stream = NULL; 6295 } 6296#endif 6297 xmlXPathFreeCompExpr(ctxt->comp); 6298 } 6299 xmlFree(ctxt); 6300} 6301 6302/************************************************************************ 6303 * * 6304 * The implicit core function library * 6305 * * 6306 ************************************************************************/ 6307 6308/** 6309 * xmlXPathNodeValHash: 6310 * @node: a node pointer 6311 * 6312 * Function computing the beginning of the string value of the node, 6313 * used to speed up comparisons 6314 * 6315 * Returns an int usable as a hash 6316 */ 6317static unsigned int 6318xmlXPathNodeValHash(xmlNodePtr node) { 6319 int len = 2; 6320 const xmlChar * string = NULL; 6321 xmlNodePtr tmp = NULL; 6322 unsigned int ret = 0; 6323 6324 if (node == NULL) 6325 return(0); 6326 6327 if (node->type == XML_DOCUMENT_NODE) { 6328 tmp = xmlDocGetRootElement((xmlDocPtr) node); 6329 if (tmp == NULL) 6330 node = node->children; 6331 else 6332 node = tmp; 6333 6334 if (node == NULL) 6335 return(0); 6336 } 6337 6338 switch (node->type) { 6339 case XML_COMMENT_NODE: 6340 case XML_PI_NODE: 6341 case XML_CDATA_SECTION_NODE: 6342 case XML_TEXT_NODE: 6343 string = node->content; 6344 if (string == NULL) 6345 return(0); 6346 if (string[0] == 0) 6347 return(0); 6348 return(((unsigned int) string[0]) + 6349 (((unsigned int) string[1]) << 8)); 6350 case XML_NAMESPACE_DECL: 6351 string = ((xmlNsPtr)node)->href; 6352 if (string == NULL) 6353 return(0); 6354 if (string[0] == 0) 6355 return(0); 6356 return(((unsigned int) string[0]) + 6357 (((unsigned int) string[1]) << 8)); 6358 case XML_ATTRIBUTE_NODE: 6359 tmp = ((xmlAttrPtr) node)->children; 6360 break; 6361 case XML_ELEMENT_NODE: 6362 tmp = node->children; 6363 break; 6364 default: 6365 return(0); 6366 } 6367 while (tmp != NULL) { 6368 switch (tmp->type) { 6369 case XML_COMMENT_NODE: 6370 case XML_PI_NODE: 6371 case XML_CDATA_SECTION_NODE: 6372 case XML_TEXT_NODE: 6373 string = tmp->content; 6374 break; 6375 case XML_NAMESPACE_DECL: 6376 string = ((xmlNsPtr)tmp)->href; 6377 break; 6378 default: 6379 break; 6380 } 6381 if ((string != NULL) && (string[0] != 0)) { 6382 if (len == 1) { 6383 return(ret + (((unsigned int) string[0]) << 8)); 6384 } 6385 if (string[1] == 0) { 6386 len = 1; 6387 ret = (unsigned int) string[0]; 6388 } else { 6389 return(((unsigned int) string[0]) + 6390 (((unsigned int) string[1]) << 8)); 6391 } 6392 } 6393 /* 6394 * Skip to next node 6395 */ 6396 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) { 6397 if (tmp->children->type != XML_ENTITY_DECL) { 6398 tmp = tmp->children; 6399 continue; 6400 } 6401 } 6402 if (tmp == node) 6403 break; 6404 6405 if (tmp->next != NULL) { 6406 tmp = tmp->next; 6407 continue; 6408 } 6409 6410 do { 6411 tmp = tmp->parent; 6412 if (tmp == NULL) 6413 break; 6414 if (tmp == node) { 6415 tmp = NULL; 6416 break; 6417 } 6418 if (tmp->next != NULL) { 6419 tmp = tmp->next; 6420 break; 6421 } 6422 } while (tmp != NULL); 6423 } 6424 return(ret); 6425} 6426 6427/** 6428 * xmlXPathStringHash: 6429 * @string: a string 6430 * 6431 * Function computing the beginning of the string value of the node, 6432 * used to speed up comparisons 6433 * 6434 * Returns an int usable as a hash 6435 */ 6436static unsigned int 6437xmlXPathStringHash(const xmlChar * string) { 6438 if (string == NULL) 6439 return((unsigned int) 0); 6440 if (string[0] == 0) 6441 return(0); 6442 return(((unsigned int) string[0]) + 6443 (((unsigned int) string[1]) << 8)); 6444} 6445 6446/** 6447 * xmlXPathCompareNodeSetFloat: 6448 * @ctxt: the XPath Parser context 6449 * @inf: less than (1) or greater than (0) 6450 * @strict: is the comparison strict 6451 * @arg: the node set 6452 * @f: the value 6453 * 6454 * Implement the compare operation between a nodeset and a number 6455 * @ns < @val (1, 1, ... 6456 * @ns <= @val (1, 0, ... 6457 * @ns > @val (0, 1, ... 6458 * @ns >= @val (0, 0, ... 6459 * 6460 * If one object to be compared is a node-set and the other is a number, 6461 * then the comparison will be true if and only if there is a node in the 6462 * node-set such that the result of performing the comparison on the number 6463 * to be compared and on the result of converting the string-value of that 6464 * node to a number using the number function is true. 6465 * 6466 * Returns 0 or 1 depending on the results of the test. 6467 */ 6468static int 6469xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict, 6470 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) { 6471 int i, ret = 0; 6472 xmlNodeSetPtr ns; 6473 xmlChar *str2; 6474 6475 if ((f == NULL) || (arg == NULL) || 6476 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) { 6477 xmlXPathReleaseObject(ctxt->context, arg); 6478 xmlXPathReleaseObject(ctxt->context, f); 6479 return(0); 6480 } 6481 ns = arg->nodesetval; 6482 if (ns != NULL) { 6483 for (i = 0;i < ns->nodeNr;i++) { 6484 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 6485 if (str2 != NULL) { 6486 valuePush(ctxt, 6487 xmlXPathCacheNewString(ctxt->context, str2)); 6488 xmlFree(str2); 6489 xmlXPathNumberFunction(ctxt, 1); 6490 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f)); 6491 ret = xmlXPathCompareValues(ctxt, inf, strict); 6492 if (ret) 6493 break; 6494 } 6495 } 6496 } 6497 xmlXPathReleaseObject(ctxt->context, arg); 6498 xmlXPathReleaseObject(ctxt->context, f); 6499 return(ret); 6500} 6501 6502/** 6503 * xmlXPathCompareNodeSetString: 6504 * @ctxt: the XPath Parser context 6505 * @inf: less than (1) or greater than (0) 6506 * @strict: is the comparison strict 6507 * @arg: the node set 6508 * @s: the value 6509 * 6510 * Implement the compare operation between a nodeset and a string 6511 * @ns < @val (1, 1, ... 6512 * @ns <= @val (1, 0, ... 6513 * @ns > @val (0, 1, ... 6514 * @ns >= @val (0, 0, ... 6515 * 6516 * If one object to be compared is a node-set and the other is a string, 6517 * then the comparison will be true if and only if there is a node in 6518 * the node-set such that the result of performing the comparison on the 6519 * string-value of the node and the other string is true. 6520 * 6521 * Returns 0 or 1 depending on the results of the test. 6522 */ 6523static int 6524xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict, 6525 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) { 6526 int i, ret = 0; 6527 xmlNodeSetPtr ns; 6528 xmlChar *str2; 6529 6530 if ((s == NULL) || (arg == NULL) || 6531 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) { 6532 xmlXPathReleaseObject(ctxt->context, arg); 6533 xmlXPathReleaseObject(ctxt->context, s); 6534 return(0); 6535 } 6536 ns = arg->nodesetval; 6537 if (ns != NULL) { 6538 for (i = 0;i < ns->nodeNr;i++) { 6539 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 6540 if (str2 != NULL) { 6541 valuePush(ctxt, 6542 xmlXPathCacheNewString(ctxt->context, str2)); 6543 xmlFree(str2); 6544 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s)); 6545 ret = xmlXPathCompareValues(ctxt, inf, strict); 6546 if (ret) 6547 break; 6548 } 6549 } 6550 } 6551 xmlXPathReleaseObject(ctxt->context, arg); 6552 xmlXPathReleaseObject(ctxt->context, s); 6553 return(ret); 6554} 6555 6556/** 6557 * xmlXPathCompareNodeSets: 6558 * @inf: less than (1) or greater than (0) 6559 * @strict: is the comparison strict 6560 * @arg1: the first node set object 6561 * @arg2: the second node set object 6562 * 6563 * Implement the compare operation on nodesets: 6564 * 6565 * If both objects to be compared are node-sets, then the comparison 6566 * will be true if and only if there is a node in the first node-set 6567 * and a node in the second node-set such that the result of performing 6568 * the comparison on the string-values of the two nodes is true. 6569 * .... 6570 * When neither object to be compared is a node-set and the operator 6571 * is <=, <, >= or >, then the objects are compared by converting both 6572 * objects to numbers and comparing the numbers according to IEEE 754. 6573 * .... 6574 * The number function converts its argument to a number as follows: 6575 * - a string that consists of optional whitespace followed by an 6576 * optional minus sign followed by a Number followed by whitespace 6577 * is converted to the IEEE 754 number that is nearest (according 6578 * to the IEEE 754 round-to-nearest rule) to the mathematical value 6579 * represented by the string; any other string is converted to NaN 6580 * 6581 * Conclusion all nodes need to be converted first to their string value 6582 * and then the comparison must be done when possible 6583 */ 6584static int 6585xmlXPathCompareNodeSets(int inf, int strict, 6586 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) { 6587 int i, j, init = 0; 6588 double val1; 6589 double *values2; 6590 int ret = 0; 6591 xmlNodeSetPtr ns1; 6592 xmlNodeSetPtr ns2; 6593 6594 if ((arg1 == NULL) || 6595 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) { 6596 xmlXPathFreeObject(arg2); 6597 return(0); 6598 } 6599 if ((arg2 == NULL) || 6600 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) { 6601 xmlXPathFreeObject(arg1); 6602 xmlXPathFreeObject(arg2); 6603 return(0); 6604 } 6605 6606 ns1 = arg1->nodesetval; 6607 ns2 = arg2->nodesetval; 6608 6609 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) { 6610 xmlXPathFreeObject(arg1); 6611 xmlXPathFreeObject(arg2); 6612 return(0); 6613 } 6614 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) { 6615 xmlXPathFreeObject(arg1); 6616 xmlXPathFreeObject(arg2); 6617 return(0); 6618 } 6619 6620 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double)); 6621 if (values2 == NULL) { 6622 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6623 xmlXPathFreeObject(arg1); 6624 xmlXPathFreeObject(arg2); 6625 return(0); 6626 } 6627 for (i = 0;i < ns1->nodeNr;i++) { 6628 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]); 6629 if (xmlXPathIsNaN(val1)) 6630 continue; 6631 for (j = 0;j < ns2->nodeNr;j++) { 6632 if (init == 0) { 6633 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]); 6634 } 6635 if (xmlXPathIsNaN(values2[j])) 6636 continue; 6637 if (inf && strict) 6638 ret = (val1 < values2[j]); 6639 else if (inf && !strict) 6640 ret = (val1 <= values2[j]); 6641 else if (!inf && strict) 6642 ret = (val1 > values2[j]); 6643 else if (!inf && !strict) 6644 ret = (val1 >= values2[j]); 6645 if (ret) 6646 break; 6647 } 6648 if (ret) 6649 break; 6650 init = 1; 6651 } 6652 xmlFree(values2); 6653 xmlXPathFreeObject(arg1); 6654 xmlXPathFreeObject(arg2); 6655 return(ret); 6656} 6657 6658/** 6659 * xmlXPathCompareNodeSetValue: 6660 * @ctxt: the XPath Parser context 6661 * @inf: less than (1) or greater than (0) 6662 * @strict: is the comparison strict 6663 * @arg: the node set 6664 * @val: the value 6665 * 6666 * Implement the compare operation between a nodeset and a value 6667 * @ns < @val (1, 1, ... 6668 * @ns <= @val (1, 0, ... 6669 * @ns > @val (0, 1, ... 6670 * @ns >= @val (0, 0, ... 6671 * 6672 * If one object to be compared is a node-set and the other is a boolean, 6673 * then the comparison will be true if and only if the result of performing 6674 * the comparison on the boolean and on the result of converting 6675 * the node-set to a boolean using the boolean function is true. 6676 * 6677 * Returns 0 or 1 depending on the results of the test. 6678 */ 6679static int 6680xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict, 6681 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) { 6682 if ((val == NULL) || (arg == NULL) || 6683 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 6684 return(0); 6685 6686 switch(val->type) { 6687 case XPATH_NUMBER: 6688 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val)); 6689 case XPATH_NODESET: 6690 case XPATH_XSLT_TREE: 6691 return(xmlXPathCompareNodeSets(inf, strict, arg, val)); 6692 case XPATH_STRING: 6693 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val)); 6694 case XPATH_BOOLEAN: 6695 valuePush(ctxt, arg); 6696 xmlXPathBooleanFunction(ctxt, 1); 6697 valuePush(ctxt, val); 6698 return(xmlXPathCompareValues(ctxt, inf, strict)); 6699 default: 6700 TODO 6701 } 6702 return(0); 6703} 6704 6705/** 6706 * xmlXPathEqualNodeSetString: 6707 * @arg: the nodeset object argument 6708 * @str: the string to compare to. 6709 * @neq: flag to show whether for '=' (0) or '!=' (1) 6710 * 6711 * Implement the equal operation on XPath objects content: @arg1 == @arg2 6712 * If one object to be compared is a node-set and the other is a string, 6713 * then the comparison will be true if and only if there is a node in 6714 * the node-set such that the result of performing the comparison on the 6715 * string-value of the node and the other string is true. 6716 * 6717 * Returns 0 or 1 depending on the results of the test. 6718 */ 6719static int 6720xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq) 6721{ 6722 int i; 6723 xmlNodeSetPtr ns; 6724 xmlChar *str2; 6725 unsigned int hash; 6726 6727 if ((str == NULL) || (arg == NULL) || 6728 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 6729 return (0); 6730 ns = arg->nodesetval; 6731 /* 6732 * A NULL nodeset compared with a string is always false 6733 * (since there is no node equal, and no node not equal) 6734 */ 6735 if ((ns == NULL) || (ns->nodeNr <= 0) ) 6736 return (0); 6737 hash = xmlXPathStringHash(str); 6738 for (i = 0; i < ns->nodeNr; i++) { 6739 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) { 6740 str2 = xmlNodeGetContent(ns->nodeTab[i]); 6741 if ((str2 != NULL) && (xmlStrEqual(str, str2))) { 6742 xmlFree(str2); 6743 if (neq) 6744 continue; 6745 return (1); 6746 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) { 6747 if (neq) 6748 continue; 6749 return (1); 6750 } else if (neq) { 6751 if (str2 != NULL) 6752 xmlFree(str2); 6753 return (1); 6754 } 6755 if (str2 != NULL) 6756 xmlFree(str2); 6757 } else if (neq) 6758 return (1); 6759 } 6760 return (0); 6761} 6762 6763/** 6764 * xmlXPathEqualNodeSetFloat: 6765 * @arg: the nodeset object argument 6766 * @f: the float to compare to 6767 * @neq: flag to show whether to compare '=' (0) or '!=' (1) 6768 * 6769 * Implement the equal operation on XPath objects content: @arg1 == @arg2 6770 * If one object to be compared is a node-set and the other is a number, 6771 * then the comparison will be true if and only if there is a node in 6772 * the node-set such that the result of performing the comparison on the 6773 * number to be compared and on the result of converting the string-value 6774 * of that node to a number using the number function is true. 6775 * 6776 * Returns 0 or 1 depending on the results of the test. 6777 */ 6778static int 6779xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt, 6780 xmlXPathObjectPtr arg, double f, int neq) { 6781 int i, ret=0; 6782 xmlNodeSetPtr ns; 6783 xmlChar *str2; 6784 xmlXPathObjectPtr val; 6785 double v; 6786 6787 if ((arg == NULL) || 6788 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 6789 return(0); 6790 6791 ns = arg->nodesetval; 6792 if (ns != NULL) { 6793 for (i=0;i<ns->nodeNr;i++) { 6794 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 6795 if (str2 != NULL) { 6796 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2)); 6797 xmlFree(str2); 6798 xmlXPathNumberFunction(ctxt, 1); 6799 val = valuePop(ctxt); 6800 v = val->floatval; 6801 xmlXPathReleaseObject(ctxt->context, val); 6802 if (!xmlXPathIsNaN(v)) { 6803 if ((!neq) && (v==f)) { 6804 ret = 1; 6805 break; 6806 } else if ((neq) && (v!=f)) { 6807 ret = 1; 6808 break; 6809 } 6810 } else { /* NaN is unequal to any value */ 6811 if (neq) 6812 ret = 1; 6813 } 6814 } 6815 } 6816 } 6817 6818 return(ret); 6819} 6820 6821 6822/** 6823 * xmlXPathEqualNodeSets: 6824 * @arg1: first nodeset object argument 6825 * @arg2: second nodeset object argument 6826 * @neq: flag to show whether to test '=' (0) or '!=' (1) 6827 * 6828 * Implement the equal / not equal operation on XPath nodesets: 6829 * @arg1 == @arg2 or @arg1 != @arg2 6830 * If both objects to be compared are node-sets, then the comparison 6831 * will be true if and only if there is a node in the first node-set and 6832 * a node in the second node-set such that the result of performing the 6833 * comparison on the string-values of the two nodes is true. 6834 * 6835 * (needless to say, this is a costly operation) 6836 * 6837 * Returns 0 or 1 depending on the results of the test. 6838 */ 6839static int 6840xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) { 6841 int i, j; 6842 unsigned int *hashs1; 6843 unsigned int *hashs2; 6844 xmlChar **values1; 6845 xmlChar **values2; 6846 int ret = 0; 6847 xmlNodeSetPtr ns1; 6848 xmlNodeSetPtr ns2; 6849 6850 if ((arg1 == NULL) || 6851 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) 6852 return(0); 6853 if ((arg2 == NULL) || 6854 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) 6855 return(0); 6856 6857 ns1 = arg1->nodesetval; 6858 ns2 = arg2->nodesetval; 6859 6860 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) 6861 return(0); 6862 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) 6863 return(0); 6864 6865 /* 6866 * for equal, check if there is a node pertaining to both sets 6867 */ 6868 if (neq == 0) 6869 for (i = 0;i < ns1->nodeNr;i++) 6870 for (j = 0;j < ns2->nodeNr;j++) 6871 if (ns1->nodeTab[i] == ns2->nodeTab[j]) 6872 return(1); 6873 6874 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *)); 6875 if (values1 == NULL) { 6876 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6877 return(0); 6878 } 6879 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int)); 6880 if (hashs1 == NULL) { 6881 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6882 xmlFree(values1); 6883 return(0); 6884 } 6885 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *)); 6886 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *)); 6887 if (values2 == NULL) { 6888 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6889 xmlFree(hashs1); 6890 xmlFree(values1); 6891 return(0); 6892 } 6893 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int)); 6894 if (hashs2 == NULL) { 6895 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6896 xmlFree(hashs1); 6897 xmlFree(values1); 6898 xmlFree(values2); 6899 return(0); 6900 } 6901 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *)); 6902 for (i = 0;i < ns1->nodeNr;i++) { 6903 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]); 6904 for (j = 0;j < ns2->nodeNr;j++) { 6905 if (i == 0) 6906 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]); 6907 if (hashs1[i] != hashs2[j]) { 6908 if (neq) { 6909 ret = 1; 6910 break; 6911 } 6912 } 6913 else { 6914 if (values1[i] == NULL) 6915 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]); 6916 if (values2[j] == NULL) 6917 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]); 6918 ret = xmlStrEqual(values1[i], values2[j]) ^ neq; 6919 if (ret) 6920 break; 6921 } 6922 } 6923 if (ret) 6924 break; 6925 } 6926 for (i = 0;i < ns1->nodeNr;i++) 6927 if (values1[i] != NULL) 6928 xmlFree(values1[i]); 6929 for (j = 0;j < ns2->nodeNr;j++) 6930 if (values2[j] != NULL) 6931 xmlFree(values2[j]); 6932 xmlFree(values1); 6933 xmlFree(values2); 6934 xmlFree(hashs1); 6935 xmlFree(hashs2); 6936 return(ret); 6937} 6938 6939static int 6940xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt, 6941 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) { 6942 int ret = 0; 6943 /* 6944 *At this point we are assured neither arg1 nor arg2 6945 *is a nodeset, so we can just pick the appropriate routine. 6946 */ 6947 switch (arg1->type) { 6948 case XPATH_UNDEFINED: 6949#ifdef DEBUG_EXPR 6950 xmlGenericError(xmlGenericErrorContext, 6951 "Equal: undefined\n"); 6952#endif 6953 break; 6954 case XPATH_BOOLEAN: 6955 switch (arg2->type) { 6956 case XPATH_UNDEFINED: 6957#ifdef DEBUG_EXPR 6958 xmlGenericError(xmlGenericErrorContext, 6959 "Equal: undefined\n"); 6960#endif 6961 break; 6962 case XPATH_BOOLEAN: 6963#ifdef DEBUG_EXPR 6964 xmlGenericError(xmlGenericErrorContext, 6965 "Equal: %d boolean %d \n", 6966 arg1->boolval, arg2->boolval); 6967#endif 6968 ret = (arg1->boolval == arg2->boolval); 6969 break; 6970 case XPATH_NUMBER: 6971 ret = (arg1->boolval == 6972 xmlXPathCastNumberToBoolean(arg2->floatval)); 6973 break; 6974 case XPATH_STRING: 6975 if ((arg2->stringval == NULL) || 6976 (arg2->stringval[0] == 0)) ret = 0; 6977 else 6978 ret = 1; 6979 ret = (arg1->boolval == ret); 6980 break; 6981 case XPATH_USERS: 6982 case XPATH_POINT: 6983 case XPATH_RANGE: 6984 case XPATH_LOCATIONSET: 6985 TODO 6986 break; 6987 case XPATH_NODESET: 6988 case XPATH_XSLT_TREE: 6989 break; 6990 } 6991 break; 6992 case XPATH_NUMBER: 6993 switch (arg2->type) { 6994 case XPATH_UNDEFINED: 6995#ifdef DEBUG_EXPR 6996 xmlGenericError(xmlGenericErrorContext, 6997 "Equal: undefined\n"); 6998#endif 6999 break; 7000 case XPATH_BOOLEAN: 7001 ret = (arg2->boolval== 7002 xmlXPathCastNumberToBoolean(arg1->floatval)); 7003 break; 7004 case XPATH_STRING: 7005 valuePush(ctxt, arg2); 7006 xmlXPathNumberFunction(ctxt, 1); 7007 arg2 = valuePop(ctxt); 7008 /* no break on purpose */ 7009 case XPATH_NUMBER: 7010 /* Hand check NaN and Infinity equalities */ 7011 if (xmlXPathIsNaN(arg1->floatval) || 7012 xmlXPathIsNaN(arg2->floatval)) { 7013 ret = 0; 7014 } else if (xmlXPathIsInf(arg1->floatval) == 1) { 7015 if (xmlXPathIsInf(arg2->floatval) == 1) 7016 ret = 1; 7017 else 7018 ret = 0; 7019 } else if (xmlXPathIsInf(arg1->floatval) == -1) { 7020 if (xmlXPathIsInf(arg2->floatval) == -1) 7021 ret = 1; 7022 else 7023 ret = 0; 7024 } else if (xmlXPathIsInf(arg2->floatval) == 1) { 7025 if (xmlXPathIsInf(arg1->floatval) == 1) 7026 ret = 1; 7027 else 7028 ret = 0; 7029 } else if (xmlXPathIsInf(arg2->floatval) == -1) { 7030 if (xmlXPathIsInf(arg1->floatval) == -1) 7031 ret = 1; 7032 else 7033 ret = 0; 7034 } else { 7035 ret = (arg1->floatval == arg2->floatval); 7036 } 7037 break; 7038 case XPATH_USERS: 7039 case XPATH_POINT: 7040 case XPATH_RANGE: 7041 case XPATH_LOCATIONSET: 7042 TODO 7043 break; 7044 case XPATH_NODESET: 7045 case XPATH_XSLT_TREE: 7046 break; 7047 } 7048 break; 7049 case XPATH_STRING: 7050 switch (arg2->type) { 7051 case XPATH_UNDEFINED: 7052#ifdef DEBUG_EXPR 7053 xmlGenericError(xmlGenericErrorContext, 7054 "Equal: undefined\n"); 7055#endif 7056 break; 7057 case XPATH_BOOLEAN: 7058 if ((arg1->stringval == NULL) || 7059 (arg1->stringval[0] == 0)) ret = 0; 7060 else 7061 ret = 1; 7062 ret = (arg2->boolval == ret); 7063 break; 7064 case XPATH_STRING: 7065 ret = xmlStrEqual(arg1->stringval, arg2->stringval); 7066 break; 7067 case XPATH_NUMBER: 7068 valuePush(ctxt, arg1); 7069 xmlXPathNumberFunction(ctxt, 1); 7070 arg1 = valuePop(ctxt); 7071 /* Hand check NaN and Infinity equalities */ 7072 if (xmlXPathIsNaN(arg1->floatval) || 7073 xmlXPathIsNaN(arg2->floatval)) { 7074 ret = 0; 7075 } else if (xmlXPathIsInf(arg1->floatval) == 1) { 7076 if (xmlXPathIsInf(arg2->floatval) == 1) 7077 ret = 1; 7078 else 7079 ret = 0; 7080 } else if (xmlXPathIsInf(arg1->floatval) == -1) { 7081 if (xmlXPathIsInf(arg2->floatval) == -1) 7082 ret = 1; 7083 else 7084 ret = 0; 7085 } else if (xmlXPathIsInf(arg2->floatval) == 1) { 7086 if (xmlXPathIsInf(arg1->floatval) == 1) 7087 ret = 1; 7088 else 7089 ret = 0; 7090 } else if (xmlXPathIsInf(arg2->floatval) == -1) { 7091 if (xmlXPathIsInf(arg1->floatval) == -1) 7092 ret = 1; 7093 else 7094 ret = 0; 7095 } else { 7096 ret = (arg1->floatval == arg2->floatval); 7097 } 7098 break; 7099 case XPATH_USERS: 7100 case XPATH_POINT: 7101 case XPATH_RANGE: 7102 case XPATH_LOCATIONSET: 7103 TODO 7104 break; 7105 case XPATH_NODESET: 7106 case XPATH_XSLT_TREE: 7107 break; 7108 } 7109 break; 7110 case XPATH_USERS: 7111 case XPATH_POINT: 7112 case XPATH_RANGE: 7113 case XPATH_LOCATIONSET: 7114 TODO 7115 break; 7116 case XPATH_NODESET: 7117 case XPATH_XSLT_TREE: 7118 break; 7119 } 7120 xmlXPathReleaseObject(ctxt->context, arg1); 7121 xmlXPathReleaseObject(ctxt->context, arg2); 7122 return(ret); 7123} 7124 7125/** 7126 * xmlXPathEqualValues: 7127 * @ctxt: the XPath Parser context 7128 * 7129 * Implement the equal operation on XPath objects content: @arg1 == @arg2 7130 * 7131 * Returns 0 or 1 depending on the results of the test. 7132 */ 7133int 7134xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) { 7135 xmlXPathObjectPtr arg1, arg2, argtmp; 7136 int ret = 0; 7137 7138 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); 7139 arg2 = valuePop(ctxt); 7140 arg1 = valuePop(ctxt); 7141 if ((arg1 == NULL) || (arg2 == NULL)) { 7142 if (arg1 != NULL) 7143 xmlXPathReleaseObject(ctxt->context, arg1); 7144 else 7145 xmlXPathReleaseObject(ctxt->context, arg2); 7146 XP_ERROR0(XPATH_INVALID_OPERAND); 7147 } 7148 7149 if (arg1 == arg2) { 7150#ifdef DEBUG_EXPR 7151 xmlGenericError(xmlGenericErrorContext, 7152 "Equal: by pointer\n"); 7153#endif 7154 xmlXPathFreeObject(arg1); 7155 return(1); 7156 } 7157 7158 /* 7159 *If either argument is a nodeset, it's a 'special case' 7160 */ 7161 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 7162 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7163 /* 7164 *Hack it to assure arg1 is the nodeset 7165 */ 7166 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) { 7167 argtmp = arg2; 7168 arg2 = arg1; 7169 arg1 = argtmp; 7170 } 7171 switch (arg2->type) { 7172 case XPATH_UNDEFINED: 7173#ifdef DEBUG_EXPR 7174 xmlGenericError(xmlGenericErrorContext, 7175 "Equal: undefined\n"); 7176#endif 7177 break; 7178 case XPATH_NODESET: 7179 case XPATH_XSLT_TREE: 7180 ret = xmlXPathEqualNodeSets(arg1, arg2, 0); 7181 break; 7182 case XPATH_BOOLEAN: 7183 if ((arg1->nodesetval == NULL) || 7184 (arg1->nodesetval->nodeNr == 0)) ret = 0; 7185 else 7186 ret = 1; 7187 ret = (ret == arg2->boolval); 7188 break; 7189 case XPATH_NUMBER: 7190 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0); 7191 break; 7192 case XPATH_STRING: 7193 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0); 7194 break; 7195 case XPATH_USERS: 7196 case XPATH_POINT: 7197 case XPATH_RANGE: 7198 case XPATH_LOCATIONSET: 7199 TODO 7200 break; 7201 } 7202 xmlXPathReleaseObject(ctxt->context, arg1); 7203 xmlXPathReleaseObject(ctxt->context, arg2); 7204 return(ret); 7205 } 7206 7207 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2)); 7208} 7209 7210/** 7211 * xmlXPathNotEqualValues: 7212 * @ctxt: the XPath Parser context 7213 * 7214 * Implement the equal operation on XPath objects content: @arg1 == @arg2 7215 * 7216 * Returns 0 or 1 depending on the results of the test. 7217 */ 7218int 7219xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) { 7220 xmlXPathObjectPtr arg1, arg2, argtmp; 7221 int ret = 0; 7222 7223 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); 7224 arg2 = valuePop(ctxt); 7225 arg1 = valuePop(ctxt); 7226 if ((arg1 == NULL) || (arg2 == NULL)) { 7227 if (arg1 != NULL) 7228 xmlXPathReleaseObject(ctxt->context, arg1); 7229 else 7230 xmlXPathReleaseObject(ctxt->context, arg2); 7231 XP_ERROR0(XPATH_INVALID_OPERAND); 7232 } 7233 7234 if (arg1 == arg2) { 7235#ifdef DEBUG_EXPR 7236 xmlGenericError(xmlGenericErrorContext, 7237 "NotEqual: by pointer\n"); 7238#endif 7239 xmlXPathReleaseObject(ctxt->context, arg1); 7240 return(0); 7241 } 7242 7243 /* 7244 *If either argument is a nodeset, it's a 'special case' 7245 */ 7246 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 7247 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7248 /* 7249 *Hack it to assure arg1 is the nodeset 7250 */ 7251 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) { 7252 argtmp = arg2; 7253 arg2 = arg1; 7254 arg1 = argtmp; 7255 } 7256 switch (arg2->type) { 7257 case XPATH_UNDEFINED: 7258#ifdef DEBUG_EXPR 7259 xmlGenericError(xmlGenericErrorContext, 7260 "NotEqual: undefined\n"); 7261#endif 7262 break; 7263 case XPATH_NODESET: 7264 case XPATH_XSLT_TREE: 7265 ret = xmlXPathEqualNodeSets(arg1, arg2, 1); 7266 break; 7267 case XPATH_BOOLEAN: 7268 if ((arg1->nodesetval == NULL) || 7269 (arg1->nodesetval->nodeNr == 0)) ret = 0; 7270 else 7271 ret = 1; 7272 ret = (ret != arg2->boolval); 7273 break; 7274 case XPATH_NUMBER: 7275 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1); 7276 break; 7277 case XPATH_STRING: 7278 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1); 7279 break; 7280 case XPATH_USERS: 7281 case XPATH_POINT: 7282 case XPATH_RANGE: 7283 case XPATH_LOCATIONSET: 7284 TODO 7285 break; 7286 } 7287 xmlXPathReleaseObject(ctxt->context, arg1); 7288 xmlXPathReleaseObject(ctxt->context, arg2); 7289 return(ret); 7290 } 7291 7292 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2)); 7293} 7294 7295/** 7296 * xmlXPathCompareValues: 7297 * @ctxt: the XPath Parser context 7298 * @inf: less than (1) or greater than (0) 7299 * @strict: is the comparison strict 7300 * 7301 * Implement the compare operation on XPath objects: 7302 * @arg1 < @arg2 (1, 1, ... 7303 * @arg1 <= @arg2 (1, 0, ... 7304 * @arg1 > @arg2 (0, 1, ... 7305 * @arg1 >= @arg2 (0, 0, ... 7306 * 7307 * When neither object to be compared is a node-set and the operator is 7308 * <=, <, >=, >, then the objects are compared by converted both objects 7309 * to numbers and comparing the numbers according to IEEE 754. The < 7310 * comparison will be true if and only if the first number is less than the 7311 * second number. The <= comparison will be true if and only if the first 7312 * number is less than or equal to the second number. The > comparison 7313 * will be true if and only if the first number is greater than the second 7314 * number. The >= comparison will be true if and only if the first number 7315 * is greater than or equal to the second number. 7316 * 7317 * Returns 1 if the comparison succeeded, 0 if it failed 7318 */ 7319int 7320xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) { 7321 int ret = 0, arg1i = 0, arg2i = 0; 7322 xmlXPathObjectPtr arg1, arg2; 7323 7324 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); 7325 arg2 = valuePop(ctxt); 7326 arg1 = valuePop(ctxt); 7327 if ((arg1 == NULL) || (arg2 == NULL)) { 7328 if (arg1 != NULL) 7329 xmlXPathReleaseObject(ctxt->context, arg1); 7330 else 7331 xmlXPathReleaseObject(ctxt->context, arg2); 7332 XP_ERROR0(XPATH_INVALID_OPERAND); 7333 } 7334 7335 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 7336 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7337 /* 7338 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments 7339 * are not freed from within this routine; they will be freed from the 7340 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue 7341 */ 7342 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) && 7343 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){ 7344 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2); 7345 } else { 7346 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7347 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict, 7348 arg1, arg2); 7349 } else { 7350 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict, 7351 arg2, arg1); 7352 } 7353 } 7354 return(ret); 7355 } 7356 7357 if (arg1->type != XPATH_NUMBER) { 7358 valuePush(ctxt, arg1); 7359 xmlXPathNumberFunction(ctxt, 1); 7360 arg1 = valuePop(ctxt); 7361 } 7362 if (arg1->type != XPATH_NUMBER) { 7363 xmlXPathFreeObject(arg1); 7364 xmlXPathFreeObject(arg2); 7365 XP_ERROR0(XPATH_INVALID_OPERAND); 7366 } 7367 if (arg2->type != XPATH_NUMBER) { 7368 valuePush(ctxt, arg2); 7369 xmlXPathNumberFunction(ctxt, 1); 7370 arg2 = valuePop(ctxt); 7371 } 7372 if (arg2->type != XPATH_NUMBER) { 7373 xmlXPathReleaseObject(ctxt->context, arg1); 7374 xmlXPathReleaseObject(ctxt->context, arg2); 7375 XP_ERROR0(XPATH_INVALID_OPERAND); 7376 } 7377 /* 7378 * Add tests for infinity and nan 7379 * => feedback on 3.4 for Inf and NaN 7380 */ 7381 /* Hand check NaN and Infinity comparisons */ 7382 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) { 7383 ret=0; 7384 } else { 7385 arg1i=xmlXPathIsInf(arg1->floatval); 7386 arg2i=xmlXPathIsInf(arg2->floatval); 7387 if (inf && strict) { 7388 if ((arg1i == -1 && arg2i != -1) || 7389 (arg2i == 1 && arg1i != 1)) { 7390 ret = 1; 7391 } else if (arg1i == 0 && arg2i == 0) { 7392 ret = (arg1->floatval < arg2->floatval); 7393 } else { 7394 ret = 0; 7395 } 7396 } 7397 else if (inf && !strict) { 7398 if (arg1i == -1 || arg2i == 1) { 7399 ret = 1; 7400 } else if (arg1i == 0 && arg2i == 0) { 7401 ret = (arg1->floatval <= arg2->floatval); 7402 } else { 7403 ret = 0; 7404 } 7405 } 7406 else if (!inf && strict) { 7407 if ((arg1i == 1 && arg2i != 1) || 7408 (arg2i == -1 && arg1i != -1)) { 7409 ret = 1; 7410 } else if (arg1i == 0 && arg2i == 0) { 7411 ret = (arg1->floatval > arg2->floatval); 7412 } else { 7413 ret = 0; 7414 } 7415 } 7416 else if (!inf && !strict) { 7417 if (arg1i == 1 || arg2i == -1) { 7418 ret = 1; 7419 } else if (arg1i == 0 && arg2i == 0) { 7420 ret = (arg1->floatval >= arg2->floatval); 7421 } else { 7422 ret = 0; 7423 } 7424 } 7425 } 7426 xmlXPathReleaseObject(ctxt->context, arg1); 7427 xmlXPathReleaseObject(ctxt->context, arg2); 7428 return(ret); 7429} 7430 7431/** 7432 * xmlXPathValueFlipSign: 7433 * @ctxt: the XPath Parser context 7434 * 7435 * Implement the unary - operation on an XPath object 7436 * The numeric operators convert their operands to numbers as if 7437 * by calling the number function. 7438 */ 7439void 7440xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) { 7441 if ((ctxt == NULL) || (ctxt->context == NULL)) return; 7442 CAST_TO_NUMBER; 7443 CHECK_TYPE(XPATH_NUMBER); 7444 if (xmlXPathIsNaN(ctxt->value->floatval)) 7445 ctxt->value->floatval=xmlXPathNAN; 7446 else if (xmlXPathIsInf(ctxt->value->floatval) == 1) 7447 ctxt->value->floatval=xmlXPathNINF; 7448 else if (xmlXPathIsInf(ctxt->value->floatval) == -1) 7449 ctxt->value->floatval=xmlXPathPINF; 7450 else if (ctxt->value->floatval == 0) { 7451 if (xmlXPathGetSign(ctxt->value->floatval) == 0) 7452 ctxt->value->floatval = xmlXPathNZERO; 7453 else 7454 ctxt->value->floatval = 0; 7455 } 7456 else 7457 ctxt->value->floatval = - ctxt->value->floatval; 7458} 7459 7460/** 7461 * xmlXPathAddValues: 7462 * @ctxt: the XPath Parser context 7463 * 7464 * Implement the add operation on XPath objects: 7465 * The numeric operators convert their operands to numbers as if 7466 * by calling the number function. 7467 */ 7468void 7469xmlXPathAddValues(xmlXPathParserContextPtr ctxt) { 7470 xmlXPathObjectPtr arg; 7471 double val; 7472 7473 arg = valuePop(ctxt); 7474 if (arg == NULL) 7475 XP_ERROR(XPATH_INVALID_OPERAND); 7476 val = xmlXPathCastToNumber(arg); 7477 xmlXPathReleaseObject(ctxt->context, arg); 7478 CAST_TO_NUMBER; 7479 CHECK_TYPE(XPATH_NUMBER); 7480 ctxt->value->floatval += val; 7481} 7482 7483/** 7484 * xmlXPathSubValues: 7485 * @ctxt: the XPath Parser context 7486 * 7487 * Implement the subtraction operation on XPath objects: 7488 * The numeric operators convert their operands to numbers as if 7489 * by calling the number function. 7490 */ 7491void 7492xmlXPathSubValues(xmlXPathParserContextPtr ctxt) { 7493 xmlXPathObjectPtr arg; 7494 double val; 7495 7496 arg = valuePop(ctxt); 7497 if (arg == NULL) 7498 XP_ERROR(XPATH_INVALID_OPERAND); 7499 val = xmlXPathCastToNumber(arg); 7500 xmlXPathReleaseObject(ctxt->context, arg); 7501 CAST_TO_NUMBER; 7502 CHECK_TYPE(XPATH_NUMBER); 7503 ctxt->value->floatval -= val; 7504} 7505 7506/** 7507 * xmlXPathMultValues: 7508 * @ctxt: the XPath Parser context 7509 * 7510 * Implement the multiply operation on XPath objects: 7511 * The numeric operators convert their operands to numbers as if 7512 * by calling the number function. 7513 */ 7514void 7515xmlXPathMultValues(xmlXPathParserContextPtr ctxt) { 7516 xmlXPathObjectPtr arg; 7517 double val; 7518 7519 arg = valuePop(ctxt); 7520 if (arg == NULL) 7521 XP_ERROR(XPATH_INVALID_OPERAND); 7522 val = xmlXPathCastToNumber(arg); 7523 xmlXPathReleaseObject(ctxt->context, arg); 7524 CAST_TO_NUMBER; 7525 CHECK_TYPE(XPATH_NUMBER); 7526 ctxt->value->floatval *= val; 7527} 7528 7529/** 7530 * xmlXPathDivValues: 7531 * @ctxt: the XPath Parser context 7532 * 7533 * Implement the div operation on XPath objects @arg1 / @arg2: 7534 * The numeric operators convert their operands to numbers as if 7535 * by calling the number function. 7536 */ 7537void 7538xmlXPathDivValues(xmlXPathParserContextPtr ctxt) { 7539 xmlXPathObjectPtr arg; 7540 double val; 7541 7542 arg = valuePop(ctxt); 7543 if (arg == NULL) 7544 XP_ERROR(XPATH_INVALID_OPERAND); 7545 val = xmlXPathCastToNumber(arg); 7546 xmlXPathReleaseObject(ctxt->context, arg); 7547 CAST_TO_NUMBER; 7548 CHECK_TYPE(XPATH_NUMBER); 7549 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval)) 7550 ctxt->value->floatval = xmlXPathNAN; 7551 else if (val == 0 && xmlXPathGetSign(val) != 0) { 7552 if (ctxt->value->floatval == 0) 7553 ctxt->value->floatval = xmlXPathNAN; 7554 else if (ctxt->value->floatval > 0) 7555 ctxt->value->floatval = xmlXPathNINF; 7556 else if (ctxt->value->floatval < 0) 7557 ctxt->value->floatval = xmlXPathPINF; 7558 } 7559 else if (val == 0) { 7560 if (ctxt->value->floatval == 0) 7561 ctxt->value->floatval = xmlXPathNAN; 7562 else if (ctxt->value->floatval > 0) 7563 ctxt->value->floatval = xmlXPathPINF; 7564 else if (ctxt->value->floatval < 0) 7565 ctxt->value->floatval = xmlXPathNINF; 7566 } else 7567 ctxt->value->floatval /= val; 7568} 7569 7570/** 7571 * xmlXPathModValues: 7572 * @ctxt: the XPath Parser context 7573 * 7574 * Implement the mod operation on XPath objects: @arg1 / @arg2 7575 * The numeric operators convert their operands to numbers as if 7576 * by calling the number function. 7577 */ 7578void 7579xmlXPathModValues(xmlXPathParserContextPtr ctxt) { 7580 xmlXPathObjectPtr arg; 7581 double arg1, arg2; 7582 7583 arg = valuePop(ctxt); 7584 if (arg == NULL) 7585 XP_ERROR(XPATH_INVALID_OPERAND); 7586 arg2 = xmlXPathCastToNumber(arg); 7587 xmlXPathReleaseObject(ctxt->context, arg); 7588 CAST_TO_NUMBER; 7589 CHECK_TYPE(XPATH_NUMBER); 7590 arg1 = ctxt->value->floatval; 7591 if (arg2 == 0) 7592 ctxt->value->floatval = xmlXPathNAN; 7593 else { 7594 ctxt->value->floatval = fmod(arg1, arg2); 7595 } 7596} 7597 7598/************************************************************************ 7599 * * 7600 * The traversal functions * 7601 * * 7602 ************************************************************************/ 7603 7604/* 7605 * A traversal function enumerates nodes along an axis. 7606 * Initially it must be called with NULL, and it indicates 7607 * termination on the axis by returning NULL. 7608 */ 7609typedef xmlNodePtr (*xmlXPathTraversalFunction) 7610 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur); 7611 7612/* 7613 * xmlXPathTraversalFunctionExt: 7614 * A traversal function enumerates nodes along an axis. 7615 * Initially it must be called with NULL, and it indicates 7616 * termination on the axis by returning NULL. 7617 * The context node of the traversal is specified via @contextNode. 7618 */ 7619typedef xmlNodePtr (*xmlXPathTraversalFunctionExt) 7620 (xmlNodePtr cur, xmlNodePtr contextNode); 7621 7622/* 7623 * xmlXPathNodeSetMergeFunction: 7624 * Used for merging node sets in xmlXPathCollectAndTest(). 7625 */ 7626typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction) 7627 (xmlNodeSetPtr, xmlNodeSetPtr, int); 7628 7629 7630/** 7631 * xmlXPathNextSelf: 7632 * @ctxt: the XPath Parser context 7633 * @cur: the current node in the traversal 7634 * 7635 * Traversal function for the "self" direction 7636 * The self axis contains just the context node itself 7637 * 7638 * Returns the next element following that axis 7639 */ 7640xmlNodePtr 7641xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7642 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7643 if (cur == NULL) 7644 return(ctxt->context->node); 7645 return(NULL); 7646} 7647 7648/** 7649 * xmlXPathNextChild: 7650 * @ctxt: the XPath Parser context 7651 * @cur: the current node in the traversal 7652 * 7653 * Traversal function for the "child" direction 7654 * The child axis contains the children of the context node in document order. 7655 * 7656 * Returns the next element following that axis 7657 */ 7658xmlNodePtr 7659xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7660 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7661 if (cur == NULL) { 7662 if (ctxt->context->node == NULL) return(NULL); 7663 switch (ctxt->context->node->type) { 7664 case XML_ELEMENT_NODE: 7665 case XML_TEXT_NODE: 7666 case XML_CDATA_SECTION_NODE: 7667 case XML_ENTITY_REF_NODE: 7668 case XML_ENTITY_NODE: 7669 case XML_PI_NODE: 7670 case XML_COMMENT_NODE: 7671 case XML_NOTATION_NODE: 7672 case XML_DTD_NODE: 7673 return(ctxt->context->node->children); 7674 case XML_DOCUMENT_NODE: 7675 case XML_DOCUMENT_TYPE_NODE: 7676 case XML_DOCUMENT_FRAG_NODE: 7677 case XML_HTML_DOCUMENT_NODE: 7678#ifdef LIBXML_DOCB_ENABLED 7679 case XML_DOCB_DOCUMENT_NODE: 7680#endif 7681 return(((xmlDocPtr) ctxt->context->node)->children); 7682 case XML_ELEMENT_DECL: 7683 case XML_ATTRIBUTE_DECL: 7684 case XML_ENTITY_DECL: 7685 case XML_ATTRIBUTE_NODE: 7686 case XML_NAMESPACE_DECL: 7687 case XML_XINCLUDE_START: 7688 case XML_XINCLUDE_END: 7689 return(NULL); 7690 } 7691 return(NULL); 7692 } 7693 if ((cur->type == XML_DOCUMENT_NODE) || 7694 (cur->type == XML_HTML_DOCUMENT_NODE)) 7695 return(NULL); 7696 return(cur->next); 7697} 7698 7699/** 7700 * xmlXPathNextChildElement: 7701 * @ctxt: the XPath Parser context 7702 * @cur: the current node in the traversal 7703 * 7704 * Traversal function for the "child" direction and nodes of type element. 7705 * The child axis contains the children of the context node in document order. 7706 * 7707 * Returns the next element following that axis 7708 */ 7709static xmlNodePtr 7710xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7711 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7712 if (cur == NULL) { 7713 cur = ctxt->context->node; 7714 if (cur == NULL) return(NULL); 7715 /* 7716 * Get the first element child. 7717 */ 7718 switch (cur->type) { 7719 case XML_ELEMENT_NODE: 7720 case XML_DOCUMENT_FRAG_NODE: 7721 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */ 7722 case XML_ENTITY_NODE: 7723 cur = cur->children; 7724 if (cur != NULL) { 7725 if (cur->type == XML_ELEMENT_NODE) 7726 return(cur); 7727 do { 7728 cur = cur->next; 7729 } while ((cur != NULL) && 7730 (cur->type != XML_ELEMENT_NODE)); 7731 return(cur); 7732 } 7733 return(NULL); 7734 case XML_DOCUMENT_NODE: 7735 case XML_HTML_DOCUMENT_NODE: 7736#ifdef LIBXML_DOCB_ENABLED 7737 case XML_DOCB_DOCUMENT_NODE: 7738#endif 7739 return(xmlDocGetRootElement((xmlDocPtr) cur)); 7740 default: 7741 return(NULL); 7742 } 7743 return(NULL); 7744 } 7745 /* 7746 * Get the next sibling element node. 7747 */ 7748 switch (cur->type) { 7749 case XML_ELEMENT_NODE: 7750 case XML_TEXT_NODE: 7751 case XML_ENTITY_REF_NODE: 7752 case XML_ENTITY_NODE: 7753 case XML_CDATA_SECTION_NODE: 7754 case XML_PI_NODE: 7755 case XML_COMMENT_NODE: 7756 case XML_XINCLUDE_END: 7757 break; 7758 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */ 7759 default: 7760 return(NULL); 7761 } 7762 if (cur->next != NULL) { 7763 if (cur->next->type == XML_ELEMENT_NODE) 7764 return(cur->next); 7765 cur = cur->next; 7766 do { 7767 cur = cur->next; 7768 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE)); 7769 return(cur); 7770 } 7771 return(NULL); 7772} 7773 7774/** 7775 * xmlXPathNextDescendantOrSelfElemParent: 7776 * @ctxt: the XPath Parser context 7777 * @cur: the current node in the traversal 7778 * 7779 * Traversal function for the "descendant-or-self" axis. 7780 * Additionally it returns only nodes which can be parents of 7781 * element nodes. 7782 * 7783 * 7784 * Returns the next element following that axis 7785 */ 7786static xmlNodePtr 7787xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur, 7788 xmlNodePtr contextNode) 7789{ 7790 if (cur == NULL) { 7791 if (contextNode == NULL) 7792 return(NULL); 7793 switch (contextNode->type) { 7794 case XML_ELEMENT_NODE: 7795 case XML_XINCLUDE_START: 7796 case XML_DOCUMENT_FRAG_NODE: 7797 case XML_DOCUMENT_NODE: 7798#ifdef LIBXML_DOCB_ENABLED 7799 case XML_DOCB_DOCUMENT_NODE: 7800#endif 7801 case XML_HTML_DOCUMENT_NODE: 7802 return(contextNode); 7803 default: 7804 return(NULL); 7805 } 7806 return(NULL); 7807 } else { 7808 xmlNodePtr start = cur; 7809 7810 while (cur != NULL) { 7811 switch (cur->type) { 7812 case XML_ELEMENT_NODE: 7813 /* TODO: OK to have XInclude here? */ 7814 case XML_XINCLUDE_START: 7815 case XML_DOCUMENT_FRAG_NODE: 7816 if (cur != start) 7817 return(cur); 7818 if (cur->children != NULL) { 7819 cur = cur->children; 7820 continue; 7821 } 7822 break; 7823 /* Not sure if we need those here. */ 7824 case XML_DOCUMENT_NODE: 7825#ifdef LIBXML_DOCB_ENABLED 7826 case XML_DOCB_DOCUMENT_NODE: 7827#endif 7828 case XML_HTML_DOCUMENT_NODE: 7829 if (cur != start) 7830 return(cur); 7831 return(xmlDocGetRootElement((xmlDocPtr) cur)); 7832 default: 7833 break; 7834 } 7835 7836next_sibling: 7837 if ((cur == NULL) || (cur == contextNode)) 7838 return(NULL); 7839 if (cur->next != NULL) { 7840 cur = cur->next; 7841 } else { 7842 cur = cur->parent; 7843 goto next_sibling; 7844 } 7845 } 7846 } 7847 return(NULL); 7848} 7849 7850/** 7851 * xmlXPathNextDescendant: 7852 * @ctxt: the XPath Parser context 7853 * @cur: the current node in the traversal 7854 * 7855 * Traversal function for the "descendant" direction 7856 * the descendant axis contains the descendants of the context node in document 7857 * order; a descendant is a child or a child of a child and so on. 7858 * 7859 * Returns the next element following that axis 7860 */ 7861xmlNodePtr 7862xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7863 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7864 if (cur == NULL) { 7865 if (ctxt->context->node == NULL) 7866 return(NULL); 7867 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 7868 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 7869 return(NULL); 7870 7871 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc) 7872 return(ctxt->context->doc->children); 7873 return(ctxt->context->node->children); 7874 } 7875 7876 if (cur->type == XML_NAMESPACE_DECL) 7877 return(NULL); 7878 if (cur->children != NULL) { 7879 /* 7880 * Do not descend on entities declarations 7881 */ 7882 if (cur->children->type != XML_ENTITY_DECL) { 7883 cur = cur->children; 7884 /* 7885 * Skip DTDs 7886 */ 7887 if (cur->type != XML_DTD_NODE) 7888 return(cur); 7889 } 7890 } 7891 7892 if (cur == ctxt->context->node) return(NULL); 7893 7894 while (cur->next != NULL) { 7895 cur = cur->next; 7896 if ((cur->type != XML_ENTITY_DECL) && 7897 (cur->type != XML_DTD_NODE)) 7898 return(cur); 7899 } 7900 7901 do { 7902 cur = cur->parent; 7903 if (cur == NULL) break; 7904 if (cur == ctxt->context->node) return(NULL); 7905 if (cur->next != NULL) { 7906 cur = cur->next; 7907 return(cur); 7908 } 7909 } while (cur != NULL); 7910 return(cur); 7911} 7912 7913/** 7914 * xmlXPathNextDescendantOrSelf: 7915 * @ctxt: the XPath Parser context 7916 * @cur: the current node in the traversal 7917 * 7918 * Traversal function for the "descendant-or-self" direction 7919 * the descendant-or-self axis contains the context node and the descendants 7920 * of the context node in document order; thus the context node is the first 7921 * node on the axis, and the first child of the context node is the second node 7922 * on the axis 7923 * 7924 * Returns the next element following that axis 7925 */ 7926xmlNodePtr 7927xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7928 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7929 if (cur == NULL) { 7930 if (ctxt->context->node == NULL) 7931 return(NULL); 7932 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 7933 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 7934 return(NULL); 7935 return(ctxt->context->node); 7936 } 7937 7938 return(xmlXPathNextDescendant(ctxt, cur)); 7939} 7940 7941/** 7942 * xmlXPathNextParent: 7943 * @ctxt: the XPath Parser context 7944 * @cur: the current node in the traversal 7945 * 7946 * Traversal function for the "parent" direction 7947 * The parent axis contains the parent of the context node, if there is one. 7948 * 7949 * Returns the next element following that axis 7950 */ 7951xmlNodePtr 7952xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7953 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7954 /* 7955 * the parent of an attribute or namespace node is the element 7956 * to which the attribute or namespace node is attached 7957 * Namespace handling !!! 7958 */ 7959 if (cur == NULL) { 7960 if (ctxt->context->node == NULL) return(NULL); 7961 switch (ctxt->context->node->type) { 7962 case XML_ELEMENT_NODE: 7963 case XML_TEXT_NODE: 7964 case XML_CDATA_SECTION_NODE: 7965 case XML_ENTITY_REF_NODE: 7966 case XML_ENTITY_NODE: 7967 case XML_PI_NODE: 7968 case XML_COMMENT_NODE: 7969 case XML_NOTATION_NODE: 7970 case XML_DTD_NODE: 7971 case XML_ELEMENT_DECL: 7972 case XML_ATTRIBUTE_DECL: 7973 case XML_XINCLUDE_START: 7974 case XML_XINCLUDE_END: 7975 case XML_ENTITY_DECL: 7976 if (ctxt->context->node->parent == NULL) 7977 return((xmlNodePtr) ctxt->context->doc); 7978 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) && 7979 ((ctxt->context->node->parent->name[0] == ' ') || 7980 (xmlStrEqual(ctxt->context->node->parent->name, 7981 BAD_CAST "fake node libxslt")))) 7982 return(NULL); 7983 return(ctxt->context->node->parent); 7984 case XML_ATTRIBUTE_NODE: { 7985 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node; 7986 7987 return(att->parent); 7988 } 7989 case XML_DOCUMENT_NODE: 7990 case XML_DOCUMENT_TYPE_NODE: 7991 case XML_DOCUMENT_FRAG_NODE: 7992 case XML_HTML_DOCUMENT_NODE: 7993#ifdef LIBXML_DOCB_ENABLED 7994 case XML_DOCB_DOCUMENT_NODE: 7995#endif 7996 return(NULL); 7997 case XML_NAMESPACE_DECL: { 7998 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; 7999 8000 if ((ns->next != NULL) && 8001 (ns->next->type != XML_NAMESPACE_DECL)) 8002 return((xmlNodePtr) ns->next); 8003 return(NULL); 8004 } 8005 } 8006 } 8007 return(NULL); 8008} 8009 8010/** 8011 * xmlXPathNextAncestor: 8012 * @ctxt: the XPath Parser context 8013 * @cur: the current node in the traversal 8014 * 8015 * Traversal function for the "ancestor" direction 8016 * the ancestor axis contains the ancestors of the context node; the ancestors 8017 * of the context node consist of the parent of context node and the parent's 8018 * parent and so on; the nodes are ordered in reverse document order; thus the 8019 * parent is the first node on the axis, and the parent's parent is the second 8020 * node on the axis 8021 * 8022 * Returns the next element following that axis 8023 */ 8024xmlNodePtr 8025xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8026 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8027 /* 8028 * the parent of an attribute or namespace node is the element 8029 * to which the attribute or namespace node is attached 8030 * !!!!!!!!!!!!! 8031 */ 8032 if (cur == NULL) { 8033 if (ctxt->context->node == NULL) return(NULL); 8034 switch (ctxt->context->node->type) { 8035 case XML_ELEMENT_NODE: 8036 case XML_TEXT_NODE: 8037 case XML_CDATA_SECTION_NODE: 8038 case XML_ENTITY_REF_NODE: 8039 case XML_ENTITY_NODE: 8040 case XML_PI_NODE: 8041 case XML_COMMENT_NODE: 8042 case XML_DTD_NODE: 8043 case XML_ELEMENT_DECL: 8044 case XML_ATTRIBUTE_DECL: 8045 case XML_ENTITY_DECL: 8046 case XML_NOTATION_NODE: 8047 case XML_XINCLUDE_START: 8048 case XML_XINCLUDE_END: 8049 if (ctxt->context->node->parent == NULL) 8050 return((xmlNodePtr) ctxt->context->doc); 8051 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) && 8052 ((ctxt->context->node->parent->name[0] == ' ') || 8053 (xmlStrEqual(ctxt->context->node->parent->name, 8054 BAD_CAST "fake node libxslt")))) 8055 return(NULL); 8056 return(ctxt->context->node->parent); 8057 case XML_ATTRIBUTE_NODE: { 8058 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node; 8059 8060 return(tmp->parent); 8061 } 8062 case XML_DOCUMENT_NODE: 8063 case XML_DOCUMENT_TYPE_NODE: 8064 case XML_DOCUMENT_FRAG_NODE: 8065 case XML_HTML_DOCUMENT_NODE: 8066#ifdef LIBXML_DOCB_ENABLED 8067 case XML_DOCB_DOCUMENT_NODE: 8068#endif 8069 return(NULL); 8070 case XML_NAMESPACE_DECL: { 8071 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; 8072 8073 if ((ns->next != NULL) && 8074 (ns->next->type != XML_NAMESPACE_DECL)) 8075 return((xmlNodePtr) ns->next); 8076 /* Bad, how did that namespace end up here ? */ 8077 return(NULL); 8078 } 8079 } 8080 return(NULL); 8081 } 8082 if (cur == ctxt->context->doc->children) 8083 return((xmlNodePtr) ctxt->context->doc); 8084 if (cur == (xmlNodePtr) ctxt->context->doc) 8085 return(NULL); 8086 switch (cur->type) { 8087 case XML_ELEMENT_NODE: 8088 case XML_TEXT_NODE: 8089 case XML_CDATA_SECTION_NODE: 8090 case XML_ENTITY_REF_NODE: 8091 case XML_ENTITY_NODE: 8092 case XML_PI_NODE: 8093 case XML_COMMENT_NODE: 8094 case XML_NOTATION_NODE: 8095 case XML_DTD_NODE: 8096 case XML_ELEMENT_DECL: 8097 case XML_ATTRIBUTE_DECL: 8098 case XML_ENTITY_DECL: 8099 case XML_XINCLUDE_START: 8100 case XML_XINCLUDE_END: 8101 if (cur->parent == NULL) 8102 return(NULL); 8103 if ((cur->parent->type == XML_ELEMENT_NODE) && 8104 ((cur->parent->name[0] == ' ') || 8105 (xmlStrEqual(cur->parent->name, 8106 BAD_CAST "fake node libxslt")))) 8107 return(NULL); 8108 return(cur->parent); 8109 case XML_ATTRIBUTE_NODE: { 8110 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node; 8111 8112 return(att->parent); 8113 } 8114 case XML_NAMESPACE_DECL: { 8115 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; 8116 8117 if ((ns->next != NULL) && 8118 (ns->next->type != XML_NAMESPACE_DECL)) 8119 return((xmlNodePtr) ns->next); 8120 /* Bad, how did that namespace end up here ? */ 8121 return(NULL); 8122 } 8123 case XML_DOCUMENT_NODE: 8124 case XML_DOCUMENT_TYPE_NODE: 8125 case XML_DOCUMENT_FRAG_NODE: 8126 case XML_HTML_DOCUMENT_NODE: 8127#ifdef LIBXML_DOCB_ENABLED 8128 case XML_DOCB_DOCUMENT_NODE: 8129#endif 8130 return(NULL); 8131 } 8132 return(NULL); 8133} 8134 8135/** 8136 * xmlXPathNextAncestorOrSelf: 8137 * @ctxt: the XPath Parser context 8138 * @cur: the current node in the traversal 8139 * 8140 * Traversal function for the "ancestor-or-self" direction 8141 * he ancestor-or-self axis contains the context node and ancestors of 8142 * the context node in reverse document order; thus the context node is 8143 * the first node on the axis, and the context node's parent the second; 8144 * parent here is defined the same as with the parent axis. 8145 * 8146 * Returns the next element following that axis 8147 */ 8148xmlNodePtr 8149xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8150 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8151 if (cur == NULL) 8152 return(ctxt->context->node); 8153 return(xmlXPathNextAncestor(ctxt, cur)); 8154} 8155 8156/** 8157 * xmlXPathNextFollowingSibling: 8158 * @ctxt: the XPath Parser context 8159 * @cur: the current node in the traversal 8160 * 8161 * Traversal function for the "following-sibling" direction 8162 * The following-sibling axis contains the following siblings of the context 8163 * node in document order. 8164 * 8165 * Returns the next element following that axis 8166 */ 8167xmlNodePtr 8168xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8169 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8170 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 8171 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 8172 return(NULL); 8173 if (cur == (xmlNodePtr) ctxt->context->doc) 8174 return(NULL); 8175 if (cur == NULL) 8176 return(ctxt->context->node->next); 8177 return(cur->next); 8178} 8179 8180/** 8181 * xmlXPathNextPrecedingSibling: 8182 * @ctxt: the XPath Parser context 8183 * @cur: the current node in the traversal 8184 * 8185 * Traversal function for the "preceding-sibling" direction 8186 * The preceding-sibling axis contains the preceding siblings of the context 8187 * node in reverse document order; the first preceding sibling is first on the 8188 * axis; the sibling preceding that node is the second on the axis and so on. 8189 * 8190 * Returns the next element following that axis 8191 */ 8192xmlNodePtr 8193xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8194 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8195 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 8196 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 8197 return(NULL); 8198 if (cur == (xmlNodePtr) ctxt->context->doc) 8199 return(NULL); 8200 if (cur == NULL) 8201 return(ctxt->context->node->prev); 8202 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) { 8203 cur = cur->prev; 8204 if (cur == NULL) 8205 return(ctxt->context->node->prev); 8206 } 8207 return(cur->prev); 8208} 8209 8210/** 8211 * xmlXPathNextFollowing: 8212 * @ctxt: the XPath Parser context 8213 * @cur: the current node in the traversal 8214 * 8215 * Traversal function for the "following" direction 8216 * The following axis contains all nodes in the same document as the context 8217 * node that are after the context node in document order, excluding any 8218 * descendants and excluding attribute nodes and namespace nodes; the nodes 8219 * are ordered in document order 8220 * 8221 * Returns the next element following that axis 8222 */ 8223xmlNodePtr 8224xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8225 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8226 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) && 8227 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL)) 8228 return(cur->children); 8229 8230 if (cur == NULL) { 8231 cur = ctxt->context->node; 8232 if (cur->type == XML_NAMESPACE_DECL) 8233 return(NULL); 8234 if (cur->type == XML_ATTRIBUTE_NODE) 8235 cur = cur->parent; 8236 } 8237 if (cur == NULL) return(NULL) ; /* ERROR */ 8238 if (cur->next != NULL) return(cur->next) ; 8239 do { 8240 cur = cur->parent; 8241 if (cur == NULL) break; 8242 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL); 8243 if (cur->next != NULL) return(cur->next); 8244 } while (cur != NULL); 8245 return(cur); 8246} 8247 8248/* 8249 * xmlXPathIsAncestor: 8250 * @ancestor: the ancestor node 8251 * @node: the current node 8252 * 8253 * Check that @ancestor is a @node's ancestor 8254 * 8255 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise. 8256 */ 8257static int 8258xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) { 8259 if ((ancestor == NULL) || (node == NULL)) return(0); 8260 if (node->type == XML_NAMESPACE_DECL) 8261 return(0); 8262 if (ancestor->type == XML_NAMESPACE_DECL) 8263 return(0); 8264 /* nodes need to be in the same document */ 8265 if (ancestor->doc != node->doc) return(0); 8266 /* avoid searching if ancestor or node is the root node */ 8267 if (ancestor == (xmlNodePtr) node->doc) return(1); 8268 if (node == (xmlNodePtr) ancestor->doc) return(0); 8269 while (node->parent != NULL) { 8270 if (node->parent == ancestor) 8271 return(1); 8272 node = node->parent; 8273 } 8274 return(0); 8275} 8276 8277/** 8278 * xmlXPathNextPreceding: 8279 * @ctxt: the XPath Parser context 8280 * @cur: the current node in the traversal 8281 * 8282 * Traversal function for the "preceding" direction 8283 * the preceding axis contains all nodes in the same document as the context 8284 * node that are before the context node in document order, excluding any 8285 * ancestors and excluding attribute nodes and namespace nodes; the nodes are 8286 * ordered in reverse document order 8287 * 8288 * Returns the next element following that axis 8289 */ 8290xmlNodePtr 8291xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) 8292{ 8293 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8294 if (cur == NULL) { 8295 cur = ctxt->context->node; 8296 if (cur->type == XML_NAMESPACE_DECL) 8297 return(NULL); 8298 if (cur->type == XML_ATTRIBUTE_NODE) 8299 return(cur->parent); 8300 } 8301 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) 8302 return (NULL); 8303 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) 8304 cur = cur->prev; 8305 do { 8306 if (cur->prev != NULL) { 8307 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ; 8308 return (cur); 8309 } 8310 8311 cur = cur->parent; 8312 if (cur == NULL) 8313 return (NULL); 8314 if (cur == ctxt->context->doc->children) 8315 return (NULL); 8316 } while (xmlXPathIsAncestor(cur, ctxt->context->node)); 8317 return (cur); 8318} 8319 8320/** 8321 * xmlXPathNextPrecedingInternal: 8322 * @ctxt: the XPath Parser context 8323 * @cur: the current node in the traversal 8324 * 8325 * Traversal function for the "preceding" direction 8326 * the preceding axis contains all nodes in the same document as the context 8327 * node that are before the context node in document order, excluding any 8328 * ancestors and excluding attribute nodes and namespace nodes; the nodes are 8329 * ordered in reverse document order 8330 * This is a faster implementation but internal only since it requires a 8331 * state kept in the parser context: ctxt->ancestor. 8332 * 8333 * Returns the next element following that axis 8334 */ 8335static xmlNodePtr 8336xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt, 8337 xmlNodePtr cur) 8338{ 8339 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8340 if (cur == NULL) { 8341 cur = ctxt->context->node; 8342 if (cur == NULL) 8343 return (NULL); 8344 if (cur->type == XML_NAMESPACE_DECL) 8345 return (NULL); 8346 ctxt->ancestor = cur->parent; 8347 } 8348 if (cur->type == XML_NAMESPACE_DECL) 8349 return(NULL); 8350 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) 8351 cur = cur->prev; 8352 while (cur->prev == NULL) { 8353 cur = cur->parent; 8354 if (cur == NULL) 8355 return (NULL); 8356 if (cur == ctxt->context->doc->children) 8357 return (NULL); 8358 if (cur != ctxt->ancestor) 8359 return (cur); 8360 ctxt->ancestor = cur->parent; 8361 } 8362 cur = cur->prev; 8363 while (cur->last != NULL) 8364 cur = cur->last; 8365 return (cur); 8366} 8367 8368/** 8369 * xmlXPathNextNamespace: 8370 * @ctxt: the XPath Parser context 8371 * @cur: the current attribute in the traversal 8372 * 8373 * Traversal function for the "namespace" direction 8374 * the namespace axis contains the namespace nodes of the context node; 8375 * the order of nodes on this axis is implementation-defined; the axis will 8376 * be empty unless the context node is an element 8377 * 8378 * We keep the XML namespace node at the end of the list. 8379 * 8380 * Returns the next element following that axis 8381 */ 8382xmlNodePtr 8383xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8384 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8385 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL); 8386 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) { 8387 if (ctxt->context->tmpNsList != NULL) 8388 xmlFree(ctxt->context->tmpNsList); 8389 ctxt->context->tmpNsList = 8390 xmlGetNsList(ctxt->context->doc, ctxt->context->node); 8391 ctxt->context->tmpNsNr = 0; 8392 if (ctxt->context->tmpNsList != NULL) { 8393 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) { 8394 ctxt->context->tmpNsNr++; 8395 } 8396 } 8397 return((xmlNodePtr) xmlXPathXMLNamespace); 8398 } 8399 if (ctxt->context->tmpNsNr > 0) { 8400 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr]; 8401 } else { 8402 if (ctxt->context->tmpNsList != NULL) 8403 xmlFree(ctxt->context->tmpNsList); 8404 ctxt->context->tmpNsList = NULL; 8405 return(NULL); 8406 } 8407} 8408 8409/** 8410 * xmlXPathNextAttribute: 8411 * @ctxt: the XPath Parser context 8412 * @cur: the current attribute in the traversal 8413 * 8414 * Traversal function for the "attribute" direction 8415 * TODO: support DTD inherited default attributes 8416 * 8417 * Returns the next element following that axis 8418 */ 8419xmlNodePtr 8420xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8421 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8422 if (ctxt->context->node == NULL) 8423 return(NULL); 8424 if (ctxt->context->node->type != XML_ELEMENT_NODE) 8425 return(NULL); 8426 if (cur == NULL) { 8427 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc) 8428 return(NULL); 8429 return((xmlNodePtr)ctxt->context->node->properties); 8430 } 8431 return((xmlNodePtr)cur->next); 8432} 8433 8434/************************************************************************ 8435 * * 8436 * NodeTest Functions * 8437 * * 8438 ************************************************************************/ 8439 8440#define IS_FUNCTION 200 8441 8442 8443/************************************************************************ 8444 * * 8445 * Implicit tree core function library * 8446 * * 8447 ************************************************************************/ 8448 8449/** 8450 * xmlXPathRoot: 8451 * @ctxt: the XPath Parser context 8452 * 8453 * Initialize the context to the root of the document 8454 */ 8455void 8456xmlXPathRoot(xmlXPathParserContextPtr ctxt) { 8457 if ((ctxt == NULL) || (ctxt->context == NULL)) 8458 return; 8459 ctxt->context->node = (xmlNodePtr) ctxt->context->doc; 8460 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8461 ctxt->context->node)); 8462} 8463 8464/************************************************************************ 8465 * * 8466 * The explicit core function library * 8467 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib * 8468 * * 8469 ************************************************************************/ 8470 8471 8472/** 8473 * xmlXPathLastFunction: 8474 * @ctxt: the XPath Parser context 8475 * @nargs: the number of arguments 8476 * 8477 * Implement the last() XPath function 8478 * number last() 8479 * The last function returns the number of nodes in the context node list. 8480 */ 8481void 8482xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8483 CHECK_ARITY(0); 8484 if (ctxt->context->contextSize >= 0) { 8485 valuePush(ctxt, 8486 xmlXPathCacheNewFloat(ctxt->context, 8487 (double) ctxt->context->contextSize)); 8488#ifdef DEBUG_EXPR 8489 xmlGenericError(xmlGenericErrorContext, 8490 "last() : %d\n", ctxt->context->contextSize); 8491#endif 8492 } else { 8493 XP_ERROR(XPATH_INVALID_CTXT_SIZE); 8494 } 8495} 8496 8497/** 8498 * xmlXPathPositionFunction: 8499 * @ctxt: the XPath Parser context 8500 * @nargs: the number of arguments 8501 * 8502 * Implement the position() XPath function 8503 * number position() 8504 * The position function returns the position of the context node in the 8505 * context node list. The first position is 1, and so the last position 8506 * will be equal to last(). 8507 */ 8508void 8509xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8510 CHECK_ARITY(0); 8511 if (ctxt->context->proximityPosition >= 0) { 8512 valuePush(ctxt, 8513 xmlXPathCacheNewFloat(ctxt->context, 8514 (double) ctxt->context->proximityPosition)); 8515#ifdef DEBUG_EXPR 8516 xmlGenericError(xmlGenericErrorContext, "position() : %d\n", 8517 ctxt->context->proximityPosition); 8518#endif 8519 } else { 8520 XP_ERROR(XPATH_INVALID_CTXT_POSITION); 8521 } 8522} 8523 8524/** 8525 * xmlXPathCountFunction: 8526 * @ctxt: the XPath Parser context 8527 * @nargs: the number of arguments 8528 * 8529 * Implement the count() XPath function 8530 * number count(node-set) 8531 */ 8532void 8533xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8534 xmlXPathObjectPtr cur; 8535 8536 CHECK_ARITY(1); 8537 if ((ctxt->value == NULL) || 8538 ((ctxt->value->type != XPATH_NODESET) && 8539 (ctxt->value->type != XPATH_XSLT_TREE))) 8540 XP_ERROR(XPATH_INVALID_TYPE); 8541 cur = valuePop(ctxt); 8542 8543 if ((cur == NULL) || (cur->nodesetval == NULL)) 8544 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0)); 8545 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) { 8546 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 8547 (double) cur->nodesetval->nodeNr)); 8548 } else { 8549 if ((cur->nodesetval->nodeNr != 1) || 8550 (cur->nodesetval->nodeTab == NULL)) { 8551 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0)); 8552 } else { 8553 xmlNodePtr tmp; 8554 int i = 0; 8555 8556 tmp = cur->nodesetval->nodeTab[0]; 8557 if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) { 8558 tmp = tmp->children; 8559 while (tmp != NULL) { 8560 tmp = tmp->next; 8561 i++; 8562 } 8563 } 8564 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i)); 8565 } 8566 } 8567 xmlXPathReleaseObject(ctxt->context, cur); 8568} 8569 8570/** 8571 * xmlXPathGetElementsByIds: 8572 * @doc: the document 8573 * @ids: a whitespace separated list of IDs 8574 * 8575 * Selects elements by their unique ID. 8576 * 8577 * Returns a node-set of selected elements. 8578 */ 8579static xmlNodeSetPtr 8580xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) { 8581 xmlNodeSetPtr ret; 8582 const xmlChar *cur = ids; 8583 xmlChar *ID; 8584 xmlAttrPtr attr; 8585 xmlNodePtr elem = NULL; 8586 8587 if (ids == NULL) return(NULL); 8588 8589 ret = xmlXPathNodeSetCreate(NULL); 8590 if (ret == NULL) 8591 return(ret); 8592 8593 while (IS_BLANK_CH(*cur)) cur++; 8594 while (*cur != 0) { 8595 while ((!IS_BLANK_CH(*cur)) && (*cur != 0)) 8596 cur++; 8597 8598 ID = xmlStrndup(ids, cur - ids); 8599 if (ID != NULL) { 8600 /* 8601 * We used to check the fact that the value passed 8602 * was an NCName, but this generated much troubles for 8603 * me and Aleksey Sanin, people blatantly violated that 8604 * constaint, like Visa3D spec. 8605 * if (xmlValidateNCName(ID, 1) == 0) 8606 */ 8607 attr = xmlGetID(doc, ID); 8608 if (attr != NULL) { 8609 if (attr->type == XML_ATTRIBUTE_NODE) 8610 elem = attr->parent; 8611 else if (attr->type == XML_ELEMENT_NODE) 8612 elem = (xmlNodePtr) attr; 8613 else 8614 elem = NULL; 8615 if (elem != NULL) 8616 xmlXPathNodeSetAdd(ret, elem); 8617 } 8618 xmlFree(ID); 8619 } 8620 8621 while (IS_BLANK_CH(*cur)) cur++; 8622 ids = cur; 8623 } 8624 return(ret); 8625} 8626 8627/** 8628 * xmlXPathIdFunction: 8629 * @ctxt: the XPath Parser context 8630 * @nargs: the number of arguments 8631 * 8632 * Implement the id() XPath function 8633 * node-set id(object) 8634 * The id function selects elements by their unique ID 8635 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set, 8636 * then the result is the union of the result of applying id to the 8637 * string value of each of the nodes in the argument node-set. When the 8638 * argument to id is of any other type, the argument is converted to a 8639 * string as if by a call to the string function; the string is split 8640 * into a whitespace-separated list of tokens (whitespace is any sequence 8641 * of characters matching the production S); the result is a node-set 8642 * containing the elements in the same document as the context node that 8643 * have a unique ID equal to any of the tokens in the list. 8644 */ 8645void 8646xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8647 xmlChar *tokens; 8648 xmlNodeSetPtr ret; 8649 xmlXPathObjectPtr obj; 8650 8651 CHECK_ARITY(1); 8652 obj = valuePop(ctxt); 8653 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 8654 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) { 8655 xmlNodeSetPtr ns; 8656 int i; 8657 8658 ret = xmlXPathNodeSetCreate(NULL); 8659 /* 8660 * FIXME -- in an out-of-memory condition this will behave badly. 8661 * The solution is not clear -- we already popped an item from 8662 * ctxt, so the object is in a corrupt state. 8663 */ 8664 8665 if (obj->nodesetval != NULL) { 8666 for (i = 0; i < obj->nodesetval->nodeNr; i++) { 8667 tokens = 8668 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]); 8669 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens); 8670 ret = xmlXPathNodeSetMerge(ret, ns); 8671 xmlXPathFreeNodeSet(ns); 8672 if (tokens != NULL) 8673 xmlFree(tokens); 8674 } 8675 } 8676 xmlXPathReleaseObject(ctxt->context, obj); 8677 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret)); 8678 return; 8679 } 8680 obj = xmlXPathCacheConvertString(ctxt->context, obj); 8681 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval); 8682 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret)); 8683 xmlXPathReleaseObject(ctxt->context, obj); 8684 return; 8685} 8686 8687/** 8688 * xmlXPathLocalNameFunction: 8689 * @ctxt: the XPath Parser context 8690 * @nargs: the number of arguments 8691 * 8692 * Implement the local-name() XPath function 8693 * string local-name(node-set?) 8694 * The local-name function returns a string containing the local part 8695 * of the name of the node in the argument node-set that is first in 8696 * document order. If the node-set is empty or the first node has no 8697 * name, an empty string is returned. If the argument is omitted it 8698 * defaults to the context node. 8699 */ 8700void 8701xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8702 xmlXPathObjectPtr cur; 8703 8704 if (ctxt == NULL) return; 8705 8706 if (nargs == 0) { 8707 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8708 ctxt->context->node)); 8709 nargs = 1; 8710 } 8711 8712 CHECK_ARITY(1); 8713 if ((ctxt->value == NULL) || 8714 ((ctxt->value->type != XPATH_NODESET) && 8715 (ctxt->value->type != XPATH_XSLT_TREE))) 8716 XP_ERROR(XPATH_INVALID_TYPE); 8717 cur = valuePop(ctxt); 8718 8719 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 8720 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8721 } else { 8722 int i = 0; /* Should be first in document order !!!!! */ 8723 switch (cur->nodesetval->nodeTab[i]->type) { 8724 case XML_ELEMENT_NODE: 8725 case XML_ATTRIBUTE_NODE: 8726 case XML_PI_NODE: 8727 if (cur->nodesetval->nodeTab[i]->name[0] == ' ') 8728 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8729 else 8730 valuePush(ctxt, 8731 xmlXPathCacheNewString(ctxt->context, 8732 cur->nodesetval->nodeTab[i]->name)); 8733 break; 8734 case XML_NAMESPACE_DECL: 8735 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 8736 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix)); 8737 break; 8738 default: 8739 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8740 } 8741 } 8742 xmlXPathReleaseObject(ctxt->context, cur); 8743} 8744 8745/** 8746 * xmlXPathNamespaceURIFunction: 8747 * @ctxt: the XPath Parser context 8748 * @nargs: the number of arguments 8749 * 8750 * Implement the namespace-uri() XPath function 8751 * string namespace-uri(node-set?) 8752 * The namespace-uri function returns a string containing the 8753 * namespace URI of the expanded name of the node in the argument 8754 * node-set that is first in document order. If the node-set is empty, 8755 * the first node has no name, or the expanded name has no namespace 8756 * URI, an empty string is returned. If the argument is omitted it 8757 * defaults to the context node. 8758 */ 8759void 8760xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8761 xmlXPathObjectPtr cur; 8762 8763 if (ctxt == NULL) return; 8764 8765 if (nargs == 0) { 8766 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8767 ctxt->context->node)); 8768 nargs = 1; 8769 } 8770 CHECK_ARITY(1); 8771 if ((ctxt->value == NULL) || 8772 ((ctxt->value->type != XPATH_NODESET) && 8773 (ctxt->value->type != XPATH_XSLT_TREE))) 8774 XP_ERROR(XPATH_INVALID_TYPE); 8775 cur = valuePop(ctxt); 8776 8777 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 8778 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8779 } else { 8780 int i = 0; /* Should be first in document order !!!!! */ 8781 switch (cur->nodesetval->nodeTab[i]->type) { 8782 case XML_ELEMENT_NODE: 8783 case XML_ATTRIBUTE_NODE: 8784 if (cur->nodesetval->nodeTab[i]->ns == NULL) 8785 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8786 else 8787 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 8788 cur->nodesetval->nodeTab[i]->ns->href)); 8789 break; 8790 default: 8791 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8792 } 8793 } 8794 xmlXPathReleaseObject(ctxt->context, cur); 8795} 8796 8797/** 8798 * xmlXPathNameFunction: 8799 * @ctxt: the XPath Parser context 8800 * @nargs: the number of arguments 8801 * 8802 * Implement the name() XPath function 8803 * string name(node-set?) 8804 * The name function returns a string containing a QName representing 8805 * the name of the node in the argument node-set that is first in document 8806 * order. The QName must represent the name with respect to the namespace 8807 * declarations in effect on the node whose name is being represented. 8808 * Typically, this will be the form in which the name occurred in the XML 8809 * source. This need not be the case if there are namespace declarations 8810 * in effect on the node that associate multiple prefixes with the same 8811 * namespace. However, an implementation may include information about 8812 * the original prefix in its representation of nodes; in this case, an 8813 * implementation can ensure that the returned string is always the same 8814 * as the QName used in the XML source. If the argument it omitted it 8815 * defaults to the context node. 8816 * Libxml keep the original prefix so the "real qualified name" used is 8817 * returned. 8818 */ 8819static void 8820xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) 8821{ 8822 xmlXPathObjectPtr cur; 8823 8824 if (nargs == 0) { 8825 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8826 ctxt->context->node)); 8827 nargs = 1; 8828 } 8829 8830 CHECK_ARITY(1); 8831 if ((ctxt->value == NULL) || 8832 ((ctxt->value->type != XPATH_NODESET) && 8833 (ctxt->value->type != XPATH_XSLT_TREE))) 8834 XP_ERROR(XPATH_INVALID_TYPE); 8835 cur = valuePop(ctxt); 8836 8837 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 8838 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8839 } else { 8840 int i = 0; /* Should be first in document order !!!!! */ 8841 8842 switch (cur->nodesetval->nodeTab[i]->type) { 8843 case XML_ELEMENT_NODE: 8844 case XML_ATTRIBUTE_NODE: 8845 if (cur->nodesetval->nodeTab[i]->name[0] == ' ') 8846 valuePush(ctxt, 8847 xmlXPathCacheNewCString(ctxt->context, "")); 8848 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) || 8849 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) { 8850 valuePush(ctxt, 8851 xmlXPathCacheNewString(ctxt->context, 8852 cur->nodesetval->nodeTab[i]->name)); 8853 } else { 8854 xmlChar *fullname; 8855 8856 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name, 8857 cur->nodesetval->nodeTab[i]->ns->prefix, 8858 NULL, 0); 8859 if (fullname == cur->nodesetval->nodeTab[i]->name) 8860 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name); 8861 if (fullname == NULL) { 8862 XP_ERROR(XPATH_MEMORY_ERROR); 8863 } 8864 valuePush(ctxt, xmlXPathCacheWrapString( 8865 ctxt->context, fullname)); 8866 } 8867 break; 8868 default: 8869 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8870 cur->nodesetval->nodeTab[i])); 8871 xmlXPathLocalNameFunction(ctxt, 1); 8872 } 8873 } 8874 xmlXPathReleaseObject(ctxt->context, cur); 8875} 8876 8877 8878/** 8879 * xmlXPathStringFunction: 8880 * @ctxt: the XPath Parser context 8881 * @nargs: the number of arguments 8882 * 8883 * Implement the string() XPath function 8884 * string string(object?) 8885 * The string function converts an object to a string as follows: 8886 * - A node-set is converted to a string by returning the value of 8887 * the node in the node-set that is first in document order. 8888 * If the node-set is empty, an empty string is returned. 8889 * - A number is converted to a string as follows 8890 * + NaN is converted to the string NaN 8891 * + positive zero is converted to the string 0 8892 * + negative zero is converted to the string 0 8893 * + positive infinity is converted to the string Infinity 8894 * + negative infinity is converted to the string -Infinity 8895 * + if the number is an integer, the number is represented in 8896 * decimal form as a Number with no decimal point and no leading 8897 * zeros, preceded by a minus sign (-) if the number is negative 8898 * + otherwise, the number is represented in decimal form as a 8899 * Number including a decimal point with at least one digit 8900 * before the decimal point and at least one digit after the 8901 * decimal point, preceded by a minus sign (-) if the number 8902 * is negative; there must be no leading zeros before the decimal 8903 * point apart possibly from the one required digit immediately 8904 * before the decimal point; beyond the one required digit 8905 * after the decimal point there must be as many, but only as 8906 * many, more digits as are needed to uniquely distinguish the 8907 * number from all other IEEE 754 numeric values. 8908 * - The boolean false value is converted to the string false. 8909 * The boolean true value is converted to the string true. 8910 * 8911 * If the argument is omitted, it defaults to a node-set with the 8912 * context node as its only member. 8913 */ 8914void 8915xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8916 xmlXPathObjectPtr cur; 8917 8918 if (ctxt == NULL) return; 8919 if (nargs == 0) { 8920 valuePush(ctxt, 8921 xmlXPathCacheWrapString(ctxt->context, 8922 xmlXPathCastNodeToString(ctxt->context->node))); 8923 return; 8924 } 8925 8926 CHECK_ARITY(1); 8927 cur = valuePop(ctxt); 8928 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 8929 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur)); 8930} 8931 8932/** 8933 * xmlXPathStringLengthFunction: 8934 * @ctxt: the XPath Parser context 8935 * @nargs: the number of arguments 8936 * 8937 * Implement the string-length() XPath function 8938 * number string-length(string?) 8939 * The string-length returns the number of characters in the string 8940 * (see [3.6 Strings]). If the argument is omitted, it defaults to 8941 * the context node converted to a string, in other words the value 8942 * of the context node. 8943 */ 8944void 8945xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8946 xmlXPathObjectPtr cur; 8947 8948 if (nargs == 0) { 8949 if ((ctxt == NULL) || (ctxt->context == NULL)) 8950 return; 8951 if (ctxt->context->node == NULL) { 8952 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0)); 8953 } else { 8954 xmlChar *content; 8955 8956 content = xmlXPathCastNodeToString(ctxt->context->node); 8957 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 8958 xmlUTF8Strlen(content))); 8959 xmlFree(content); 8960 } 8961 return; 8962 } 8963 CHECK_ARITY(1); 8964 CAST_TO_STRING; 8965 CHECK_TYPE(XPATH_STRING); 8966 cur = valuePop(ctxt); 8967 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 8968 xmlUTF8Strlen(cur->stringval))); 8969 xmlXPathReleaseObject(ctxt->context, cur); 8970} 8971 8972/** 8973 * xmlXPathConcatFunction: 8974 * @ctxt: the XPath Parser context 8975 * @nargs: the number of arguments 8976 * 8977 * Implement the concat() XPath function 8978 * string concat(string, string, string*) 8979 * The concat function returns the concatenation of its arguments. 8980 */ 8981void 8982xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8983 xmlXPathObjectPtr cur, newobj; 8984 xmlChar *tmp; 8985 8986 if (ctxt == NULL) return; 8987 if (nargs < 2) { 8988 CHECK_ARITY(2); 8989 } 8990 8991 CAST_TO_STRING; 8992 cur = valuePop(ctxt); 8993 if ((cur == NULL) || (cur->type != XPATH_STRING)) { 8994 xmlXPathReleaseObject(ctxt->context, cur); 8995 return; 8996 } 8997 nargs--; 8998 8999 while (nargs > 0) { 9000 CAST_TO_STRING; 9001 newobj = valuePop(ctxt); 9002 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) { 9003 xmlXPathReleaseObject(ctxt->context, newobj); 9004 xmlXPathReleaseObject(ctxt->context, cur); 9005 XP_ERROR(XPATH_INVALID_TYPE); 9006 } 9007 tmp = xmlStrcat(newobj->stringval, cur->stringval); 9008 newobj->stringval = cur->stringval; 9009 cur->stringval = tmp; 9010 xmlXPathReleaseObject(ctxt->context, newobj); 9011 nargs--; 9012 } 9013 valuePush(ctxt, cur); 9014} 9015 9016/** 9017 * xmlXPathContainsFunction: 9018 * @ctxt: the XPath Parser context 9019 * @nargs: the number of arguments 9020 * 9021 * Implement the contains() XPath function 9022 * boolean contains(string, string) 9023 * The contains function returns true if the first argument string 9024 * contains the second argument string, and otherwise returns false. 9025 */ 9026void 9027xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9028 xmlXPathObjectPtr hay, needle; 9029 9030 CHECK_ARITY(2); 9031 CAST_TO_STRING; 9032 CHECK_TYPE(XPATH_STRING); 9033 needle = valuePop(ctxt); 9034 CAST_TO_STRING; 9035 hay = valuePop(ctxt); 9036 9037 if ((hay == NULL) || (hay->type != XPATH_STRING)) { 9038 xmlXPathReleaseObject(ctxt->context, hay); 9039 xmlXPathReleaseObject(ctxt->context, needle); 9040 XP_ERROR(XPATH_INVALID_TYPE); 9041 } 9042 if (xmlStrstr(hay->stringval, needle->stringval)) 9043 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); 9044 else 9045 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); 9046 xmlXPathReleaseObject(ctxt->context, hay); 9047 xmlXPathReleaseObject(ctxt->context, needle); 9048} 9049 9050/** 9051 * xmlXPathStartsWithFunction: 9052 * @ctxt: the XPath Parser context 9053 * @nargs: the number of arguments 9054 * 9055 * Implement the starts-with() XPath function 9056 * boolean starts-with(string, string) 9057 * The starts-with function returns true if the first argument string 9058 * starts with the second argument string, and otherwise returns false. 9059 */ 9060void 9061xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9062 xmlXPathObjectPtr hay, needle; 9063 int n; 9064 9065 CHECK_ARITY(2); 9066 CAST_TO_STRING; 9067 CHECK_TYPE(XPATH_STRING); 9068 needle = valuePop(ctxt); 9069 CAST_TO_STRING; 9070 hay = valuePop(ctxt); 9071 9072 if ((hay == NULL) || (hay->type != XPATH_STRING)) { 9073 xmlXPathReleaseObject(ctxt->context, hay); 9074 xmlXPathReleaseObject(ctxt->context, needle); 9075 XP_ERROR(XPATH_INVALID_TYPE); 9076 } 9077 n = xmlStrlen(needle->stringval); 9078 if (xmlStrncmp(hay->stringval, needle->stringval, n)) 9079 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); 9080 else 9081 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); 9082 xmlXPathReleaseObject(ctxt->context, hay); 9083 xmlXPathReleaseObject(ctxt->context, needle); 9084} 9085 9086/** 9087 * xmlXPathSubstringFunction: 9088 * @ctxt: the XPath Parser context 9089 * @nargs: the number of arguments 9090 * 9091 * Implement the substring() XPath function 9092 * string substring(string, number, number?) 9093 * The substring function returns the substring of the first argument 9094 * starting at the position specified in the second argument with 9095 * length specified in the third argument. For example, 9096 * substring("12345",2,3) returns "234". If the third argument is not 9097 * specified, it returns the substring starting at the position specified 9098 * in the second argument and continuing to the end of the string. For 9099 * example, substring("12345",2) returns "2345". More precisely, each 9100 * character in the string (see [3.6 Strings]) is considered to have a 9101 * numeric position: the position of the first character is 1, the position 9102 * of the second character is 2 and so on. The returned substring contains 9103 * those characters for which the position of the character is greater than 9104 * or equal to the second argument and, if the third argument is specified, 9105 * less than the sum of the second and third arguments; the comparisons 9106 * and addition used for the above follow the standard IEEE 754 rules. Thus: 9107 * - substring("12345", 1.5, 2.6) returns "234" 9108 * - substring("12345", 0, 3) returns "12" 9109 * - substring("12345", 0 div 0, 3) returns "" 9110 * - substring("12345", 1, 0 div 0) returns "" 9111 * - substring("12345", -42, 1 div 0) returns "12345" 9112 * - substring("12345", -1 div 0, 1 div 0) returns "" 9113 */ 9114void 9115xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9116 xmlXPathObjectPtr str, start, len; 9117 double le=0, in; 9118 int i, l, m; 9119 xmlChar *ret; 9120 9121 if (nargs < 2) { 9122 CHECK_ARITY(2); 9123 } 9124 if (nargs > 3) { 9125 CHECK_ARITY(3); 9126 } 9127 /* 9128 * take care of possible last (position) argument 9129 */ 9130 if (nargs == 3) { 9131 CAST_TO_NUMBER; 9132 CHECK_TYPE(XPATH_NUMBER); 9133 len = valuePop(ctxt); 9134 le = len->floatval; 9135 xmlXPathReleaseObject(ctxt->context, len); 9136 } 9137 9138 CAST_TO_NUMBER; 9139 CHECK_TYPE(XPATH_NUMBER); 9140 start = valuePop(ctxt); 9141 in = start->floatval; 9142 xmlXPathReleaseObject(ctxt->context, start); 9143 CAST_TO_STRING; 9144 CHECK_TYPE(XPATH_STRING); 9145 str = valuePop(ctxt); 9146 m = xmlUTF8Strlen((const unsigned char *)str->stringval); 9147 9148 /* 9149 * If last pos not present, calculate last position 9150 */ 9151 if (nargs != 3) { 9152 le = (double)m; 9153 if (in < 1.0) 9154 in = 1.0; 9155 } 9156 9157 /* Need to check for the special cases where either 9158 * the index is NaN, the length is NaN, or both 9159 * arguments are infinity (relying on Inf + -Inf = NaN) 9160 */ 9161 if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) { 9162 /* 9163 * To meet the requirements of the spec, the arguments 9164 * must be converted to integer format before 9165 * initial index calculations are done 9166 * 9167 * First we go to integer form, rounding up 9168 * and checking for special cases 9169 */ 9170 i = (int) in; 9171 if (((double)i)+0.5 <= in) i++; 9172 9173 if (xmlXPathIsInf(le) == 1) { 9174 l = m; 9175 if (i < 1) 9176 i = 1; 9177 } 9178 else if (xmlXPathIsInf(le) == -1 || le < 0.0) 9179 l = 0; 9180 else { 9181 l = (int) le; 9182 if (((double)l)+0.5 <= le) l++; 9183 } 9184 9185 /* Now we normalize inidices */ 9186 i -= 1; 9187 l += i; 9188 if (i < 0) 9189 i = 0; 9190 if (l > m) 9191 l = m; 9192 9193 /* number of chars to copy */ 9194 l -= i; 9195 9196 ret = xmlUTF8Strsub(str->stringval, i, l); 9197 } 9198 else { 9199 ret = NULL; 9200 } 9201 if (ret == NULL) 9202 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 9203 else { 9204 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret)); 9205 xmlFree(ret); 9206 } 9207 xmlXPathReleaseObject(ctxt->context, str); 9208} 9209 9210/** 9211 * xmlXPathSubstringBeforeFunction: 9212 * @ctxt: the XPath Parser context 9213 * @nargs: the number of arguments 9214 * 9215 * Implement the substring-before() XPath function 9216 * string substring-before(string, string) 9217 * The substring-before function returns the substring of the first 9218 * argument string that precedes the first occurrence of the second 9219 * argument string in the first argument string, or the empty string 9220 * if the first argument string does not contain the second argument 9221 * string. For example, substring-before("1999/04/01","/") returns 1999. 9222 */ 9223void 9224xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9225 xmlXPathObjectPtr str; 9226 xmlXPathObjectPtr find; 9227 xmlBufPtr target; 9228 const xmlChar *point; 9229 int offset; 9230 9231 CHECK_ARITY(2); 9232 CAST_TO_STRING; 9233 find = valuePop(ctxt); 9234 CAST_TO_STRING; 9235 str = valuePop(ctxt); 9236 9237 target = xmlBufCreate(); 9238 if (target) { 9239 point = xmlStrstr(str->stringval, find->stringval); 9240 if (point) { 9241 offset = (int)(point - str->stringval); 9242 xmlBufAdd(target, str->stringval, offset); 9243 } 9244 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9245 xmlBufContent(target))); 9246 xmlBufFree(target); 9247 } 9248 xmlXPathReleaseObject(ctxt->context, str); 9249 xmlXPathReleaseObject(ctxt->context, find); 9250} 9251 9252/** 9253 * xmlXPathSubstringAfterFunction: 9254 * @ctxt: the XPath Parser context 9255 * @nargs: the number of arguments 9256 * 9257 * Implement the substring-after() XPath function 9258 * string substring-after(string, string) 9259 * The substring-after function returns the substring of the first 9260 * argument string that follows the first occurrence of the second 9261 * argument string in the first argument string, or the empty stringi 9262 * if the first argument string does not contain the second argument 9263 * string. For example, substring-after("1999/04/01","/") returns 04/01, 9264 * and substring-after("1999/04/01","19") returns 99/04/01. 9265 */ 9266void 9267xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9268 xmlXPathObjectPtr str; 9269 xmlXPathObjectPtr find; 9270 xmlBufPtr target; 9271 const xmlChar *point; 9272 int offset; 9273 9274 CHECK_ARITY(2); 9275 CAST_TO_STRING; 9276 find = valuePop(ctxt); 9277 CAST_TO_STRING; 9278 str = valuePop(ctxt); 9279 9280 target = xmlBufCreate(); 9281 if (target) { 9282 point = xmlStrstr(str->stringval, find->stringval); 9283 if (point) { 9284 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval); 9285 xmlBufAdd(target, &str->stringval[offset], 9286 xmlStrlen(str->stringval) - offset); 9287 } 9288 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9289 xmlBufContent(target))); 9290 xmlBufFree(target); 9291 } 9292 xmlXPathReleaseObject(ctxt->context, str); 9293 xmlXPathReleaseObject(ctxt->context, find); 9294} 9295 9296/** 9297 * xmlXPathNormalizeFunction: 9298 * @ctxt: the XPath Parser context 9299 * @nargs: the number of arguments 9300 * 9301 * Implement the normalize-space() XPath function 9302 * string normalize-space(string?) 9303 * The normalize-space function returns the argument string with white 9304 * space normalized by stripping leading and trailing whitespace 9305 * and replacing sequences of whitespace characters by a single 9306 * space. Whitespace characters are the same allowed by the S production 9307 * in XML. If the argument is omitted, it defaults to the context 9308 * node converted to a string, in other words the value of the context node. 9309 */ 9310void 9311xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9312 xmlXPathObjectPtr obj = NULL; 9313 xmlChar *source = NULL; 9314 xmlBufPtr target; 9315 xmlChar blank; 9316 9317 if (ctxt == NULL) return; 9318 if (nargs == 0) { 9319 /* Use current context node */ 9320 valuePush(ctxt, 9321 xmlXPathCacheWrapString(ctxt->context, 9322 xmlXPathCastNodeToString(ctxt->context->node))); 9323 nargs = 1; 9324 } 9325 9326 CHECK_ARITY(1); 9327 CAST_TO_STRING; 9328 CHECK_TYPE(XPATH_STRING); 9329 obj = valuePop(ctxt); 9330 source = obj->stringval; 9331 9332 target = xmlBufCreate(); 9333 if (target && source) { 9334 9335 /* Skip leading whitespaces */ 9336 while (IS_BLANK_CH(*source)) 9337 source++; 9338 9339 /* Collapse intermediate whitespaces, and skip trailing whitespaces */ 9340 blank = 0; 9341 while (*source) { 9342 if (IS_BLANK_CH(*source)) { 9343 blank = 0x20; 9344 } else { 9345 if (blank) { 9346 xmlBufAdd(target, &blank, 1); 9347 blank = 0; 9348 } 9349 xmlBufAdd(target, source, 1); 9350 } 9351 source++; 9352 } 9353 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9354 xmlBufContent(target))); 9355 xmlBufFree(target); 9356 } 9357 xmlXPathReleaseObject(ctxt->context, obj); 9358} 9359 9360/** 9361 * xmlXPathTranslateFunction: 9362 * @ctxt: the XPath Parser context 9363 * @nargs: the number of arguments 9364 * 9365 * Implement the translate() XPath function 9366 * string translate(string, string, string) 9367 * The translate function returns the first argument string with 9368 * occurrences of characters in the second argument string replaced 9369 * by the character at the corresponding position in the third argument 9370 * string. For example, translate("bar","abc","ABC") returns the string 9371 * BAr. If there is a character in the second argument string with no 9372 * character at a corresponding position in the third argument string 9373 * (because the second argument string is longer than the third argument 9374 * string), then occurrences of that character in the first argument 9375 * string are removed. For example, translate("--aaa--","abc-","ABC") 9376 * returns "AAA". If a character occurs more than once in second 9377 * argument string, then the first occurrence determines the replacement 9378 * character. If the third argument string is longer than the second 9379 * argument string, then excess characters are ignored. 9380 */ 9381void 9382xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9383 xmlXPathObjectPtr str; 9384 xmlXPathObjectPtr from; 9385 xmlXPathObjectPtr to; 9386 xmlBufPtr target; 9387 int offset, max; 9388 xmlChar ch; 9389 const xmlChar *point; 9390 xmlChar *cptr; 9391 9392 CHECK_ARITY(3); 9393 9394 CAST_TO_STRING; 9395 to = valuePop(ctxt); 9396 CAST_TO_STRING; 9397 from = valuePop(ctxt); 9398 CAST_TO_STRING; 9399 str = valuePop(ctxt); 9400 9401 target = xmlBufCreate(); 9402 if (target) { 9403 max = xmlUTF8Strlen(to->stringval); 9404 for (cptr = str->stringval; (ch=*cptr); ) { 9405 offset = xmlUTF8Strloc(from->stringval, cptr); 9406 if (offset >= 0) { 9407 if (offset < max) { 9408 point = xmlUTF8Strpos(to->stringval, offset); 9409 if (point) 9410 xmlBufAdd(target, point, xmlUTF8Strsize(point, 1)); 9411 } 9412 } else 9413 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1)); 9414 9415 /* Step to next character in input */ 9416 cptr++; 9417 if ( ch & 0x80 ) { 9418 /* if not simple ascii, verify proper format */ 9419 if ( (ch & 0xc0) != 0xc0 ) { 9420 xmlGenericError(xmlGenericErrorContext, 9421 "xmlXPathTranslateFunction: Invalid UTF8 string\n"); 9422 /* not asserting an XPath error is probably better */ 9423 break; 9424 } 9425 /* then skip over remaining bytes for this char */ 9426 while ( (ch <<= 1) & 0x80 ) 9427 if ( (*cptr++ & 0xc0) != 0x80 ) { 9428 xmlGenericError(xmlGenericErrorContext, 9429 "xmlXPathTranslateFunction: Invalid UTF8 string\n"); 9430 /* not asserting an XPath error is probably better */ 9431 break; 9432 } 9433 if (ch & 0x80) /* must have had error encountered */ 9434 break; 9435 } 9436 } 9437 } 9438 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9439 xmlBufContent(target))); 9440 xmlBufFree(target); 9441 xmlXPathReleaseObject(ctxt->context, str); 9442 xmlXPathReleaseObject(ctxt->context, from); 9443 xmlXPathReleaseObject(ctxt->context, to); 9444} 9445 9446/** 9447 * xmlXPathBooleanFunction: 9448 * @ctxt: the XPath Parser context 9449 * @nargs: the number of arguments 9450 * 9451 * Implement the boolean() XPath function 9452 * boolean boolean(object) 9453 * The boolean function converts its argument to a boolean as follows: 9454 * - a number is true if and only if it is neither positive or 9455 * negative zero nor NaN 9456 * - a node-set is true if and only if it is non-empty 9457 * - a string is true if and only if its length is non-zero 9458 */ 9459void 9460xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9461 xmlXPathObjectPtr cur; 9462 9463 CHECK_ARITY(1); 9464 cur = valuePop(ctxt); 9465 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 9466 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur); 9467 valuePush(ctxt, cur); 9468} 9469 9470/** 9471 * xmlXPathNotFunction: 9472 * @ctxt: the XPath Parser context 9473 * @nargs: the number of arguments 9474 * 9475 * Implement the not() XPath function 9476 * boolean not(boolean) 9477 * The not function returns true if its argument is false, 9478 * and false otherwise. 9479 */ 9480void 9481xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9482 CHECK_ARITY(1); 9483 CAST_TO_BOOLEAN; 9484 CHECK_TYPE(XPATH_BOOLEAN); 9485 ctxt->value->boolval = ! ctxt->value->boolval; 9486} 9487 9488/** 9489 * xmlXPathTrueFunction: 9490 * @ctxt: the XPath Parser context 9491 * @nargs: the number of arguments 9492 * 9493 * Implement the true() XPath function 9494 * boolean true() 9495 */ 9496void 9497xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9498 CHECK_ARITY(0); 9499 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); 9500} 9501 9502/** 9503 * xmlXPathFalseFunction: 9504 * @ctxt: the XPath Parser context 9505 * @nargs: the number of arguments 9506 * 9507 * Implement the false() XPath function 9508 * boolean false() 9509 */ 9510void 9511xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9512 CHECK_ARITY(0); 9513 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); 9514} 9515 9516/** 9517 * xmlXPathLangFunction: 9518 * @ctxt: the XPath Parser context 9519 * @nargs: the number of arguments 9520 * 9521 * Implement the lang() XPath function 9522 * boolean lang(string) 9523 * The lang function returns true or false depending on whether the 9524 * language of the context node as specified by xml:lang attributes 9525 * is the same as or is a sublanguage of the language specified by 9526 * the argument string. The language of the context node is determined 9527 * by the value of the xml:lang attribute on the context node, or, if 9528 * the context node has no xml:lang attribute, by the value of the 9529 * xml:lang attribute on the nearest ancestor of the context node that 9530 * has an xml:lang attribute. If there is no such attribute, then lang 9531 * returns false. If there is such an attribute, then lang returns 9532 * true if the attribute value is equal to the argument ignoring case, 9533 * or if there is some suffix starting with - such that the attribute 9534 * value is equal to the argument ignoring that suffix of the attribute 9535 * value and ignoring case. 9536 */ 9537void 9538xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9539 xmlXPathObjectPtr val = NULL; 9540 const xmlChar *theLang = NULL; 9541 const xmlChar *lang; 9542 int ret = 0; 9543 int i; 9544 9545 CHECK_ARITY(1); 9546 CAST_TO_STRING; 9547 CHECK_TYPE(XPATH_STRING); 9548 val = valuePop(ctxt); 9549 lang = val->stringval; 9550 theLang = xmlNodeGetLang(ctxt->context->node); 9551 if ((theLang != NULL) && (lang != NULL)) { 9552 for (i = 0;lang[i] != 0;i++) 9553 if (toupper(lang[i]) != toupper(theLang[i])) 9554 goto not_equal; 9555 if ((theLang[i] == 0) || (theLang[i] == '-')) 9556 ret = 1; 9557 } 9558not_equal: 9559 if (theLang != NULL) 9560 xmlFree((void *)theLang); 9561 9562 xmlXPathReleaseObject(ctxt->context, val); 9563 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret)); 9564} 9565 9566/** 9567 * xmlXPathNumberFunction: 9568 * @ctxt: the XPath Parser context 9569 * @nargs: the number of arguments 9570 * 9571 * Implement the number() XPath function 9572 * number number(object?) 9573 */ 9574void 9575xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9576 xmlXPathObjectPtr cur; 9577 double res; 9578 9579 if (ctxt == NULL) return; 9580 if (nargs == 0) { 9581 if (ctxt->context->node == NULL) { 9582 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0)); 9583 } else { 9584 xmlChar* content = xmlNodeGetContent(ctxt->context->node); 9585 9586 res = xmlXPathStringEvalNumber(content); 9587 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res)); 9588 xmlFree(content); 9589 } 9590 return; 9591 } 9592 9593 CHECK_ARITY(1); 9594 cur = valuePop(ctxt); 9595 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur)); 9596} 9597 9598/** 9599 * xmlXPathSumFunction: 9600 * @ctxt: the XPath Parser context 9601 * @nargs: the number of arguments 9602 * 9603 * Implement the sum() XPath function 9604 * number sum(node-set) 9605 * The sum function returns the sum of the values of the nodes in 9606 * the argument node-set. 9607 */ 9608void 9609xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9610 xmlXPathObjectPtr cur; 9611 int i; 9612 double res = 0.0; 9613 9614 CHECK_ARITY(1); 9615 if ((ctxt->value == NULL) || 9616 ((ctxt->value->type != XPATH_NODESET) && 9617 (ctxt->value->type != XPATH_XSLT_TREE))) 9618 XP_ERROR(XPATH_INVALID_TYPE); 9619 cur = valuePop(ctxt); 9620 9621 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) { 9622 for (i = 0; i < cur->nodesetval->nodeNr; i++) { 9623 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]); 9624 } 9625 } 9626 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res)); 9627 xmlXPathReleaseObject(ctxt->context, cur); 9628} 9629 9630/* 9631 * To assure working code on multiple platforms, we want to only depend 9632 * upon the characteristic truncation of converting a floating point value 9633 * to an integer. Unfortunately, because of the different storage sizes 9634 * of our internal floating point value (double) and integer (int), we 9635 * can't directly convert (see bug 301162). This macro is a messy 9636 * 'workaround' 9637 */ 9638#define XTRUNC(f, v) \ 9639 f = fmod((v), INT_MAX); \ 9640 f = (v) - (f) + (double)((int)(f)); 9641 9642/** 9643 * xmlXPathFloorFunction: 9644 * @ctxt: the XPath Parser context 9645 * @nargs: the number of arguments 9646 * 9647 * Implement the floor() XPath function 9648 * number floor(number) 9649 * The floor function returns the largest (closest to positive infinity) 9650 * number that is not greater than the argument and that is an integer. 9651 */ 9652void 9653xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9654 double f; 9655 9656 CHECK_ARITY(1); 9657 CAST_TO_NUMBER; 9658 CHECK_TYPE(XPATH_NUMBER); 9659 9660 XTRUNC(f, ctxt->value->floatval); 9661 if (f != ctxt->value->floatval) { 9662 if (ctxt->value->floatval > 0) 9663 ctxt->value->floatval = f; 9664 else 9665 ctxt->value->floatval = f - 1; 9666 } 9667} 9668 9669/** 9670 * xmlXPathCeilingFunction: 9671 * @ctxt: the XPath Parser context 9672 * @nargs: the number of arguments 9673 * 9674 * Implement the ceiling() XPath function 9675 * number ceiling(number) 9676 * The ceiling function returns the smallest (closest to negative infinity) 9677 * number that is not less than the argument and that is an integer. 9678 */ 9679void 9680xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9681 double f; 9682 9683 CHECK_ARITY(1); 9684 CAST_TO_NUMBER; 9685 CHECK_TYPE(XPATH_NUMBER); 9686 9687#if 0 9688 ctxt->value->floatval = ceil(ctxt->value->floatval); 9689#else 9690 XTRUNC(f, ctxt->value->floatval); 9691 if (f != ctxt->value->floatval) { 9692 if (ctxt->value->floatval > 0) 9693 ctxt->value->floatval = f + 1; 9694 else { 9695 if (ctxt->value->floatval < 0 && f == 0) 9696 ctxt->value->floatval = xmlXPathNZERO; 9697 else 9698 ctxt->value->floatval = f; 9699 } 9700 9701 } 9702#endif 9703} 9704 9705/** 9706 * xmlXPathRoundFunction: 9707 * @ctxt: the XPath Parser context 9708 * @nargs: the number of arguments 9709 * 9710 * Implement the round() XPath function 9711 * number round(number) 9712 * The round function returns the number that is closest to the 9713 * argument and that is an integer. If there are two such numbers, 9714 * then the one that is even is returned. 9715 */ 9716void 9717xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9718 double f; 9719 9720 CHECK_ARITY(1); 9721 CAST_TO_NUMBER; 9722 CHECK_TYPE(XPATH_NUMBER); 9723 9724 if ((xmlXPathIsNaN(ctxt->value->floatval)) || 9725 (xmlXPathIsInf(ctxt->value->floatval) == 1) || 9726 (xmlXPathIsInf(ctxt->value->floatval) == -1) || 9727 (ctxt->value->floatval == 0.0)) 9728 return; 9729 9730 XTRUNC(f, ctxt->value->floatval); 9731 if (ctxt->value->floatval < 0) { 9732 if (ctxt->value->floatval < f - 0.5) 9733 ctxt->value->floatval = f - 1; 9734 else 9735 ctxt->value->floatval = f; 9736 if (ctxt->value->floatval == 0) 9737 ctxt->value->floatval = xmlXPathNZERO; 9738 } else { 9739 if (ctxt->value->floatval < f + 0.5) 9740 ctxt->value->floatval = f; 9741 else 9742 ctxt->value->floatval = f + 1; 9743 } 9744} 9745 9746/************************************************************************ 9747 * * 9748 * The Parser * 9749 * * 9750 ************************************************************************/ 9751 9752/* 9753 * a few forward declarations since we use a recursive call based 9754 * implementation. 9755 */ 9756static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort); 9757static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter); 9758static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt); 9759static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt); 9760static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, 9761 int qualified); 9762 9763/** 9764 * xmlXPathCurrentChar: 9765 * @ctxt: the XPath parser context 9766 * @cur: pointer to the beginning of the char 9767 * @len: pointer to the length of the char read 9768 * 9769 * The current char value, if using UTF-8 this may actually span multiple 9770 * bytes in the input buffer. 9771 * 9772 * Returns the current char value and its length 9773 */ 9774 9775static int 9776xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) { 9777 unsigned char c; 9778 unsigned int val; 9779 const xmlChar *cur; 9780 9781 if (ctxt == NULL) 9782 return(0); 9783 cur = ctxt->cur; 9784 9785 /* 9786 * We are supposed to handle UTF8, check it's valid 9787 * From rfc2044: encoding of the Unicode values on UTF-8: 9788 * 9789 * UCS-4 range (hex.) UTF-8 octet sequence (binary) 9790 * 0000 0000-0000 007F 0xxxxxxx 9791 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx 9792 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx 9793 * 9794 * Check for the 0x110000 limit too 9795 */ 9796 c = *cur; 9797 if (c & 0x80) { 9798 if ((cur[1] & 0xc0) != 0x80) 9799 goto encoding_error; 9800 if ((c & 0xe0) == 0xe0) { 9801 9802 if ((cur[2] & 0xc0) != 0x80) 9803 goto encoding_error; 9804 if ((c & 0xf0) == 0xf0) { 9805 if (((c & 0xf8) != 0xf0) || 9806 ((cur[3] & 0xc0) != 0x80)) 9807 goto encoding_error; 9808 /* 4-byte code */ 9809 *len = 4; 9810 val = (cur[0] & 0x7) << 18; 9811 val |= (cur[1] & 0x3f) << 12; 9812 val |= (cur[2] & 0x3f) << 6; 9813 val |= cur[3] & 0x3f; 9814 } else { 9815 /* 3-byte code */ 9816 *len = 3; 9817 val = (cur[0] & 0xf) << 12; 9818 val |= (cur[1] & 0x3f) << 6; 9819 val |= cur[2] & 0x3f; 9820 } 9821 } else { 9822 /* 2-byte code */ 9823 *len = 2; 9824 val = (cur[0] & 0x1f) << 6; 9825 val |= cur[1] & 0x3f; 9826 } 9827 if (!IS_CHAR(val)) { 9828 XP_ERROR0(XPATH_INVALID_CHAR_ERROR); 9829 } 9830 return(val); 9831 } else { 9832 /* 1-byte code */ 9833 *len = 1; 9834 return((int) *cur); 9835 } 9836encoding_error: 9837 /* 9838 * If we detect an UTF8 error that probably means that the 9839 * input encoding didn't get properly advertised in the 9840 * declaration header. Report the error and switch the encoding 9841 * to ISO-Latin-1 (if you don't like this policy, just declare the 9842 * encoding !) 9843 */ 9844 *len = 0; 9845 XP_ERROR0(XPATH_ENCODING_ERROR); 9846} 9847 9848/** 9849 * xmlXPathParseNCName: 9850 * @ctxt: the XPath Parser context 9851 * 9852 * parse an XML namespace non qualified name. 9853 * 9854 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)* 9855 * 9856 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' | 9857 * CombiningChar | Extender 9858 * 9859 * Returns the namespace name or NULL 9860 */ 9861 9862xmlChar * 9863xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) { 9864 const xmlChar *in; 9865 xmlChar *ret; 9866 int count = 0; 9867 9868 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL); 9869 /* 9870 * Accelerator for simple ASCII names 9871 */ 9872 in = ctxt->cur; 9873 if (((*in >= 0x61) && (*in <= 0x7A)) || 9874 ((*in >= 0x41) && (*in <= 0x5A)) || 9875 (*in == '_')) { 9876 in++; 9877 while (((*in >= 0x61) && (*in <= 0x7A)) || 9878 ((*in >= 0x41) && (*in <= 0x5A)) || 9879 ((*in >= 0x30) && (*in <= 0x39)) || 9880 (*in == '_') || (*in == '.') || 9881 (*in == '-')) 9882 in++; 9883 if ((*in == ' ') || (*in == '>') || (*in == '/') || 9884 (*in == '[') || (*in == ']') || (*in == ':') || 9885 (*in == '@') || (*in == '*')) { 9886 count = in - ctxt->cur; 9887 if (count == 0) 9888 return(NULL); 9889 ret = xmlStrndup(ctxt->cur, count); 9890 ctxt->cur = in; 9891 return(ret); 9892 } 9893 } 9894 return(xmlXPathParseNameComplex(ctxt, 0)); 9895} 9896 9897 9898/** 9899 * xmlXPathParseQName: 9900 * @ctxt: the XPath Parser context 9901 * @prefix: a xmlChar ** 9902 * 9903 * parse an XML qualified name 9904 * 9905 * [NS 5] QName ::= (Prefix ':')? LocalPart 9906 * 9907 * [NS 6] Prefix ::= NCName 9908 * 9909 * [NS 7] LocalPart ::= NCName 9910 * 9911 * Returns the function returns the local part, and prefix is updated 9912 * to get the Prefix if any. 9913 */ 9914 9915static xmlChar * 9916xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) { 9917 xmlChar *ret = NULL; 9918 9919 *prefix = NULL; 9920 ret = xmlXPathParseNCName(ctxt); 9921 if (ret && CUR == ':') { 9922 *prefix = ret; 9923 NEXT; 9924 ret = xmlXPathParseNCName(ctxt); 9925 } 9926 return(ret); 9927} 9928 9929/** 9930 * xmlXPathParseName: 9931 * @ctxt: the XPath Parser context 9932 * 9933 * parse an XML name 9934 * 9935 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | 9936 * CombiningChar | Extender 9937 * 9938 * [5] Name ::= (Letter | '_' | ':') (NameChar)* 9939 * 9940 * Returns the namespace name or NULL 9941 */ 9942 9943xmlChar * 9944xmlXPathParseName(xmlXPathParserContextPtr ctxt) { 9945 const xmlChar *in; 9946 xmlChar *ret; 9947 size_t count = 0; 9948 9949 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL); 9950 /* 9951 * Accelerator for simple ASCII names 9952 */ 9953 in = ctxt->cur; 9954 if (((*in >= 0x61) && (*in <= 0x7A)) || 9955 ((*in >= 0x41) && (*in <= 0x5A)) || 9956 (*in == '_') || (*in == ':')) { 9957 in++; 9958 while (((*in >= 0x61) && (*in <= 0x7A)) || 9959 ((*in >= 0x41) && (*in <= 0x5A)) || 9960 ((*in >= 0x30) && (*in <= 0x39)) || 9961 (*in == '_') || (*in == '-') || 9962 (*in == ':') || (*in == '.')) 9963 in++; 9964 if ((*in > 0) && (*in < 0x80)) { 9965 count = in - ctxt->cur; 9966 if (count > XML_MAX_NAME_LENGTH) { 9967 ctxt->cur = in; 9968 XP_ERRORNULL(XPATH_EXPR_ERROR); 9969 } 9970 ret = xmlStrndup(ctxt->cur, count); 9971 ctxt->cur = in; 9972 return(ret); 9973 } 9974 } 9975 return(xmlXPathParseNameComplex(ctxt, 1)); 9976} 9977 9978static xmlChar * 9979xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) { 9980 xmlChar buf[XML_MAX_NAMELEN + 5]; 9981 int len = 0, l; 9982 int c; 9983 9984 /* 9985 * Handler for more complex cases 9986 */ 9987 c = CUR_CHAR(l); 9988 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */ 9989 (c == '[') || (c == ']') || (c == '@') || /* accelerators */ 9990 (c == '*') || /* accelerators */ 9991 (!IS_LETTER(c) && (c != '_') && 9992 ((qualified) && (c != ':')))) { 9993 return(NULL); 9994 } 9995 9996 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */ 9997 ((IS_LETTER(c)) || (IS_DIGIT(c)) || 9998 (c == '.') || (c == '-') || 9999 (c == '_') || ((qualified) && (c == ':')) || 10000 (IS_COMBINING(c)) || 10001 (IS_EXTENDER(c)))) { 10002 COPY_BUF(l,buf,len,c); 10003 NEXTL(l); 10004 c = CUR_CHAR(l); 10005 if (len >= XML_MAX_NAMELEN) { 10006 /* 10007 * Okay someone managed to make a huge name, so he's ready to pay 10008 * for the processing speed. 10009 */ 10010 xmlChar *buffer; 10011 int max = len * 2; 10012 10013 if (len > XML_MAX_NAME_LENGTH) { 10014 XP_ERRORNULL(XPATH_EXPR_ERROR); 10015 } 10016 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar)); 10017 if (buffer == NULL) { 10018 XP_ERRORNULL(XPATH_MEMORY_ERROR); 10019 } 10020 memcpy(buffer, buf, len); 10021 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */ 10022 (c == '.') || (c == '-') || 10023 (c == '_') || ((qualified) && (c == ':')) || 10024 (IS_COMBINING(c)) || 10025 (IS_EXTENDER(c))) { 10026 if (len + 10 > max) { 10027 if (max > XML_MAX_NAME_LENGTH) { 10028 XP_ERRORNULL(XPATH_EXPR_ERROR); 10029 } 10030 max *= 2; 10031 buffer = (xmlChar *) xmlRealloc(buffer, 10032 max * sizeof(xmlChar)); 10033 if (buffer == NULL) { 10034 XP_ERRORNULL(XPATH_MEMORY_ERROR); 10035 } 10036 } 10037 COPY_BUF(l,buffer,len,c); 10038 NEXTL(l); 10039 c = CUR_CHAR(l); 10040 } 10041 buffer[len] = 0; 10042 return(buffer); 10043 } 10044 } 10045 if (len == 0) 10046 return(NULL); 10047 return(xmlStrndup(buf, len)); 10048} 10049 10050#define MAX_FRAC 20 10051 10052/* 10053 * These are used as divisors for the fractional part of a number. 10054 * Since the table includes 1.0 (representing '0' fractional digits), 10055 * it must be dimensioned at MAX_FRAC+1 (bug 133921) 10056 */ 10057static double my_pow10[MAX_FRAC+1] = { 10058 1.0, 10.0, 100.0, 1000.0, 10000.0, 10059 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0, 10060 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0, 10061 100000000000000.0, 10062 1000000000000000.0, 10000000000000000.0, 100000000000000000.0, 10063 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0 10064}; 10065 10066/** 10067 * xmlXPathStringEvalNumber: 10068 * @str: A string to scan 10069 * 10070 * [30a] Float ::= Number ('e' Digits?)? 10071 * 10072 * [30] Number ::= Digits ('.' Digits?)? 10073 * | '.' Digits 10074 * [31] Digits ::= [0-9]+ 10075 * 10076 * Compile a Number in the string 10077 * In complement of the Number expression, this function also handles 10078 * negative values : '-' Number. 10079 * 10080 * Returns the double value. 10081 */ 10082double 10083xmlXPathStringEvalNumber(const xmlChar *str) { 10084 const xmlChar *cur = str; 10085 double ret; 10086 int ok = 0; 10087 int isneg = 0; 10088 int exponent = 0; 10089 int is_exponent_negative = 0; 10090#ifdef __GNUC__ 10091 unsigned long tmp = 0; 10092 double temp; 10093#endif 10094 if (cur == NULL) return(0); 10095 while (IS_BLANK_CH(*cur)) cur++; 10096 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) { 10097 return(xmlXPathNAN); 10098 } 10099 if (*cur == '-') { 10100 isneg = 1; 10101 cur++; 10102 } 10103 10104#ifdef __GNUC__ 10105 /* 10106 * tmp/temp is a workaround against a gcc compiler bug 10107 * http://veillard.com/gcc.bug 10108 */ 10109 ret = 0; 10110 while ((*cur >= '0') && (*cur <= '9')) { 10111 ret = ret * 10; 10112 tmp = (*cur - '0'); 10113 ok = 1; 10114 cur++; 10115 temp = (double) tmp; 10116 ret = ret + temp; 10117 } 10118#else 10119 ret = 0; 10120 while ((*cur >= '0') && (*cur <= '9')) { 10121 ret = ret * 10 + (*cur - '0'); 10122 ok = 1; 10123 cur++; 10124 } 10125#endif 10126 10127 if (*cur == '.') { 10128 int v, frac = 0; 10129 double fraction = 0; 10130 10131 cur++; 10132 if (((*cur < '0') || (*cur > '9')) && (!ok)) { 10133 return(xmlXPathNAN); 10134 } 10135 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) { 10136 v = (*cur - '0'); 10137 fraction = fraction * 10 + v; 10138 frac = frac + 1; 10139 cur++; 10140 } 10141 fraction /= my_pow10[frac]; 10142 ret = ret + fraction; 10143 while ((*cur >= '0') && (*cur <= '9')) 10144 cur++; 10145 } 10146 if ((*cur == 'e') || (*cur == 'E')) { 10147 cur++; 10148 if (*cur == '-') { 10149 is_exponent_negative = 1; 10150 cur++; 10151 } else if (*cur == '+') { 10152 cur++; 10153 } 10154 while ((*cur >= '0') && (*cur <= '9')) { 10155 exponent = exponent * 10 + (*cur - '0'); 10156 cur++; 10157 } 10158 } 10159 while (IS_BLANK_CH(*cur)) cur++; 10160 if (*cur != 0) return(xmlXPathNAN); 10161 if (isneg) ret = -ret; 10162 if (is_exponent_negative) exponent = -exponent; 10163 ret *= pow(10.0, (double)exponent); 10164 return(ret); 10165} 10166 10167/** 10168 * xmlXPathCompNumber: 10169 * @ctxt: the XPath Parser context 10170 * 10171 * [30] Number ::= Digits ('.' Digits?)? 10172 * | '.' Digits 10173 * [31] Digits ::= [0-9]+ 10174 * 10175 * Compile a Number, then push it on the stack 10176 * 10177 */ 10178static void 10179xmlXPathCompNumber(xmlXPathParserContextPtr ctxt) 10180{ 10181 double ret = 0.0; 10182 int ok = 0; 10183 int exponent = 0; 10184 int is_exponent_negative = 0; 10185#ifdef __GNUC__ 10186 unsigned long tmp = 0; 10187 double temp; 10188#endif 10189 10190 CHECK_ERROR; 10191 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) { 10192 XP_ERROR(XPATH_NUMBER_ERROR); 10193 } 10194#ifdef __GNUC__ 10195 /* 10196 * tmp/temp is a workaround against a gcc compiler bug 10197 * http://veillard.com/gcc.bug 10198 */ 10199 ret = 0; 10200 while ((CUR >= '0') && (CUR <= '9')) { 10201 ret = ret * 10; 10202 tmp = (CUR - '0'); 10203 ok = 1; 10204 NEXT; 10205 temp = (double) tmp; 10206 ret = ret + temp; 10207 } 10208#else 10209 ret = 0; 10210 while ((CUR >= '0') && (CUR <= '9')) { 10211 ret = ret * 10 + (CUR - '0'); 10212 ok = 1; 10213 NEXT; 10214 } 10215#endif 10216 if (CUR == '.') { 10217 int v, frac = 0; 10218 double fraction = 0; 10219 10220 NEXT; 10221 if (((CUR < '0') || (CUR > '9')) && (!ok)) { 10222 XP_ERROR(XPATH_NUMBER_ERROR); 10223 } 10224 while ((CUR >= '0') && (CUR <= '9') && (frac < MAX_FRAC)) { 10225 v = (CUR - '0'); 10226 fraction = fraction * 10 + v; 10227 frac = frac + 1; 10228 NEXT; 10229 } 10230 fraction /= my_pow10[frac]; 10231 ret = ret + fraction; 10232 while ((CUR >= '0') && (CUR <= '9')) 10233 NEXT; 10234 } 10235 if ((CUR == 'e') || (CUR == 'E')) { 10236 NEXT; 10237 if (CUR == '-') { 10238 is_exponent_negative = 1; 10239 NEXT; 10240 } else if (CUR == '+') { 10241 NEXT; 10242 } 10243 while ((CUR >= '0') && (CUR <= '9')) { 10244 exponent = exponent * 10 + (CUR - '0'); 10245 NEXT; 10246 } 10247 if (is_exponent_negative) 10248 exponent = -exponent; 10249 ret *= pow(10.0, (double) exponent); 10250 } 10251 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, 10252 xmlXPathCacheNewFloat(ctxt->context, ret), NULL); 10253} 10254 10255/** 10256 * xmlXPathParseLiteral: 10257 * @ctxt: the XPath Parser context 10258 * 10259 * Parse a Literal 10260 * 10261 * [29] Literal ::= '"' [^"]* '"' 10262 * | "'" [^']* "'" 10263 * 10264 * Returns the value found or NULL in case of error 10265 */ 10266static xmlChar * 10267xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) { 10268 const xmlChar *q; 10269 xmlChar *ret = NULL; 10270 10271 if (CUR == '"') { 10272 NEXT; 10273 q = CUR_PTR; 10274 while ((IS_CHAR_CH(CUR)) && (CUR != '"')) 10275 NEXT; 10276 if (!IS_CHAR_CH(CUR)) { 10277 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR); 10278 } else { 10279 ret = xmlStrndup(q, CUR_PTR - q); 10280 NEXT; 10281 } 10282 } else if (CUR == '\'') { 10283 NEXT; 10284 q = CUR_PTR; 10285 while ((IS_CHAR_CH(CUR)) && (CUR != '\'')) 10286 NEXT; 10287 if (!IS_CHAR_CH(CUR)) { 10288 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR); 10289 } else { 10290 ret = xmlStrndup(q, CUR_PTR - q); 10291 NEXT; 10292 } 10293 } else { 10294 XP_ERRORNULL(XPATH_START_LITERAL_ERROR); 10295 } 10296 return(ret); 10297} 10298 10299/** 10300 * xmlXPathCompLiteral: 10301 * @ctxt: the XPath Parser context 10302 * 10303 * Parse a Literal and push it on the stack. 10304 * 10305 * [29] Literal ::= '"' [^"]* '"' 10306 * | "'" [^']* "'" 10307 * 10308 * TODO: xmlXPathCompLiteral memory allocation could be improved. 10309 */ 10310static void 10311xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) { 10312 const xmlChar *q; 10313 xmlChar *ret = NULL; 10314 10315 if (CUR == '"') { 10316 NEXT; 10317 q = CUR_PTR; 10318 while ((IS_CHAR_CH(CUR)) && (CUR != '"')) 10319 NEXT; 10320 if (!IS_CHAR_CH(CUR)) { 10321 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR); 10322 } else { 10323 ret = xmlStrndup(q, CUR_PTR - q); 10324 NEXT; 10325 } 10326 } else if (CUR == '\'') { 10327 NEXT; 10328 q = CUR_PTR; 10329 while ((IS_CHAR_CH(CUR)) && (CUR != '\'')) 10330 NEXT; 10331 if (!IS_CHAR_CH(CUR)) { 10332 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR); 10333 } else { 10334 ret = xmlStrndup(q, CUR_PTR - q); 10335 NEXT; 10336 } 10337 } else { 10338 XP_ERROR(XPATH_START_LITERAL_ERROR); 10339 } 10340 if (ret == NULL) return; 10341 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, 10342 xmlXPathCacheNewString(ctxt->context, ret), NULL); 10343 xmlFree(ret); 10344} 10345 10346/** 10347 * xmlXPathCompVariableReference: 10348 * @ctxt: the XPath Parser context 10349 * 10350 * Parse a VariableReference, evaluate it and push it on the stack. 10351 * 10352 * The variable bindings consist of a mapping from variable names 10353 * to variable values. The value of a variable is an object, which can be 10354 * of any of the types that are possible for the value of an expression, 10355 * and may also be of additional types not specified here. 10356 * 10357 * Early evaluation is possible since: 10358 * The variable bindings [...] used to evaluate a subexpression are 10359 * always the same as those used to evaluate the containing expression. 10360 * 10361 * [36] VariableReference ::= '$' QName 10362 */ 10363static void 10364xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) { 10365 xmlChar *name; 10366 xmlChar *prefix; 10367 10368 SKIP_BLANKS; 10369 if (CUR != '$') { 10370 XP_ERROR(XPATH_VARIABLE_REF_ERROR); 10371 } 10372 NEXT; 10373 name = xmlXPathParseQName(ctxt, &prefix); 10374 if (name == NULL) { 10375 XP_ERROR(XPATH_VARIABLE_REF_ERROR); 10376 } 10377 ctxt->comp->last = -1; 10378 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, 10379 name, prefix); 10380 SKIP_BLANKS; 10381 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) { 10382 XP_ERROR(XPATH_FORBID_VARIABLE_ERROR); 10383 } 10384} 10385 10386/** 10387 * xmlXPathIsNodeType: 10388 * @name: a name string 10389 * 10390 * Is the name given a NodeType one. 10391 * 10392 * [38] NodeType ::= 'comment' 10393 * | 'text' 10394 * | 'processing-instruction' 10395 * | 'node' 10396 * 10397 * Returns 1 if true 0 otherwise 10398 */ 10399int 10400xmlXPathIsNodeType(const xmlChar *name) { 10401 if (name == NULL) 10402 return(0); 10403 10404 if (xmlStrEqual(name, BAD_CAST "node")) 10405 return(1); 10406 if (xmlStrEqual(name, BAD_CAST "text")) 10407 return(1); 10408 if (xmlStrEqual(name, BAD_CAST "comment")) 10409 return(1); 10410 if (xmlStrEqual(name, BAD_CAST "processing-instruction")) 10411 return(1); 10412 return(0); 10413} 10414 10415/** 10416 * xmlXPathCompFunctionCall: 10417 * @ctxt: the XPath Parser context 10418 * 10419 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')' 10420 * [17] Argument ::= Expr 10421 * 10422 * Compile a function call, the evaluation of all arguments are 10423 * pushed on the stack 10424 */ 10425static void 10426xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) { 10427 xmlChar *name; 10428 xmlChar *prefix; 10429 int nbargs = 0; 10430 int sort = 1; 10431 10432 name = xmlXPathParseQName(ctxt, &prefix); 10433 if (name == NULL) { 10434 xmlFree(prefix); 10435 XP_ERROR(XPATH_EXPR_ERROR); 10436 } 10437 SKIP_BLANKS; 10438#ifdef DEBUG_EXPR 10439 if (prefix == NULL) 10440 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n", 10441 name); 10442 else 10443 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n", 10444 prefix, name); 10445#endif 10446 10447 if (CUR != '(') { 10448 XP_ERROR(XPATH_EXPR_ERROR); 10449 } 10450 NEXT; 10451 SKIP_BLANKS; 10452 10453 /* 10454 * Optimization for count(): we don't need the node-set to be sorted. 10455 */ 10456 if ((prefix == NULL) && (name[0] == 'c') && 10457 xmlStrEqual(name, BAD_CAST "count")) 10458 { 10459 sort = 0; 10460 } 10461 ctxt->comp->last = -1; 10462 if (CUR != ')') { 10463 while (CUR != 0) { 10464 int op1 = ctxt->comp->last; 10465 ctxt->comp->last = -1; 10466 xmlXPathCompileExpr(ctxt, sort); 10467 if (ctxt->error != XPATH_EXPRESSION_OK) { 10468 xmlFree(name); 10469 xmlFree(prefix); 10470 return; 10471 } 10472 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0); 10473 nbargs++; 10474 if (CUR == ')') break; 10475 if (CUR != ',') { 10476 XP_ERROR(XPATH_EXPR_ERROR); 10477 } 10478 NEXT; 10479 SKIP_BLANKS; 10480 } 10481 } 10482 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, 10483 name, prefix); 10484 NEXT; 10485 SKIP_BLANKS; 10486} 10487 10488/** 10489 * xmlXPathCompPrimaryExpr: 10490 * @ctxt: the XPath Parser context 10491 * 10492 * [15] PrimaryExpr ::= VariableReference 10493 * | '(' Expr ')' 10494 * | Literal 10495 * | Number 10496 * | FunctionCall 10497 * 10498 * Compile a primary expression. 10499 */ 10500static void 10501xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) { 10502 SKIP_BLANKS; 10503 if (CUR == '$') xmlXPathCompVariableReference(ctxt); 10504 else if (CUR == '(') { 10505 NEXT; 10506 SKIP_BLANKS; 10507 xmlXPathCompileExpr(ctxt, 1); 10508 CHECK_ERROR; 10509 if (CUR != ')') { 10510 XP_ERROR(XPATH_EXPR_ERROR); 10511 } 10512 NEXT; 10513 SKIP_BLANKS; 10514 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) { 10515 xmlXPathCompNumber(ctxt); 10516 } else if ((CUR == '\'') || (CUR == '"')) { 10517 xmlXPathCompLiteral(ctxt); 10518 } else { 10519 xmlXPathCompFunctionCall(ctxt); 10520 } 10521 SKIP_BLANKS; 10522} 10523 10524/** 10525 * xmlXPathCompFilterExpr: 10526 * @ctxt: the XPath Parser context 10527 * 10528 * [20] FilterExpr ::= PrimaryExpr 10529 * | FilterExpr Predicate 10530 * 10531 * Compile a filter expression. 10532 * Square brackets are used to filter expressions in the same way that 10533 * they are used in location paths. It is an error if the expression to 10534 * be filtered does not evaluate to a node-set. The context node list 10535 * used for evaluating the expression in square brackets is the node-set 10536 * to be filtered listed in document order. 10537 */ 10538 10539static void 10540xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) { 10541 xmlXPathCompPrimaryExpr(ctxt); 10542 CHECK_ERROR; 10543 SKIP_BLANKS; 10544 10545 while (CUR == '[') { 10546 xmlXPathCompPredicate(ctxt, 1); 10547 SKIP_BLANKS; 10548 } 10549 10550 10551} 10552 10553/** 10554 * xmlXPathScanName: 10555 * @ctxt: the XPath Parser context 10556 * 10557 * Trickery: parse an XML name but without consuming the input flow 10558 * Needed to avoid insanity in the parser state. 10559 * 10560 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | 10561 * CombiningChar | Extender 10562 * 10563 * [5] Name ::= (Letter | '_' | ':') (NameChar)* 10564 * 10565 * [6] Names ::= Name (S Name)* 10566 * 10567 * Returns the Name parsed or NULL 10568 */ 10569 10570static xmlChar * 10571xmlXPathScanName(xmlXPathParserContextPtr ctxt) { 10572 int len = 0, l; 10573 int c; 10574 const xmlChar *cur; 10575 xmlChar *ret; 10576 10577 cur = ctxt->cur; 10578 10579 c = CUR_CHAR(l); 10580 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */ 10581 (!IS_LETTER(c) && (c != '_') && 10582 (c != ':'))) { 10583 return(NULL); 10584 } 10585 10586 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */ 10587 ((IS_LETTER(c)) || (IS_DIGIT(c)) || 10588 (c == '.') || (c == '-') || 10589 (c == '_') || (c == ':') || 10590 (IS_COMBINING(c)) || 10591 (IS_EXTENDER(c)))) { 10592 len += l; 10593 NEXTL(l); 10594 c = CUR_CHAR(l); 10595 } 10596 ret = xmlStrndup(cur, ctxt->cur - cur); 10597 ctxt->cur = cur; 10598 return(ret); 10599} 10600 10601/** 10602 * xmlXPathCompPathExpr: 10603 * @ctxt: the XPath Parser context 10604 * 10605 * [19] PathExpr ::= LocationPath 10606 * | FilterExpr 10607 * | FilterExpr '/' RelativeLocationPath 10608 * | FilterExpr '//' RelativeLocationPath 10609 * 10610 * Compile a path expression. 10611 * The / operator and // operators combine an arbitrary expression 10612 * and a relative location path. It is an error if the expression 10613 * does not evaluate to a node-set. 10614 * The / operator does composition in the same way as when / is 10615 * used in a location path. As in location paths, // is short for 10616 * /descendant-or-self::node()/. 10617 */ 10618 10619static void 10620xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) { 10621 int lc = 1; /* Should we branch to LocationPath ? */ 10622 xmlChar *name = NULL; /* we may have to preparse a name to find out */ 10623 10624 SKIP_BLANKS; 10625 if ((CUR == '$') || (CUR == '(') || 10626 (IS_ASCII_DIGIT(CUR)) || 10627 (CUR == '\'') || (CUR == '"') || 10628 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) { 10629 lc = 0; 10630 } else if (CUR == '*') { 10631 /* relative or absolute location path */ 10632 lc = 1; 10633 } else if (CUR == '/') { 10634 /* relative or absolute location path */ 10635 lc = 1; 10636 } else if (CUR == '@') { 10637 /* relative abbreviated attribute location path */ 10638 lc = 1; 10639 } else if (CUR == '.') { 10640 /* relative abbreviated attribute location path */ 10641 lc = 1; 10642 } else { 10643 /* 10644 * Problem is finding if we have a name here whether it's: 10645 * - a nodetype 10646 * - a function call in which case it's followed by '(' 10647 * - an axis in which case it's followed by ':' 10648 * - a element name 10649 * We do an a priori analysis here rather than having to 10650 * maintain parsed token content through the recursive function 10651 * calls. This looks uglier but makes the code easier to 10652 * read/write/debug. 10653 */ 10654 SKIP_BLANKS; 10655 name = xmlXPathScanName(ctxt); 10656 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) { 10657#ifdef DEBUG_STEP 10658 xmlGenericError(xmlGenericErrorContext, 10659 "PathExpr: Axis\n"); 10660#endif 10661 lc = 1; 10662 xmlFree(name); 10663 } else if (name != NULL) { 10664 int len =xmlStrlen(name); 10665 10666 10667 while (NXT(len) != 0) { 10668 if (NXT(len) == '/') { 10669 /* element name */ 10670#ifdef DEBUG_STEP 10671 xmlGenericError(xmlGenericErrorContext, 10672 "PathExpr: AbbrRelLocation\n"); 10673#endif 10674 lc = 1; 10675 break; 10676 } else if (IS_BLANK_CH(NXT(len))) { 10677 /* ignore blanks */ 10678 ; 10679 } else if (NXT(len) == ':') { 10680#ifdef DEBUG_STEP 10681 xmlGenericError(xmlGenericErrorContext, 10682 "PathExpr: AbbrRelLocation\n"); 10683#endif 10684 lc = 1; 10685 break; 10686 } else if ((NXT(len) == '(')) { 10687 /* Note Type or Function */ 10688 if (xmlXPathIsNodeType(name)) { 10689#ifdef DEBUG_STEP 10690 xmlGenericError(xmlGenericErrorContext, 10691 "PathExpr: Type search\n"); 10692#endif 10693 lc = 1; 10694 } else { 10695#ifdef DEBUG_STEP 10696 xmlGenericError(xmlGenericErrorContext, 10697 "PathExpr: function call\n"); 10698#endif 10699 lc = 0; 10700 } 10701 break; 10702 } else if ((NXT(len) == '[')) { 10703 /* element name */ 10704#ifdef DEBUG_STEP 10705 xmlGenericError(xmlGenericErrorContext, 10706 "PathExpr: AbbrRelLocation\n"); 10707#endif 10708 lc = 1; 10709 break; 10710 } else if ((NXT(len) == '<') || (NXT(len) == '>') || 10711 (NXT(len) == '=')) { 10712 lc = 1; 10713 break; 10714 } else { 10715 lc = 1; 10716 break; 10717 } 10718 len++; 10719 } 10720 if (NXT(len) == 0) { 10721#ifdef DEBUG_STEP 10722 xmlGenericError(xmlGenericErrorContext, 10723 "PathExpr: AbbrRelLocation\n"); 10724#endif 10725 /* element name */ 10726 lc = 1; 10727 } 10728 xmlFree(name); 10729 } else { 10730 /* make sure all cases are covered explicitly */ 10731 XP_ERROR(XPATH_EXPR_ERROR); 10732 } 10733 } 10734 10735 if (lc) { 10736 if (CUR == '/') { 10737 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0); 10738 } else { 10739 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0); 10740 } 10741 xmlXPathCompLocationPath(ctxt); 10742 } else { 10743 xmlXPathCompFilterExpr(ctxt); 10744 CHECK_ERROR; 10745 if ((CUR == '/') && (NXT(1) == '/')) { 10746 SKIP(2); 10747 SKIP_BLANKS; 10748 10749 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 10750 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 10751 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0); 10752 10753 xmlXPathCompRelativeLocationPath(ctxt); 10754 } else if (CUR == '/') { 10755 xmlXPathCompRelativeLocationPath(ctxt); 10756 } 10757 } 10758 SKIP_BLANKS; 10759} 10760 10761/** 10762 * xmlXPathCompUnionExpr: 10763 * @ctxt: the XPath Parser context 10764 * 10765 * [18] UnionExpr ::= PathExpr 10766 * | UnionExpr '|' PathExpr 10767 * 10768 * Compile an union expression. 10769 */ 10770 10771static void 10772xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) { 10773 xmlXPathCompPathExpr(ctxt); 10774 CHECK_ERROR; 10775 SKIP_BLANKS; 10776 while (CUR == '|') { 10777 int op1 = ctxt->comp->last; 10778 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0); 10779 10780 NEXT; 10781 SKIP_BLANKS; 10782 xmlXPathCompPathExpr(ctxt); 10783 10784 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0); 10785 10786 SKIP_BLANKS; 10787 } 10788} 10789 10790/** 10791 * xmlXPathCompUnaryExpr: 10792 * @ctxt: the XPath Parser context 10793 * 10794 * [27] UnaryExpr ::= UnionExpr 10795 * | '-' UnaryExpr 10796 * 10797 * Compile an unary expression. 10798 */ 10799 10800static void 10801xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) { 10802 int minus = 0; 10803 int found = 0; 10804 10805 SKIP_BLANKS; 10806 while (CUR == '-') { 10807 minus = 1 - minus; 10808 found = 1; 10809 NEXT; 10810 SKIP_BLANKS; 10811 } 10812 10813 xmlXPathCompUnionExpr(ctxt); 10814 CHECK_ERROR; 10815 if (found) { 10816 if (minus) 10817 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0); 10818 else 10819 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0); 10820 } 10821} 10822 10823/** 10824 * xmlXPathCompMultiplicativeExpr: 10825 * @ctxt: the XPath Parser context 10826 * 10827 * [26] MultiplicativeExpr ::= UnaryExpr 10828 * | MultiplicativeExpr MultiplyOperator UnaryExpr 10829 * | MultiplicativeExpr 'div' UnaryExpr 10830 * | MultiplicativeExpr 'mod' UnaryExpr 10831 * [34] MultiplyOperator ::= '*' 10832 * 10833 * Compile an Additive expression. 10834 */ 10835 10836static void 10837xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) { 10838 xmlXPathCompUnaryExpr(ctxt); 10839 CHECK_ERROR; 10840 SKIP_BLANKS; 10841 while ((CUR == '*') || 10842 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) || 10843 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) { 10844 int op = -1; 10845 int op1 = ctxt->comp->last; 10846 10847 if (CUR == '*') { 10848 op = 0; 10849 NEXT; 10850 } else if (CUR == 'd') { 10851 op = 1; 10852 SKIP(3); 10853 } else if (CUR == 'm') { 10854 op = 2; 10855 SKIP(3); 10856 } 10857 SKIP_BLANKS; 10858 xmlXPathCompUnaryExpr(ctxt); 10859 CHECK_ERROR; 10860 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0); 10861 SKIP_BLANKS; 10862 } 10863} 10864 10865/** 10866 * xmlXPathCompAdditiveExpr: 10867 * @ctxt: the XPath Parser context 10868 * 10869 * [25] AdditiveExpr ::= MultiplicativeExpr 10870 * | AdditiveExpr '+' MultiplicativeExpr 10871 * | AdditiveExpr '-' MultiplicativeExpr 10872 * 10873 * Compile an Additive expression. 10874 */ 10875 10876static void 10877xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) { 10878 10879 xmlXPathCompMultiplicativeExpr(ctxt); 10880 CHECK_ERROR; 10881 SKIP_BLANKS; 10882 while ((CUR == '+') || (CUR == '-')) { 10883 int plus; 10884 int op1 = ctxt->comp->last; 10885 10886 if (CUR == '+') plus = 1; 10887 else plus = 0; 10888 NEXT; 10889 SKIP_BLANKS; 10890 xmlXPathCompMultiplicativeExpr(ctxt); 10891 CHECK_ERROR; 10892 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0); 10893 SKIP_BLANKS; 10894 } 10895} 10896 10897/** 10898 * xmlXPathCompRelationalExpr: 10899 * @ctxt: the XPath Parser context 10900 * 10901 * [24] RelationalExpr ::= AdditiveExpr 10902 * | RelationalExpr '<' AdditiveExpr 10903 * | RelationalExpr '>' AdditiveExpr 10904 * | RelationalExpr '<=' AdditiveExpr 10905 * | RelationalExpr '>=' AdditiveExpr 10906 * 10907 * A <= B > C is allowed ? Answer from James, yes with 10908 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr 10909 * which is basically what got implemented. 10910 * 10911 * Compile a Relational expression, then push the result 10912 * on the stack 10913 */ 10914 10915static void 10916xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) { 10917 xmlXPathCompAdditiveExpr(ctxt); 10918 CHECK_ERROR; 10919 SKIP_BLANKS; 10920 while ((CUR == '<') || 10921 (CUR == '>') || 10922 ((CUR == '<') && (NXT(1) == '=')) || 10923 ((CUR == '>') && (NXT(1) == '='))) { 10924 int inf, strict; 10925 int op1 = ctxt->comp->last; 10926 10927 if (CUR == '<') inf = 1; 10928 else inf = 0; 10929 if (NXT(1) == '=') strict = 0; 10930 else strict = 1; 10931 NEXT; 10932 if (!strict) NEXT; 10933 SKIP_BLANKS; 10934 xmlXPathCompAdditiveExpr(ctxt); 10935 CHECK_ERROR; 10936 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict); 10937 SKIP_BLANKS; 10938 } 10939} 10940 10941/** 10942 * xmlXPathCompEqualityExpr: 10943 * @ctxt: the XPath Parser context 10944 * 10945 * [23] EqualityExpr ::= RelationalExpr 10946 * | EqualityExpr '=' RelationalExpr 10947 * | EqualityExpr '!=' RelationalExpr 10948 * 10949 * A != B != C is allowed ? Answer from James, yes with 10950 * (RelationalExpr = RelationalExpr) = RelationalExpr 10951 * (RelationalExpr != RelationalExpr) != RelationalExpr 10952 * which is basically what got implemented. 10953 * 10954 * Compile an Equality expression. 10955 * 10956 */ 10957static void 10958xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) { 10959 xmlXPathCompRelationalExpr(ctxt); 10960 CHECK_ERROR; 10961 SKIP_BLANKS; 10962 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) { 10963 int eq; 10964 int op1 = ctxt->comp->last; 10965 10966 if (CUR == '=') eq = 1; 10967 else eq = 0; 10968 NEXT; 10969 if (!eq) NEXT; 10970 SKIP_BLANKS; 10971 xmlXPathCompRelationalExpr(ctxt); 10972 CHECK_ERROR; 10973 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0); 10974 SKIP_BLANKS; 10975 } 10976} 10977 10978/** 10979 * xmlXPathCompAndExpr: 10980 * @ctxt: the XPath Parser context 10981 * 10982 * [22] AndExpr ::= EqualityExpr 10983 * | AndExpr 'and' EqualityExpr 10984 * 10985 * Compile an AND expression. 10986 * 10987 */ 10988static void 10989xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) { 10990 xmlXPathCompEqualityExpr(ctxt); 10991 CHECK_ERROR; 10992 SKIP_BLANKS; 10993 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) { 10994 int op1 = ctxt->comp->last; 10995 SKIP(3); 10996 SKIP_BLANKS; 10997 xmlXPathCompEqualityExpr(ctxt); 10998 CHECK_ERROR; 10999 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0); 11000 SKIP_BLANKS; 11001 } 11002} 11003 11004/** 11005 * xmlXPathCompileExpr: 11006 * @ctxt: the XPath Parser context 11007 * 11008 * [14] Expr ::= OrExpr 11009 * [21] OrExpr ::= AndExpr 11010 * | OrExpr 'or' AndExpr 11011 * 11012 * Parse and compile an expression 11013 */ 11014static void 11015xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) { 11016 xmlXPathCompAndExpr(ctxt); 11017 CHECK_ERROR; 11018 SKIP_BLANKS; 11019 while ((CUR == 'o') && (NXT(1) == 'r')) { 11020 int op1 = ctxt->comp->last; 11021 SKIP(2); 11022 SKIP_BLANKS; 11023 xmlXPathCompAndExpr(ctxt); 11024 CHECK_ERROR; 11025 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0); 11026 SKIP_BLANKS; 11027 } 11028 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) { 11029 /* more ops could be optimized too */ 11030 /* 11031 * This is the main place to eliminate sorting for 11032 * operations which don't require a sorted node-set. 11033 * E.g. count(). 11034 */ 11035 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0); 11036 } 11037} 11038 11039/** 11040 * xmlXPathCompPredicate: 11041 * @ctxt: the XPath Parser context 11042 * @filter: act as a filter 11043 * 11044 * [8] Predicate ::= '[' PredicateExpr ']' 11045 * [9] PredicateExpr ::= Expr 11046 * 11047 * Compile a predicate expression 11048 */ 11049static void 11050xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) { 11051 int op1 = ctxt->comp->last; 11052 11053 SKIP_BLANKS; 11054 if (CUR != '[') { 11055 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); 11056 } 11057 NEXT; 11058 SKIP_BLANKS; 11059 11060 ctxt->comp->last = -1; 11061 /* 11062 * This call to xmlXPathCompileExpr() will deactivate sorting 11063 * of the predicate result. 11064 * TODO: Sorting is still activated for filters, since I'm not 11065 * sure if needed. Normally sorting should not be needed, since 11066 * a filter can only diminish the number of items in a sequence, 11067 * but won't change its order; so if the initial sequence is sorted, 11068 * subsequent sorting is not needed. 11069 */ 11070 if (! filter) 11071 xmlXPathCompileExpr(ctxt, 0); 11072 else 11073 xmlXPathCompileExpr(ctxt, 1); 11074 CHECK_ERROR; 11075 11076 if (CUR != ']') { 11077 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); 11078 } 11079 11080 if (filter) 11081 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0); 11082 else 11083 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0); 11084 11085 NEXT; 11086 SKIP_BLANKS; 11087} 11088 11089/** 11090 * xmlXPathCompNodeTest: 11091 * @ctxt: the XPath Parser context 11092 * @test: pointer to a xmlXPathTestVal 11093 * @type: pointer to a xmlXPathTypeVal 11094 * @prefix: placeholder for a possible name prefix 11095 * 11096 * [7] NodeTest ::= NameTest 11097 * | NodeType '(' ')' 11098 * | 'processing-instruction' '(' Literal ')' 11099 * 11100 * [37] NameTest ::= '*' 11101 * | NCName ':' '*' 11102 * | QName 11103 * [38] NodeType ::= 'comment' 11104 * | 'text' 11105 * | 'processing-instruction' 11106 * | 'node' 11107 * 11108 * Returns the name found and updates @test, @type and @prefix appropriately 11109 */ 11110static xmlChar * 11111xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test, 11112 xmlXPathTypeVal *type, const xmlChar **prefix, 11113 xmlChar *name) { 11114 int blanks; 11115 11116 if ((test == NULL) || (type == NULL) || (prefix == NULL)) { 11117 STRANGE; 11118 return(NULL); 11119 } 11120 *type = (xmlXPathTypeVal) 0; 11121 *test = (xmlXPathTestVal) 0; 11122 *prefix = NULL; 11123 SKIP_BLANKS; 11124 11125 if ((name == NULL) && (CUR == '*')) { 11126 /* 11127 * All elements 11128 */ 11129 NEXT; 11130 *test = NODE_TEST_ALL; 11131 return(NULL); 11132 } 11133 11134 if (name == NULL) 11135 name = xmlXPathParseNCName(ctxt); 11136 if (name == NULL) { 11137 XP_ERRORNULL(XPATH_EXPR_ERROR); 11138 } 11139 11140 blanks = IS_BLANK_CH(CUR); 11141 SKIP_BLANKS; 11142 if (CUR == '(') { 11143 NEXT; 11144 /* 11145 * NodeType or PI search 11146 */ 11147 if (xmlStrEqual(name, BAD_CAST "comment")) 11148 *type = NODE_TYPE_COMMENT; 11149 else if (xmlStrEqual(name, BAD_CAST "node")) 11150 *type = NODE_TYPE_NODE; 11151 else if (xmlStrEqual(name, BAD_CAST "processing-instruction")) 11152 *type = NODE_TYPE_PI; 11153 else if (xmlStrEqual(name, BAD_CAST "text")) 11154 *type = NODE_TYPE_TEXT; 11155 else { 11156 if (name != NULL) 11157 xmlFree(name); 11158 XP_ERRORNULL(XPATH_EXPR_ERROR); 11159 } 11160 11161 *test = NODE_TEST_TYPE; 11162 11163 SKIP_BLANKS; 11164 if (*type == NODE_TYPE_PI) { 11165 /* 11166 * Specific case: search a PI by name. 11167 */ 11168 if (name != NULL) 11169 xmlFree(name); 11170 name = NULL; 11171 if (CUR != ')') { 11172 name = xmlXPathParseLiteral(ctxt); 11173 CHECK_ERROR NULL; 11174 *test = NODE_TEST_PI; 11175 SKIP_BLANKS; 11176 } 11177 } 11178 if (CUR != ')') { 11179 if (name != NULL) 11180 xmlFree(name); 11181 XP_ERRORNULL(XPATH_UNCLOSED_ERROR); 11182 } 11183 NEXT; 11184 return(name); 11185 } 11186 *test = NODE_TEST_NAME; 11187 if ((!blanks) && (CUR == ':')) { 11188 NEXT; 11189 11190 /* 11191 * Since currently the parser context don't have a 11192 * namespace list associated: 11193 * The namespace name for this prefix can be computed 11194 * only at evaluation time. The compilation is done 11195 * outside of any context. 11196 */ 11197#if 0 11198 *prefix = xmlXPathNsLookup(ctxt->context, name); 11199 if (name != NULL) 11200 xmlFree(name); 11201 if (*prefix == NULL) { 11202 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); 11203 } 11204#else 11205 *prefix = name; 11206#endif 11207 11208 if (CUR == '*') { 11209 /* 11210 * All elements 11211 */ 11212 NEXT; 11213 *test = NODE_TEST_ALL; 11214 return(NULL); 11215 } 11216 11217 name = xmlXPathParseNCName(ctxt); 11218 if (name == NULL) { 11219 XP_ERRORNULL(XPATH_EXPR_ERROR); 11220 } 11221 } 11222 return(name); 11223} 11224 11225/** 11226 * xmlXPathIsAxisName: 11227 * @name: a preparsed name token 11228 * 11229 * [6] AxisName ::= 'ancestor' 11230 * | 'ancestor-or-self' 11231 * | 'attribute' 11232 * | 'child' 11233 * | 'descendant' 11234 * | 'descendant-or-self' 11235 * | 'following' 11236 * | 'following-sibling' 11237 * | 'namespace' 11238 * | 'parent' 11239 * | 'preceding' 11240 * | 'preceding-sibling' 11241 * | 'self' 11242 * 11243 * Returns the axis or 0 11244 */ 11245static xmlXPathAxisVal 11246xmlXPathIsAxisName(const xmlChar *name) { 11247 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0; 11248 switch (name[0]) { 11249 case 'a': 11250 if (xmlStrEqual(name, BAD_CAST "ancestor")) 11251 ret = AXIS_ANCESTOR; 11252 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self")) 11253 ret = AXIS_ANCESTOR_OR_SELF; 11254 if (xmlStrEqual(name, BAD_CAST "attribute")) 11255 ret = AXIS_ATTRIBUTE; 11256 break; 11257 case 'c': 11258 if (xmlStrEqual(name, BAD_CAST "child")) 11259 ret = AXIS_CHILD; 11260 break; 11261 case 'd': 11262 if (xmlStrEqual(name, BAD_CAST "descendant")) 11263 ret = AXIS_DESCENDANT; 11264 if (xmlStrEqual(name, BAD_CAST "descendant-or-self")) 11265 ret = AXIS_DESCENDANT_OR_SELF; 11266 break; 11267 case 'f': 11268 if (xmlStrEqual(name, BAD_CAST "following")) 11269 ret = AXIS_FOLLOWING; 11270 if (xmlStrEqual(name, BAD_CAST "following-sibling")) 11271 ret = AXIS_FOLLOWING_SIBLING; 11272 break; 11273 case 'n': 11274 if (xmlStrEqual(name, BAD_CAST "namespace")) 11275 ret = AXIS_NAMESPACE; 11276 break; 11277 case 'p': 11278 if (xmlStrEqual(name, BAD_CAST "parent")) 11279 ret = AXIS_PARENT; 11280 if (xmlStrEqual(name, BAD_CAST "preceding")) 11281 ret = AXIS_PRECEDING; 11282 if (xmlStrEqual(name, BAD_CAST "preceding-sibling")) 11283 ret = AXIS_PRECEDING_SIBLING; 11284 break; 11285 case 's': 11286 if (xmlStrEqual(name, BAD_CAST "self")) 11287 ret = AXIS_SELF; 11288 break; 11289 } 11290 return(ret); 11291} 11292 11293/** 11294 * xmlXPathCompStep: 11295 * @ctxt: the XPath Parser context 11296 * 11297 * [4] Step ::= AxisSpecifier NodeTest Predicate* 11298 * | AbbreviatedStep 11299 * 11300 * [12] AbbreviatedStep ::= '.' | '..' 11301 * 11302 * [5] AxisSpecifier ::= AxisName '::' 11303 * | AbbreviatedAxisSpecifier 11304 * 11305 * [13] AbbreviatedAxisSpecifier ::= '@'? 11306 * 11307 * Modified for XPtr range support as: 11308 * 11309 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate* 11310 * | AbbreviatedStep 11311 * | 'range-to' '(' Expr ')' Predicate* 11312 * 11313 * Compile one step in a Location Path 11314 * A location step of . is short for self::node(). This is 11315 * particularly useful in conjunction with //. For example, the 11316 * location path .//para is short for 11317 * self::node()/descendant-or-self::node()/child::para 11318 * and so will select all para descendant elements of the context 11319 * node. 11320 * Similarly, a location step of .. is short for parent::node(). 11321 * For example, ../title is short for parent::node()/child::title 11322 * and so will select the title children of the parent of the context 11323 * node. 11324 */ 11325static void 11326xmlXPathCompStep(xmlXPathParserContextPtr ctxt) { 11327#ifdef LIBXML_XPTR_ENABLED 11328 int rangeto = 0; 11329 int op2 = -1; 11330#endif 11331 11332 SKIP_BLANKS; 11333 if ((CUR == '.') && (NXT(1) == '.')) { 11334 SKIP(2); 11335 SKIP_BLANKS; 11336 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT, 11337 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11338 } else if (CUR == '.') { 11339 NEXT; 11340 SKIP_BLANKS; 11341 } else { 11342 xmlChar *name = NULL; 11343 const xmlChar *prefix = NULL; 11344 xmlXPathTestVal test = (xmlXPathTestVal) 0; 11345 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0; 11346 xmlXPathTypeVal type = (xmlXPathTypeVal) 0; 11347 int op1; 11348 11349 /* 11350 * The modification needed for XPointer change to the production 11351 */ 11352#ifdef LIBXML_XPTR_ENABLED 11353 if (ctxt->xptr) { 11354 name = xmlXPathParseNCName(ctxt); 11355 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) { 11356 op2 = ctxt->comp->last; 11357 xmlFree(name); 11358 SKIP_BLANKS; 11359 if (CUR != '(') { 11360 XP_ERROR(XPATH_EXPR_ERROR); 11361 } 11362 NEXT; 11363 SKIP_BLANKS; 11364 11365 xmlXPathCompileExpr(ctxt, 1); 11366 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */ 11367 CHECK_ERROR; 11368 11369 SKIP_BLANKS; 11370 if (CUR != ')') { 11371 XP_ERROR(XPATH_EXPR_ERROR); 11372 } 11373 NEXT; 11374 rangeto = 1; 11375 goto eval_predicates; 11376 } 11377 } 11378#endif 11379 if (CUR == '*') { 11380 axis = AXIS_CHILD; 11381 } else { 11382 if (name == NULL) 11383 name = xmlXPathParseNCName(ctxt); 11384 if (name != NULL) { 11385 axis = xmlXPathIsAxisName(name); 11386 if (axis != 0) { 11387 SKIP_BLANKS; 11388 if ((CUR == ':') && (NXT(1) == ':')) { 11389 SKIP(2); 11390 xmlFree(name); 11391 name = NULL; 11392 } else { 11393 /* an element name can conflict with an axis one :-\ */ 11394 axis = AXIS_CHILD; 11395 } 11396 } else { 11397 axis = AXIS_CHILD; 11398 } 11399 } else if (CUR == '@') { 11400 NEXT; 11401 axis = AXIS_ATTRIBUTE; 11402 } else { 11403 axis = AXIS_CHILD; 11404 } 11405 } 11406 11407 if (ctxt->error != XPATH_EXPRESSION_OK) { 11408 xmlFree(name); 11409 return; 11410 } 11411 11412 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name); 11413 if (test == 0) 11414 return; 11415 11416 if ((prefix != NULL) && (ctxt->context != NULL) && 11417 (ctxt->context->flags & XML_XPATH_CHECKNS)) { 11418 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) { 11419 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR); 11420 } 11421 } 11422#ifdef DEBUG_STEP 11423 xmlGenericError(xmlGenericErrorContext, 11424 "Basis : computing new set\n"); 11425#endif 11426 11427#ifdef DEBUG_STEP 11428 xmlGenericError(xmlGenericErrorContext, "Basis : "); 11429 if (ctxt->value == NULL) 11430 xmlGenericError(xmlGenericErrorContext, "no value\n"); 11431 else if (ctxt->value->nodesetval == NULL) 11432 xmlGenericError(xmlGenericErrorContext, "Empty\n"); 11433 else 11434 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval); 11435#endif 11436 11437#ifdef LIBXML_XPTR_ENABLED 11438eval_predicates: 11439#endif 11440 op1 = ctxt->comp->last; 11441 ctxt->comp->last = -1; 11442 11443 SKIP_BLANKS; 11444 while (CUR == '[') { 11445 xmlXPathCompPredicate(ctxt, 0); 11446 } 11447 11448#ifdef LIBXML_XPTR_ENABLED 11449 if (rangeto) { 11450 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0); 11451 } else 11452#endif 11453 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis, 11454 test, type, (void *)prefix, (void *)name); 11455 11456 } 11457#ifdef DEBUG_STEP 11458 xmlGenericError(xmlGenericErrorContext, "Step : "); 11459 if (ctxt->value == NULL) 11460 xmlGenericError(xmlGenericErrorContext, "no value\n"); 11461 else if (ctxt->value->nodesetval == NULL) 11462 xmlGenericError(xmlGenericErrorContext, "Empty\n"); 11463 else 11464 xmlGenericErrorContextNodeSet(xmlGenericErrorContext, 11465 ctxt->value->nodesetval); 11466#endif 11467} 11468 11469/** 11470 * xmlXPathCompRelativeLocationPath: 11471 * @ctxt: the XPath Parser context 11472 * 11473 * [3] RelativeLocationPath ::= Step 11474 * | RelativeLocationPath '/' Step 11475 * | AbbreviatedRelativeLocationPath 11476 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step 11477 * 11478 * Compile a relative location path. 11479 */ 11480static void 11481xmlXPathCompRelativeLocationPath 11482(xmlXPathParserContextPtr ctxt) { 11483 SKIP_BLANKS; 11484 if ((CUR == '/') && (NXT(1) == '/')) { 11485 SKIP(2); 11486 SKIP_BLANKS; 11487 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 11488 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11489 } else if (CUR == '/') { 11490 NEXT; 11491 SKIP_BLANKS; 11492 } 11493 xmlXPathCompStep(ctxt); 11494 CHECK_ERROR; 11495 SKIP_BLANKS; 11496 while (CUR == '/') { 11497 if ((CUR == '/') && (NXT(1) == '/')) { 11498 SKIP(2); 11499 SKIP_BLANKS; 11500 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 11501 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11502 xmlXPathCompStep(ctxt); 11503 } else if (CUR == '/') { 11504 NEXT; 11505 SKIP_BLANKS; 11506 xmlXPathCompStep(ctxt); 11507 } 11508 SKIP_BLANKS; 11509 } 11510} 11511 11512/** 11513 * xmlXPathCompLocationPath: 11514 * @ctxt: the XPath Parser context 11515 * 11516 * [1] LocationPath ::= RelativeLocationPath 11517 * | AbsoluteLocationPath 11518 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath? 11519 * | AbbreviatedAbsoluteLocationPath 11520 * [10] AbbreviatedAbsoluteLocationPath ::= 11521 * '//' RelativeLocationPath 11522 * 11523 * Compile a location path 11524 * 11525 * // is short for /descendant-or-self::node()/. For example, 11526 * //para is short for /descendant-or-self::node()/child::para and 11527 * so will select any para element in the document (even a para element 11528 * that is a document element will be selected by //para since the 11529 * document element node is a child of the root node); div//para is 11530 * short for div/descendant-or-self::node()/child::para and so will 11531 * select all para descendants of div children. 11532 */ 11533static void 11534xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) { 11535 SKIP_BLANKS; 11536 if (CUR != '/') { 11537 xmlXPathCompRelativeLocationPath(ctxt); 11538 } else { 11539 while (CUR == '/') { 11540 if ((CUR == '/') && (NXT(1) == '/')) { 11541 SKIP(2); 11542 SKIP_BLANKS; 11543 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 11544 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11545 xmlXPathCompRelativeLocationPath(ctxt); 11546 } else if (CUR == '/') { 11547 NEXT; 11548 SKIP_BLANKS; 11549 if ((CUR != 0 ) && 11550 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') || 11551 (CUR == '@') || (CUR == '*'))) 11552 xmlXPathCompRelativeLocationPath(ctxt); 11553 } 11554 CHECK_ERROR; 11555 } 11556 } 11557} 11558 11559/************************************************************************ 11560 * * 11561 * XPath precompiled expression evaluation * 11562 * * 11563 ************************************************************************/ 11564 11565static int 11566xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op); 11567 11568#ifdef DEBUG_STEP 11569static void 11570xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op, 11571 int nbNodes) 11572{ 11573 xmlGenericError(xmlGenericErrorContext, "new step : "); 11574 switch (op->value) { 11575 case AXIS_ANCESTOR: 11576 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' "); 11577 break; 11578 case AXIS_ANCESTOR_OR_SELF: 11579 xmlGenericError(xmlGenericErrorContext, 11580 "axis 'ancestors-or-self' "); 11581 break; 11582 case AXIS_ATTRIBUTE: 11583 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' "); 11584 break; 11585 case AXIS_CHILD: 11586 xmlGenericError(xmlGenericErrorContext, "axis 'child' "); 11587 break; 11588 case AXIS_DESCENDANT: 11589 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' "); 11590 break; 11591 case AXIS_DESCENDANT_OR_SELF: 11592 xmlGenericError(xmlGenericErrorContext, 11593 "axis 'descendant-or-self' "); 11594 break; 11595 case AXIS_FOLLOWING: 11596 xmlGenericError(xmlGenericErrorContext, "axis 'following' "); 11597 break; 11598 case AXIS_FOLLOWING_SIBLING: 11599 xmlGenericError(xmlGenericErrorContext, 11600 "axis 'following-siblings' "); 11601 break; 11602 case AXIS_NAMESPACE: 11603 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' "); 11604 break; 11605 case AXIS_PARENT: 11606 xmlGenericError(xmlGenericErrorContext, "axis 'parent' "); 11607 break; 11608 case AXIS_PRECEDING: 11609 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' "); 11610 break; 11611 case AXIS_PRECEDING_SIBLING: 11612 xmlGenericError(xmlGenericErrorContext, 11613 "axis 'preceding-sibling' "); 11614 break; 11615 case AXIS_SELF: 11616 xmlGenericError(xmlGenericErrorContext, "axis 'self' "); 11617 break; 11618 } 11619 xmlGenericError(xmlGenericErrorContext, 11620 " context contains %d nodes\n", nbNodes); 11621 switch (op->value2) { 11622 case NODE_TEST_NONE: 11623 xmlGenericError(xmlGenericErrorContext, 11624 " searching for none !!!\n"); 11625 break; 11626 case NODE_TEST_TYPE: 11627 xmlGenericError(xmlGenericErrorContext, 11628 " searching for type %d\n", op->value3); 11629 break; 11630 case NODE_TEST_PI: 11631 xmlGenericError(xmlGenericErrorContext, 11632 " searching for PI !!!\n"); 11633 break; 11634 case NODE_TEST_ALL: 11635 xmlGenericError(xmlGenericErrorContext, 11636 " searching for *\n"); 11637 break; 11638 case NODE_TEST_NS: 11639 xmlGenericError(xmlGenericErrorContext, 11640 " searching for namespace %s\n", 11641 op->value5); 11642 break; 11643 case NODE_TEST_NAME: 11644 xmlGenericError(xmlGenericErrorContext, 11645 " searching for name %s\n", op->value5); 11646 if (op->value4) 11647 xmlGenericError(xmlGenericErrorContext, 11648 " with namespace %s\n", op->value4); 11649 break; 11650 } 11651 xmlGenericError(xmlGenericErrorContext, "Testing : "); 11652} 11653#endif /* DEBUG_STEP */ 11654 11655static int 11656xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt, 11657 xmlXPathStepOpPtr op, 11658 xmlNodeSetPtr set, 11659 int contextSize, 11660 int hasNsNodes) 11661{ 11662 if (op->ch1 != -1) { 11663 xmlXPathCompExprPtr comp = ctxt->comp; 11664 /* 11665 * Process inner predicates first. 11666 */ 11667 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) { 11668 /* 11669 * TODO: raise an internal error. 11670 */ 11671 } 11672 contextSize = xmlXPathCompOpEvalPredicate(ctxt, 11673 &comp->steps[op->ch1], set, contextSize, hasNsNodes); 11674 CHECK_ERROR0; 11675 if (contextSize <= 0) 11676 return(0); 11677 } 11678 if (op->ch2 != -1) { 11679 xmlXPathContextPtr xpctxt = ctxt->context; 11680 xmlNodePtr contextNode, oldContextNode; 11681 xmlDocPtr oldContextDoc; 11682 int i, res, contextPos = 0, newContextSize; 11683 xmlXPathStepOpPtr exprOp; 11684 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL; 11685 11686#ifdef LIBXML_XPTR_ENABLED 11687 /* 11688 * URGENT TODO: Check the following: 11689 * We don't expect location sets if evaluating prediates, right? 11690 * Only filters should expect location sets, right? 11691 */ 11692#endif 11693 /* 11694 * SPEC XPath 1.0: 11695 * "For each node in the node-set to be filtered, the 11696 * PredicateExpr is evaluated with that node as the 11697 * context node, with the number of nodes in the 11698 * node-set as the context size, and with the proximity 11699 * position of the node in the node-set with respect to 11700 * the axis as the context position;" 11701 * @oldset is the node-set" to be filtered. 11702 * 11703 * SPEC XPath 1.0: 11704 * "only predicates change the context position and 11705 * context size (see [2.4 Predicates])." 11706 * Example: 11707 * node-set context pos 11708 * nA 1 11709 * nB 2 11710 * nC 3 11711 * After applying predicate [position() > 1] : 11712 * node-set context pos 11713 * nB 1 11714 * nC 2 11715 */ 11716 oldContextNode = xpctxt->node; 11717 oldContextDoc = xpctxt->doc; 11718 /* 11719 * Get the expression of this predicate. 11720 */ 11721 exprOp = &ctxt->comp->steps[op->ch2]; 11722 newContextSize = 0; 11723 for (i = 0; i < set->nodeNr; i++) { 11724 if (set->nodeTab[i] == NULL) 11725 continue; 11726 11727 contextNode = set->nodeTab[i]; 11728 xpctxt->node = contextNode; 11729 xpctxt->contextSize = contextSize; 11730 xpctxt->proximityPosition = ++contextPos; 11731 11732 /* 11733 * Also set the xpath document in case things like 11734 * key() are evaluated in the predicate. 11735 */ 11736 if ((contextNode->type != XML_NAMESPACE_DECL) && 11737 (contextNode->doc != NULL)) 11738 xpctxt->doc = contextNode->doc; 11739 /* 11740 * Evaluate the predicate expression with 1 context node 11741 * at a time; this node is packaged into a node set; this 11742 * node set is handed over to the evaluation mechanism. 11743 */ 11744 if (contextObj == NULL) 11745 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode); 11746 else { 11747 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval, 11748 contextNode) < 0) { 11749 ctxt->error = XPATH_MEMORY_ERROR; 11750 goto evaluation_exit; 11751 } 11752 } 11753 11754 valuePush(ctxt, contextObj); 11755 11756 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1); 11757 11758 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) { 11759 xmlXPathNodeSetClear(set, hasNsNodes); 11760 newContextSize = 0; 11761 goto evaluation_exit; 11762 } 11763 11764 if (res != 0) { 11765 newContextSize++; 11766 } else { 11767 /* 11768 * Remove the entry from the initial node set. 11769 */ 11770 set->nodeTab[i] = NULL; 11771 if (contextNode->type == XML_NAMESPACE_DECL) 11772 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode); 11773 } 11774 if (ctxt->value == contextObj) { 11775 /* 11776 * Don't free the temporary XPath object holding the 11777 * context node, in order to avoid massive recreation 11778 * inside this loop. 11779 */ 11780 valuePop(ctxt); 11781 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes); 11782 } else { 11783 /* 11784 * TODO: The object was lost in the evaluation machinery. 11785 * Can this happen? Maybe in internal-error cases. 11786 */ 11787 contextObj = NULL; 11788 } 11789 } 11790 11791 if (contextObj != NULL) { 11792 if (ctxt->value == contextObj) 11793 valuePop(ctxt); 11794 xmlXPathReleaseObject(xpctxt, contextObj); 11795 } 11796evaluation_exit: 11797 if (exprRes != NULL) 11798 xmlXPathReleaseObject(ctxt->context, exprRes); 11799 /* 11800 * Reset/invalidate the context. 11801 */ 11802 xpctxt->node = oldContextNode; 11803 xpctxt->doc = oldContextDoc; 11804 xpctxt->contextSize = -1; 11805 xpctxt->proximityPosition = -1; 11806 return(newContextSize); 11807 } 11808 return(contextSize); 11809} 11810 11811static int 11812xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt, 11813 xmlXPathStepOpPtr op, 11814 xmlNodeSetPtr set, 11815 int contextSize, 11816 int minPos, 11817 int maxPos, 11818 int hasNsNodes) 11819{ 11820 if (op->ch1 != -1) { 11821 xmlXPathCompExprPtr comp = ctxt->comp; 11822 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) { 11823 /* 11824 * TODO: raise an internal error. 11825 */ 11826 } 11827 contextSize = xmlXPathCompOpEvalPredicate(ctxt, 11828 &comp->steps[op->ch1], set, contextSize, hasNsNodes); 11829 CHECK_ERROR0; 11830 if (contextSize <= 0) 11831 return(0); 11832 } 11833 /* 11834 * Check if the node set contains a sufficient number of nodes for 11835 * the requested range. 11836 */ 11837 if (contextSize < minPos) { 11838 xmlXPathNodeSetClear(set, hasNsNodes); 11839 return(0); 11840 } 11841 if (op->ch2 == -1) { 11842 /* 11843 * TODO: Can this ever happen? 11844 */ 11845 return (contextSize); 11846 } else { 11847 xmlDocPtr oldContextDoc; 11848 int i, pos = 0, newContextSize = 0, contextPos = 0, res; 11849 xmlXPathStepOpPtr exprOp; 11850 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL; 11851 xmlNodePtr oldContextNode, contextNode = NULL; 11852 xmlXPathContextPtr xpctxt = ctxt->context; 11853 int frame; 11854 11855#ifdef LIBXML_XPTR_ENABLED 11856 /* 11857 * URGENT TODO: Check the following: 11858 * We don't expect location sets if evaluating prediates, right? 11859 * Only filters should expect location sets, right? 11860 */ 11861#endif /* LIBXML_XPTR_ENABLED */ 11862 11863 /* 11864 * Save old context. 11865 */ 11866 oldContextNode = xpctxt->node; 11867 oldContextDoc = xpctxt->doc; 11868 /* 11869 * Get the expression of this predicate. 11870 */ 11871 exprOp = &ctxt->comp->steps[op->ch2]; 11872 for (i = 0; i < set->nodeNr; i++) { 11873 xmlXPathObjectPtr tmp; 11874 11875 if (set->nodeTab[i] == NULL) 11876 continue; 11877 11878 contextNode = set->nodeTab[i]; 11879 xpctxt->node = contextNode; 11880 xpctxt->contextSize = contextSize; 11881 xpctxt->proximityPosition = ++contextPos; 11882 11883 /* 11884 * Initialize the new set. 11885 * Also set the xpath document in case things like 11886 * key() evaluation are attempted on the predicate 11887 */ 11888 if ((contextNode->type != XML_NAMESPACE_DECL) && 11889 (contextNode->doc != NULL)) 11890 xpctxt->doc = contextNode->doc; 11891 /* 11892 * Evaluate the predicate expression with 1 context node 11893 * at a time; this node is packaged into a node set; this 11894 * node set is handed over to the evaluation mechanism. 11895 */ 11896 if (contextObj == NULL) 11897 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode); 11898 else { 11899 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval, 11900 contextNode) < 0) { 11901 ctxt->error = XPATH_MEMORY_ERROR; 11902 goto evaluation_exit; 11903 } 11904 } 11905 11906 frame = xmlXPathSetFrame(ctxt); 11907 valuePush(ctxt, contextObj); 11908 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1); 11909 tmp = valuePop(ctxt); 11910 xmlXPathPopFrame(ctxt, frame); 11911 11912 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) { 11913 while (tmp != contextObj) { 11914 /* 11915 * Free up the result 11916 * then pop off contextObj, which will be freed later 11917 */ 11918 xmlXPathReleaseObject(xpctxt, tmp); 11919 tmp = valuePop(ctxt); 11920 } 11921 goto evaluation_error; 11922 } 11923 /* push the result back onto the stack */ 11924 valuePush(ctxt, tmp); 11925 11926 if (res) 11927 pos++; 11928 11929 if (res && (pos >= minPos) && (pos <= maxPos)) { 11930 /* 11931 * Fits in the requested range. 11932 */ 11933 newContextSize++; 11934 if (minPos == maxPos) { 11935 /* 11936 * Only 1 node was requested. 11937 */ 11938 if (contextNode->type == XML_NAMESPACE_DECL) { 11939 /* 11940 * As always: take care of those nasty 11941 * namespace nodes. 11942 */ 11943 set->nodeTab[i] = NULL; 11944 } 11945 xmlXPathNodeSetClear(set, hasNsNodes); 11946 set->nodeNr = 1; 11947 set->nodeTab[0] = contextNode; 11948 goto evaluation_exit; 11949 } 11950 if (pos == maxPos) { 11951 /* 11952 * We are done. 11953 */ 11954 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes); 11955 goto evaluation_exit; 11956 } 11957 } else { 11958 /* 11959 * Remove the entry from the initial node set. 11960 */ 11961 set->nodeTab[i] = NULL; 11962 if (contextNode->type == XML_NAMESPACE_DECL) 11963 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode); 11964 } 11965 if (exprRes != NULL) { 11966 xmlXPathReleaseObject(ctxt->context, exprRes); 11967 exprRes = NULL; 11968 } 11969 if (ctxt->value == contextObj) { 11970 /* 11971 * Don't free the temporary XPath object holding the 11972 * context node, in order to avoid massive recreation 11973 * inside this loop. 11974 */ 11975 valuePop(ctxt); 11976 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes); 11977 } else { 11978 /* 11979 * The object was lost in the evaluation machinery. 11980 * Can this happen? Maybe in case of internal-errors. 11981 */ 11982 contextObj = NULL; 11983 } 11984 } 11985 goto evaluation_exit; 11986 11987evaluation_error: 11988 xmlXPathNodeSetClear(set, hasNsNodes); 11989 newContextSize = 0; 11990 11991evaluation_exit: 11992 if (contextObj != NULL) { 11993 if (ctxt->value == contextObj) 11994 valuePop(ctxt); 11995 xmlXPathReleaseObject(xpctxt, contextObj); 11996 } 11997 if (exprRes != NULL) 11998 xmlXPathReleaseObject(ctxt->context, exprRes); 11999 /* 12000 * Reset/invalidate the context. 12001 */ 12002 xpctxt->node = oldContextNode; 12003 xpctxt->doc = oldContextDoc; 12004 xpctxt->contextSize = -1; 12005 xpctxt->proximityPosition = -1; 12006 return(newContextSize); 12007 } 12008 return(contextSize); 12009} 12010 12011static int 12012xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt, 12013 xmlXPathStepOpPtr op, 12014 int *maxPos) 12015{ 12016 12017 xmlXPathStepOpPtr exprOp; 12018 12019 /* 12020 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet! 12021 */ 12022 12023 /* 12024 * If not -1, then ch1 will point to: 12025 * 1) For predicates (XPATH_OP_PREDICATE): 12026 * - an inner predicate operator 12027 * 2) For filters (XPATH_OP_FILTER): 12028 * - an inner filter operater OR 12029 * - an expression selecting the node set. 12030 * E.g. "key('a', 'b')" or "(//foo | //bar)". 12031 */ 12032 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER)) 12033 return(0); 12034 12035 if (op->ch2 != -1) { 12036 exprOp = &ctxt->comp->steps[op->ch2]; 12037 } else 12038 return(0); 12039 12040 if ((exprOp != NULL) && 12041 (exprOp->op == XPATH_OP_VALUE) && 12042 (exprOp->value4 != NULL) && 12043 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER)) 12044 { 12045 /* 12046 * We have a "[n]" predicate here. 12047 * TODO: Unfortunately this simplistic test here is not 12048 * able to detect a position() predicate in compound 12049 * expressions like "[@attr = 'a" and position() = 1], 12050 * and even not the usage of position() in 12051 * "[position() = 1]"; thus - obviously - a position-range, 12052 * like it "[position() < 5]", is also not detected. 12053 * Maybe we could rewrite the AST to ease the optimization. 12054 */ 12055 *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval; 12056 12057 if (((xmlXPathObjectPtr) exprOp->value4)->floatval == 12058 (float) *maxPos) 12059 { 12060 return(1); 12061 } 12062 } 12063 return(0); 12064} 12065 12066static int 12067xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, 12068 xmlXPathStepOpPtr op, 12069 xmlNodePtr * first, xmlNodePtr * last, 12070 int toBool) 12071{ 12072 12073#define XP_TEST_HIT \ 12074 if (hasAxisRange != 0) { \ 12075 if (++pos == maxPos) { \ 12076 if (addNode(seq, cur) < 0) \ 12077 ctxt->error = XPATH_MEMORY_ERROR; \ 12078 goto axis_range_end; } \ 12079 } else { \ 12080 if (addNode(seq, cur) < 0) \ 12081 ctxt->error = XPATH_MEMORY_ERROR; \ 12082 if (breakOnFirstHit) goto first_hit; } 12083 12084#define XP_TEST_HIT_NS \ 12085 if (hasAxisRange != 0) { \ 12086 if (++pos == maxPos) { \ 12087 hasNsNodes = 1; \ 12088 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \ 12089 ctxt->error = XPATH_MEMORY_ERROR; \ 12090 goto axis_range_end; } \ 12091 } else { \ 12092 hasNsNodes = 1; \ 12093 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \ 12094 ctxt->error = XPATH_MEMORY_ERROR; \ 12095 if (breakOnFirstHit) goto first_hit; } 12096 12097 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value; 12098 xmlXPathTestVal test = (xmlXPathTestVal) op->value2; 12099 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3; 12100 const xmlChar *prefix = op->value4; 12101 const xmlChar *name = op->value5; 12102 const xmlChar *URI = NULL; 12103 12104#ifdef DEBUG_STEP 12105 int nbMatches = 0, prevMatches = 0; 12106#endif 12107 int total = 0, hasNsNodes = 0; 12108 /* The popped object holding the context nodes */ 12109 xmlXPathObjectPtr obj; 12110 /* The set of context nodes for the node tests */ 12111 xmlNodeSetPtr contextSeq; 12112 int contextIdx; 12113 xmlNodePtr contextNode; 12114 /* The context node for a compound traversal */ 12115 xmlNodePtr outerContextNode; 12116 /* The final resulting node set wrt to all context nodes */ 12117 xmlNodeSetPtr outSeq; 12118 /* 12119 * The temporary resulting node set wrt 1 context node. 12120 * Used to feed predicate evaluation. 12121 */ 12122 xmlNodeSetPtr seq; 12123 xmlNodePtr cur; 12124 /* First predicate operator */ 12125 xmlXPathStepOpPtr predOp; 12126 int maxPos; /* The requested position() (when a "[n]" predicate) */ 12127 int hasPredicateRange, hasAxisRange, pos, size, newSize; 12128 int breakOnFirstHit; 12129 12130 xmlXPathTraversalFunction next = NULL; 12131 int (*addNode) (xmlNodeSetPtr, xmlNodePtr); 12132 xmlXPathNodeSetMergeFunction mergeAndClear; 12133 xmlNodePtr oldContextNode; 12134 xmlXPathContextPtr xpctxt = ctxt->context; 12135 12136 12137 CHECK_TYPE0(XPATH_NODESET); 12138 obj = valuePop(ctxt); 12139 /* 12140 * Setup namespaces. 12141 */ 12142 if (prefix != NULL) { 12143 URI = xmlXPathNsLookup(xpctxt, prefix); 12144 if (URI == NULL) { 12145 xmlXPathReleaseObject(xpctxt, obj); 12146 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); 12147 } 12148 } 12149 /* 12150 * Setup axis. 12151 * 12152 * MAYBE FUTURE TODO: merging optimizations: 12153 * - If the nodes to be traversed wrt to the initial nodes and 12154 * the current axis cannot overlap, then we could avoid searching 12155 * for duplicates during the merge. 12156 * But the question is how/when to evaluate if they cannot overlap. 12157 * Example: if we know that for two initial nodes, the one is 12158 * not in the ancestor-or-self axis of the other, then we could safely 12159 * avoid a duplicate-aware merge, if the axis to be traversed is e.g. 12160 * the descendant-or-self axis. 12161 */ 12162 mergeAndClear = xmlXPathNodeSetMergeAndClear; 12163 switch (axis) { 12164 case AXIS_ANCESTOR: 12165 first = NULL; 12166 next = xmlXPathNextAncestor; 12167 break; 12168 case AXIS_ANCESTOR_OR_SELF: 12169 first = NULL; 12170 next = xmlXPathNextAncestorOrSelf; 12171 break; 12172 case AXIS_ATTRIBUTE: 12173 first = NULL; 12174 last = NULL; 12175 next = xmlXPathNextAttribute; 12176 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12177 break; 12178 case AXIS_CHILD: 12179 last = NULL; 12180 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) && 12181 (type == NODE_TYPE_NODE)) 12182 { 12183 /* 12184 * Optimization if an element node type is 'element'. 12185 */ 12186 next = xmlXPathNextChildElement; 12187 } else 12188 next = xmlXPathNextChild; 12189 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12190 break; 12191 case AXIS_DESCENDANT: 12192 last = NULL; 12193 next = xmlXPathNextDescendant; 12194 break; 12195 case AXIS_DESCENDANT_OR_SELF: 12196 last = NULL; 12197 next = xmlXPathNextDescendantOrSelf; 12198 break; 12199 case AXIS_FOLLOWING: 12200 last = NULL; 12201 next = xmlXPathNextFollowing; 12202 break; 12203 case AXIS_FOLLOWING_SIBLING: 12204 last = NULL; 12205 next = xmlXPathNextFollowingSibling; 12206 break; 12207 case AXIS_NAMESPACE: 12208 first = NULL; 12209 last = NULL; 12210 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; 12211 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12212 break; 12213 case AXIS_PARENT: 12214 first = NULL; 12215 next = xmlXPathNextParent; 12216 break; 12217 case AXIS_PRECEDING: 12218 first = NULL; 12219 next = xmlXPathNextPrecedingInternal; 12220 break; 12221 case AXIS_PRECEDING_SIBLING: 12222 first = NULL; 12223 next = xmlXPathNextPrecedingSibling; 12224 break; 12225 case AXIS_SELF: 12226 first = NULL; 12227 last = NULL; 12228 next = xmlXPathNextSelf; 12229 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12230 break; 12231 } 12232 12233#ifdef DEBUG_STEP 12234 xmlXPathDebugDumpStepAxis(op, 12235 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0); 12236#endif 12237 12238 if (next == NULL) { 12239 xmlXPathReleaseObject(xpctxt, obj); 12240 return(0); 12241 } 12242 contextSeq = obj->nodesetval; 12243 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) { 12244 xmlXPathReleaseObject(xpctxt, obj); 12245 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL)); 12246 return(0); 12247 } 12248 /* 12249 * Predicate optimization --------------------------------------------- 12250 * If this step has a last predicate, which contains a position(), 12251 * then we'll optimize (although not exactly "position()", but only 12252 * the short-hand form, i.e., "[n]". 12253 * 12254 * Example - expression "/foo[parent::bar][1]": 12255 * 12256 * COLLECT 'child' 'name' 'node' foo -- op (we are here) 12257 * ROOT -- op->ch1 12258 * PREDICATE -- op->ch2 (predOp) 12259 * PREDICATE -- predOp->ch1 = [parent::bar] 12260 * SORT 12261 * COLLECT 'parent' 'name' 'node' bar 12262 * NODE 12263 * ELEM Object is a number : 1 -- predOp->ch2 = [1] 12264 * 12265 */ 12266 maxPos = 0; 12267 predOp = NULL; 12268 hasPredicateRange = 0; 12269 hasAxisRange = 0; 12270 if (op->ch2 != -1) { 12271 /* 12272 * There's at least one predicate. 16 == XPATH_OP_PREDICATE 12273 */ 12274 predOp = &ctxt->comp->steps[op->ch2]; 12275 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) { 12276 if (predOp->ch1 != -1) { 12277 /* 12278 * Use the next inner predicate operator. 12279 */ 12280 predOp = &ctxt->comp->steps[predOp->ch1]; 12281 hasPredicateRange = 1; 12282 } else { 12283 /* 12284 * There's no other predicate than the [n] predicate. 12285 */ 12286 predOp = NULL; 12287 hasAxisRange = 1; 12288 } 12289 } 12290 } 12291 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0; 12292 /* 12293 * Axis traversal ----------------------------------------------------- 12294 */ 12295 /* 12296 * 2.3 Node Tests 12297 * - For the attribute axis, the principal node type is attribute. 12298 * - For the namespace axis, the principal node type is namespace. 12299 * - For other axes, the principal node type is element. 12300 * 12301 * A node test * is true for any node of the 12302 * principal node type. For example, child::* will 12303 * select all element children of the context node 12304 */ 12305 oldContextNode = xpctxt->node; 12306 addNode = xmlXPathNodeSetAddUnique; 12307 outSeq = NULL; 12308 seq = NULL; 12309 outerContextNode = NULL; 12310 contextNode = NULL; 12311 contextIdx = 0; 12312 12313 12314 while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) && 12315 (ctxt->error == XPATH_EXPRESSION_OK)) { 12316 xpctxt->node = contextSeq->nodeTab[contextIdx++]; 12317 12318 if (seq == NULL) { 12319 seq = xmlXPathNodeSetCreate(NULL); 12320 if (seq == NULL) { 12321 total = 0; 12322 goto error; 12323 } 12324 } 12325 /* 12326 * Traverse the axis and test the nodes. 12327 */ 12328 pos = 0; 12329 cur = NULL; 12330 hasNsNodes = 0; 12331 do { 12332 cur = next(ctxt, cur); 12333 if (cur == NULL) 12334 break; 12335 12336 /* 12337 * QUESTION TODO: What does the "first" and "last" stuff do? 12338 */ 12339 if ((first != NULL) && (*first != NULL)) { 12340 if (*first == cur) 12341 break; 12342 if (((total % 256) == 0) && 12343#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 12344 (xmlXPathCmpNodesExt(*first, cur) >= 0)) 12345#else 12346 (xmlXPathCmpNodes(*first, cur) >= 0)) 12347#endif 12348 { 12349 break; 12350 } 12351 } 12352 if ((last != NULL) && (*last != NULL)) { 12353 if (*last == cur) 12354 break; 12355 if (((total % 256) == 0) && 12356#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 12357 (xmlXPathCmpNodesExt(cur, *last) >= 0)) 12358#else 12359 (xmlXPathCmpNodes(cur, *last) >= 0)) 12360#endif 12361 { 12362 break; 12363 } 12364 } 12365 12366 total++; 12367 12368#ifdef DEBUG_STEP 12369 xmlGenericError(xmlGenericErrorContext, " %s", cur->name); 12370#endif 12371 12372 switch (test) { 12373 case NODE_TEST_NONE: 12374 total = 0; 12375 STRANGE 12376 goto error; 12377 case NODE_TEST_TYPE: 12378 /* 12379 * TODO: Don't we need to use 12380 * xmlXPathNodeSetAddNs() for namespace nodes here? 12381 * Surprisingly, some c14n tests fail, if we do this. 12382 */ 12383 if (type == NODE_TYPE_NODE) { 12384 switch (cur->type) { 12385 case XML_DOCUMENT_NODE: 12386 case XML_HTML_DOCUMENT_NODE: 12387#ifdef LIBXML_DOCB_ENABLED 12388 case XML_DOCB_DOCUMENT_NODE: 12389#endif 12390 case XML_ELEMENT_NODE: 12391 case XML_ATTRIBUTE_NODE: 12392 case XML_PI_NODE: 12393 case XML_COMMENT_NODE: 12394 case XML_CDATA_SECTION_NODE: 12395 case XML_TEXT_NODE: 12396 case XML_NAMESPACE_DECL: 12397 XP_TEST_HIT 12398 break; 12399 default: 12400 break; 12401 } 12402 } else if (cur->type == type) { 12403 if (type == XML_NAMESPACE_DECL) 12404 XP_TEST_HIT_NS 12405 else 12406 XP_TEST_HIT 12407 } else if ((type == NODE_TYPE_TEXT) && 12408 (cur->type == XML_CDATA_SECTION_NODE)) 12409 { 12410 XP_TEST_HIT 12411 } 12412 break; 12413 case NODE_TEST_PI: 12414 if ((cur->type == XML_PI_NODE) && 12415 ((name == NULL) || xmlStrEqual(name, cur->name))) 12416 { 12417 XP_TEST_HIT 12418 } 12419 break; 12420 case NODE_TEST_ALL: 12421 if (axis == AXIS_ATTRIBUTE) { 12422 if (cur->type == XML_ATTRIBUTE_NODE) 12423 { 12424 XP_TEST_HIT 12425 } 12426 } else if (axis == AXIS_NAMESPACE) { 12427 if (cur->type == XML_NAMESPACE_DECL) 12428 { 12429 XP_TEST_HIT_NS 12430 } 12431 } else { 12432 if (cur->type == XML_ELEMENT_NODE) { 12433 if (prefix == NULL) 12434 { 12435 XP_TEST_HIT 12436 12437 } else if ((cur->ns != NULL) && 12438 (xmlStrEqual(URI, cur->ns->href))) 12439 { 12440 XP_TEST_HIT 12441 } 12442 } 12443 } 12444 break; 12445 case NODE_TEST_NS:{ 12446 TODO; 12447 break; 12448 } 12449 case NODE_TEST_NAME: 12450 if (axis == AXIS_ATTRIBUTE) { 12451 if (cur->type != XML_ATTRIBUTE_NODE) 12452 break; 12453 } else if (axis == AXIS_NAMESPACE) { 12454 if (cur->type != XML_NAMESPACE_DECL) 12455 break; 12456 } else { 12457 if (cur->type != XML_ELEMENT_NODE) 12458 break; 12459 } 12460 switch (cur->type) { 12461 case XML_ELEMENT_NODE: 12462 if (xmlStrEqual(name, cur->name)) { 12463 if (prefix == NULL) { 12464 if (cur->ns == NULL) 12465 { 12466 XP_TEST_HIT 12467 } 12468 } else { 12469 if ((cur->ns != NULL) && 12470 (xmlStrEqual(URI, cur->ns->href))) 12471 { 12472 XP_TEST_HIT 12473 } 12474 } 12475 } 12476 break; 12477 case XML_ATTRIBUTE_NODE:{ 12478 xmlAttrPtr attr = (xmlAttrPtr) cur; 12479 12480 if (xmlStrEqual(name, attr->name)) { 12481 if (prefix == NULL) { 12482 if ((attr->ns == NULL) || 12483 (attr->ns->prefix == NULL)) 12484 { 12485 XP_TEST_HIT 12486 } 12487 } else { 12488 if ((attr->ns != NULL) && 12489 (xmlStrEqual(URI, 12490 attr->ns->href))) 12491 { 12492 XP_TEST_HIT 12493 } 12494 } 12495 } 12496 break; 12497 } 12498 case XML_NAMESPACE_DECL: 12499 if (cur->type == XML_NAMESPACE_DECL) { 12500 xmlNsPtr ns = (xmlNsPtr) cur; 12501 12502 if ((ns->prefix != NULL) && (name != NULL) 12503 && (xmlStrEqual(ns->prefix, name))) 12504 { 12505 XP_TEST_HIT_NS 12506 } 12507 } 12508 break; 12509 default: 12510 break; 12511 } 12512 break; 12513 } /* switch(test) */ 12514 } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK)); 12515 12516 goto apply_predicates; 12517 12518axis_range_end: /* ----------------------------------------------------- */ 12519 /* 12520 * We have a "/foo[n]", and position() = n was reached. 12521 * Note that we can have as well "/foo/::parent::foo[1]", so 12522 * a duplicate-aware merge is still needed. 12523 * Merge with the result. 12524 */ 12525 if (outSeq == NULL) { 12526 outSeq = seq; 12527 seq = NULL; 12528 } else 12529 outSeq = mergeAndClear(outSeq, seq, 0); 12530 /* 12531 * Break if only a true/false result was requested. 12532 */ 12533 if (toBool) 12534 break; 12535 continue; 12536 12537first_hit: /* ---------------------------------------------------------- */ 12538 /* 12539 * Break if only a true/false result was requested and 12540 * no predicates existed and a node test succeeded. 12541 */ 12542 if (outSeq == NULL) { 12543 outSeq = seq; 12544 seq = NULL; 12545 } else 12546 outSeq = mergeAndClear(outSeq, seq, 0); 12547 break; 12548 12549#ifdef DEBUG_STEP 12550 if (seq != NULL) 12551 nbMatches += seq->nodeNr; 12552#endif 12553 12554apply_predicates: /* --------------------------------------------------- */ 12555 if (ctxt->error != XPATH_EXPRESSION_OK) 12556 goto error; 12557 12558 /* 12559 * Apply predicates. 12560 */ 12561 if ((predOp != NULL) && (seq->nodeNr > 0)) { 12562 /* 12563 * E.g. when we have a "/foo[some expression][n]". 12564 */ 12565 /* 12566 * QUESTION TODO: The old predicate evaluation took into 12567 * account location-sets. 12568 * (E.g. ctxt->value->type == XPATH_LOCATIONSET) 12569 * Do we expect such a set here? 12570 * All what I learned now from the evaluation semantics 12571 * does not indicate that a location-set will be processed 12572 * here, so this looks OK. 12573 */ 12574 /* 12575 * Iterate over all predicates, starting with the outermost 12576 * predicate. 12577 * TODO: Problem: we cannot execute the inner predicates first 12578 * since we cannot go back *up* the operator tree! 12579 * Options we have: 12580 * 1) Use of recursive functions (like is it currently done 12581 * via xmlXPathCompOpEval()) 12582 * 2) Add a predicate evaluation information stack to the 12583 * context struct 12584 * 3) Change the way the operators are linked; we need a 12585 * "parent" field on xmlXPathStepOp 12586 * 12587 * For the moment, I'll try to solve this with a recursive 12588 * function: xmlXPathCompOpEvalPredicate(). 12589 */ 12590 size = seq->nodeNr; 12591 if (hasPredicateRange != 0) 12592 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt, 12593 predOp, seq, size, maxPos, maxPos, hasNsNodes); 12594 else 12595 newSize = xmlXPathCompOpEvalPredicate(ctxt, 12596 predOp, seq, size, hasNsNodes); 12597 12598 if (ctxt->error != XPATH_EXPRESSION_OK) { 12599 total = 0; 12600 goto error; 12601 } 12602 /* 12603 * Add the filtered set of nodes to the result node set. 12604 */ 12605 if (newSize == 0) { 12606 /* 12607 * The predicates filtered all nodes out. 12608 */ 12609 xmlXPathNodeSetClear(seq, hasNsNodes); 12610 } else if (seq->nodeNr > 0) { 12611 /* 12612 * Add to result set. 12613 */ 12614 if (outSeq == NULL) { 12615 if (size != newSize) { 12616 /* 12617 * We need to merge and clear here, since 12618 * the sequence will contained NULLed entries. 12619 */ 12620 outSeq = mergeAndClear(NULL, seq, 1); 12621 } else { 12622 outSeq = seq; 12623 seq = NULL; 12624 } 12625 } else 12626 outSeq = mergeAndClear(outSeq, seq, 12627 (size != newSize) ? 1: 0); 12628 /* 12629 * Break if only a true/false result was requested. 12630 */ 12631 if (toBool) 12632 break; 12633 } 12634 } else if (seq->nodeNr > 0) { 12635 /* 12636 * Add to result set. 12637 */ 12638 if (outSeq == NULL) { 12639 outSeq = seq; 12640 seq = NULL; 12641 } else { 12642 outSeq = mergeAndClear(outSeq, seq, 0); 12643 } 12644 } 12645 } 12646 12647error: 12648 if ((obj->boolval) && (obj->user != NULL)) { 12649 /* 12650 * QUESTION TODO: What does this do and why? 12651 * TODO: Do we have to do this also for the "error" 12652 * cleanup further down? 12653 */ 12654 ctxt->value->boolval = 1; 12655 ctxt->value->user = obj->user; 12656 obj->user = NULL; 12657 obj->boolval = 0; 12658 } 12659 xmlXPathReleaseObject(xpctxt, obj); 12660 12661 /* 12662 * Ensure we return at least an emtpy set. 12663 */ 12664 if (outSeq == NULL) { 12665 if ((seq != NULL) && (seq->nodeNr == 0)) 12666 outSeq = seq; 12667 else 12668 outSeq = xmlXPathNodeSetCreate(NULL); 12669 /* XXX what if xmlXPathNodeSetCreate returned NULL here? */ 12670 } 12671 if ((seq != NULL) && (seq != outSeq)) { 12672 xmlXPathFreeNodeSet(seq); 12673 } 12674 /* 12675 * Hand over the result. Better to push the set also in 12676 * case of errors. 12677 */ 12678 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq)); 12679 /* 12680 * Reset the context node. 12681 */ 12682 xpctxt->node = oldContextNode; 12683 12684#ifdef DEBUG_STEP 12685 xmlGenericError(xmlGenericErrorContext, 12686 "\nExamined %d nodes, found %d nodes at that step\n", 12687 total, nbMatches); 12688#endif 12689 12690 return(total); 12691} 12692 12693static int 12694xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt, 12695 xmlXPathStepOpPtr op, xmlNodePtr * first); 12696 12697/** 12698 * xmlXPathCompOpEvalFirst: 12699 * @ctxt: the XPath parser context with the compiled expression 12700 * @op: an XPath compiled operation 12701 * @first: the first elem found so far 12702 * 12703 * Evaluate the Precompiled XPath operation searching only the first 12704 * element in document order 12705 * 12706 * Returns the number of examined objects. 12707 */ 12708static int 12709xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt, 12710 xmlXPathStepOpPtr op, xmlNodePtr * first) 12711{ 12712 int total = 0, cur; 12713 xmlXPathCompExprPtr comp; 12714 xmlXPathObjectPtr arg1, arg2; 12715 12716 CHECK_ERROR0; 12717 comp = ctxt->comp; 12718 switch (op->op) { 12719 case XPATH_OP_END: 12720 return (0); 12721 case XPATH_OP_UNION: 12722 total = 12723 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1], 12724 first); 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 /* 12734 * OPTIMIZE TODO: This implicitely sorts 12735 * the result, even if not needed. E.g. if the argument 12736 * of the count() function, no sorting is needed. 12737 * OPTIMIZE TODO: How do we know if the node-list wasn't 12738 * aready sorted? 12739 */ 12740 if (ctxt->value->nodesetval->nodeNr > 1) 12741 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12742 *first = ctxt->value->nodesetval->nodeTab[0]; 12743 } 12744 cur = 12745 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2], 12746 first); 12747 CHECK_ERROR0; 12748 CHECK_TYPE0(XPATH_NODESET); 12749 arg2 = valuePop(ctxt); 12750 12751 CHECK_TYPE0(XPATH_NODESET); 12752 arg1 = valuePop(ctxt); 12753 12754 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 12755 arg2->nodesetval); 12756 valuePush(ctxt, arg1); 12757 xmlXPathReleaseObject(ctxt->context, arg2); 12758 /* optimizer */ 12759 if (total > cur) 12760 xmlXPathCompSwap(op); 12761 return (total + cur); 12762 case XPATH_OP_ROOT: 12763 xmlXPathRoot(ctxt); 12764 return (0); 12765 case XPATH_OP_NODE: 12766 if (op->ch1 != -1) 12767 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12768 CHECK_ERROR0; 12769 if (op->ch2 != -1) 12770 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12771 CHECK_ERROR0; 12772 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 12773 ctxt->context->node)); 12774 return (total); 12775 case XPATH_OP_RESET: 12776 if (op->ch1 != -1) 12777 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12778 CHECK_ERROR0; 12779 if (op->ch2 != -1) 12780 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12781 CHECK_ERROR0; 12782 ctxt->context->node = NULL; 12783 return (total); 12784 case XPATH_OP_COLLECT:{ 12785 if (op->ch1 == -1) 12786 return (total); 12787 12788 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12789 CHECK_ERROR0; 12790 12791 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0); 12792 return (total); 12793 } 12794 case XPATH_OP_VALUE: 12795 valuePush(ctxt, 12796 xmlXPathCacheObjectCopy(ctxt->context, 12797 (xmlXPathObjectPtr) op->value4)); 12798 return (0); 12799 case XPATH_OP_SORT: 12800 if (op->ch1 != -1) 12801 total += 12802 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1], 12803 first); 12804 CHECK_ERROR0; 12805 if ((ctxt->value != NULL) 12806 && (ctxt->value->type == XPATH_NODESET) 12807 && (ctxt->value->nodesetval != NULL) 12808 && (ctxt->value->nodesetval->nodeNr > 1)) 12809 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12810 return (total); 12811#ifdef XP_OPTIMIZED_FILTER_FIRST 12812 case XPATH_OP_FILTER: 12813 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first); 12814 return (total); 12815#endif 12816 default: 12817 return (xmlXPathCompOpEval(ctxt, op)); 12818 } 12819} 12820 12821/** 12822 * xmlXPathCompOpEvalLast: 12823 * @ctxt: the XPath parser context with the compiled expression 12824 * @op: an XPath compiled operation 12825 * @last: the last elem found so far 12826 * 12827 * Evaluate the Precompiled XPath operation searching only the last 12828 * element in document order 12829 * 12830 * Returns the number of nodes traversed 12831 */ 12832static int 12833xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op, 12834 xmlNodePtr * last) 12835{ 12836 int total = 0, cur; 12837 xmlXPathCompExprPtr comp; 12838 xmlXPathObjectPtr arg1, arg2; 12839 xmlNodePtr bak; 12840 xmlDocPtr bakd; 12841 int pp; 12842 int cs; 12843 12844 CHECK_ERROR0; 12845 comp = ctxt->comp; 12846 switch (op->op) { 12847 case XPATH_OP_END: 12848 return (0); 12849 case XPATH_OP_UNION: 12850 bakd = ctxt->context->doc; 12851 bak = ctxt->context->node; 12852 pp = ctxt->context->proximityPosition; 12853 cs = ctxt->context->contextSize; 12854 total = 12855 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last); 12856 CHECK_ERROR0; 12857 if ((ctxt->value != NULL) 12858 && (ctxt->value->type == XPATH_NODESET) 12859 && (ctxt->value->nodesetval != NULL) 12860 && (ctxt->value->nodesetval->nodeNr >= 1)) { 12861 /* 12862 * limit tree traversing to first node in the result 12863 */ 12864 if (ctxt->value->nodesetval->nodeNr > 1) 12865 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12866 *last = 12867 ctxt->value->nodesetval->nodeTab[ctxt->value-> 12868 nodesetval->nodeNr - 12869 1]; 12870 } 12871 ctxt->context->doc = bakd; 12872 ctxt->context->node = bak; 12873 ctxt->context->proximityPosition = pp; 12874 ctxt->context->contextSize = cs; 12875 cur = 12876 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last); 12877 CHECK_ERROR0; 12878 if ((ctxt->value != NULL) 12879 && (ctxt->value->type == XPATH_NODESET) 12880 && (ctxt->value->nodesetval != NULL) 12881 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */ 12882 } 12883 CHECK_TYPE0(XPATH_NODESET); 12884 arg2 = valuePop(ctxt); 12885 12886 CHECK_TYPE0(XPATH_NODESET); 12887 arg1 = valuePop(ctxt); 12888 12889 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 12890 arg2->nodesetval); 12891 valuePush(ctxt, arg1); 12892 xmlXPathReleaseObject(ctxt->context, arg2); 12893 /* optimizer */ 12894 if (total > cur) 12895 xmlXPathCompSwap(op); 12896 return (total + cur); 12897 case XPATH_OP_ROOT: 12898 xmlXPathRoot(ctxt); 12899 return (0); 12900 case XPATH_OP_NODE: 12901 if (op->ch1 != -1) 12902 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12903 CHECK_ERROR0; 12904 if (op->ch2 != -1) 12905 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12906 CHECK_ERROR0; 12907 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 12908 ctxt->context->node)); 12909 return (total); 12910 case XPATH_OP_RESET: 12911 if (op->ch1 != -1) 12912 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12913 CHECK_ERROR0; 12914 if (op->ch2 != -1) 12915 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12916 CHECK_ERROR0; 12917 ctxt->context->node = NULL; 12918 return (total); 12919 case XPATH_OP_COLLECT:{ 12920 if (op->ch1 == -1) 12921 return (0); 12922 12923 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12924 CHECK_ERROR0; 12925 12926 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0); 12927 return (total); 12928 } 12929 case XPATH_OP_VALUE: 12930 valuePush(ctxt, 12931 xmlXPathCacheObjectCopy(ctxt->context, 12932 (xmlXPathObjectPtr) op->value4)); 12933 return (0); 12934 case XPATH_OP_SORT: 12935 if (op->ch1 != -1) 12936 total += 12937 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], 12938 last); 12939 CHECK_ERROR0; 12940 if ((ctxt->value != NULL) 12941 && (ctxt->value->type == XPATH_NODESET) 12942 && (ctxt->value->nodesetval != NULL) 12943 && (ctxt->value->nodesetval->nodeNr > 1)) 12944 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12945 return (total); 12946 default: 12947 return (xmlXPathCompOpEval(ctxt, op)); 12948 } 12949} 12950 12951#ifdef XP_OPTIMIZED_FILTER_FIRST 12952static int 12953xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt, 12954 xmlXPathStepOpPtr op, xmlNodePtr * first) 12955{ 12956 int total = 0; 12957 xmlXPathCompExprPtr comp; 12958 xmlXPathObjectPtr res; 12959 xmlXPathObjectPtr obj; 12960 xmlNodeSetPtr oldset; 12961 xmlNodePtr oldnode; 12962 xmlDocPtr oldDoc; 12963 int i; 12964 12965 CHECK_ERROR0; 12966 comp = ctxt->comp; 12967 /* 12968 * Optimization for ()[last()] selection i.e. the last elem 12969 */ 12970 if ((op->ch1 != -1) && (op->ch2 != -1) && 12971 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 12972 (comp->steps[op->ch2].op == XPATH_OP_SORT)) { 12973 int f = comp->steps[op->ch2].ch1; 12974 12975 if ((f != -1) && 12976 (comp->steps[f].op == XPATH_OP_FUNCTION) && 12977 (comp->steps[f].value5 == NULL) && 12978 (comp->steps[f].value == 0) && 12979 (comp->steps[f].value4 != NULL) && 12980 (xmlStrEqual 12981 (comp->steps[f].value4, BAD_CAST "last"))) { 12982 xmlNodePtr last = NULL; 12983 12984 total += 12985 xmlXPathCompOpEvalLast(ctxt, 12986 &comp->steps[op->ch1], 12987 &last); 12988 CHECK_ERROR0; 12989 /* 12990 * The nodeset should be in document order, 12991 * Keep only the last value 12992 */ 12993 if ((ctxt->value != NULL) && 12994 (ctxt->value->type == XPATH_NODESET) && 12995 (ctxt->value->nodesetval != NULL) && 12996 (ctxt->value->nodesetval->nodeTab != NULL) && 12997 (ctxt->value->nodesetval->nodeNr > 1)) { 12998 ctxt->value->nodesetval->nodeTab[0] = 12999 ctxt->value->nodesetval->nodeTab[ctxt-> 13000 value-> 13001 nodesetval-> 13002 nodeNr - 13003 1]; 13004 ctxt->value->nodesetval->nodeNr = 1; 13005 *first = *(ctxt->value->nodesetval->nodeTab); 13006 } 13007 return (total); 13008 } 13009 } 13010 13011 if (op->ch1 != -1) 13012 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13013 CHECK_ERROR0; 13014 if (op->ch2 == -1) 13015 return (total); 13016 if (ctxt->value == NULL) 13017 return (total); 13018 13019#ifdef LIBXML_XPTR_ENABLED 13020 oldnode = ctxt->context->node; 13021 /* 13022 * Hum are we filtering the result of an XPointer expression 13023 */ 13024 if (ctxt->value->type == XPATH_LOCATIONSET) { 13025 xmlXPathObjectPtr tmp = NULL; 13026 xmlLocationSetPtr newlocset = NULL; 13027 xmlLocationSetPtr oldlocset; 13028 13029 /* 13030 * Extract the old locset, and then evaluate the result of the 13031 * expression for all the element in the locset. use it to grow 13032 * up a new locset. 13033 */ 13034 CHECK_TYPE0(XPATH_LOCATIONSET); 13035 obj = valuePop(ctxt); 13036 oldlocset = obj->user; 13037 ctxt->context->node = NULL; 13038 13039 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) { 13040 ctxt->context->contextSize = 0; 13041 ctxt->context->proximityPosition = 0; 13042 if (op->ch2 != -1) 13043 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13044 res = valuePop(ctxt); 13045 if (res != NULL) { 13046 xmlXPathReleaseObject(ctxt->context, res); 13047 } 13048 valuePush(ctxt, obj); 13049 CHECK_ERROR0; 13050 return (total); 13051 } 13052 newlocset = xmlXPtrLocationSetCreate(NULL); 13053 13054 for (i = 0; i < oldlocset->locNr; i++) { 13055 /* 13056 * Run the evaluation with a node list made of a 13057 * single item in the nodelocset. 13058 */ 13059 ctxt->context->node = oldlocset->locTab[i]->user; 13060 ctxt->context->contextSize = oldlocset->locNr; 13061 ctxt->context->proximityPosition = i + 1; 13062 if (tmp == NULL) { 13063 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13064 ctxt->context->node); 13065 } else { 13066 if (xmlXPathNodeSetAddUnique(tmp->nodesetval, 13067 ctxt->context->node) < 0) { 13068 ctxt->error = XPATH_MEMORY_ERROR; 13069 } 13070 } 13071 valuePush(ctxt, tmp); 13072 if (op->ch2 != -1) 13073 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13074 if (ctxt->error != XPATH_EXPRESSION_OK) { 13075 xmlXPathFreeObject(obj); 13076 return(0); 13077 } 13078 /* 13079 * The result of the evaluation need to be tested to 13080 * decided whether the filter succeeded or not 13081 */ 13082 res = valuePop(ctxt); 13083 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 13084 xmlXPtrLocationSetAdd(newlocset, 13085 xmlXPathCacheObjectCopy(ctxt->context, 13086 oldlocset->locTab[i])); 13087 } 13088 /* 13089 * Cleanup 13090 */ 13091 if (res != NULL) { 13092 xmlXPathReleaseObject(ctxt->context, res); 13093 } 13094 if (ctxt->value == tmp) { 13095 valuePop(ctxt); 13096 xmlXPathNodeSetClear(tmp->nodesetval, 1); 13097 /* 13098 * REVISIT TODO: Don't create a temporary nodeset 13099 * for everly iteration. 13100 */ 13101 /* OLD: xmlXPathFreeObject(res); */ 13102 } else 13103 tmp = NULL; 13104 ctxt->context->node = NULL; 13105 /* 13106 * Only put the first node in the result, then leave. 13107 */ 13108 if (newlocset->locNr > 0) { 13109 *first = (xmlNodePtr) oldlocset->locTab[i]->user; 13110 break; 13111 } 13112 } 13113 if (tmp != NULL) { 13114 xmlXPathReleaseObject(ctxt->context, tmp); 13115 } 13116 /* 13117 * The result is used as the new evaluation locset. 13118 */ 13119 xmlXPathReleaseObject(ctxt->context, obj); 13120 ctxt->context->node = NULL; 13121 ctxt->context->contextSize = -1; 13122 ctxt->context->proximityPosition = -1; 13123 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset)); 13124 ctxt->context->node = oldnode; 13125 return (total); 13126 } 13127#endif /* LIBXML_XPTR_ENABLED */ 13128 13129 /* 13130 * Extract the old set, and then evaluate the result of the 13131 * expression for all the element in the set. use it to grow 13132 * up a new set. 13133 */ 13134 CHECK_TYPE0(XPATH_NODESET); 13135 obj = valuePop(ctxt); 13136 oldset = obj->nodesetval; 13137 13138 oldnode = ctxt->context->node; 13139 oldDoc = ctxt->context->doc; 13140 ctxt->context->node = NULL; 13141 13142 if ((oldset == NULL) || (oldset->nodeNr == 0)) { 13143 ctxt->context->contextSize = 0; 13144 ctxt->context->proximityPosition = 0; 13145 /* QUESTION TODO: Why was this code commented out? 13146 if (op->ch2 != -1) 13147 total += 13148 xmlXPathCompOpEval(ctxt, 13149 &comp->steps[op->ch2]); 13150 CHECK_ERROR0; 13151 res = valuePop(ctxt); 13152 if (res != NULL) 13153 xmlXPathFreeObject(res); 13154 */ 13155 valuePush(ctxt, obj); 13156 ctxt->context->node = oldnode; 13157 CHECK_ERROR0; 13158 } else { 13159 xmlNodeSetPtr newset; 13160 xmlXPathObjectPtr tmp = NULL; 13161 /* 13162 * Initialize the new set. 13163 * Also set the xpath document in case things like 13164 * key() evaluation are attempted on the predicate 13165 */ 13166 newset = xmlXPathNodeSetCreate(NULL); 13167 /* XXX what if xmlXPathNodeSetCreate returned NULL? */ 13168 13169 for (i = 0; i < oldset->nodeNr; i++) { 13170 /* 13171 * Run the evaluation with a node list made of 13172 * a single item in the nodeset. 13173 */ 13174 ctxt->context->node = oldset->nodeTab[i]; 13175 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) && 13176 (oldset->nodeTab[i]->doc != NULL)) 13177 ctxt->context->doc = oldset->nodeTab[i]->doc; 13178 if (tmp == NULL) { 13179 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13180 ctxt->context->node); 13181 } else { 13182 if (xmlXPathNodeSetAddUnique(tmp->nodesetval, 13183 ctxt->context->node) < 0) { 13184 ctxt->error = XPATH_MEMORY_ERROR; 13185 } 13186 } 13187 valuePush(ctxt, tmp); 13188 ctxt->context->contextSize = oldset->nodeNr; 13189 ctxt->context->proximityPosition = i + 1; 13190 if (op->ch2 != -1) 13191 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13192 if (ctxt->error != XPATH_EXPRESSION_OK) { 13193 xmlXPathFreeNodeSet(newset); 13194 xmlXPathFreeObject(obj); 13195 return(0); 13196 } 13197 /* 13198 * The result of the evaluation needs to be tested to 13199 * decide whether the filter succeeded or not 13200 */ 13201 res = valuePop(ctxt); 13202 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 13203 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0) 13204 ctxt->error = XPATH_MEMORY_ERROR; 13205 } 13206 /* 13207 * Cleanup 13208 */ 13209 if (res != NULL) { 13210 xmlXPathReleaseObject(ctxt->context, res); 13211 } 13212 if (ctxt->value == tmp) { 13213 valuePop(ctxt); 13214 /* 13215 * Don't free the temporary nodeset 13216 * in order to avoid massive recreation inside this 13217 * loop. 13218 */ 13219 xmlXPathNodeSetClear(tmp->nodesetval, 1); 13220 } else 13221 tmp = NULL; 13222 ctxt->context->node = NULL; 13223 /* 13224 * Only put the first node in the result, then leave. 13225 */ 13226 if (newset->nodeNr > 0) { 13227 *first = *(newset->nodeTab); 13228 break; 13229 } 13230 } 13231 if (tmp != NULL) { 13232 xmlXPathReleaseObject(ctxt->context, tmp); 13233 } 13234 /* 13235 * The result is used as the new evaluation set. 13236 */ 13237 xmlXPathReleaseObject(ctxt->context, obj); 13238 ctxt->context->node = NULL; 13239 ctxt->context->contextSize = -1; 13240 ctxt->context->proximityPosition = -1; 13241 /* may want to move this past the '}' later */ 13242 ctxt->context->doc = oldDoc; 13243 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset)); 13244 } 13245 ctxt->context->node = oldnode; 13246 return(total); 13247} 13248#endif /* XP_OPTIMIZED_FILTER_FIRST */ 13249 13250/** 13251 * xmlXPathCompOpEval: 13252 * @ctxt: the XPath parser context with the compiled expression 13253 * @op: an XPath compiled operation 13254 * 13255 * Evaluate the Precompiled XPath operation 13256 * Returns the number of nodes traversed 13257 */ 13258static int 13259xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) 13260{ 13261 int total = 0; 13262 int equal, ret; 13263 xmlXPathCompExprPtr comp; 13264 xmlXPathObjectPtr arg1, arg2; 13265 xmlNodePtr bak; 13266 xmlDocPtr bakd; 13267 int pp; 13268 int cs; 13269 13270 CHECK_ERROR0; 13271 comp = ctxt->comp; 13272 switch (op->op) { 13273 case XPATH_OP_END: 13274 return (0); 13275 case XPATH_OP_AND: 13276 bakd = ctxt->context->doc; 13277 bak = ctxt->context->node; 13278 pp = ctxt->context->proximityPosition; 13279 cs = ctxt->context->contextSize; 13280 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13281 CHECK_ERROR0; 13282 xmlXPathBooleanFunction(ctxt, 1); 13283 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0)) 13284 return (total); 13285 arg2 = valuePop(ctxt); 13286 ctxt->context->doc = bakd; 13287 ctxt->context->node = bak; 13288 ctxt->context->proximityPosition = pp; 13289 ctxt->context->contextSize = cs; 13290 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13291 if (ctxt->error) { 13292 xmlXPathFreeObject(arg2); 13293 return(0); 13294 } 13295 xmlXPathBooleanFunction(ctxt, 1); 13296 arg1 = valuePop(ctxt); 13297 arg1->boolval &= arg2->boolval; 13298 valuePush(ctxt, arg1); 13299 xmlXPathReleaseObject(ctxt->context, arg2); 13300 return (total); 13301 case XPATH_OP_OR: 13302 bakd = ctxt->context->doc; 13303 bak = ctxt->context->node; 13304 pp = ctxt->context->proximityPosition; 13305 cs = ctxt->context->contextSize; 13306 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13307 CHECK_ERROR0; 13308 xmlXPathBooleanFunction(ctxt, 1); 13309 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1)) 13310 return (total); 13311 arg2 = valuePop(ctxt); 13312 ctxt->context->doc = bakd; 13313 ctxt->context->node = bak; 13314 ctxt->context->proximityPosition = pp; 13315 ctxt->context->contextSize = cs; 13316 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13317 if (ctxt->error) { 13318 xmlXPathFreeObject(arg2); 13319 return(0); 13320 } 13321 xmlXPathBooleanFunction(ctxt, 1); 13322 arg1 = valuePop(ctxt); 13323 arg1->boolval |= arg2->boolval; 13324 valuePush(ctxt, arg1); 13325 xmlXPathReleaseObject(ctxt->context, arg2); 13326 return (total); 13327 case XPATH_OP_EQUAL: 13328 bakd = ctxt->context->doc; 13329 bak = ctxt->context->node; 13330 pp = ctxt->context->proximityPosition; 13331 cs = ctxt->context->contextSize; 13332 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13333 CHECK_ERROR0; 13334 ctxt->context->doc = bakd; 13335 ctxt->context->node = bak; 13336 ctxt->context->proximityPosition = pp; 13337 ctxt->context->contextSize = cs; 13338 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13339 CHECK_ERROR0; 13340 if (op->value) 13341 equal = xmlXPathEqualValues(ctxt); 13342 else 13343 equal = xmlXPathNotEqualValues(ctxt); 13344 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal)); 13345 return (total); 13346 case XPATH_OP_CMP: 13347 bakd = ctxt->context->doc; 13348 bak = ctxt->context->node; 13349 pp = ctxt->context->proximityPosition; 13350 cs = ctxt->context->contextSize; 13351 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13352 CHECK_ERROR0; 13353 ctxt->context->doc = bakd; 13354 ctxt->context->node = bak; 13355 ctxt->context->proximityPosition = pp; 13356 ctxt->context->contextSize = cs; 13357 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13358 CHECK_ERROR0; 13359 ret = xmlXPathCompareValues(ctxt, op->value, op->value2); 13360 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret)); 13361 return (total); 13362 case XPATH_OP_PLUS: 13363 bakd = ctxt->context->doc; 13364 bak = ctxt->context->node; 13365 pp = ctxt->context->proximityPosition; 13366 cs = ctxt->context->contextSize; 13367 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13368 CHECK_ERROR0; 13369 if (op->ch2 != -1) { 13370 ctxt->context->doc = bakd; 13371 ctxt->context->node = bak; 13372 ctxt->context->proximityPosition = pp; 13373 ctxt->context->contextSize = cs; 13374 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13375 } 13376 CHECK_ERROR0; 13377 if (op->value == 0) 13378 xmlXPathSubValues(ctxt); 13379 else if (op->value == 1) 13380 xmlXPathAddValues(ctxt); 13381 else if (op->value == 2) 13382 xmlXPathValueFlipSign(ctxt); 13383 else if (op->value == 3) { 13384 CAST_TO_NUMBER; 13385 CHECK_TYPE0(XPATH_NUMBER); 13386 } 13387 return (total); 13388 case XPATH_OP_MULT: 13389 bakd = ctxt->context->doc; 13390 bak = ctxt->context->node; 13391 pp = ctxt->context->proximityPosition; 13392 cs = ctxt->context->contextSize; 13393 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13394 CHECK_ERROR0; 13395 ctxt->context->doc = bakd; 13396 ctxt->context->node = bak; 13397 ctxt->context->proximityPosition = pp; 13398 ctxt->context->contextSize = cs; 13399 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13400 CHECK_ERROR0; 13401 if (op->value == 0) 13402 xmlXPathMultValues(ctxt); 13403 else if (op->value == 1) 13404 xmlXPathDivValues(ctxt); 13405 else if (op->value == 2) 13406 xmlXPathModValues(ctxt); 13407 return (total); 13408 case XPATH_OP_UNION: 13409 bakd = ctxt->context->doc; 13410 bak = ctxt->context->node; 13411 pp = ctxt->context->proximityPosition; 13412 cs = ctxt->context->contextSize; 13413 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13414 CHECK_ERROR0; 13415 ctxt->context->doc = bakd; 13416 ctxt->context->node = bak; 13417 ctxt->context->proximityPosition = pp; 13418 ctxt->context->contextSize = cs; 13419 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13420 CHECK_ERROR0; 13421 CHECK_TYPE0(XPATH_NODESET); 13422 arg2 = valuePop(ctxt); 13423 13424 CHECK_TYPE0(XPATH_NODESET); 13425 arg1 = valuePop(ctxt); 13426 13427 if ((arg1->nodesetval == NULL) || 13428 ((arg2->nodesetval != NULL) && 13429 (arg2->nodesetval->nodeNr != 0))) 13430 { 13431 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 13432 arg2->nodesetval); 13433 } 13434 13435 valuePush(ctxt, arg1); 13436 xmlXPathReleaseObject(ctxt->context, arg2); 13437 return (total); 13438 case XPATH_OP_ROOT: 13439 xmlXPathRoot(ctxt); 13440 return (total); 13441 case XPATH_OP_NODE: 13442 if (op->ch1 != -1) 13443 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13444 CHECK_ERROR0; 13445 if (op->ch2 != -1) 13446 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13447 CHECK_ERROR0; 13448 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 13449 ctxt->context->node)); 13450 return (total); 13451 case XPATH_OP_RESET: 13452 if (op->ch1 != -1) 13453 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13454 CHECK_ERROR0; 13455 if (op->ch2 != -1) 13456 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13457 CHECK_ERROR0; 13458 ctxt->context->node = NULL; 13459 return (total); 13460 case XPATH_OP_COLLECT:{ 13461 if (op->ch1 == -1) 13462 return (total); 13463 13464 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13465 CHECK_ERROR0; 13466 13467 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0); 13468 return (total); 13469 } 13470 case XPATH_OP_VALUE: 13471 valuePush(ctxt, 13472 xmlXPathCacheObjectCopy(ctxt->context, 13473 (xmlXPathObjectPtr) op->value4)); 13474 return (total); 13475 case XPATH_OP_VARIABLE:{ 13476 xmlXPathObjectPtr val; 13477 13478 if (op->ch1 != -1) 13479 total += 13480 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13481 if (op->value5 == NULL) { 13482 val = xmlXPathVariableLookup(ctxt->context, op->value4); 13483 if (val == NULL) { 13484 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR; 13485 return(0); 13486 } 13487 valuePush(ctxt, val); 13488 } else { 13489 const xmlChar *URI; 13490 13491 URI = xmlXPathNsLookup(ctxt->context, op->value5); 13492 if (URI == NULL) { 13493 xmlGenericError(xmlGenericErrorContext, 13494 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n", 13495 (char *) op->value4, (char *)op->value5); 13496 ctxt->error = XPATH_UNDEF_PREFIX_ERROR; 13497 return (total); 13498 } 13499 val = xmlXPathVariableLookupNS(ctxt->context, 13500 op->value4, URI); 13501 if (val == NULL) { 13502 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR; 13503 return(0); 13504 } 13505 valuePush(ctxt, val); 13506 } 13507 return (total); 13508 } 13509 case XPATH_OP_FUNCTION:{ 13510 xmlXPathFunction func; 13511 const xmlChar *oldFunc, *oldFuncURI; 13512 int i; 13513 int frame; 13514 13515 frame = xmlXPathSetFrame(ctxt); 13516 if (op->ch1 != -1) 13517 total += 13518 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13519 if (ctxt->valueNr < op->value) { 13520 xmlGenericError(xmlGenericErrorContext, 13521 "xmlXPathCompOpEval: parameter error\n"); 13522 ctxt->error = XPATH_INVALID_OPERAND; 13523 xmlXPathPopFrame(ctxt, frame); 13524 return (total); 13525 } 13526 for (i = 0; i < op->value; i++) { 13527 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) { 13528 xmlGenericError(xmlGenericErrorContext, 13529 "xmlXPathCompOpEval: parameter error\n"); 13530 ctxt->error = XPATH_INVALID_OPERAND; 13531 xmlXPathPopFrame(ctxt, frame); 13532 return (total); 13533 } 13534 } 13535 if (op->cache != NULL) 13536 XML_CAST_FPTR(func) = op->cache; 13537 else { 13538 const xmlChar *URI = NULL; 13539 13540 if (op->value5 == NULL) 13541 func = 13542 xmlXPathFunctionLookup(ctxt->context, 13543 op->value4); 13544 else { 13545 URI = xmlXPathNsLookup(ctxt->context, op->value5); 13546 if (URI == NULL) { 13547 xmlGenericError(xmlGenericErrorContext, 13548 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n", 13549 (char *)op->value4, (char *)op->value5); 13550 xmlXPathPopFrame(ctxt, frame); 13551 ctxt->error = XPATH_UNDEF_PREFIX_ERROR; 13552 return (total); 13553 } 13554 func = xmlXPathFunctionLookupNS(ctxt->context, 13555 op->value4, URI); 13556 } 13557 if (func == NULL) { 13558 xmlGenericError(xmlGenericErrorContext, 13559 "xmlXPathCompOpEval: function %s not found\n", 13560 (char *)op->value4); 13561 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR); 13562 } 13563 op->cache = XML_CAST_FPTR(func); 13564 op->cacheURI = (void *) URI; 13565 } 13566 oldFunc = ctxt->context->function; 13567 oldFuncURI = ctxt->context->functionURI; 13568 ctxt->context->function = op->value4; 13569 ctxt->context->functionURI = op->cacheURI; 13570 func(ctxt, op->value); 13571 ctxt->context->function = oldFunc; 13572 ctxt->context->functionURI = oldFuncURI; 13573 xmlXPathPopFrame(ctxt, frame); 13574 return (total); 13575 } 13576 case XPATH_OP_ARG: 13577 bakd = ctxt->context->doc; 13578 bak = ctxt->context->node; 13579 pp = ctxt->context->proximityPosition; 13580 cs = ctxt->context->contextSize; 13581 if (op->ch1 != -1) 13582 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13583 ctxt->context->contextSize = cs; 13584 ctxt->context->proximityPosition = pp; 13585 ctxt->context->node = bak; 13586 ctxt->context->doc = bakd; 13587 CHECK_ERROR0; 13588 if (op->ch2 != -1) { 13589 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13590 ctxt->context->doc = bakd; 13591 ctxt->context->node = bak; 13592 CHECK_ERROR0; 13593 } 13594 return (total); 13595 case XPATH_OP_PREDICATE: 13596 case XPATH_OP_FILTER:{ 13597 xmlXPathObjectPtr res; 13598 xmlXPathObjectPtr obj, tmp; 13599 xmlNodeSetPtr newset = NULL; 13600 xmlNodeSetPtr oldset; 13601 xmlNodePtr oldnode; 13602 xmlDocPtr oldDoc; 13603 int i; 13604 13605 /* 13606 * Optimization for ()[1] selection i.e. the first elem 13607 */ 13608 if ((op->ch1 != -1) && (op->ch2 != -1) && 13609#ifdef XP_OPTIMIZED_FILTER_FIRST 13610 /* 13611 * FILTER TODO: Can we assume that the inner processing 13612 * will result in an ordered list if we have an 13613 * XPATH_OP_FILTER? 13614 * What about an additional field or flag on 13615 * xmlXPathObject like @sorted ? This way we wouln'd need 13616 * to assume anything, so it would be more robust and 13617 * easier to optimize. 13618 */ 13619 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */ 13620 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */ 13621#else 13622 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 13623#endif 13624 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */ 13625 xmlXPathObjectPtr val; 13626 13627 val = comp->steps[op->ch2].value4; 13628 if ((val != NULL) && (val->type == XPATH_NUMBER) && 13629 (val->floatval == 1.0)) { 13630 xmlNodePtr first = NULL; 13631 13632 total += 13633 xmlXPathCompOpEvalFirst(ctxt, 13634 &comp->steps[op->ch1], 13635 &first); 13636 CHECK_ERROR0; 13637 /* 13638 * The nodeset should be in document order, 13639 * Keep only the first value 13640 */ 13641 if ((ctxt->value != NULL) && 13642 (ctxt->value->type == XPATH_NODESET) && 13643 (ctxt->value->nodesetval != NULL) && 13644 (ctxt->value->nodesetval->nodeNr > 1)) 13645 ctxt->value->nodesetval->nodeNr = 1; 13646 return (total); 13647 } 13648 } 13649 /* 13650 * Optimization for ()[last()] selection i.e. the last elem 13651 */ 13652 if ((op->ch1 != -1) && (op->ch2 != -1) && 13653 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 13654 (comp->steps[op->ch2].op == XPATH_OP_SORT)) { 13655 int f = comp->steps[op->ch2].ch1; 13656 13657 if ((f != -1) && 13658 (comp->steps[f].op == XPATH_OP_FUNCTION) && 13659 (comp->steps[f].value5 == NULL) && 13660 (comp->steps[f].value == 0) && 13661 (comp->steps[f].value4 != NULL) && 13662 (xmlStrEqual 13663 (comp->steps[f].value4, BAD_CAST "last"))) { 13664 xmlNodePtr last = NULL; 13665 13666 total += 13667 xmlXPathCompOpEvalLast(ctxt, 13668 &comp->steps[op->ch1], 13669 &last); 13670 CHECK_ERROR0; 13671 /* 13672 * The nodeset should be in document order, 13673 * Keep only the last value 13674 */ 13675 if ((ctxt->value != NULL) && 13676 (ctxt->value->type == XPATH_NODESET) && 13677 (ctxt->value->nodesetval != NULL) && 13678 (ctxt->value->nodesetval->nodeTab != NULL) && 13679 (ctxt->value->nodesetval->nodeNr > 1)) { 13680 ctxt->value->nodesetval->nodeTab[0] = 13681 ctxt->value->nodesetval->nodeTab[ctxt-> 13682 value-> 13683 nodesetval-> 13684 nodeNr - 13685 1]; 13686 ctxt->value->nodesetval->nodeNr = 1; 13687 } 13688 return (total); 13689 } 13690 } 13691 /* 13692 * Process inner predicates first. 13693 * Example "index[parent::book][1]": 13694 * ... 13695 * PREDICATE <-- we are here "[1]" 13696 * PREDICATE <-- process "[parent::book]" first 13697 * SORT 13698 * COLLECT 'parent' 'name' 'node' book 13699 * NODE 13700 * ELEM Object is a number : 1 13701 */ 13702 if (op->ch1 != -1) 13703 total += 13704 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13705 CHECK_ERROR0; 13706 if (op->ch2 == -1) 13707 return (total); 13708 if (ctxt->value == NULL) 13709 return (total); 13710 13711 oldnode = ctxt->context->node; 13712 13713#ifdef LIBXML_XPTR_ENABLED 13714 /* 13715 * Hum are we filtering the result of an XPointer expression 13716 */ 13717 if (ctxt->value->type == XPATH_LOCATIONSET) { 13718 xmlLocationSetPtr newlocset = NULL; 13719 xmlLocationSetPtr oldlocset; 13720 13721 /* 13722 * Extract the old locset, and then evaluate the result of the 13723 * expression for all the element in the locset. use it to grow 13724 * up a new locset. 13725 */ 13726 CHECK_TYPE0(XPATH_LOCATIONSET); 13727 obj = valuePop(ctxt); 13728 oldlocset = obj->user; 13729 ctxt->context->node = NULL; 13730 13731 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) { 13732 ctxt->context->contextSize = 0; 13733 ctxt->context->proximityPosition = 0; 13734 if (op->ch2 != -1) 13735 total += 13736 xmlXPathCompOpEval(ctxt, 13737 &comp->steps[op->ch2]); 13738 res = valuePop(ctxt); 13739 if (res != NULL) { 13740 xmlXPathReleaseObject(ctxt->context, res); 13741 } 13742 valuePush(ctxt, obj); 13743 CHECK_ERROR0; 13744 return (total); 13745 } 13746 newlocset = xmlXPtrLocationSetCreate(NULL); 13747 13748 for (i = 0; i < oldlocset->locNr; i++) { 13749 /* 13750 * Run the evaluation with a node list made of a 13751 * single item in the nodelocset. 13752 */ 13753 ctxt->context->node = oldlocset->locTab[i]->user; 13754 ctxt->context->contextSize = oldlocset->locNr; 13755 ctxt->context->proximityPosition = i + 1; 13756 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13757 ctxt->context->node); 13758 valuePush(ctxt, tmp); 13759 13760 if (op->ch2 != -1) 13761 total += 13762 xmlXPathCompOpEval(ctxt, 13763 &comp->steps[op->ch2]); 13764 if (ctxt->error != XPATH_EXPRESSION_OK) { 13765 xmlXPathFreeObject(obj); 13766 return(0); 13767 } 13768 13769 /* 13770 * The result of the evaluation need to be tested to 13771 * decided whether the filter succeeded or not 13772 */ 13773 res = valuePop(ctxt); 13774 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 13775 xmlXPtrLocationSetAdd(newlocset, 13776 xmlXPathObjectCopy 13777 (oldlocset->locTab[i])); 13778 } 13779 13780 /* 13781 * Cleanup 13782 */ 13783 if (res != NULL) { 13784 xmlXPathReleaseObject(ctxt->context, res); 13785 } 13786 if (ctxt->value == tmp) { 13787 res = valuePop(ctxt); 13788 xmlXPathReleaseObject(ctxt->context, res); 13789 } 13790 13791 ctxt->context->node = NULL; 13792 } 13793 13794 /* 13795 * The result is used as the new evaluation locset. 13796 */ 13797 xmlXPathReleaseObject(ctxt->context, obj); 13798 ctxt->context->node = NULL; 13799 ctxt->context->contextSize = -1; 13800 ctxt->context->proximityPosition = -1; 13801 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset)); 13802 ctxt->context->node = oldnode; 13803 return (total); 13804 } 13805#endif /* LIBXML_XPTR_ENABLED */ 13806 13807 /* 13808 * Extract the old set, and then evaluate the result of the 13809 * expression for all the element in the set. use it to grow 13810 * up a new set. 13811 */ 13812 CHECK_TYPE0(XPATH_NODESET); 13813 obj = valuePop(ctxt); 13814 oldset = obj->nodesetval; 13815 13816 oldnode = ctxt->context->node; 13817 oldDoc = ctxt->context->doc; 13818 ctxt->context->node = NULL; 13819 13820 if ((oldset == NULL) || (oldset->nodeNr == 0)) { 13821 ctxt->context->contextSize = 0; 13822 ctxt->context->proximityPosition = 0; 13823/* 13824 if (op->ch2 != -1) 13825 total += 13826 xmlXPathCompOpEval(ctxt, 13827 &comp->steps[op->ch2]); 13828 CHECK_ERROR0; 13829 res = valuePop(ctxt); 13830 if (res != NULL) 13831 xmlXPathFreeObject(res); 13832*/ 13833 valuePush(ctxt, obj); 13834 ctxt->context->node = oldnode; 13835 CHECK_ERROR0; 13836 } else { 13837 tmp = NULL; 13838 /* 13839 * Initialize the new set. 13840 * Also set the xpath document in case things like 13841 * key() evaluation are attempted on the predicate 13842 */ 13843 newset = xmlXPathNodeSetCreate(NULL); 13844 /* 13845 * SPEC XPath 1.0: 13846 * "For each node in the node-set to be filtered, the 13847 * PredicateExpr is evaluated with that node as the 13848 * context node, with the number of nodes in the 13849 * node-set as the context size, and with the proximity 13850 * position of the node in the node-set with respect to 13851 * the axis as the context position;" 13852 * @oldset is the node-set" to be filtered. 13853 * 13854 * SPEC XPath 1.0: 13855 * "only predicates change the context position and 13856 * context size (see [2.4 Predicates])." 13857 * Example: 13858 * node-set context pos 13859 * nA 1 13860 * nB 2 13861 * nC 3 13862 * After applying predicate [position() > 1] : 13863 * node-set context pos 13864 * nB 1 13865 * nC 2 13866 * 13867 * removed the first node in the node-set, then 13868 * the context position of the 13869 */ 13870 for (i = 0; i < oldset->nodeNr; i++) { 13871 /* 13872 * Run the evaluation with a node list made of 13873 * a single item in the nodeset. 13874 */ 13875 ctxt->context->node = oldset->nodeTab[i]; 13876 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) && 13877 (oldset->nodeTab[i]->doc != NULL)) 13878 ctxt->context->doc = oldset->nodeTab[i]->doc; 13879 if (tmp == NULL) { 13880 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13881 ctxt->context->node); 13882 } else { 13883 if (xmlXPathNodeSetAddUnique(tmp->nodesetval, 13884 ctxt->context->node) < 0) { 13885 ctxt->error = XPATH_MEMORY_ERROR; 13886 } 13887 } 13888 valuePush(ctxt, tmp); 13889 ctxt->context->contextSize = oldset->nodeNr; 13890 ctxt->context->proximityPosition = i + 1; 13891 /* 13892 * Evaluate the predicate against the context node. 13893 * Can/should we optimize position() predicates 13894 * here (e.g. "[1]")? 13895 */ 13896 if (op->ch2 != -1) 13897 total += 13898 xmlXPathCompOpEval(ctxt, 13899 &comp->steps[op->ch2]); 13900 if (ctxt->error != XPATH_EXPRESSION_OK) { 13901 xmlXPathFreeNodeSet(newset); 13902 xmlXPathFreeObject(obj); 13903 return(0); 13904 } 13905 13906 /* 13907 * The result of the evaluation needs to be tested to 13908 * decide whether the filter succeeded or not 13909 */ 13910 /* 13911 * OPTIMIZE TODO: Can we use 13912 * xmlXPathNodeSetAdd*Unique()* instead? 13913 */ 13914 res = valuePop(ctxt); 13915 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 13916 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) 13917 < 0) 13918 ctxt->error = XPATH_MEMORY_ERROR; 13919 } 13920 13921 /* 13922 * Cleanup 13923 */ 13924 if (res != NULL) { 13925 xmlXPathReleaseObject(ctxt->context, res); 13926 } 13927 if (ctxt->value == tmp) { 13928 valuePop(ctxt); 13929 xmlXPathNodeSetClear(tmp->nodesetval, 1); 13930 /* 13931 * Don't free the temporary nodeset 13932 * in order to avoid massive recreation inside this 13933 * loop. 13934 */ 13935 } else 13936 tmp = NULL; 13937 ctxt->context->node = NULL; 13938 } 13939 if (tmp != NULL) 13940 xmlXPathReleaseObject(ctxt->context, tmp); 13941 /* 13942 * The result is used as the new evaluation set. 13943 */ 13944 xmlXPathReleaseObject(ctxt->context, obj); 13945 ctxt->context->node = NULL; 13946 ctxt->context->contextSize = -1; 13947 ctxt->context->proximityPosition = -1; 13948 /* may want to move this past the '}' later */ 13949 ctxt->context->doc = oldDoc; 13950 valuePush(ctxt, 13951 xmlXPathCacheWrapNodeSet(ctxt->context, newset)); 13952 } 13953 ctxt->context->node = oldnode; 13954 return (total); 13955 } 13956 case XPATH_OP_SORT: 13957 if (op->ch1 != -1) 13958 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13959 CHECK_ERROR0; 13960 if ((ctxt->value != NULL) && 13961 (ctxt->value->type == XPATH_NODESET) && 13962 (ctxt->value->nodesetval != NULL) && 13963 (ctxt->value->nodesetval->nodeNr > 1)) 13964 { 13965 xmlXPathNodeSetSort(ctxt->value->nodesetval); 13966 } 13967 return (total); 13968#ifdef LIBXML_XPTR_ENABLED 13969 case XPATH_OP_RANGETO:{ 13970 xmlXPathObjectPtr range; 13971 xmlXPathObjectPtr res, obj; 13972 xmlXPathObjectPtr tmp; 13973 xmlLocationSetPtr newlocset = NULL; 13974 xmlLocationSetPtr oldlocset; 13975 xmlNodeSetPtr oldset; 13976 int i, j; 13977 13978 if (op->ch1 != -1) 13979 total += 13980 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13981 if (op->ch2 == -1) 13982 return (total); 13983 13984 if (ctxt->value->type == XPATH_LOCATIONSET) { 13985 /* 13986 * Extract the old locset, and then evaluate the result of the 13987 * expression for all the element in the locset. use it to grow 13988 * up a new locset. 13989 */ 13990 CHECK_TYPE0(XPATH_LOCATIONSET); 13991 obj = valuePop(ctxt); 13992 oldlocset = obj->user; 13993 13994 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) { 13995 ctxt->context->node = NULL; 13996 ctxt->context->contextSize = 0; 13997 ctxt->context->proximityPosition = 0; 13998 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]); 13999 res = valuePop(ctxt); 14000 if (res != NULL) { 14001 xmlXPathReleaseObject(ctxt->context, res); 14002 } 14003 valuePush(ctxt, obj); 14004 CHECK_ERROR0; 14005 return (total); 14006 } 14007 newlocset = xmlXPtrLocationSetCreate(NULL); 14008 14009 for (i = 0; i < oldlocset->locNr; i++) { 14010 /* 14011 * Run the evaluation with a node list made of a 14012 * single item in the nodelocset. 14013 */ 14014 ctxt->context->node = oldlocset->locTab[i]->user; 14015 ctxt->context->contextSize = oldlocset->locNr; 14016 ctxt->context->proximityPosition = i + 1; 14017 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 14018 ctxt->context->node); 14019 valuePush(ctxt, tmp); 14020 14021 if (op->ch2 != -1) 14022 total += 14023 xmlXPathCompOpEval(ctxt, 14024 &comp->steps[op->ch2]); 14025 if (ctxt->error != XPATH_EXPRESSION_OK) { 14026 xmlXPathFreeObject(obj); 14027 return(0); 14028 } 14029 14030 res = valuePop(ctxt); 14031 if (res->type == XPATH_LOCATIONSET) { 14032 xmlLocationSetPtr rloc = 14033 (xmlLocationSetPtr)res->user; 14034 for (j=0; j<rloc->locNr; j++) { 14035 range = xmlXPtrNewRange( 14036 oldlocset->locTab[i]->user, 14037 oldlocset->locTab[i]->index, 14038 rloc->locTab[j]->user2, 14039 rloc->locTab[j]->index2); 14040 if (range != NULL) { 14041 xmlXPtrLocationSetAdd(newlocset, range); 14042 } 14043 } 14044 } else { 14045 range = xmlXPtrNewRangeNodeObject( 14046 (xmlNodePtr)oldlocset->locTab[i]->user, res); 14047 if (range != NULL) { 14048 xmlXPtrLocationSetAdd(newlocset,range); 14049 } 14050 } 14051 14052 /* 14053 * Cleanup 14054 */ 14055 if (res != NULL) { 14056 xmlXPathReleaseObject(ctxt->context, res); 14057 } 14058 if (ctxt->value == tmp) { 14059 res = valuePop(ctxt); 14060 xmlXPathReleaseObject(ctxt->context, res); 14061 } 14062 14063 ctxt->context->node = NULL; 14064 } 14065 } else { /* Not a location set */ 14066 CHECK_TYPE0(XPATH_NODESET); 14067 obj = valuePop(ctxt); 14068 oldset = obj->nodesetval; 14069 ctxt->context->node = NULL; 14070 14071 newlocset = xmlXPtrLocationSetCreate(NULL); 14072 14073 if (oldset != NULL) { 14074 for (i = 0; i < oldset->nodeNr; i++) { 14075 /* 14076 * Run the evaluation with a node list made of a single item 14077 * in the nodeset. 14078 */ 14079 ctxt->context->node = oldset->nodeTab[i]; 14080 /* 14081 * OPTIMIZE TODO: Avoid recreation for every iteration. 14082 */ 14083 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 14084 ctxt->context->node); 14085 valuePush(ctxt, tmp); 14086 14087 if (op->ch2 != -1) 14088 total += 14089 xmlXPathCompOpEval(ctxt, 14090 &comp->steps[op->ch2]); 14091 if (ctxt->error != XPATH_EXPRESSION_OK) { 14092 xmlXPathFreeObject(obj); 14093 return(0); 14094 } 14095 14096 res = valuePop(ctxt); 14097 range = 14098 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i], 14099 res); 14100 if (range != NULL) { 14101 xmlXPtrLocationSetAdd(newlocset, range); 14102 } 14103 14104 /* 14105 * Cleanup 14106 */ 14107 if (res != NULL) { 14108 xmlXPathReleaseObject(ctxt->context, res); 14109 } 14110 if (ctxt->value == tmp) { 14111 res = valuePop(ctxt); 14112 xmlXPathReleaseObject(ctxt->context, res); 14113 } 14114 14115 ctxt->context->node = NULL; 14116 } 14117 } 14118 } 14119 14120 /* 14121 * The result is used as the new evaluation set. 14122 */ 14123 xmlXPathReleaseObject(ctxt->context, obj); 14124 ctxt->context->node = NULL; 14125 ctxt->context->contextSize = -1; 14126 ctxt->context->proximityPosition = -1; 14127 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset)); 14128 return (total); 14129 } 14130#endif /* LIBXML_XPTR_ENABLED */ 14131 } 14132 xmlGenericError(xmlGenericErrorContext, 14133 "XPath: unknown precompiled operation %d\n", op->op); 14134 ctxt->error = XPATH_INVALID_OPERAND; 14135 return (total); 14136} 14137 14138/** 14139 * xmlXPathCompOpEvalToBoolean: 14140 * @ctxt: the XPath parser context 14141 * 14142 * Evaluates if the expression evaluates to true. 14143 * 14144 * Returns 1 if true, 0 if false and -1 on API or internal errors. 14145 */ 14146static int 14147xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt, 14148 xmlXPathStepOpPtr op, 14149 int isPredicate) 14150{ 14151 xmlXPathObjectPtr resObj = NULL; 14152 14153start: 14154 /* comp = ctxt->comp; */ 14155 switch (op->op) { 14156 case XPATH_OP_END: 14157 return (0); 14158 case XPATH_OP_VALUE: 14159 resObj = (xmlXPathObjectPtr) op->value4; 14160 if (isPredicate) 14161 return(xmlXPathEvaluatePredicateResult(ctxt, resObj)); 14162 return(xmlXPathCastToBoolean(resObj)); 14163 case XPATH_OP_SORT: 14164 /* 14165 * We don't need sorting for boolean results. Skip this one. 14166 */ 14167 if (op->ch1 != -1) { 14168 op = &ctxt->comp->steps[op->ch1]; 14169 goto start; 14170 } 14171 return(0); 14172 case XPATH_OP_COLLECT: 14173 if (op->ch1 == -1) 14174 return(0); 14175 14176 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]); 14177 if (ctxt->error != XPATH_EXPRESSION_OK) 14178 return(-1); 14179 14180 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1); 14181 if (ctxt->error != XPATH_EXPRESSION_OK) 14182 return(-1); 14183 14184 resObj = valuePop(ctxt); 14185 if (resObj == NULL) 14186 return(-1); 14187 break; 14188 default: 14189 /* 14190 * Fallback to call xmlXPathCompOpEval(). 14191 */ 14192 xmlXPathCompOpEval(ctxt, op); 14193 if (ctxt->error != XPATH_EXPRESSION_OK) 14194 return(-1); 14195 14196 resObj = valuePop(ctxt); 14197 if (resObj == NULL) 14198 return(-1); 14199 break; 14200 } 14201 14202 if (resObj) { 14203 int res; 14204 14205 if (resObj->type == XPATH_BOOLEAN) { 14206 res = resObj->boolval; 14207 } else if (isPredicate) { 14208 /* 14209 * For predicates a result of type "number" is handled 14210 * differently: 14211 * SPEC XPath 1.0: 14212 * "If the result is a number, the result will be converted 14213 * to true if the number is equal to the context position 14214 * and will be converted to false otherwise;" 14215 */ 14216 res = xmlXPathEvaluatePredicateResult(ctxt, resObj); 14217 } else { 14218 res = xmlXPathCastToBoolean(resObj); 14219 } 14220 xmlXPathReleaseObject(ctxt->context, resObj); 14221 return(res); 14222 } 14223 14224 return(0); 14225} 14226 14227#ifdef XPATH_STREAMING 14228/** 14229 * xmlXPathRunStreamEval: 14230 * @ctxt: the XPath parser context with the compiled expression 14231 * 14232 * Evaluate the Precompiled Streamable XPath expression in the given context. 14233 */ 14234static int 14235xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp, 14236 xmlXPathObjectPtr *resultSeq, int toBool) 14237{ 14238 int max_depth, min_depth; 14239 int from_root; 14240 int ret, depth; 14241 int eval_all_nodes; 14242 xmlNodePtr cur = NULL, limit = NULL; 14243 xmlStreamCtxtPtr patstream = NULL; 14244 14245 int nb_nodes = 0; 14246 14247 if ((ctxt == NULL) || (comp == NULL)) 14248 return(-1); 14249 max_depth = xmlPatternMaxDepth(comp); 14250 if (max_depth == -1) 14251 return(-1); 14252 if (max_depth == -2) 14253 max_depth = 10000; 14254 min_depth = xmlPatternMinDepth(comp); 14255 if (min_depth == -1) 14256 return(-1); 14257 from_root = xmlPatternFromRoot(comp); 14258 if (from_root < 0) 14259 return(-1); 14260#if 0 14261 printf("stream eval: depth %d from root %d\n", max_depth, from_root); 14262#endif 14263 14264 if (! toBool) { 14265 if (resultSeq == NULL) 14266 return(-1); 14267 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL); 14268 if (*resultSeq == NULL) 14269 return(-1); 14270 } 14271 14272 /* 14273 * handle the special cases of "/" amd "." being matched 14274 */ 14275 if (min_depth == 0) { 14276 if (from_root) { 14277 /* Select "/" */ 14278 if (toBool) 14279 return(1); 14280 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, 14281 (xmlNodePtr) ctxt->doc); 14282 } else { 14283 /* Select "self::node()" */ 14284 if (toBool) 14285 return(1); 14286 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node); 14287 } 14288 } 14289 if (max_depth == 0) { 14290 return(0); 14291 } 14292 14293 if (from_root) { 14294 cur = (xmlNodePtr)ctxt->doc; 14295 } else if (ctxt->node != NULL) { 14296 switch (ctxt->node->type) { 14297 case XML_ELEMENT_NODE: 14298 case XML_DOCUMENT_NODE: 14299 case XML_DOCUMENT_FRAG_NODE: 14300 case XML_HTML_DOCUMENT_NODE: 14301#ifdef LIBXML_DOCB_ENABLED 14302 case XML_DOCB_DOCUMENT_NODE: 14303#endif 14304 cur = ctxt->node; 14305 break; 14306 case XML_ATTRIBUTE_NODE: 14307 case XML_TEXT_NODE: 14308 case XML_CDATA_SECTION_NODE: 14309 case XML_ENTITY_REF_NODE: 14310 case XML_ENTITY_NODE: 14311 case XML_PI_NODE: 14312 case XML_COMMENT_NODE: 14313 case XML_NOTATION_NODE: 14314 case XML_DTD_NODE: 14315 case XML_DOCUMENT_TYPE_NODE: 14316 case XML_ELEMENT_DECL: 14317 case XML_ATTRIBUTE_DECL: 14318 case XML_ENTITY_DECL: 14319 case XML_NAMESPACE_DECL: 14320 case XML_XINCLUDE_START: 14321 case XML_XINCLUDE_END: 14322 break; 14323 } 14324 limit = cur; 14325 } 14326 if (cur == NULL) { 14327 return(0); 14328 } 14329 14330 patstream = xmlPatternGetStreamCtxt(comp); 14331 if (patstream == NULL) { 14332 /* 14333 * QUESTION TODO: Is this an error? 14334 */ 14335 return(0); 14336 } 14337 14338 eval_all_nodes = xmlStreamWantsAnyNode(patstream); 14339 14340 if (from_root) { 14341 ret = xmlStreamPush(patstream, NULL, NULL); 14342 if (ret < 0) { 14343 } else if (ret == 1) { 14344 if (toBool) 14345 goto return_1; 14346 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur); 14347 } 14348 } 14349 depth = 0; 14350 goto scan_children; 14351next_node: 14352 do { 14353 nb_nodes++; 14354 14355 switch (cur->type) { 14356 case XML_ELEMENT_NODE: 14357 case XML_TEXT_NODE: 14358 case XML_CDATA_SECTION_NODE: 14359 case XML_COMMENT_NODE: 14360 case XML_PI_NODE: 14361 if (cur->type == XML_ELEMENT_NODE) { 14362 ret = xmlStreamPush(patstream, cur->name, 14363 (cur->ns ? cur->ns->href : NULL)); 14364 } else if (eval_all_nodes) 14365 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type); 14366 else 14367 break; 14368 14369 if (ret < 0) { 14370 /* NOP. */ 14371 } else if (ret == 1) { 14372 if (toBool) 14373 goto return_1; 14374 if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur) 14375 < 0) { 14376 ctxt->lastError.domain = XML_FROM_XPATH; 14377 ctxt->lastError.code = XML_ERR_NO_MEMORY; 14378 } 14379 } 14380 if ((cur->children == NULL) || (depth >= max_depth)) { 14381 ret = xmlStreamPop(patstream); 14382 while (cur->next != NULL) { 14383 cur = cur->next; 14384 if ((cur->type != XML_ENTITY_DECL) && 14385 (cur->type != XML_DTD_NODE)) 14386 goto next_node; 14387 } 14388 } 14389 default: 14390 break; 14391 } 14392 14393scan_children: 14394 if (cur->type == XML_NAMESPACE_DECL) break; 14395 if ((cur->children != NULL) && (depth < max_depth)) { 14396 /* 14397 * Do not descend on entities declarations 14398 */ 14399 if (cur->children->type != XML_ENTITY_DECL) { 14400 cur = cur->children; 14401 depth++; 14402 /* 14403 * Skip DTDs 14404 */ 14405 if (cur->type != XML_DTD_NODE) 14406 continue; 14407 } 14408 } 14409 14410 if (cur == limit) 14411 break; 14412 14413 while (cur->next != NULL) { 14414 cur = cur->next; 14415 if ((cur->type != XML_ENTITY_DECL) && 14416 (cur->type != XML_DTD_NODE)) 14417 goto next_node; 14418 } 14419 14420 do { 14421 cur = cur->parent; 14422 depth--; 14423 if ((cur == NULL) || (cur == limit)) 14424 goto done; 14425 if (cur->type == XML_ELEMENT_NODE) { 14426 ret = xmlStreamPop(patstream); 14427 } else if ((eval_all_nodes) && 14428 ((cur->type == XML_TEXT_NODE) || 14429 (cur->type == XML_CDATA_SECTION_NODE) || 14430 (cur->type == XML_COMMENT_NODE) || 14431 (cur->type == XML_PI_NODE))) 14432 { 14433 ret = xmlStreamPop(patstream); 14434 } 14435 if (cur->next != NULL) { 14436 cur = cur->next; 14437 break; 14438 } 14439 } while (cur != NULL); 14440 14441 } while ((cur != NULL) && (depth >= 0)); 14442 14443done: 14444 14445#if 0 14446 printf("stream eval: checked %d nodes selected %d\n", 14447 nb_nodes, retObj->nodesetval->nodeNr); 14448#endif 14449 14450 if (patstream) 14451 xmlFreeStreamCtxt(patstream); 14452 return(0); 14453 14454return_1: 14455 if (patstream) 14456 xmlFreeStreamCtxt(patstream); 14457 return(1); 14458} 14459#endif /* XPATH_STREAMING */ 14460 14461/** 14462 * xmlXPathRunEval: 14463 * @ctxt: the XPath parser context with the compiled expression 14464 * @toBool: evaluate to a boolean result 14465 * 14466 * Evaluate the Precompiled XPath expression in the given context. 14467 */ 14468static int 14469xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool) 14470{ 14471 xmlXPathCompExprPtr comp; 14472 14473 if ((ctxt == NULL) || (ctxt->comp == NULL)) 14474 return(-1); 14475 14476 if (ctxt->valueTab == NULL) { 14477 /* Allocate the value stack */ 14478 ctxt->valueTab = (xmlXPathObjectPtr *) 14479 xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); 14480 if (ctxt->valueTab == NULL) { 14481 xmlXPathPErrMemory(ctxt, "creating evaluation context\n"); 14482 xmlFree(ctxt); 14483 } 14484 ctxt->valueNr = 0; 14485 ctxt->valueMax = 10; 14486 ctxt->value = NULL; 14487 ctxt->valueFrame = 0; 14488 } 14489#ifdef XPATH_STREAMING 14490 if (ctxt->comp->stream) { 14491 int res; 14492 14493 if (toBool) { 14494 /* 14495 * Evaluation to boolean result. 14496 */ 14497 res = xmlXPathRunStreamEval(ctxt->context, 14498 ctxt->comp->stream, NULL, 1); 14499 if (res != -1) 14500 return(res); 14501 } else { 14502 xmlXPathObjectPtr resObj = NULL; 14503 14504 /* 14505 * Evaluation to a sequence. 14506 */ 14507 res = xmlXPathRunStreamEval(ctxt->context, 14508 ctxt->comp->stream, &resObj, 0); 14509 14510 if ((res != -1) && (resObj != NULL)) { 14511 valuePush(ctxt, resObj); 14512 return(0); 14513 } 14514 if (resObj != NULL) 14515 xmlXPathReleaseObject(ctxt->context, resObj); 14516 } 14517 /* 14518 * QUESTION TODO: This falls back to normal XPath evaluation 14519 * if res == -1. Is this intended? 14520 */ 14521 } 14522#endif 14523 comp = ctxt->comp; 14524 if (comp->last < 0) { 14525 xmlGenericError(xmlGenericErrorContext, 14526 "xmlXPathRunEval: last is less than zero\n"); 14527 return(-1); 14528 } 14529 if (toBool) 14530 return(xmlXPathCompOpEvalToBoolean(ctxt, 14531 &comp->steps[comp->last], 0)); 14532 else 14533 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]); 14534 14535 return(0); 14536} 14537 14538/************************************************************************ 14539 * * 14540 * Public interfaces * 14541 * * 14542 ************************************************************************/ 14543 14544/** 14545 * xmlXPathEvalPredicate: 14546 * @ctxt: the XPath context 14547 * @res: the Predicate Expression evaluation result 14548 * 14549 * Evaluate a predicate result for the current node. 14550 * A PredicateExpr is evaluated by evaluating the Expr and converting 14551 * the result to a boolean. If the result is a number, the result will 14552 * be converted to true if the number is equal to the position of the 14553 * context node in the context node list (as returned by the position 14554 * function) and will be converted to false otherwise; if the result 14555 * is not a number, then the result will be converted as if by a call 14556 * to the boolean function. 14557 * 14558 * Returns 1 if predicate is true, 0 otherwise 14559 */ 14560int 14561xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) { 14562 if ((ctxt == NULL) || (res == NULL)) return(0); 14563 switch (res->type) { 14564 case XPATH_BOOLEAN: 14565 return(res->boolval); 14566 case XPATH_NUMBER: 14567 return(res->floatval == ctxt->proximityPosition); 14568 case XPATH_NODESET: 14569 case XPATH_XSLT_TREE: 14570 if (res->nodesetval == NULL) 14571 return(0); 14572 return(res->nodesetval->nodeNr != 0); 14573 case XPATH_STRING: 14574 return((res->stringval != NULL) && 14575 (xmlStrlen(res->stringval) != 0)); 14576 default: 14577 STRANGE 14578 } 14579 return(0); 14580} 14581 14582/** 14583 * xmlXPathEvaluatePredicateResult: 14584 * @ctxt: the XPath Parser context 14585 * @res: the Predicate Expression evaluation result 14586 * 14587 * Evaluate a predicate result for the current node. 14588 * A PredicateExpr is evaluated by evaluating the Expr and converting 14589 * the result to a boolean. If the result is a number, the result will 14590 * be converted to true if the number is equal to the position of the 14591 * context node in the context node list (as returned by the position 14592 * function) and will be converted to false otherwise; if the result 14593 * is not a number, then the result will be converted as if by a call 14594 * to the boolean function. 14595 * 14596 * Returns 1 if predicate is true, 0 otherwise 14597 */ 14598int 14599xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt, 14600 xmlXPathObjectPtr res) { 14601 if ((ctxt == NULL) || (res == NULL)) return(0); 14602 switch (res->type) { 14603 case XPATH_BOOLEAN: 14604 return(res->boolval); 14605 case XPATH_NUMBER: 14606#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200)) 14607 return((res->floatval == ctxt->context->proximityPosition) && 14608 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/ 14609#else 14610 return(res->floatval == ctxt->context->proximityPosition); 14611#endif 14612 case XPATH_NODESET: 14613 case XPATH_XSLT_TREE: 14614 if (res->nodesetval == NULL) 14615 return(0); 14616 return(res->nodesetval->nodeNr != 0); 14617 case XPATH_STRING: 14618 return((res->stringval != NULL) && (res->stringval[0] != 0)); 14619#ifdef LIBXML_XPTR_ENABLED 14620 case XPATH_LOCATIONSET:{ 14621 xmlLocationSetPtr ptr = res->user; 14622 if (ptr == NULL) 14623 return(0); 14624 return (ptr->locNr != 0); 14625 } 14626#endif 14627 default: 14628 STRANGE 14629 } 14630 return(0); 14631} 14632 14633#ifdef XPATH_STREAMING 14634/** 14635 * xmlXPathTryStreamCompile: 14636 * @ctxt: an XPath context 14637 * @str: the XPath expression 14638 * 14639 * Try to compile the XPath expression as a streamable subset. 14640 * 14641 * Returns the compiled expression or NULL if failed to compile. 14642 */ 14643static xmlXPathCompExprPtr 14644xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { 14645 /* 14646 * Optimization: use streaming patterns when the XPath expression can 14647 * be compiled to a stream lookup 14648 */ 14649 xmlPatternPtr stream; 14650 xmlXPathCompExprPtr comp; 14651 xmlDictPtr dict = NULL; 14652 const xmlChar **namespaces = NULL; 14653 xmlNsPtr ns; 14654 int i, j; 14655 14656 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) && 14657 (!xmlStrchr(str, '@'))) { 14658 const xmlChar *tmp; 14659 14660 /* 14661 * We don't try to handle expressions using the verbose axis 14662 * specifiers ("::"), just the simplied form at this point. 14663 * Additionally, if there is no list of namespaces available and 14664 * there's a ":" in the expression, indicating a prefixed QName, 14665 * then we won't try to compile either. xmlPatterncompile() needs 14666 * to have a list of namespaces at compilation time in order to 14667 * compile prefixed name tests. 14668 */ 14669 tmp = xmlStrchr(str, ':'); 14670 if ((tmp != NULL) && 14671 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':'))) 14672 return(NULL); 14673 14674 if (ctxt != NULL) { 14675 dict = ctxt->dict; 14676 if (ctxt->nsNr > 0) { 14677 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*)); 14678 if (namespaces == NULL) { 14679 xmlXPathErrMemory(ctxt, "allocating namespaces array\n"); 14680 return(NULL); 14681 } 14682 for (i = 0, j = 0; (j < ctxt->nsNr); j++) { 14683 ns = ctxt->namespaces[j]; 14684 namespaces[i++] = ns->href; 14685 namespaces[i++] = ns->prefix; 14686 } 14687 namespaces[i++] = NULL; 14688 namespaces[i] = NULL; 14689 } 14690 } 14691 14692 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, 14693 &namespaces[0]); 14694 if (namespaces != NULL) { 14695 xmlFree((xmlChar **)namespaces); 14696 } 14697 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) { 14698 comp = xmlXPathNewCompExpr(); 14699 if (comp == NULL) { 14700 xmlXPathErrMemory(ctxt, "allocating streamable expression\n"); 14701 return(NULL); 14702 } 14703 comp->stream = stream; 14704 comp->dict = dict; 14705 if (comp->dict) 14706 xmlDictReference(comp->dict); 14707 return(comp); 14708 } 14709 xmlFreePattern(stream); 14710 } 14711 return(NULL); 14712} 14713#endif /* XPATH_STREAMING */ 14714 14715static void 14716xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op) 14717{ 14718 /* 14719 * Try to rewrite "descendant-or-self::node()/foo" to an optimized 14720 * internal representation. 14721 */ 14722 14723 if ((op->ch1 != -1) && 14724 (op->op == XPATH_OP_COLLECT /* 11 */)) 14725 { 14726 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1]; 14727 14728 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) && 14729 ((xmlXPathAxisVal) prevop->value == 14730 AXIS_DESCENDANT_OR_SELF) && 14731 (prevop->ch2 == -1) && 14732 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) && 14733 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE)) 14734 { 14735 /* 14736 * This is a "descendant-or-self::node()" without predicates. 14737 * Try to eliminate it. 14738 */ 14739 14740 switch ((xmlXPathAxisVal) op->value) { 14741 case AXIS_CHILD: 14742 case AXIS_DESCENDANT: 14743 /* 14744 * Convert "descendant-or-self::node()/child::" or 14745 * "descendant-or-self::node()/descendant::" to 14746 * "descendant::" 14747 */ 14748 op->ch1 = prevop->ch1; 14749 op->value = AXIS_DESCENDANT; 14750 break; 14751 case AXIS_SELF: 14752 case AXIS_DESCENDANT_OR_SELF: 14753 /* 14754 * Convert "descendant-or-self::node()/self::" or 14755 * "descendant-or-self::node()/descendant-or-self::" to 14756 * to "descendant-or-self::" 14757 */ 14758 op->ch1 = prevop->ch1; 14759 op->value = AXIS_DESCENDANT_OR_SELF; 14760 break; 14761 default: 14762 break; 14763 } 14764 } 14765 } 14766 14767 /* Recurse */ 14768 if (op->ch1 != -1) 14769 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]); 14770 if (op->ch2 != -1) 14771 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]); 14772} 14773 14774/** 14775 * xmlXPathCtxtCompile: 14776 * @ctxt: an XPath context 14777 * @str: the XPath expression 14778 * 14779 * Compile an XPath expression 14780 * 14781 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL. 14782 * the caller has to free the object. 14783 */ 14784xmlXPathCompExprPtr 14785xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { 14786 xmlXPathParserContextPtr pctxt; 14787 xmlXPathCompExprPtr comp; 14788 14789#ifdef XPATH_STREAMING 14790 comp = xmlXPathTryStreamCompile(ctxt, str); 14791 if (comp != NULL) 14792 return(comp); 14793#endif 14794 14795 xmlXPathInit(); 14796 14797 pctxt = xmlXPathNewParserContext(str, ctxt); 14798 if (pctxt == NULL) 14799 return NULL; 14800 xmlXPathCompileExpr(pctxt, 1); 14801 14802 if( pctxt->error != XPATH_EXPRESSION_OK ) 14803 { 14804 xmlXPathFreeParserContext(pctxt); 14805 return(NULL); 14806 } 14807 14808 if (*pctxt->cur != 0) { 14809 /* 14810 * aleksey: in some cases this line prints *second* error message 14811 * (see bug #78858) and probably this should be fixed. 14812 * However, we are not sure that all error messages are printed 14813 * out in other places. It's not critical so we leave it as-is for now 14814 */ 14815 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR); 14816 comp = NULL; 14817 } else { 14818 comp = pctxt->comp; 14819 pctxt->comp = NULL; 14820 } 14821 xmlXPathFreeParserContext(pctxt); 14822 14823 if (comp != NULL) { 14824 comp->expr = xmlStrdup(str); 14825#ifdef DEBUG_EVAL_COUNTS 14826 comp->string = xmlStrdup(str); 14827 comp->nb = 0; 14828#endif 14829 if ((comp->nbStep > 1) && (comp->last >= 0)) { 14830 xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]); 14831 } 14832 } 14833 return(comp); 14834} 14835 14836/** 14837 * xmlXPathCompile: 14838 * @str: the XPath expression 14839 * 14840 * Compile an XPath expression 14841 * 14842 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL. 14843 * the caller has to free the object. 14844 */ 14845xmlXPathCompExprPtr 14846xmlXPathCompile(const xmlChar *str) { 14847 return(xmlXPathCtxtCompile(NULL, str)); 14848} 14849 14850/** 14851 * xmlXPathCompiledEvalInternal: 14852 * @comp: the compiled XPath expression 14853 * @ctxt: the XPath context 14854 * @resObj: the resulting XPath object or NULL 14855 * @toBool: 1 if only a boolean result is requested 14856 * 14857 * Evaluate the Precompiled XPath expression in the given context. 14858 * The caller has to free @resObj. 14859 * 14860 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14861 * the caller has to free the object. 14862 */ 14863static int 14864xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp, 14865 xmlXPathContextPtr ctxt, 14866 xmlXPathObjectPtr *resObj, 14867 int toBool) 14868{ 14869 xmlXPathParserContextPtr pctxt; 14870#ifndef LIBXML_THREAD_ENABLED 14871 static int reentance = 0; 14872#endif 14873 int res; 14874 14875 CHECK_CTXT_NEG(ctxt) 14876 14877 if (comp == NULL) 14878 return(-1); 14879 xmlXPathInit(); 14880 14881#ifndef LIBXML_THREAD_ENABLED 14882 reentance++; 14883 if (reentance > 1) 14884 xmlXPathDisableOptimizer = 1; 14885#endif 14886 14887#ifdef DEBUG_EVAL_COUNTS 14888 comp->nb++; 14889 if ((comp->string != NULL) && (comp->nb > 100)) { 14890 fprintf(stderr, "100 x %s\n", comp->string); 14891 comp->nb = 0; 14892 } 14893#endif 14894 pctxt = xmlXPathCompParserContext(comp, ctxt); 14895 res = xmlXPathRunEval(pctxt, toBool); 14896 14897 if (resObj) { 14898 if (pctxt->value == NULL) { 14899 xmlGenericError(xmlGenericErrorContext, 14900 "xmlXPathCompiledEval: evaluation failed\n"); 14901 *resObj = NULL; 14902 } else { 14903 *resObj = valuePop(pctxt); 14904 } 14905 } 14906 14907 /* 14908 * Pop all remaining objects from the stack. 14909 */ 14910 if (pctxt->valueNr > 0) { 14911 xmlXPathObjectPtr tmp; 14912 int stack = 0; 14913 14914 do { 14915 tmp = valuePop(pctxt); 14916 if (tmp != NULL) { 14917 stack++; 14918 xmlXPathReleaseObject(ctxt, tmp); 14919 } 14920 } while (tmp != NULL); 14921 if ((stack != 0) && 14922 ((toBool) || ((resObj) && (*resObj)))) 14923 { 14924 xmlGenericError(xmlGenericErrorContext, 14925 "xmlXPathCompiledEval: %d objects left on the stack.\n", 14926 stack); 14927 } 14928 } 14929 14930 if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) { 14931 xmlXPathFreeObject(*resObj); 14932 *resObj = NULL; 14933 } 14934 pctxt->comp = NULL; 14935 xmlXPathFreeParserContext(pctxt); 14936#ifndef LIBXML_THREAD_ENABLED 14937 reentance--; 14938#endif 14939 14940 return(res); 14941} 14942 14943/** 14944 * xmlXPathCompiledEval: 14945 * @comp: the compiled XPath expression 14946 * @ctx: the XPath context 14947 * 14948 * Evaluate the Precompiled XPath expression in the given context. 14949 * 14950 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14951 * the caller has to free the object. 14952 */ 14953xmlXPathObjectPtr 14954xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) 14955{ 14956 xmlXPathObjectPtr res = NULL; 14957 14958 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0); 14959 return(res); 14960} 14961 14962/** 14963 * xmlXPathCompiledEvalToBoolean: 14964 * @comp: the compiled XPath expression 14965 * @ctxt: the XPath context 14966 * 14967 * Applies the XPath boolean() function on the result of the given 14968 * compiled expression. 14969 * 14970 * Returns 1 if the expression evaluated to true, 0 if to false and 14971 * -1 in API and internal errors. 14972 */ 14973int 14974xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp, 14975 xmlXPathContextPtr ctxt) 14976{ 14977 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1)); 14978} 14979 14980/** 14981 * xmlXPathEvalExpr: 14982 * @ctxt: the XPath Parser context 14983 * 14984 * Parse and evaluate an XPath expression in the given context, 14985 * then push the result on the context stack 14986 */ 14987void 14988xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) { 14989#ifdef XPATH_STREAMING 14990 xmlXPathCompExprPtr comp; 14991#endif 14992 14993 if (ctxt == NULL) return; 14994 14995#ifdef XPATH_STREAMING 14996 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base); 14997 if (comp != NULL) { 14998 if (ctxt->comp != NULL) 14999 xmlXPathFreeCompExpr(ctxt->comp); 15000 ctxt->comp = comp; 15001 if (ctxt->cur != NULL) 15002 while (*ctxt->cur != 0) ctxt->cur++; 15003 } else 15004#endif 15005 { 15006 xmlXPathCompileExpr(ctxt, 1); 15007 if ((ctxt->error == XPATH_EXPRESSION_OK) && 15008 (ctxt->comp != NULL) && 15009 (ctxt->comp->nbStep > 1) && 15010 (ctxt->comp->last >= 0)) 15011 { 15012 xmlXPathOptimizeExpression(ctxt->comp, 15013 &ctxt->comp->steps[ctxt->comp->last]); 15014 } 15015 } 15016 CHECK_ERROR; 15017 xmlXPathRunEval(ctxt, 0); 15018} 15019 15020/** 15021 * xmlXPathEval: 15022 * @str: the XPath expression 15023 * @ctx: the XPath context 15024 * 15025 * Evaluate the XPath Location Path in the given context. 15026 * 15027 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 15028 * the caller has to free the object. 15029 */ 15030xmlXPathObjectPtr 15031xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) { 15032 xmlXPathParserContextPtr ctxt; 15033 xmlXPathObjectPtr res, tmp, init = NULL; 15034 int stack = 0; 15035 15036 CHECK_CTXT(ctx) 15037 15038 xmlXPathInit(); 15039 15040 ctxt = xmlXPathNewParserContext(str, ctx); 15041 if (ctxt == NULL) 15042 return NULL; 15043 xmlXPathEvalExpr(ctxt); 15044 15045 if (ctxt->value == NULL) { 15046 xmlGenericError(xmlGenericErrorContext, 15047 "xmlXPathEval: evaluation failed\n"); 15048 res = NULL; 15049 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL) 15050#ifdef XPATH_STREAMING 15051 && (ctxt->comp->stream == NULL) 15052#endif 15053 ) { 15054 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR); 15055 res = NULL; 15056 } else { 15057 res = valuePop(ctxt); 15058 } 15059 15060 do { 15061 tmp = valuePop(ctxt); 15062 if (tmp != NULL) { 15063 if (tmp != init) 15064 stack++; 15065 xmlXPathReleaseObject(ctx, tmp); 15066 } 15067 } while (tmp != NULL); 15068 if ((stack != 0) && (res != NULL)) { 15069 xmlGenericError(xmlGenericErrorContext, 15070 "xmlXPathEval: %d object left on the stack\n", 15071 stack); 15072 } 15073 if (ctxt->error != XPATH_EXPRESSION_OK) { 15074 xmlXPathFreeObject(res); 15075 res = NULL; 15076 } 15077 15078 xmlXPathFreeParserContext(ctxt); 15079 return(res); 15080} 15081 15082/** 15083 * xmlXPathEvalExpression: 15084 * @str: the XPath expression 15085 * @ctxt: the XPath context 15086 * 15087 * Evaluate the XPath expression in the given context. 15088 * 15089 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 15090 * the caller has to free the object. 15091 */ 15092xmlXPathObjectPtr 15093xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) { 15094 xmlXPathParserContextPtr pctxt; 15095 xmlXPathObjectPtr res, tmp; 15096 int stack = 0; 15097 15098 CHECK_CTXT(ctxt) 15099 15100 xmlXPathInit(); 15101 15102 pctxt = xmlXPathNewParserContext(str, ctxt); 15103 if (pctxt == NULL) 15104 return NULL; 15105 xmlXPathEvalExpr(pctxt); 15106 15107 if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) { 15108 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR); 15109 res = NULL; 15110 } else { 15111 res = valuePop(pctxt); 15112 } 15113 do { 15114 tmp = valuePop(pctxt); 15115 if (tmp != NULL) { 15116 xmlXPathReleaseObject(ctxt, tmp); 15117 stack++; 15118 } 15119 } while (tmp != NULL); 15120 if ((stack != 0) && (res != NULL)) { 15121 xmlGenericError(xmlGenericErrorContext, 15122 "xmlXPathEvalExpression: %d object left on the stack\n", 15123 stack); 15124 } 15125 xmlXPathFreeParserContext(pctxt); 15126 return(res); 15127} 15128 15129/************************************************************************ 15130 * * 15131 * Extra functions not pertaining to the XPath spec * 15132 * * 15133 ************************************************************************/ 15134/** 15135 * xmlXPathEscapeUriFunction: 15136 * @ctxt: the XPath Parser context 15137 * @nargs: the number of arguments 15138 * 15139 * Implement the escape-uri() XPath function 15140 * string escape-uri(string $str, bool $escape-reserved) 15141 * 15142 * This function applies the URI escaping rules defined in section 2 of [RFC 15143 * 2396] to the string supplied as $uri-part, which typically represents all 15144 * or part of a URI. The effect of the function is to replace any special 15145 * character in the string by an escape sequence of the form %xx%yy..., 15146 * where xxyy... is the hexadecimal representation of the octets used to 15147 * represent the character in UTF-8. 15148 * 15149 * The set of characters that are escaped depends on the setting of the 15150 * boolean argument $escape-reserved. 15151 * 15152 * If $escape-reserved is true, all characters are escaped other than lower 15153 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters 15154 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!" 15155 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only 15156 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and 15157 * A-F). 15158 * 15159 * If $escape-reserved is false, the behavior differs in that characters 15160 * referred to in [RFC 2396] as reserved characters are not escaped. These 15161 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",". 15162 * 15163 * [RFC 2396] does not define whether escaped URIs should use lower case or 15164 * upper case for hexadecimal digits. To ensure that escaped URIs can be 15165 * compared using string comparison functions, this function must always use 15166 * the upper-case letters A-F. 15167 * 15168 * Generally, $escape-reserved should be set to true when escaping a string 15169 * that is to form a single part of a URI, and to false when escaping an 15170 * entire URI or URI reference. 15171 * 15172 * In the case of non-ascii characters, the string is encoded according to 15173 * utf-8 and then converted according to RFC 2396. 15174 * 15175 * Examples 15176 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true()) 15177 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean" 15178 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false()) 15179 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean" 15180 * 15181 */ 15182static void 15183xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) { 15184 xmlXPathObjectPtr str; 15185 int escape_reserved; 15186 xmlBufPtr target; 15187 xmlChar *cptr; 15188 xmlChar escape[4]; 15189 15190 CHECK_ARITY(2); 15191 15192 escape_reserved = xmlXPathPopBoolean(ctxt); 15193 15194 CAST_TO_STRING; 15195 str = valuePop(ctxt); 15196 15197 target = xmlBufCreate(); 15198 15199 escape[0] = '%'; 15200 escape[3] = 0; 15201 15202 if (target) { 15203 for (cptr = str->stringval; *cptr; cptr++) { 15204 if ((*cptr >= 'A' && *cptr <= 'Z') || 15205 (*cptr >= 'a' && *cptr <= 'z') || 15206 (*cptr >= '0' && *cptr <= '9') || 15207 *cptr == '-' || *cptr == '_' || *cptr == '.' || 15208 *cptr == '!' || *cptr == '~' || *cptr == '*' || 15209 *cptr == '\''|| *cptr == '(' || *cptr == ')' || 15210 (*cptr == '%' && 15211 ((cptr[1] >= 'A' && cptr[1] <= 'F') || 15212 (cptr[1] >= 'a' && cptr[1] <= 'f') || 15213 (cptr[1] >= '0' && cptr[1] <= '9')) && 15214 ((cptr[2] >= 'A' && cptr[2] <= 'F') || 15215 (cptr[2] >= 'a' && cptr[2] <= 'f') || 15216 (cptr[2] >= '0' && cptr[2] <= '9'))) || 15217 (!escape_reserved && 15218 (*cptr == ';' || *cptr == '/' || *cptr == '?' || 15219 *cptr == ':' || *cptr == '@' || *cptr == '&' || 15220 *cptr == '=' || *cptr == '+' || *cptr == '$' || 15221 *cptr == ','))) { 15222 xmlBufAdd(target, cptr, 1); 15223 } else { 15224 if ((*cptr >> 4) < 10) 15225 escape[1] = '0' + (*cptr >> 4); 15226 else 15227 escape[1] = 'A' - 10 + (*cptr >> 4); 15228 if ((*cptr & 0xF) < 10) 15229 escape[2] = '0' + (*cptr & 0xF); 15230 else 15231 escape[2] = 'A' - 10 + (*cptr & 0xF); 15232 15233 xmlBufAdd(target, &escape[0], 3); 15234 } 15235 } 15236 } 15237 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 15238 xmlBufContent(target))); 15239 xmlBufFree(target); 15240 xmlXPathReleaseObject(ctxt->context, str); 15241} 15242 15243/** 15244 * xmlXPathRegisterAllFunctions: 15245 * @ctxt: the XPath context 15246 * 15247 * Registers all default XPath functions in this context 15248 */ 15249void 15250xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt) 15251{ 15252 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean", 15253 xmlXPathBooleanFunction); 15254 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling", 15255 xmlXPathCeilingFunction); 15256 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count", 15257 xmlXPathCountFunction); 15258 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat", 15259 xmlXPathConcatFunction); 15260 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains", 15261 xmlXPathContainsFunction); 15262 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id", 15263 xmlXPathIdFunction); 15264 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false", 15265 xmlXPathFalseFunction); 15266 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor", 15267 xmlXPathFloorFunction); 15268 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last", 15269 xmlXPathLastFunction); 15270 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang", 15271 xmlXPathLangFunction); 15272 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name", 15273 xmlXPathLocalNameFunction); 15274 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not", 15275 xmlXPathNotFunction); 15276 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name", 15277 xmlXPathNameFunction); 15278 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri", 15279 xmlXPathNamespaceURIFunction); 15280 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space", 15281 xmlXPathNormalizeFunction); 15282 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number", 15283 xmlXPathNumberFunction); 15284 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position", 15285 xmlXPathPositionFunction); 15286 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round", 15287 xmlXPathRoundFunction); 15288 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string", 15289 xmlXPathStringFunction); 15290 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length", 15291 xmlXPathStringLengthFunction); 15292 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with", 15293 xmlXPathStartsWithFunction); 15294 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring", 15295 xmlXPathSubstringFunction); 15296 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before", 15297 xmlXPathSubstringBeforeFunction); 15298 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after", 15299 xmlXPathSubstringAfterFunction); 15300 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum", 15301 xmlXPathSumFunction); 15302 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true", 15303 xmlXPathTrueFunction); 15304 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate", 15305 xmlXPathTranslateFunction); 15306 15307 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri", 15308 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions", 15309 xmlXPathEscapeUriFunction); 15310} 15311 15312#endif /* LIBXML_XPATH_ENABLED */ 15313#define bottom_xpath 15314#include "elfgcchack.h" 15315