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 /* To avoid EBCDIC trouble when parsing on zOS */ 18 #if defined(__MVS__) 19 #pragma convert("ISO8859-1") 20 #endif 21 22 #define IN_LIBXML 23 #include "libxml.h" 24 25 #include <limits.h> 26 #include <string.h> 27 #include <stddef.h> 28 29 #ifdef HAVE_SYS_TYPES_H 30 #include <sys/types.h> 31 #endif 32 #ifdef HAVE_MATH_H 33 #include <math.h> 34 #endif 35 #ifdef HAVE_FLOAT_H 36 #include <float.h> 37 #endif 38 #ifdef HAVE_CTYPE_H 39 #include <ctype.h> 40 #endif 41 #ifdef HAVE_SIGNAL_H 42 #include <signal.h> 43 #endif 44 45 #include <libxml/xmlmemory.h> 46 #include <libxml/tree.h> 47 #include <libxml/valid.h> 48 #include <libxml/xpath.h> 49 #include <libxml/xpathInternals.h> 50 #include <libxml/parserInternals.h> 51 #include <libxml/hash.h> 52 #ifdef LIBXML_XPTR_ENABLED 53 #include <libxml/xpointer.h> 54 #endif 55 #ifdef LIBXML_DEBUG_ENABLED 56 #include <libxml/debugXML.h> 57 #endif 58 #include <libxml/xmlerror.h> 59 #include <libxml/threads.h> 60 #include <libxml/globals.h> 61 #ifdef LIBXML_PATTERN_ENABLED 62 #include <libxml/pattern.h> 63 #endif 64 65 #include "buf.h" 66 67 #ifdef LIBXML_PATTERN_ENABLED 68 #define XPATH_STREAMING 69 #endif 70 71 #define TODO \ 72 xmlGenericError(xmlGenericErrorContext, \ 73 "Unimplemented block at %s:%d\n", \ 74 __FILE__, __LINE__); 75 76 /** 77 * WITH_TIM_SORT: 78 * 79 * Use the Timsort algorithm provided in timsort.h to sort 80 * nodeset as this is a great improvement over the old Shell sort 81 * used in xmlXPathNodeSetSort() 82 */ 83 #define WITH_TIM_SORT 84 85 /* 86 * XP_OPTIMIZED_NON_ELEM_COMPARISON: 87 * If defined, this will use xmlXPathCmpNodesExt() instead of 88 * xmlXPathCmpNodes(). The new function is optimized comparison of 89 * non-element nodes; actually it will speed up comparison only if 90 * xmlXPathOrderDocElems() was called in order to index the elements of 91 * a tree in document order; Libxslt does such an indexing, thus it will 92 * benefit from this optimization. 93 */ 94 #define XP_OPTIMIZED_NON_ELEM_COMPARISON 95 96 /* 97 * XP_OPTIMIZED_FILTER_FIRST: 98 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]" 99 * in a way, that it stop evaluation at the first node. 100 */ 101 #define XP_OPTIMIZED_FILTER_FIRST 102 103 /* 104 * XP_DEBUG_OBJ_USAGE: 105 * Internal flag to enable tracking of how much XPath objects have been 106 * created. 107 */ 108 /* #define XP_DEBUG_OBJ_USAGE */ 109 110 /* 111 * XPATH_MAX_STEPS: 112 * when compiling an XPath expression we arbitrary limit the maximum 113 * number of step operation in the compiled expression. 1000000 is 114 * an insanely large value which should never be reached under normal 115 * circumstances 116 */ 117 #define XPATH_MAX_STEPS 1000000 118 119 /* 120 * XPATH_MAX_STACK_DEPTH: 121 * when evaluating an XPath expression we arbitrary limit the maximum 122 * number of object allowed to be pushed on the stack. 1000000 is 123 * an insanely large value which should never be reached under normal 124 * circumstances 125 */ 126 #define XPATH_MAX_STACK_DEPTH 1000000 127 128 /* 129 * XPATH_MAX_NODESET_LENGTH: 130 * when evaluating an XPath expression nodesets are created and we 131 * arbitrary limit the maximum length of those node set. 10000000 is 132 * an insanely large value which should never be reached under normal 133 * circumstances, one would first need to construct an in memory tree 134 * with more than 10 millions nodes. 135 */ 136 #define XPATH_MAX_NODESET_LENGTH 10000000 137 138 /* 139 * TODO: 140 * There are a few spots where some tests are done which depend upon ascii 141 * data. These should be enhanced for full UTF8 support (see particularly 142 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT) 143 */ 144 145 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 146 /** 147 * xmlXPathCmpNodesExt: 148 * @node1: the first node 149 * @node2: the second node 150 * 151 * Compare two nodes w.r.t document order. 152 * This one is optimized for handling of non-element nodes. 153 * 154 * Returns -2 in case of error 1 if first point < second point, 0 if 155 * it's the same node, -1 otherwise 156 */ 157 static int 158 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) { 159 int depth1, depth2; 160 int misc = 0, precedence1 = 0, precedence2 = 0; 161 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL; 162 xmlNodePtr cur, root; 163 ptrdiff_t l1, l2; 164 165 if ((node1 == NULL) || (node2 == NULL)) 166 return(-2); 167 168 if (node1 == node2) 169 return(0); 170 171 /* 172 * a couple of optimizations which will avoid computations in most cases 173 */ 174 switch (node1->type) { 175 case XML_ELEMENT_NODE: 176 if (node2->type == XML_ELEMENT_NODE) { 177 if ((0 > (ptrdiff_t) node1->content) && 178 (0 > (ptrdiff_t) node2->content) && 179 (node1->doc == node2->doc)) 180 { 181 l1 = -((ptrdiff_t) node1->content); 182 l2 = -((ptrdiff_t) node2->content); 183 if (l1 < l2) 184 return(1); 185 if (l1 > l2) 186 return(-1); 187 } else 188 goto turtle_comparison; 189 } 190 break; 191 case XML_ATTRIBUTE_NODE: 192 precedence1 = 1; /* element is owner */ 193 miscNode1 = node1; 194 node1 = node1->parent; 195 misc = 1; 196 break; 197 case XML_TEXT_NODE: 198 case XML_CDATA_SECTION_NODE: 199 case XML_COMMENT_NODE: 200 case XML_PI_NODE: { 201 miscNode1 = node1; 202 /* 203 * Find nearest element node. 204 */ 205 if (node1->prev != NULL) { 206 do { 207 node1 = node1->prev; 208 if (node1->type == XML_ELEMENT_NODE) { 209 precedence1 = 3; /* element in prev-sibl axis */ 210 break; 211 } 212 if (node1->prev == NULL) { 213 precedence1 = 2; /* element is parent */ 214 /* 215 * URGENT TODO: Are there any cases, where the 216 * parent of such a node is not an element node? 217 */ 218 node1 = node1->parent; 219 break; 220 } 221 } while (1); 222 } else { 223 precedence1 = 2; /* element is parent */ 224 node1 = node1->parent; 225 } 226 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) || 227 (0 <= (ptrdiff_t) node1->content)) { 228 /* 229 * Fallback for whatever case. 230 */ 231 node1 = miscNode1; 232 precedence1 = 0; 233 } else 234 misc = 1; 235 } 236 break; 237 case XML_NAMESPACE_DECL: 238 /* 239 * TODO: why do we return 1 for namespace nodes? 240 */ 241 return(1); 242 default: 243 break; 244 } 245 switch (node2->type) { 246 case XML_ELEMENT_NODE: 247 break; 248 case XML_ATTRIBUTE_NODE: 249 precedence2 = 1; /* element is owner */ 250 miscNode2 = node2; 251 node2 = node2->parent; 252 misc = 1; 253 break; 254 case XML_TEXT_NODE: 255 case XML_CDATA_SECTION_NODE: 256 case XML_COMMENT_NODE: 257 case XML_PI_NODE: { 258 miscNode2 = node2; 259 if (node2->prev != NULL) { 260 do { 261 node2 = node2->prev; 262 if (node2->type == XML_ELEMENT_NODE) { 263 precedence2 = 3; /* element in prev-sibl axis */ 264 break; 265 } 266 if (node2->prev == NULL) { 267 precedence2 = 2; /* element is parent */ 268 node2 = node2->parent; 269 break; 270 } 271 } while (1); 272 } else { 273 precedence2 = 2; /* element is parent */ 274 node2 = node2->parent; 275 } 276 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) || 277 (0 <= (ptrdiff_t) node2->content)) 278 { 279 node2 = miscNode2; 280 precedence2 = 0; 281 } else 282 misc = 1; 283 } 284 break; 285 case XML_NAMESPACE_DECL: 286 return(1); 287 default: 288 break; 289 } 290 if (misc) { 291 if (node1 == node2) { 292 if (precedence1 == precedence2) { 293 /* 294 * The ugly case; but normally there aren't many 295 * adjacent non-element nodes around. 296 */ 297 cur = miscNode2->prev; 298 while (cur != NULL) { 299 if (cur == miscNode1) 300 return(1); 301 if (cur->type == XML_ELEMENT_NODE) 302 return(-1); 303 cur = cur->prev; 304 } 305 return (-1); 306 } else { 307 /* 308 * Evaluate based on higher precedence wrt to the element. 309 * TODO: This assumes attributes are sorted before content. 310 * Is this 100% correct? 311 */ 312 if (precedence1 < precedence2) 313 return(1); 314 else 315 return(-1); 316 } 317 } 318 /* 319 * Special case: One of the helper-elements is contained by the other. 320 * <foo> 321 * <node2> 322 * <node1>Text-1(precedence1 == 2)</node1> 323 * </node2> 324 * Text-6(precedence2 == 3) 325 * </foo> 326 */ 327 if ((precedence2 == 3) && (precedence1 > 1)) { 328 cur = node1->parent; 329 while (cur) { 330 if (cur == node2) 331 return(1); 332 cur = cur->parent; 333 } 334 } 335 if ((precedence1 == 3) && (precedence2 > 1)) { 336 cur = node2->parent; 337 while (cur) { 338 if (cur == node1) 339 return(-1); 340 cur = cur->parent; 341 } 342 } 343 } 344 345 /* 346 * Speedup using document order if availble. 347 */ 348 if ((node1->type == XML_ELEMENT_NODE) && 349 (node2->type == XML_ELEMENT_NODE) && 350 (0 > (ptrdiff_t) node1->content) && 351 (0 > (ptrdiff_t) node2->content) && 352 (node1->doc == node2->doc)) { 353 354 l1 = -((ptrdiff_t) node1->content); 355 l2 = -((ptrdiff_t) node2->content); 356 if (l1 < l2) 357 return(1); 358 if (l1 > l2) 359 return(-1); 360 } 361 362 turtle_comparison: 363 364 if (node1 == node2->prev) 365 return(1); 366 if (node1 == node2->next) 367 return(-1); 368 /* 369 * compute depth to root 370 */ 371 for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) { 372 if (cur->parent == node1) 373 return(1); 374 depth2++; 375 } 376 root = cur; 377 for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) { 378 if (cur->parent == node2) 379 return(-1); 380 depth1++; 381 } 382 /* 383 * Distinct document (or distinct entities :-( ) case. 384 */ 385 if (root != cur) { 386 return(-2); 387 } 388 /* 389 * get the nearest common ancestor. 390 */ 391 while (depth1 > depth2) { 392 depth1--; 393 node1 = node1->parent; 394 } 395 while (depth2 > depth1) { 396 depth2--; 397 node2 = node2->parent; 398 } 399 while (node1->parent != node2->parent) { 400 node1 = node1->parent; 401 node2 = node2->parent; 402 /* should not happen but just in case ... */ 403 if ((node1 == NULL) || (node2 == NULL)) 404 return(-2); 405 } 406 /* 407 * Find who's first. 408 */ 409 if (node1 == node2->prev) 410 return(1); 411 if (node1 == node2->next) 412 return(-1); 413 /* 414 * Speedup using document order if availble. 415 */ 416 if ((node1->type == XML_ELEMENT_NODE) && 417 (node2->type == XML_ELEMENT_NODE) && 418 (0 > (ptrdiff_t) node1->content) && 419 (0 > (ptrdiff_t) node2->content) && 420 (node1->doc == node2->doc)) { 421 422 l1 = -((ptrdiff_t) node1->content); 423 l2 = -((ptrdiff_t) node2->content); 424 if (l1 < l2) 425 return(1); 426 if (l1 > l2) 427 return(-1); 428 } 429 430 for (cur = node1->next;cur != NULL;cur = cur->next) 431 if (cur == node2) 432 return(1); 433 return(-1); /* assume there is no sibling list corruption */ 434 } 435 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */ 436 437 /* 438 * Wrapper for the Timsort argorithm from timsort.h 439 */ 440 #ifdef WITH_TIM_SORT 441 #define SORT_NAME libxml_domnode 442 #define SORT_TYPE xmlNodePtr 443 /** 444 * wrap_cmp: 445 * @x: a node 446 * @y: another node 447 * 448 * Comparison function for the Timsort implementation 449 * 450 * Returns -2 in case of error -1 if first point < second point, 0 if 451 * it's the same node, +1 otherwise 452 */ 453 static 454 int wrap_cmp( xmlNodePtr x, xmlNodePtr y ); 455 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 456 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y ) 457 { 458 int res = xmlXPathCmpNodesExt(x, y); 459 return res == -2 ? res : -res; 460 } 461 #else 462 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y ) 463 { 464 int res = xmlXPathCmpNodes(x, y); 465 return res == -2 ? res : -res; 466 } 467 #endif 468 #define SORT_CMP(x, y) (wrap_cmp(x, y)) 469 #include "timsort.h" 470 #endif /* WITH_TIM_SORT */ 471 472 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) 473 474 /************************************************************************ 475 * * 476 * Floating point stuff * 477 * * 478 ************************************************************************/ 479 480 #ifndef TRIO_REPLACE_STDIO 481 #define TRIO_PUBLIC static 482 #endif 483 #include "trionan.c" 484 485 /* 486 * The lack of portability of this section of the libc is annoying ! 487 */ 488 double xmlXPathNAN = 0; 489 double xmlXPathPINF = 1; 490 double xmlXPathNINF = -1; 491 static double xmlXPathNZERO = 0; /* not exported from headers */ 492 static int xmlXPathInitialized = 0; 493 494 /** 495 * xmlXPathInit: 496 * 497 * Initialize the XPath environment 498 */ 499 void 500 xmlXPathInit(void) { 501 if (xmlXPathInitialized) return; 502 503 xmlXPathPINF = trio_pinf(); 504 xmlXPathNINF = trio_ninf(); 505 xmlXPathNAN = trio_nan(); 506 xmlXPathNZERO = trio_nzero(); 507 508 xmlXPathInitialized = 1; 509 } 510 511 /** 512 * xmlXPathIsNaN: 513 * @val: a double value 514 * 515 * Provides a portable isnan() function to detect whether a double 516 * is a NotaNumber. Based on trio code 517 * http://sourceforge.net/projects/ctrio/ 518 * 519 * Returns 1 if the value is a NaN, 0 otherwise 520 */ 521 int 522 xmlXPathIsNaN(double val) { 523 return(trio_isnan(val)); 524 } 525 526 /** 527 * xmlXPathIsInf: 528 * @val: a double value 529 * 530 * Provides a portable isinf() function to detect whether a double 531 * is a +Infinite or -Infinite. Based on trio code 532 * http://sourceforge.net/projects/ctrio/ 533 * 534 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise 535 */ 536 int 537 xmlXPathIsInf(double val) { 538 return(trio_isinf(val)); 539 } 540 541 #endif /* SCHEMAS or XPATH */ 542 #ifdef LIBXML_XPATH_ENABLED 543 /** 544 * xmlXPathGetSign: 545 * @val: a double value 546 * 547 * Provides a portable function to detect the sign of a double 548 * Modified from trio code 549 * http://sourceforge.net/projects/ctrio/ 550 * 551 * Returns 1 if the value is Negative, 0 if positive 552 */ 553 static int 554 xmlXPathGetSign(double val) { 555 return(trio_signbit(val)); 556 } 557 558 559 /* 560 * TODO: when compatibility allows remove all "fake node libxslt" strings 561 * the test should just be name[0] = ' ' 562 */ 563 #ifdef DEBUG_XPATH_EXPRESSION 564 #define DEBUG_STEP 565 #define DEBUG_EXPR 566 #define DEBUG_EVAL_COUNTS 567 #endif 568 569 static xmlNs xmlXPathXMLNamespaceStruct = { 570 NULL, 571 XML_NAMESPACE_DECL, 572 XML_XML_NAMESPACE, 573 BAD_CAST "xml", 574 NULL, 575 NULL 576 }; 577 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct; 578 #ifndef LIBXML_THREAD_ENABLED 579 /* 580 * Optimizer is disabled only when threaded apps are detected while 581 * the library ain't compiled for thread safety. 582 */ 583 static int xmlXPathDisableOptimizer = 0; 584 #endif 585 586 /************************************************************************ 587 * * 588 * Error handling routines * 589 * * 590 ************************************************************************/ 591 592 /** 593 * XP_ERRORNULL: 594 * @X: the error code 595 * 596 * Macro to raise an XPath error and return NULL. 597 */ 598 #define XP_ERRORNULL(X) \ 599 { xmlXPathErr(ctxt, X); return(NULL); } 600 601 /* 602 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError 603 */ 604 static const char *xmlXPathErrorMessages[] = { 605 "Ok\n", 606 "Number encoding\n", 607 "Unfinished literal\n", 608 "Start of literal\n", 609 "Expected $ for variable reference\n", 610 "Undefined variable\n", 611 "Invalid predicate\n", 612 "Invalid expression\n", 613 "Missing closing curly brace\n", 614 "Unregistered function\n", 615 "Invalid operand\n", 616 "Invalid type\n", 617 "Invalid number of arguments\n", 618 "Invalid context size\n", 619 "Invalid context position\n", 620 "Memory allocation error\n", 621 "Syntax error\n", 622 "Resource error\n", 623 "Sub resource error\n", 624 "Undefined namespace prefix\n", 625 "Encoding error\n", 626 "Char out of XML range\n", 627 "Invalid or incomplete context\n", 628 "Stack usage error\n", 629 "Forbidden variable\n", 630 "?? Unknown error ??\n" /* Must be last in the list! */ 631 }; 632 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \ 633 sizeof(xmlXPathErrorMessages[0])) - 1) 634 /** 635 * xmlXPathErrMemory: 636 * @ctxt: an XPath context 637 * @extra: extra informations 638 * 639 * Handle a redefinition of attribute error 640 */ 641 static void 642 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra) 643 { 644 if (ctxt != NULL) { 645 if (extra) { 646 xmlChar buf[200]; 647 648 xmlStrPrintf(buf, 200, 649 "Memory allocation failed : %s\n", 650 extra); 651 ctxt->lastError.message = (char *) xmlStrdup(buf); 652 } else { 653 ctxt->lastError.message = (char *) 654 xmlStrdup(BAD_CAST "Memory allocation failed\n"); 655 } 656 ctxt->lastError.domain = XML_FROM_XPATH; 657 ctxt->lastError.code = XML_ERR_NO_MEMORY; 658 if (ctxt->error != NULL) 659 ctxt->error(ctxt->userData, &ctxt->lastError); 660 } else { 661 if (extra) 662 __xmlRaiseError(NULL, NULL, NULL, 663 NULL, NULL, XML_FROM_XPATH, 664 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, 665 extra, NULL, NULL, 0, 0, 666 "Memory allocation failed : %s\n", extra); 667 else 668 __xmlRaiseError(NULL, NULL, NULL, 669 NULL, NULL, XML_FROM_XPATH, 670 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, 671 NULL, NULL, NULL, 0, 0, 672 "Memory allocation failed\n"); 673 } 674 } 675 676 /** 677 * xmlXPathPErrMemory: 678 * @ctxt: an XPath parser context 679 * @extra: extra informations 680 * 681 * Handle a redefinition of attribute error 682 */ 683 static void 684 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra) 685 { 686 if (ctxt == NULL) 687 xmlXPathErrMemory(NULL, extra); 688 else { 689 ctxt->error = XPATH_MEMORY_ERROR; 690 xmlXPathErrMemory(ctxt->context, extra); 691 } 692 } 693 694 /** 695 * xmlXPathErr: 696 * @ctxt: a XPath parser context 697 * @error: the error code 698 * 699 * Handle an XPath error 700 */ 701 void 702 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error) 703 { 704 if ((error < 0) || (error > MAXERRNO)) 705 error = MAXERRNO; 706 if (ctxt == NULL) { 707 __xmlRaiseError(NULL, NULL, NULL, 708 NULL, NULL, XML_FROM_XPATH, 709 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, 710 XML_ERR_ERROR, NULL, 0, 711 NULL, NULL, NULL, 0, 0, 712 "%s", xmlXPathErrorMessages[error]); 713 return; 714 } 715 ctxt->error = error; 716 if (ctxt->context == NULL) { 717 __xmlRaiseError(NULL, NULL, NULL, 718 NULL, NULL, XML_FROM_XPATH, 719 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, 720 XML_ERR_ERROR, NULL, 0, 721 (const char *) ctxt->base, NULL, NULL, 722 ctxt->cur - ctxt->base, 0, 723 "%s", xmlXPathErrorMessages[error]); 724 return; 725 } 726 727 /* cleanup current last error */ 728 xmlResetError(&ctxt->context->lastError); 729 730 ctxt->context->lastError.domain = XML_FROM_XPATH; 731 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK - 732 XPATH_EXPRESSION_OK; 733 ctxt->context->lastError.level = XML_ERR_ERROR; 734 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base); 735 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base; 736 ctxt->context->lastError.node = ctxt->context->debugNode; 737 if (ctxt->context->error != NULL) { 738 ctxt->context->error(ctxt->context->userData, 739 &ctxt->context->lastError); 740 } else { 741 __xmlRaiseError(NULL, NULL, NULL, 742 NULL, ctxt->context->debugNode, XML_FROM_XPATH, 743 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, 744 XML_ERR_ERROR, NULL, 0, 745 (const char *) ctxt->base, NULL, NULL, 746 ctxt->cur - ctxt->base, 0, 747 "%s", xmlXPathErrorMessages[error]); 748 } 749 750 } 751 752 /** 753 * xmlXPatherror: 754 * @ctxt: the XPath Parser context 755 * @file: the file name 756 * @line: the line number 757 * @no: the error number 758 * 759 * Formats an error message. 760 */ 761 void 762 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED, 763 int line ATTRIBUTE_UNUSED, int no) { 764 xmlXPathErr(ctxt, no); 765 } 766 767 /************************************************************************ 768 * * 769 * Utilities * 770 * * 771 ************************************************************************/ 772 773 /** 774 * xsltPointerList: 775 * 776 * Pointer-list for various purposes. 777 */ 778 typedef struct _xmlPointerList xmlPointerList; 779 typedef xmlPointerList *xmlPointerListPtr; 780 struct _xmlPointerList { 781 void **items; 782 int number; 783 int size; 784 }; 785 /* 786 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt 787 * and here, we should make the functions public. 788 */ 789 static int 790 xmlPointerListAddSize(xmlPointerListPtr list, 791 void *item, 792 int initialSize) 793 { 794 if (list->items == NULL) { 795 if (initialSize <= 0) 796 initialSize = 1; 797 list->items = (void **) xmlMalloc(initialSize * sizeof(void *)); 798 if (list->items == NULL) { 799 xmlXPathErrMemory(NULL, 800 "xmlPointerListCreate: allocating item\n"); 801 return(-1); 802 } 803 list->number = 0; 804 list->size = initialSize; 805 } else if (list->size <= list->number) { 806 if (list->size > 50000000) { 807 xmlXPathErrMemory(NULL, 808 "xmlPointerListAddSize: re-allocating item\n"); 809 return(-1); 810 } 811 list->size *= 2; 812 list->items = (void **) xmlRealloc(list->items, 813 list->size * sizeof(void *)); 814 if (list->items == NULL) { 815 xmlXPathErrMemory(NULL, 816 "xmlPointerListAddSize: re-allocating item\n"); 817 list->size = 0; 818 return(-1); 819 } 820 } 821 list->items[list->number++] = item; 822 return(0); 823 } 824 825 /** 826 * xsltPointerListCreate: 827 * 828 * Creates an xsltPointerList structure. 829 * 830 * Returns a xsltPointerList structure or NULL in case of an error. 831 */ 832 static xmlPointerListPtr 833 xmlPointerListCreate(int initialSize) 834 { 835 xmlPointerListPtr ret; 836 837 ret = xmlMalloc(sizeof(xmlPointerList)); 838 if (ret == NULL) { 839 xmlXPathErrMemory(NULL, 840 "xmlPointerListCreate: allocating item\n"); 841 return (NULL); 842 } 843 memset(ret, 0, sizeof(xmlPointerList)); 844 if (initialSize > 0) { 845 xmlPointerListAddSize(ret, NULL, initialSize); 846 ret->number = 0; 847 } 848 return (ret); 849 } 850 851 /** 852 * xsltPointerListFree: 853 * 854 * Frees the xsltPointerList structure. This does not free 855 * the content of the list. 856 */ 857 static void 858 xmlPointerListFree(xmlPointerListPtr list) 859 { 860 if (list == NULL) 861 return; 862 if (list->items != NULL) 863 xmlFree(list->items); 864 xmlFree(list); 865 } 866 867 /************************************************************************ 868 * * 869 * Parser Types * 870 * * 871 ************************************************************************/ 872 873 /* 874 * Types are private: 875 */ 876 877 typedef enum { 878 XPATH_OP_END=0, 879 XPATH_OP_AND, 880 XPATH_OP_OR, 881 XPATH_OP_EQUAL, 882 XPATH_OP_CMP, 883 XPATH_OP_PLUS, 884 XPATH_OP_MULT, 885 XPATH_OP_UNION, 886 XPATH_OP_ROOT, 887 XPATH_OP_NODE, 888 XPATH_OP_RESET, /* 10 */ 889 XPATH_OP_COLLECT, 890 XPATH_OP_VALUE, /* 12 */ 891 XPATH_OP_VARIABLE, 892 XPATH_OP_FUNCTION, 893 XPATH_OP_ARG, 894 XPATH_OP_PREDICATE, 895 XPATH_OP_FILTER, /* 17 */ 896 XPATH_OP_SORT /* 18 */ 897 #ifdef LIBXML_XPTR_ENABLED 898 ,XPATH_OP_RANGETO 899 #endif 900 } xmlXPathOp; 901 902 typedef enum { 903 AXIS_ANCESTOR = 1, 904 AXIS_ANCESTOR_OR_SELF, 905 AXIS_ATTRIBUTE, 906 AXIS_CHILD, 907 AXIS_DESCENDANT, 908 AXIS_DESCENDANT_OR_SELF, 909 AXIS_FOLLOWING, 910 AXIS_FOLLOWING_SIBLING, 911 AXIS_NAMESPACE, 912 AXIS_PARENT, 913 AXIS_PRECEDING, 914 AXIS_PRECEDING_SIBLING, 915 AXIS_SELF 916 } xmlXPathAxisVal; 917 918 typedef enum { 919 NODE_TEST_NONE = 0, 920 NODE_TEST_TYPE = 1, 921 NODE_TEST_PI = 2, 922 NODE_TEST_ALL = 3, 923 NODE_TEST_NS = 4, 924 NODE_TEST_NAME = 5 925 } xmlXPathTestVal; 926 927 typedef enum { 928 NODE_TYPE_NODE = 0, 929 NODE_TYPE_COMMENT = XML_COMMENT_NODE, 930 NODE_TYPE_TEXT = XML_TEXT_NODE, 931 NODE_TYPE_PI = XML_PI_NODE 932 } xmlXPathTypeVal; 933 934 typedef struct _xmlXPathStepOp xmlXPathStepOp; 935 typedef xmlXPathStepOp *xmlXPathStepOpPtr; 936 struct _xmlXPathStepOp { 937 xmlXPathOp op; /* The identifier of the operation */ 938 int ch1; /* First child */ 939 int ch2; /* Second child */ 940 int value; 941 int value2; 942 int value3; 943 void *value4; 944 void *value5; 945 xmlXPathFunction cache; 946 void *cacheURI; 947 }; 948 949 struct _xmlXPathCompExpr { 950 int nbStep; /* Number of steps in this expression */ 951 int maxStep; /* Maximum number of steps allocated */ 952 xmlXPathStepOp *steps; /* ops for computation of this expression */ 953 int last; /* index of last step in expression */ 954 xmlChar *expr; /* the expression being computed */ 955 xmlDictPtr dict; /* the dictionary to use if any */ 956 #ifdef DEBUG_EVAL_COUNTS 957 int nb; 958 xmlChar *string; 959 #endif 960 #ifdef XPATH_STREAMING 961 xmlPatternPtr stream; 962 #endif 963 }; 964 965 /************************************************************************ 966 * * 967 * Forward declarations * 968 * * 969 ************************************************************************/ 970 static void 971 xmlXPathFreeValueTree(xmlNodeSetPtr obj); 972 static void 973 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj); 974 static int 975 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt, 976 xmlXPathStepOpPtr op, xmlNodePtr *first); 977 static int 978 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt, 979 xmlXPathStepOpPtr op, 980 int isPredicate); 981 982 /************************************************************************ 983 * * 984 * Parser Type functions * 985 * * 986 ************************************************************************/ 987 988 /** 989 * xmlXPathNewCompExpr: 990 * 991 * Create a new Xpath component 992 * 993 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error 994 */ 995 static xmlXPathCompExprPtr 996 xmlXPathNewCompExpr(void) { 997 xmlXPathCompExprPtr cur; 998 999 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr)); 1000 if (cur == NULL) { 1001 xmlXPathErrMemory(NULL, "allocating component\n"); 1002 return(NULL); 1003 } 1004 memset(cur, 0, sizeof(xmlXPathCompExpr)); 1005 cur->maxStep = 10; 1006 cur->nbStep = 0; 1007 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep * 1008 sizeof(xmlXPathStepOp)); 1009 if (cur->steps == NULL) { 1010 xmlXPathErrMemory(NULL, "allocating steps\n"); 1011 xmlFree(cur); 1012 return(NULL); 1013 } 1014 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp)); 1015 cur->last = -1; 1016 #ifdef DEBUG_EVAL_COUNTS 1017 cur->nb = 0; 1018 #endif 1019 return(cur); 1020 } 1021 1022 /** 1023 * xmlXPathFreeCompExpr: 1024 * @comp: an XPATH comp 1025 * 1026 * Free up the memory allocated by @comp 1027 */ 1028 void 1029 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp) 1030 { 1031 xmlXPathStepOpPtr op; 1032 int i; 1033 1034 if (comp == NULL) 1035 return; 1036 if (comp->dict == NULL) { 1037 for (i = 0; i < comp->nbStep; i++) { 1038 op = &comp->steps[i]; 1039 if (op->value4 != NULL) { 1040 if (op->op == XPATH_OP_VALUE) 1041 xmlXPathFreeObject(op->value4); 1042 else 1043 xmlFree(op->value4); 1044 } 1045 if (op->value5 != NULL) 1046 xmlFree(op->value5); 1047 } 1048 } else { 1049 for (i = 0; i < comp->nbStep; i++) { 1050 op = &comp->steps[i]; 1051 if (op->value4 != NULL) { 1052 if (op->op == XPATH_OP_VALUE) 1053 xmlXPathFreeObject(op->value4); 1054 } 1055 } 1056 xmlDictFree(comp->dict); 1057 } 1058 if (comp->steps != NULL) { 1059 xmlFree(comp->steps); 1060 } 1061 #ifdef DEBUG_EVAL_COUNTS 1062 if (comp->string != NULL) { 1063 xmlFree(comp->string); 1064 } 1065 #endif 1066 #ifdef XPATH_STREAMING 1067 if (comp->stream != NULL) { 1068 xmlFreePatternList(comp->stream); 1069 } 1070 #endif 1071 if (comp->expr != NULL) { 1072 xmlFree(comp->expr); 1073 } 1074 1075 xmlFree(comp); 1076 } 1077 1078 /** 1079 * xmlXPathCompExprAdd: 1080 * @comp: the compiled expression 1081 * @ch1: first child index 1082 * @ch2: second child index 1083 * @op: an op 1084 * @value: the first int value 1085 * @value2: the second int value 1086 * @value3: the third int value 1087 * @value4: the first string value 1088 * @value5: the second string value 1089 * 1090 * Add a step to an XPath Compiled Expression 1091 * 1092 * Returns -1 in case of failure, the index otherwise 1093 */ 1094 static int 1095 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2, 1096 xmlXPathOp op, int value, 1097 int value2, int value3, void *value4, void *value5) { 1098 if (comp->nbStep >= comp->maxStep) { 1099 xmlXPathStepOp *real; 1100 1101 if (comp->maxStep >= XPATH_MAX_STEPS) { 1102 xmlXPathErrMemory(NULL, "adding step\n"); 1103 return(-1); 1104 } 1105 comp->maxStep *= 2; 1106 real = (xmlXPathStepOp *) xmlRealloc(comp->steps, 1107 comp->maxStep * sizeof(xmlXPathStepOp)); 1108 if (real == NULL) { 1109 comp->maxStep /= 2; 1110 xmlXPathErrMemory(NULL, "adding step\n"); 1111 return(-1); 1112 } 1113 comp->steps = real; 1114 } 1115 comp->last = comp->nbStep; 1116 comp->steps[comp->nbStep].ch1 = ch1; 1117 comp->steps[comp->nbStep].ch2 = ch2; 1118 comp->steps[comp->nbStep].op = op; 1119 comp->steps[comp->nbStep].value = value; 1120 comp->steps[comp->nbStep].value2 = value2; 1121 comp->steps[comp->nbStep].value3 = value3; 1122 if ((comp->dict != NULL) && 1123 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) || 1124 (op == XPATH_OP_COLLECT))) { 1125 if (value4 != NULL) { 1126 comp->steps[comp->nbStep].value4 = (xmlChar *) 1127 (void *)xmlDictLookup(comp->dict, value4, -1); 1128 xmlFree(value4); 1129 } else 1130 comp->steps[comp->nbStep].value4 = NULL; 1131 if (value5 != NULL) { 1132 comp->steps[comp->nbStep].value5 = (xmlChar *) 1133 (void *)xmlDictLookup(comp->dict, value5, -1); 1134 xmlFree(value5); 1135 } else 1136 comp->steps[comp->nbStep].value5 = NULL; 1137 } else { 1138 comp->steps[comp->nbStep].value4 = value4; 1139 comp->steps[comp->nbStep].value5 = value5; 1140 } 1141 comp->steps[comp->nbStep].cache = NULL; 1142 return(comp->nbStep++); 1143 } 1144 1145 /** 1146 * xmlXPathCompSwap: 1147 * @comp: the compiled expression 1148 * @op: operation index 1149 * 1150 * Swaps 2 operations in the compiled expression 1151 */ 1152 static void 1153 xmlXPathCompSwap(xmlXPathStepOpPtr op) { 1154 int tmp; 1155 1156 #ifndef LIBXML_THREAD_ENABLED 1157 /* 1158 * Since this manipulates possibly shared variables, this is 1159 * disabled if one detects that the library is used in a multithreaded 1160 * application 1161 */ 1162 if (xmlXPathDisableOptimizer) 1163 return; 1164 #endif 1165 1166 tmp = op->ch1; 1167 op->ch1 = op->ch2; 1168 op->ch2 = tmp; 1169 } 1170 1171 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \ 1172 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \ 1173 (op), (val), (val2), (val3), (val4), (val5)) 1174 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \ 1175 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \ 1176 (op), (val), (val2), (val3), (val4), (val5)) 1177 1178 #define PUSH_LEAVE_EXPR(op, val, val2) \ 1179 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL) 1180 1181 #define PUSH_UNARY_EXPR(op, ch, val, val2) \ 1182 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL) 1183 1184 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \ 1185 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \ 1186 (val), (val2), 0 ,NULL ,NULL) 1187 1188 /************************************************************************ 1189 * * 1190 * XPath object cache structures * 1191 * * 1192 ************************************************************************/ 1193 1194 /* #define XP_DEFAULT_CACHE_ON */ 1195 1196 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL)) 1197 1198 typedef struct _xmlXPathContextCache xmlXPathContextCache; 1199 typedef xmlXPathContextCache *xmlXPathContextCachePtr; 1200 struct _xmlXPathContextCache { 1201 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */ 1202 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */ 1203 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */ 1204 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */ 1205 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */ 1206 int maxNodeset; 1207 int maxString; 1208 int maxBoolean; 1209 int maxNumber; 1210 int maxMisc; 1211 #ifdef XP_DEBUG_OBJ_USAGE 1212 int dbgCachedAll; 1213 int dbgCachedNodeset; 1214 int dbgCachedString; 1215 int dbgCachedBool; 1216 int dbgCachedNumber; 1217 int dbgCachedPoint; 1218 int dbgCachedRange; 1219 int dbgCachedLocset; 1220 int dbgCachedUsers; 1221 int dbgCachedXSLTTree; 1222 int dbgCachedUndefined; 1223 1224 1225 int dbgReusedAll; 1226 int dbgReusedNodeset; 1227 int dbgReusedString; 1228 int dbgReusedBool; 1229 int dbgReusedNumber; 1230 int dbgReusedPoint; 1231 int dbgReusedRange; 1232 int dbgReusedLocset; 1233 int dbgReusedUsers; 1234 int dbgReusedXSLTTree; 1235 int dbgReusedUndefined; 1236 1237 #endif 1238 }; 1239 1240 /************************************************************************ 1241 * * 1242 * Debugging related functions * 1243 * * 1244 ************************************************************************/ 1245 1246 #define STRANGE \ 1247 xmlGenericError(xmlGenericErrorContext, \ 1248 "Internal error at %s:%d\n", \ 1249 __FILE__, __LINE__); 1250 1251 #ifdef LIBXML_DEBUG_ENABLED 1252 static void 1253 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) { 1254 int i; 1255 char shift[100]; 1256 1257 for (i = 0;((i < depth) && (i < 25));i++) 1258 shift[2 * i] = shift[2 * i + 1] = ' '; 1259 shift[2 * i] = shift[2 * i + 1] = 0; 1260 if (cur == NULL) { 1261 fprintf(output, "%s", shift); 1262 fprintf(output, "Node is NULL !\n"); 1263 return; 1264 1265 } 1266 1267 if ((cur->type == XML_DOCUMENT_NODE) || 1268 (cur->type == XML_HTML_DOCUMENT_NODE)) { 1269 fprintf(output, "%s", shift); 1270 fprintf(output, " /\n"); 1271 } else if (cur->type == XML_ATTRIBUTE_NODE) 1272 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth); 1273 else 1274 xmlDebugDumpOneNode(output, cur, depth); 1275 } 1276 static void 1277 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) { 1278 xmlNodePtr tmp; 1279 int i; 1280 char shift[100]; 1281 1282 for (i = 0;((i < depth) && (i < 25));i++) 1283 shift[2 * i] = shift[2 * i + 1] = ' '; 1284 shift[2 * i] = shift[2 * i + 1] = 0; 1285 if (cur == NULL) { 1286 fprintf(output, "%s", shift); 1287 fprintf(output, "Node is NULL !\n"); 1288 return; 1289 1290 } 1291 1292 while (cur != NULL) { 1293 tmp = cur; 1294 cur = cur->next; 1295 xmlDebugDumpOneNode(output, tmp, depth); 1296 } 1297 } 1298 1299 static void 1300 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) { 1301 int i; 1302 char shift[100]; 1303 1304 for (i = 0;((i < depth) && (i < 25));i++) 1305 shift[2 * i] = shift[2 * i + 1] = ' '; 1306 shift[2 * i] = shift[2 * i + 1] = 0; 1307 1308 if (cur == NULL) { 1309 fprintf(output, "%s", shift); 1310 fprintf(output, "NodeSet is NULL !\n"); 1311 return; 1312 1313 } 1314 1315 if (cur != NULL) { 1316 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr); 1317 for (i = 0;i < cur->nodeNr;i++) { 1318 fprintf(output, "%s", shift); 1319 fprintf(output, "%d", i + 1); 1320 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1); 1321 } 1322 } 1323 } 1324 1325 static void 1326 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) { 1327 int i; 1328 char shift[100]; 1329 1330 for (i = 0;((i < depth) && (i < 25));i++) 1331 shift[2 * i] = shift[2 * i + 1] = ' '; 1332 shift[2 * i] = shift[2 * i + 1] = 0; 1333 1334 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) { 1335 fprintf(output, "%s", shift); 1336 fprintf(output, "Value Tree is NULL !\n"); 1337 return; 1338 1339 } 1340 1341 fprintf(output, "%s", shift); 1342 fprintf(output, "%d", i + 1); 1343 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1); 1344 } 1345 #if defined(LIBXML_XPTR_ENABLED) 1346 static void 1347 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) { 1348 int i; 1349 char shift[100]; 1350 1351 for (i = 0;((i < depth) && (i < 25));i++) 1352 shift[2 * i] = shift[2 * i + 1] = ' '; 1353 shift[2 * i] = shift[2 * i + 1] = 0; 1354 1355 if (cur == NULL) { 1356 fprintf(output, "%s", shift); 1357 fprintf(output, "LocationSet is NULL !\n"); 1358 return; 1359 1360 } 1361 1362 for (i = 0;i < cur->locNr;i++) { 1363 fprintf(output, "%s", shift); 1364 fprintf(output, "%d : ", i + 1); 1365 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1); 1366 } 1367 } 1368 #endif /* LIBXML_XPTR_ENABLED */ 1369 1370 /** 1371 * xmlXPathDebugDumpObject: 1372 * @output: the FILE * to dump the output 1373 * @cur: the object to inspect 1374 * @depth: indentation level 1375 * 1376 * Dump the content of the object for debugging purposes 1377 */ 1378 void 1379 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) { 1380 int i; 1381 char shift[100]; 1382 1383 if (output == NULL) return; 1384 1385 for (i = 0;((i < depth) && (i < 25));i++) 1386 shift[2 * i] = shift[2 * i + 1] = ' '; 1387 shift[2 * i] = shift[2 * i + 1] = 0; 1388 1389 1390 fprintf(output, "%s", shift); 1391 1392 if (cur == NULL) { 1393 fprintf(output, "Object is empty (NULL)\n"); 1394 return; 1395 } 1396 switch(cur->type) { 1397 case XPATH_UNDEFINED: 1398 fprintf(output, "Object is uninitialized\n"); 1399 break; 1400 case XPATH_NODESET: 1401 fprintf(output, "Object is a Node Set :\n"); 1402 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth); 1403 break; 1404 case XPATH_XSLT_TREE: 1405 fprintf(output, "Object is an XSLT value tree :\n"); 1406 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth); 1407 break; 1408 case XPATH_BOOLEAN: 1409 fprintf(output, "Object is a Boolean : "); 1410 if (cur->boolval) fprintf(output, "true\n"); 1411 else fprintf(output, "false\n"); 1412 break; 1413 case XPATH_NUMBER: 1414 switch (xmlXPathIsInf(cur->floatval)) { 1415 case 1: 1416 fprintf(output, "Object is a number : Infinity\n"); 1417 break; 1418 case -1: 1419 fprintf(output, "Object is a number : -Infinity\n"); 1420 break; 1421 default: 1422 if (xmlXPathIsNaN(cur->floatval)) { 1423 fprintf(output, "Object is a number : NaN\n"); 1424 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) { 1425 fprintf(output, "Object is a number : 0\n"); 1426 } else { 1427 fprintf(output, "Object is a number : %0g\n", cur->floatval); 1428 } 1429 } 1430 break; 1431 case XPATH_STRING: 1432 fprintf(output, "Object is a string : "); 1433 xmlDebugDumpString(output, cur->stringval); 1434 fprintf(output, "\n"); 1435 break; 1436 case XPATH_POINT: 1437 fprintf(output, "Object is a point : index %d in node", cur->index); 1438 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1); 1439 fprintf(output, "\n"); 1440 break; 1441 case XPATH_RANGE: 1442 if ((cur->user2 == NULL) || 1443 ((cur->user2 == cur->user) && (cur->index == cur->index2))) { 1444 fprintf(output, "Object is a collapsed range :\n"); 1445 fprintf(output, "%s", shift); 1446 if (cur->index >= 0) 1447 fprintf(output, "index %d in ", cur->index); 1448 fprintf(output, "node\n"); 1449 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, 1450 depth + 1); 1451 } else { 1452 fprintf(output, "Object is a range :\n"); 1453 fprintf(output, "%s", shift); 1454 fprintf(output, "From "); 1455 if (cur->index >= 0) 1456 fprintf(output, "index %d in ", cur->index); 1457 fprintf(output, "node\n"); 1458 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, 1459 depth + 1); 1460 fprintf(output, "%s", shift); 1461 fprintf(output, "To "); 1462 if (cur->index2 >= 0) 1463 fprintf(output, "index %d in ", cur->index2); 1464 fprintf(output, "node\n"); 1465 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2, 1466 depth + 1); 1467 fprintf(output, "\n"); 1468 } 1469 break; 1470 case XPATH_LOCATIONSET: 1471 #if defined(LIBXML_XPTR_ENABLED) 1472 fprintf(output, "Object is a Location Set:\n"); 1473 xmlXPathDebugDumpLocationSet(output, 1474 (xmlLocationSetPtr) cur->user, depth); 1475 #endif 1476 break; 1477 case XPATH_USERS: 1478 fprintf(output, "Object is user defined\n"); 1479 break; 1480 } 1481 } 1482 1483 static void 1484 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp, 1485 xmlXPathStepOpPtr op, int depth) { 1486 int i; 1487 char shift[100]; 1488 1489 for (i = 0;((i < depth) && (i < 25));i++) 1490 shift[2 * i] = shift[2 * i + 1] = ' '; 1491 shift[2 * i] = shift[2 * i + 1] = 0; 1492 1493 fprintf(output, "%s", shift); 1494 if (op == NULL) { 1495 fprintf(output, "Step is NULL\n"); 1496 return; 1497 } 1498 switch (op->op) { 1499 case XPATH_OP_END: 1500 fprintf(output, "END"); break; 1501 case XPATH_OP_AND: 1502 fprintf(output, "AND"); break; 1503 case XPATH_OP_OR: 1504 fprintf(output, "OR"); break; 1505 case XPATH_OP_EQUAL: 1506 if (op->value) 1507 fprintf(output, "EQUAL ="); 1508 else 1509 fprintf(output, "EQUAL !="); 1510 break; 1511 case XPATH_OP_CMP: 1512 if (op->value) 1513 fprintf(output, "CMP <"); 1514 else 1515 fprintf(output, "CMP >"); 1516 if (!op->value2) 1517 fprintf(output, "="); 1518 break; 1519 case XPATH_OP_PLUS: 1520 if (op->value == 0) 1521 fprintf(output, "PLUS -"); 1522 else if (op->value == 1) 1523 fprintf(output, "PLUS +"); 1524 else if (op->value == 2) 1525 fprintf(output, "PLUS unary -"); 1526 else if (op->value == 3) 1527 fprintf(output, "PLUS unary - -"); 1528 break; 1529 case XPATH_OP_MULT: 1530 if (op->value == 0) 1531 fprintf(output, "MULT *"); 1532 else if (op->value == 1) 1533 fprintf(output, "MULT div"); 1534 else 1535 fprintf(output, "MULT mod"); 1536 break; 1537 case XPATH_OP_UNION: 1538 fprintf(output, "UNION"); break; 1539 case XPATH_OP_ROOT: 1540 fprintf(output, "ROOT"); break; 1541 case XPATH_OP_NODE: 1542 fprintf(output, "NODE"); break; 1543 case XPATH_OP_RESET: 1544 fprintf(output, "RESET"); break; 1545 case XPATH_OP_SORT: 1546 fprintf(output, "SORT"); break; 1547 case XPATH_OP_COLLECT: { 1548 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value; 1549 xmlXPathTestVal test = (xmlXPathTestVal)op->value2; 1550 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3; 1551 const xmlChar *prefix = op->value4; 1552 const xmlChar *name = op->value5; 1553 1554 fprintf(output, "COLLECT "); 1555 switch (axis) { 1556 case AXIS_ANCESTOR: 1557 fprintf(output, " 'ancestors' "); break; 1558 case AXIS_ANCESTOR_OR_SELF: 1559 fprintf(output, " 'ancestors-or-self' "); break; 1560 case AXIS_ATTRIBUTE: 1561 fprintf(output, " 'attributes' "); break; 1562 case AXIS_CHILD: 1563 fprintf(output, " 'child' "); break; 1564 case AXIS_DESCENDANT: 1565 fprintf(output, " 'descendant' "); break; 1566 case AXIS_DESCENDANT_OR_SELF: 1567 fprintf(output, " 'descendant-or-self' "); break; 1568 case AXIS_FOLLOWING: 1569 fprintf(output, " 'following' "); break; 1570 case AXIS_FOLLOWING_SIBLING: 1571 fprintf(output, " 'following-siblings' "); break; 1572 case AXIS_NAMESPACE: 1573 fprintf(output, " 'namespace' "); break; 1574 case AXIS_PARENT: 1575 fprintf(output, " 'parent' "); break; 1576 case AXIS_PRECEDING: 1577 fprintf(output, " 'preceding' "); break; 1578 case AXIS_PRECEDING_SIBLING: 1579 fprintf(output, " 'preceding-sibling' "); break; 1580 case AXIS_SELF: 1581 fprintf(output, " 'self' "); break; 1582 } 1583 switch (test) { 1584 case NODE_TEST_NONE: 1585 fprintf(output, "'none' "); break; 1586 case NODE_TEST_TYPE: 1587 fprintf(output, "'type' "); break; 1588 case NODE_TEST_PI: 1589 fprintf(output, "'PI' "); break; 1590 case NODE_TEST_ALL: 1591 fprintf(output, "'all' "); break; 1592 case NODE_TEST_NS: 1593 fprintf(output, "'namespace' "); break; 1594 case NODE_TEST_NAME: 1595 fprintf(output, "'name' "); break; 1596 } 1597 switch (type) { 1598 case NODE_TYPE_NODE: 1599 fprintf(output, "'node' "); break; 1600 case NODE_TYPE_COMMENT: 1601 fprintf(output, "'comment' "); break; 1602 case NODE_TYPE_TEXT: 1603 fprintf(output, "'text' "); break; 1604 case NODE_TYPE_PI: 1605 fprintf(output, "'PI' "); break; 1606 } 1607 if (prefix != NULL) 1608 fprintf(output, "%s:", prefix); 1609 if (name != NULL) 1610 fprintf(output, "%s", (const char *) name); 1611 break; 1612 1613 } 1614 case XPATH_OP_VALUE: { 1615 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4; 1616 1617 fprintf(output, "ELEM "); 1618 xmlXPathDebugDumpObject(output, object, 0); 1619 goto finish; 1620 } 1621 case XPATH_OP_VARIABLE: { 1622 const xmlChar *prefix = op->value5; 1623 const xmlChar *name = op->value4; 1624 1625 if (prefix != NULL) 1626 fprintf(output, "VARIABLE %s:%s", prefix, name); 1627 else 1628 fprintf(output, "VARIABLE %s", name); 1629 break; 1630 } 1631 case XPATH_OP_FUNCTION: { 1632 int nbargs = op->value; 1633 const xmlChar *prefix = op->value5; 1634 const xmlChar *name = op->value4; 1635 1636 if (prefix != NULL) 1637 fprintf(output, "FUNCTION %s:%s(%d args)", 1638 prefix, name, nbargs); 1639 else 1640 fprintf(output, "FUNCTION %s(%d args)", name, nbargs); 1641 break; 1642 } 1643 case XPATH_OP_ARG: fprintf(output, "ARG"); break; 1644 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break; 1645 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break; 1646 #ifdef LIBXML_XPTR_ENABLED 1647 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break; 1648 #endif 1649 default: 1650 fprintf(output, "UNKNOWN %d\n", op->op); return; 1651 } 1652 fprintf(output, "\n"); 1653 finish: 1654 if (op->ch1 >= 0) 1655 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1); 1656 if (op->ch2 >= 0) 1657 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1); 1658 } 1659 1660 /** 1661 * xmlXPathDebugDumpCompExpr: 1662 * @output: the FILE * for the output 1663 * @comp: the precompiled XPath expression 1664 * @depth: the indentation level. 1665 * 1666 * Dumps the tree of the compiled XPath expression. 1667 */ 1668 void 1669 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp, 1670 int depth) { 1671 int i; 1672 char shift[100]; 1673 1674 if ((output == NULL) || (comp == NULL)) return; 1675 1676 for (i = 0;((i < depth) && (i < 25));i++) 1677 shift[2 * i] = shift[2 * i + 1] = ' '; 1678 shift[2 * i] = shift[2 * i + 1] = 0; 1679 1680 fprintf(output, "%s", shift); 1681 1682 #ifdef XPATH_STREAMING 1683 if (comp->stream) { 1684 fprintf(output, "Streaming Expression\n"); 1685 } else 1686 #endif 1687 { 1688 fprintf(output, "Compiled Expression : %d elements\n", 1689 comp->nbStep); 1690 i = comp->last; 1691 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1); 1692 } 1693 } 1694 1695 #ifdef XP_DEBUG_OBJ_USAGE 1696 1697 /* 1698 * XPath object usage related debugging variables. 1699 */ 1700 static int xmlXPathDebugObjCounterUndefined = 0; 1701 static int xmlXPathDebugObjCounterNodeset = 0; 1702 static int xmlXPathDebugObjCounterBool = 0; 1703 static int xmlXPathDebugObjCounterNumber = 0; 1704 static int xmlXPathDebugObjCounterString = 0; 1705 static int xmlXPathDebugObjCounterPoint = 0; 1706 static int xmlXPathDebugObjCounterRange = 0; 1707 static int xmlXPathDebugObjCounterLocset = 0; 1708 static int xmlXPathDebugObjCounterUsers = 0; 1709 static int xmlXPathDebugObjCounterXSLTTree = 0; 1710 static int xmlXPathDebugObjCounterAll = 0; 1711 1712 static int xmlXPathDebugObjTotalUndefined = 0; 1713 static int xmlXPathDebugObjTotalNodeset = 0; 1714 static int xmlXPathDebugObjTotalBool = 0; 1715 static int xmlXPathDebugObjTotalNumber = 0; 1716 static int xmlXPathDebugObjTotalString = 0; 1717 static int xmlXPathDebugObjTotalPoint = 0; 1718 static int xmlXPathDebugObjTotalRange = 0; 1719 static int xmlXPathDebugObjTotalLocset = 0; 1720 static int xmlXPathDebugObjTotalUsers = 0; 1721 static int xmlXPathDebugObjTotalXSLTTree = 0; 1722 static int xmlXPathDebugObjTotalAll = 0; 1723 1724 static int xmlXPathDebugObjMaxUndefined = 0; 1725 static int xmlXPathDebugObjMaxNodeset = 0; 1726 static int xmlXPathDebugObjMaxBool = 0; 1727 static int xmlXPathDebugObjMaxNumber = 0; 1728 static int xmlXPathDebugObjMaxString = 0; 1729 static int xmlXPathDebugObjMaxPoint = 0; 1730 static int xmlXPathDebugObjMaxRange = 0; 1731 static int xmlXPathDebugObjMaxLocset = 0; 1732 static int xmlXPathDebugObjMaxUsers = 0; 1733 static int xmlXPathDebugObjMaxXSLTTree = 0; 1734 static int xmlXPathDebugObjMaxAll = 0; 1735 1736 /* REVISIT TODO: Make this static when committing */ 1737 static void 1738 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt) 1739 { 1740 if (ctxt != NULL) { 1741 if (ctxt->cache != NULL) { 1742 xmlXPathContextCachePtr cache = 1743 (xmlXPathContextCachePtr) ctxt->cache; 1744 1745 cache->dbgCachedAll = 0; 1746 cache->dbgCachedNodeset = 0; 1747 cache->dbgCachedString = 0; 1748 cache->dbgCachedBool = 0; 1749 cache->dbgCachedNumber = 0; 1750 cache->dbgCachedPoint = 0; 1751 cache->dbgCachedRange = 0; 1752 cache->dbgCachedLocset = 0; 1753 cache->dbgCachedUsers = 0; 1754 cache->dbgCachedXSLTTree = 0; 1755 cache->dbgCachedUndefined = 0; 1756 1757 cache->dbgReusedAll = 0; 1758 cache->dbgReusedNodeset = 0; 1759 cache->dbgReusedString = 0; 1760 cache->dbgReusedBool = 0; 1761 cache->dbgReusedNumber = 0; 1762 cache->dbgReusedPoint = 0; 1763 cache->dbgReusedRange = 0; 1764 cache->dbgReusedLocset = 0; 1765 cache->dbgReusedUsers = 0; 1766 cache->dbgReusedXSLTTree = 0; 1767 cache->dbgReusedUndefined = 0; 1768 } 1769 } 1770 1771 xmlXPathDebugObjCounterUndefined = 0; 1772 xmlXPathDebugObjCounterNodeset = 0; 1773 xmlXPathDebugObjCounterBool = 0; 1774 xmlXPathDebugObjCounterNumber = 0; 1775 xmlXPathDebugObjCounterString = 0; 1776 xmlXPathDebugObjCounterPoint = 0; 1777 xmlXPathDebugObjCounterRange = 0; 1778 xmlXPathDebugObjCounterLocset = 0; 1779 xmlXPathDebugObjCounterUsers = 0; 1780 xmlXPathDebugObjCounterXSLTTree = 0; 1781 xmlXPathDebugObjCounterAll = 0; 1782 1783 xmlXPathDebugObjTotalUndefined = 0; 1784 xmlXPathDebugObjTotalNodeset = 0; 1785 xmlXPathDebugObjTotalBool = 0; 1786 xmlXPathDebugObjTotalNumber = 0; 1787 xmlXPathDebugObjTotalString = 0; 1788 xmlXPathDebugObjTotalPoint = 0; 1789 xmlXPathDebugObjTotalRange = 0; 1790 xmlXPathDebugObjTotalLocset = 0; 1791 xmlXPathDebugObjTotalUsers = 0; 1792 xmlXPathDebugObjTotalXSLTTree = 0; 1793 xmlXPathDebugObjTotalAll = 0; 1794 1795 xmlXPathDebugObjMaxUndefined = 0; 1796 xmlXPathDebugObjMaxNodeset = 0; 1797 xmlXPathDebugObjMaxBool = 0; 1798 xmlXPathDebugObjMaxNumber = 0; 1799 xmlXPathDebugObjMaxString = 0; 1800 xmlXPathDebugObjMaxPoint = 0; 1801 xmlXPathDebugObjMaxRange = 0; 1802 xmlXPathDebugObjMaxLocset = 0; 1803 xmlXPathDebugObjMaxUsers = 0; 1804 xmlXPathDebugObjMaxXSLTTree = 0; 1805 xmlXPathDebugObjMaxAll = 0; 1806 1807 } 1808 1809 static void 1810 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt, 1811 xmlXPathObjectType objType) 1812 { 1813 int isCached = 0; 1814 1815 if (ctxt != NULL) { 1816 if (ctxt->cache != NULL) { 1817 xmlXPathContextCachePtr cache = 1818 (xmlXPathContextCachePtr) ctxt->cache; 1819 1820 isCached = 1; 1821 1822 cache->dbgReusedAll++; 1823 switch (objType) { 1824 case XPATH_UNDEFINED: 1825 cache->dbgReusedUndefined++; 1826 break; 1827 case XPATH_NODESET: 1828 cache->dbgReusedNodeset++; 1829 break; 1830 case XPATH_BOOLEAN: 1831 cache->dbgReusedBool++; 1832 break; 1833 case XPATH_NUMBER: 1834 cache->dbgReusedNumber++; 1835 break; 1836 case XPATH_STRING: 1837 cache->dbgReusedString++; 1838 break; 1839 case XPATH_POINT: 1840 cache->dbgReusedPoint++; 1841 break; 1842 case XPATH_RANGE: 1843 cache->dbgReusedRange++; 1844 break; 1845 case XPATH_LOCATIONSET: 1846 cache->dbgReusedLocset++; 1847 break; 1848 case XPATH_USERS: 1849 cache->dbgReusedUsers++; 1850 break; 1851 case XPATH_XSLT_TREE: 1852 cache->dbgReusedXSLTTree++; 1853 break; 1854 default: 1855 break; 1856 } 1857 } 1858 } 1859 1860 switch (objType) { 1861 case XPATH_UNDEFINED: 1862 if (! isCached) 1863 xmlXPathDebugObjTotalUndefined++; 1864 xmlXPathDebugObjCounterUndefined++; 1865 if (xmlXPathDebugObjCounterUndefined > 1866 xmlXPathDebugObjMaxUndefined) 1867 xmlXPathDebugObjMaxUndefined = 1868 xmlXPathDebugObjCounterUndefined; 1869 break; 1870 case XPATH_NODESET: 1871 if (! isCached) 1872 xmlXPathDebugObjTotalNodeset++; 1873 xmlXPathDebugObjCounterNodeset++; 1874 if (xmlXPathDebugObjCounterNodeset > 1875 xmlXPathDebugObjMaxNodeset) 1876 xmlXPathDebugObjMaxNodeset = 1877 xmlXPathDebugObjCounterNodeset; 1878 break; 1879 case XPATH_BOOLEAN: 1880 if (! isCached) 1881 xmlXPathDebugObjTotalBool++; 1882 xmlXPathDebugObjCounterBool++; 1883 if (xmlXPathDebugObjCounterBool > 1884 xmlXPathDebugObjMaxBool) 1885 xmlXPathDebugObjMaxBool = 1886 xmlXPathDebugObjCounterBool; 1887 break; 1888 case XPATH_NUMBER: 1889 if (! isCached) 1890 xmlXPathDebugObjTotalNumber++; 1891 xmlXPathDebugObjCounterNumber++; 1892 if (xmlXPathDebugObjCounterNumber > 1893 xmlXPathDebugObjMaxNumber) 1894 xmlXPathDebugObjMaxNumber = 1895 xmlXPathDebugObjCounterNumber; 1896 break; 1897 case XPATH_STRING: 1898 if (! isCached) 1899 xmlXPathDebugObjTotalString++; 1900 xmlXPathDebugObjCounterString++; 1901 if (xmlXPathDebugObjCounterString > 1902 xmlXPathDebugObjMaxString) 1903 xmlXPathDebugObjMaxString = 1904 xmlXPathDebugObjCounterString; 1905 break; 1906 case XPATH_POINT: 1907 if (! isCached) 1908 xmlXPathDebugObjTotalPoint++; 1909 xmlXPathDebugObjCounterPoint++; 1910 if (xmlXPathDebugObjCounterPoint > 1911 xmlXPathDebugObjMaxPoint) 1912 xmlXPathDebugObjMaxPoint = 1913 xmlXPathDebugObjCounterPoint; 1914 break; 1915 case XPATH_RANGE: 1916 if (! isCached) 1917 xmlXPathDebugObjTotalRange++; 1918 xmlXPathDebugObjCounterRange++; 1919 if (xmlXPathDebugObjCounterRange > 1920 xmlXPathDebugObjMaxRange) 1921 xmlXPathDebugObjMaxRange = 1922 xmlXPathDebugObjCounterRange; 1923 break; 1924 case XPATH_LOCATIONSET: 1925 if (! isCached) 1926 xmlXPathDebugObjTotalLocset++; 1927 xmlXPathDebugObjCounterLocset++; 1928 if (xmlXPathDebugObjCounterLocset > 1929 xmlXPathDebugObjMaxLocset) 1930 xmlXPathDebugObjMaxLocset = 1931 xmlXPathDebugObjCounterLocset; 1932 break; 1933 case XPATH_USERS: 1934 if (! isCached) 1935 xmlXPathDebugObjTotalUsers++; 1936 xmlXPathDebugObjCounterUsers++; 1937 if (xmlXPathDebugObjCounterUsers > 1938 xmlXPathDebugObjMaxUsers) 1939 xmlXPathDebugObjMaxUsers = 1940 xmlXPathDebugObjCounterUsers; 1941 break; 1942 case XPATH_XSLT_TREE: 1943 if (! isCached) 1944 xmlXPathDebugObjTotalXSLTTree++; 1945 xmlXPathDebugObjCounterXSLTTree++; 1946 if (xmlXPathDebugObjCounterXSLTTree > 1947 xmlXPathDebugObjMaxXSLTTree) 1948 xmlXPathDebugObjMaxXSLTTree = 1949 xmlXPathDebugObjCounterXSLTTree; 1950 break; 1951 default: 1952 break; 1953 } 1954 if (! isCached) 1955 xmlXPathDebugObjTotalAll++; 1956 xmlXPathDebugObjCounterAll++; 1957 if (xmlXPathDebugObjCounterAll > 1958 xmlXPathDebugObjMaxAll) 1959 xmlXPathDebugObjMaxAll = 1960 xmlXPathDebugObjCounterAll; 1961 } 1962 1963 static void 1964 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt, 1965 xmlXPathObjectType objType) 1966 { 1967 int isCached = 0; 1968 1969 if (ctxt != NULL) { 1970 if (ctxt->cache != NULL) { 1971 xmlXPathContextCachePtr cache = 1972 (xmlXPathContextCachePtr) ctxt->cache; 1973 1974 isCached = 1; 1975 1976 cache->dbgCachedAll++; 1977 switch (objType) { 1978 case XPATH_UNDEFINED: 1979 cache->dbgCachedUndefined++; 1980 break; 1981 case XPATH_NODESET: 1982 cache->dbgCachedNodeset++; 1983 break; 1984 case XPATH_BOOLEAN: 1985 cache->dbgCachedBool++; 1986 break; 1987 case XPATH_NUMBER: 1988 cache->dbgCachedNumber++; 1989 break; 1990 case XPATH_STRING: 1991 cache->dbgCachedString++; 1992 break; 1993 case XPATH_POINT: 1994 cache->dbgCachedPoint++; 1995 break; 1996 case XPATH_RANGE: 1997 cache->dbgCachedRange++; 1998 break; 1999 case XPATH_LOCATIONSET: 2000 cache->dbgCachedLocset++; 2001 break; 2002 case XPATH_USERS: 2003 cache->dbgCachedUsers++; 2004 break; 2005 case XPATH_XSLT_TREE: 2006 cache->dbgCachedXSLTTree++; 2007 break; 2008 default: 2009 break; 2010 } 2011 2012 } 2013 } 2014 switch (objType) { 2015 case XPATH_UNDEFINED: 2016 xmlXPathDebugObjCounterUndefined--; 2017 break; 2018 case XPATH_NODESET: 2019 xmlXPathDebugObjCounterNodeset--; 2020 break; 2021 case XPATH_BOOLEAN: 2022 xmlXPathDebugObjCounterBool--; 2023 break; 2024 case XPATH_NUMBER: 2025 xmlXPathDebugObjCounterNumber--; 2026 break; 2027 case XPATH_STRING: 2028 xmlXPathDebugObjCounterString--; 2029 break; 2030 case XPATH_POINT: 2031 xmlXPathDebugObjCounterPoint--; 2032 break; 2033 case XPATH_RANGE: 2034 xmlXPathDebugObjCounterRange--; 2035 break; 2036 case XPATH_LOCATIONSET: 2037 xmlXPathDebugObjCounterLocset--; 2038 break; 2039 case XPATH_USERS: 2040 xmlXPathDebugObjCounterUsers--; 2041 break; 2042 case XPATH_XSLT_TREE: 2043 xmlXPathDebugObjCounterXSLTTree--; 2044 break; 2045 default: 2046 break; 2047 } 2048 xmlXPathDebugObjCounterAll--; 2049 } 2050 2051 /* REVISIT TODO: Make this static when committing */ 2052 static void 2053 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt) 2054 { 2055 int reqAll, reqNodeset, reqString, reqBool, reqNumber, 2056 reqXSLTTree, reqUndefined; 2057 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0, 2058 caNumber = 0, caXSLTTree = 0, caUndefined = 0; 2059 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0, 2060 reNumber = 0, reXSLTTree = 0, reUndefined = 0; 2061 int leftObjs = xmlXPathDebugObjCounterAll; 2062 2063 reqAll = xmlXPathDebugObjTotalAll; 2064 reqNodeset = xmlXPathDebugObjTotalNodeset; 2065 reqString = xmlXPathDebugObjTotalString; 2066 reqBool = xmlXPathDebugObjTotalBool; 2067 reqNumber = xmlXPathDebugObjTotalNumber; 2068 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree; 2069 reqUndefined = xmlXPathDebugObjTotalUndefined; 2070 2071 printf("# XPath object usage:\n"); 2072 2073 if (ctxt != NULL) { 2074 if (ctxt->cache != NULL) { 2075 xmlXPathContextCachePtr cache = 2076 (xmlXPathContextCachePtr) ctxt->cache; 2077 2078 reAll = cache->dbgReusedAll; 2079 reqAll += reAll; 2080 reNodeset = cache->dbgReusedNodeset; 2081 reqNodeset += reNodeset; 2082 reString = cache->dbgReusedString; 2083 reqString += reString; 2084 reBool = cache->dbgReusedBool; 2085 reqBool += reBool; 2086 reNumber = cache->dbgReusedNumber; 2087 reqNumber += reNumber; 2088 reXSLTTree = cache->dbgReusedXSLTTree; 2089 reqXSLTTree += reXSLTTree; 2090 reUndefined = cache->dbgReusedUndefined; 2091 reqUndefined += reUndefined; 2092 2093 caAll = cache->dbgCachedAll; 2094 caBool = cache->dbgCachedBool; 2095 caNodeset = cache->dbgCachedNodeset; 2096 caString = cache->dbgCachedString; 2097 caNumber = cache->dbgCachedNumber; 2098 caXSLTTree = cache->dbgCachedXSLTTree; 2099 caUndefined = cache->dbgCachedUndefined; 2100 2101 if (cache->nodesetObjs) 2102 leftObjs -= cache->nodesetObjs->number; 2103 if (cache->stringObjs) 2104 leftObjs -= cache->stringObjs->number; 2105 if (cache->booleanObjs) 2106 leftObjs -= cache->booleanObjs->number; 2107 if (cache->numberObjs) 2108 leftObjs -= cache->numberObjs->number; 2109 if (cache->miscObjs) 2110 leftObjs -= cache->miscObjs->number; 2111 } 2112 } 2113 2114 printf("# all\n"); 2115 printf("# total : %d\n", reqAll); 2116 printf("# left : %d\n", leftObjs); 2117 printf("# created: %d\n", xmlXPathDebugObjTotalAll); 2118 printf("# reused : %d\n", reAll); 2119 printf("# max : %d\n", xmlXPathDebugObjMaxAll); 2120 2121 printf("# node-sets\n"); 2122 printf("# total : %d\n", reqNodeset); 2123 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset); 2124 printf("# reused : %d\n", reNodeset); 2125 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset); 2126 2127 printf("# strings\n"); 2128 printf("# total : %d\n", reqString); 2129 printf("# created: %d\n", xmlXPathDebugObjTotalString); 2130 printf("# reused : %d\n", reString); 2131 printf("# max : %d\n", xmlXPathDebugObjMaxString); 2132 2133 printf("# booleans\n"); 2134 printf("# total : %d\n", reqBool); 2135 printf("# created: %d\n", xmlXPathDebugObjTotalBool); 2136 printf("# reused : %d\n", reBool); 2137 printf("# max : %d\n", xmlXPathDebugObjMaxBool); 2138 2139 printf("# numbers\n"); 2140 printf("# total : %d\n", reqNumber); 2141 printf("# created: %d\n", xmlXPathDebugObjTotalNumber); 2142 printf("# reused : %d\n", reNumber); 2143 printf("# max : %d\n", xmlXPathDebugObjMaxNumber); 2144 2145 printf("# XSLT result tree fragments\n"); 2146 printf("# total : %d\n", reqXSLTTree); 2147 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree); 2148 printf("# reused : %d\n", reXSLTTree); 2149 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree); 2150 2151 printf("# undefined\n"); 2152 printf("# total : %d\n", reqUndefined); 2153 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined); 2154 printf("# reused : %d\n", reUndefined); 2155 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined); 2156 2157 } 2158 2159 #endif /* XP_DEBUG_OBJ_USAGE */ 2160 2161 #endif /* LIBXML_DEBUG_ENABLED */ 2162 2163 /************************************************************************ 2164 * * 2165 * XPath object caching * 2166 * * 2167 ************************************************************************/ 2168 2169 /** 2170 * xmlXPathNewCache: 2171 * 2172 * Create a new object cache 2173 * 2174 * Returns the xmlXPathCache just allocated. 2175 */ 2176 static xmlXPathContextCachePtr 2177 xmlXPathNewCache(void) 2178 { 2179 xmlXPathContextCachePtr ret; 2180 2181 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache)); 2182 if (ret == NULL) { 2183 xmlXPathErrMemory(NULL, "creating object cache\n"); 2184 return(NULL); 2185 } 2186 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache)); 2187 ret->maxNodeset = 100; 2188 ret->maxString = 100; 2189 ret->maxBoolean = 100; 2190 ret->maxNumber = 100; 2191 ret->maxMisc = 100; 2192 return(ret); 2193 } 2194 2195 static void 2196 xmlXPathCacheFreeObjectList(xmlPointerListPtr list) 2197 { 2198 int i; 2199 xmlXPathObjectPtr obj; 2200 2201 if (list == NULL) 2202 return; 2203 2204 for (i = 0; i < list->number; i++) { 2205 obj = list->items[i]; 2206 /* 2207 * Note that it is already assured that we don't need to 2208 * look out for namespace nodes in the node-set. 2209 */ 2210 if (obj->nodesetval != NULL) { 2211 if (obj->nodesetval->nodeTab != NULL) 2212 xmlFree(obj->nodesetval->nodeTab); 2213 xmlFree(obj->nodesetval); 2214 } 2215 xmlFree(obj); 2216 #ifdef XP_DEBUG_OBJ_USAGE 2217 xmlXPathDebugObjCounterAll--; 2218 #endif 2219 } 2220 xmlPointerListFree(list); 2221 } 2222 2223 static void 2224 xmlXPathFreeCache(xmlXPathContextCachePtr cache) 2225 { 2226 if (cache == NULL) 2227 return; 2228 if (cache->nodesetObjs) 2229 xmlXPathCacheFreeObjectList(cache->nodesetObjs); 2230 if (cache->stringObjs) 2231 xmlXPathCacheFreeObjectList(cache->stringObjs); 2232 if (cache->booleanObjs) 2233 xmlXPathCacheFreeObjectList(cache->booleanObjs); 2234 if (cache->numberObjs) 2235 xmlXPathCacheFreeObjectList(cache->numberObjs); 2236 if (cache->miscObjs) 2237 xmlXPathCacheFreeObjectList(cache->miscObjs); 2238 xmlFree(cache); 2239 } 2240 2241 /** 2242 * xmlXPathContextSetCache: 2243 * 2244 * @ctxt: the XPath context 2245 * @active: enables/disables (creates/frees) the cache 2246 * @value: a value with semantics dependant on @options 2247 * @options: options (currently only the value 0 is used) 2248 * 2249 * Creates/frees an object cache on the XPath context. 2250 * If activates XPath objects (xmlXPathObject) will be cached internally 2251 * to be reused. 2252 * @options: 2253 * 0: This will set the XPath object caching: 2254 * @value: 2255 * This will set the maximum number of XPath objects 2256 * to be cached per slot 2257 * There are 5 slots for: node-set, string, number, boolean, and 2258 * misc objects. Use <0 for the default number (100). 2259 * Other values for @options have currently no effect. 2260 * 2261 * Returns 0 if the setting succeeded, and -1 on API or internal errors. 2262 */ 2263 int 2264 xmlXPathContextSetCache(xmlXPathContextPtr ctxt, 2265 int active, 2266 int value, 2267 int options) 2268 { 2269 if (ctxt == NULL) 2270 return(-1); 2271 if (active) { 2272 xmlXPathContextCachePtr cache; 2273 2274 if (ctxt->cache == NULL) { 2275 ctxt->cache = xmlXPathNewCache(); 2276 if (ctxt->cache == NULL) 2277 return(-1); 2278 } 2279 cache = (xmlXPathContextCachePtr) ctxt->cache; 2280 if (options == 0) { 2281 if (value < 0) 2282 value = 100; 2283 cache->maxNodeset = value; 2284 cache->maxString = value; 2285 cache->maxNumber = value; 2286 cache->maxBoolean = value; 2287 cache->maxMisc = value; 2288 } 2289 } else if (ctxt->cache != NULL) { 2290 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache); 2291 ctxt->cache = NULL; 2292 } 2293 return(0); 2294 } 2295 2296 /** 2297 * xmlXPathCacheWrapNodeSet: 2298 * @ctxt: the XPath context 2299 * @val: the NodePtr value 2300 * 2301 * This is the cached version of xmlXPathWrapNodeSet(). 2302 * Wrap the Nodeset @val in a new xmlXPathObjectPtr 2303 * 2304 * Returns the created or reused object. 2305 */ 2306 static xmlXPathObjectPtr 2307 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val) 2308 { 2309 if ((ctxt != NULL) && (ctxt->cache != NULL)) { 2310 xmlXPathContextCachePtr cache = 2311 (xmlXPathContextCachePtr) ctxt->cache; 2312 2313 if ((cache->miscObjs != NULL) && 2314 (cache->miscObjs->number != 0)) 2315 { 2316 xmlXPathObjectPtr ret; 2317 2318 ret = (xmlXPathObjectPtr) 2319 cache->miscObjs->items[--cache->miscObjs->number]; 2320 ret->type = XPATH_NODESET; 2321 ret->nodesetval = val; 2322 #ifdef XP_DEBUG_OBJ_USAGE 2323 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 2324 #endif 2325 return(ret); 2326 } 2327 } 2328 2329 return(xmlXPathWrapNodeSet(val)); 2330 2331 } 2332 2333 /** 2334 * xmlXPathCacheWrapString: 2335 * @ctxt: the XPath context 2336 * @val: the xmlChar * value 2337 * 2338 * This is the cached version of xmlXPathWrapString(). 2339 * Wraps the @val string into an XPath object. 2340 * 2341 * Returns the created or reused object. 2342 */ 2343 static xmlXPathObjectPtr 2344 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val) 2345 { 2346 if ((ctxt != NULL) && (ctxt->cache != NULL)) { 2347 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2348 2349 if ((cache->stringObjs != NULL) && 2350 (cache->stringObjs->number != 0)) 2351 { 2352 2353 xmlXPathObjectPtr ret; 2354 2355 ret = (xmlXPathObjectPtr) 2356 cache->stringObjs->items[--cache->stringObjs->number]; 2357 ret->type = XPATH_STRING; 2358 ret->stringval = val; 2359 #ifdef XP_DEBUG_OBJ_USAGE 2360 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2361 #endif 2362 return(ret); 2363 } else if ((cache->miscObjs != NULL) && 2364 (cache->miscObjs->number != 0)) 2365 { 2366 xmlXPathObjectPtr ret; 2367 /* 2368 * Fallback to misc-cache. 2369 */ 2370 ret = (xmlXPathObjectPtr) 2371 cache->miscObjs->items[--cache->miscObjs->number]; 2372 2373 ret->type = XPATH_STRING; 2374 ret->stringval = val; 2375 #ifdef XP_DEBUG_OBJ_USAGE 2376 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2377 #endif 2378 return(ret); 2379 } 2380 } 2381 return(xmlXPathWrapString(val)); 2382 } 2383 2384 /** 2385 * xmlXPathCacheNewNodeSet: 2386 * @ctxt: the XPath context 2387 * @val: the NodePtr value 2388 * 2389 * This is the cached version of xmlXPathNewNodeSet(). 2390 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize 2391 * it with the single Node @val 2392 * 2393 * Returns the created or reused object. 2394 */ 2395 static xmlXPathObjectPtr 2396 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val) 2397 { 2398 if ((ctxt != NULL) && (ctxt->cache)) { 2399 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2400 2401 if ((cache->nodesetObjs != NULL) && 2402 (cache->nodesetObjs->number != 0)) 2403 { 2404 xmlXPathObjectPtr ret; 2405 /* 2406 * Use the nodset-cache. 2407 */ 2408 ret = (xmlXPathObjectPtr) 2409 cache->nodesetObjs->items[--cache->nodesetObjs->number]; 2410 ret->type = XPATH_NODESET; 2411 ret->boolval = 0; 2412 if (val) { 2413 if ((ret->nodesetval->nodeMax == 0) || 2414 (val->type == XML_NAMESPACE_DECL)) 2415 { 2416 xmlXPathNodeSetAddUnique(ret->nodesetval, val); 2417 } else { 2418 ret->nodesetval->nodeTab[0] = val; 2419 ret->nodesetval->nodeNr = 1; 2420 } 2421 } 2422 #ifdef XP_DEBUG_OBJ_USAGE 2423 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 2424 #endif 2425 return(ret); 2426 } else if ((cache->miscObjs != NULL) && 2427 (cache->miscObjs->number != 0)) 2428 { 2429 xmlXPathObjectPtr ret; 2430 /* 2431 * Fallback to misc-cache. 2432 */ 2433 2434 ret = (xmlXPathObjectPtr) 2435 cache->miscObjs->items[--cache->miscObjs->number]; 2436 2437 ret->type = XPATH_NODESET; 2438 ret->boolval = 0; 2439 ret->nodesetval = xmlXPathNodeSetCreate(val); 2440 if (ret->nodesetval == NULL) { 2441 ctxt->lastError.domain = XML_FROM_XPATH; 2442 ctxt->lastError.code = XML_ERR_NO_MEMORY; 2443 return(NULL); 2444 } 2445 #ifdef XP_DEBUG_OBJ_USAGE 2446 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 2447 #endif 2448 return(ret); 2449 } 2450 } 2451 return(xmlXPathNewNodeSet(val)); 2452 } 2453 2454 /** 2455 * xmlXPathCacheNewCString: 2456 * @ctxt: the XPath context 2457 * @val: the char * value 2458 * 2459 * This is the cached version of xmlXPathNewCString(). 2460 * Acquire an xmlXPathObjectPtr of type string and of value @val 2461 * 2462 * Returns the created or reused object. 2463 */ 2464 static xmlXPathObjectPtr 2465 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val) 2466 { 2467 if ((ctxt != NULL) && (ctxt->cache)) { 2468 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2469 2470 if ((cache->stringObjs != NULL) && 2471 (cache->stringObjs->number != 0)) 2472 { 2473 xmlXPathObjectPtr ret; 2474 2475 ret = (xmlXPathObjectPtr) 2476 cache->stringObjs->items[--cache->stringObjs->number]; 2477 2478 ret->type = XPATH_STRING; 2479 ret->stringval = xmlStrdup(BAD_CAST val); 2480 #ifdef XP_DEBUG_OBJ_USAGE 2481 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2482 #endif 2483 return(ret); 2484 } else if ((cache->miscObjs != NULL) && 2485 (cache->miscObjs->number != 0)) 2486 { 2487 xmlXPathObjectPtr ret; 2488 2489 ret = (xmlXPathObjectPtr) 2490 cache->miscObjs->items[--cache->miscObjs->number]; 2491 2492 ret->type = XPATH_STRING; 2493 ret->stringval = xmlStrdup(BAD_CAST val); 2494 #ifdef XP_DEBUG_OBJ_USAGE 2495 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2496 #endif 2497 return(ret); 2498 } 2499 } 2500 return(xmlXPathNewCString(val)); 2501 } 2502 2503 /** 2504 * xmlXPathCacheNewString: 2505 * @ctxt: the XPath context 2506 * @val: the xmlChar * value 2507 * 2508 * This is the cached version of xmlXPathNewString(). 2509 * Acquire an xmlXPathObjectPtr of type string and of value @val 2510 * 2511 * Returns the created or reused object. 2512 */ 2513 static xmlXPathObjectPtr 2514 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val) 2515 { 2516 if ((ctxt != NULL) && (ctxt->cache)) { 2517 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2518 2519 if ((cache->stringObjs != NULL) && 2520 (cache->stringObjs->number != 0)) 2521 { 2522 xmlXPathObjectPtr ret; 2523 2524 ret = (xmlXPathObjectPtr) 2525 cache->stringObjs->items[--cache->stringObjs->number]; 2526 ret->type = XPATH_STRING; 2527 if (val != NULL) 2528 ret->stringval = xmlStrdup(val); 2529 else 2530 ret->stringval = xmlStrdup((const xmlChar *)""); 2531 #ifdef XP_DEBUG_OBJ_USAGE 2532 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2533 #endif 2534 return(ret); 2535 } else if ((cache->miscObjs != NULL) && 2536 (cache->miscObjs->number != 0)) 2537 { 2538 xmlXPathObjectPtr ret; 2539 2540 ret = (xmlXPathObjectPtr) 2541 cache->miscObjs->items[--cache->miscObjs->number]; 2542 2543 ret->type = XPATH_STRING; 2544 if (val != NULL) 2545 ret->stringval = xmlStrdup(val); 2546 else 2547 ret->stringval = xmlStrdup((const xmlChar *)""); 2548 #ifdef XP_DEBUG_OBJ_USAGE 2549 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2550 #endif 2551 return(ret); 2552 } 2553 } 2554 return(xmlXPathNewString(val)); 2555 } 2556 2557 /** 2558 * xmlXPathCacheNewBoolean: 2559 * @ctxt: the XPath context 2560 * @val: the boolean value 2561 * 2562 * This is the cached version of xmlXPathNewBoolean(). 2563 * Acquires an xmlXPathObjectPtr of type boolean and of value @val 2564 * 2565 * Returns the created or reused object. 2566 */ 2567 static xmlXPathObjectPtr 2568 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val) 2569 { 2570 if ((ctxt != NULL) && (ctxt->cache)) { 2571 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2572 2573 if ((cache->booleanObjs != NULL) && 2574 (cache->booleanObjs->number != 0)) 2575 { 2576 xmlXPathObjectPtr ret; 2577 2578 ret = (xmlXPathObjectPtr) 2579 cache->booleanObjs->items[--cache->booleanObjs->number]; 2580 ret->type = XPATH_BOOLEAN; 2581 ret->boolval = (val != 0); 2582 #ifdef XP_DEBUG_OBJ_USAGE 2583 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN); 2584 #endif 2585 return(ret); 2586 } else if ((cache->miscObjs != NULL) && 2587 (cache->miscObjs->number != 0)) 2588 { 2589 xmlXPathObjectPtr ret; 2590 2591 ret = (xmlXPathObjectPtr) 2592 cache->miscObjs->items[--cache->miscObjs->number]; 2593 2594 ret->type = XPATH_BOOLEAN; 2595 ret->boolval = (val != 0); 2596 #ifdef XP_DEBUG_OBJ_USAGE 2597 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN); 2598 #endif 2599 return(ret); 2600 } 2601 } 2602 return(xmlXPathNewBoolean(val)); 2603 } 2604 2605 /** 2606 * xmlXPathCacheNewFloat: 2607 * @ctxt: the XPath context 2608 * @val: the double value 2609 * 2610 * This is the cached version of xmlXPathNewFloat(). 2611 * Acquires an xmlXPathObjectPtr of type double and of value @val 2612 * 2613 * Returns the created or reused object. 2614 */ 2615 static xmlXPathObjectPtr 2616 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val) 2617 { 2618 if ((ctxt != NULL) && (ctxt->cache)) { 2619 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2620 2621 if ((cache->numberObjs != NULL) && 2622 (cache->numberObjs->number != 0)) 2623 { 2624 xmlXPathObjectPtr ret; 2625 2626 ret = (xmlXPathObjectPtr) 2627 cache->numberObjs->items[--cache->numberObjs->number]; 2628 ret->type = XPATH_NUMBER; 2629 ret->floatval = val; 2630 #ifdef XP_DEBUG_OBJ_USAGE 2631 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER); 2632 #endif 2633 return(ret); 2634 } else if ((cache->miscObjs != NULL) && 2635 (cache->miscObjs->number != 0)) 2636 { 2637 xmlXPathObjectPtr ret; 2638 2639 ret = (xmlXPathObjectPtr) 2640 cache->miscObjs->items[--cache->miscObjs->number]; 2641 2642 ret->type = XPATH_NUMBER; 2643 ret->floatval = val; 2644 #ifdef XP_DEBUG_OBJ_USAGE 2645 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER); 2646 #endif 2647 return(ret); 2648 } 2649 } 2650 return(xmlXPathNewFloat(val)); 2651 } 2652 2653 /** 2654 * xmlXPathCacheConvertString: 2655 * @ctxt: the XPath context 2656 * @val: an XPath object 2657 * 2658 * This is the cached version of xmlXPathConvertString(). 2659 * Converts an existing object to its string() equivalent 2660 * 2661 * Returns a created or reused object, the old one is freed (cached) 2662 * (or the operation is done directly on @val) 2663 */ 2664 2665 static xmlXPathObjectPtr 2666 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 2667 xmlChar *res = NULL; 2668 2669 if (val == NULL) 2670 return(xmlXPathCacheNewCString(ctxt, "")); 2671 2672 switch (val->type) { 2673 case XPATH_UNDEFINED: 2674 #ifdef DEBUG_EXPR 2675 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n"); 2676 #endif 2677 break; 2678 case XPATH_NODESET: 2679 case XPATH_XSLT_TREE: 2680 res = xmlXPathCastNodeSetToString(val->nodesetval); 2681 break; 2682 case XPATH_STRING: 2683 return(val); 2684 case XPATH_BOOLEAN: 2685 res = xmlXPathCastBooleanToString(val->boolval); 2686 break; 2687 case XPATH_NUMBER: 2688 res = xmlXPathCastNumberToString(val->floatval); 2689 break; 2690 case XPATH_USERS: 2691 case XPATH_POINT: 2692 case XPATH_RANGE: 2693 case XPATH_LOCATIONSET: 2694 TODO; 2695 break; 2696 } 2697 xmlXPathReleaseObject(ctxt, val); 2698 if (res == NULL) 2699 return(xmlXPathCacheNewCString(ctxt, "")); 2700 return(xmlXPathCacheWrapString(ctxt, res)); 2701 } 2702 2703 /** 2704 * xmlXPathCacheObjectCopy: 2705 * @ctxt: the XPath context 2706 * @val: the original object 2707 * 2708 * This is the cached version of xmlXPathObjectCopy(). 2709 * Acquire a copy of a given object 2710 * 2711 * Returns a created or reused created object. 2712 */ 2713 static xmlXPathObjectPtr 2714 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) 2715 { 2716 if (val == NULL) 2717 return(NULL); 2718 2719 if (XP_HAS_CACHE(ctxt)) { 2720 switch (val->type) { 2721 case XPATH_NODESET: 2722 return(xmlXPathCacheWrapNodeSet(ctxt, 2723 xmlXPathNodeSetMerge(NULL, val->nodesetval))); 2724 case XPATH_STRING: 2725 return(xmlXPathCacheNewString(ctxt, val->stringval)); 2726 case XPATH_BOOLEAN: 2727 return(xmlXPathCacheNewBoolean(ctxt, val->boolval)); 2728 case XPATH_NUMBER: 2729 return(xmlXPathCacheNewFloat(ctxt, val->floatval)); 2730 default: 2731 break; 2732 } 2733 } 2734 return(xmlXPathObjectCopy(val)); 2735 } 2736 2737 /** 2738 * xmlXPathCacheConvertBoolean: 2739 * @ctxt: the XPath context 2740 * @val: an XPath object 2741 * 2742 * This is the cached version of xmlXPathConvertBoolean(). 2743 * Converts an existing object to its boolean() equivalent 2744 * 2745 * Returns a created or reused object, the old one is freed (or the operation 2746 * is done directly on @val) 2747 */ 2748 static xmlXPathObjectPtr 2749 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 2750 xmlXPathObjectPtr ret; 2751 2752 if (val == NULL) 2753 return(xmlXPathCacheNewBoolean(ctxt, 0)); 2754 if (val->type == XPATH_BOOLEAN) 2755 return(val); 2756 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val)); 2757 xmlXPathReleaseObject(ctxt, val); 2758 return(ret); 2759 } 2760 2761 /** 2762 * xmlXPathCacheConvertNumber: 2763 * @ctxt: the XPath context 2764 * @val: an XPath object 2765 * 2766 * This is the cached version of xmlXPathConvertNumber(). 2767 * Converts an existing object to its number() equivalent 2768 * 2769 * Returns a created or reused object, the old one is freed (or the operation 2770 * is done directly on @val) 2771 */ 2772 static xmlXPathObjectPtr 2773 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 2774 xmlXPathObjectPtr ret; 2775 2776 if (val == NULL) 2777 return(xmlXPathCacheNewFloat(ctxt, 0.0)); 2778 if (val->type == XPATH_NUMBER) 2779 return(val); 2780 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val)); 2781 xmlXPathReleaseObject(ctxt, val); 2782 return(ret); 2783 } 2784 2785 /************************************************************************ 2786 * * 2787 * Parser stacks related functions and macros * 2788 * * 2789 ************************************************************************/ 2790 2791 /** 2792 * xmlXPathSetFrame: 2793 * @ctxt: an XPath parser context 2794 * 2795 * Set the callee evaluation frame 2796 * 2797 * Returns the previous frame value to be restored once done 2798 */ 2799 static int 2800 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) { 2801 int ret; 2802 2803 if (ctxt == NULL) 2804 return(0); 2805 ret = ctxt->valueFrame; 2806 ctxt->valueFrame = ctxt->valueNr; 2807 return(ret); 2808 } 2809 2810 /** 2811 * xmlXPathPopFrame: 2812 * @ctxt: an XPath parser context 2813 * @frame: the previous frame value 2814 * 2815 * Remove the callee evaluation frame 2816 */ 2817 static void 2818 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) { 2819 if (ctxt == NULL) 2820 return; 2821 if (ctxt->valueNr < ctxt->valueFrame) { 2822 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR); 2823 } 2824 ctxt->valueFrame = frame; 2825 } 2826 2827 /** 2828 * valuePop: 2829 * @ctxt: an XPath evaluation context 2830 * 2831 * Pops the top XPath object from the value stack 2832 * 2833 * Returns the XPath object just removed 2834 */ 2835 xmlXPathObjectPtr 2836 valuePop(xmlXPathParserContextPtr ctxt) 2837 { 2838 xmlXPathObjectPtr ret; 2839 2840 if ((ctxt == NULL) || (ctxt->valueNr <= 0)) 2841 return (NULL); 2842 2843 if (ctxt->valueNr <= ctxt->valueFrame) { 2844 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR); 2845 return (NULL); 2846 } 2847 2848 ctxt->valueNr--; 2849 if (ctxt->valueNr > 0) 2850 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1]; 2851 else 2852 ctxt->value = NULL; 2853 ret = ctxt->valueTab[ctxt->valueNr]; 2854 ctxt->valueTab[ctxt->valueNr] = NULL; 2855 return (ret); 2856 } 2857 /** 2858 * valuePush: 2859 * @ctxt: an XPath evaluation context 2860 * @value: the XPath object 2861 * 2862 * Pushes a new XPath object on top of the value stack 2863 * 2864 * returns the number of items on the value stack 2865 */ 2866 int 2867 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value) 2868 { 2869 if ((ctxt == NULL) || (value == NULL)) return(-1); 2870 if (ctxt->valueNr >= ctxt->valueMax) { 2871 xmlXPathObjectPtr *tmp; 2872 2873 if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) { 2874 xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n"); 2875 ctxt->error = XPATH_MEMORY_ERROR; 2876 return (0); 2877 } 2878 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab, 2879 2 * ctxt->valueMax * 2880 sizeof(ctxt->valueTab[0])); 2881 if (tmp == NULL) { 2882 xmlXPathErrMemory(NULL, "pushing value\n"); 2883 ctxt->error = XPATH_MEMORY_ERROR; 2884 return (0); 2885 } 2886 ctxt->valueMax *= 2; 2887 ctxt->valueTab = tmp; 2888 } 2889 ctxt->valueTab[ctxt->valueNr] = value; 2890 ctxt->value = value; 2891 return (ctxt->valueNr++); 2892 } 2893 2894 /** 2895 * xmlXPathPopBoolean: 2896 * @ctxt: an XPath parser context 2897 * 2898 * Pops a boolean from the stack, handling conversion if needed. 2899 * Check error with #xmlXPathCheckError. 2900 * 2901 * Returns the boolean 2902 */ 2903 int 2904 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) { 2905 xmlXPathObjectPtr obj; 2906 int ret; 2907 2908 obj = valuePop(ctxt); 2909 if (obj == NULL) { 2910 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2911 return(0); 2912 } 2913 if (obj->type != XPATH_BOOLEAN) 2914 ret = xmlXPathCastToBoolean(obj); 2915 else 2916 ret = obj->boolval; 2917 xmlXPathReleaseObject(ctxt->context, obj); 2918 return(ret); 2919 } 2920 2921 /** 2922 * xmlXPathPopNumber: 2923 * @ctxt: an XPath parser context 2924 * 2925 * Pops a number from the stack, handling conversion if needed. 2926 * Check error with #xmlXPathCheckError. 2927 * 2928 * Returns the number 2929 */ 2930 double 2931 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) { 2932 xmlXPathObjectPtr obj; 2933 double ret; 2934 2935 obj = valuePop(ctxt); 2936 if (obj == NULL) { 2937 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2938 return(0); 2939 } 2940 if (obj->type != XPATH_NUMBER) 2941 ret = xmlXPathCastToNumber(obj); 2942 else 2943 ret = obj->floatval; 2944 xmlXPathReleaseObject(ctxt->context, obj); 2945 return(ret); 2946 } 2947 2948 /** 2949 * xmlXPathPopString: 2950 * @ctxt: an XPath parser context 2951 * 2952 * Pops a string from the stack, handling conversion if needed. 2953 * Check error with #xmlXPathCheckError. 2954 * 2955 * Returns the string 2956 */ 2957 xmlChar * 2958 xmlXPathPopString (xmlXPathParserContextPtr ctxt) { 2959 xmlXPathObjectPtr obj; 2960 xmlChar * ret; 2961 2962 obj = valuePop(ctxt); 2963 if (obj == NULL) { 2964 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2965 return(NULL); 2966 } 2967 ret = xmlXPathCastToString(obj); /* this does required strdup */ 2968 /* TODO: needs refactoring somewhere else */ 2969 if (obj->stringval == ret) 2970 obj->stringval = NULL; 2971 xmlXPathReleaseObject(ctxt->context, obj); 2972 return(ret); 2973 } 2974 2975 /** 2976 * xmlXPathPopNodeSet: 2977 * @ctxt: an XPath parser context 2978 * 2979 * Pops a node-set from the stack, handling conversion if needed. 2980 * Check error with #xmlXPathCheckError. 2981 * 2982 * Returns the node-set 2983 */ 2984 xmlNodeSetPtr 2985 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) { 2986 xmlXPathObjectPtr obj; 2987 xmlNodeSetPtr ret; 2988 2989 if (ctxt == NULL) return(NULL); 2990 if (ctxt->value == NULL) { 2991 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2992 return(NULL); 2993 } 2994 if (!xmlXPathStackIsNodeSet(ctxt)) { 2995 xmlXPathSetTypeError(ctxt); 2996 return(NULL); 2997 } 2998 obj = valuePop(ctxt); 2999 ret = obj->nodesetval; 3000 #if 0 3001 /* to fix memory leak of not clearing obj->user */ 3002 if (obj->boolval && obj->user != NULL) 3003 xmlFreeNodeList((xmlNodePtr) obj->user); 3004 #endif 3005 obj->nodesetval = NULL; 3006 xmlXPathReleaseObject(ctxt->context, obj); 3007 return(ret); 3008 } 3009 3010 /** 3011 * xmlXPathPopExternal: 3012 * @ctxt: an XPath parser context 3013 * 3014 * Pops an external object from the stack, handling conversion if needed. 3015 * Check error with #xmlXPathCheckError. 3016 * 3017 * Returns the object 3018 */ 3019 void * 3020 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) { 3021 xmlXPathObjectPtr obj; 3022 void * ret; 3023 3024 if ((ctxt == NULL) || (ctxt->value == NULL)) { 3025 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 3026 return(NULL); 3027 } 3028 if (ctxt->value->type != XPATH_USERS) { 3029 xmlXPathSetTypeError(ctxt); 3030 return(NULL); 3031 } 3032 obj = valuePop(ctxt); 3033 ret = obj->user; 3034 obj->user = NULL; 3035 xmlXPathReleaseObject(ctxt->context, obj); 3036 return(ret); 3037 } 3038 3039 /* 3040 * Macros for accessing the content. Those should be used only by the parser, 3041 * and not exported. 3042 * 3043 * Dirty macros, i.e. one need to make assumption on the context to use them 3044 * 3045 * CUR_PTR return the current pointer to the xmlChar to be parsed. 3046 * CUR returns the current xmlChar value, i.e. a 8 bit value 3047 * in ISO-Latin or UTF-8. 3048 * This should be used internally by the parser 3049 * only to compare to ASCII values otherwise it would break when 3050 * running with UTF-8 encoding. 3051 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only 3052 * to compare on ASCII based substring. 3053 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined 3054 * strings within the parser. 3055 * CURRENT Returns the current char value, with the full decoding of 3056 * UTF-8 if we are using this mode. It returns an int. 3057 * NEXT Skip to the next character, this does the proper decoding 3058 * in UTF-8 mode. It also pop-up unfinished entities on the fly. 3059 * It returns the pointer to the current xmlChar. 3060 */ 3061 3062 #define CUR (*ctxt->cur) 3063 #define SKIP(val) ctxt->cur += (val) 3064 #define NXT(val) ctxt->cur[(val)] 3065 #define CUR_PTR ctxt->cur 3066 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l) 3067 3068 #define COPY_BUF(l,b,i,v) \ 3069 if (l == 1) b[i++] = (xmlChar) v; \ 3070 else i += xmlCopyChar(l,&b[i],v) 3071 3072 #define NEXTL(l) ctxt->cur += l 3073 3074 #define SKIP_BLANKS \ 3075 while (IS_BLANK_CH(*(ctxt->cur))) NEXT 3076 3077 #define CURRENT (*ctxt->cur) 3078 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur) 3079 3080 3081 #ifndef DBL_DIG 3082 #define DBL_DIG 16 3083 #endif 3084 #ifndef DBL_EPSILON 3085 #define DBL_EPSILON 1E-9 3086 #endif 3087 3088 #define UPPER_DOUBLE 1E9 3089 #define LOWER_DOUBLE 1E-5 3090 #define LOWER_DOUBLE_EXP 5 3091 3092 #define INTEGER_DIGITS DBL_DIG 3093 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP)) 3094 #define EXPONENT_DIGITS (3 + 2) 3095 3096 /** 3097 * xmlXPathFormatNumber: 3098 * @number: number to format 3099 * @buffer: output buffer 3100 * @buffersize: size of output buffer 3101 * 3102 * Convert the number into a string representation. 3103 */ 3104 static void 3105 xmlXPathFormatNumber(double number, char buffer[], int buffersize) 3106 { 3107 switch (xmlXPathIsInf(number)) { 3108 case 1: 3109 if (buffersize > (int)sizeof("Infinity")) 3110 snprintf(buffer, buffersize, "Infinity"); 3111 break; 3112 case -1: 3113 if (buffersize > (int)sizeof("-Infinity")) 3114 snprintf(buffer, buffersize, "-Infinity"); 3115 break; 3116 default: 3117 if (xmlXPathIsNaN(number)) { 3118 if (buffersize > (int)sizeof("NaN")) 3119 snprintf(buffer, buffersize, "NaN"); 3120 } else if (number == 0 && xmlXPathGetSign(number) != 0) { 3121 snprintf(buffer, buffersize, "0"); 3122 } else if ((number > INT_MIN) && (number < INT_MAX) && 3123 (number == (int) number)) { 3124 char work[30]; 3125 char *ptr, *cur; 3126 int value = (int) number; 3127 3128 ptr = &buffer[0]; 3129 if (value == 0) { 3130 *ptr++ = '0'; 3131 } else { 3132 snprintf(work, 29, "%d", value); 3133 cur = &work[0]; 3134 while ((*cur) && (ptr - buffer < buffersize)) { 3135 *ptr++ = *cur++; 3136 } 3137 } 3138 if (ptr - buffer < buffersize) { 3139 *ptr = 0; 3140 } else if (buffersize > 0) { 3141 ptr--; 3142 *ptr = 0; 3143 } 3144 } else { 3145 /* 3146 For the dimension of work, 3147 DBL_DIG is number of significant digits 3148 EXPONENT is only needed for "scientific notation" 3149 3 is sign, decimal point, and terminating zero 3150 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction 3151 Note that this dimension is slightly (a few characters) 3152 larger than actually necessary. 3153 */ 3154 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP]; 3155 int integer_place, fraction_place; 3156 char *ptr; 3157 char *after_fraction; 3158 double absolute_value; 3159 int size; 3160 3161 absolute_value = fabs(number); 3162 3163 /* 3164 * First choose format - scientific or regular floating point. 3165 * In either case, result is in work, and after_fraction points 3166 * just past the fractional part. 3167 */ 3168 if ( ((absolute_value > UPPER_DOUBLE) || 3169 (absolute_value < LOWER_DOUBLE)) && 3170 (absolute_value != 0.0) ) { 3171 /* Use scientific notation */ 3172 integer_place = DBL_DIG + EXPONENT_DIGITS + 1; 3173 fraction_place = DBL_DIG - 1; 3174 size = snprintf(work, sizeof(work),"%*.*e", 3175 integer_place, fraction_place, number); 3176 while ((size > 0) && (work[size] != 'e')) size--; 3177 3178 } 3179 else { 3180 /* Use regular notation */ 3181 if (absolute_value > 0.0) { 3182 integer_place = (int)log10(absolute_value); 3183 if (integer_place > 0) 3184 fraction_place = DBL_DIG - integer_place - 1; 3185 else 3186 fraction_place = DBL_DIG - integer_place; 3187 } else { 3188 fraction_place = 1; 3189 } 3190 size = snprintf(work, sizeof(work), "%0.*f", 3191 fraction_place, number); 3192 } 3193 3194 /* Remove leading spaces sometimes inserted by snprintf */ 3195 while (work[0] == ' ') { 3196 for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++); 3197 size--; 3198 } 3199 3200 /* Remove fractional trailing zeroes */ 3201 after_fraction = work + size; 3202 ptr = after_fraction; 3203 while (*(--ptr) == '0') 3204 ; 3205 if (*ptr != '.') 3206 ptr++; 3207 while ((*ptr++ = *after_fraction++) != 0); 3208 3209 /* Finally copy result back to caller */ 3210 size = strlen(work) + 1; 3211 if (size > buffersize) { 3212 work[buffersize - 1] = 0; 3213 size = buffersize; 3214 } 3215 memmove(buffer, work, size); 3216 } 3217 break; 3218 } 3219 } 3220 3221 3222 /************************************************************************ 3223 * * 3224 * Routines to handle NodeSets * 3225 * * 3226 ************************************************************************/ 3227 3228 /** 3229 * xmlXPathOrderDocElems: 3230 * @doc: an input document 3231 * 3232 * Call this routine to speed up XPath computation on static documents. 3233 * This stamps all the element nodes with the document order 3234 * Like for line information, the order is kept in the element->content 3235 * field, the value stored is actually - the node number (starting at -1) 3236 * to be able to differentiate from line numbers. 3237 * 3238 * Returns the number of elements found in the document or -1 in case 3239 * of error. 3240 */ 3241 long 3242 xmlXPathOrderDocElems(xmlDocPtr doc) { 3243 ptrdiff_t count = 0; 3244 xmlNodePtr cur; 3245 3246 if (doc == NULL) 3247 return(-1); 3248 cur = doc->children; 3249 while (cur != NULL) { 3250 if (cur->type == XML_ELEMENT_NODE) { 3251 cur->content = (void *) (-(++count)); 3252 if (cur->children != NULL) { 3253 cur = cur->children; 3254 continue; 3255 } 3256 } 3257 if (cur->next != NULL) { 3258 cur = cur->next; 3259 continue; 3260 } 3261 do { 3262 cur = cur->parent; 3263 if (cur == NULL) 3264 break; 3265 if (cur == (xmlNodePtr) doc) { 3266 cur = NULL; 3267 break; 3268 } 3269 if (cur->next != NULL) { 3270 cur = cur->next; 3271 break; 3272 } 3273 } while (cur != NULL); 3274 } 3275 return((long) count); 3276 } 3277 3278 /** 3279 * xmlXPathCmpNodes: 3280 * @node1: the first node 3281 * @node2: the second node 3282 * 3283 * Compare two nodes w.r.t document order 3284 * 3285 * Returns -2 in case of error 1 if first point < second point, 0 if 3286 * it's the same node, -1 otherwise 3287 */ 3288 int 3289 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) { 3290 int depth1, depth2; 3291 int attr1 = 0, attr2 = 0; 3292 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL; 3293 xmlNodePtr cur, root; 3294 3295 if ((node1 == NULL) || (node2 == NULL)) 3296 return(-2); 3297 /* 3298 * a couple of optimizations which will avoid computations in most cases 3299 */ 3300 if (node1 == node2) /* trivial case */ 3301 return(0); 3302 if (node1->type == XML_ATTRIBUTE_NODE) { 3303 attr1 = 1; 3304 attrNode1 = node1; 3305 node1 = node1->parent; 3306 } 3307 if (node2->type == XML_ATTRIBUTE_NODE) { 3308 attr2 = 1; 3309 attrNode2 = node2; 3310 node2 = node2->parent; 3311 } 3312 if (node1 == node2) { 3313 if (attr1 == attr2) { 3314 /* not required, but we keep attributes in order */ 3315 if (attr1 != 0) { 3316 cur = attrNode2->prev; 3317 while (cur != NULL) { 3318 if (cur == attrNode1) 3319 return (1); 3320 cur = cur->prev; 3321 } 3322 return (-1); 3323 } 3324 return(0); 3325 } 3326 if (attr2 == 1) 3327 return(1); 3328 return(-1); 3329 } 3330 if ((node1->type == XML_NAMESPACE_DECL) || 3331 (node2->type == XML_NAMESPACE_DECL)) 3332 return(1); 3333 if (node1 == node2->prev) 3334 return(1); 3335 if (node1 == node2->next) 3336 return(-1); 3337 3338 /* 3339 * Speedup using document order if availble. 3340 */ 3341 if ((node1->type == XML_ELEMENT_NODE) && 3342 (node2->type == XML_ELEMENT_NODE) && 3343 (0 > (ptrdiff_t) node1->content) && 3344 (0 > (ptrdiff_t) node2->content) && 3345 (node1->doc == node2->doc)) { 3346 ptrdiff_t l1, l2; 3347 3348 l1 = -((ptrdiff_t) node1->content); 3349 l2 = -((ptrdiff_t) node2->content); 3350 if (l1 < l2) 3351 return(1); 3352 if (l1 > l2) 3353 return(-1); 3354 } 3355 3356 /* 3357 * compute depth to root 3358 */ 3359 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) { 3360 if (cur->parent == node1) 3361 return(1); 3362 depth2++; 3363 } 3364 root = cur; 3365 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) { 3366 if (cur->parent == node2) 3367 return(-1); 3368 depth1++; 3369 } 3370 /* 3371 * Distinct document (or distinct entities :-( ) case. 3372 */ 3373 if (root != cur) { 3374 return(-2); 3375 } 3376 /* 3377 * get the nearest common ancestor. 3378 */ 3379 while (depth1 > depth2) { 3380 depth1--; 3381 node1 = node1->parent; 3382 } 3383 while (depth2 > depth1) { 3384 depth2--; 3385 node2 = node2->parent; 3386 } 3387 while (node1->parent != node2->parent) { 3388 node1 = node1->parent; 3389 node2 = node2->parent; 3390 /* should not happen but just in case ... */ 3391 if ((node1 == NULL) || (node2 == NULL)) 3392 return(-2); 3393 } 3394 /* 3395 * Find who's first. 3396 */ 3397 if (node1 == node2->prev) 3398 return(1); 3399 if (node1 == node2->next) 3400 return(-1); 3401 /* 3402 * Speedup using document order if availble. 3403 */ 3404 if ((node1->type == XML_ELEMENT_NODE) && 3405 (node2->type == XML_ELEMENT_NODE) && 3406 (0 > (ptrdiff_t) node1->content) && 3407 (0 > (ptrdiff_t) node2->content) && 3408 (node1->doc == node2->doc)) { 3409 ptrdiff_t l1, l2; 3410 3411 l1 = -((ptrdiff_t) node1->content); 3412 l2 = -((ptrdiff_t) node2->content); 3413 if (l1 < l2) 3414 return(1); 3415 if (l1 > l2) 3416 return(-1); 3417 } 3418 3419 for (cur = node1->next;cur != NULL;cur = cur->next) 3420 if (cur == node2) 3421 return(1); 3422 return(-1); /* assume there is no sibling list corruption */ 3423 } 3424 3425 /** 3426 * xmlXPathNodeSetSort: 3427 * @set: the node set 3428 * 3429 * Sort the node set in document order 3430 */ 3431 void 3432 xmlXPathNodeSetSort(xmlNodeSetPtr set) { 3433 #ifndef WITH_TIM_SORT 3434 int i, j, incr, len; 3435 xmlNodePtr tmp; 3436 #endif 3437 3438 if (set == NULL) 3439 return; 3440 3441 #ifndef WITH_TIM_SORT 3442 /* 3443 * Use the old Shell's sort implementation to sort the node-set 3444 * Timsort ought to be quite faster 3445 */ 3446 len = set->nodeNr; 3447 for (incr = len / 2; incr > 0; incr /= 2) { 3448 for (i = incr; i < len; i++) { 3449 j = i - incr; 3450 while (j >= 0) { 3451 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 3452 if (xmlXPathCmpNodesExt(set->nodeTab[j], 3453 set->nodeTab[j + incr]) == -1) 3454 #else 3455 if (xmlXPathCmpNodes(set->nodeTab[j], 3456 set->nodeTab[j + incr]) == -1) 3457 #endif 3458 { 3459 tmp = set->nodeTab[j]; 3460 set->nodeTab[j] = set->nodeTab[j + incr]; 3461 set->nodeTab[j + incr] = tmp; 3462 j -= incr; 3463 } else 3464 break; 3465 } 3466 } 3467 } 3468 #else /* WITH_TIM_SORT */ 3469 libxml_domnode_tim_sort(set->nodeTab, set->nodeNr); 3470 #endif /* WITH_TIM_SORT */ 3471 } 3472 3473 #define XML_NODESET_DEFAULT 10 3474 /** 3475 * xmlXPathNodeSetDupNs: 3476 * @node: the parent node of the namespace XPath node 3477 * @ns: the libxml namespace declaration node. 3478 * 3479 * Namespace node in libxml don't match the XPath semantic. In a node set 3480 * the namespace nodes are duplicated and the next pointer is set to the 3481 * parent node in the XPath semantic. 3482 * 3483 * Returns the newly created object. 3484 */ 3485 static xmlNodePtr 3486 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) { 3487 xmlNsPtr cur; 3488 3489 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) 3490 return(NULL); 3491 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) 3492 return((xmlNodePtr) ns); 3493 3494 /* 3495 * Allocate a new Namespace and fill the fields. 3496 */ 3497 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); 3498 if (cur == NULL) { 3499 xmlXPathErrMemory(NULL, "duplicating namespace\n"); 3500 return(NULL); 3501 } 3502 memset(cur, 0, sizeof(xmlNs)); 3503 cur->type = XML_NAMESPACE_DECL; 3504 if (ns->href != NULL) 3505 cur->href = xmlStrdup(ns->href); 3506 if (ns->prefix != NULL) 3507 cur->prefix = xmlStrdup(ns->prefix); 3508 cur->next = (xmlNsPtr) node; 3509 return((xmlNodePtr) cur); 3510 } 3511 3512 /** 3513 * xmlXPathNodeSetFreeNs: 3514 * @ns: the XPath namespace node found in a nodeset. 3515 * 3516 * Namespace nodes in libxml don't match the XPath semantic. In a node set 3517 * the namespace nodes are duplicated and the next pointer is set to the 3518 * parent node in the XPath semantic. Check if such a node needs to be freed 3519 */ 3520 void 3521 xmlXPathNodeSetFreeNs(xmlNsPtr ns) { 3522 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) 3523 return; 3524 3525 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) { 3526 if (ns->href != NULL) 3527 xmlFree((xmlChar *)ns->href); 3528 if (ns->prefix != NULL) 3529 xmlFree((xmlChar *)ns->prefix); 3530 xmlFree(ns); 3531 } 3532 } 3533 3534 /** 3535 * xmlXPathNodeSetCreate: 3536 * @val: an initial xmlNodePtr, or NULL 3537 * 3538 * Create a new xmlNodeSetPtr of type double and of value @val 3539 * 3540 * Returns the newly created object. 3541 */ 3542 xmlNodeSetPtr 3543 xmlXPathNodeSetCreate(xmlNodePtr val) { 3544 xmlNodeSetPtr ret; 3545 3546 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet)); 3547 if (ret == NULL) { 3548 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3549 return(NULL); 3550 } 3551 memset(ret, 0 , (size_t) sizeof(xmlNodeSet)); 3552 if (val != NULL) { 3553 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3554 sizeof(xmlNodePtr)); 3555 if (ret->nodeTab == NULL) { 3556 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3557 xmlFree(ret); 3558 return(NULL); 3559 } 3560 memset(ret->nodeTab, 0 , 3561 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3562 ret->nodeMax = XML_NODESET_DEFAULT; 3563 if (val->type == XML_NAMESPACE_DECL) { 3564 xmlNsPtr ns = (xmlNsPtr) val; 3565 3566 ret->nodeTab[ret->nodeNr++] = 3567 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3568 } else 3569 ret->nodeTab[ret->nodeNr++] = val; 3570 } 3571 return(ret); 3572 } 3573 3574 /** 3575 * xmlXPathNodeSetCreateSize: 3576 * @size: the initial size of the set 3577 * 3578 * Create a new xmlNodeSetPtr of type double and of value @val 3579 * 3580 * Returns the newly created object. 3581 */ 3582 static xmlNodeSetPtr 3583 xmlXPathNodeSetCreateSize(int size) { 3584 xmlNodeSetPtr ret; 3585 3586 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet)); 3587 if (ret == NULL) { 3588 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3589 return(NULL); 3590 } 3591 memset(ret, 0 , (size_t) sizeof(xmlNodeSet)); 3592 if (size < XML_NODESET_DEFAULT) 3593 size = XML_NODESET_DEFAULT; 3594 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr)); 3595 if (ret->nodeTab == NULL) { 3596 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3597 xmlFree(ret); 3598 return(NULL); 3599 } 3600 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr)); 3601 ret->nodeMax = size; 3602 return(ret); 3603 } 3604 3605 /** 3606 * xmlXPathNodeSetContains: 3607 * @cur: the node-set 3608 * @val: the node 3609 * 3610 * checks whether @cur contains @val 3611 * 3612 * Returns true (1) if @cur contains @val, false (0) otherwise 3613 */ 3614 int 3615 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) { 3616 int i; 3617 3618 if ((cur == NULL) || (val == NULL)) return(0); 3619 if (val->type == XML_NAMESPACE_DECL) { 3620 for (i = 0; i < cur->nodeNr; i++) { 3621 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) { 3622 xmlNsPtr ns1, ns2; 3623 3624 ns1 = (xmlNsPtr) val; 3625 ns2 = (xmlNsPtr) cur->nodeTab[i]; 3626 if (ns1 == ns2) 3627 return(1); 3628 if ((ns1->next != NULL) && (ns2->next == ns1->next) && 3629 (xmlStrEqual(ns1->prefix, ns2->prefix))) 3630 return(1); 3631 } 3632 } 3633 } else { 3634 for (i = 0; i < cur->nodeNr; i++) { 3635 if (cur->nodeTab[i] == val) 3636 return(1); 3637 } 3638 } 3639 return(0); 3640 } 3641 3642 /** 3643 * xmlXPathNodeSetAddNs: 3644 * @cur: the initial node set 3645 * @node: the hosting node 3646 * @ns: a the namespace node 3647 * 3648 * add a new namespace node to an existing NodeSet 3649 * 3650 * Returns 0 in case of success and -1 in case of error 3651 */ 3652 int 3653 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) { 3654 int i; 3655 3656 3657 if ((cur == NULL) || (ns == NULL) || (node == NULL) || 3658 (ns->type != XML_NAMESPACE_DECL) || 3659 (node->type != XML_ELEMENT_NODE)) 3660 return(-1); 3661 3662 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3663 /* 3664 * prevent duplicates 3665 */ 3666 for (i = 0;i < cur->nodeNr;i++) { 3667 if ((cur->nodeTab[i] != NULL) && 3668 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) && 3669 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) && 3670 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix))) 3671 return(0); 3672 } 3673 3674 /* 3675 * grow the nodeTab if needed 3676 */ 3677 if (cur->nodeMax == 0) { 3678 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3679 sizeof(xmlNodePtr)); 3680 if (cur->nodeTab == NULL) { 3681 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3682 return(-1); 3683 } 3684 memset(cur->nodeTab, 0 , 3685 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3686 cur->nodeMax = XML_NODESET_DEFAULT; 3687 } else if (cur->nodeNr == cur->nodeMax) { 3688 xmlNodePtr *temp; 3689 3690 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 3691 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n"); 3692 return(-1); 3693 } 3694 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 * 3695 sizeof(xmlNodePtr)); 3696 if (temp == NULL) { 3697 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3698 return(-1); 3699 } 3700 cur->nodeMax *= 2; 3701 cur->nodeTab = temp; 3702 } 3703 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns); 3704 return(0); 3705 } 3706 3707 /** 3708 * xmlXPathNodeSetAdd: 3709 * @cur: the initial node set 3710 * @val: a new xmlNodePtr 3711 * 3712 * add a new xmlNodePtr to an existing NodeSet 3713 * 3714 * Returns 0 in case of success, and -1 in case of error 3715 */ 3716 int 3717 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) { 3718 int i; 3719 3720 if ((cur == NULL) || (val == NULL)) return(-1); 3721 3722 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3723 /* 3724 * prevent duplicates 3725 */ 3726 for (i = 0;i < cur->nodeNr;i++) 3727 if (cur->nodeTab[i] == val) return(0); 3728 3729 /* 3730 * grow the nodeTab if needed 3731 */ 3732 if (cur->nodeMax == 0) { 3733 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3734 sizeof(xmlNodePtr)); 3735 if (cur->nodeTab == NULL) { 3736 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3737 return(-1); 3738 } 3739 memset(cur->nodeTab, 0 , 3740 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3741 cur->nodeMax = XML_NODESET_DEFAULT; 3742 } else if (cur->nodeNr == cur->nodeMax) { 3743 xmlNodePtr *temp; 3744 3745 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 3746 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n"); 3747 return(-1); 3748 } 3749 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 * 3750 sizeof(xmlNodePtr)); 3751 if (temp == NULL) { 3752 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3753 return(-1); 3754 } 3755 cur->nodeMax *= 2; 3756 cur->nodeTab = temp; 3757 } 3758 if (val->type == XML_NAMESPACE_DECL) { 3759 xmlNsPtr ns = (xmlNsPtr) val; 3760 3761 cur->nodeTab[cur->nodeNr++] = 3762 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3763 } else 3764 cur->nodeTab[cur->nodeNr++] = val; 3765 return(0); 3766 } 3767 3768 /** 3769 * xmlXPathNodeSetAddUnique: 3770 * @cur: the initial node set 3771 * @val: a new xmlNodePtr 3772 * 3773 * add a new xmlNodePtr to an existing NodeSet, optimized version 3774 * when we are sure the node is not already in the set. 3775 * 3776 * Returns 0 in case of success and -1 in case of failure 3777 */ 3778 int 3779 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) { 3780 if ((cur == NULL) || (val == NULL)) return(-1); 3781 3782 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3783 /* 3784 * grow the nodeTab if needed 3785 */ 3786 if (cur->nodeMax == 0) { 3787 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3788 sizeof(xmlNodePtr)); 3789 if (cur->nodeTab == NULL) { 3790 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3791 return(-1); 3792 } 3793 memset(cur->nodeTab, 0 , 3794 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3795 cur->nodeMax = XML_NODESET_DEFAULT; 3796 } else if (cur->nodeNr == cur->nodeMax) { 3797 xmlNodePtr *temp; 3798 3799 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 3800 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n"); 3801 return(-1); 3802 } 3803 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 * 3804 sizeof(xmlNodePtr)); 3805 if (temp == NULL) { 3806 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3807 return(-1); 3808 } 3809 cur->nodeTab = temp; 3810 cur->nodeMax *= 2; 3811 } 3812 if (val->type == XML_NAMESPACE_DECL) { 3813 xmlNsPtr ns = (xmlNsPtr) val; 3814 3815 cur->nodeTab[cur->nodeNr++] = 3816 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3817 } else 3818 cur->nodeTab[cur->nodeNr++] = val; 3819 return(0); 3820 } 3821 3822 /** 3823 * xmlXPathNodeSetMerge: 3824 * @val1: the first NodeSet or NULL 3825 * @val2: the second NodeSet 3826 * 3827 * Merges two nodesets, all nodes from @val2 are added to @val1 3828 * if @val1 is NULL, a new set is created and copied from @val2 3829 * 3830 * Returns @val1 once extended or NULL in case of error. 3831 */ 3832 xmlNodeSetPtr 3833 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) { 3834 int i, j, initNr, skip; 3835 xmlNodePtr n1, n2; 3836 3837 if (val2 == NULL) return(val1); 3838 if (val1 == NULL) { 3839 val1 = xmlXPathNodeSetCreate(NULL); 3840 if (val1 == NULL) 3841 return (NULL); 3842 #if 0 3843 /* 3844 * TODO: The optimization won't work in every case, since 3845 * those nasty namespace nodes need to be added with 3846 * xmlXPathNodeSetDupNs() to the set; thus a pure 3847 * memcpy is not possible. 3848 * If there was a flag on the nodesetval, indicating that 3849 * some temporary nodes are in, that would be helpfull. 3850 */ 3851 /* 3852 * Optimization: Create an equally sized node-set 3853 * and memcpy the content. 3854 */ 3855 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr); 3856 if (val1 == NULL) 3857 return(NULL); 3858 if (val2->nodeNr != 0) { 3859 if (val2->nodeNr == 1) 3860 *(val1->nodeTab) = *(val2->nodeTab); 3861 else { 3862 memcpy(val1->nodeTab, val2->nodeTab, 3863 val2->nodeNr * sizeof(xmlNodePtr)); 3864 } 3865 val1->nodeNr = val2->nodeNr; 3866 } 3867 return(val1); 3868 #endif 3869 } 3870 3871 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3872 initNr = val1->nodeNr; 3873 3874 for (i = 0;i < val2->nodeNr;i++) { 3875 n2 = val2->nodeTab[i]; 3876 /* 3877 * check against duplicates 3878 */ 3879 skip = 0; 3880 for (j = 0; j < initNr; j++) { 3881 n1 = val1->nodeTab[j]; 3882 if (n1 == n2) { 3883 skip = 1; 3884 break; 3885 } else if ((n1->type == XML_NAMESPACE_DECL) && 3886 (n2->type == XML_NAMESPACE_DECL)) { 3887 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) && 3888 (xmlStrEqual(((xmlNsPtr) n1)->prefix, 3889 ((xmlNsPtr) n2)->prefix))) 3890 { 3891 skip = 1; 3892 break; 3893 } 3894 } 3895 } 3896 if (skip) 3897 continue; 3898 3899 /* 3900 * grow the nodeTab if needed 3901 */ 3902 if (val1->nodeMax == 0) { 3903 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3904 sizeof(xmlNodePtr)); 3905 if (val1->nodeTab == NULL) { 3906 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3907 return(NULL); 3908 } 3909 memset(val1->nodeTab, 0 , 3910 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3911 val1->nodeMax = XML_NODESET_DEFAULT; 3912 } else if (val1->nodeNr == val1->nodeMax) { 3913 xmlNodePtr *temp; 3914 3915 if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 3916 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n"); 3917 return(NULL); 3918 } 3919 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 * 3920 sizeof(xmlNodePtr)); 3921 if (temp == NULL) { 3922 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3923 return(NULL); 3924 } 3925 val1->nodeTab = temp; 3926 val1->nodeMax *= 2; 3927 } 3928 if (n2->type == XML_NAMESPACE_DECL) { 3929 xmlNsPtr ns = (xmlNsPtr) n2; 3930 3931 val1->nodeTab[val1->nodeNr++] = 3932 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3933 } else 3934 val1->nodeTab[val1->nodeNr++] = n2; 3935 } 3936 3937 return(val1); 3938 } 3939 3940 3941 /** 3942 * xmlXPathNodeSetMergeAndClear: 3943 * @set1: the first NodeSet or NULL 3944 * @set2: the second NodeSet 3945 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes 3946 * 3947 * Merges two nodesets, all nodes from @set2 are added to @set1 3948 * if @set1 is NULL, a new set is created and copied from @set2. 3949 * Checks for duplicate nodes. Clears set2. 3950 * 3951 * Returns @set1 once extended or NULL in case of error. 3952 */ 3953 static xmlNodeSetPtr 3954 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2, 3955 int hasNullEntries) 3956 { 3957 if ((set1 == NULL) && (hasNullEntries == 0)) { 3958 /* 3959 * Note that doing a memcpy of the list, namespace nodes are 3960 * just assigned to set1, since set2 is cleared anyway. 3961 */ 3962 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr); 3963 if (set1 == NULL) 3964 return(NULL); 3965 if (set2->nodeNr != 0) { 3966 memcpy(set1->nodeTab, set2->nodeTab, 3967 set2->nodeNr * sizeof(xmlNodePtr)); 3968 set1->nodeNr = set2->nodeNr; 3969 } 3970 } else { 3971 int i, j, initNbSet1; 3972 xmlNodePtr n1, n2; 3973 3974 if (set1 == NULL) 3975 set1 = xmlXPathNodeSetCreate(NULL); 3976 if (set1 == NULL) 3977 return (NULL); 3978 3979 initNbSet1 = set1->nodeNr; 3980 for (i = 0;i < set2->nodeNr;i++) { 3981 n2 = set2->nodeTab[i]; 3982 /* 3983 * Skip NULLed entries. 3984 */ 3985 if (n2 == NULL) 3986 continue; 3987 /* 3988 * Skip duplicates. 3989 */ 3990 for (j = 0; j < initNbSet1; j++) { 3991 n1 = set1->nodeTab[j]; 3992 if (n1 == n2) { 3993 goto skip_node; 3994 } else if ((n1->type == XML_NAMESPACE_DECL) && 3995 (n2->type == XML_NAMESPACE_DECL)) 3996 { 3997 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) && 3998 (xmlStrEqual(((xmlNsPtr) n1)->prefix, 3999 ((xmlNsPtr) n2)->prefix))) 4000 { 4001 /* 4002 * Free the namespace node. 4003 */ 4004 set2->nodeTab[i] = NULL; 4005 xmlXPathNodeSetFreeNs((xmlNsPtr) n2); 4006 goto skip_node; 4007 } 4008 } 4009 } 4010 /* 4011 * grow the nodeTab if needed 4012 */ 4013 if (set1->nodeMax == 0) { 4014 set1->nodeTab = (xmlNodePtr *) xmlMalloc( 4015 XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); 4016 if (set1->nodeTab == NULL) { 4017 xmlXPathErrMemory(NULL, "merging nodeset\n"); 4018 return(NULL); 4019 } 4020 memset(set1->nodeTab, 0, 4021 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 4022 set1->nodeMax = XML_NODESET_DEFAULT; 4023 } else if (set1->nodeNr >= set1->nodeMax) { 4024 xmlNodePtr *temp; 4025 4026 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 4027 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n"); 4028 return(NULL); 4029 } 4030 temp = (xmlNodePtr *) xmlRealloc( 4031 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr)); 4032 if (temp == NULL) { 4033 xmlXPathErrMemory(NULL, "merging nodeset\n"); 4034 return(NULL); 4035 } 4036 set1->nodeTab = temp; 4037 set1->nodeMax *= 2; 4038 } 4039 set1->nodeTab[set1->nodeNr++] = n2; 4040 skip_node: 4041 {} 4042 } 4043 } 4044 set2->nodeNr = 0; 4045 return(set1); 4046 } 4047 4048 /** 4049 * xmlXPathNodeSetMergeAndClearNoDupls: 4050 * @set1: the first NodeSet or NULL 4051 * @set2: the second NodeSet 4052 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes 4053 * 4054 * Merges two nodesets, all nodes from @set2 are added to @set1 4055 * if @set1 is NULL, a new set is created and copied from @set2. 4056 * Doesn't chack for duplicate nodes. Clears set2. 4057 * 4058 * Returns @set1 once extended or NULL in case of error. 4059 */ 4060 static xmlNodeSetPtr 4061 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2, 4062 int hasNullEntries) 4063 { 4064 if (set2 == NULL) 4065 return(set1); 4066 if ((set1 == NULL) && (hasNullEntries == 0)) { 4067 /* 4068 * Note that doing a memcpy of the list, namespace nodes are 4069 * just assigned to set1, since set2 is cleared anyway. 4070 */ 4071 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr); 4072 if (set1 == NULL) 4073 return(NULL); 4074 if (set2->nodeNr != 0) { 4075 memcpy(set1->nodeTab, set2->nodeTab, 4076 set2->nodeNr * sizeof(xmlNodePtr)); 4077 set1->nodeNr = set2->nodeNr; 4078 } 4079 } else { 4080 int i; 4081 xmlNodePtr n2; 4082 4083 if (set1 == NULL) 4084 set1 = xmlXPathNodeSetCreate(NULL); 4085 if (set1 == NULL) 4086 return (NULL); 4087 4088 for (i = 0;i < set2->nodeNr;i++) { 4089 n2 = set2->nodeTab[i]; 4090 /* 4091 * Skip NULLed entries. 4092 */ 4093 if (n2 == NULL) 4094 continue; 4095 if (set1->nodeMax == 0) { 4096 set1->nodeTab = (xmlNodePtr *) xmlMalloc( 4097 XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); 4098 if (set1->nodeTab == NULL) { 4099 xmlXPathErrMemory(NULL, "merging nodeset\n"); 4100 return(NULL); 4101 } 4102 memset(set1->nodeTab, 0, 4103 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 4104 set1->nodeMax = XML_NODESET_DEFAULT; 4105 } else if (set1->nodeNr >= set1->nodeMax) { 4106 xmlNodePtr *temp; 4107 4108 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 4109 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n"); 4110 return(NULL); 4111 } 4112 temp = (xmlNodePtr *) xmlRealloc( 4113 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr)); 4114 if (temp == NULL) { 4115 xmlXPathErrMemory(NULL, "merging nodeset\n"); 4116 return(NULL); 4117 } 4118 set1->nodeTab = temp; 4119 set1->nodeMax *= 2; 4120 } 4121 set1->nodeTab[set1->nodeNr++] = n2; 4122 } 4123 } 4124 set2->nodeNr = 0; 4125 return(set1); 4126 } 4127 4128 /** 4129 * xmlXPathNodeSetDel: 4130 * @cur: the initial node set 4131 * @val: an xmlNodePtr 4132 * 4133 * Removes an xmlNodePtr from an existing NodeSet 4134 */ 4135 void 4136 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) { 4137 int i; 4138 4139 if (cur == NULL) return; 4140 if (val == NULL) return; 4141 4142 /* 4143 * find node in nodeTab 4144 */ 4145 for (i = 0;i < cur->nodeNr;i++) 4146 if (cur->nodeTab[i] == val) break; 4147 4148 if (i >= cur->nodeNr) { /* not found */ 4149 #ifdef DEBUG 4150 xmlGenericError(xmlGenericErrorContext, 4151 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n", 4152 val->name); 4153 #endif 4154 return; 4155 } 4156 if ((cur->nodeTab[i] != NULL) && 4157 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL)) 4158 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]); 4159 cur->nodeNr--; 4160 for (;i < cur->nodeNr;i++) 4161 cur->nodeTab[i] = cur->nodeTab[i + 1]; 4162 cur->nodeTab[cur->nodeNr] = NULL; 4163 } 4164 4165 /** 4166 * xmlXPathNodeSetRemove: 4167 * @cur: the initial node set 4168 * @val: the index to remove 4169 * 4170 * Removes an entry from an existing NodeSet list. 4171 */ 4172 void 4173 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) { 4174 if (cur == NULL) return; 4175 if (val >= cur->nodeNr) return; 4176 if ((cur->nodeTab[val] != NULL) && 4177 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL)) 4178 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]); 4179 cur->nodeNr--; 4180 for (;val < cur->nodeNr;val++) 4181 cur->nodeTab[val] = cur->nodeTab[val + 1]; 4182 cur->nodeTab[cur->nodeNr] = NULL; 4183 } 4184 4185 /** 4186 * xmlXPathFreeNodeSet: 4187 * @obj: the xmlNodeSetPtr to free 4188 * 4189 * Free the NodeSet compound (not the actual nodes !). 4190 */ 4191 void 4192 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) { 4193 if (obj == NULL) return; 4194 if (obj->nodeTab != NULL) { 4195 int i; 4196 4197 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 4198 for (i = 0;i < obj->nodeNr;i++) 4199 if ((obj->nodeTab[i] != NULL) && 4200 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL)) 4201 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]); 4202 xmlFree(obj->nodeTab); 4203 } 4204 xmlFree(obj); 4205 } 4206 4207 /** 4208 * xmlXPathNodeSetClearFromPos: 4209 * @set: the node set to be cleared 4210 * @pos: the start position to clear from 4211 * 4212 * Clears the list from temporary XPath objects (e.g. namespace nodes 4213 * are feed) starting with the entry at @pos, but does *not* free the list 4214 * itself. Sets the length of the list to @pos. 4215 */ 4216 static void 4217 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes) 4218 { 4219 if ((set == NULL) || (pos >= set->nodeNr)) 4220 return; 4221 else if ((hasNsNodes)) { 4222 int i; 4223 xmlNodePtr node; 4224 4225 for (i = pos; i < set->nodeNr; i++) { 4226 node = set->nodeTab[i]; 4227 if ((node != NULL) && 4228 (node->type == XML_NAMESPACE_DECL)) 4229 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 4230 } 4231 } 4232 set->nodeNr = pos; 4233 } 4234 4235 /** 4236 * xmlXPathNodeSetClear: 4237 * @set: the node set to clear 4238 * 4239 * Clears the list from all temporary XPath objects (e.g. namespace nodes 4240 * are feed), but does *not* free the list itself. Sets the length of the 4241 * list to 0. 4242 */ 4243 static void 4244 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes) 4245 { 4246 xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes); 4247 } 4248 4249 /** 4250 * xmlXPathNodeSetKeepLast: 4251 * @set: the node set to be cleared 4252 * 4253 * Move the last node to the first position and clear temporary XPath objects 4254 * (e.g. namespace nodes) from all other nodes. Sets the length of the list 4255 * to 1. 4256 */ 4257 static void 4258 xmlXPathNodeSetKeepLast(xmlNodeSetPtr set) 4259 { 4260 int i; 4261 xmlNodePtr node; 4262 4263 if ((set == NULL) || (set->nodeNr <= 1)) 4264 return; 4265 for (i = 0; i < set->nodeNr - 1; i++) { 4266 node = set->nodeTab[i]; 4267 if ((node != NULL) && 4268 (node->type == XML_NAMESPACE_DECL)) 4269 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 4270 } 4271 set->nodeTab[0] = set->nodeTab[set->nodeNr-1]; 4272 set->nodeNr = 1; 4273 } 4274 4275 /** 4276 * xmlXPathFreeValueTree: 4277 * @obj: the xmlNodeSetPtr to free 4278 * 4279 * Free the NodeSet compound and the actual tree, this is different 4280 * from xmlXPathFreeNodeSet() 4281 */ 4282 static void 4283 xmlXPathFreeValueTree(xmlNodeSetPtr obj) { 4284 int i; 4285 4286 if (obj == NULL) return; 4287 4288 if (obj->nodeTab != NULL) { 4289 for (i = 0;i < obj->nodeNr;i++) { 4290 if (obj->nodeTab[i] != NULL) { 4291 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) { 4292 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]); 4293 } else { 4294 xmlFreeNodeList(obj->nodeTab[i]); 4295 } 4296 } 4297 } 4298 xmlFree(obj->nodeTab); 4299 } 4300 xmlFree(obj); 4301 } 4302 4303 #if defined(DEBUG) || defined(DEBUG_STEP) 4304 /** 4305 * xmlGenericErrorContextNodeSet: 4306 * @output: a FILE * for the output 4307 * @obj: the xmlNodeSetPtr to display 4308 * 4309 * Quick display of a NodeSet 4310 */ 4311 void 4312 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) { 4313 int i; 4314 4315 if (output == NULL) output = xmlGenericErrorContext; 4316 if (obj == NULL) { 4317 fprintf(output, "NodeSet == NULL !\n"); 4318 return; 4319 } 4320 if (obj->nodeNr == 0) { 4321 fprintf(output, "NodeSet is empty\n"); 4322 return; 4323 } 4324 if (obj->nodeTab == NULL) { 4325 fprintf(output, " nodeTab == NULL !\n"); 4326 return; 4327 } 4328 for (i = 0; i < obj->nodeNr; i++) { 4329 if (obj->nodeTab[i] == NULL) { 4330 fprintf(output, " NULL !\n"); 4331 return; 4332 } 4333 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) || 4334 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE)) 4335 fprintf(output, " /"); 4336 else if (obj->nodeTab[i]->name == NULL) 4337 fprintf(output, " noname!"); 4338 else fprintf(output, " %s", obj->nodeTab[i]->name); 4339 } 4340 fprintf(output, "\n"); 4341 } 4342 #endif 4343 4344 /** 4345 * xmlXPathNewNodeSet: 4346 * @val: the NodePtr value 4347 * 4348 * Create a new xmlXPathObjectPtr of type NodeSet and initialize 4349 * it with the single Node @val 4350 * 4351 * Returns the newly created object. 4352 */ 4353 xmlXPathObjectPtr 4354 xmlXPathNewNodeSet(xmlNodePtr val) { 4355 xmlXPathObjectPtr ret; 4356 4357 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4358 if (ret == NULL) { 4359 xmlXPathErrMemory(NULL, "creating nodeset\n"); 4360 return(NULL); 4361 } 4362 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4363 ret->type = XPATH_NODESET; 4364 ret->boolval = 0; 4365 ret->nodesetval = xmlXPathNodeSetCreate(val); 4366 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 4367 #ifdef XP_DEBUG_OBJ_USAGE 4368 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET); 4369 #endif 4370 return(ret); 4371 } 4372 4373 /** 4374 * xmlXPathNewValueTree: 4375 * @val: the NodePtr value 4376 * 4377 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize 4378 * it with the tree root @val 4379 * 4380 * Returns the newly created object. 4381 */ 4382 xmlXPathObjectPtr 4383 xmlXPathNewValueTree(xmlNodePtr val) { 4384 xmlXPathObjectPtr ret; 4385 4386 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4387 if (ret == NULL) { 4388 xmlXPathErrMemory(NULL, "creating result value tree\n"); 4389 return(NULL); 4390 } 4391 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4392 ret->type = XPATH_XSLT_TREE; 4393 ret->boolval = 1; 4394 ret->user = (void *) val; 4395 ret->nodesetval = xmlXPathNodeSetCreate(val); 4396 #ifdef XP_DEBUG_OBJ_USAGE 4397 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE); 4398 #endif 4399 return(ret); 4400 } 4401 4402 /** 4403 * xmlXPathNewNodeSetList: 4404 * @val: an existing NodeSet 4405 * 4406 * Create a new xmlXPathObjectPtr of type NodeSet and initialize 4407 * it with the Nodeset @val 4408 * 4409 * Returns the newly created object. 4410 */ 4411 xmlXPathObjectPtr 4412 xmlXPathNewNodeSetList(xmlNodeSetPtr val) 4413 { 4414 xmlXPathObjectPtr ret; 4415 int i; 4416 4417 if (val == NULL) 4418 ret = NULL; 4419 else if (val->nodeTab == NULL) 4420 ret = xmlXPathNewNodeSet(NULL); 4421 else { 4422 ret = xmlXPathNewNodeSet(val->nodeTab[0]); 4423 if (ret) { 4424 for (i = 1; i < val->nodeNr; ++i) { 4425 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]) 4426 < 0) break; 4427 } 4428 } 4429 } 4430 4431 return (ret); 4432 } 4433 4434 /** 4435 * xmlXPathWrapNodeSet: 4436 * @val: the NodePtr value 4437 * 4438 * Wrap the Nodeset @val in a new xmlXPathObjectPtr 4439 * 4440 * Returns the newly created object. 4441 */ 4442 xmlXPathObjectPtr 4443 xmlXPathWrapNodeSet(xmlNodeSetPtr val) { 4444 xmlXPathObjectPtr ret; 4445 4446 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4447 if (ret == NULL) { 4448 xmlXPathErrMemory(NULL, "creating node set object\n"); 4449 return(NULL); 4450 } 4451 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4452 ret->type = XPATH_NODESET; 4453 ret->nodesetval = val; 4454 #ifdef XP_DEBUG_OBJ_USAGE 4455 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET); 4456 #endif 4457 return(ret); 4458 } 4459 4460 /** 4461 * xmlXPathFreeNodeSetList: 4462 * @obj: an existing NodeSetList object 4463 * 4464 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in 4465 * the list contrary to xmlXPathFreeObject(). 4466 */ 4467 void 4468 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) { 4469 if (obj == NULL) return; 4470 #ifdef XP_DEBUG_OBJ_USAGE 4471 xmlXPathDebugObjUsageReleased(NULL, obj->type); 4472 #endif 4473 xmlFree(obj); 4474 } 4475 4476 /** 4477 * xmlXPathDifference: 4478 * @nodes1: a node-set 4479 * @nodes2: a node-set 4480 * 4481 * Implements the EXSLT - Sets difference() function: 4482 * node-set set:difference (node-set, node-set) 4483 * 4484 * Returns the difference between the two node sets, or nodes1 if 4485 * nodes2 is empty 4486 */ 4487 xmlNodeSetPtr 4488 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4489 xmlNodeSetPtr ret; 4490 int i, l1; 4491 xmlNodePtr cur; 4492 4493 if (xmlXPathNodeSetIsEmpty(nodes2)) 4494 return(nodes1); 4495 4496 ret = xmlXPathNodeSetCreate(NULL); 4497 if (xmlXPathNodeSetIsEmpty(nodes1)) 4498 return(ret); 4499 4500 l1 = xmlXPathNodeSetGetLength(nodes1); 4501 4502 for (i = 0; i < l1; i++) { 4503 cur = xmlXPathNodeSetItem(nodes1, i); 4504 if (!xmlXPathNodeSetContains(nodes2, cur)) { 4505 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) 4506 break; 4507 } 4508 } 4509 return(ret); 4510 } 4511 4512 /** 4513 * xmlXPathIntersection: 4514 * @nodes1: a node-set 4515 * @nodes2: a node-set 4516 * 4517 * Implements the EXSLT - Sets intersection() function: 4518 * node-set set:intersection (node-set, node-set) 4519 * 4520 * Returns a node set comprising the nodes that are within both the 4521 * node sets passed as arguments 4522 */ 4523 xmlNodeSetPtr 4524 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4525 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL); 4526 int i, l1; 4527 xmlNodePtr cur; 4528 4529 if (ret == NULL) 4530 return(ret); 4531 if (xmlXPathNodeSetIsEmpty(nodes1)) 4532 return(ret); 4533 if (xmlXPathNodeSetIsEmpty(nodes2)) 4534 return(ret); 4535 4536 l1 = xmlXPathNodeSetGetLength(nodes1); 4537 4538 for (i = 0; i < l1; i++) { 4539 cur = xmlXPathNodeSetItem(nodes1, i); 4540 if (xmlXPathNodeSetContains(nodes2, cur)) { 4541 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) 4542 break; 4543 } 4544 } 4545 return(ret); 4546 } 4547 4548 /** 4549 * xmlXPathDistinctSorted: 4550 * @nodes: a node-set, sorted by document order 4551 * 4552 * Implements the EXSLT - Sets distinct() function: 4553 * node-set set:distinct (node-set) 4554 * 4555 * Returns a subset of the nodes contained in @nodes, or @nodes if 4556 * it is empty 4557 */ 4558 xmlNodeSetPtr 4559 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) { 4560 xmlNodeSetPtr ret; 4561 xmlHashTablePtr hash; 4562 int i, l; 4563 xmlChar * strval; 4564 xmlNodePtr cur; 4565 4566 if (xmlXPathNodeSetIsEmpty(nodes)) 4567 return(nodes); 4568 4569 ret = xmlXPathNodeSetCreate(NULL); 4570 if (ret == NULL) 4571 return(ret); 4572 l = xmlXPathNodeSetGetLength(nodes); 4573 hash = xmlHashCreate (l); 4574 for (i = 0; i < l; i++) { 4575 cur = xmlXPathNodeSetItem(nodes, i); 4576 strval = xmlXPathCastNodeToString(cur); 4577 if (xmlHashLookup(hash, strval) == NULL) { 4578 xmlHashAddEntry(hash, strval, strval); 4579 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) 4580 break; 4581 } else { 4582 xmlFree(strval); 4583 } 4584 } 4585 xmlHashFree(hash, (xmlHashDeallocator) xmlFree); 4586 return(ret); 4587 } 4588 4589 /** 4590 * xmlXPathDistinct: 4591 * @nodes: a node-set 4592 * 4593 * Implements the EXSLT - Sets distinct() function: 4594 * node-set set:distinct (node-set) 4595 * @nodes is sorted by document order, then #exslSetsDistinctSorted 4596 * is called with the sorted node-set 4597 * 4598 * Returns a subset of the nodes contained in @nodes, or @nodes if 4599 * it is empty 4600 */ 4601 xmlNodeSetPtr 4602 xmlXPathDistinct (xmlNodeSetPtr nodes) { 4603 if (xmlXPathNodeSetIsEmpty(nodes)) 4604 return(nodes); 4605 4606 xmlXPathNodeSetSort(nodes); 4607 return(xmlXPathDistinctSorted(nodes)); 4608 } 4609 4610 /** 4611 * xmlXPathHasSameNodes: 4612 * @nodes1: a node-set 4613 * @nodes2: a node-set 4614 * 4615 * Implements the EXSLT - Sets has-same-nodes function: 4616 * boolean set:has-same-node(node-set, node-set) 4617 * 4618 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0) 4619 * otherwise 4620 */ 4621 int 4622 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4623 int i, l; 4624 xmlNodePtr cur; 4625 4626 if (xmlXPathNodeSetIsEmpty(nodes1) || 4627 xmlXPathNodeSetIsEmpty(nodes2)) 4628 return(0); 4629 4630 l = xmlXPathNodeSetGetLength(nodes1); 4631 for (i = 0; i < l; i++) { 4632 cur = xmlXPathNodeSetItem(nodes1, i); 4633 if (xmlXPathNodeSetContains(nodes2, cur)) 4634 return(1); 4635 } 4636 return(0); 4637 } 4638 4639 /** 4640 * xmlXPathNodeLeadingSorted: 4641 * @nodes: a node-set, sorted by document order 4642 * @node: a node 4643 * 4644 * Implements the EXSLT - Sets leading() function: 4645 * node-set set:leading (node-set, node-set) 4646 * 4647 * Returns the nodes in @nodes that precede @node in document order, 4648 * @nodes if @node is NULL or an empty node-set if @nodes 4649 * doesn't contain @node 4650 */ 4651 xmlNodeSetPtr 4652 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { 4653 int i, l; 4654 xmlNodePtr cur; 4655 xmlNodeSetPtr ret; 4656 4657 if (node == NULL) 4658 return(nodes); 4659 4660 ret = xmlXPathNodeSetCreate(NULL); 4661 if (ret == NULL) 4662 return(ret); 4663 if (xmlXPathNodeSetIsEmpty(nodes) || 4664 (!xmlXPathNodeSetContains(nodes, node))) 4665 return(ret); 4666 4667 l = xmlXPathNodeSetGetLength(nodes); 4668 for (i = 0; i < l; i++) { 4669 cur = xmlXPathNodeSetItem(nodes, i); 4670 if (cur == node) 4671 break; 4672 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) 4673 break; 4674 } 4675 return(ret); 4676 } 4677 4678 /** 4679 * xmlXPathNodeLeading: 4680 * @nodes: a node-set 4681 * @node: a node 4682 * 4683 * Implements the EXSLT - Sets leading() function: 4684 * node-set set:leading (node-set, node-set) 4685 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted 4686 * is called. 4687 * 4688 * Returns the nodes in @nodes that precede @node in document order, 4689 * @nodes if @node is NULL or an empty node-set if @nodes 4690 * doesn't contain @node 4691 */ 4692 xmlNodeSetPtr 4693 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) { 4694 xmlXPathNodeSetSort(nodes); 4695 return(xmlXPathNodeLeadingSorted(nodes, node)); 4696 } 4697 4698 /** 4699 * xmlXPathLeadingSorted: 4700 * @nodes1: a node-set, sorted by document order 4701 * @nodes2: a node-set, sorted by document order 4702 * 4703 * Implements the EXSLT - Sets leading() function: 4704 * node-set set:leading (node-set, node-set) 4705 * 4706 * Returns the nodes in @nodes1 that precede the first node in @nodes2 4707 * in document order, @nodes1 if @nodes2 is NULL or empty or 4708 * an empty node-set if @nodes1 doesn't contain @nodes2 4709 */ 4710 xmlNodeSetPtr 4711 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4712 if (xmlXPathNodeSetIsEmpty(nodes2)) 4713 return(nodes1); 4714 return(xmlXPathNodeLeadingSorted(nodes1, 4715 xmlXPathNodeSetItem(nodes2, 1))); 4716 } 4717 4718 /** 4719 * xmlXPathLeading: 4720 * @nodes1: a node-set 4721 * @nodes2: a node-set 4722 * 4723 * Implements the EXSLT - Sets leading() function: 4724 * node-set set:leading (node-set, node-set) 4725 * @nodes1 and @nodes2 are sorted by document order, then 4726 * #exslSetsLeadingSorted is called. 4727 * 4728 * Returns the nodes in @nodes1 that precede the first node in @nodes2 4729 * in document order, @nodes1 if @nodes2 is NULL or empty or 4730 * an empty node-set if @nodes1 doesn't contain @nodes2 4731 */ 4732 xmlNodeSetPtr 4733 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4734 if (xmlXPathNodeSetIsEmpty(nodes2)) 4735 return(nodes1); 4736 if (xmlXPathNodeSetIsEmpty(nodes1)) 4737 return(xmlXPathNodeSetCreate(NULL)); 4738 xmlXPathNodeSetSort(nodes1); 4739 xmlXPathNodeSetSort(nodes2); 4740 return(xmlXPathNodeLeadingSorted(nodes1, 4741 xmlXPathNodeSetItem(nodes2, 1))); 4742 } 4743 4744 /** 4745 * xmlXPathNodeTrailingSorted: 4746 * @nodes: a node-set, sorted by document order 4747 * @node: a node 4748 * 4749 * Implements the EXSLT - Sets trailing() function: 4750 * node-set set:trailing (node-set, node-set) 4751 * 4752 * Returns the nodes in @nodes that follow @node in document order, 4753 * @nodes if @node is NULL or an empty node-set if @nodes 4754 * doesn't contain @node 4755 */ 4756 xmlNodeSetPtr 4757 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { 4758 int i, l; 4759 xmlNodePtr cur; 4760 xmlNodeSetPtr ret; 4761 4762 if (node == NULL) 4763 return(nodes); 4764 4765 ret = xmlXPathNodeSetCreate(NULL); 4766 if (ret == NULL) 4767 return(ret); 4768 if (xmlXPathNodeSetIsEmpty(nodes) || 4769 (!xmlXPathNodeSetContains(nodes, node))) 4770 return(ret); 4771 4772 l = xmlXPathNodeSetGetLength(nodes); 4773 for (i = l - 1; i >= 0; i--) { 4774 cur = xmlXPathNodeSetItem(nodes, i); 4775 if (cur == node) 4776 break; 4777 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) 4778 break; 4779 } 4780 xmlXPathNodeSetSort(ret); /* bug 413451 */ 4781 return(ret); 4782 } 4783 4784 /** 4785 * xmlXPathNodeTrailing: 4786 * @nodes: a node-set 4787 * @node: a node 4788 * 4789 * Implements the EXSLT - Sets trailing() function: 4790 * node-set set:trailing (node-set, node-set) 4791 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted 4792 * is called. 4793 * 4794 * Returns the nodes in @nodes that follow @node in document order, 4795 * @nodes if @node is NULL or an empty node-set if @nodes 4796 * doesn't contain @node 4797 */ 4798 xmlNodeSetPtr 4799 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) { 4800 xmlXPathNodeSetSort(nodes); 4801 return(xmlXPathNodeTrailingSorted(nodes, node)); 4802 } 4803 4804 /** 4805 * xmlXPathTrailingSorted: 4806 * @nodes1: a node-set, sorted by document order 4807 * @nodes2: a node-set, sorted by document order 4808 * 4809 * Implements the EXSLT - Sets trailing() function: 4810 * node-set set:trailing (node-set, node-set) 4811 * 4812 * Returns the nodes in @nodes1 that follow the first node in @nodes2 4813 * in document order, @nodes1 if @nodes2 is NULL or empty or 4814 * an empty node-set if @nodes1 doesn't contain @nodes2 4815 */ 4816 xmlNodeSetPtr 4817 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4818 if (xmlXPathNodeSetIsEmpty(nodes2)) 4819 return(nodes1); 4820 return(xmlXPathNodeTrailingSorted(nodes1, 4821 xmlXPathNodeSetItem(nodes2, 0))); 4822 } 4823 4824 /** 4825 * xmlXPathTrailing: 4826 * @nodes1: a node-set 4827 * @nodes2: a node-set 4828 * 4829 * Implements the EXSLT - Sets trailing() function: 4830 * node-set set:trailing (node-set, node-set) 4831 * @nodes1 and @nodes2 are sorted by document order, then 4832 * #xmlXPathTrailingSorted is called. 4833 * 4834 * Returns the nodes in @nodes1 that follow the first node in @nodes2 4835 * in document order, @nodes1 if @nodes2 is NULL or empty or 4836 * an empty node-set if @nodes1 doesn't contain @nodes2 4837 */ 4838 xmlNodeSetPtr 4839 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4840 if (xmlXPathNodeSetIsEmpty(nodes2)) 4841 return(nodes1); 4842 if (xmlXPathNodeSetIsEmpty(nodes1)) 4843 return(xmlXPathNodeSetCreate(NULL)); 4844 xmlXPathNodeSetSort(nodes1); 4845 xmlXPathNodeSetSort(nodes2); 4846 return(xmlXPathNodeTrailingSorted(nodes1, 4847 xmlXPathNodeSetItem(nodes2, 0))); 4848 } 4849 4850 /************************************************************************ 4851 * * 4852 * Routines to handle extra functions * 4853 * * 4854 ************************************************************************/ 4855 4856 /** 4857 * xmlXPathRegisterFunc: 4858 * @ctxt: the XPath context 4859 * @name: the function name 4860 * @f: the function implementation or NULL 4861 * 4862 * Register a new function. If @f is NULL it unregisters the function 4863 * 4864 * Returns 0 in case of success, -1 in case of error 4865 */ 4866 int 4867 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name, 4868 xmlXPathFunction f) { 4869 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f)); 4870 } 4871 4872 /** 4873 * xmlXPathRegisterFuncNS: 4874 * @ctxt: the XPath context 4875 * @name: the function name 4876 * @ns_uri: the function namespace URI 4877 * @f: the function implementation or NULL 4878 * 4879 * Register a new function. If @f is NULL it unregisters the function 4880 * 4881 * Returns 0 in case of success, -1 in case of error 4882 */ 4883 int 4884 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name, 4885 const xmlChar *ns_uri, xmlXPathFunction f) { 4886 if (ctxt == NULL) 4887 return(-1); 4888 if (name == NULL) 4889 return(-1); 4890 4891 if (ctxt->funcHash == NULL) 4892 ctxt->funcHash = xmlHashCreate(0); 4893 if (ctxt->funcHash == NULL) 4894 return(-1); 4895 if (f == NULL) 4896 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL)); 4897 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f))); 4898 } 4899 4900 /** 4901 * xmlXPathRegisterFuncLookup: 4902 * @ctxt: the XPath context 4903 * @f: the lookup function 4904 * @funcCtxt: the lookup data 4905 * 4906 * Registers an external mechanism to do function lookup. 4907 */ 4908 void 4909 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt, 4910 xmlXPathFuncLookupFunc f, 4911 void *funcCtxt) { 4912 if (ctxt == NULL) 4913 return; 4914 ctxt->funcLookupFunc = f; 4915 ctxt->funcLookupData = funcCtxt; 4916 } 4917 4918 /** 4919 * xmlXPathFunctionLookup: 4920 * @ctxt: the XPath context 4921 * @name: the function name 4922 * 4923 * Search in the Function array of the context for the given 4924 * function. 4925 * 4926 * Returns the xmlXPathFunction or NULL if not found 4927 */ 4928 xmlXPathFunction 4929 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { 4930 if (ctxt == NULL) 4931 return (NULL); 4932 4933 if (ctxt->funcLookupFunc != NULL) { 4934 xmlXPathFunction ret; 4935 xmlXPathFuncLookupFunc f; 4936 4937 f = ctxt->funcLookupFunc; 4938 ret = f(ctxt->funcLookupData, name, NULL); 4939 if (ret != NULL) 4940 return(ret); 4941 } 4942 return(xmlXPathFunctionLookupNS(ctxt, name, NULL)); 4943 } 4944 4945 /** 4946 * xmlXPathFunctionLookupNS: 4947 * @ctxt: the XPath context 4948 * @name: the function name 4949 * @ns_uri: the function namespace URI 4950 * 4951 * Search in the Function array of the context for the given 4952 * function. 4953 * 4954 * Returns the xmlXPathFunction or NULL if not found 4955 */ 4956 xmlXPathFunction 4957 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name, 4958 const xmlChar *ns_uri) { 4959 xmlXPathFunction ret; 4960 4961 if (ctxt == NULL) 4962 return(NULL); 4963 if (name == NULL) 4964 return(NULL); 4965 4966 if (ctxt->funcLookupFunc != NULL) { 4967 xmlXPathFuncLookupFunc f; 4968 4969 f = ctxt->funcLookupFunc; 4970 ret = f(ctxt->funcLookupData, name, ns_uri); 4971 if (ret != NULL) 4972 return(ret); 4973 } 4974 4975 if (ctxt->funcHash == NULL) 4976 return(NULL); 4977 4978 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri); 4979 return(ret); 4980 } 4981 4982 /** 4983 * xmlXPathRegisteredFuncsCleanup: 4984 * @ctxt: the XPath context 4985 * 4986 * Cleanup the XPath context data associated to registered functions 4987 */ 4988 void 4989 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) { 4990 if (ctxt == NULL) 4991 return; 4992 4993 xmlHashFree(ctxt->funcHash, NULL); 4994 ctxt->funcHash = NULL; 4995 } 4996 4997 /************************************************************************ 4998 * * 4999 * Routines to handle Variables * 5000 * * 5001 ************************************************************************/ 5002 5003 /** 5004 * xmlXPathRegisterVariable: 5005 * @ctxt: the XPath context 5006 * @name: the variable name 5007 * @value: the variable value or NULL 5008 * 5009 * Register a new variable value. If @value is NULL it unregisters 5010 * the variable 5011 * 5012 * Returns 0 in case of success, -1 in case of error 5013 */ 5014 int 5015 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name, 5016 xmlXPathObjectPtr value) { 5017 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value)); 5018 } 5019 5020 /** 5021 * xmlXPathRegisterVariableNS: 5022 * @ctxt: the XPath context 5023 * @name: the variable name 5024 * @ns_uri: the variable namespace URI 5025 * @value: the variable value or NULL 5026 * 5027 * Register a new variable value. If @value is NULL it unregisters 5028 * the variable 5029 * 5030 * Returns 0 in case of success, -1 in case of error 5031 */ 5032 int 5033 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name, 5034 const xmlChar *ns_uri, 5035 xmlXPathObjectPtr value) { 5036 if (ctxt == NULL) 5037 return(-1); 5038 if (name == NULL) 5039 return(-1); 5040 5041 if (ctxt->varHash == NULL) 5042 ctxt->varHash = xmlHashCreate(0); 5043 if (ctxt->varHash == NULL) 5044 return(-1); 5045 if (value == NULL) 5046 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri, 5047 (xmlHashDeallocator)xmlXPathFreeObject)); 5048 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri, 5049 (void *) value, 5050 (xmlHashDeallocator)xmlXPathFreeObject)); 5051 } 5052 5053 /** 5054 * xmlXPathRegisterVariableLookup: 5055 * @ctxt: the XPath context 5056 * @f: the lookup function 5057 * @data: the lookup data 5058 * 5059 * register an external mechanism to do variable lookup 5060 */ 5061 void 5062 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt, 5063 xmlXPathVariableLookupFunc f, void *data) { 5064 if (ctxt == NULL) 5065 return; 5066 ctxt->varLookupFunc = f; 5067 ctxt->varLookupData = data; 5068 } 5069 5070 /** 5071 * xmlXPathVariableLookup: 5072 * @ctxt: the XPath context 5073 * @name: the variable name 5074 * 5075 * Search in the Variable array of the context for the given 5076 * variable value. 5077 * 5078 * Returns a copy of the value or NULL if not found 5079 */ 5080 xmlXPathObjectPtr 5081 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { 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, NULL); 5090 return(ret); 5091 } 5092 return(xmlXPathVariableLookupNS(ctxt, name, NULL)); 5093 } 5094 5095 /** 5096 * xmlXPathVariableLookupNS: 5097 * @ctxt: the XPath context 5098 * @name: the variable name 5099 * @ns_uri: the variable namespace URI 5100 * 5101 * Search in the Variable array of the context for the given 5102 * variable value. 5103 * 5104 * Returns the a copy of the value or NULL if not found 5105 */ 5106 xmlXPathObjectPtr 5107 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name, 5108 const xmlChar *ns_uri) { 5109 if (ctxt == NULL) 5110 return(NULL); 5111 5112 if (ctxt->varLookupFunc != NULL) { 5113 xmlXPathObjectPtr ret; 5114 5115 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc) 5116 (ctxt->varLookupData, name, ns_uri); 5117 if (ret != NULL) return(ret); 5118 } 5119 5120 if (ctxt->varHash == NULL) 5121 return(NULL); 5122 if (name == NULL) 5123 return(NULL); 5124 5125 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr) 5126 xmlHashLookup2(ctxt->varHash, name, ns_uri))); 5127 } 5128 5129 /** 5130 * xmlXPathRegisteredVariablesCleanup: 5131 * @ctxt: the XPath context 5132 * 5133 * Cleanup the XPath context data associated to registered variables 5134 */ 5135 void 5136 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) { 5137 if (ctxt == NULL) 5138 return; 5139 5140 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject); 5141 ctxt->varHash = NULL; 5142 } 5143 5144 /** 5145 * xmlXPathRegisterNs: 5146 * @ctxt: the XPath context 5147 * @prefix: the namespace prefix cannot be NULL or empty string 5148 * @ns_uri: the namespace name 5149 * 5150 * Register a new namespace. If @ns_uri is NULL it unregisters 5151 * the namespace 5152 * 5153 * Returns 0 in case of success, -1 in case of error 5154 */ 5155 int 5156 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix, 5157 const xmlChar *ns_uri) { 5158 if (ctxt == NULL) 5159 return(-1); 5160 if (prefix == NULL) 5161 return(-1); 5162 if (prefix[0] == 0) 5163 return(-1); 5164 5165 if (ctxt->nsHash == NULL) 5166 ctxt->nsHash = xmlHashCreate(10); 5167 if (ctxt->nsHash == NULL) 5168 return(-1); 5169 if (ns_uri == NULL) 5170 return(xmlHashRemoveEntry(ctxt->nsHash, prefix, 5171 (xmlHashDeallocator)xmlFree)); 5172 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri), 5173 (xmlHashDeallocator)xmlFree)); 5174 } 5175 5176 /** 5177 * xmlXPathNsLookup: 5178 * @ctxt: the XPath context 5179 * @prefix: the namespace prefix value 5180 * 5181 * Search in the namespace declaration array of the context for the given 5182 * namespace name associated to the given prefix 5183 * 5184 * Returns the value or NULL if not found 5185 */ 5186 const xmlChar * 5187 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) { 5188 if (ctxt == NULL) 5189 return(NULL); 5190 if (prefix == NULL) 5191 return(NULL); 5192 5193 #ifdef XML_XML_NAMESPACE 5194 if (xmlStrEqual(prefix, (const xmlChar *) "xml")) 5195 return(XML_XML_NAMESPACE); 5196 #endif 5197 5198 if (ctxt->namespaces != NULL) { 5199 int i; 5200 5201 for (i = 0;i < ctxt->nsNr;i++) { 5202 if ((ctxt->namespaces[i] != NULL) && 5203 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix))) 5204 return(ctxt->namespaces[i]->href); 5205 } 5206 } 5207 5208 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix)); 5209 } 5210 5211 /** 5212 * xmlXPathRegisteredNsCleanup: 5213 * @ctxt: the XPath context 5214 * 5215 * Cleanup the XPath context data associated to registered variables 5216 */ 5217 void 5218 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) { 5219 if (ctxt == NULL) 5220 return; 5221 5222 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree); 5223 ctxt->nsHash = NULL; 5224 } 5225 5226 /************************************************************************ 5227 * * 5228 * Routines to handle Values * 5229 * * 5230 ************************************************************************/ 5231 5232 /* Allocations are terrible, one needs to optimize all this !!! */ 5233 5234 /** 5235 * xmlXPathNewFloat: 5236 * @val: the double value 5237 * 5238 * Create a new xmlXPathObjectPtr of type double and of value @val 5239 * 5240 * Returns the newly created object. 5241 */ 5242 xmlXPathObjectPtr 5243 xmlXPathNewFloat(double val) { 5244 xmlXPathObjectPtr ret; 5245 5246 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5247 if (ret == NULL) { 5248 xmlXPathErrMemory(NULL, "creating float object\n"); 5249 return(NULL); 5250 } 5251 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5252 ret->type = XPATH_NUMBER; 5253 ret->floatval = val; 5254 #ifdef XP_DEBUG_OBJ_USAGE 5255 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER); 5256 #endif 5257 return(ret); 5258 } 5259 5260 /** 5261 * xmlXPathNewBoolean: 5262 * @val: the boolean value 5263 * 5264 * Create a new xmlXPathObjectPtr of type boolean and of value @val 5265 * 5266 * Returns the newly created object. 5267 */ 5268 xmlXPathObjectPtr 5269 xmlXPathNewBoolean(int val) { 5270 xmlXPathObjectPtr ret; 5271 5272 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5273 if (ret == NULL) { 5274 xmlXPathErrMemory(NULL, "creating boolean object\n"); 5275 return(NULL); 5276 } 5277 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5278 ret->type = XPATH_BOOLEAN; 5279 ret->boolval = (val != 0); 5280 #ifdef XP_DEBUG_OBJ_USAGE 5281 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN); 5282 #endif 5283 return(ret); 5284 } 5285 5286 /** 5287 * xmlXPathNewString: 5288 * @val: the xmlChar * value 5289 * 5290 * Create a new xmlXPathObjectPtr of type string and of value @val 5291 * 5292 * Returns the newly created object. 5293 */ 5294 xmlXPathObjectPtr 5295 xmlXPathNewString(const xmlChar *val) { 5296 xmlXPathObjectPtr ret; 5297 5298 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5299 if (ret == NULL) { 5300 xmlXPathErrMemory(NULL, "creating string object\n"); 5301 return(NULL); 5302 } 5303 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5304 ret->type = XPATH_STRING; 5305 if (val != NULL) 5306 ret->stringval = xmlStrdup(val); 5307 else 5308 ret->stringval = xmlStrdup((const xmlChar *)""); 5309 #ifdef XP_DEBUG_OBJ_USAGE 5310 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); 5311 #endif 5312 return(ret); 5313 } 5314 5315 /** 5316 * xmlXPathWrapString: 5317 * @val: the xmlChar * value 5318 * 5319 * Wraps the @val string into an XPath object. 5320 * 5321 * Returns the newly created object. 5322 */ 5323 xmlXPathObjectPtr 5324 xmlXPathWrapString (xmlChar *val) { 5325 xmlXPathObjectPtr ret; 5326 5327 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5328 if (ret == NULL) { 5329 xmlXPathErrMemory(NULL, "creating string object\n"); 5330 return(NULL); 5331 } 5332 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5333 ret->type = XPATH_STRING; 5334 ret->stringval = val; 5335 #ifdef XP_DEBUG_OBJ_USAGE 5336 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); 5337 #endif 5338 return(ret); 5339 } 5340 5341 /** 5342 * xmlXPathNewCString: 5343 * @val: the char * value 5344 * 5345 * Create a new xmlXPathObjectPtr of type string and of value @val 5346 * 5347 * Returns the newly created object. 5348 */ 5349 xmlXPathObjectPtr 5350 xmlXPathNewCString(const char *val) { 5351 xmlXPathObjectPtr ret; 5352 5353 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5354 if (ret == NULL) { 5355 xmlXPathErrMemory(NULL, "creating string object\n"); 5356 return(NULL); 5357 } 5358 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5359 ret->type = XPATH_STRING; 5360 ret->stringval = xmlStrdup(BAD_CAST val); 5361 #ifdef XP_DEBUG_OBJ_USAGE 5362 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); 5363 #endif 5364 return(ret); 5365 } 5366 5367 /** 5368 * xmlXPathWrapCString: 5369 * @val: the char * value 5370 * 5371 * Wraps a string into an XPath object. 5372 * 5373 * Returns the newly created object. 5374 */ 5375 xmlXPathObjectPtr 5376 xmlXPathWrapCString (char * val) { 5377 return(xmlXPathWrapString((xmlChar *)(val))); 5378 } 5379 5380 /** 5381 * xmlXPathWrapExternal: 5382 * @val: the user data 5383 * 5384 * Wraps the @val data into an XPath object. 5385 * 5386 * Returns the newly created object. 5387 */ 5388 xmlXPathObjectPtr 5389 xmlXPathWrapExternal (void *val) { 5390 xmlXPathObjectPtr ret; 5391 5392 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5393 if (ret == NULL) { 5394 xmlXPathErrMemory(NULL, "creating user object\n"); 5395 return(NULL); 5396 } 5397 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5398 ret->type = XPATH_USERS; 5399 ret->user = val; 5400 #ifdef XP_DEBUG_OBJ_USAGE 5401 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS); 5402 #endif 5403 return(ret); 5404 } 5405 5406 /** 5407 * xmlXPathObjectCopy: 5408 * @val: the original object 5409 * 5410 * allocate a new copy of a given object 5411 * 5412 * Returns the newly created object. 5413 */ 5414 xmlXPathObjectPtr 5415 xmlXPathObjectCopy(xmlXPathObjectPtr val) { 5416 xmlXPathObjectPtr ret; 5417 5418 if (val == NULL) 5419 return(NULL); 5420 5421 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5422 if (ret == NULL) { 5423 xmlXPathErrMemory(NULL, "copying object\n"); 5424 return(NULL); 5425 } 5426 memcpy(ret, val , (size_t) sizeof(xmlXPathObject)); 5427 #ifdef XP_DEBUG_OBJ_USAGE 5428 xmlXPathDebugObjUsageRequested(NULL, val->type); 5429 #endif 5430 switch (val->type) { 5431 case XPATH_BOOLEAN: 5432 case XPATH_NUMBER: 5433 case XPATH_POINT: 5434 case XPATH_RANGE: 5435 break; 5436 case XPATH_STRING: 5437 ret->stringval = xmlStrdup(val->stringval); 5438 break; 5439 case XPATH_XSLT_TREE: 5440 #if 0 5441 /* 5442 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that 5443 this previous handling is no longer correct, and can cause some serious 5444 problems (ref. bug 145547) 5445 */ 5446 if ((val->nodesetval != NULL) && 5447 (val->nodesetval->nodeTab != NULL)) { 5448 xmlNodePtr cur, tmp; 5449 xmlDocPtr top; 5450 5451 ret->boolval = 1; 5452 top = xmlNewDoc(NULL); 5453 top->name = (char *) 5454 xmlStrdup(val->nodesetval->nodeTab[0]->name); 5455 ret->user = top; 5456 if (top != NULL) { 5457 top->doc = top; 5458 cur = val->nodesetval->nodeTab[0]->children; 5459 while (cur != NULL) { 5460 tmp = xmlDocCopyNode(cur, top, 1); 5461 xmlAddChild((xmlNodePtr) top, tmp); 5462 cur = cur->next; 5463 } 5464 } 5465 5466 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top); 5467 } else 5468 ret->nodesetval = xmlXPathNodeSetCreate(NULL); 5469 /* Deallocate the copied tree value */ 5470 break; 5471 #endif 5472 case XPATH_NODESET: 5473 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval); 5474 /* Do not deallocate the copied tree value */ 5475 ret->boolval = 0; 5476 break; 5477 case XPATH_LOCATIONSET: 5478 #ifdef LIBXML_XPTR_ENABLED 5479 { 5480 xmlLocationSetPtr loc = val->user; 5481 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc); 5482 break; 5483 } 5484 #endif 5485 case XPATH_USERS: 5486 ret->user = val->user; 5487 break; 5488 case XPATH_UNDEFINED: 5489 xmlGenericError(xmlGenericErrorContext, 5490 "xmlXPathObjectCopy: unsupported type %d\n", 5491 val->type); 5492 break; 5493 } 5494 return(ret); 5495 } 5496 5497 /** 5498 * xmlXPathFreeObject: 5499 * @obj: the object to free 5500 * 5501 * Free up an xmlXPathObjectPtr object. 5502 */ 5503 void 5504 xmlXPathFreeObject(xmlXPathObjectPtr obj) { 5505 if (obj == NULL) return; 5506 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) { 5507 if (obj->boolval) { 5508 #if 0 5509 if (obj->user != NULL) { 5510 xmlXPathFreeNodeSet(obj->nodesetval); 5511 xmlFreeNodeList((xmlNodePtr) obj->user); 5512 } else 5513 #endif 5514 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */ 5515 if (obj->nodesetval != NULL) 5516 xmlXPathFreeValueTree(obj->nodesetval); 5517 } else { 5518 if (obj->nodesetval != NULL) 5519 xmlXPathFreeNodeSet(obj->nodesetval); 5520 } 5521 #ifdef LIBXML_XPTR_ENABLED 5522 } else if (obj->type == XPATH_LOCATIONSET) { 5523 if (obj->user != NULL) 5524 xmlXPtrFreeLocationSet(obj->user); 5525 #endif 5526 } else if (obj->type == XPATH_STRING) { 5527 if (obj->stringval != NULL) 5528 xmlFree(obj->stringval); 5529 } 5530 #ifdef XP_DEBUG_OBJ_USAGE 5531 xmlXPathDebugObjUsageReleased(NULL, obj->type); 5532 #endif 5533 xmlFree(obj); 5534 } 5535 5536 /** 5537 * xmlXPathReleaseObject: 5538 * @obj: the xmlXPathObjectPtr to free or to cache 5539 * 5540 * Depending on the state of the cache this frees the given 5541 * XPath object or stores it in the cache. 5542 */ 5543 static void 5544 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj) 5545 { 5546 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \ 5547 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \ 5548 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj; 5549 5550 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n)) 5551 5552 if (obj == NULL) 5553 return; 5554 if ((ctxt == NULL) || (ctxt->cache == NULL)) { 5555 xmlXPathFreeObject(obj); 5556 } else { 5557 xmlXPathContextCachePtr cache = 5558 (xmlXPathContextCachePtr) ctxt->cache; 5559 5560 switch (obj->type) { 5561 case XPATH_NODESET: 5562 case XPATH_XSLT_TREE: 5563 if (obj->nodesetval != NULL) { 5564 if (obj->boolval) { 5565 /* 5566 * It looks like the @boolval is used for 5567 * evaluation if this an XSLT Result Tree Fragment. 5568 * TODO: Check if this assumption is correct. 5569 */ 5570 obj->type = XPATH_XSLT_TREE; /* just for debugging */ 5571 xmlXPathFreeValueTree(obj->nodesetval); 5572 obj->nodesetval = NULL; 5573 } else if ((obj->nodesetval->nodeMax <= 40) && 5574 (XP_CACHE_WANTS(cache->nodesetObjs, 5575 cache->maxNodeset))) 5576 { 5577 XP_CACHE_ADD(cache->nodesetObjs, obj); 5578 goto obj_cached; 5579 } else { 5580 xmlXPathFreeNodeSet(obj->nodesetval); 5581 obj->nodesetval = NULL; 5582 } 5583 } 5584 break; 5585 case XPATH_STRING: 5586 if (obj->stringval != NULL) 5587 xmlFree(obj->stringval); 5588 5589 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) { 5590 XP_CACHE_ADD(cache->stringObjs, obj); 5591 goto obj_cached; 5592 } 5593 break; 5594 case XPATH_BOOLEAN: 5595 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) { 5596 XP_CACHE_ADD(cache->booleanObjs, obj); 5597 goto obj_cached; 5598 } 5599 break; 5600 case XPATH_NUMBER: 5601 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) { 5602 XP_CACHE_ADD(cache->numberObjs, obj); 5603 goto obj_cached; 5604 } 5605 break; 5606 #ifdef LIBXML_XPTR_ENABLED 5607 case XPATH_LOCATIONSET: 5608 if (obj->user != NULL) { 5609 xmlXPtrFreeLocationSet(obj->user); 5610 } 5611 goto free_obj; 5612 #endif 5613 default: 5614 goto free_obj; 5615 } 5616 5617 /* 5618 * Fallback to adding to the misc-objects slot. 5619 */ 5620 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) { 5621 XP_CACHE_ADD(cache->miscObjs, obj); 5622 } else 5623 goto free_obj; 5624 5625 obj_cached: 5626 5627 #ifdef XP_DEBUG_OBJ_USAGE 5628 xmlXPathDebugObjUsageReleased(ctxt, obj->type); 5629 #endif 5630 5631 if (obj->nodesetval != NULL) { 5632 xmlNodeSetPtr tmpset = obj->nodesetval; 5633 5634 /* 5635 * TODO: Due to those nasty ns-nodes, we need to traverse 5636 * the list and free the ns-nodes. 5637 * URGENT TODO: Check if it's actually slowing things down. 5638 * Maybe we shouldn't try to preserve the list. 5639 */ 5640 if (tmpset->nodeNr > 1) { 5641 int i; 5642 xmlNodePtr node; 5643 5644 for (i = 0; i < tmpset->nodeNr; i++) { 5645 node = tmpset->nodeTab[i]; 5646 if ((node != NULL) && 5647 (node->type == XML_NAMESPACE_DECL)) 5648 { 5649 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 5650 } 5651 } 5652 } else if (tmpset->nodeNr == 1) { 5653 if ((tmpset->nodeTab[0] != NULL) && 5654 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL)) 5655 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]); 5656 } 5657 tmpset->nodeNr = 0; 5658 memset(obj, 0, sizeof(xmlXPathObject)); 5659 obj->nodesetval = tmpset; 5660 } else 5661 memset(obj, 0, sizeof(xmlXPathObject)); 5662 5663 return; 5664 5665 free_obj: 5666 /* 5667 * Cache is full; free the object. 5668 */ 5669 if (obj->nodesetval != NULL) 5670 xmlXPathFreeNodeSet(obj->nodesetval); 5671 #ifdef XP_DEBUG_OBJ_USAGE 5672 xmlXPathDebugObjUsageReleased(NULL, obj->type); 5673 #endif 5674 xmlFree(obj); 5675 } 5676 return; 5677 } 5678 5679 5680 /************************************************************************ 5681 * * 5682 * Type Casting Routines * 5683 * * 5684 ************************************************************************/ 5685 5686 /** 5687 * xmlXPathCastBooleanToString: 5688 * @val: a boolean 5689 * 5690 * Converts a boolean to its string value. 5691 * 5692 * Returns a newly allocated string. 5693 */ 5694 xmlChar * 5695 xmlXPathCastBooleanToString (int val) { 5696 xmlChar *ret; 5697 if (val) 5698 ret = xmlStrdup((const xmlChar *) "true"); 5699 else 5700 ret = xmlStrdup((const xmlChar *) "false"); 5701 return(ret); 5702 } 5703 5704 /** 5705 * xmlXPathCastNumberToString: 5706 * @val: a number 5707 * 5708 * Converts a number to its string value. 5709 * 5710 * Returns a newly allocated string. 5711 */ 5712 xmlChar * 5713 xmlXPathCastNumberToString (double val) { 5714 xmlChar *ret; 5715 switch (xmlXPathIsInf(val)) { 5716 case 1: 5717 ret = xmlStrdup((const xmlChar *) "Infinity"); 5718 break; 5719 case -1: 5720 ret = xmlStrdup((const xmlChar *) "-Infinity"); 5721 break; 5722 default: 5723 if (xmlXPathIsNaN(val)) { 5724 ret = xmlStrdup((const xmlChar *) "NaN"); 5725 } else if (val == 0 && xmlXPathGetSign(val) != 0) { 5726 ret = xmlStrdup((const xmlChar *) "0"); 5727 } else { 5728 /* could be improved */ 5729 char buf[100]; 5730 xmlXPathFormatNumber(val, buf, 99); 5731 buf[99] = 0; 5732 ret = xmlStrdup((const xmlChar *) buf); 5733 } 5734 } 5735 return(ret); 5736 } 5737 5738 /** 5739 * xmlXPathCastNodeToString: 5740 * @node: a node 5741 * 5742 * Converts a node to its string value. 5743 * 5744 * Returns a newly allocated string. 5745 */ 5746 xmlChar * 5747 xmlXPathCastNodeToString (xmlNodePtr node) { 5748 xmlChar *ret; 5749 if ((ret = xmlNodeGetContent(node)) == NULL) 5750 ret = xmlStrdup((const xmlChar *) ""); 5751 return(ret); 5752 } 5753 5754 /** 5755 * xmlXPathCastNodeSetToString: 5756 * @ns: a node-set 5757 * 5758 * Converts a node-set to its string value. 5759 * 5760 * Returns a newly allocated string. 5761 */ 5762 xmlChar * 5763 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) { 5764 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL)) 5765 return(xmlStrdup((const xmlChar *) "")); 5766 5767 if (ns->nodeNr > 1) 5768 xmlXPathNodeSetSort(ns); 5769 return(xmlXPathCastNodeToString(ns->nodeTab[0])); 5770 } 5771 5772 /** 5773 * xmlXPathCastToString: 5774 * @val: an XPath object 5775 * 5776 * Converts an existing object to its string() equivalent 5777 * 5778 * Returns the allocated string value of the object, NULL in case of error. 5779 * It's up to the caller to free the string memory with xmlFree(). 5780 */ 5781 xmlChar * 5782 xmlXPathCastToString(xmlXPathObjectPtr val) { 5783 xmlChar *ret = NULL; 5784 5785 if (val == NULL) 5786 return(xmlStrdup((const xmlChar *) "")); 5787 switch (val->type) { 5788 case XPATH_UNDEFINED: 5789 #ifdef DEBUG_EXPR 5790 xmlGenericError(xmlGenericErrorContext, "String: undefined\n"); 5791 #endif 5792 ret = xmlStrdup((const xmlChar *) ""); 5793 break; 5794 case XPATH_NODESET: 5795 case XPATH_XSLT_TREE: 5796 ret = xmlXPathCastNodeSetToString(val->nodesetval); 5797 break; 5798 case XPATH_STRING: 5799 return(xmlStrdup(val->stringval)); 5800 case XPATH_BOOLEAN: 5801 ret = xmlXPathCastBooleanToString(val->boolval); 5802 break; 5803 case XPATH_NUMBER: { 5804 ret = xmlXPathCastNumberToString(val->floatval); 5805 break; 5806 } 5807 case XPATH_USERS: 5808 case XPATH_POINT: 5809 case XPATH_RANGE: 5810 case XPATH_LOCATIONSET: 5811 TODO 5812 ret = xmlStrdup((const xmlChar *) ""); 5813 break; 5814 } 5815 return(ret); 5816 } 5817 5818 /** 5819 * xmlXPathConvertString: 5820 * @val: an XPath object 5821 * 5822 * Converts an existing object to its string() equivalent 5823 * 5824 * Returns the new object, the old one is freed (or the operation 5825 * is done directly on @val) 5826 */ 5827 xmlXPathObjectPtr 5828 xmlXPathConvertString(xmlXPathObjectPtr val) { 5829 xmlChar *res = NULL; 5830 5831 if (val == NULL) 5832 return(xmlXPathNewCString("")); 5833 5834 switch (val->type) { 5835 case XPATH_UNDEFINED: 5836 #ifdef DEBUG_EXPR 5837 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n"); 5838 #endif 5839 break; 5840 case XPATH_NODESET: 5841 case XPATH_XSLT_TREE: 5842 res = xmlXPathCastNodeSetToString(val->nodesetval); 5843 break; 5844 case XPATH_STRING: 5845 return(val); 5846 case XPATH_BOOLEAN: 5847 res = xmlXPathCastBooleanToString(val->boolval); 5848 break; 5849 case XPATH_NUMBER: 5850 res = xmlXPathCastNumberToString(val->floatval); 5851 break; 5852 case XPATH_USERS: 5853 case XPATH_POINT: 5854 case XPATH_RANGE: 5855 case XPATH_LOCATIONSET: 5856 TODO; 5857 break; 5858 } 5859 xmlXPathFreeObject(val); 5860 if (res == NULL) 5861 return(xmlXPathNewCString("")); 5862 return(xmlXPathWrapString(res)); 5863 } 5864 5865 /** 5866 * xmlXPathCastBooleanToNumber: 5867 * @val: a boolean 5868 * 5869 * Converts a boolean to its number value 5870 * 5871 * Returns the number value 5872 */ 5873 double 5874 xmlXPathCastBooleanToNumber(int val) { 5875 if (val) 5876 return(1.0); 5877 return(0.0); 5878 } 5879 5880 /** 5881 * xmlXPathCastStringToNumber: 5882 * @val: a string 5883 * 5884 * Converts a string to its number value 5885 * 5886 * Returns the number value 5887 */ 5888 double 5889 xmlXPathCastStringToNumber(const xmlChar * val) { 5890 return(xmlXPathStringEvalNumber(val)); 5891 } 5892 5893 /** 5894 * xmlXPathCastNodeToNumber: 5895 * @node: a node 5896 * 5897 * Converts a node to its number value 5898 * 5899 * Returns the number value 5900 */ 5901 double 5902 xmlXPathCastNodeToNumber (xmlNodePtr node) { 5903 xmlChar *strval; 5904 double ret; 5905 5906 if (node == NULL) 5907 return(xmlXPathNAN); 5908 strval = xmlXPathCastNodeToString(node); 5909 if (strval == NULL) 5910 return(xmlXPathNAN); 5911 ret = xmlXPathCastStringToNumber(strval); 5912 xmlFree(strval); 5913 5914 return(ret); 5915 } 5916 5917 /** 5918 * xmlXPathCastNodeSetToNumber: 5919 * @ns: a node-set 5920 * 5921 * Converts a node-set to its number value 5922 * 5923 * Returns the number value 5924 */ 5925 double 5926 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) { 5927 xmlChar *str; 5928 double ret; 5929 5930 if (ns == NULL) 5931 return(xmlXPathNAN); 5932 str = xmlXPathCastNodeSetToString(ns); 5933 ret = xmlXPathCastStringToNumber(str); 5934 xmlFree(str); 5935 return(ret); 5936 } 5937 5938 /** 5939 * xmlXPathCastToNumber: 5940 * @val: an XPath object 5941 * 5942 * Converts an XPath object to its number value 5943 * 5944 * Returns the number value 5945 */ 5946 double 5947 xmlXPathCastToNumber(xmlXPathObjectPtr val) { 5948 double ret = 0.0; 5949 5950 if (val == NULL) 5951 return(xmlXPathNAN); 5952 switch (val->type) { 5953 case XPATH_UNDEFINED: 5954 #ifdef DEGUB_EXPR 5955 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n"); 5956 #endif 5957 ret = xmlXPathNAN; 5958 break; 5959 case XPATH_NODESET: 5960 case XPATH_XSLT_TREE: 5961 ret = xmlXPathCastNodeSetToNumber(val->nodesetval); 5962 break; 5963 case XPATH_STRING: 5964 ret = xmlXPathCastStringToNumber(val->stringval); 5965 break; 5966 case XPATH_NUMBER: 5967 ret = val->floatval; 5968 break; 5969 case XPATH_BOOLEAN: 5970 ret = xmlXPathCastBooleanToNumber(val->boolval); 5971 break; 5972 case XPATH_USERS: 5973 case XPATH_POINT: 5974 case XPATH_RANGE: 5975 case XPATH_LOCATIONSET: 5976 TODO; 5977 ret = xmlXPathNAN; 5978 break; 5979 } 5980 return(ret); 5981 } 5982 5983 /** 5984 * xmlXPathConvertNumber: 5985 * @val: an XPath object 5986 * 5987 * Converts an existing object to its number() equivalent 5988 * 5989 * Returns the new object, the old one is freed (or the operation 5990 * is done directly on @val) 5991 */ 5992 xmlXPathObjectPtr 5993 xmlXPathConvertNumber(xmlXPathObjectPtr val) { 5994 xmlXPathObjectPtr ret; 5995 5996 if (val == NULL) 5997 return(xmlXPathNewFloat(0.0)); 5998 if (val->type == XPATH_NUMBER) 5999 return(val); 6000 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val)); 6001 xmlXPathFreeObject(val); 6002 return(ret); 6003 } 6004 6005 /** 6006 * xmlXPathCastNumberToBoolean: 6007 * @val: a number 6008 * 6009 * Converts a number to its boolean value 6010 * 6011 * Returns the boolean value 6012 */ 6013 int 6014 xmlXPathCastNumberToBoolean (double val) { 6015 if (xmlXPathIsNaN(val) || (val == 0.0)) 6016 return(0); 6017 return(1); 6018 } 6019 6020 /** 6021 * xmlXPathCastStringToBoolean: 6022 * @val: a string 6023 * 6024 * Converts a string to its boolean value 6025 * 6026 * Returns the boolean value 6027 */ 6028 int 6029 xmlXPathCastStringToBoolean (const xmlChar *val) { 6030 if ((val == NULL) || (xmlStrlen(val) == 0)) 6031 return(0); 6032 return(1); 6033 } 6034 6035 /** 6036 * xmlXPathCastNodeSetToBoolean: 6037 * @ns: a node-set 6038 * 6039 * Converts a node-set to its boolean value 6040 * 6041 * Returns the boolean value 6042 */ 6043 int 6044 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) { 6045 if ((ns == NULL) || (ns->nodeNr == 0)) 6046 return(0); 6047 return(1); 6048 } 6049 6050 /** 6051 * xmlXPathCastToBoolean: 6052 * @val: an XPath object 6053 * 6054 * Converts an XPath object to its boolean value 6055 * 6056 * Returns the boolean value 6057 */ 6058 int 6059 xmlXPathCastToBoolean (xmlXPathObjectPtr val) { 6060 int ret = 0; 6061 6062 if (val == NULL) 6063 return(0); 6064 switch (val->type) { 6065 case XPATH_UNDEFINED: 6066 #ifdef DEBUG_EXPR 6067 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n"); 6068 #endif 6069 ret = 0; 6070 break; 6071 case XPATH_NODESET: 6072 case XPATH_XSLT_TREE: 6073 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval); 6074 break; 6075 case XPATH_STRING: 6076 ret = xmlXPathCastStringToBoolean(val->stringval); 6077 break; 6078 case XPATH_NUMBER: 6079 ret = xmlXPathCastNumberToBoolean(val->floatval); 6080 break; 6081 case XPATH_BOOLEAN: 6082 ret = val->boolval; 6083 break; 6084 case XPATH_USERS: 6085 case XPATH_POINT: 6086 case XPATH_RANGE: 6087 case XPATH_LOCATIONSET: 6088 TODO; 6089 ret = 0; 6090 break; 6091 } 6092 return(ret); 6093 } 6094 6095 6096 /** 6097 * xmlXPathConvertBoolean: 6098 * @val: an XPath object 6099 * 6100 * Converts an existing object to its boolean() equivalent 6101 * 6102 * Returns the new object, the old one is freed (or the operation 6103 * is done directly on @val) 6104 */ 6105 xmlXPathObjectPtr 6106 xmlXPathConvertBoolean(xmlXPathObjectPtr val) { 6107 xmlXPathObjectPtr ret; 6108 6109 if (val == NULL) 6110 return(xmlXPathNewBoolean(0)); 6111 if (val->type == XPATH_BOOLEAN) 6112 return(val); 6113 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val)); 6114 xmlXPathFreeObject(val); 6115 return(ret); 6116 } 6117 6118 /************************************************************************ 6119 * * 6120 * Routines to handle XPath contexts * 6121 * * 6122 ************************************************************************/ 6123 6124 /** 6125 * xmlXPathNewContext: 6126 * @doc: the XML document 6127 * 6128 * Create a new xmlXPathContext 6129 * 6130 * Returns the xmlXPathContext just allocated. The caller will need to free it. 6131 */ 6132 xmlXPathContextPtr 6133 xmlXPathNewContext(xmlDocPtr doc) { 6134 xmlXPathContextPtr ret; 6135 6136 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext)); 6137 if (ret == NULL) { 6138 xmlXPathErrMemory(NULL, "creating context\n"); 6139 return(NULL); 6140 } 6141 memset(ret, 0 , (size_t) sizeof(xmlXPathContext)); 6142 ret->doc = doc; 6143 ret->node = NULL; 6144 6145 ret->varHash = NULL; 6146 6147 ret->nb_types = 0; 6148 ret->max_types = 0; 6149 ret->types = NULL; 6150 6151 ret->funcHash = xmlHashCreate(0); 6152 6153 ret->nb_axis = 0; 6154 ret->max_axis = 0; 6155 ret->axis = NULL; 6156 6157 ret->nsHash = NULL; 6158 ret->user = NULL; 6159 6160 ret->contextSize = -1; 6161 ret->proximityPosition = -1; 6162 6163 #ifdef XP_DEFAULT_CACHE_ON 6164 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) { 6165 xmlXPathFreeContext(ret); 6166 return(NULL); 6167 } 6168 #endif 6169 6170 xmlXPathRegisterAllFunctions(ret); 6171 6172 return(ret); 6173 } 6174 6175 /** 6176 * xmlXPathFreeContext: 6177 * @ctxt: the context to free 6178 * 6179 * Free up an xmlXPathContext 6180 */ 6181 void 6182 xmlXPathFreeContext(xmlXPathContextPtr ctxt) { 6183 if (ctxt == NULL) return; 6184 6185 if (ctxt->cache != NULL) 6186 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache); 6187 xmlXPathRegisteredNsCleanup(ctxt); 6188 xmlXPathRegisteredFuncsCleanup(ctxt); 6189 xmlXPathRegisteredVariablesCleanup(ctxt); 6190 xmlResetError(&ctxt->lastError); 6191 xmlFree(ctxt); 6192 } 6193 6194 /************************************************************************ 6195 * * 6196 * Routines to handle XPath parser contexts * 6197 * * 6198 ************************************************************************/ 6199 6200 #define CHECK_CTXT(ctxt) \ 6201 if (ctxt == NULL) { \ 6202 __xmlRaiseError(NULL, NULL, NULL, \ 6203 NULL, NULL, XML_FROM_XPATH, \ 6204 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \ 6205 __FILE__, __LINE__, \ 6206 NULL, NULL, NULL, 0, 0, \ 6207 "NULL context pointer\n"); \ 6208 return(NULL); \ 6209 } \ 6210 6211 #define CHECK_CTXT_NEG(ctxt) \ 6212 if (ctxt == NULL) { \ 6213 __xmlRaiseError(NULL, NULL, NULL, \ 6214 NULL, NULL, XML_FROM_XPATH, \ 6215 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \ 6216 __FILE__, __LINE__, \ 6217 NULL, NULL, NULL, 0, 0, \ 6218 "NULL context pointer\n"); \ 6219 return(-1); \ 6220 } \ 6221 6222 6223 #define CHECK_CONTEXT(ctxt) \ 6224 if ((ctxt == NULL) || (ctxt->doc == NULL) || \ 6225 (ctxt->doc->children == NULL)) { \ 6226 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \ 6227 return(NULL); \ 6228 } 6229 6230 6231 /** 6232 * xmlXPathNewParserContext: 6233 * @str: the XPath expression 6234 * @ctxt: the XPath context 6235 * 6236 * Create a new xmlXPathParserContext 6237 * 6238 * Returns the xmlXPathParserContext just allocated. 6239 */ 6240 xmlXPathParserContextPtr 6241 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) { 6242 xmlXPathParserContextPtr ret; 6243 6244 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext)); 6245 if (ret == NULL) { 6246 xmlXPathErrMemory(ctxt, "creating parser context\n"); 6247 return(NULL); 6248 } 6249 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext)); 6250 ret->cur = ret->base = str; 6251 ret->context = ctxt; 6252 6253 ret->comp = xmlXPathNewCompExpr(); 6254 if (ret->comp == NULL) { 6255 xmlFree(ret->valueTab); 6256 xmlFree(ret); 6257 return(NULL); 6258 } 6259 if ((ctxt != NULL) && (ctxt->dict != NULL)) { 6260 ret->comp->dict = ctxt->dict; 6261 xmlDictReference(ret->comp->dict); 6262 } 6263 6264 return(ret); 6265 } 6266 6267 /** 6268 * xmlXPathCompParserContext: 6269 * @comp: the XPath compiled expression 6270 * @ctxt: the XPath context 6271 * 6272 * Create a new xmlXPathParserContext when processing a compiled expression 6273 * 6274 * Returns the xmlXPathParserContext just allocated. 6275 */ 6276 static xmlXPathParserContextPtr 6277 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) { 6278 xmlXPathParserContextPtr ret; 6279 6280 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext)); 6281 if (ret == NULL) { 6282 xmlXPathErrMemory(ctxt, "creating evaluation context\n"); 6283 return(NULL); 6284 } 6285 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext)); 6286 6287 /* Allocate the value stack */ 6288 ret->valueTab = (xmlXPathObjectPtr *) 6289 xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); 6290 if (ret->valueTab == NULL) { 6291 xmlFree(ret); 6292 xmlXPathErrMemory(ctxt, "creating evaluation context\n"); 6293 return(NULL); 6294 } 6295 ret->valueNr = 0; 6296 ret->valueMax = 10; 6297 ret->value = NULL; 6298 ret->valueFrame = 0; 6299 6300 ret->context = ctxt; 6301 ret->comp = comp; 6302 6303 return(ret); 6304 } 6305 6306 /** 6307 * xmlXPathFreeParserContext: 6308 * @ctxt: the context to free 6309 * 6310 * Free up an xmlXPathParserContext 6311 */ 6312 void 6313 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) { 6314 int i; 6315 6316 if (ctxt->valueTab != NULL) { 6317 for (i = 0; i < ctxt->valueNr; i++) { 6318 if (ctxt->context) 6319 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]); 6320 else 6321 xmlXPathFreeObject(ctxt->valueTab[i]); 6322 } 6323 xmlFree(ctxt->valueTab); 6324 } 6325 if (ctxt->comp != NULL) { 6326 #ifdef XPATH_STREAMING 6327 if (ctxt->comp->stream != NULL) { 6328 xmlFreePatternList(ctxt->comp->stream); 6329 ctxt->comp->stream = NULL; 6330 } 6331 #endif 6332 xmlXPathFreeCompExpr(ctxt->comp); 6333 } 6334 xmlFree(ctxt); 6335 } 6336 6337 /************************************************************************ 6338 * * 6339 * The implicit core function library * 6340 * * 6341 ************************************************************************/ 6342 6343 /** 6344 * xmlXPathNodeValHash: 6345 * @node: a node pointer 6346 * 6347 * Function computing the beginning of the string value of the node, 6348 * used to speed up comparisons 6349 * 6350 * Returns an int usable as a hash 6351 */ 6352 static unsigned int 6353 xmlXPathNodeValHash(xmlNodePtr node) { 6354 int len = 2; 6355 const xmlChar * string = NULL; 6356 xmlNodePtr tmp = NULL; 6357 unsigned int ret = 0; 6358 6359 if (node == NULL) 6360 return(0); 6361 6362 if (node->type == XML_DOCUMENT_NODE) { 6363 tmp = xmlDocGetRootElement((xmlDocPtr) node); 6364 if (tmp == NULL) 6365 node = node->children; 6366 else 6367 node = tmp; 6368 6369 if (node == NULL) 6370 return(0); 6371 } 6372 6373 switch (node->type) { 6374 case XML_COMMENT_NODE: 6375 case XML_PI_NODE: 6376 case XML_CDATA_SECTION_NODE: 6377 case XML_TEXT_NODE: 6378 string = node->content; 6379 if (string == NULL) 6380 return(0); 6381 if (string[0] == 0) 6382 return(0); 6383 return(((unsigned int) string[0]) + 6384 (((unsigned int) string[1]) << 8)); 6385 case XML_NAMESPACE_DECL: 6386 string = ((xmlNsPtr)node)->href; 6387 if (string == NULL) 6388 return(0); 6389 if (string[0] == 0) 6390 return(0); 6391 return(((unsigned int) string[0]) + 6392 (((unsigned int) string[1]) << 8)); 6393 case XML_ATTRIBUTE_NODE: 6394 tmp = ((xmlAttrPtr) node)->children; 6395 break; 6396 case XML_ELEMENT_NODE: 6397 tmp = node->children; 6398 break; 6399 default: 6400 return(0); 6401 } 6402 while (tmp != NULL) { 6403 switch (tmp->type) { 6404 case XML_CDATA_SECTION_NODE: 6405 case XML_TEXT_NODE: 6406 string = tmp->content; 6407 break; 6408 default: 6409 string = NULL; 6410 break; 6411 } 6412 if ((string != NULL) && (string[0] != 0)) { 6413 if (len == 1) { 6414 return(ret + (((unsigned int) string[0]) << 8)); 6415 } 6416 if (string[1] == 0) { 6417 len = 1; 6418 ret = (unsigned int) string[0]; 6419 } else { 6420 return(((unsigned int) string[0]) + 6421 (((unsigned int) string[1]) << 8)); 6422 } 6423 } 6424 /* 6425 * Skip to next node 6426 */ 6427 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) { 6428 if (tmp->children->type != XML_ENTITY_DECL) { 6429 tmp = tmp->children; 6430 continue; 6431 } 6432 } 6433 if (tmp == node) 6434 break; 6435 6436 if (tmp->next != NULL) { 6437 tmp = tmp->next; 6438 continue; 6439 } 6440 6441 do { 6442 tmp = tmp->parent; 6443 if (tmp == NULL) 6444 break; 6445 if (tmp == node) { 6446 tmp = NULL; 6447 break; 6448 } 6449 if (tmp->next != NULL) { 6450 tmp = tmp->next; 6451 break; 6452 } 6453 } while (tmp != NULL); 6454 } 6455 return(ret); 6456 } 6457 6458 /** 6459 * xmlXPathStringHash: 6460 * @string: a string 6461 * 6462 * Function computing the beginning of the string value of the node, 6463 * used to speed up comparisons 6464 * 6465 * Returns an int usable as a hash 6466 */ 6467 static unsigned int 6468 xmlXPathStringHash(const xmlChar * string) { 6469 if (string == NULL) 6470 return((unsigned int) 0); 6471 if (string[0] == 0) 6472 return(0); 6473 return(((unsigned int) string[0]) + 6474 (((unsigned int) string[1]) << 8)); 6475 } 6476 6477 /** 6478 * xmlXPathCompareNodeSetFloat: 6479 * @ctxt: the XPath Parser context 6480 * @inf: less than (1) or greater than (0) 6481 * @strict: is the comparison strict 6482 * @arg: the node set 6483 * @f: the value 6484 * 6485 * Implement the compare operation between a nodeset and a number 6486 * @ns < @val (1, 1, ... 6487 * @ns <= @val (1, 0, ... 6488 * @ns > @val (0, 1, ... 6489 * @ns >= @val (0, 0, ... 6490 * 6491 * If one object to be compared is a node-set and the other is a number, 6492 * then the comparison will be true if and only if there is a node in the 6493 * node-set such that the result of performing the comparison on the number 6494 * to be compared and on the result of converting the string-value of that 6495 * node to a number using the number function is true. 6496 * 6497 * Returns 0 or 1 depending on the results of the test. 6498 */ 6499 static int 6500 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict, 6501 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) { 6502 int i, ret = 0; 6503 xmlNodeSetPtr ns; 6504 xmlChar *str2; 6505 6506 if ((f == NULL) || (arg == NULL) || 6507 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) { 6508 xmlXPathReleaseObject(ctxt->context, arg); 6509 xmlXPathReleaseObject(ctxt->context, f); 6510 return(0); 6511 } 6512 ns = arg->nodesetval; 6513 if (ns != NULL) { 6514 for (i = 0;i < ns->nodeNr;i++) { 6515 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 6516 if (str2 != NULL) { 6517 valuePush(ctxt, 6518 xmlXPathCacheNewString(ctxt->context, str2)); 6519 xmlFree(str2); 6520 xmlXPathNumberFunction(ctxt, 1); 6521 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f)); 6522 ret = xmlXPathCompareValues(ctxt, inf, strict); 6523 if (ret) 6524 break; 6525 } 6526 } 6527 } 6528 xmlXPathReleaseObject(ctxt->context, arg); 6529 xmlXPathReleaseObject(ctxt->context, f); 6530 return(ret); 6531 } 6532 6533 /** 6534 * xmlXPathCompareNodeSetString: 6535 * @ctxt: the XPath Parser context 6536 * @inf: less than (1) or greater than (0) 6537 * @strict: is the comparison strict 6538 * @arg: the node set 6539 * @s: the value 6540 * 6541 * Implement the compare operation between a nodeset and a string 6542 * @ns < @val (1, 1, ... 6543 * @ns <= @val (1, 0, ... 6544 * @ns > @val (0, 1, ... 6545 * @ns >= @val (0, 0, ... 6546 * 6547 * If one object to be compared is a node-set and the other is a string, 6548 * then the comparison will be true if and only if there is a node in 6549 * the node-set such that the result of performing the comparison on the 6550 * string-value of the node and the other string is true. 6551 * 6552 * Returns 0 or 1 depending on the results of the test. 6553 */ 6554 static int 6555 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict, 6556 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) { 6557 int i, ret = 0; 6558 xmlNodeSetPtr ns; 6559 xmlChar *str2; 6560 6561 if ((s == NULL) || (arg == NULL) || 6562 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) { 6563 xmlXPathReleaseObject(ctxt->context, arg); 6564 xmlXPathReleaseObject(ctxt->context, s); 6565 return(0); 6566 } 6567 ns = arg->nodesetval; 6568 if (ns != NULL) { 6569 for (i = 0;i < ns->nodeNr;i++) { 6570 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 6571 if (str2 != NULL) { 6572 valuePush(ctxt, 6573 xmlXPathCacheNewString(ctxt->context, str2)); 6574 xmlFree(str2); 6575 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s)); 6576 ret = xmlXPathCompareValues(ctxt, inf, strict); 6577 if (ret) 6578 break; 6579 } 6580 } 6581 } 6582 xmlXPathReleaseObject(ctxt->context, arg); 6583 xmlXPathReleaseObject(ctxt->context, s); 6584 return(ret); 6585 } 6586 6587 /** 6588 * xmlXPathCompareNodeSets: 6589 * @inf: less than (1) or greater than (0) 6590 * @strict: is the comparison strict 6591 * @arg1: the first node set object 6592 * @arg2: the second node set object 6593 * 6594 * Implement the compare operation on nodesets: 6595 * 6596 * If both objects to be compared are node-sets, then the comparison 6597 * will be true if and only if there is a node in the first node-set 6598 * and a node in the second node-set such that the result of performing 6599 * the comparison on the string-values of the two nodes is true. 6600 * .... 6601 * When neither object to be compared is a node-set and the operator 6602 * is <=, <, >= or >, then the objects are compared by converting both 6603 * objects to numbers and comparing the numbers according to IEEE 754. 6604 * .... 6605 * The number function converts its argument to a number as follows: 6606 * - a string that consists of optional whitespace followed by an 6607 * optional minus sign followed by a Number followed by whitespace 6608 * is converted to the IEEE 754 number that is nearest (according 6609 * to the IEEE 754 round-to-nearest rule) to the mathematical value 6610 * represented by the string; any other string is converted to NaN 6611 * 6612 * Conclusion all nodes need to be converted first to their string value 6613 * and then the comparison must be done when possible 6614 */ 6615 static int 6616 xmlXPathCompareNodeSets(int inf, int strict, 6617 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) { 6618 int i, j, init = 0; 6619 double val1; 6620 double *values2; 6621 int ret = 0; 6622 xmlNodeSetPtr ns1; 6623 xmlNodeSetPtr ns2; 6624 6625 if ((arg1 == NULL) || 6626 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) { 6627 xmlXPathFreeObject(arg2); 6628 return(0); 6629 } 6630 if ((arg2 == NULL) || 6631 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) { 6632 xmlXPathFreeObject(arg1); 6633 xmlXPathFreeObject(arg2); 6634 return(0); 6635 } 6636 6637 ns1 = arg1->nodesetval; 6638 ns2 = arg2->nodesetval; 6639 6640 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) { 6641 xmlXPathFreeObject(arg1); 6642 xmlXPathFreeObject(arg2); 6643 return(0); 6644 } 6645 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) { 6646 xmlXPathFreeObject(arg1); 6647 xmlXPathFreeObject(arg2); 6648 return(0); 6649 } 6650 6651 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double)); 6652 if (values2 == NULL) { 6653 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6654 xmlXPathFreeObject(arg1); 6655 xmlXPathFreeObject(arg2); 6656 return(0); 6657 } 6658 for (i = 0;i < ns1->nodeNr;i++) { 6659 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]); 6660 if (xmlXPathIsNaN(val1)) 6661 continue; 6662 for (j = 0;j < ns2->nodeNr;j++) { 6663 if (init == 0) { 6664 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]); 6665 } 6666 if (xmlXPathIsNaN(values2[j])) 6667 continue; 6668 if (inf && strict) 6669 ret = (val1 < values2[j]); 6670 else if (inf && !strict) 6671 ret = (val1 <= values2[j]); 6672 else if (!inf && strict) 6673 ret = (val1 > values2[j]); 6674 else if (!inf && !strict) 6675 ret = (val1 >= values2[j]); 6676 if (ret) 6677 break; 6678 } 6679 if (ret) 6680 break; 6681 init = 1; 6682 } 6683 xmlFree(values2); 6684 xmlXPathFreeObject(arg1); 6685 xmlXPathFreeObject(arg2); 6686 return(ret); 6687 } 6688 6689 /** 6690 * xmlXPathCompareNodeSetValue: 6691 * @ctxt: the XPath Parser context 6692 * @inf: less than (1) or greater than (0) 6693 * @strict: is the comparison strict 6694 * @arg: the node set 6695 * @val: the value 6696 * 6697 * Implement the compare operation between a nodeset and a value 6698 * @ns < @val (1, 1, ... 6699 * @ns <= @val (1, 0, ... 6700 * @ns > @val (0, 1, ... 6701 * @ns >= @val (0, 0, ... 6702 * 6703 * If one object to be compared is a node-set and the other is a boolean, 6704 * then the comparison will be true if and only if the result of performing 6705 * the comparison on the boolean and on the result of converting 6706 * the node-set to a boolean using the boolean function is true. 6707 * 6708 * Returns 0 or 1 depending on the results of the test. 6709 */ 6710 static int 6711 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict, 6712 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) { 6713 if ((val == NULL) || (arg == NULL) || 6714 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 6715 return(0); 6716 6717 switch(val->type) { 6718 case XPATH_NUMBER: 6719 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val)); 6720 case XPATH_NODESET: 6721 case XPATH_XSLT_TREE: 6722 return(xmlXPathCompareNodeSets(inf, strict, arg, val)); 6723 case XPATH_STRING: 6724 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val)); 6725 case XPATH_BOOLEAN: 6726 valuePush(ctxt, arg); 6727 xmlXPathBooleanFunction(ctxt, 1); 6728 valuePush(ctxt, val); 6729 return(xmlXPathCompareValues(ctxt, inf, strict)); 6730 default: 6731 xmlGenericError(xmlGenericErrorContext, 6732 "xmlXPathCompareNodeSetValue: Can't compare node set " 6733 "and object of type %d\n", 6734 val->type); 6735 xmlXPathReleaseObject(ctxt->context, arg); 6736 xmlXPathReleaseObject(ctxt->context, val); 6737 XP_ERROR0(XPATH_INVALID_TYPE); 6738 } 6739 return(0); 6740 } 6741 6742 /** 6743 * xmlXPathEqualNodeSetString: 6744 * @arg: the nodeset object argument 6745 * @str: the string to compare to. 6746 * @neq: flag to show whether for '=' (0) or '!=' (1) 6747 * 6748 * Implement the equal operation on XPath objects content: @arg1 == @arg2 6749 * If one object to be compared is a node-set and the other is a string, 6750 * then the comparison will be true if and only if there is a node in 6751 * the node-set such that the result of performing the comparison on the 6752 * string-value of the node and the other string is true. 6753 * 6754 * Returns 0 or 1 depending on the results of the test. 6755 */ 6756 static int 6757 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq) 6758 { 6759 int i; 6760 xmlNodeSetPtr ns; 6761 xmlChar *str2; 6762 unsigned int hash; 6763 6764 if ((str == NULL) || (arg == NULL) || 6765 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 6766 return (0); 6767 ns = arg->nodesetval; 6768 /* 6769 * A NULL nodeset compared with a string is always false 6770 * (since there is no node equal, and no node not equal) 6771 */ 6772 if ((ns == NULL) || (ns->nodeNr <= 0) ) 6773 return (0); 6774 hash = xmlXPathStringHash(str); 6775 for (i = 0; i < ns->nodeNr; i++) { 6776 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) { 6777 str2 = xmlNodeGetContent(ns->nodeTab[i]); 6778 if ((str2 != NULL) && (xmlStrEqual(str, str2))) { 6779 xmlFree(str2); 6780 if (neq) 6781 continue; 6782 return (1); 6783 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) { 6784 if (neq) 6785 continue; 6786 return (1); 6787 } else if (neq) { 6788 if (str2 != NULL) 6789 xmlFree(str2); 6790 return (1); 6791 } 6792 if (str2 != NULL) 6793 xmlFree(str2); 6794 } else if (neq) 6795 return (1); 6796 } 6797 return (0); 6798 } 6799 6800 /** 6801 * xmlXPathEqualNodeSetFloat: 6802 * @arg: the nodeset object argument 6803 * @f: the float to compare to 6804 * @neq: flag to show whether to compare '=' (0) or '!=' (1) 6805 * 6806 * Implement the equal operation on XPath objects content: @arg1 == @arg2 6807 * If one object to be compared is a node-set and the other is a number, 6808 * then the comparison will be true if and only if there is a node in 6809 * the node-set such that the result of performing the comparison on the 6810 * number to be compared and on the result of converting the string-value 6811 * of that node to a number using the number function is true. 6812 * 6813 * Returns 0 or 1 depending on the results of the test. 6814 */ 6815 static int 6816 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt, 6817 xmlXPathObjectPtr arg, double f, int neq) { 6818 int i, ret=0; 6819 xmlNodeSetPtr ns; 6820 xmlChar *str2; 6821 xmlXPathObjectPtr val; 6822 double v; 6823 6824 if ((arg == NULL) || 6825 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 6826 return(0); 6827 6828 ns = arg->nodesetval; 6829 if (ns != NULL) { 6830 for (i=0;i<ns->nodeNr;i++) { 6831 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 6832 if (str2 != NULL) { 6833 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2)); 6834 xmlFree(str2); 6835 xmlXPathNumberFunction(ctxt, 1); 6836 val = valuePop(ctxt); 6837 v = val->floatval; 6838 xmlXPathReleaseObject(ctxt->context, val); 6839 if (!xmlXPathIsNaN(v)) { 6840 if ((!neq) && (v==f)) { 6841 ret = 1; 6842 break; 6843 } else if ((neq) && (v!=f)) { 6844 ret = 1; 6845 break; 6846 } 6847 } else { /* NaN is unequal to any value */ 6848 if (neq) 6849 ret = 1; 6850 } 6851 } 6852 } 6853 } 6854 6855 return(ret); 6856 } 6857 6858 6859 /** 6860 * xmlXPathEqualNodeSets: 6861 * @arg1: first nodeset object argument 6862 * @arg2: second nodeset object argument 6863 * @neq: flag to show whether to test '=' (0) or '!=' (1) 6864 * 6865 * Implement the equal / not equal operation on XPath nodesets: 6866 * @arg1 == @arg2 or @arg1 != @arg2 6867 * If both objects to be compared are node-sets, then the comparison 6868 * will be true if and only if there is a node in the first node-set and 6869 * a node in the second node-set such that the result of performing the 6870 * comparison on the string-values of the two nodes is true. 6871 * 6872 * (needless to say, this is a costly operation) 6873 * 6874 * Returns 0 or 1 depending on the results of the test. 6875 */ 6876 static int 6877 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) { 6878 int i, j; 6879 unsigned int *hashs1; 6880 unsigned int *hashs2; 6881 xmlChar **values1; 6882 xmlChar **values2; 6883 int ret = 0; 6884 xmlNodeSetPtr ns1; 6885 xmlNodeSetPtr ns2; 6886 6887 if ((arg1 == NULL) || 6888 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) 6889 return(0); 6890 if ((arg2 == NULL) || 6891 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) 6892 return(0); 6893 6894 ns1 = arg1->nodesetval; 6895 ns2 = arg2->nodesetval; 6896 6897 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) 6898 return(0); 6899 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) 6900 return(0); 6901 6902 /* 6903 * for equal, check if there is a node pertaining to both sets 6904 */ 6905 if (neq == 0) 6906 for (i = 0;i < ns1->nodeNr;i++) 6907 for (j = 0;j < ns2->nodeNr;j++) 6908 if (ns1->nodeTab[i] == ns2->nodeTab[j]) 6909 return(1); 6910 6911 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *)); 6912 if (values1 == NULL) { 6913 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6914 return(0); 6915 } 6916 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int)); 6917 if (hashs1 == NULL) { 6918 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6919 xmlFree(values1); 6920 return(0); 6921 } 6922 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *)); 6923 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *)); 6924 if (values2 == NULL) { 6925 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6926 xmlFree(hashs1); 6927 xmlFree(values1); 6928 return(0); 6929 } 6930 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int)); 6931 if (hashs2 == NULL) { 6932 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6933 xmlFree(hashs1); 6934 xmlFree(values1); 6935 xmlFree(values2); 6936 return(0); 6937 } 6938 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *)); 6939 for (i = 0;i < ns1->nodeNr;i++) { 6940 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]); 6941 for (j = 0;j < ns2->nodeNr;j++) { 6942 if (i == 0) 6943 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]); 6944 if (hashs1[i] != hashs2[j]) { 6945 if (neq) { 6946 ret = 1; 6947 break; 6948 } 6949 } 6950 else { 6951 if (values1[i] == NULL) 6952 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]); 6953 if (values2[j] == NULL) 6954 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]); 6955 ret = xmlStrEqual(values1[i], values2[j]) ^ neq; 6956 if (ret) 6957 break; 6958 } 6959 } 6960 if (ret) 6961 break; 6962 } 6963 for (i = 0;i < ns1->nodeNr;i++) 6964 if (values1[i] != NULL) 6965 xmlFree(values1[i]); 6966 for (j = 0;j < ns2->nodeNr;j++) 6967 if (values2[j] != NULL) 6968 xmlFree(values2[j]); 6969 xmlFree(values1); 6970 xmlFree(values2); 6971 xmlFree(hashs1); 6972 xmlFree(hashs2); 6973 return(ret); 6974 } 6975 6976 static int 6977 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt, 6978 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) { 6979 int ret = 0; 6980 /* 6981 *At this point we are assured neither arg1 nor arg2 6982 *is a nodeset, so we can just pick the appropriate routine. 6983 */ 6984 switch (arg1->type) { 6985 case XPATH_UNDEFINED: 6986 #ifdef DEBUG_EXPR 6987 xmlGenericError(xmlGenericErrorContext, 6988 "Equal: undefined\n"); 6989 #endif 6990 break; 6991 case XPATH_BOOLEAN: 6992 switch (arg2->type) { 6993 case XPATH_UNDEFINED: 6994 #ifdef DEBUG_EXPR 6995 xmlGenericError(xmlGenericErrorContext, 6996 "Equal: undefined\n"); 6997 #endif 6998 break; 6999 case XPATH_BOOLEAN: 7000 #ifdef DEBUG_EXPR 7001 xmlGenericError(xmlGenericErrorContext, 7002 "Equal: %d boolean %d \n", 7003 arg1->boolval, arg2->boolval); 7004 #endif 7005 ret = (arg1->boolval == arg2->boolval); 7006 break; 7007 case XPATH_NUMBER: 7008 ret = (arg1->boolval == 7009 xmlXPathCastNumberToBoolean(arg2->floatval)); 7010 break; 7011 case XPATH_STRING: 7012 if ((arg2->stringval == NULL) || 7013 (arg2->stringval[0] == 0)) ret = 0; 7014 else 7015 ret = 1; 7016 ret = (arg1->boolval == ret); 7017 break; 7018 case XPATH_USERS: 7019 case XPATH_POINT: 7020 case XPATH_RANGE: 7021 case XPATH_LOCATIONSET: 7022 TODO 7023 break; 7024 case XPATH_NODESET: 7025 case XPATH_XSLT_TREE: 7026 break; 7027 } 7028 break; 7029 case XPATH_NUMBER: 7030 switch (arg2->type) { 7031 case XPATH_UNDEFINED: 7032 #ifdef DEBUG_EXPR 7033 xmlGenericError(xmlGenericErrorContext, 7034 "Equal: undefined\n"); 7035 #endif 7036 break; 7037 case XPATH_BOOLEAN: 7038 ret = (arg2->boolval== 7039 xmlXPathCastNumberToBoolean(arg1->floatval)); 7040 break; 7041 case XPATH_STRING: 7042 valuePush(ctxt, arg2); 7043 xmlXPathNumberFunction(ctxt, 1); 7044 arg2 = valuePop(ctxt); 7045 /* Falls through. */ 7046 case XPATH_NUMBER: 7047 /* Hand check NaN and Infinity equalities */ 7048 if (xmlXPathIsNaN(arg1->floatval) || 7049 xmlXPathIsNaN(arg2->floatval)) { 7050 ret = 0; 7051 } else if (xmlXPathIsInf(arg1->floatval) == 1) { 7052 if (xmlXPathIsInf(arg2->floatval) == 1) 7053 ret = 1; 7054 else 7055 ret = 0; 7056 } else if (xmlXPathIsInf(arg1->floatval) == -1) { 7057 if (xmlXPathIsInf(arg2->floatval) == -1) 7058 ret = 1; 7059 else 7060 ret = 0; 7061 } else if (xmlXPathIsInf(arg2->floatval) == 1) { 7062 if (xmlXPathIsInf(arg1->floatval) == 1) 7063 ret = 1; 7064 else 7065 ret = 0; 7066 } else if (xmlXPathIsInf(arg2->floatval) == -1) { 7067 if (xmlXPathIsInf(arg1->floatval) == -1) 7068 ret = 1; 7069 else 7070 ret = 0; 7071 } else { 7072 ret = (arg1->floatval == arg2->floatval); 7073 } 7074 break; 7075 case XPATH_USERS: 7076 case XPATH_POINT: 7077 case XPATH_RANGE: 7078 case XPATH_LOCATIONSET: 7079 TODO 7080 break; 7081 case XPATH_NODESET: 7082 case XPATH_XSLT_TREE: 7083 break; 7084 } 7085 break; 7086 case XPATH_STRING: 7087 switch (arg2->type) { 7088 case XPATH_UNDEFINED: 7089 #ifdef DEBUG_EXPR 7090 xmlGenericError(xmlGenericErrorContext, 7091 "Equal: undefined\n"); 7092 #endif 7093 break; 7094 case XPATH_BOOLEAN: 7095 if ((arg1->stringval == NULL) || 7096 (arg1->stringval[0] == 0)) ret = 0; 7097 else 7098 ret = 1; 7099 ret = (arg2->boolval == ret); 7100 break; 7101 case XPATH_STRING: 7102 ret = xmlStrEqual(arg1->stringval, arg2->stringval); 7103 break; 7104 case XPATH_NUMBER: 7105 valuePush(ctxt, arg1); 7106 xmlXPathNumberFunction(ctxt, 1); 7107 arg1 = valuePop(ctxt); 7108 /* Hand check NaN and Infinity equalities */ 7109 if (xmlXPathIsNaN(arg1->floatval) || 7110 xmlXPathIsNaN(arg2->floatval)) { 7111 ret = 0; 7112 } else if (xmlXPathIsInf(arg1->floatval) == 1) { 7113 if (xmlXPathIsInf(arg2->floatval) == 1) 7114 ret = 1; 7115 else 7116 ret = 0; 7117 } else if (xmlXPathIsInf(arg1->floatval) == -1) { 7118 if (xmlXPathIsInf(arg2->floatval) == -1) 7119 ret = 1; 7120 else 7121 ret = 0; 7122 } else if (xmlXPathIsInf(arg2->floatval) == 1) { 7123 if (xmlXPathIsInf(arg1->floatval) == 1) 7124 ret = 1; 7125 else 7126 ret = 0; 7127 } else if (xmlXPathIsInf(arg2->floatval) == -1) { 7128 if (xmlXPathIsInf(arg1->floatval) == -1) 7129 ret = 1; 7130 else 7131 ret = 0; 7132 } else { 7133 ret = (arg1->floatval == arg2->floatval); 7134 } 7135 break; 7136 case XPATH_USERS: 7137 case XPATH_POINT: 7138 case XPATH_RANGE: 7139 case XPATH_LOCATIONSET: 7140 TODO 7141 break; 7142 case XPATH_NODESET: 7143 case XPATH_XSLT_TREE: 7144 break; 7145 } 7146 break; 7147 case XPATH_USERS: 7148 case XPATH_POINT: 7149 case XPATH_RANGE: 7150 case XPATH_LOCATIONSET: 7151 TODO 7152 break; 7153 case XPATH_NODESET: 7154 case XPATH_XSLT_TREE: 7155 break; 7156 } 7157 xmlXPathReleaseObject(ctxt->context, arg1); 7158 xmlXPathReleaseObject(ctxt->context, arg2); 7159 return(ret); 7160 } 7161 7162 /** 7163 * xmlXPathEqualValues: 7164 * @ctxt: the XPath Parser context 7165 * 7166 * Implement the equal operation on XPath objects content: @arg1 == @arg2 7167 * 7168 * Returns 0 or 1 depending on the results of the test. 7169 */ 7170 int 7171 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) { 7172 xmlXPathObjectPtr arg1, arg2, argtmp; 7173 int ret = 0; 7174 7175 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); 7176 arg2 = valuePop(ctxt); 7177 arg1 = valuePop(ctxt); 7178 if ((arg1 == NULL) || (arg2 == NULL)) { 7179 if (arg1 != NULL) 7180 xmlXPathReleaseObject(ctxt->context, arg1); 7181 else 7182 xmlXPathReleaseObject(ctxt->context, arg2); 7183 XP_ERROR0(XPATH_INVALID_OPERAND); 7184 } 7185 7186 if (arg1 == arg2) { 7187 #ifdef DEBUG_EXPR 7188 xmlGenericError(xmlGenericErrorContext, 7189 "Equal: by pointer\n"); 7190 #endif 7191 xmlXPathFreeObject(arg1); 7192 return(1); 7193 } 7194 7195 /* 7196 *If either argument is a nodeset, it's a 'special case' 7197 */ 7198 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 7199 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7200 /* 7201 *Hack it to assure arg1 is the nodeset 7202 */ 7203 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) { 7204 argtmp = arg2; 7205 arg2 = arg1; 7206 arg1 = argtmp; 7207 } 7208 switch (arg2->type) { 7209 case XPATH_UNDEFINED: 7210 #ifdef DEBUG_EXPR 7211 xmlGenericError(xmlGenericErrorContext, 7212 "Equal: undefined\n"); 7213 #endif 7214 break; 7215 case XPATH_NODESET: 7216 case XPATH_XSLT_TREE: 7217 ret = xmlXPathEqualNodeSets(arg1, arg2, 0); 7218 break; 7219 case XPATH_BOOLEAN: 7220 if ((arg1->nodesetval == NULL) || 7221 (arg1->nodesetval->nodeNr == 0)) ret = 0; 7222 else 7223 ret = 1; 7224 ret = (ret == arg2->boolval); 7225 break; 7226 case XPATH_NUMBER: 7227 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0); 7228 break; 7229 case XPATH_STRING: 7230 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0); 7231 break; 7232 case XPATH_USERS: 7233 case XPATH_POINT: 7234 case XPATH_RANGE: 7235 case XPATH_LOCATIONSET: 7236 TODO 7237 break; 7238 } 7239 xmlXPathReleaseObject(ctxt->context, arg1); 7240 xmlXPathReleaseObject(ctxt->context, arg2); 7241 return(ret); 7242 } 7243 7244 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2)); 7245 } 7246 7247 /** 7248 * xmlXPathNotEqualValues: 7249 * @ctxt: the XPath Parser context 7250 * 7251 * Implement the equal operation on XPath objects content: @arg1 == @arg2 7252 * 7253 * Returns 0 or 1 depending on the results of the test. 7254 */ 7255 int 7256 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) { 7257 xmlXPathObjectPtr arg1, arg2, argtmp; 7258 int ret = 0; 7259 7260 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); 7261 arg2 = valuePop(ctxt); 7262 arg1 = valuePop(ctxt); 7263 if ((arg1 == NULL) || (arg2 == NULL)) { 7264 if (arg1 != NULL) 7265 xmlXPathReleaseObject(ctxt->context, arg1); 7266 else 7267 xmlXPathReleaseObject(ctxt->context, arg2); 7268 XP_ERROR0(XPATH_INVALID_OPERAND); 7269 } 7270 7271 if (arg1 == arg2) { 7272 #ifdef DEBUG_EXPR 7273 xmlGenericError(xmlGenericErrorContext, 7274 "NotEqual: by pointer\n"); 7275 #endif 7276 xmlXPathReleaseObject(ctxt->context, arg1); 7277 return(0); 7278 } 7279 7280 /* 7281 *If either argument is a nodeset, it's a 'special case' 7282 */ 7283 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 7284 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7285 /* 7286 *Hack it to assure arg1 is the nodeset 7287 */ 7288 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) { 7289 argtmp = arg2; 7290 arg2 = arg1; 7291 arg1 = argtmp; 7292 } 7293 switch (arg2->type) { 7294 case XPATH_UNDEFINED: 7295 #ifdef DEBUG_EXPR 7296 xmlGenericError(xmlGenericErrorContext, 7297 "NotEqual: undefined\n"); 7298 #endif 7299 break; 7300 case XPATH_NODESET: 7301 case XPATH_XSLT_TREE: 7302 ret = xmlXPathEqualNodeSets(arg1, arg2, 1); 7303 break; 7304 case XPATH_BOOLEAN: 7305 if ((arg1->nodesetval == NULL) || 7306 (arg1->nodesetval->nodeNr == 0)) ret = 0; 7307 else 7308 ret = 1; 7309 ret = (ret != arg2->boolval); 7310 break; 7311 case XPATH_NUMBER: 7312 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1); 7313 break; 7314 case XPATH_STRING: 7315 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1); 7316 break; 7317 case XPATH_USERS: 7318 case XPATH_POINT: 7319 case XPATH_RANGE: 7320 case XPATH_LOCATIONSET: 7321 TODO 7322 break; 7323 } 7324 xmlXPathReleaseObject(ctxt->context, arg1); 7325 xmlXPathReleaseObject(ctxt->context, arg2); 7326 return(ret); 7327 } 7328 7329 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2)); 7330 } 7331 7332 /** 7333 * xmlXPathCompareValues: 7334 * @ctxt: the XPath Parser context 7335 * @inf: less than (1) or greater than (0) 7336 * @strict: is the comparison strict 7337 * 7338 * Implement the compare operation on XPath objects: 7339 * @arg1 < @arg2 (1, 1, ... 7340 * @arg1 <= @arg2 (1, 0, ... 7341 * @arg1 > @arg2 (0, 1, ... 7342 * @arg1 >= @arg2 (0, 0, ... 7343 * 7344 * When neither object to be compared is a node-set and the operator is 7345 * <=, <, >=, >, then the objects are compared by converted both objects 7346 * to numbers and comparing the numbers according to IEEE 754. The < 7347 * comparison will be true if and only if the first number is less than the 7348 * second number. The <= comparison will be true if and only if the first 7349 * number is less than or equal to the second number. The > comparison 7350 * will be true if and only if the first number is greater than the second 7351 * number. The >= comparison will be true if and only if the first number 7352 * is greater than or equal to the second number. 7353 * 7354 * Returns 1 if the comparison succeeded, 0 if it failed 7355 */ 7356 int 7357 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) { 7358 int ret = 0, arg1i = 0, arg2i = 0; 7359 xmlXPathObjectPtr arg1, arg2; 7360 7361 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); 7362 arg2 = valuePop(ctxt); 7363 arg1 = valuePop(ctxt); 7364 if ((arg1 == NULL) || (arg2 == NULL)) { 7365 if (arg1 != NULL) 7366 xmlXPathReleaseObject(ctxt->context, arg1); 7367 else 7368 xmlXPathReleaseObject(ctxt->context, arg2); 7369 XP_ERROR0(XPATH_INVALID_OPERAND); 7370 } 7371 7372 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 7373 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7374 /* 7375 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments 7376 * are not freed from within this routine; they will be freed from the 7377 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue 7378 */ 7379 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) && 7380 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){ 7381 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2); 7382 } else { 7383 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7384 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict, 7385 arg1, arg2); 7386 } else { 7387 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict, 7388 arg2, arg1); 7389 } 7390 } 7391 return(ret); 7392 } 7393 7394 if (arg1->type != XPATH_NUMBER) { 7395 valuePush(ctxt, arg1); 7396 xmlXPathNumberFunction(ctxt, 1); 7397 arg1 = valuePop(ctxt); 7398 } 7399 if (arg1->type != XPATH_NUMBER) { 7400 xmlXPathFreeObject(arg1); 7401 xmlXPathFreeObject(arg2); 7402 XP_ERROR0(XPATH_INVALID_OPERAND); 7403 } 7404 if (arg2->type != XPATH_NUMBER) { 7405 valuePush(ctxt, arg2); 7406 xmlXPathNumberFunction(ctxt, 1); 7407 arg2 = valuePop(ctxt); 7408 } 7409 if (arg2->type != XPATH_NUMBER) { 7410 xmlXPathReleaseObject(ctxt->context, arg1); 7411 xmlXPathReleaseObject(ctxt->context, arg2); 7412 XP_ERROR0(XPATH_INVALID_OPERAND); 7413 } 7414 /* 7415 * Add tests for infinity and nan 7416 * => feedback on 3.4 for Inf and NaN 7417 */ 7418 /* Hand check NaN and Infinity comparisons */ 7419 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) { 7420 ret=0; 7421 } else { 7422 arg1i=xmlXPathIsInf(arg1->floatval); 7423 arg2i=xmlXPathIsInf(arg2->floatval); 7424 if (inf && strict) { 7425 if ((arg1i == -1 && arg2i != -1) || 7426 (arg2i == 1 && arg1i != 1)) { 7427 ret = 1; 7428 } else if (arg1i == 0 && arg2i == 0) { 7429 ret = (arg1->floatval < arg2->floatval); 7430 } else { 7431 ret = 0; 7432 } 7433 } 7434 else if (inf && !strict) { 7435 if (arg1i == -1 || arg2i == 1) { 7436 ret = 1; 7437 } else if (arg1i == 0 && arg2i == 0) { 7438 ret = (arg1->floatval <= arg2->floatval); 7439 } else { 7440 ret = 0; 7441 } 7442 } 7443 else if (!inf && strict) { 7444 if ((arg1i == 1 && arg2i != 1) || 7445 (arg2i == -1 && arg1i != -1)) { 7446 ret = 1; 7447 } else if (arg1i == 0 && arg2i == 0) { 7448 ret = (arg1->floatval > arg2->floatval); 7449 } else { 7450 ret = 0; 7451 } 7452 } 7453 else if (!inf && !strict) { 7454 if (arg1i == 1 || arg2i == -1) { 7455 ret = 1; 7456 } else if (arg1i == 0 && arg2i == 0) { 7457 ret = (arg1->floatval >= arg2->floatval); 7458 } else { 7459 ret = 0; 7460 } 7461 } 7462 } 7463 xmlXPathReleaseObject(ctxt->context, arg1); 7464 xmlXPathReleaseObject(ctxt->context, arg2); 7465 return(ret); 7466 } 7467 7468 /** 7469 * xmlXPathValueFlipSign: 7470 * @ctxt: the XPath Parser context 7471 * 7472 * Implement the unary - operation on an XPath object 7473 * The numeric operators convert their operands to numbers as if 7474 * by calling the number function. 7475 */ 7476 void 7477 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) { 7478 if ((ctxt == NULL) || (ctxt->context == NULL)) return; 7479 CAST_TO_NUMBER; 7480 CHECK_TYPE(XPATH_NUMBER); 7481 if (xmlXPathIsNaN(ctxt->value->floatval)) 7482 ctxt->value->floatval=xmlXPathNAN; 7483 else if (xmlXPathIsInf(ctxt->value->floatval) == 1) 7484 ctxt->value->floatval=xmlXPathNINF; 7485 else if (xmlXPathIsInf(ctxt->value->floatval) == -1) 7486 ctxt->value->floatval=xmlXPathPINF; 7487 else if (ctxt->value->floatval == 0) { 7488 if (xmlXPathGetSign(ctxt->value->floatval) == 0) 7489 ctxt->value->floatval = xmlXPathNZERO; 7490 else 7491 ctxt->value->floatval = 0; 7492 } 7493 else 7494 ctxt->value->floatval = - ctxt->value->floatval; 7495 } 7496 7497 /** 7498 * xmlXPathAddValues: 7499 * @ctxt: the XPath Parser context 7500 * 7501 * Implement the add operation on XPath objects: 7502 * The numeric operators convert their operands to numbers as if 7503 * by calling the number function. 7504 */ 7505 void 7506 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) { 7507 xmlXPathObjectPtr arg; 7508 double val; 7509 7510 arg = valuePop(ctxt); 7511 if (arg == NULL) 7512 XP_ERROR(XPATH_INVALID_OPERAND); 7513 val = xmlXPathCastToNumber(arg); 7514 xmlXPathReleaseObject(ctxt->context, arg); 7515 CAST_TO_NUMBER; 7516 CHECK_TYPE(XPATH_NUMBER); 7517 ctxt->value->floatval += val; 7518 } 7519 7520 /** 7521 * xmlXPathSubValues: 7522 * @ctxt: the XPath Parser context 7523 * 7524 * Implement the subtraction operation on XPath objects: 7525 * The numeric operators convert their operands to numbers as if 7526 * by calling the number function. 7527 */ 7528 void 7529 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) { 7530 xmlXPathObjectPtr arg; 7531 double val; 7532 7533 arg = valuePop(ctxt); 7534 if (arg == NULL) 7535 XP_ERROR(XPATH_INVALID_OPERAND); 7536 val = xmlXPathCastToNumber(arg); 7537 xmlXPathReleaseObject(ctxt->context, arg); 7538 CAST_TO_NUMBER; 7539 CHECK_TYPE(XPATH_NUMBER); 7540 ctxt->value->floatval -= val; 7541 } 7542 7543 /** 7544 * xmlXPathMultValues: 7545 * @ctxt: the XPath Parser context 7546 * 7547 * Implement the multiply operation on XPath objects: 7548 * The numeric operators convert their operands to numbers as if 7549 * by calling the number function. 7550 */ 7551 void 7552 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) { 7553 xmlXPathObjectPtr arg; 7554 double val; 7555 7556 arg = valuePop(ctxt); 7557 if (arg == NULL) 7558 XP_ERROR(XPATH_INVALID_OPERAND); 7559 val = xmlXPathCastToNumber(arg); 7560 xmlXPathReleaseObject(ctxt->context, arg); 7561 CAST_TO_NUMBER; 7562 CHECK_TYPE(XPATH_NUMBER); 7563 ctxt->value->floatval *= val; 7564 } 7565 7566 /** 7567 * xmlXPathDivValues: 7568 * @ctxt: the XPath Parser context 7569 * 7570 * Implement the div operation on XPath objects @arg1 / @arg2: 7571 * The numeric operators convert their operands to numbers as if 7572 * by calling the number function. 7573 */ 7574 void 7575 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) { 7576 xmlXPathObjectPtr arg; 7577 double val; 7578 7579 arg = valuePop(ctxt); 7580 if (arg == NULL) 7581 XP_ERROR(XPATH_INVALID_OPERAND); 7582 val = xmlXPathCastToNumber(arg); 7583 xmlXPathReleaseObject(ctxt->context, arg); 7584 CAST_TO_NUMBER; 7585 CHECK_TYPE(XPATH_NUMBER); 7586 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval)) 7587 ctxt->value->floatval = xmlXPathNAN; 7588 else if (val == 0 && xmlXPathGetSign(val) != 0) { 7589 if (ctxt->value->floatval == 0) 7590 ctxt->value->floatval = xmlXPathNAN; 7591 else if (ctxt->value->floatval > 0) 7592 ctxt->value->floatval = xmlXPathNINF; 7593 else if (ctxt->value->floatval < 0) 7594 ctxt->value->floatval = xmlXPathPINF; 7595 } 7596 else if (val == 0) { 7597 if (ctxt->value->floatval == 0) 7598 ctxt->value->floatval = xmlXPathNAN; 7599 else if (ctxt->value->floatval > 0) 7600 ctxt->value->floatval = xmlXPathPINF; 7601 else if (ctxt->value->floatval < 0) 7602 ctxt->value->floatval = xmlXPathNINF; 7603 } else 7604 ctxt->value->floatval /= val; 7605 } 7606 7607 /** 7608 * xmlXPathModValues: 7609 * @ctxt: the XPath Parser context 7610 * 7611 * Implement the mod operation on XPath objects: @arg1 / @arg2 7612 * The numeric operators convert their operands to numbers as if 7613 * by calling the number function. 7614 */ 7615 void 7616 xmlXPathModValues(xmlXPathParserContextPtr ctxt) { 7617 xmlXPathObjectPtr arg; 7618 double arg1, arg2; 7619 7620 arg = valuePop(ctxt); 7621 if (arg == NULL) 7622 XP_ERROR(XPATH_INVALID_OPERAND); 7623 arg2 = xmlXPathCastToNumber(arg); 7624 xmlXPathReleaseObject(ctxt->context, arg); 7625 CAST_TO_NUMBER; 7626 CHECK_TYPE(XPATH_NUMBER); 7627 arg1 = ctxt->value->floatval; 7628 if (arg2 == 0) 7629 ctxt->value->floatval = xmlXPathNAN; 7630 else { 7631 ctxt->value->floatval = fmod(arg1, arg2); 7632 } 7633 } 7634 7635 /************************************************************************ 7636 * * 7637 * The traversal functions * 7638 * * 7639 ************************************************************************/ 7640 7641 /* 7642 * A traversal function enumerates nodes along an axis. 7643 * Initially it must be called with NULL, and it indicates 7644 * termination on the axis by returning NULL. 7645 */ 7646 typedef xmlNodePtr (*xmlXPathTraversalFunction) 7647 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur); 7648 7649 /* 7650 * xmlXPathTraversalFunctionExt: 7651 * A traversal function enumerates nodes along an axis. 7652 * Initially it must be called with NULL, and it indicates 7653 * termination on the axis by returning NULL. 7654 * The context node of the traversal is specified via @contextNode. 7655 */ 7656 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt) 7657 (xmlNodePtr cur, xmlNodePtr contextNode); 7658 7659 /* 7660 * xmlXPathNodeSetMergeFunction: 7661 * Used for merging node sets in xmlXPathCollectAndTest(). 7662 */ 7663 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction) 7664 (xmlNodeSetPtr, xmlNodeSetPtr, int); 7665 7666 7667 /** 7668 * xmlXPathNextSelf: 7669 * @ctxt: the XPath Parser context 7670 * @cur: the current node in the traversal 7671 * 7672 * Traversal function for the "self" direction 7673 * The self axis contains just the context node itself 7674 * 7675 * Returns the next element following that axis 7676 */ 7677 xmlNodePtr 7678 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7679 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7680 if (cur == NULL) 7681 return(ctxt->context->node); 7682 return(NULL); 7683 } 7684 7685 /** 7686 * xmlXPathNextChild: 7687 * @ctxt: the XPath Parser context 7688 * @cur: the current node in the traversal 7689 * 7690 * Traversal function for the "child" direction 7691 * The child axis contains the children of the context node in document order. 7692 * 7693 * Returns the next element following that axis 7694 */ 7695 xmlNodePtr 7696 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7697 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7698 if (cur == NULL) { 7699 if (ctxt->context->node == NULL) return(NULL); 7700 switch (ctxt->context->node->type) { 7701 case XML_ELEMENT_NODE: 7702 case XML_TEXT_NODE: 7703 case XML_CDATA_SECTION_NODE: 7704 case XML_ENTITY_REF_NODE: 7705 case XML_ENTITY_NODE: 7706 case XML_PI_NODE: 7707 case XML_COMMENT_NODE: 7708 case XML_NOTATION_NODE: 7709 case XML_DTD_NODE: 7710 return(ctxt->context->node->children); 7711 case XML_DOCUMENT_NODE: 7712 case XML_DOCUMENT_TYPE_NODE: 7713 case XML_DOCUMENT_FRAG_NODE: 7714 case XML_HTML_DOCUMENT_NODE: 7715 #ifdef LIBXML_DOCB_ENABLED 7716 case XML_DOCB_DOCUMENT_NODE: 7717 #endif 7718 return(((xmlDocPtr) ctxt->context->node)->children); 7719 case XML_ELEMENT_DECL: 7720 case XML_ATTRIBUTE_DECL: 7721 case XML_ENTITY_DECL: 7722 case XML_ATTRIBUTE_NODE: 7723 case XML_NAMESPACE_DECL: 7724 case XML_XINCLUDE_START: 7725 case XML_XINCLUDE_END: 7726 return(NULL); 7727 } 7728 return(NULL); 7729 } 7730 if ((cur->type == XML_DOCUMENT_NODE) || 7731 (cur->type == XML_HTML_DOCUMENT_NODE)) 7732 return(NULL); 7733 return(cur->next); 7734 } 7735 7736 /** 7737 * xmlXPathNextChildElement: 7738 * @ctxt: the XPath Parser context 7739 * @cur: the current node in the traversal 7740 * 7741 * Traversal function for the "child" direction and nodes of type element. 7742 * The child axis contains the children of the context node in document order. 7743 * 7744 * Returns the next element following that axis 7745 */ 7746 static xmlNodePtr 7747 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7748 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7749 if (cur == NULL) { 7750 cur = ctxt->context->node; 7751 if (cur == NULL) return(NULL); 7752 /* 7753 * Get the first element child. 7754 */ 7755 switch (cur->type) { 7756 case XML_ELEMENT_NODE: 7757 case XML_DOCUMENT_FRAG_NODE: 7758 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */ 7759 case XML_ENTITY_NODE: 7760 cur = cur->children; 7761 if (cur != NULL) { 7762 if (cur->type == XML_ELEMENT_NODE) 7763 return(cur); 7764 do { 7765 cur = cur->next; 7766 } while ((cur != NULL) && 7767 (cur->type != XML_ELEMENT_NODE)); 7768 return(cur); 7769 } 7770 return(NULL); 7771 case XML_DOCUMENT_NODE: 7772 case XML_HTML_DOCUMENT_NODE: 7773 #ifdef LIBXML_DOCB_ENABLED 7774 case XML_DOCB_DOCUMENT_NODE: 7775 #endif 7776 return(xmlDocGetRootElement((xmlDocPtr) cur)); 7777 default: 7778 return(NULL); 7779 } 7780 return(NULL); 7781 } 7782 /* 7783 * Get the next sibling element node. 7784 */ 7785 switch (cur->type) { 7786 case XML_ELEMENT_NODE: 7787 case XML_TEXT_NODE: 7788 case XML_ENTITY_REF_NODE: 7789 case XML_ENTITY_NODE: 7790 case XML_CDATA_SECTION_NODE: 7791 case XML_PI_NODE: 7792 case XML_COMMENT_NODE: 7793 case XML_XINCLUDE_END: 7794 break; 7795 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */ 7796 default: 7797 return(NULL); 7798 } 7799 if (cur->next != NULL) { 7800 if (cur->next->type == XML_ELEMENT_NODE) 7801 return(cur->next); 7802 cur = cur->next; 7803 do { 7804 cur = cur->next; 7805 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE)); 7806 return(cur); 7807 } 7808 return(NULL); 7809 } 7810 7811 #if 0 7812 /** 7813 * xmlXPathNextDescendantOrSelfElemParent: 7814 * @ctxt: the XPath Parser context 7815 * @cur: the current node in the traversal 7816 * 7817 * Traversal function for the "descendant-or-self" axis. 7818 * Additionally it returns only nodes which can be parents of 7819 * element nodes. 7820 * 7821 * 7822 * Returns the next element following that axis 7823 */ 7824 static xmlNodePtr 7825 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur, 7826 xmlNodePtr contextNode) 7827 { 7828 if (cur == NULL) { 7829 if (contextNode == NULL) 7830 return(NULL); 7831 switch (contextNode->type) { 7832 case XML_ELEMENT_NODE: 7833 case XML_XINCLUDE_START: 7834 case XML_DOCUMENT_FRAG_NODE: 7835 case XML_DOCUMENT_NODE: 7836 #ifdef LIBXML_DOCB_ENABLED 7837 case XML_DOCB_DOCUMENT_NODE: 7838 #endif 7839 case XML_HTML_DOCUMENT_NODE: 7840 return(contextNode); 7841 default: 7842 return(NULL); 7843 } 7844 return(NULL); 7845 } else { 7846 xmlNodePtr start = cur; 7847 7848 while (cur != NULL) { 7849 switch (cur->type) { 7850 case XML_ELEMENT_NODE: 7851 /* TODO: OK to have XInclude here? */ 7852 case XML_XINCLUDE_START: 7853 case XML_DOCUMENT_FRAG_NODE: 7854 if (cur != start) 7855 return(cur); 7856 if (cur->children != NULL) { 7857 cur = cur->children; 7858 continue; 7859 } 7860 break; 7861 /* Not sure if we need those here. */ 7862 case XML_DOCUMENT_NODE: 7863 #ifdef LIBXML_DOCB_ENABLED 7864 case XML_DOCB_DOCUMENT_NODE: 7865 #endif 7866 case XML_HTML_DOCUMENT_NODE: 7867 if (cur != start) 7868 return(cur); 7869 return(xmlDocGetRootElement((xmlDocPtr) cur)); 7870 default: 7871 break; 7872 } 7873 7874 next_sibling: 7875 if ((cur == NULL) || (cur == contextNode)) 7876 return(NULL); 7877 if (cur->next != NULL) { 7878 cur = cur->next; 7879 } else { 7880 cur = cur->parent; 7881 goto next_sibling; 7882 } 7883 } 7884 } 7885 return(NULL); 7886 } 7887 #endif 7888 7889 /** 7890 * xmlXPathNextDescendant: 7891 * @ctxt: the XPath Parser context 7892 * @cur: the current node in the traversal 7893 * 7894 * Traversal function for the "descendant" direction 7895 * the descendant axis contains the descendants of the context node in document 7896 * order; a descendant is a child or a child of a child and so on. 7897 * 7898 * Returns the next element following that axis 7899 */ 7900 xmlNodePtr 7901 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7902 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7903 if (cur == NULL) { 7904 if (ctxt->context->node == NULL) 7905 return(NULL); 7906 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 7907 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 7908 return(NULL); 7909 7910 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc) 7911 return(ctxt->context->doc->children); 7912 return(ctxt->context->node->children); 7913 } 7914 7915 if (cur->type == XML_NAMESPACE_DECL) 7916 return(NULL); 7917 if (cur->children != NULL) { 7918 /* 7919 * Do not descend on entities declarations 7920 */ 7921 if (cur->children->type != XML_ENTITY_DECL) { 7922 cur = cur->children; 7923 /* 7924 * Skip DTDs 7925 */ 7926 if (cur->type != XML_DTD_NODE) 7927 return(cur); 7928 } 7929 } 7930 7931 if (cur == ctxt->context->node) return(NULL); 7932 7933 while (cur->next != NULL) { 7934 cur = cur->next; 7935 if ((cur->type != XML_ENTITY_DECL) && 7936 (cur->type != XML_DTD_NODE)) 7937 return(cur); 7938 } 7939 7940 do { 7941 cur = cur->parent; 7942 if (cur == NULL) break; 7943 if (cur == ctxt->context->node) return(NULL); 7944 if (cur->next != NULL) { 7945 cur = cur->next; 7946 return(cur); 7947 } 7948 } while (cur != NULL); 7949 return(cur); 7950 } 7951 7952 /** 7953 * xmlXPathNextDescendantOrSelf: 7954 * @ctxt: the XPath Parser context 7955 * @cur: the current node in the traversal 7956 * 7957 * Traversal function for the "descendant-or-self" direction 7958 * the descendant-or-self axis contains the context node and the descendants 7959 * of the context node in document order; thus the context node is the first 7960 * node on the axis, and the first child of the context node is the second node 7961 * on the axis 7962 * 7963 * Returns the next element following that axis 7964 */ 7965 xmlNodePtr 7966 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7967 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7968 if (cur == NULL) 7969 return(ctxt->context->node); 7970 7971 if (ctxt->context->node == NULL) 7972 return(NULL); 7973 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 7974 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 7975 return(NULL); 7976 7977 return(xmlXPathNextDescendant(ctxt, cur)); 7978 } 7979 7980 /** 7981 * xmlXPathNextParent: 7982 * @ctxt: the XPath Parser context 7983 * @cur: the current node in the traversal 7984 * 7985 * Traversal function for the "parent" direction 7986 * The parent axis contains the parent of the context node, if there is one. 7987 * 7988 * Returns the next element following that axis 7989 */ 7990 xmlNodePtr 7991 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7992 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7993 /* 7994 * the parent of an attribute or namespace node is the element 7995 * to which the attribute or namespace node is attached 7996 * Namespace handling !!! 7997 */ 7998 if (cur == NULL) { 7999 if (ctxt->context->node == NULL) return(NULL); 8000 switch (ctxt->context->node->type) { 8001 case XML_ELEMENT_NODE: 8002 case XML_TEXT_NODE: 8003 case XML_CDATA_SECTION_NODE: 8004 case XML_ENTITY_REF_NODE: 8005 case XML_ENTITY_NODE: 8006 case XML_PI_NODE: 8007 case XML_COMMENT_NODE: 8008 case XML_NOTATION_NODE: 8009 case XML_DTD_NODE: 8010 case XML_ELEMENT_DECL: 8011 case XML_ATTRIBUTE_DECL: 8012 case XML_XINCLUDE_START: 8013 case XML_XINCLUDE_END: 8014 case XML_ENTITY_DECL: 8015 if (ctxt->context->node->parent == NULL) 8016 return((xmlNodePtr) ctxt->context->doc); 8017 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) && 8018 ((ctxt->context->node->parent->name[0] == ' ') || 8019 (xmlStrEqual(ctxt->context->node->parent->name, 8020 BAD_CAST "fake node libxslt")))) 8021 return(NULL); 8022 return(ctxt->context->node->parent); 8023 case XML_ATTRIBUTE_NODE: { 8024 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node; 8025 8026 return(att->parent); 8027 } 8028 case XML_DOCUMENT_NODE: 8029 case XML_DOCUMENT_TYPE_NODE: 8030 case XML_DOCUMENT_FRAG_NODE: 8031 case XML_HTML_DOCUMENT_NODE: 8032 #ifdef LIBXML_DOCB_ENABLED 8033 case XML_DOCB_DOCUMENT_NODE: 8034 #endif 8035 return(NULL); 8036 case XML_NAMESPACE_DECL: { 8037 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; 8038 8039 if ((ns->next != NULL) && 8040 (ns->next->type != XML_NAMESPACE_DECL)) 8041 return((xmlNodePtr) ns->next); 8042 return(NULL); 8043 } 8044 } 8045 } 8046 return(NULL); 8047 } 8048 8049 /** 8050 * xmlXPathNextAncestor: 8051 * @ctxt: the XPath Parser context 8052 * @cur: the current node in the traversal 8053 * 8054 * Traversal function for the "ancestor" direction 8055 * the ancestor axis contains the ancestors of the context node; the ancestors 8056 * of the context node consist of the parent of context node and the parent's 8057 * parent and so on; the nodes are ordered in reverse document order; thus the 8058 * parent is the first node on the axis, and the parent's parent is the second 8059 * node on the axis 8060 * 8061 * Returns the next element following that axis 8062 */ 8063 xmlNodePtr 8064 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8065 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8066 /* 8067 * the parent of an attribute or namespace node is the element 8068 * to which the attribute or namespace node is attached 8069 * !!!!!!!!!!!!! 8070 */ 8071 if (cur == NULL) { 8072 if (ctxt->context->node == NULL) return(NULL); 8073 switch (ctxt->context->node->type) { 8074 case XML_ELEMENT_NODE: 8075 case XML_TEXT_NODE: 8076 case XML_CDATA_SECTION_NODE: 8077 case XML_ENTITY_REF_NODE: 8078 case XML_ENTITY_NODE: 8079 case XML_PI_NODE: 8080 case XML_COMMENT_NODE: 8081 case XML_DTD_NODE: 8082 case XML_ELEMENT_DECL: 8083 case XML_ATTRIBUTE_DECL: 8084 case XML_ENTITY_DECL: 8085 case XML_NOTATION_NODE: 8086 case XML_XINCLUDE_START: 8087 case XML_XINCLUDE_END: 8088 if (ctxt->context->node->parent == NULL) 8089 return((xmlNodePtr) ctxt->context->doc); 8090 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) && 8091 ((ctxt->context->node->parent->name[0] == ' ') || 8092 (xmlStrEqual(ctxt->context->node->parent->name, 8093 BAD_CAST "fake node libxslt")))) 8094 return(NULL); 8095 return(ctxt->context->node->parent); 8096 case XML_ATTRIBUTE_NODE: { 8097 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node; 8098 8099 return(tmp->parent); 8100 } 8101 case XML_DOCUMENT_NODE: 8102 case XML_DOCUMENT_TYPE_NODE: 8103 case XML_DOCUMENT_FRAG_NODE: 8104 case XML_HTML_DOCUMENT_NODE: 8105 #ifdef LIBXML_DOCB_ENABLED 8106 case XML_DOCB_DOCUMENT_NODE: 8107 #endif 8108 return(NULL); 8109 case XML_NAMESPACE_DECL: { 8110 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; 8111 8112 if ((ns->next != NULL) && 8113 (ns->next->type != XML_NAMESPACE_DECL)) 8114 return((xmlNodePtr) ns->next); 8115 /* Bad, how did that namespace end up here ? */ 8116 return(NULL); 8117 } 8118 } 8119 return(NULL); 8120 } 8121 if (cur == ctxt->context->doc->children) 8122 return((xmlNodePtr) ctxt->context->doc); 8123 if (cur == (xmlNodePtr) ctxt->context->doc) 8124 return(NULL); 8125 switch (cur->type) { 8126 case XML_ELEMENT_NODE: 8127 case XML_TEXT_NODE: 8128 case XML_CDATA_SECTION_NODE: 8129 case XML_ENTITY_REF_NODE: 8130 case XML_ENTITY_NODE: 8131 case XML_PI_NODE: 8132 case XML_COMMENT_NODE: 8133 case XML_NOTATION_NODE: 8134 case XML_DTD_NODE: 8135 case XML_ELEMENT_DECL: 8136 case XML_ATTRIBUTE_DECL: 8137 case XML_ENTITY_DECL: 8138 case XML_XINCLUDE_START: 8139 case XML_XINCLUDE_END: 8140 if (cur->parent == NULL) 8141 return(NULL); 8142 if ((cur->parent->type == XML_ELEMENT_NODE) && 8143 ((cur->parent->name[0] == ' ') || 8144 (xmlStrEqual(cur->parent->name, 8145 BAD_CAST "fake node libxslt")))) 8146 return(NULL); 8147 return(cur->parent); 8148 case XML_ATTRIBUTE_NODE: { 8149 xmlAttrPtr att = (xmlAttrPtr) cur; 8150 8151 return(att->parent); 8152 } 8153 case XML_NAMESPACE_DECL: { 8154 xmlNsPtr ns = (xmlNsPtr) cur; 8155 8156 if ((ns->next != NULL) && 8157 (ns->next->type != XML_NAMESPACE_DECL)) 8158 return((xmlNodePtr) ns->next); 8159 /* Bad, how did that namespace end up here ? */ 8160 return(NULL); 8161 } 8162 case XML_DOCUMENT_NODE: 8163 case XML_DOCUMENT_TYPE_NODE: 8164 case XML_DOCUMENT_FRAG_NODE: 8165 case XML_HTML_DOCUMENT_NODE: 8166 #ifdef LIBXML_DOCB_ENABLED 8167 case XML_DOCB_DOCUMENT_NODE: 8168 #endif 8169 return(NULL); 8170 } 8171 return(NULL); 8172 } 8173 8174 /** 8175 * xmlXPathNextAncestorOrSelf: 8176 * @ctxt: the XPath Parser context 8177 * @cur: the current node in the traversal 8178 * 8179 * Traversal function for the "ancestor-or-self" direction 8180 * he ancestor-or-self axis contains the context node and ancestors of 8181 * the context node in reverse document order; thus the context node is 8182 * the first node on the axis, and the context node's parent the second; 8183 * parent here is defined the same as with the parent axis. 8184 * 8185 * Returns the next element following that axis 8186 */ 8187 xmlNodePtr 8188 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8189 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8190 if (cur == NULL) 8191 return(ctxt->context->node); 8192 return(xmlXPathNextAncestor(ctxt, cur)); 8193 } 8194 8195 /** 8196 * xmlXPathNextFollowingSibling: 8197 * @ctxt: the XPath Parser context 8198 * @cur: the current node in the traversal 8199 * 8200 * Traversal function for the "following-sibling" direction 8201 * The following-sibling axis contains the following siblings of the context 8202 * node in document order. 8203 * 8204 * Returns the next element following that axis 8205 */ 8206 xmlNodePtr 8207 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8208 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8209 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 8210 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 8211 return(NULL); 8212 if (cur == (xmlNodePtr) ctxt->context->doc) 8213 return(NULL); 8214 if (cur == NULL) 8215 return(ctxt->context->node->next); 8216 return(cur->next); 8217 } 8218 8219 /** 8220 * xmlXPathNextPrecedingSibling: 8221 * @ctxt: the XPath Parser context 8222 * @cur: the current node in the traversal 8223 * 8224 * Traversal function for the "preceding-sibling" direction 8225 * The preceding-sibling axis contains the preceding siblings of the context 8226 * node in reverse document order; the first preceding sibling is first on the 8227 * axis; the sibling preceding that node is the second on the axis and so on. 8228 * 8229 * Returns the next element following that axis 8230 */ 8231 xmlNodePtr 8232 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8233 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8234 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 8235 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 8236 return(NULL); 8237 if (cur == (xmlNodePtr) ctxt->context->doc) 8238 return(NULL); 8239 if (cur == NULL) 8240 return(ctxt->context->node->prev); 8241 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) { 8242 cur = cur->prev; 8243 if (cur == NULL) 8244 return(ctxt->context->node->prev); 8245 } 8246 return(cur->prev); 8247 } 8248 8249 /** 8250 * xmlXPathNextFollowing: 8251 * @ctxt: the XPath Parser context 8252 * @cur: the current node in the traversal 8253 * 8254 * Traversal function for the "following" direction 8255 * The following axis contains all nodes in the same document as the context 8256 * node that are after the context node in document order, excluding any 8257 * descendants and excluding attribute nodes and namespace nodes; the nodes 8258 * are ordered in document order 8259 * 8260 * Returns the next element following that axis 8261 */ 8262 xmlNodePtr 8263 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8264 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8265 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) && 8266 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL)) 8267 return(cur->children); 8268 8269 if (cur == NULL) { 8270 cur = ctxt->context->node; 8271 if (cur->type == XML_ATTRIBUTE_NODE) { 8272 cur = cur->parent; 8273 } else if (cur->type == XML_NAMESPACE_DECL) { 8274 xmlNsPtr ns = (xmlNsPtr) cur; 8275 8276 if ((ns->next == NULL) || 8277 (ns->next->type == XML_NAMESPACE_DECL)) 8278 return (NULL); 8279 cur = (xmlNodePtr) ns->next; 8280 } 8281 } 8282 if (cur == NULL) return(NULL) ; /* ERROR */ 8283 if (cur->next != NULL) return(cur->next) ; 8284 do { 8285 cur = cur->parent; 8286 if (cur == NULL) break; 8287 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL); 8288 if (cur->next != NULL) return(cur->next); 8289 } while (cur != NULL); 8290 return(cur); 8291 } 8292 8293 /* 8294 * xmlXPathIsAncestor: 8295 * @ancestor: the ancestor node 8296 * @node: the current node 8297 * 8298 * Check that @ancestor is a @node's ancestor 8299 * 8300 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise. 8301 */ 8302 static int 8303 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) { 8304 if ((ancestor == NULL) || (node == NULL)) return(0); 8305 if (node->type == XML_NAMESPACE_DECL) 8306 return(0); 8307 if (ancestor->type == XML_NAMESPACE_DECL) 8308 return(0); 8309 /* nodes need to be in the same document */ 8310 if (ancestor->doc != node->doc) return(0); 8311 /* avoid searching if ancestor or node is the root node */ 8312 if (ancestor == (xmlNodePtr) node->doc) return(1); 8313 if (node == (xmlNodePtr) ancestor->doc) return(0); 8314 while (node->parent != NULL) { 8315 if (node->parent == ancestor) 8316 return(1); 8317 node = node->parent; 8318 } 8319 return(0); 8320 } 8321 8322 /** 8323 * xmlXPathNextPreceding: 8324 * @ctxt: the XPath Parser context 8325 * @cur: the current node in the traversal 8326 * 8327 * Traversal function for the "preceding" direction 8328 * the preceding axis contains all nodes in the same document as the context 8329 * node that are before the context node in document order, excluding any 8330 * ancestors and excluding attribute nodes and namespace nodes; the nodes are 8331 * ordered in reverse document order 8332 * 8333 * Returns the next element following that axis 8334 */ 8335 xmlNodePtr 8336 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) 8337 { 8338 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8339 if (cur == NULL) { 8340 cur = ctxt->context->node; 8341 if (cur->type == XML_ATTRIBUTE_NODE) { 8342 cur = cur->parent; 8343 } else if (cur->type == XML_NAMESPACE_DECL) { 8344 xmlNsPtr ns = (xmlNsPtr) cur; 8345 8346 if ((ns->next == NULL) || 8347 (ns->next->type == XML_NAMESPACE_DECL)) 8348 return (NULL); 8349 cur = (xmlNodePtr) ns->next; 8350 } 8351 } 8352 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) 8353 return (NULL); 8354 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) 8355 cur = cur->prev; 8356 do { 8357 if (cur->prev != NULL) { 8358 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ; 8359 return (cur); 8360 } 8361 8362 cur = cur->parent; 8363 if (cur == NULL) 8364 return (NULL); 8365 if (cur == ctxt->context->doc->children) 8366 return (NULL); 8367 } while (xmlXPathIsAncestor(cur, ctxt->context->node)); 8368 return (cur); 8369 } 8370 8371 /** 8372 * xmlXPathNextPrecedingInternal: 8373 * @ctxt: the XPath Parser context 8374 * @cur: the current node in the traversal 8375 * 8376 * Traversal function for the "preceding" direction 8377 * the preceding axis contains all nodes in the same document as the context 8378 * node that are before the context node in document order, excluding any 8379 * ancestors and excluding attribute nodes and namespace nodes; the nodes are 8380 * ordered in reverse document order 8381 * This is a faster implementation but internal only since it requires a 8382 * state kept in the parser context: ctxt->ancestor. 8383 * 8384 * Returns the next element following that axis 8385 */ 8386 static xmlNodePtr 8387 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt, 8388 xmlNodePtr cur) 8389 { 8390 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8391 if (cur == NULL) { 8392 cur = ctxt->context->node; 8393 if (cur == NULL) 8394 return (NULL); 8395 if (cur->type == XML_ATTRIBUTE_NODE) { 8396 cur = cur->parent; 8397 } else if (cur->type == XML_NAMESPACE_DECL) { 8398 xmlNsPtr ns = (xmlNsPtr) cur; 8399 8400 if ((ns->next == NULL) || 8401 (ns->next->type == XML_NAMESPACE_DECL)) 8402 return (NULL); 8403 cur = (xmlNodePtr) ns->next; 8404 } 8405 ctxt->ancestor = cur->parent; 8406 } 8407 if (cur->type == XML_NAMESPACE_DECL) 8408 return(NULL); 8409 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) 8410 cur = cur->prev; 8411 while (cur->prev == NULL) { 8412 cur = cur->parent; 8413 if (cur == NULL) 8414 return (NULL); 8415 if (cur == ctxt->context->doc->children) 8416 return (NULL); 8417 if (cur != ctxt->ancestor) 8418 return (cur); 8419 ctxt->ancestor = cur->parent; 8420 } 8421 cur = cur->prev; 8422 while (cur->last != NULL) 8423 cur = cur->last; 8424 return (cur); 8425 } 8426 8427 /** 8428 * xmlXPathNextNamespace: 8429 * @ctxt: the XPath Parser context 8430 * @cur: the current attribute in the traversal 8431 * 8432 * Traversal function for the "namespace" direction 8433 * the namespace axis contains the namespace nodes of the context node; 8434 * the order of nodes on this axis is implementation-defined; the axis will 8435 * be empty unless the context node is an element 8436 * 8437 * We keep the XML namespace node at the end of the list. 8438 * 8439 * Returns the next element following that axis 8440 */ 8441 xmlNodePtr 8442 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8443 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8444 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL); 8445 if (cur == NULL) { 8446 if (ctxt->context->tmpNsList != NULL) 8447 xmlFree(ctxt->context->tmpNsList); 8448 ctxt->context->tmpNsList = 8449 xmlGetNsList(ctxt->context->doc, ctxt->context->node); 8450 ctxt->context->tmpNsNr = 0; 8451 if (ctxt->context->tmpNsList != NULL) { 8452 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) { 8453 ctxt->context->tmpNsNr++; 8454 } 8455 } 8456 return((xmlNodePtr) xmlXPathXMLNamespace); 8457 } 8458 if (ctxt->context->tmpNsNr > 0) { 8459 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr]; 8460 } else { 8461 if (ctxt->context->tmpNsList != NULL) 8462 xmlFree(ctxt->context->tmpNsList); 8463 ctxt->context->tmpNsList = NULL; 8464 return(NULL); 8465 } 8466 } 8467 8468 /** 8469 * xmlXPathNextAttribute: 8470 * @ctxt: the XPath Parser context 8471 * @cur: the current attribute in the traversal 8472 * 8473 * Traversal function for the "attribute" direction 8474 * TODO: support DTD inherited default attributes 8475 * 8476 * Returns the next element following that axis 8477 */ 8478 xmlNodePtr 8479 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8480 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8481 if (ctxt->context->node == NULL) 8482 return(NULL); 8483 if (ctxt->context->node->type != XML_ELEMENT_NODE) 8484 return(NULL); 8485 if (cur == NULL) { 8486 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc) 8487 return(NULL); 8488 return((xmlNodePtr)ctxt->context->node->properties); 8489 } 8490 return((xmlNodePtr)cur->next); 8491 } 8492 8493 /************************************************************************ 8494 * * 8495 * NodeTest Functions * 8496 * * 8497 ************************************************************************/ 8498 8499 #define IS_FUNCTION 200 8500 8501 8502 /************************************************************************ 8503 * * 8504 * Implicit tree core function library * 8505 * * 8506 ************************************************************************/ 8507 8508 /** 8509 * xmlXPathRoot: 8510 * @ctxt: the XPath Parser context 8511 * 8512 * Initialize the context to the root of the document 8513 */ 8514 void 8515 xmlXPathRoot(xmlXPathParserContextPtr ctxt) { 8516 if ((ctxt == NULL) || (ctxt->context == NULL)) 8517 return; 8518 ctxt->context->node = (xmlNodePtr) ctxt->context->doc; 8519 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8520 ctxt->context->node)); 8521 } 8522 8523 /************************************************************************ 8524 * * 8525 * The explicit core function library * 8526 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib * 8527 * * 8528 ************************************************************************/ 8529 8530 8531 /** 8532 * xmlXPathLastFunction: 8533 * @ctxt: the XPath Parser context 8534 * @nargs: the number of arguments 8535 * 8536 * Implement the last() XPath function 8537 * number last() 8538 * The last function returns the number of nodes in the context node list. 8539 */ 8540 void 8541 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8542 CHECK_ARITY(0); 8543 if (ctxt->context->contextSize >= 0) { 8544 valuePush(ctxt, 8545 xmlXPathCacheNewFloat(ctxt->context, 8546 (double) ctxt->context->contextSize)); 8547 #ifdef DEBUG_EXPR 8548 xmlGenericError(xmlGenericErrorContext, 8549 "last() : %d\n", ctxt->context->contextSize); 8550 #endif 8551 } else { 8552 XP_ERROR(XPATH_INVALID_CTXT_SIZE); 8553 } 8554 } 8555 8556 /** 8557 * xmlXPathPositionFunction: 8558 * @ctxt: the XPath Parser context 8559 * @nargs: the number of arguments 8560 * 8561 * Implement the position() XPath function 8562 * number position() 8563 * The position function returns the position of the context node in the 8564 * context node list. The first position is 1, and so the last position 8565 * will be equal to last(). 8566 */ 8567 void 8568 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8569 CHECK_ARITY(0); 8570 if (ctxt->context->proximityPosition >= 0) { 8571 valuePush(ctxt, 8572 xmlXPathCacheNewFloat(ctxt->context, 8573 (double) ctxt->context->proximityPosition)); 8574 #ifdef DEBUG_EXPR 8575 xmlGenericError(xmlGenericErrorContext, "position() : %d\n", 8576 ctxt->context->proximityPosition); 8577 #endif 8578 } else { 8579 XP_ERROR(XPATH_INVALID_CTXT_POSITION); 8580 } 8581 } 8582 8583 /** 8584 * xmlXPathCountFunction: 8585 * @ctxt: the XPath Parser context 8586 * @nargs: the number of arguments 8587 * 8588 * Implement the count() XPath function 8589 * number count(node-set) 8590 */ 8591 void 8592 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8593 xmlXPathObjectPtr cur; 8594 8595 CHECK_ARITY(1); 8596 if ((ctxt->value == NULL) || 8597 ((ctxt->value->type != XPATH_NODESET) && 8598 (ctxt->value->type != XPATH_XSLT_TREE))) 8599 XP_ERROR(XPATH_INVALID_TYPE); 8600 cur = valuePop(ctxt); 8601 8602 if ((cur == NULL) || (cur->nodesetval == NULL)) 8603 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0)); 8604 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) { 8605 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 8606 (double) cur->nodesetval->nodeNr)); 8607 } else { 8608 if ((cur->nodesetval->nodeNr != 1) || 8609 (cur->nodesetval->nodeTab == NULL)) { 8610 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0)); 8611 } else { 8612 xmlNodePtr tmp; 8613 int i = 0; 8614 8615 tmp = cur->nodesetval->nodeTab[0]; 8616 if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) { 8617 tmp = tmp->children; 8618 while (tmp != NULL) { 8619 tmp = tmp->next; 8620 i++; 8621 } 8622 } 8623 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i)); 8624 } 8625 } 8626 xmlXPathReleaseObject(ctxt->context, cur); 8627 } 8628 8629 /** 8630 * xmlXPathGetElementsByIds: 8631 * @doc: the document 8632 * @ids: a whitespace separated list of IDs 8633 * 8634 * Selects elements by their unique ID. 8635 * 8636 * Returns a node-set of selected elements. 8637 */ 8638 static xmlNodeSetPtr 8639 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) { 8640 xmlNodeSetPtr ret; 8641 const xmlChar *cur = ids; 8642 xmlChar *ID; 8643 xmlAttrPtr attr; 8644 xmlNodePtr elem = NULL; 8645 8646 if (ids == NULL) return(NULL); 8647 8648 ret = xmlXPathNodeSetCreate(NULL); 8649 if (ret == NULL) 8650 return(ret); 8651 8652 while (IS_BLANK_CH(*cur)) cur++; 8653 while (*cur != 0) { 8654 while ((!IS_BLANK_CH(*cur)) && (*cur != 0)) 8655 cur++; 8656 8657 ID = xmlStrndup(ids, cur - ids); 8658 if (ID != NULL) { 8659 /* 8660 * We used to check the fact that the value passed 8661 * was an NCName, but this generated much troubles for 8662 * me and Aleksey Sanin, people blatantly violated that 8663 * constaint, like Visa3D spec. 8664 * if (xmlValidateNCName(ID, 1) == 0) 8665 */ 8666 attr = xmlGetID(doc, ID); 8667 if (attr != NULL) { 8668 if (attr->type == XML_ATTRIBUTE_NODE) 8669 elem = attr->parent; 8670 else if (attr->type == XML_ELEMENT_NODE) 8671 elem = (xmlNodePtr) attr; 8672 else 8673 elem = NULL; 8674 if (elem != NULL) 8675 xmlXPathNodeSetAdd(ret, elem); 8676 } 8677 xmlFree(ID); 8678 } 8679 8680 while (IS_BLANK_CH(*cur)) cur++; 8681 ids = cur; 8682 } 8683 return(ret); 8684 } 8685 8686 /** 8687 * xmlXPathIdFunction: 8688 * @ctxt: the XPath Parser context 8689 * @nargs: the number of arguments 8690 * 8691 * Implement the id() XPath function 8692 * node-set id(object) 8693 * The id function selects elements by their unique ID 8694 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set, 8695 * then the result is the union of the result of applying id to the 8696 * string value of each of the nodes in the argument node-set. When the 8697 * argument to id is of any other type, the argument is converted to a 8698 * string as if by a call to the string function; the string is split 8699 * into a whitespace-separated list of tokens (whitespace is any sequence 8700 * of characters matching the production S); the result is a node-set 8701 * containing the elements in the same document as the context node that 8702 * have a unique ID equal to any of the tokens in the list. 8703 */ 8704 void 8705 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8706 xmlChar *tokens; 8707 xmlNodeSetPtr ret; 8708 xmlXPathObjectPtr obj; 8709 8710 CHECK_ARITY(1); 8711 obj = valuePop(ctxt); 8712 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 8713 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) { 8714 xmlNodeSetPtr ns; 8715 int i; 8716 8717 ret = xmlXPathNodeSetCreate(NULL); 8718 /* 8719 * FIXME -- in an out-of-memory condition this will behave badly. 8720 * The solution is not clear -- we already popped an item from 8721 * ctxt, so the object is in a corrupt state. 8722 */ 8723 8724 if (obj->nodesetval != NULL) { 8725 for (i = 0; i < obj->nodesetval->nodeNr; i++) { 8726 tokens = 8727 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]); 8728 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens); 8729 ret = xmlXPathNodeSetMerge(ret, ns); 8730 xmlXPathFreeNodeSet(ns); 8731 if (tokens != NULL) 8732 xmlFree(tokens); 8733 } 8734 } 8735 xmlXPathReleaseObject(ctxt->context, obj); 8736 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret)); 8737 return; 8738 } 8739 obj = xmlXPathCacheConvertString(ctxt->context, obj); 8740 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval); 8741 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret)); 8742 xmlXPathReleaseObject(ctxt->context, obj); 8743 return; 8744 } 8745 8746 /** 8747 * xmlXPathLocalNameFunction: 8748 * @ctxt: the XPath Parser context 8749 * @nargs: the number of arguments 8750 * 8751 * Implement the local-name() XPath function 8752 * string local-name(node-set?) 8753 * The local-name function returns a string containing the local part 8754 * of the name of the node in the argument node-set that is first in 8755 * document order. If the node-set is empty or the first node has no 8756 * name, an empty string is returned. If the argument is omitted it 8757 * defaults to the context node. 8758 */ 8759 void 8760 xmlXPathLocalNameFunction(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 8771 CHECK_ARITY(1); 8772 if ((ctxt->value == NULL) || 8773 ((ctxt->value->type != XPATH_NODESET) && 8774 (ctxt->value->type != XPATH_XSLT_TREE))) 8775 XP_ERROR(XPATH_INVALID_TYPE); 8776 cur = valuePop(ctxt); 8777 8778 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 8779 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8780 } else { 8781 int i = 0; /* Should be first in document order !!!!! */ 8782 switch (cur->nodesetval->nodeTab[i]->type) { 8783 case XML_ELEMENT_NODE: 8784 case XML_ATTRIBUTE_NODE: 8785 case XML_PI_NODE: 8786 if (cur->nodesetval->nodeTab[i]->name[0] == ' ') 8787 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8788 else 8789 valuePush(ctxt, 8790 xmlXPathCacheNewString(ctxt->context, 8791 cur->nodesetval->nodeTab[i]->name)); 8792 break; 8793 case XML_NAMESPACE_DECL: 8794 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 8795 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix)); 8796 break; 8797 default: 8798 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8799 } 8800 } 8801 xmlXPathReleaseObject(ctxt->context, cur); 8802 } 8803 8804 /** 8805 * xmlXPathNamespaceURIFunction: 8806 * @ctxt: the XPath Parser context 8807 * @nargs: the number of arguments 8808 * 8809 * Implement the namespace-uri() XPath function 8810 * string namespace-uri(node-set?) 8811 * The namespace-uri function returns a string containing the 8812 * namespace URI of the expanded name of the node in the argument 8813 * node-set that is first in document order. If the node-set is empty, 8814 * the first node has no name, or the expanded name has no namespace 8815 * URI, an empty string is returned. If the argument is omitted it 8816 * defaults to the context node. 8817 */ 8818 void 8819 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8820 xmlXPathObjectPtr cur; 8821 8822 if (ctxt == NULL) return; 8823 8824 if (nargs == 0) { 8825 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8826 ctxt->context->node)); 8827 nargs = 1; 8828 } 8829 CHECK_ARITY(1); 8830 if ((ctxt->value == NULL) || 8831 ((ctxt->value->type != XPATH_NODESET) && 8832 (ctxt->value->type != XPATH_XSLT_TREE))) 8833 XP_ERROR(XPATH_INVALID_TYPE); 8834 cur = valuePop(ctxt); 8835 8836 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 8837 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8838 } else { 8839 int i = 0; /* Should be first in document order !!!!! */ 8840 switch (cur->nodesetval->nodeTab[i]->type) { 8841 case XML_ELEMENT_NODE: 8842 case XML_ATTRIBUTE_NODE: 8843 if (cur->nodesetval->nodeTab[i]->ns == NULL) 8844 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8845 else 8846 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 8847 cur->nodesetval->nodeTab[i]->ns->href)); 8848 break; 8849 default: 8850 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8851 } 8852 } 8853 xmlXPathReleaseObject(ctxt->context, cur); 8854 } 8855 8856 /** 8857 * xmlXPathNameFunction: 8858 * @ctxt: the XPath Parser context 8859 * @nargs: the number of arguments 8860 * 8861 * Implement the name() XPath function 8862 * string name(node-set?) 8863 * The name function returns a string containing a QName representing 8864 * the name of the node in the argument node-set that is first in document 8865 * order. The QName must represent the name with respect to the namespace 8866 * declarations in effect on the node whose name is being represented. 8867 * Typically, this will be the form in which the name occurred in the XML 8868 * source. This need not be the case if there are namespace declarations 8869 * in effect on the node that associate multiple prefixes with the same 8870 * namespace. However, an implementation may include information about 8871 * the original prefix in its representation of nodes; in this case, an 8872 * implementation can ensure that the returned string is always the same 8873 * as the QName used in the XML source. If the argument it omitted it 8874 * defaults to the context node. 8875 * Libxml keep the original prefix so the "real qualified name" used is 8876 * returned. 8877 */ 8878 static void 8879 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) 8880 { 8881 xmlXPathObjectPtr cur; 8882 8883 if (nargs == 0) { 8884 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8885 ctxt->context->node)); 8886 nargs = 1; 8887 } 8888 8889 CHECK_ARITY(1); 8890 if ((ctxt->value == NULL) || 8891 ((ctxt->value->type != XPATH_NODESET) && 8892 (ctxt->value->type != XPATH_XSLT_TREE))) 8893 XP_ERROR(XPATH_INVALID_TYPE); 8894 cur = valuePop(ctxt); 8895 8896 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 8897 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8898 } else { 8899 int i = 0; /* Should be first in document order !!!!! */ 8900 8901 switch (cur->nodesetval->nodeTab[i]->type) { 8902 case XML_ELEMENT_NODE: 8903 case XML_ATTRIBUTE_NODE: 8904 if (cur->nodesetval->nodeTab[i]->name[0] == ' ') 8905 valuePush(ctxt, 8906 xmlXPathCacheNewCString(ctxt->context, "")); 8907 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) || 8908 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) { 8909 valuePush(ctxt, 8910 xmlXPathCacheNewString(ctxt->context, 8911 cur->nodesetval->nodeTab[i]->name)); 8912 } else { 8913 xmlChar *fullname; 8914 8915 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name, 8916 cur->nodesetval->nodeTab[i]->ns->prefix, 8917 NULL, 0); 8918 if (fullname == cur->nodesetval->nodeTab[i]->name) 8919 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name); 8920 if (fullname == NULL) { 8921 XP_ERROR(XPATH_MEMORY_ERROR); 8922 } 8923 valuePush(ctxt, xmlXPathCacheWrapString( 8924 ctxt->context, fullname)); 8925 } 8926 break; 8927 default: 8928 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8929 cur->nodesetval->nodeTab[i])); 8930 xmlXPathLocalNameFunction(ctxt, 1); 8931 } 8932 } 8933 xmlXPathReleaseObject(ctxt->context, cur); 8934 } 8935 8936 8937 /** 8938 * xmlXPathStringFunction: 8939 * @ctxt: the XPath Parser context 8940 * @nargs: the number of arguments 8941 * 8942 * Implement the string() XPath function 8943 * string string(object?) 8944 * The string function converts an object to a string as follows: 8945 * - A node-set is converted to a string by returning the value of 8946 * the node in the node-set that is first in document order. 8947 * If the node-set is empty, an empty string is returned. 8948 * - A number is converted to a string as follows 8949 * + NaN is converted to the string NaN 8950 * + positive zero is converted to the string 0 8951 * + negative zero is converted to the string 0 8952 * + positive infinity is converted to the string Infinity 8953 * + negative infinity is converted to the string -Infinity 8954 * + if the number is an integer, the number is represented in 8955 * decimal form as a Number with no decimal point and no leading 8956 * zeros, preceded by a minus sign (-) if the number is negative 8957 * + otherwise, the number is represented in decimal form as a 8958 * Number including a decimal point with at least one digit 8959 * before the decimal point and at least one digit after the 8960 * decimal point, preceded by a minus sign (-) if the number 8961 * is negative; there must be no leading zeros before the decimal 8962 * point apart possibly from the one required digit immediately 8963 * before the decimal point; beyond the one required digit 8964 * after the decimal point there must be as many, but only as 8965 * many, more digits as are needed to uniquely distinguish the 8966 * number from all other IEEE 754 numeric values. 8967 * - The boolean false value is converted to the string false. 8968 * The boolean true value is converted to the string true. 8969 * 8970 * If the argument is omitted, it defaults to a node-set with the 8971 * context node as its only member. 8972 */ 8973 void 8974 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8975 xmlXPathObjectPtr cur; 8976 8977 if (ctxt == NULL) return; 8978 if (nargs == 0) { 8979 valuePush(ctxt, 8980 xmlXPathCacheWrapString(ctxt->context, 8981 xmlXPathCastNodeToString(ctxt->context->node))); 8982 return; 8983 } 8984 8985 CHECK_ARITY(1); 8986 cur = valuePop(ctxt); 8987 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 8988 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur)); 8989 } 8990 8991 /** 8992 * xmlXPathStringLengthFunction: 8993 * @ctxt: the XPath Parser context 8994 * @nargs: the number of arguments 8995 * 8996 * Implement the string-length() XPath function 8997 * number string-length(string?) 8998 * The string-length returns the number of characters in the string 8999 * (see [3.6 Strings]). If the argument is omitted, it defaults to 9000 * the context node converted to a string, in other words the value 9001 * of the context node. 9002 */ 9003 void 9004 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9005 xmlXPathObjectPtr cur; 9006 9007 if (nargs == 0) { 9008 if ((ctxt == NULL) || (ctxt->context == NULL)) 9009 return; 9010 if (ctxt->context->node == NULL) { 9011 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0)); 9012 } else { 9013 xmlChar *content; 9014 9015 content = xmlXPathCastNodeToString(ctxt->context->node); 9016 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 9017 xmlUTF8Strlen(content))); 9018 xmlFree(content); 9019 } 9020 return; 9021 } 9022 CHECK_ARITY(1); 9023 CAST_TO_STRING; 9024 CHECK_TYPE(XPATH_STRING); 9025 cur = valuePop(ctxt); 9026 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 9027 xmlUTF8Strlen(cur->stringval))); 9028 xmlXPathReleaseObject(ctxt->context, cur); 9029 } 9030 9031 /** 9032 * xmlXPathConcatFunction: 9033 * @ctxt: the XPath Parser context 9034 * @nargs: the number of arguments 9035 * 9036 * Implement the concat() XPath function 9037 * string concat(string, string, string*) 9038 * The concat function returns the concatenation of its arguments. 9039 */ 9040 void 9041 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9042 xmlXPathObjectPtr cur, newobj; 9043 xmlChar *tmp; 9044 9045 if (ctxt == NULL) return; 9046 if (nargs < 2) { 9047 CHECK_ARITY(2); 9048 } 9049 9050 CAST_TO_STRING; 9051 cur = valuePop(ctxt); 9052 if ((cur == NULL) || (cur->type != XPATH_STRING)) { 9053 xmlXPathReleaseObject(ctxt->context, cur); 9054 return; 9055 } 9056 nargs--; 9057 9058 while (nargs > 0) { 9059 CAST_TO_STRING; 9060 newobj = valuePop(ctxt); 9061 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) { 9062 xmlXPathReleaseObject(ctxt->context, newobj); 9063 xmlXPathReleaseObject(ctxt->context, cur); 9064 XP_ERROR(XPATH_INVALID_TYPE); 9065 } 9066 tmp = xmlStrcat(newobj->stringval, cur->stringval); 9067 newobj->stringval = cur->stringval; 9068 cur->stringval = tmp; 9069 xmlXPathReleaseObject(ctxt->context, newobj); 9070 nargs--; 9071 } 9072 valuePush(ctxt, cur); 9073 } 9074 9075 /** 9076 * xmlXPathContainsFunction: 9077 * @ctxt: the XPath Parser context 9078 * @nargs: the number of arguments 9079 * 9080 * Implement the contains() XPath function 9081 * boolean contains(string, string) 9082 * The contains function returns true if the first argument string 9083 * contains the second argument string, and otherwise returns false. 9084 */ 9085 void 9086 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9087 xmlXPathObjectPtr hay, needle; 9088 9089 CHECK_ARITY(2); 9090 CAST_TO_STRING; 9091 CHECK_TYPE(XPATH_STRING); 9092 needle = valuePop(ctxt); 9093 CAST_TO_STRING; 9094 hay = valuePop(ctxt); 9095 9096 if ((hay == NULL) || (hay->type != XPATH_STRING)) { 9097 xmlXPathReleaseObject(ctxt->context, hay); 9098 xmlXPathReleaseObject(ctxt->context, needle); 9099 XP_ERROR(XPATH_INVALID_TYPE); 9100 } 9101 if (xmlStrstr(hay->stringval, needle->stringval)) 9102 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); 9103 else 9104 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); 9105 xmlXPathReleaseObject(ctxt->context, hay); 9106 xmlXPathReleaseObject(ctxt->context, needle); 9107 } 9108 9109 /** 9110 * xmlXPathStartsWithFunction: 9111 * @ctxt: the XPath Parser context 9112 * @nargs: the number of arguments 9113 * 9114 * Implement the starts-with() XPath function 9115 * boolean starts-with(string, string) 9116 * The starts-with function returns true if the first argument string 9117 * starts with the second argument string, and otherwise returns false. 9118 */ 9119 void 9120 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9121 xmlXPathObjectPtr hay, needle; 9122 int n; 9123 9124 CHECK_ARITY(2); 9125 CAST_TO_STRING; 9126 CHECK_TYPE(XPATH_STRING); 9127 needle = valuePop(ctxt); 9128 CAST_TO_STRING; 9129 hay = valuePop(ctxt); 9130 9131 if ((hay == NULL) || (hay->type != XPATH_STRING)) { 9132 xmlXPathReleaseObject(ctxt->context, hay); 9133 xmlXPathReleaseObject(ctxt->context, needle); 9134 XP_ERROR(XPATH_INVALID_TYPE); 9135 } 9136 n = xmlStrlen(needle->stringval); 9137 if (xmlStrncmp(hay->stringval, needle->stringval, n)) 9138 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); 9139 else 9140 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); 9141 xmlXPathReleaseObject(ctxt->context, hay); 9142 xmlXPathReleaseObject(ctxt->context, needle); 9143 } 9144 9145 /** 9146 * xmlXPathSubstringFunction: 9147 * @ctxt: the XPath Parser context 9148 * @nargs: the number of arguments 9149 * 9150 * Implement the substring() XPath function 9151 * string substring(string, number, number?) 9152 * The substring function returns the substring of the first argument 9153 * starting at the position specified in the second argument with 9154 * length specified in the third argument. For example, 9155 * substring("12345",2,3) returns "234". If the third argument is not 9156 * specified, it returns the substring starting at the position specified 9157 * in the second argument and continuing to the end of the string. For 9158 * example, substring("12345",2) returns "2345". More precisely, each 9159 * character in the string (see [3.6 Strings]) is considered to have a 9160 * numeric position: the position of the first character is 1, the position 9161 * of the second character is 2 and so on. The returned substring contains 9162 * those characters for which the position of the character is greater than 9163 * or equal to the second argument and, if the third argument is specified, 9164 * less than the sum of the second and third arguments; the comparisons 9165 * and addition used for the above follow the standard IEEE 754 rules. Thus: 9166 * - substring("12345", 1.5, 2.6) returns "234" 9167 * - substring("12345", 0, 3) returns "12" 9168 * - substring("12345", 0 div 0, 3) returns "" 9169 * - substring("12345", 1, 0 div 0) returns "" 9170 * - substring("12345", -42, 1 div 0) returns "12345" 9171 * - substring("12345", -1 div 0, 1 div 0) returns "" 9172 */ 9173 void 9174 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9175 xmlXPathObjectPtr str, start, len; 9176 double le=0, in; 9177 int i, l, m; 9178 xmlChar *ret; 9179 9180 if (nargs < 2) { 9181 CHECK_ARITY(2); 9182 } 9183 if (nargs > 3) { 9184 CHECK_ARITY(3); 9185 } 9186 /* 9187 * take care of possible last (position) argument 9188 */ 9189 if (nargs == 3) { 9190 CAST_TO_NUMBER; 9191 CHECK_TYPE(XPATH_NUMBER); 9192 len = valuePop(ctxt); 9193 le = len->floatval; 9194 xmlXPathReleaseObject(ctxt->context, len); 9195 } 9196 9197 CAST_TO_NUMBER; 9198 CHECK_TYPE(XPATH_NUMBER); 9199 start = valuePop(ctxt); 9200 in = start->floatval; 9201 xmlXPathReleaseObject(ctxt->context, start); 9202 CAST_TO_STRING; 9203 CHECK_TYPE(XPATH_STRING); 9204 str = valuePop(ctxt); 9205 m = xmlUTF8Strlen((const unsigned char *)str->stringval); 9206 9207 /* 9208 * If last pos not present, calculate last position 9209 */ 9210 if (nargs != 3) { 9211 le = (double)m; 9212 if (in < 1.0) 9213 in = 1.0; 9214 } 9215 9216 /* Need to check for the special cases where either 9217 * the index is NaN, the length is NaN, or both 9218 * arguments are infinity (relying on Inf + -Inf = NaN) 9219 */ 9220 if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) { 9221 /* 9222 * To meet the requirements of the spec, the arguments 9223 * must be converted to integer format before 9224 * initial index calculations are done 9225 * 9226 * First we go to integer form, rounding up 9227 * and checking for special cases 9228 */ 9229 i = (int) in; 9230 if (((double)i)+0.5 <= in) i++; 9231 9232 if (xmlXPathIsInf(le) == 1) { 9233 l = m; 9234 if (i < 1) 9235 i = 1; 9236 } 9237 else if (xmlXPathIsInf(le) == -1 || le < 0.0) 9238 l = 0; 9239 else { 9240 l = (int) le; 9241 if (((double)l)+0.5 <= le) l++; 9242 } 9243 9244 /* Now we normalize inidices */ 9245 i -= 1; 9246 l += i; 9247 if (i < 0) 9248 i = 0; 9249 if (l > m) 9250 l = m; 9251 9252 /* number of chars to copy */ 9253 l -= i; 9254 9255 ret = xmlUTF8Strsub(str->stringval, i, l); 9256 } 9257 else { 9258 ret = NULL; 9259 } 9260 if (ret == NULL) 9261 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 9262 else { 9263 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret)); 9264 xmlFree(ret); 9265 } 9266 xmlXPathReleaseObject(ctxt->context, str); 9267 } 9268 9269 /** 9270 * xmlXPathSubstringBeforeFunction: 9271 * @ctxt: the XPath Parser context 9272 * @nargs: the number of arguments 9273 * 9274 * Implement the substring-before() XPath function 9275 * string substring-before(string, string) 9276 * The substring-before function returns the substring of the first 9277 * argument string that precedes the first occurrence of the second 9278 * argument string in the first argument string, or the empty string 9279 * if the first argument string does not contain the second argument 9280 * string. For example, substring-before("1999/04/01","/") returns 1999. 9281 */ 9282 void 9283 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9284 xmlXPathObjectPtr str; 9285 xmlXPathObjectPtr find; 9286 xmlBufPtr target; 9287 const xmlChar *point; 9288 int offset; 9289 9290 CHECK_ARITY(2); 9291 CAST_TO_STRING; 9292 find = valuePop(ctxt); 9293 CAST_TO_STRING; 9294 str = valuePop(ctxt); 9295 9296 target = xmlBufCreate(); 9297 if (target) { 9298 point = xmlStrstr(str->stringval, find->stringval); 9299 if (point) { 9300 offset = (int)(point - str->stringval); 9301 xmlBufAdd(target, str->stringval, offset); 9302 } 9303 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9304 xmlBufContent(target))); 9305 xmlBufFree(target); 9306 } 9307 xmlXPathReleaseObject(ctxt->context, str); 9308 xmlXPathReleaseObject(ctxt->context, find); 9309 } 9310 9311 /** 9312 * xmlXPathSubstringAfterFunction: 9313 * @ctxt: the XPath Parser context 9314 * @nargs: the number of arguments 9315 * 9316 * Implement the substring-after() XPath function 9317 * string substring-after(string, string) 9318 * The substring-after function returns the substring of the first 9319 * argument string that follows the first occurrence of the second 9320 * argument string in the first argument string, or the empty stringi 9321 * if the first argument string does not contain the second argument 9322 * string. For example, substring-after("1999/04/01","/") returns 04/01, 9323 * and substring-after("1999/04/01","19") returns 99/04/01. 9324 */ 9325 void 9326 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9327 xmlXPathObjectPtr str; 9328 xmlXPathObjectPtr find; 9329 xmlBufPtr target; 9330 const xmlChar *point; 9331 int offset; 9332 9333 CHECK_ARITY(2); 9334 CAST_TO_STRING; 9335 find = valuePop(ctxt); 9336 CAST_TO_STRING; 9337 str = valuePop(ctxt); 9338 9339 target = xmlBufCreate(); 9340 if (target) { 9341 point = xmlStrstr(str->stringval, find->stringval); 9342 if (point) { 9343 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval); 9344 xmlBufAdd(target, &str->stringval[offset], 9345 xmlStrlen(str->stringval) - offset); 9346 } 9347 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9348 xmlBufContent(target))); 9349 xmlBufFree(target); 9350 } 9351 xmlXPathReleaseObject(ctxt->context, str); 9352 xmlXPathReleaseObject(ctxt->context, find); 9353 } 9354 9355 /** 9356 * xmlXPathNormalizeFunction: 9357 * @ctxt: the XPath Parser context 9358 * @nargs: the number of arguments 9359 * 9360 * Implement the normalize-space() XPath function 9361 * string normalize-space(string?) 9362 * The normalize-space function returns the argument string with white 9363 * space normalized by stripping leading and trailing whitespace 9364 * and replacing sequences of whitespace characters by a single 9365 * space. Whitespace characters are the same allowed by the S production 9366 * in XML. If the argument is omitted, it defaults to the context 9367 * node converted to a string, in other words the value of the context node. 9368 */ 9369 void 9370 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9371 xmlXPathObjectPtr obj = NULL; 9372 xmlChar *source = NULL; 9373 xmlBufPtr target; 9374 xmlChar blank; 9375 9376 if (ctxt == NULL) return; 9377 if (nargs == 0) { 9378 /* Use current context node */ 9379 valuePush(ctxt, 9380 xmlXPathCacheWrapString(ctxt->context, 9381 xmlXPathCastNodeToString(ctxt->context->node))); 9382 nargs = 1; 9383 } 9384 9385 CHECK_ARITY(1); 9386 CAST_TO_STRING; 9387 CHECK_TYPE(XPATH_STRING); 9388 obj = valuePop(ctxt); 9389 source = obj->stringval; 9390 9391 target = xmlBufCreate(); 9392 if (target && source) { 9393 9394 /* Skip leading whitespaces */ 9395 while (IS_BLANK_CH(*source)) 9396 source++; 9397 9398 /* Collapse intermediate whitespaces, and skip trailing whitespaces */ 9399 blank = 0; 9400 while (*source) { 9401 if (IS_BLANK_CH(*source)) { 9402 blank = 0x20; 9403 } else { 9404 if (blank) { 9405 xmlBufAdd(target, &blank, 1); 9406 blank = 0; 9407 } 9408 xmlBufAdd(target, source, 1); 9409 } 9410 source++; 9411 } 9412 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9413 xmlBufContent(target))); 9414 xmlBufFree(target); 9415 } 9416 xmlXPathReleaseObject(ctxt->context, obj); 9417 } 9418 9419 /** 9420 * xmlXPathTranslateFunction: 9421 * @ctxt: the XPath Parser context 9422 * @nargs: the number of arguments 9423 * 9424 * Implement the translate() XPath function 9425 * string translate(string, string, string) 9426 * The translate function returns the first argument string with 9427 * occurrences of characters in the second argument string replaced 9428 * by the character at the corresponding position in the third argument 9429 * string. For example, translate("bar","abc","ABC") returns the string 9430 * BAr. If there is a character in the second argument string with no 9431 * character at a corresponding position in the third argument string 9432 * (because the second argument string is longer than the third argument 9433 * string), then occurrences of that character in the first argument 9434 * string are removed. For example, translate("--aaa--","abc-","ABC") 9435 * returns "AAA". If a character occurs more than once in second 9436 * argument string, then the first occurrence determines the replacement 9437 * character. If the third argument string is longer than the second 9438 * argument string, then excess characters are ignored. 9439 */ 9440 void 9441 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9442 xmlXPathObjectPtr str; 9443 xmlXPathObjectPtr from; 9444 xmlXPathObjectPtr to; 9445 xmlBufPtr target; 9446 int offset, max; 9447 xmlChar ch; 9448 const xmlChar *point; 9449 xmlChar *cptr; 9450 9451 CHECK_ARITY(3); 9452 9453 CAST_TO_STRING; 9454 to = valuePop(ctxt); 9455 CAST_TO_STRING; 9456 from = valuePop(ctxt); 9457 CAST_TO_STRING; 9458 str = valuePop(ctxt); 9459 9460 target = xmlBufCreate(); 9461 if (target) { 9462 max = xmlUTF8Strlen(to->stringval); 9463 for (cptr = str->stringval; (ch=*cptr); ) { 9464 offset = xmlUTF8Strloc(from->stringval, cptr); 9465 if (offset >= 0) { 9466 if (offset < max) { 9467 point = xmlUTF8Strpos(to->stringval, offset); 9468 if (point) 9469 xmlBufAdd(target, point, xmlUTF8Strsize(point, 1)); 9470 } 9471 } else 9472 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1)); 9473 9474 /* Step to next character in input */ 9475 cptr++; 9476 if ( ch & 0x80 ) { 9477 /* if not simple ascii, verify proper format */ 9478 if ( (ch & 0xc0) != 0xc0 ) { 9479 xmlGenericError(xmlGenericErrorContext, 9480 "xmlXPathTranslateFunction: Invalid UTF8 string\n"); 9481 /* not asserting an XPath error is probably better */ 9482 break; 9483 } 9484 /* then skip over remaining bytes for this char */ 9485 while ( (ch <<= 1) & 0x80 ) 9486 if ( (*cptr++ & 0xc0) != 0x80 ) { 9487 xmlGenericError(xmlGenericErrorContext, 9488 "xmlXPathTranslateFunction: Invalid UTF8 string\n"); 9489 /* not asserting an XPath error is probably better */ 9490 break; 9491 } 9492 if (ch & 0x80) /* must have had error encountered */ 9493 break; 9494 } 9495 } 9496 } 9497 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9498 xmlBufContent(target))); 9499 xmlBufFree(target); 9500 xmlXPathReleaseObject(ctxt->context, str); 9501 xmlXPathReleaseObject(ctxt->context, from); 9502 xmlXPathReleaseObject(ctxt->context, to); 9503 } 9504 9505 /** 9506 * xmlXPathBooleanFunction: 9507 * @ctxt: the XPath Parser context 9508 * @nargs: the number of arguments 9509 * 9510 * Implement the boolean() XPath function 9511 * boolean boolean(object) 9512 * The boolean function converts its argument to a boolean as follows: 9513 * - a number is true if and only if it is neither positive or 9514 * negative zero nor NaN 9515 * - a node-set is true if and only if it is non-empty 9516 * - a string is true if and only if its length is non-zero 9517 */ 9518 void 9519 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9520 xmlXPathObjectPtr cur; 9521 9522 CHECK_ARITY(1); 9523 cur = valuePop(ctxt); 9524 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 9525 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur); 9526 valuePush(ctxt, cur); 9527 } 9528 9529 /** 9530 * xmlXPathNotFunction: 9531 * @ctxt: the XPath Parser context 9532 * @nargs: the number of arguments 9533 * 9534 * Implement the not() XPath function 9535 * boolean not(boolean) 9536 * The not function returns true if its argument is false, 9537 * and false otherwise. 9538 */ 9539 void 9540 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9541 CHECK_ARITY(1); 9542 CAST_TO_BOOLEAN; 9543 CHECK_TYPE(XPATH_BOOLEAN); 9544 ctxt->value->boolval = ! ctxt->value->boolval; 9545 } 9546 9547 /** 9548 * xmlXPathTrueFunction: 9549 * @ctxt: the XPath Parser context 9550 * @nargs: the number of arguments 9551 * 9552 * Implement the true() XPath function 9553 * boolean true() 9554 */ 9555 void 9556 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9557 CHECK_ARITY(0); 9558 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); 9559 } 9560 9561 /** 9562 * xmlXPathFalseFunction: 9563 * @ctxt: the XPath Parser context 9564 * @nargs: the number of arguments 9565 * 9566 * Implement the false() XPath function 9567 * boolean false() 9568 */ 9569 void 9570 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9571 CHECK_ARITY(0); 9572 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); 9573 } 9574 9575 /** 9576 * xmlXPathLangFunction: 9577 * @ctxt: the XPath Parser context 9578 * @nargs: the number of arguments 9579 * 9580 * Implement the lang() XPath function 9581 * boolean lang(string) 9582 * The lang function returns true or false depending on whether the 9583 * language of the context node as specified by xml:lang attributes 9584 * is the same as or is a sublanguage of the language specified by 9585 * the argument string. The language of the context node is determined 9586 * by the value of the xml:lang attribute on the context node, or, if 9587 * the context node has no xml:lang attribute, by the value of the 9588 * xml:lang attribute on the nearest ancestor of the context node that 9589 * has an xml:lang attribute. If there is no such attribute, then lang 9590 * returns false. If there is such an attribute, then lang returns 9591 * true if the attribute value is equal to the argument ignoring case, 9592 * or if there is some suffix starting with - such that the attribute 9593 * value is equal to the argument ignoring that suffix of the attribute 9594 * value and ignoring case. 9595 */ 9596 void 9597 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9598 xmlXPathObjectPtr val = NULL; 9599 const xmlChar *theLang = NULL; 9600 const xmlChar *lang; 9601 int ret = 0; 9602 int i; 9603 9604 CHECK_ARITY(1); 9605 CAST_TO_STRING; 9606 CHECK_TYPE(XPATH_STRING); 9607 val = valuePop(ctxt); 9608 lang = val->stringval; 9609 theLang = xmlNodeGetLang(ctxt->context->node); 9610 if ((theLang != NULL) && (lang != NULL)) { 9611 for (i = 0;lang[i] != 0;i++) 9612 if (toupper(lang[i]) != toupper(theLang[i])) 9613 goto not_equal; 9614 if ((theLang[i] == 0) || (theLang[i] == '-')) 9615 ret = 1; 9616 } 9617 not_equal: 9618 if (theLang != NULL) 9619 xmlFree((void *)theLang); 9620 9621 xmlXPathReleaseObject(ctxt->context, val); 9622 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret)); 9623 } 9624 9625 /** 9626 * xmlXPathNumberFunction: 9627 * @ctxt: the XPath Parser context 9628 * @nargs: the number of arguments 9629 * 9630 * Implement the number() XPath function 9631 * number number(object?) 9632 */ 9633 void 9634 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9635 xmlXPathObjectPtr cur; 9636 double res; 9637 9638 if (ctxt == NULL) return; 9639 if (nargs == 0) { 9640 if (ctxt->context->node == NULL) { 9641 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0)); 9642 } else { 9643 xmlChar* content = xmlNodeGetContent(ctxt->context->node); 9644 9645 res = xmlXPathStringEvalNumber(content); 9646 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res)); 9647 xmlFree(content); 9648 } 9649 return; 9650 } 9651 9652 CHECK_ARITY(1); 9653 cur = valuePop(ctxt); 9654 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur)); 9655 } 9656 9657 /** 9658 * xmlXPathSumFunction: 9659 * @ctxt: the XPath Parser context 9660 * @nargs: the number of arguments 9661 * 9662 * Implement the sum() XPath function 9663 * number sum(node-set) 9664 * The sum function returns the sum of the values of the nodes in 9665 * the argument node-set. 9666 */ 9667 void 9668 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9669 xmlXPathObjectPtr cur; 9670 int i; 9671 double res = 0.0; 9672 9673 CHECK_ARITY(1); 9674 if ((ctxt->value == NULL) || 9675 ((ctxt->value->type != XPATH_NODESET) && 9676 (ctxt->value->type != XPATH_XSLT_TREE))) 9677 XP_ERROR(XPATH_INVALID_TYPE); 9678 cur = valuePop(ctxt); 9679 9680 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) { 9681 for (i = 0; i < cur->nodesetval->nodeNr; i++) { 9682 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]); 9683 } 9684 } 9685 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res)); 9686 xmlXPathReleaseObject(ctxt->context, cur); 9687 } 9688 9689 /** 9690 * xmlXPathFloorFunction: 9691 * @ctxt: the XPath Parser context 9692 * @nargs: the number of arguments 9693 * 9694 * Implement the floor() XPath function 9695 * number floor(number) 9696 * The floor function returns the largest (closest to positive infinity) 9697 * number that is not greater than the argument and that is an integer. 9698 */ 9699 void 9700 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9701 CHECK_ARITY(1); 9702 CAST_TO_NUMBER; 9703 CHECK_TYPE(XPATH_NUMBER); 9704 9705 ctxt->value->floatval = floor(ctxt->value->floatval); 9706 } 9707 9708 /** 9709 * xmlXPathCeilingFunction: 9710 * @ctxt: the XPath Parser context 9711 * @nargs: the number of arguments 9712 * 9713 * Implement the ceiling() XPath function 9714 * number ceiling(number) 9715 * The ceiling function returns the smallest (closest to negative infinity) 9716 * number that is not less than the argument and that is an integer. 9717 */ 9718 void 9719 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9720 CHECK_ARITY(1); 9721 CAST_TO_NUMBER; 9722 CHECK_TYPE(XPATH_NUMBER); 9723 9724 ctxt->value->floatval = ceil(ctxt->value->floatval); 9725 } 9726 9727 /** 9728 * xmlXPathRoundFunction: 9729 * @ctxt: the XPath Parser context 9730 * @nargs: the number of arguments 9731 * 9732 * Implement the round() XPath function 9733 * number round(number) 9734 * The round function returns the number that is closest to the 9735 * argument and that is an integer. If there are two such numbers, 9736 * then the one that is closest to positive infinity is returned. 9737 */ 9738 void 9739 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9740 double f; 9741 9742 CHECK_ARITY(1); 9743 CAST_TO_NUMBER; 9744 CHECK_TYPE(XPATH_NUMBER); 9745 9746 f = ctxt->value->floatval; 9747 9748 /* Test for zero to keep negative zero unchanged. */ 9749 if ((xmlXPathIsNaN(f)) || (f == 0.0)) 9750 return; 9751 9752 if ((f >= -0.5) && (f < 0.0)) { 9753 /* Negative zero. */ 9754 ctxt->value->floatval = xmlXPathNZERO; 9755 } 9756 else { 9757 double rounded = floor(f); 9758 if (f - rounded >= 0.5) 9759 rounded += 1.0; 9760 ctxt->value->floatval = rounded; 9761 } 9762 } 9763 9764 /************************************************************************ 9765 * * 9766 * The Parser * 9767 * * 9768 ************************************************************************/ 9769 9770 /* 9771 * a few forward declarations since we use a recursive call based 9772 * implementation. 9773 */ 9774 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort); 9775 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter); 9776 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt); 9777 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt); 9778 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, 9779 int qualified); 9780 9781 /** 9782 * xmlXPathCurrentChar: 9783 * @ctxt: the XPath parser context 9784 * @cur: pointer to the beginning of the char 9785 * @len: pointer to the length of the char read 9786 * 9787 * The current char value, if using UTF-8 this may actually span multiple 9788 * bytes in the input buffer. 9789 * 9790 * Returns the current char value and its length 9791 */ 9792 9793 static int 9794 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) { 9795 unsigned char c; 9796 unsigned int val; 9797 const xmlChar *cur; 9798 9799 if (ctxt == NULL) 9800 return(0); 9801 cur = ctxt->cur; 9802 9803 /* 9804 * We are supposed to handle UTF8, check it's valid 9805 * From rfc2044: encoding of the Unicode values on UTF-8: 9806 * 9807 * UCS-4 range (hex.) UTF-8 octet sequence (binary) 9808 * 0000 0000-0000 007F 0xxxxxxx 9809 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx 9810 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx 9811 * 9812 * Check for the 0x110000 limit too 9813 */ 9814 c = *cur; 9815 if (c & 0x80) { 9816 if ((cur[1] & 0xc0) != 0x80) 9817 goto encoding_error; 9818 if ((c & 0xe0) == 0xe0) { 9819 9820 if ((cur[2] & 0xc0) != 0x80) 9821 goto encoding_error; 9822 if ((c & 0xf0) == 0xf0) { 9823 if (((c & 0xf8) != 0xf0) || 9824 ((cur[3] & 0xc0) != 0x80)) 9825 goto encoding_error; 9826 /* 4-byte code */ 9827 *len = 4; 9828 val = (cur[0] & 0x7) << 18; 9829 val |= (cur[1] & 0x3f) << 12; 9830 val |= (cur[2] & 0x3f) << 6; 9831 val |= cur[3] & 0x3f; 9832 } else { 9833 /* 3-byte code */ 9834 *len = 3; 9835 val = (cur[0] & 0xf) << 12; 9836 val |= (cur[1] & 0x3f) << 6; 9837 val |= cur[2] & 0x3f; 9838 } 9839 } else { 9840 /* 2-byte code */ 9841 *len = 2; 9842 val = (cur[0] & 0x1f) << 6; 9843 val |= cur[1] & 0x3f; 9844 } 9845 if (!IS_CHAR(val)) { 9846 XP_ERROR0(XPATH_INVALID_CHAR_ERROR); 9847 } 9848 return(val); 9849 } else { 9850 /* 1-byte code */ 9851 *len = 1; 9852 return((int) *cur); 9853 } 9854 encoding_error: 9855 /* 9856 * If we detect an UTF8 error that probably means that the 9857 * input encoding didn't get properly advertised in the 9858 * declaration header. Report the error and switch the encoding 9859 * to ISO-Latin-1 (if you don't like this policy, just declare the 9860 * encoding !) 9861 */ 9862 *len = 0; 9863 XP_ERROR0(XPATH_ENCODING_ERROR); 9864 } 9865 9866 /** 9867 * xmlXPathParseNCName: 9868 * @ctxt: the XPath Parser context 9869 * 9870 * parse an XML namespace non qualified name. 9871 * 9872 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)* 9873 * 9874 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' | 9875 * CombiningChar | Extender 9876 * 9877 * Returns the namespace name or NULL 9878 */ 9879 9880 xmlChar * 9881 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) { 9882 const xmlChar *in; 9883 xmlChar *ret; 9884 int count = 0; 9885 9886 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL); 9887 /* 9888 * Accelerator for simple ASCII names 9889 */ 9890 in = ctxt->cur; 9891 if (((*in >= 0x61) && (*in <= 0x7A)) || 9892 ((*in >= 0x41) && (*in <= 0x5A)) || 9893 (*in == '_')) { 9894 in++; 9895 while (((*in >= 0x61) && (*in <= 0x7A)) || 9896 ((*in >= 0x41) && (*in <= 0x5A)) || 9897 ((*in >= 0x30) && (*in <= 0x39)) || 9898 (*in == '_') || (*in == '.') || 9899 (*in == '-')) 9900 in++; 9901 if ((*in == ' ') || (*in == '>') || (*in == '/') || 9902 (*in == '[') || (*in == ']') || (*in == ':') || 9903 (*in == '@') || (*in == '*')) { 9904 count = in - ctxt->cur; 9905 if (count == 0) 9906 return(NULL); 9907 ret = xmlStrndup(ctxt->cur, count); 9908 ctxt->cur = in; 9909 return(ret); 9910 } 9911 } 9912 return(xmlXPathParseNameComplex(ctxt, 0)); 9913 } 9914 9915 9916 /** 9917 * xmlXPathParseQName: 9918 * @ctxt: the XPath Parser context 9919 * @prefix: a xmlChar ** 9920 * 9921 * parse an XML qualified name 9922 * 9923 * [NS 5] QName ::= (Prefix ':')? LocalPart 9924 * 9925 * [NS 6] Prefix ::= NCName 9926 * 9927 * [NS 7] LocalPart ::= NCName 9928 * 9929 * Returns the function returns the local part, and prefix is updated 9930 * to get the Prefix if any. 9931 */ 9932 9933 static xmlChar * 9934 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) { 9935 xmlChar *ret = NULL; 9936 9937 *prefix = NULL; 9938 ret = xmlXPathParseNCName(ctxt); 9939 if (ret && CUR == ':') { 9940 *prefix = ret; 9941 NEXT; 9942 ret = xmlXPathParseNCName(ctxt); 9943 } 9944 return(ret); 9945 } 9946 9947 /** 9948 * xmlXPathParseName: 9949 * @ctxt: the XPath Parser context 9950 * 9951 * parse an XML name 9952 * 9953 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | 9954 * CombiningChar | Extender 9955 * 9956 * [5] Name ::= (Letter | '_' | ':') (NameChar)* 9957 * 9958 * Returns the namespace name or NULL 9959 */ 9960 9961 xmlChar * 9962 xmlXPathParseName(xmlXPathParserContextPtr ctxt) { 9963 const xmlChar *in; 9964 xmlChar *ret; 9965 size_t count = 0; 9966 9967 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL); 9968 /* 9969 * Accelerator for simple ASCII names 9970 */ 9971 in = ctxt->cur; 9972 if (((*in >= 0x61) && (*in <= 0x7A)) || 9973 ((*in >= 0x41) && (*in <= 0x5A)) || 9974 (*in == '_') || (*in == ':')) { 9975 in++; 9976 while (((*in >= 0x61) && (*in <= 0x7A)) || 9977 ((*in >= 0x41) && (*in <= 0x5A)) || 9978 ((*in >= 0x30) && (*in <= 0x39)) || 9979 (*in == '_') || (*in == '-') || 9980 (*in == ':') || (*in == '.')) 9981 in++; 9982 if ((*in > 0) && (*in < 0x80)) { 9983 count = in - ctxt->cur; 9984 if (count > XML_MAX_NAME_LENGTH) { 9985 ctxt->cur = in; 9986 XP_ERRORNULL(XPATH_EXPR_ERROR); 9987 } 9988 ret = xmlStrndup(ctxt->cur, count); 9989 ctxt->cur = in; 9990 return(ret); 9991 } 9992 } 9993 return(xmlXPathParseNameComplex(ctxt, 1)); 9994 } 9995 9996 static xmlChar * 9997 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) { 9998 xmlChar buf[XML_MAX_NAMELEN + 5]; 9999 int len = 0, l; 10000 int c; 10001 10002 /* 10003 * Handler for more complex cases 10004 */ 10005 c = CUR_CHAR(l); 10006 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */ 10007 (c == '[') || (c == ']') || (c == '@') || /* accelerators */ 10008 (c == '*') || /* accelerators */ 10009 (!IS_LETTER(c) && (c != '_') && 10010 ((!qualified) || (c != ':')))) { 10011 return(NULL); 10012 } 10013 10014 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */ 10015 ((IS_LETTER(c)) || (IS_DIGIT(c)) || 10016 (c == '.') || (c == '-') || 10017 (c == '_') || ((qualified) && (c == ':')) || 10018 (IS_COMBINING(c)) || 10019 (IS_EXTENDER(c)))) { 10020 COPY_BUF(l,buf,len,c); 10021 NEXTL(l); 10022 c = CUR_CHAR(l); 10023 if (len >= XML_MAX_NAMELEN) { 10024 /* 10025 * Okay someone managed to make a huge name, so he's ready to pay 10026 * for the processing speed. 10027 */ 10028 xmlChar *buffer; 10029 int max = len * 2; 10030 10031 if (len > XML_MAX_NAME_LENGTH) { 10032 XP_ERRORNULL(XPATH_EXPR_ERROR); 10033 } 10034 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar)); 10035 if (buffer == NULL) { 10036 XP_ERRORNULL(XPATH_MEMORY_ERROR); 10037 } 10038 memcpy(buffer, buf, len); 10039 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */ 10040 (c == '.') || (c == '-') || 10041 (c == '_') || ((qualified) && (c == ':')) || 10042 (IS_COMBINING(c)) || 10043 (IS_EXTENDER(c))) { 10044 if (len + 10 > max) { 10045 if (max > XML_MAX_NAME_LENGTH) { 10046 XP_ERRORNULL(XPATH_EXPR_ERROR); 10047 } 10048 max *= 2; 10049 buffer = (xmlChar *) xmlRealloc(buffer, 10050 max * sizeof(xmlChar)); 10051 if (buffer == NULL) { 10052 XP_ERRORNULL(XPATH_MEMORY_ERROR); 10053 } 10054 } 10055 COPY_BUF(l,buffer,len,c); 10056 NEXTL(l); 10057 c = CUR_CHAR(l); 10058 } 10059 buffer[len] = 0; 10060 return(buffer); 10061 } 10062 } 10063 if (len == 0) 10064 return(NULL); 10065 return(xmlStrndup(buf, len)); 10066 } 10067 10068 #define MAX_FRAC 20 10069 10070 /** 10071 * xmlXPathStringEvalNumber: 10072 * @str: A string to scan 10073 * 10074 * [30a] Float ::= Number ('e' Digits?)? 10075 * 10076 * [30] Number ::= Digits ('.' Digits?)? 10077 * | '.' Digits 10078 * [31] Digits ::= [0-9]+ 10079 * 10080 * Compile a Number in the string 10081 * In complement of the Number expression, this function also handles 10082 * negative values : '-' Number. 10083 * 10084 * Returns the double value. 10085 */ 10086 double 10087 xmlXPathStringEvalNumber(const xmlChar *str) { 10088 const xmlChar *cur = str; 10089 double ret; 10090 int ok = 0; 10091 int isneg = 0; 10092 int exponent = 0; 10093 int is_exponent_negative = 0; 10094 #ifdef __GNUC__ 10095 unsigned long tmp = 0; 10096 double temp; 10097 #endif 10098 if (cur == NULL) return(0); 10099 while (IS_BLANK_CH(*cur)) cur++; 10100 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) { 10101 return(xmlXPathNAN); 10102 } 10103 if (*cur == '-') { 10104 isneg = 1; 10105 cur++; 10106 } 10107 10108 #ifdef __GNUC__ 10109 /* 10110 * tmp/temp is a workaround against a gcc compiler bug 10111 * http://veillard.com/gcc.bug 10112 */ 10113 ret = 0; 10114 while ((*cur >= '0') && (*cur <= '9')) { 10115 ret = ret * 10; 10116 tmp = (*cur - '0'); 10117 ok = 1; 10118 cur++; 10119 temp = (double) tmp; 10120 ret = ret + temp; 10121 } 10122 #else 10123 ret = 0; 10124 while ((*cur >= '0') && (*cur <= '9')) { 10125 ret = ret * 10 + (*cur - '0'); 10126 ok = 1; 10127 cur++; 10128 } 10129 #endif 10130 10131 if (*cur == '.') { 10132 int v, frac = 0, max; 10133 double fraction = 0; 10134 10135 cur++; 10136 if (((*cur < '0') || (*cur > '9')) && (!ok)) { 10137 return(xmlXPathNAN); 10138 } 10139 while (*cur == '0') { 10140 frac = frac + 1; 10141 cur++; 10142 } 10143 max = frac + MAX_FRAC; 10144 while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) { 10145 v = (*cur - '0'); 10146 fraction = fraction * 10 + v; 10147 frac = frac + 1; 10148 cur++; 10149 } 10150 fraction /= pow(10.0, frac); 10151 ret = ret + fraction; 10152 while ((*cur >= '0') && (*cur <= '9')) 10153 cur++; 10154 } 10155 if ((*cur == 'e') || (*cur == 'E')) { 10156 cur++; 10157 if (*cur == '-') { 10158 is_exponent_negative = 1; 10159 cur++; 10160 } else if (*cur == '+') { 10161 cur++; 10162 } 10163 while ((*cur >= '0') && (*cur <= '9')) { 10164 if (exponent < 1000000) 10165 exponent = exponent * 10 + (*cur - '0'); 10166 cur++; 10167 } 10168 } 10169 while (IS_BLANK_CH(*cur)) cur++; 10170 if (*cur != 0) return(xmlXPathNAN); 10171 if (isneg) ret = -ret; 10172 if (is_exponent_negative) exponent = -exponent; 10173 ret *= pow(10.0, (double)exponent); 10174 return(ret); 10175 } 10176 10177 /** 10178 * xmlXPathCompNumber: 10179 * @ctxt: the XPath Parser context 10180 * 10181 * [30] Number ::= Digits ('.' Digits?)? 10182 * | '.' Digits 10183 * [31] Digits ::= [0-9]+ 10184 * 10185 * Compile a Number, then push it on the stack 10186 * 10187 */ 10188 static void 10189 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt) 10190 { 10191 double ret = 0.0; 10192 int ok = 0; 10193 int exponent = 0; 10194 int is_exponent_negative = 0; 10195 #ifdef __GNUC__ 10196 unsigned long tmp = 0; 10197 double temp; 10198 #endif 10199 10200 CHECK_ERROR; 10201 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) { 10202 XP_ERROR(XPATH_NUMBER_ERROR); 10203 } 10204 #ifdef __GNUC__ 10205 /* 10206 * tmp/temp is a workaround against a gcc compiler bug 10207 * http://veillard.com/gcc.bug 10208 */ 10209 ret = 0; 10210 while ((CUR >= '0') && (CUR <= '9')) { 10211 ret = ret * 10; 10212 tmp = (CUR - '0'); 10213 ok = 1; 10214 NEXT; 10215 temp = (double) tmp; 10216 ret = ret + temp; 10217 } 10218 #else 10219 ret = 0; 10220 while ((CUR >= '0') && (CUR <= '9')) { 10221 ret = ret * 10 + (CUR - '0'); 10222 ok = 1; 10223 NEXT; 10224 } 10225 #endif 10226 if (CUR == '.') { 10227 int v, frac = 0, max; 10228 double fraction = 0; 10229 10230 NEXT; 10231 if (((CUR < '0') || (CUR > '9')) && (!ok)) { 10232 XP_ERROR(XPATH_NUMBER_ERROR); 10233 } 10234 while (CUR == '0') { 10235 frac = frac + 1; 10236 NEXT; 10237 } 10238 max = frac + MAX_FRAC; 10239 while ((CUR >= '0') && (CUR <= '9') && (frac < max)) { 10240 v = (CUR - '0'); 10241 fraction = fraction * 10 + v; 10242 frac = frac + 1; 10243 NEXT; 10244 } 10245 fraction /= pow(10.0, frac); 10246 ret = ret + fraction; 10247 while ((CUR >= '0') && (CUR <= '9')) 10248 NEXT; 10249 } 10250 if ((CUR == 'e') || (CUR == 'E')) { 10251 NEXT; 10252 if (CUR == '-') { 10253 is_exponent_negative = 1; 10254 NEXT; 10255 } else if (CUR == '+') { 10256 NEXT; 10257 } 10258 while ((CUR >= '0') && (CUR <= '9')) { 10259 if (exponent < 1000000) 10260 exponent = exponent * 10 + (CUR - '0'); 10261 NEXT; 10262 } 10263 if (is_exponent_negative) 10264 exponent = -exponent; 10265 ret *= pow(10.0, (double) exponent); 10266 } 10267 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, 10268 xmlXPathCacheNewFloat(ctxt->context, ret), NULL); 10269 } 10270 10271 /** 10272 * xmlXPathParseLiteral: 10273 * @ctxt: the XPath Parser context 10274 * 10275 * Parse a Literal 10276 * 10277 * [29] Literal ::= '"' [^"]* '"' 10278 * | "'" [^']* "'" 10279 * 10280 * Returns the value found or NULL in case of error 10281 */ 10282 static xmlChar * 10283 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) { 10284 const xmlChar *q; 10285 xmlChar *ret = NULL; 10286 10287 if (CUR == '"') { 10288 NEXT; 10289 q = CUR_PTR; 10290 while ((IS_CHAR_CH(CUR)) && (CUR != '"')) 10291 NEXT; 10292 if (!IS_CHAR_CH(CUR)) { 10293 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR); 10294 } else { 10295 ret = xmlStrndup(q, CUR_PTR - q); 10296 NEXT; 10297 } 10298 } else if (CUR == '\'') { 10299 NEXT; 10300 q = CUR_PTR; 10301 while ((IS_CHAR_CH(CUR)) && (CUR != '\'')) 10302 NEXT; 10303 if (!IS_CHAR_CH(CUR)) { 10304 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR); 10305 } else { 10306 ret = xmlStrndup(q, CUR_PTR - q); 10307 NEXT; 10308 } 10309 } else { 10310 XP_ERRORNULL(XPATH_START_LITERAL_ERROR); 10311 } 10312 return(ret); 10313 } 10314 10315 /** 10316 * xmlXPathCompLiteral: 10317 * @ctxt: the XPath Parser context 10318 * 10319 * Parse a Literal and push it on the stack. 10320 * 10321 * [29] Literal ::= '"' [^"]* '"' 10322 * | "'" [^']* "'" 10323 * 10324 * TODO: xmlXPathCompLiteral memory allocation could be improved. 10325 */ 10326 static void 10327 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) { 10328 const xmlChar *q; 10329 xmlChar *ret = NULL; 10330 10331 if (CUR == '"') { 10332 NEXT; 10333 q = CUR_PTR; 10334 while ((IS_CHAR_CH(CUR)) && (CUR != '"')) 10335 NEXT; 10336 if (!IS_CHAR_CH(CUR)) { 10337 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR); 10338 } else { 10339 ret = xmlStrndup(q, CUR_PTR - q); 10340 NEXT; 10341 } 10342 } else if (CUR == '\'') { 10343 NEXT; 10344 q = CUR_PTR; 10345 while ((IS_CHAR_CH(CUR)) && (CUR != '\'')) 10346 NEXT; 10347 if (!IS_CHAR_CH(CUR)) { 10348 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR); 10349 } else { 10350 ret = xmlStrndup(q, CUR_PTR - q); 10351 NEXT; 10352 } 10353 } else { 10354 XP_ERROR(XPATH_START_LITERAL_ERROR); 10355 } 10356 if (ret == NULL) return; 10357 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, 10358 xmlXPathCacheNewString(ctxt->context, ret), NULL); 10359 xmlFree(ret); 10360 } 10361 10362 /** 10363 * xmlXPathCompVariableReference: 10364 * @ctxt: the XPath Parser context 10365 * 10366 * Parse a VariableReference, evaluate it and push it on the stack. 10367 * 10368 * The variable bindings consist of a mapping from variable names 10369 * to variable values. The value of a variable is an object, which can be 10370 * of any of the types that are possible for the value of an expression, 10371 * and may also be of additional types not specified here. 10372 * 10373 * Early evaluation is possible since: 10374 * The variable bindings [...] used to evaluate a subexpression are 10375 * always the same as those used to evaluate the containing expression. 10376 * 10377 * [36] VariableReference ::= '$' QName 10378 */ 10379 static void 10380 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) { 10381 xmlChar *name; 10382 xmlChar *prefix; 10383 10384 SKIP_BLANKS; 10385 if (CUR != '$') { 10386 XP_ERROR(XPATH_VARIABLE_REF_ERROR); 10387 } 10388 NEXT; 10389 name = xmlXPathParseQName(ctxt, &prefix); 10390 if (name == NULL) { 10391 xmlFree(prefix); 10392 XP_ERROR(XPATH_VARIABLE_REF_ERROR); 10393 } 10394 ctxt->comp->last = -1; 10395 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, 10396 name, prefix); 10397 SKIP_BLANKS; 10398 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) { 10399 XP_ERROR(XPATH_FORBID_VARIABLE_ERROR); 10400 } 10401 } 10402 10403 /** 10404 * xmlXPathIsNodeType: 10405 * @name: a name string 10406 * 10407 * Is the name given a NodeType one. 10408 * 10409 * [38] NodeType ::= 'comment' 10410 * | 'text' 10411 * | 'processing-instruction' 10412 * | 'node' 10413 * 10414 * Returns 1 if true 0 otherwise 10415 */ 10416 int 10417 xmlXPathIsNodeType(const xmlChar *name) { 10418 if (name == NULL) 10419 return(0); 10420 10421 if (xmlStrEqual(name, BAD_CAST "node")) 10422 return(1); 10423 if (xmlStrEqual(name, BAD_CAST "text")) 10424 return(1); 10425 if (xmlStrEqual(name, BAD_CAST "comment")) 10426 return(1); 10427 if (xmlStrEqual(name, BAD_CAST "processing-instruction")) 10428 return(1); 10429 return(0); 10430 } 10431 10432 /** 10433 * xmlXPathCompFunctionCall: 10434 * @ctxt: the XPath Parser context 10435 * 10436 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')' 10437 * [17] Argument ::= Expr 10438 * 10439 * Compile a function call, the evaluation of all arguments are 10440 * pushed on the stack 10441 */ 10442 static void 10443 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) { 10444 xmlChar *name; 10445 xmlChar *prefix; 10446 int nbargs = 0; 10447 int sort = 1; 10448 10449 name = xmlXPathParseQName(ctxt, &prefix); 10450 if (name == NULL) { 10451 xmlFree(prefix); 10452 XP_ERROR(XPATH_EXPR_ERROR); 10453 } 10454 SKIP_BLANKS; 10455 #ifdef DEBUG_EXPR 10456 if (prefix == NULL) 10457 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n", 10458 name); 10459 else 10460 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n", 10461 prefix, name); 10462 #endif 10463 10464 if (CUR != '(') { 10465 xmlFree(name); 10466 xmlFree(prefix); 10467 XP_ERROR(XPATH_EXPR_ERROR); 10468 } 10469 NEXT; 10470 SKIP_BLANKS; 10471 10472 /* 10473 * Optimization for count(): we don't need the node-set to be sorted. 10474 */ 10475 if ((prefix == NULL) && (name[0] == 'c') && 10476 xmlStrEqual(name, BAD_CAST "count")) 10477 { 10478 sort = 0; 10479 } 10480 ctxt->comp->last = -1; 10481 if (CUR != ')') { 10482 while (CUR != 0) { 10483 int op1 = ctxt->comp->last; 10484 ctxt->comp->last = -1; 10485 xmlXPathCompileExpr(ctxt, sort); 10486 if (ctxt->error != XPATH_EXPRESSION_OK) { 10487 xmlFree(name); 10488 xmlFree(prefix); 10489 return; 10490 } 10491 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0); 10492 nbargs++; 10493 if (CUR == ')') break; 10494 if (CUR != ',') { 10495 xmlFree(name); 10496 xmlFree(prefix); 10497 XP_ERROR(XPATH_EXPR_ERROR); 10498 } 10499 NEXT; 10500 SKIP_BLANKS; 10501 } 10502 } 10503 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, 10504 name, prefix); 10505 NEXT; 10506 SKIP_BLANKS; 10507 } 10508 10509 /** 10510 * xmlXPathCompPrimaryExpr: 10511 * @ctxt: the XPath Parser context 10512 * 10513 * [15] PrimaryExpr ::= VariableReference 10514 * | '(' Expr ')' 10515 * | Literal 10516 * | Number 10517 * | FunctionCall 10518 * 10519 * Compile a primary expression. 10520 */ 10521 static void 10522 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) { 10523 SKIP_BLANKS; 10524 if (CUR == '$') xmlXPathCompVariableReference(ctxt); 10525 else if (CUR == '(') { 10526 NEXT; 10527 SKIP_BLANKS; 10528 xmlXPathCompileExpr(ctxt, 1); 10529 CHECK_ERROR; 10530 if (CUR != ')') { 10531 XP_ERROR(XPATH_EXPR_ERROR); 10532 } 10533 NEXT; 10534 SKIP_BLANKS; 10535 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) { 10536 xmlXPathCompNumber(ctxt); 10537 } else if ((CUR == '\'') || (CUR == '"')) { 10538 xmlXPathCompLiteral(ctxt); 10539 } else { 10540 xmlXPathCompFunctionCall(ctxt); 10541 } 10542 SKIP_BLANKS; 10543 } 10544 10545 /** 10546 * xmlXPathCompFilterExpr: 10547 * @ctxt: the XPath Parser context 10548 * 10549 * [20] FilterExpr ::= PrimaryExpr 10550 * | FilterExpr Predicate 10551 * 10552 * Compile a filter expression. 10553 * Square brackets are used to filter expressions in the same way that 10554 * they are used in location paths. It is an error if the expression to 10555 * be filtered does not evaluate to a node-set. The context node list 10556 * used for evaluating the expression in square brackets is the node-set 10557 * to be filtered listed in document order. 10558 */ 10559 10560 static void 10561 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) { 10562 xmlXPathCompPrimaryExpr(ctxt); 10563 CHECK_ERROR; 10564 SKIP_BLANKS; 10565 10566 while (CUR == '[') { 10567 xmlXPathCompPredicate(ctxt, 1); 10568 SKIP_BLANKS; 10569 } 10570 10571 10572 } 10573 10574 /** 10575 * xmlXPathScanName: 10576 * @ctxt: the XPath Parser context 10577 * 10578 * Trickery: parse an XML name but without consuming the input flow 10579 * Needed to avoid insanity in the parser state. 10580 * 10581 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | 10582 * CombiningChar | Extender 10583 * 10584 * [5] Name ::= (Letter | '_' | ':') (NameChar)* 10585 * 10586 * [6] Names ::= Name (S Name)* 10587 * 10588 * Returns the Name parsed or NULL 10589 */ 10590 10591 static xmlChar * 10592 xmlXPathScanName(xmlXPathParserContextPtr ctxt) { 10593 int len = 0, l; 10594 int c; 10595 const xmlChar *cur; 10596 xmlChar *ret; 10597 10598 cur = ctxt->cur; 10599 10600 c = CUR_CHAR(l); 10601 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */ 10602 (!IS_LETTER(c) && (c != '_') && 10603 (c != ':'))) { 10604 return(NULL); 10605 } 10606 10607 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */ 10608 ((IS_LETTER(c)) || (IS_DIGIT(c)) || 10609 (c == '.') || (c == '-') || 10610 (c == '_') || (c == ':') || 10611 (IS_COMBINING(c)) || 10612 (IS_EXTENDER(c)))) { 10613 len += l; 10614 NEXTL(l); 10615 c = CUR_CHAR(l); 10616 } 10617 ret = xmlStrndup(cur, ctxt->cur - cur); 10618 ctxt->cur = cur; 10619 return(ret); 10620 } 10621 10622 /** 10623 * xmlXPathCompPathExpr: 10624 * @ctxt: the XPath Parser context 10625 * 10626 * [19] PathExpr ::= LocationPath 10627 * | FilterExpr 10628 * | FilterExpr '/' RelativeLocationPath 10629 * | FilterExpr '//' RelativeLocationPath 10630 * 10631 * Compile a path expression. 10632 * The / operator and // operators combine an arbitrary expression 10633 * and a relative location path. It is an error if the expression 10634 * does not evaluate to a node-set. 10635 * The / operator does composition in the same way as when / is 10636 * used in a location path. As in location paths, // is short for 10637 * /descendant-or-self::node()/. 10638 */ 10639 10640 static void 10641 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) { 10642 int lc = 1; /* Should we branch to LocationPath ? */ 10643 xmlChar *name = NULL; /* we may have to preparse a name to find out */ 10644 10645 SKIP_BLANKS; 10646 if ((CUR == '$') || (CUR == '(') || 10647 (IS_ASCII_DIGIT(CUR)) || 10648 (CUR == '\'') || (CUR == '"') || 10649 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) { 10650 lc = 0; 10651 } else if (CUR == '*') { 10652 /* relative or absolute location path */ 10653 lc = 1; 10654 } else if (CUR == '/') { 10655 /* relative or absolute location path */ 10656 lc = 1; 10657 } else if (CUR == '@') { 10658 /* relative abbreviated attribute location path */ 10659 lc = 1; 10660 } else if (CUR == '.') { 10661 /* relative abbreviated attribute location path */ 10662 lc = 1; 10663 } else { 10664 /* 10665 * Problem is finding if we have a name here whether it's: 10666 * - a nodetype 10667 * - a function call in which case it's followed by '(' 10668 * - an axis in which case it's followed by ':' 10669 * - a element name 10670 * We do an a priori analysis here rather than having to 10671 * maintain parsed token content through the recursive function 10672 * calls. This looks uglier but makes the code easier to 10673 * read/write/debug. 10674 */ 10675 SKIP_BLANKS; 10676 name = xmlXPathScanName(ctxt); 10677 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) { 10678 #ifdef DEBUG_STEP 10679 xmlGenericError(xmlGenericErrorContext, 10680 "PathExpr: Axis\n"); 10681 #endif 10682 lc = 1; 10683 xmlFree(name); 10684 } else if (name != NULL) { 10685 int len =xmlStrlen(name); 10686 10687 10688 while (NXT(len) != 0) { 10689 if (NXT(len) == '/') { 10690 /* element name */ 10691 #ifdef DEBUG_STEP 10692 xmlGenericError(xmlGenericErrorContext, 10693 "PathExpr: AbbrRelLocation\n"); 10694 #endif 10695 lc = 1; 10696 break; 10697 } else if (IS_BLANK_CH(NXT(len))) { 10698 /* ignore blanks */ 10699 ; 10700 } else if (NXT(len) == ':') { 10701 #ifdef DEBUG_STEP 10702 xmlGenericError(xmlGenericErrorContext, 10703 "PathExpr: AbbrRelLocation\n"); 10704 #endif 10705 lc = 1; 10706 break; 10707 } else if ((NXT(len) == '(')) { 10708 /* Node Type or Function */ 10709 if (xmlXPathIsNodeType(name)) { 10710 #ifdef DEBUG_STEP 10711 xmlGenericError(xmlGenericErrorContext, 10712 "PathExpr: Type search\n"); 10713 #endif 10714 lc = 1; 10715 #ifdef LIBXML_XPTR_ENABLED 10716 } else if (ctxt->xptr && 10717 xmlStrEqual(name, BAD_CAST "range-to")) { 10718 lc = 1; 10719 #endif 10720 } else { 10721 #ifdef DEBUG_STEP 10722 xmlGenericError(xmlGenericErrorContext, 10723 "PathExpr: function call\n"); 10724 #endif 10725 lc = 0; 10726 } 10727 break; 10728 } else if ((NXT(len) == '[')) { 10729 /* element name */ 10730 #ifdef DEBUG_STEP 10731 xmlGenericError(xmlGenericErrorContext, 10732 "PathExpr: AbbrRelLocation\n"); 10733 #endif 10734 lc = 1; 10735 break; 10736 } else if ((NXT(len) == '<') || (NXT(len) == '>') || 10737 (NXT(len) == '=')) { 10738 lc = 1; 10739 break; 10740 } else { 10741 lc = 1; 10742 break; 10743 } 10744 len++; 10745 } 10746 if (NXT(len) == 0) { 10747 #ifdef DEBUG_STEP 10748 xmlGenericError(xmlGenericErrorContext, 10749 "PathExpr: AbbrRelLocation\n"); 10750 #endif 10751 /* element name */ 10752 lc = 1; 10753 } 10754 xmlFree(name); 10755 } else { 10756 /* make sure all cases are covered explicitly */ 10757 XP_ERROR(XPATH_EXPR_ERROR); 10758 } 10759 } 10760 10761 if (lc) { 10762 if (CUR == '/') { 10763 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0); 10764 } else { 10765 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0); 10766 } 10767 xmlXPathCompLocationPath(ctxt); 10768 } else { 10769 xmlXPathCompFilterExpr(ctxt); 10770 CHECK_ERROR; 10771 if ((CUR == '/') && (NXT(1) == '/')) { 10772 SKIP(2); 10773 SKIP_BLANKS; 10774 10775 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 10776 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 10777 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0); 10778 10779 xmlXPathCompRelativeLocationPath(ctxt); 10780 } else if (CUR == '/') { 10781 xmlXPathCompRelativeLocationPath(ctxt); 10782 } 10783 } 10784 SKIP_BLANKS; 10785 } 10786 10787 /** 10788 * xmlXPathCompUnionExpr: 10789 * @ctxt: the XPath Parser context 10790 * 10791 * [18] UnionExpr ::= PathExpr 10792 * | UnionExpr '|' PathExpr 10793 * 10794 * Compile an union expression. 10795 */ 10796 10797 static void 10798 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) { 10799 xmlXPathCompPathExpr(ctxt); 10800 CHECK_ERROR; 10801 SKIP_BLANKS; 10802 while (CUR == '|') { 10803 int op1 = ctxt->comp->last; 10804 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0); 10805 10806 NEXT; 10807 SKIP_BLANKS; 10808 xmlXPathCompPathExpr(ctxt); 10809 10810 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0); 10811 10812 SKIP_BLANKS; 10813 } 10814 } 10815 10816 /** 10817 * xmlXPathCompUnaryExpr: 10818 * @ctxt: the XPath Parser context 10819 * 10820 * [27] UnaryExpr ::= UnionExpr 10821 * | '-' UnaryExpr 10822 * 10823 * Compile an unary expression. 10824 */ 10825 10826 static void 10827 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) { 10828 int minus = 0; 10829 int found = 0; 10830 10831 SKIP_BLANKS; 10832 while (CUR == '-') { 10833 minus = 1 - minus; 10834 found = 1; 10835 NEXT; 10836 SKIP_BLANKS; 10837 } 10838 10839 xmlXPathCompUnionExpr(ctxt); 10840 CHECK_ERROR; 10841 if (found) { 10842 if (minus) 10843 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0); 10844 else 10845 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0); 10846 } 10847 } 10848 10849 /** 10850 * xmlXPathCompMultiplicativeExpr: 10851 * @ctxt: the XPath Parser context 10852 * 10853 * [26] MultiplicativeExpr ::= UnaryExpr 10854 * | MultiplicativeExpr MultiplyOperator UnaryExpr 10855 * | MultiplicativeExpr 'div' UnaryExpr 10856 * | MultiplicativeExpr 'mod' UnaryExpr 10857 * [34] MultiplyOperator ::= '*' 10858 * 10859 * Compile an Additive expression. 10860 */ 10861 10862 static void 10863 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) { 10864 xmlXPathCompUnaryExpr(ctxt); 10865 CHECK_ERROR; 10866 SKIP_BLANKS; 10867 while ((CUR == '*') || 10868 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) || 10869 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) { 10870 int op = -1; 10871 int op1 = ctxt->comp->last; 10872 10873 if (CUR == '*') { 10874 op = 0; 10875 NEXT; 10876 } else if (CUR == 'd') { 10877 op = 1; 10878 SKIP(3); 10879 } else if (CUR == 'm') { 10880 op = 2; 10881 SKIP(3); 10882 } 10883 SKIP_BLANKS; 10884 xmlXPathCompUnaryExpr(ctxt); 10885 CHECK_ERROR; 10886 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0); 10887 SKIP_BLANKS; 10888 } 10889 } 10890 10891 /** 10892 * xmlXPathCompAdditiveExpr: 10893 * @ctxt: the XPath Parser context 10894 * 10895 * [25] AdditiveExpr ::= MultiplicativeExpr 10896 * | AdditiveExpr '+' MultiplicativeExpr 10897 * | AdditiveExpr '-' MultiplicativeExpr 10898 * 10899 * Compile an Additive expression. 10900 */ 10901 10902 static void 10903 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) { 10904 10905 xmlXPathCompMultiplicativeExpr(ctxt); 10906 CHECK_ERROR; 10907 SKIP_BLANKS; 10908 while ((CUR == '+') || (CUR == '-')) { 10909 int plus; 10910 int op1 = ctxt->comp->last; 10911 10912 if (CUR == '+') plus = 1; 10913 else plus = 0; 10914 NEXT; 10915 SKIP_BLANKS; 10916 xmlXPathCompMultiplicativeExpr(ctxt); 10917 CHECK_ERROR; 10918 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0); 10919 SKIP_BLANKS; 10920 } 10921 } 10922 10923 /** 10924 * xmlXPathCompRelationalExpr: 10925 * @ctxt: the XPath Parser context 10926 * 10927 * [24] RelationalExpr ::= AdditiveExpr 10928 * | RelationalExpr '<' AdditiveExpr 10929 * | RelationalExpr '>' AdditiveExpr 10930 * | RelationalExpr '<=' AdditiveExpr 10931 * | RelationalExpr '>=' AdditiveExpr 10932 * 10933 * A <= B > C is allowed ? Answer from James, yes with 10934 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr 10935 * which is basically what got implemented. 10936 * 10937 * Compile a Relational expression, then push the result 10938 * on the stack 10939 */ 10940 10941 static void 10942 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) { 10943 xmlXPathCompAdditiveExpr(ctxt); 10944 CHECK_ERROR; 10945 SKIP_BLANKS; 10946 while ((CUR == '<') || 10947 (CUR == '>') || 10948 ((CUR == '<') && (NXT(1) == '=')) || 10949 ((CUR == '>') && (NXT(1) == '='))) { 10950 int inf, strict; 10951 int op1 = ctxt->comp->last; 10952 10953 if (CUR == '<') inf = 1; 10954 else inf = 0; 10955 if (NXT(1) == '=') strict = 0; 10956 else strict = 1; 10957 NEXT; 10958 if (!strict) NEXT; 10959 SKIP_BLANKS; 10960 xmlXPathCompAdditiveExpr(ctxt); 10961 CHECK_ERROR; 10962 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict); 10963 SKIP_BLANKS; 10964 } 10965 } 10966 10967 /** 10968 * xmlXPathCompEqualityExpr: 10969 * @ctxt: the XPath Parser context 10970 * 10971 * [23] EqualityExpr ::= RelationalExpr 10972 * | EqualityExpr '=' RelationalExpr 10973 * | EqualityExpr '!=' RelationalExpr 10974 * 10975 * A != B != C is allowed ? Answer from James, yes with 10976 * (RelationalExpr = RelationalExpr) = RelationalExpr 10977 * (RelationalExpr != RelationalExpr) != RelationalExpr 10978 * which is basically what got implemented. 10979 * 10980 * Compile an Equality expression. 10981 * 10982 */ 10983 static void 10984 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) { 10985 xmlXPathCompRelationalExpr(ctxt); 10986 CHECK_ERROR; 10987 SKIP_BLANKS; 10988 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) { 10989 int eq; 10990 int op1 = ctxt->comp->last; 10991 10992 if (CUR == '=') eq = 1; 10993 else eq = 0; 10994 NEXT; 10995 if (!eq) NEXT; 10996 SKIP_BLANKS; 10997 xmlXPathCompRelationalExpr(ctxt); 10998 CHECK_ERROR; 10999 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0); 11000 SKIP_BLANKS; 11001 } 11002 } 11003 11004 /** 11005 * xmlXPathCompAndExpr: 11006 * @ctxt: the XPath Parser context 11007 * 11008 * [22] AndExpr ::= EqualityExpr 11009 * | AndExpr 'and' EqualityExpr 11010 * 11011 * Compile an AND expression. 11012 * 11013 */ 11014 static void 11015 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) { 11016 xmlXPathCompEqualityExpr(ctxt); 11017 CHECK_ERROR; 11018 SKIP_BLANKS; 11019 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) { 11020 int op1 = ctxt->comp->last; 11021 SKIP(3); 11022 SKIP_BLANKS; 11023 xmlXPathCompEqualityExpr(ctxt); 11024 CHECK_ERROR; 11025 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0); 11026 SKIP_BLANKS; 11027 } 11028 } 11029 11030 /** 11031 * xmlXPathCompileExpr: 11032 * @ctxt: the XPath Parser context 11033 * 11034 * [14] Expr ::= OrExpr 11035 * [21] OrExpr ::= AndExpr 11036 * | OrExpr 'or' AndExpr 11037 * 11038 * Parse and compile an expression 11039 */ 11040 static void 11041 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) { 11042 xmlXPathCompAndExpr(ctxt); 11043 CHECK_ERROR; 11044 SKIP_BLANKS; 11045 while ((CUR == 'o') && (NXT(1) == 'r')) { 11046 int op1 = ctxt->comp->last; 11047 SKIP(2); 11048 SKIP_BLANKS; 11049 xmlXPathCompAndExpr(ctxt); 11050 CHECK_ERROR; 11051 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0); 11052 SKIP_BLANKS; 11053 } 11054 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) { 11055 /* more ops could be optimized too */ 11056 /* 11057 * This is the main place to eliminate sorting for 11058 * operations which don't require a sorted node-set. 11059 * E.g. count(). 11060 */ 11061 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0); 11062 } 11063 } 11064 11065 /** 11066 * xmlXPathCompPredicate: 11067 * @ctxt: the XPath Parser context 11068 * @filter: act as a filter 11069 * 11070 * [8] Predicate ::= '[' PredicateExpr ']' 11071 * [9] PredicateExpr ::= Expr 11072 * 11073 * Compile a predicate expression 11074 */ 11075 static void 11076 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) { 11077 int op1 = ctxt->comp->last; 11078 11079 SKIP_BLANKS; 11080 if (CUR != '[') { 11081 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); 11082 } 11083 NEXT; 11084 SKIP_BLANKS; 11085 11086 ctxt->comp->last = -1; 11087 /* 11088 * This call to xmlXPathCompileExpr() will deactivate sorting 11089 * of the predicate result. 11090 * TODO: Sorting is still activated for filters, since I'm not 11091 * sure if needed. Normally sorting should not be needed, since 11092 * a filter can only diminish the number of items in a sequence, 11093 * but won't change its order; so if the initial sequence is sorted, 11094 * subsequent sorting is not needed. 11095 */ 11096 if (! filter) 11097 xmlXPathCompileExpr(ctxt, 0); 11098 else 11099 xmlXPathCompileExpr(ctxt, 1); 11100 CHECK_ERROR; 11101 11102 if (CUR != ']') { 11103 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); 11104 } 11105 11106 if (filter) 11107 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0); 11108 else 11109 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0); 11110 11111 NEXT; 11112 SKIP_BLANKS; 11113 } 11114 11115 /** 11116 * xmlXPathCompNodeTest: 11117 * @ctxt: the XPath Parser context 11118 * @test: pointer to a xmlXPathTestVal 11119 * @type: pointer to a xmlXPathTypeVal 11120 * @prefix: placeholder for a possible name prefix 11121 * 11122 * [7] NodeTest ::= NameTest 11123 * | NodeType '(' ')' 11124 * | 'processing-instruction' '(' Literal ')' 11125 * 11126 * [37] NameTest ::= '*' 11127 * | NCName ':' '*' 11128 * | QName 11129 * [38] NodeType ::= 'comment' 11130 * | 'text' 11131 * | 'processing-instruction' 11132 * | 'node' 11133 * 11134 * Returns the name found and updates @test, @type and @prefix appropriately 11135 */ 11136 static xmlChar * 11137 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test, 11138 xmlXPathTypeVal *type, const xmlChar **prefix, 11139 xmlChar *name) { 11140 int blanks; 11141 11142 if ((test == NULL) || (type == NULL) || (prefix == NULL)) { 11143 STRANGE; 11144 return(NULL); 11145 } 11146 *type = (xmlXPathTypeVal) 0; 11147 *test = (xmlXPathTestVal) 0; 11148 *prefix = NULL; 11149 SKIP_BLANKS; 11150 11151 if ((name == NULL) && (CUR == '*')) { 11152 /* 11153 * All elements 11154 */ 11155 NEXT; 11156 *test = NODE_TEST_ALL; 11157 return(NULL); 11158 } 11159 11160 if (name == NULL) 11161 name = xmlXPathParseNCName(ctxt); 11162 if (name == NULL) { 11163 XP_ERRORNULL(XPATH_EXPR_ERROR); 11164 } 11165 11166 blanks = IS_BLANK_CH(CUR); 11167 SKIP_BLANKS; 11168 if (CUR == '(') { 11169 NEXT; 11170 /* 11171 * NodeType or PI search 11172 */ 11173 if (xmlStrEqual(name, BAD_CAST "comment")) 11174 *type = NODE_TYPE_COMMENT; 11175 else if (xmlStrEqual(name, BAD_CAST "node")) 11176 *type = NODE_TYPE_NODE; 11177 else if (xmlStrEqual(name, BAD_CAST "processing-instruction")) 11178 *type = NODE_TYPE_PI; 11179 else if (xmlStrEqual(name, BAD_CAST "text")) 11180 *type = NODE_TYPE_TEXT; 11181 else { 11182 if (name != NULL) 11183 xmlFree(name); 11184 XP_ERRORNULL(XPATH_EXPR_ERROR); 11185 } 11186 11187 *test = NODE_TEST_TYPE; 11188 11189 SKIP_BLANKS; 11190 if (*type == NODE_TYPE_PI) { 11191 /* 11192 * Specific case: search a PI by name. 11193 */ 11194 if (name != NULL) 11195 xmlFree(name); 11196 name = NULL; 11197 if (CUR != ')') { 11198 name = xmlXPathParseLiteral(ctxt); 11199 CHECK_ERROR NULL; 11200 *test = NODE_TEST_PI; 11201 SKIP_BLANKS; 11202 } 11203 } 11204 if (CUR != ')') { 11205 if (name != NULL) 11206 xmlFree(name); 11207 XP_ERRORNULL(XPATH_UNCLOSED_ERROR); 11208 } 11209 NEXT; 11210 return(name); 11211 } 11212 *test = NODE_TEST_NAME; 11213 if ((!blanks) && (CUR == ':')) { 11214 NEXT; 11215 11216 /* 11217 * Since currently the parser context don't have a 11218 * namespace list associated: 11219 * The namespace name for this prefix can be computed 11220 * only at evaluation time. The compilation is done 11221 * outside of any context. 11222 */ 11223 #if 0 11224 *prefix = xmlXPathNsLookup(ctxt->context, name); 11225 if (name != NULL) 11226 xmlFree(name); 11227 if (*prefix == NULL) { 11228 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); 11229 } 11230 #else 11231 *prefix = name; 11232 #endif 11233 11234 if (CUR == '*') { 11235 /* 11236 * All elements 11237 */ 11238 NEXT; 11239 *test = NODE_TEST_ALL; 11240 return(NULL); 11241 } 11242 11243 name = xmlXPathParseNCName(ctxt); 11244 if (name == NULL) { 11245 XP_ERRORNULL(XPATH_EXPR_ERROR); 11246 } 11247 } 11248 return(name); 11249 } 11250 11251 /** 11252 * xmlXPathIsAxisName: 11253 * @name: a preparsed name token 11254 * 11255 * [6] AxisName ::= 'ancestor' 11256 * | 'ancestor-or-self' 11257 * | 'attribute' 11258 * | 'child' 11259 * | 'descendant' 11260 * | 'descendant-or-self' 11261 * | 'following' 11262 * | 'following-sibling' 11263 * | 'namespace' 11264 * | 'parent' 11265 * | 'preceding' 11266 * | 'preceding-sibling' 11267 * | 'self' 11268 * 11269 * Returns the axis or 0 11270 */ 11271 static xmlXPathAxisVal 11272 xmlXPathIsAxisName(const xmlChar *name) { 11273 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0; 11274 switch (name[0]) { 11275 case 'a': 11276 if (xmlStrEqual(name, BAD_CAST "ancestor")) 11277 ret = AXIS_ANCESTOR; 11278 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self")) 11279 ret = AXIS_ANCESTOR_OR_SELF; 11280 if (xmlStrEqual(name, BAD_CAST "attribute")) 11281 ret = AXIS_ATTRIBUTE; 11282 break; 11283 case 'c': 11284 if (xmlStrEqual(name, BAD_CAST "child")) 11285 ret = AXIS_CHILD; 11286 break; 11287 case 'd': 11288 if (xmlStrEqual(name, BAD_CAST "descendant")) 11289 ret = AXIS_DESCENDANT; 11290 if (xmlStrEqual(name, BAD_CAST "descendant-or-self")) 11291 ret = AXIS_DESCENDANT_OR_SELF; 11292 break; 11293 case 'f': 11294 if (xmlStrEqual(name, BAD_CAST "following")) 11295 ret = AXIS_FOLLOWING; 11296 if (xmlStrEqual(name, BAD_CAST "following-sibling")) 11297 ret = AXIS_FOLLOWING_SIBLING; 11298 break; 11299 case 'n': 11300 if (xmlStrEqual(name, BAD_CAST "namespace")) 11301 ret = AXIS_NAMESPACE; 11302 break; 11303 case 'p': 11304 if (xmlStrEqual(name, BAD_CAST "parent")) 11305 ret = AXIS_PARENT; 11306 if (xmlStrEqual(name, BAD_CAST "preceding")) 11307 ret = AXIS_PRECEDING; 11308 if (xmlStrEqual(name, BAD_CAST "preceding-sibling")) 11309 ret = AXIS_PRECEDING_SIBLING; 11310 break; 11311 case 's': 11312 if (xmlStrEqual(name, BAD_CAST "self")) 11313 ret = AXIS_SELF; 11314 break; 11315 } 11316 return(ret); 11317 } 11318 11319 /** 11320 * xmlXPathCompStep: 11321 * @ctxt: the XPath Parser context 11322 * 11323 * [4] Step ::= AxisSpecifier NodeTest Predicate* 11324 * | AbbreviatedStep 11325 * 11326 * [12] AbbreviatedStep ::= '.' | '..' 11327 * 11328 * [5] AxisSpecifier ::= AxisName '::' 11329 * | AbbreviatedAxisSpecifier 11330 * 11331 * [13] AbbreviatedAxisSpecifier ::= '@'? 11332 * 11333 * Modified for XPtr range support as: 11334 * 11335 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate* 11336 * | AbbreviatedStep 11337 * | 'range-to' '(' Expr ')' Predicate* 11338 * 11339 * Compile one step in a Location Path 11340 * A location step of . is short for self::node(). This is 11341 * particularly useful in conjunction with //. For example, the 11342 * location path .//para is short for 11343 * self::node()/descendant-or-self::node()/child::para 11344 * and so will select all para descendant elements of the context 11345 * node. 11346 * Similarly, a location step of .. is short for parent::node(). 11347 * For example, ../title is short for parent::node()/child::title 11348 * and so will select the title children of the parent of the context 11349 * node. 11350 */ 11351 static void 11352 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) { 11353 #ifdef LIBXML_XPTR_ENABLED 11354 int rangeto = 0; 11355 int op2 = -1; 11356 #endif 11357 11358 SKIP_BLANKS; 11359 if ((CUR == '.') && (NXT(1) == '.')) { 11360 SKIP(2); 11361 SKIP_BLANKS; 11362 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT, 11363 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11364 } else if (CUR == '.') { 11365 NEXT; 11366 SKIP_BLANKS; 11367 } else { 11368 xmlChar *name = NULL; 11369 const xmlChar *prefix = NULL; 11370 xmlXPathTestVal test = (xmlXPathTestVal) 0; 11371 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0; 11372 xmlXPathTypeVal type = (xmlXPathTypeVal) 0; 11373 int op1; 11374 11375 /* 11376 * The modification needed for XPointer change to the production 11377 */ 11378 #ifdef LIBXML_XPTR_ENABLED 11379 if (ctxt->xptr) { 11380 name = xmlXPathParseNCName(ctxt); 11381 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) { 11382 op2 = ctxt->comp->last; 11383 xmlFree(name); 11384 SKIP_BLANKS; 11385 if (CUR != '(') { 11386 XP_ERROR(XPATH_EXPR_ERROR); 11387 } 11388 NEXT; 11389 SKIP_BLANKS; 11390 11391 xmlXPathCompileExpr(ctxt, 1); 11392 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */ 11393 CHECK_ERROR; 11394 11395 SKIP_BLANKS; 11396 if (CUR != ')') { 11397 XP_ERROR(XPATH_EXPR_ERROR); 11398 } 11399 NEXT; 11400 rangeto = 1; 11401 goto eval_predicates; 11402 } 11403 } 11404 #endif 11405 if (CUR == '*') { 11406 axis = AXIS_CHILD; 11407 } else { 11408 if (name == NULL) 11409 name = xmlXPathParseNCName(ctxt); 11410 if (name != NULL) { 11411 axis = xmlXPathIsAxisName(name); 11412 if (axis != 0) { 11413 SKIP_BLANKS; 11414 if ((CUR == ':') && (NXT(1) == ':')) { 11415 SKIP(2); 11416 xmlFree(name); 11417 name = NULL; 11418 } else { 11419 /* an element name can conflict with an axis one :-\ */ 11420 axis = AXIS_CHILD; 11421 } 11422 } else { 11423 axis = AXIS_CHILD; 11424 } 11425 } else if (CUR == '@') { 11426 NEXT; 11427 axis = AXIS_ATTRIBUTE; 11428 } else { 11429 axis = AXIS_CHILD; 11430 } 11431 } 11432 11433 if (ctxt->error != XPATH_EXPRESSION_OK) { 11434 xmlFree(name); 11435 return; 11436 } 11437 11438 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name); 11439 if (test == 0) 11440 return; 11441 11442 if ((prefix != NULL) && (ctxt->context != NULL) && 11443 (ctxt->context->flags & XML_XPATH_CHECKNS)) { 11444 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) { 11445 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR); 11446 } 11447 } 11448 #ifdef DEBUG_STEP 11449 xmlGenericError(xmlGenericErrorContext, 11450 "Basis : computing new set\n"); 11451 #endif 11452 11453 #ifdef DEBUG_STEP 11454 xmlGenericError(xmlGenericErrorContext, "Basis : "); 11455 if (ctxt->value == NULL) 11456 xmlGenericError(xmlGenericErrorContext, "no value\n"); 11457 else if (ctxt->value->nodesetval == NULL) 11458 xmlGenericError(xmlGenericErrorContext, "Empty\n"); 11459 else 11460 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval); 11461 #endif 11462 11463 #ifdef LIBXML_XPTR_ENABLED 11464 eval_predicates: 11465 #endif 11466 op1 = ctxt->comp->last; 11467 ctxt->comp->last = -1; 11468 11469 SKIP_BLANKS; 11470 while (CUR == '[') { 11471 xmlXPathCompPredicate(ctxt, 0); 11472 } 11473 11474 #ifdef LIBXML_XPTR_ENABLED 11475 if (rangeto) { 11476 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0); 11477 } else 11478 #endif 11479 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis, 11480 test, type, (void *)prefix, (void *)name); 11481 11482 } 11483 #ifdef DEBUG_STEP 11484 xmlGenericError(xmlGenericErrorContext, "Step : "); 11485 if (ctxt->value == NULL) 11486 xmlGenericError(xmlGenericErrorContext, "no value\n"); 11487 else if (ctxt->value->nodesetval == NULL) 11488 xmlGenericError(xmlGenericErrorContext, "Empty\n"); 11489 else 11490 xmlGenericErrorContextNodeSet(xmlGenericErrorContext, 11491 ctxt->value->nodesetval); 11492 #endif 11493 } 11494 11495 /** 11496 * xmlXPathCompRelativeLocationPath: 11497 * @ctxt: the XPath Parser context 11498 * 11499 * [3] RelativeLocationPath ::= Step 11500 * | RelativeLocationPath '/' Step 11501 * | AbbreviatedRelativeLocationPath 11502 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step 11503 * 11504 * Compile a relative location path. 11505 */ 11506 static void 11507 xmlXPathCompRelativeLocationPath 11508 (xmlXPathParserContextPtr ctxt) { 11509 SKIP_BLANKS; 11510 if ((CUR == '/') && (NXT(1) == '/')) { 11511 SKIP(2); 11512 SKIP_BLANKS; 11513 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 11514 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11515 } else if (CUR == '/') { 11516 NEXT; 11517 SKIP_BLANKS; 11518 } 11519 xmlXPathCompStep(ctxt); 11520 CHECK_ERROR; 11521 SKIP_BLANKS; 11522 while (CUR == '/') { 11523 if ((CUR == '/') && (NXT(1) == '/')) { 11524 SKIP(2); 11525 SKIP_BLANKS; 11526 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 11527 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11528 xmlXPathCompStep(ctxt); 11529 } else if (CUR == '/') { 11530 NEXT; 11531 SKIP_BLANKS; 11532 xmlXPathCompStep(ctxt); 11533 } 11534 SKIP_BLANKS; 11535 } 11536 } 11537 11538 /** 11539 * xmlXPathCompLocationPath: 11540 * @ctxt: the XPath Parser context 11541 * 11542 * [1] LocationPath ::= RelativeLocationPath 11543 * | AbsoluteLocationPath 11544 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath? 11545 * | AbbreviatedAbsoluteLocationPath 11546 * [10] AbbreviatedAbsoluteLocationPath ::= 11547 * '//' RelativeLocationPath 11548 * 11549 * Compile a location path 11550 * 11551 * // is short for /descendant-or-self::node()/. For example, 11552 * //para is short for /descendant-or-self::node()/child::para and 11553 * so will select any para element in the document (even a para element 11554 * that is a document element will be selected by //para since the 11555 * document element node is a child of the root node); div//para is 11556 * short for div/descendant-or-self::node()/child::para and so will 11557 * select all para descendants of div children. 11558 */ 11559 static void 11560 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) { 11561 SKIP_BLANKS; 11562 if (CUR != '/') { 11563 xmlXPathCompRelativeLocationPath(ctxt); 11564 } else { 11565 while (CUR == '/') { 11566 if ((CUR == '/') && (NXT(1) == '/')) { 11567 SKIP(2); 11568 SKIP_BLANKS; 11569 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 11570 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11571 xmlXPathCompRelativeLocationPath(ctxt); 11572 } else if (CUR == '/') { 11573 NEXT; 11574 SKIP_BLANKS; 11575 if ((CUR != 0 ) && 11576 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') || 11577 (CUR == '@') || (CUR == '*'))) 11578 xmlXPathCompRelativeLocationPath(ctxt); 11579 } 11580 CHECK_ERROR; 11581 } 11582 } 11583 } 11584 11585 /************************************************************************ 11586 * * 11587 * XPath precompiled expression evaluation * 11588 * * 11589 ************************************************************************/ 11590 11591 static int 11592 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op); 11593 11594 #ifdef DEBUG_STEP 11595 static void 11596 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op, 11597 int nbNodes) 11598 { 11599 xmlGenericError(xmlGenericErrorContext, "new step : "); 11600 switch (op->value) { 11601 case AXIS_ANCESTOR: 11602 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' "); 11603 break; 11604 case AXIS_ANCESTOR_OR_SELF: 11605 xmlGenericError(xmlGenericErrorContext, 11606 "axis 'ancestors-or-self' "); 11607 break; 11608 case AXIS_ATTRIBUTE: 11609 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' "); 11610 break; 11611 case AXIS_CHILD: 11612 xmlGenericError(xmlGenericErrorContext, "axis 'child' "); 11613 break; 11614 case AXIS_DESCENDANT: 11615 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' "); 11616 break; 11617 case AXIS_DESCENDANT_OR_SELF: 11618 xmlGenericError(xmlGenericErrorContext, 11619 "axis 'descendant-or-self' "); 11620 break; 11621 case AXIS_FOLLOWING: 11622 xmlGenericError(xmlGenericErrorContext, "axis 'following' "); 11623 break; 11624 case AXIS_FOLLOWING_SIBLING: 11625 xmlGenericError(xmlGenericErrorContext, 11626 "axis 'following-siblings' "); 11627 break; 11628 case AXIS_NAMESPACE: 11629 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' "); 11630 break; 11631 case AXIS_PARENT: 11632 xmlGenericError(xmlGenericErrorContext, "axis 'parent' "); 11633 break; 11634 case AXIS_PRECEDING: 11635 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' "); 11636 break; 11637 case AXIS_PRECEDING_SIBLING: 11638 xmlGenericError(xmlGenericErrorContext, 11639 "axis 'preceding-sibling' "); 11640 break; 11641 case AXIS_SELF: 11642 xmlGenericError(xmlGenericErrorContext, "axis 'self' "); 11643 break; 11644 } 11645 xmlGenericError(xmlGenericErrorContext, 11646 " context contains %d nodes\n", nbNodes); 11647 switch (op->value2) { 11648 case NODE_TEST_NONE: 11649 xmlGenericError(xmlGenericErrorContext, 11650 " searching for none !!!\n"); 11651 break; 11652 case NODE_TEST_TYPE: 11653 xmlGenericError(xmlGenericErrorContext, 11654 " searching for type %d\n", op->value3); 11655 break; 11656 case NODE_TEST_PI: 11657 xmlGenericError(xmlGenericErrorContext, 11658 " searching for PI !!!\n"); 11659 break; 11660 case NODE_TEST_ALL: 11661 xmlGenericError(xmlGenericErrorContext, 11662 " searching for *\n"); 11663 break; 11664 case NODE_TEST_NS: 11665 xmlGenericError(xmlGenericErrorContext, 11666 " searching for namespace %s\n", 11667 op->value5); 11668 break; 11669 case NODE_TEST_NAME: 11670 xmlGenericError(xmlGenericErrorContext, 11671 " searching for name %s\n", op->value5); 11672 if (op->value4) 11673 xmlGenericError(xmlGenericErrorContext, 11674 " with namespace %s\n", op->value4); 11675 break; 11676 } 11677 xmlGenericError(xmlGenericErrorContext, "Testing : "); 11678 } 11679 #endif /* DEBUG_STEP */ 11680 11681 static int 11682 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt, 11683 xmlXPathStepOpPtr op, 11684 xmlNodeSetPtr set, 11685 int contextSize, 11686 int hasNsNodes) 11687 { 11688 if (op->ch1 != -1) { 11689 xmlXPathCompExprPtr comp = ctxt->comp; 11690 /* 11691 * Process inner predicates first. 11692 */ 11693 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) { 11694 /* 11695 * TODO: raise an internal error. 11696 */ 11697 } 11698 contextSize = xmlXPathCompOpEvalPredicate(ctxt, 11699 &comp->steps[op->ch1], set, contextSize, hasNsNodes); 11700 CHECK_ERROR0; 11701 if (contextSize <= 0) 11702 return(0); 11703 } 11704 if (op->ch2 != -1) { 11705 xmlXPathContextPtr xpctxt = ctxt->context; 11706 xmlNodePtr contextNode, oldContextNode; 11707 xmlDocPtr oldContextDoc; 11708 int i, res, contextPos = 0, newContextSize; 11709 xmlXPathStepOpPtr exprOp; 11710 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL; 11711 11712 #ifdef LIBXML_XPTR_ENABLED 11713 /* 11714 * URGENT TODO: Check the following: 11715 * We don't expect location sets if evaluating prediates, right? 11716 * Only filters should expect location sets, right? 11717 */ 11718 #endif 11719 /* 11720 * SPEC XPath 1.0: 11721 * "For each node in the node-set to be filtered, the 11722 * PredicateExpr is evaluated with that node as the 11723 * context node, with the number of nodes in the 11724 * node-set as the context size, and with the proximity 11725 * position of the node in the node-set with respect to 11726 * the axis as the context position;" 11727 * @oldset is the node-set" to be filtered. 11728 * 11729 * SPEC XPath 1.0: 11730 * "only predicates change the context position and 11731 * context size (see [2.4 Predicates])." 11732 * Example: 11733 * node-set context pos 11734 * nA 1 11735 * nB 2 11736 * nC 3 11737 * After applying predicate [position() > 1] : 11738 * node-set context pos 11739 * nB 1 11740 * nC 2 11741 */ 11742 oldContextNode = xpctxt->node; 11743 oldContextDoc = xpctxt->doc; 11744 /* 11745 * Get the expression of this predicate. 11746 */ 11747 exprOp = &ctxt->comp->steps[op->ch2]; 11748 newContextSize = 0; 11749 for (i = 0; i < set->nodeNr; i++) { 11750 if (set->nodeTab[i] == NULL) 11751 continue; 11752 11753 contextNode = set->nodeTab[i]; 11754 xpctxt->node = contextNode; 11755 xpctxt->contextSize = contextSize; 11756 xpctxt->proximityPosition = ++contextPos; 11757 11758 /* 11759 * Also set the xpath document in case things like 11760 * key() are evaluated in the predicate. 11761 */ 11762 if ((contextNode->type != XML_NAMESPACE_DECL) && 11763 (contextNode->doc != NULL)) 11764 xpctxt->doc = contextNode->doc; 11765 /* 11766 * Evaluate the predicate expression with 1 context node 11767 * at a time; this node is packaged into a node set; this 11768 * node set is handed over to the evaluation mechanism. 11769 */ 11770 if (contextObj == NULL) 11771 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode); 11772 else { 11773 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval, 11774 contextNode) < 0) { 11775 ctxt->error = XPATH_MEMORY_ERROR; 11776 goto evaluation_exit; 11777 } 11778 } 11779 11780 valuePush(ctxt, contextObj); 11781 11782 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1); 11783 11784 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) { 11785 xmlXPathNodeSetClear(set, hasNsNodes); 11786 newContextSize = 0; 11787 goto evaluation_exit; 11788 } 11789 11790 if (res != 0) { 11791 newContextSize++; 11792 } else { 11793 /* 11794 * Remove the entry from the initial node set. 11795 */ 11796 set->nodeTab[i] = NULL; 11797 if (contextNode->type == XML_NAMESPACE_DECL) 11798 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode); 11799 } 11800 if (ctxt->value == contextObj) { 11801 /* 11802 * Don't free the temporary XPath object holding the 11803 * context node, in order to avoid massive recreation 11804 * inside this loop. 11805 */ 11806 valuePop(ctxt); 11807 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes); 11808 } else { 11809 /* 11810 * TODO: The object was lost in the evaluation machinery. 11811 * Can this happen? Maybe in internal-error cases. 11812 */ 11813 contextObj = NULL; 11814 } 11815 } 11816 11817 if (contextObj != NULL) { 11818 if (ctxt->value == contextObj) 11819 valuePop(ctxt); 11820 xmlXPathReleaseObject(xpctxt, contextObj); 11821 } 11822 evaluation_exit: 11823 if (exprRes != NULL) 11824 xmlXPathReleaseObject(ctxt->context, exprRes); 11825 /* 11826 * Reset/invalidate the context. 11827 */ 11828 xpctxt->node = oldContextNode; 11829 xpctxt->doc = oldContextDoc; 11830 xpctxt->contextSize = -1; 11831 xpctxt->proximityPosition = -1; 11832 return(newContextSize); 11833 } 11834 return(contextSize); 11835 } 11836 11837 static int 11838 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt, 11839 xmlXPathStepOpPtr op, 11840 xmlNodeSetPtr set, 11841 int contextSize, 11842 int minPos, 11843 int maxPos, 11844 int hasNsNodes) 11845 { 11846 if (op->ch1 != -1) { 11847 xmlXPathCompExprPtr comp = ctxt->comp; 11848 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) { 11849 /* 11850 * TODO: raise an internal error. 11851 */ 11852 } 11853 contextSize = xmlXPathCompOpEvalPredicate(ctxt, 11854 &comp->steps[op->ch1], set, contextSize, hasNsNodes); 11855 CHECK_ERROR0; 11856 if (contextSize <= 0) 11857 return(0); 11858 } 11859 /* 11860 * Check if the node set contains a sufficient number of nodes for 11861 * the requested range. 11862 */ 11863 if (contextSize < minPos) { 11864 xmlXPathNodeSetClear(set, hasNsNodes); 11865 return(0); 11866 } 11867 if (op->ch2 == -1) { 11868 /* 11869 * TODO: Can this ever happen? 11870 */ 11871 return (contextSize); 11872 } else { 11873 xmlDocPtr oldContextDoc; 11874 int i, pos = 0, newContextSize = 0, contextPos = 0, res; 11875 xmlXPathStepOpPtr exprOp; 11876 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL; 11877 xmlNodePtr oldContextNode, contextNode = NULL; 11878 xmlXPathContextPtr xpctxt = ctxt->context; 11879 int frame; 11880 11881 #ifdef LIBXML_XPTR_ENABLED 11882 /* 11883 * URGENT TODO: Check the following: 11884 * We don't expect location sets if evaluating prediates, right? 11885 * Only filters should expect location sets, right? 11886 */ 11887 #endif /* LIBXML_XPTR_ENABLED */ 11888 11889 /* 11890 * Save old context. 11891 */ 11892 oldContextNode = xpctxt->node; 11893 oldContextDoc = xpctxt->doc; 11894 /* 11895 * Get the expression of this predicate. 11896 */ 11897 exprOp = &ctxt->comp->steps[op->ch2]; 11898 for (i = 0; i < set->nodeNr; i++) { 11899 xmlXPathObjectPtr tmp; 11900 11901 if (set->nodeTab[i] == NULL) 11902 continue; 11903 11904 contextNode = set->nodeTab[i]; 11905 xpctxt->node = contextNode; 11906 xpctxt->contextSize = contextSize; 11907 xpctxt->proximityPosition = ++contextPos; 11908 11909 /* 11910 * Initialize the new set. 11911 * Also set the xpath document in case things like 11912 * key() evaluation are attempted on the predicate 11913 */ 11914 if ((contextNode->type != XML_NAMESPACE_DECL) && 11915 (contextNode->doc != NULL)) 11916 xpctxt->doc = contextNode->doc; 11917 /* 11918 * Evaluate the predicate expression with 1 context node 11919 * at a time; this node is packaged into a node set; this 11920 * node set is handed over to the evaluation mechanism. 11921 */ 11922 if (contextObj == NULL) 11923 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode); 11924 else { 11925 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval, 11926 contextNode) < 0) { 11927 ctxt->error = XPATH_MEMORY_ERROR; 11928 goto evaluation_exit; 11929 } 11930 } 11931 11932 valuePush(ctxt, contextObj); 11933 frame = xmlXPathSetFrame(ctxt); 11934 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1); 11935 xmlXPathPopFrame(ctxt, frame); 11936 tmp = valuePop(ctxt); 11937 11938 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) { 11939 while (tmp != contextObj) { 11940 /* 11941 * Free up the result 11942 * then pop off contextObj, which will be freed later 11943 */ 11944 xmlXPathReleaseObject(xpctxt, tmp); 11945 tmp = valuePop(ctxt); 11946 } 11947 goto evaluation_error; 11948 } 11949 /* push the result back onto the stack */ 11950 valuePush(ctxt, tmp); 11951 11952 if (res) 11953 pos++; 11954 11955 if (res && (pos >= minPos) && (pos <= maxPos)) { 11956 /* 11957 * Fits in the requested range. 11958 */ 11959 newContextSize++; 11960 if (minPos == maxPos) { 11961 /* 11962 * Only 1 node was requested. 11963 */ 11964 if (contextNode->type == XML_NAMESPACE_DECL) { 11965 /* 11966 * As always: take care of those nasty 11967 * namespace nodes. 11968 */ 11969 set->nodeTab[i] = NULL; 11970 } 11971 xmlXPathNodeSetClear(set, hasNsNodes); 11972 set->nodeNr = 1; 11973 set->nodeTab[0] = contextNode; 11974 goto evaluation_exit; 11975 } 11976 if (pos == maxPos) { 11977 /* 11978 * We are done. 11979 */ 11980 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes); 11981 goto evaluation_exit; 11982 } 11983 } else { 11984 /* 11985 * Remove the entry from the initial node set. 11986 */ 11987 set->nodeTab[i] = NULL; 11988 if (contextNode->type == XML_NAMESPACE_DECL) 11989 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode); 11990 } 11991 if (exprRes != NULL) { 11992 xmlXPathReleaseObject(ctxt->context, exprRes); 11993 exprRes = NULL; 11994 } 11995 if (ctxt->value == contextObj) { 11996 /* 11997 * Don't free the temporary XPath object holding the 11998 * context node, in order to avoid massive recreation 11999 * inside this loop. 12000 */ 12001 valuePop(ctxt); 12002 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes); 12003 } else { 12004 /* 12005 * The object was lost in the evaluation machinery. 12006 * Can this happen? Maybe in case of internal-errors. 12007 */ 12008 contextObj = NULL; 12009 } 12010 } 12011 goto evaluation_exit; 12012 12013 evaluation_error: 12014 xmlXPathNodeSetClear(set, hasNsNodes); 12015 newContextSize = 0; 12016 12017 evaluation_exit: 12018 if (contextObj != NULL) { 12019 if (ctxt->value == contextObj) 12020 valuePop(ctxt); 12021 xmlXPathReleaseObject(xpctxt, contextObj); 12022 } 12023 if (exprRes != NULL) 12024 xmlXPathReleaseObject(ctxt->context, exprRes); 12025 /* 12026 * Reset/invalidate the context. 12027 */ 12028 xpctxt->node = oldContextNode; 12029 xpctxt->doc = oldContextDoc; 12030 xpctxt->contextSize = -1; 12031 xpctxt->proximityPosition = -1; 12032 return(newContextSize); 12033 } 12034 return(contextSize); 12035 } 12036 12037 static int 12038 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt, 12039 xmlXPathStepOpPtr op, 12040 int *maxPos) 12041 { 12042 12043 xmlXPathStepOpPtr exprOp; 12044 12045 /* 12046 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet! 12047 */ 12048 12049 /* 12050 * If not -1, then ch1 will point to: 12051 * 1) For predicates (XPATH_OP_PREDICATE): 12052 * - an inner predicate operator 12053 * 2) For filters (XPATH_OP_FILTER): 12054 * - an inner filter operater OR 12055 * - an expression selecting the node set. 12056 * E.g. "key('a', 'b')" or "(//foo | //bar)". 12057 */ 12058 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER)) 12059 return(0); 12060 12061 if (op->ch2 != -1) { 12062 exprOp = &ctxt->comp->steps[op->ch2]; 12063 } else 12064 return(0); 12065 12066 if ((exprOp != NULL) && 12067 (exprOp->op == XPATH_OP_VALUE) && 12068 (exprOp->value4 != NULL) && 12069 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER)) 12070 { 12071 double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval; 12072 12073 /* 12074 * We have a "[n]" predicate here. 12075 * TODO: Unfortunately this simplistic test here is not 12076 * able to detect a position() predicate in compound 12077 * expressions like "[@attr = 'a" and position() = 1], 12078 * and even not the usage of position() in 12079 * "[position() = 1]"; thus - obviously - a position-range, 12080 * like it "[position() < 5]", is also not detected. 12081 * Maybe we could rewrite the AST to ease the optimization. 12082 */ 12083 12084 if ((floatval > INT_MIN) && (floatval < INT_MAX)) { 12085 *maxPos = (int) floatval; 12086 if (floatval == (double) *maxPos) 12087 return(1); 12088 } 12089 } 12090 return(0); 12091 } 12092 12093 static int 12094 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, 12095 xmlXPathStepOpPtr op, 12096 xmlNodePtr * first, xmlNodePtr * last, 12097 int toBool) 12098 { 12099 12100 #define XP_TEST_HIT \ 12101 if (hasAxisRange != 0) { \ 12102 if (++pos == maxPos) { \ 12103 if (addNode(seq, cur) < 0) \ 12104 ctxt->error = XPATH_MEMORY_ERROR; \ 12105 goto axis_range_end; } \ 12106 } else { \ 12107 if (addNode(seq, cur) < 0) \ 12108 ctxt->error = XPATH_MEMORY_ERROR; \ 12109 if (breakOnFirstHit) goto first_hit; } 12110 12111 #define XP_TEST_HIT_NS \ 12112 if (hasAxisRange != 0) { \ 12113 if (++pos == maxPos) { \ 12114 hasNsNodes = 1; \ 12115 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \ 12116 ctxt->error = XPATH_MEMORY_ERROR; \ 12117 goto axis_range_end; } \ 12118 } else { \ 12119 hasNsNodes = 1; \ 12120 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \ 12121 ctxt->error = XPATH_MEMORY_ERROR; \ 12122 if (breakOnFirstHit) goto first_hit; } 12123 12124 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value; 12125 xmlXPathTestVal test = (xmlXPathTestVal) op->value2; 12126 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3; 12127 const xmlChar *prefix = op->value4; 12128 const xmlChar *name = op->value5; 12129 const xmlChar *URI = NULL; 12130 12131 #ifdef DEBUG_STEP 12132 int nbMatches = 0, prevMatches = 0; 12133 #endif 12134 int total = 0, hasNsNodes = 0; 12135 /* The popped object holding the context nodes */ 12136 xmlXPathObjectPtr obj; 12137 /* The set of context nodes for the node tests */ 12138 xmlNodeSetPtr contextSeq; 12139 int contextIdx; 12140 xmlNodePtr contextNode; 12141 /* The final resulting node set wrt to all context nodes */ 12142 xmlNodeSetPtr outSeq; 12143 /* 12144 * The temporary resulting node set wrt 1 context node. 12145 * Used to feed predicate evaluation. 12146 */ 12147 xmlNodeSetPtr seq; 12148 xmlNodePtr cur; 12149 /* First predicate operator */ 12150 xmlXPathStepOpPtr predOp; 12151 int maxPos; /* The requested position() (when a "[n]" predicate) */ 12152 int hasPredicateRange, hasAxisRange, pos, size, newSize; 12153 int breakOnFirstHit; 12154 12155 xmlXPathTraversalFunction next = NULL; 12156 int (*addNode) (xmlNodeSetPtr, xmlNodePtr); 12157 xmlXPathNodeSetMergeFunction mergeAndClear; 12158 xmlNodePtr oldContextNode; 12159 xmlXPathContextPtr xpctxt = ctxt->context; 12160 12161 12162 CHECK_TYPE0(XPATH_NODESET); 12163 obj = valuePop(ctxt); 12164 /* 12165 * Setup namespaces. 12166 */ 12167 if (prefix != NULL) { 12168 URI = xmlXPathNsLookup(xpctxt, prefix); 12169 if (URI == NULL) { 12170 xmlXPathReleaseObject(xpctxt, obj); 12171 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); 12172 } 12173 } 12174 /* 12175 * Setup axis. 12176 * 12177 * MAYBE FUTURE TODO: merging optimizations: 12178 * - If the nodes to be traversed wrt to the initial nodes and 12179 * the current axis cannot overlap, then we could avoid searching 12180 * for duplicates during the merge. 12181 * But the question is how/when to evaluate if they cannot overlap. 12182 * Example: if we know that for two initial nodes, the one is 12183 * not in the ancestor-or-self axis of the other, then we could safely 12184 * avoid a duplicate-aware merge, if the axis to be traversed is e.g. 12185 * the descendant-or-self axis. 12186 */ 12187 mergeAndClear = xmlXPathNodeSetMergeAndClear; 12188 switch (axis) { 12189 case AXIS_ANCESTOR: 12190 first = NULL; 12191 next = xmlXPathNextAncestor; 12192 break; 12193 case AXIS_ANCESTOR_OR_SELF: 12194 first = NULL; 12195 next = xmlXPathNextAncestorOrSelf; 12196 break; 12197 case AXIS_ATTRIBUTE: 12198 first = NULL; 12199 last = NULL; 12200 next = xmlXPathNextAttribute; 12201 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12202 break; 12203 case AXIS_CHILD: 12204 last = NULL; 12205 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) && 12206 (type == NODE_TYPE_NODE)) 12207 { 12208 /* 12209 * Optimization if an element node type is 'element'. 12210 */ 12211 next = xmlXPathNextChildElement; 12212 } else 12213 next = xmlXPathNextChild; 12214 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12215 break; 12216 case AXIS_DESCENDANT: 12217 last = NULL; 12218 next = xmlXPathNextDescendant; 12219 break; 12220 case AXIS_DESCENDANT_OR_SELF: 12221 last = NULL; 12222 next = xmlXPathNextDescendantOrSelf; 12223 break; 12224 case AXIS_FOLLOWING: 12225 last = NULL; 12226 next = xmlXPathNextFollowing; 12227 break; 12228 case AXIS_FOLLOWING_SIBLING: 12229 last = NULL; 12230 next = xmlXPathNextFollowingSibling; 12231 break; 12232 case AXIS_NAMESPACE: 12233 first = NULL; 12234 last = NULL; 12235 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; 12236 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12237 break; 12238 case AXIS_PARENT: 12239 first = NULL; 12240 next = xmlXPathNextParent; 12241 break; 12242 case AXIS_PRECEDING: 12243 first = NULL; 12244 next = xmlXPathNextPrecedingInternal; 12245 break; 12246 case AXIS_PRECEDING_SIBLING: 12247 first = NULL; 12248 next = xmlXPathNextPrecedingSibling; 12249 break; 12250 case AXIS_SELF: 12251 first = NULL; 12252 last = NULL; 12253 next = xmlXPathNextSelf; 12254 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12255 break; 12256 } 12257 12258 #ifdef DEBUG_STEP 12259 xmlXPathDebugDumpStepAxis(op, 12260 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0); 12261 #endif 12262 12263 if (next == NULL) { 12264 xmlXPathReleaseObject(xpctxt, obj); 12265 return(0); 12266 } 12267 contextSeq = obj->nodesetval; 12268 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) { 12269 xmlXPathReleaseObject(xpctxt, obj); 12270 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL)); 12271 return(0); 12272 } 12273 /* 12274 * Predicate optimization --------------------------------------------- 12275 * If this step has a last predicate, which contains a position(), 12276 * then we'll optimize (although not exactly "position()", but only 12277 * the short-hand form, i.e., "[n]". 12278 * 12279 * Example - expression "/foo[parent::bar][1]": 12280 * 12281 * COLLECT 'child' 'name' 'node' foo -- op (we are here) 12282 * ROOT -- op->ch1 12283 * PREDICATE -- op->ch2 (predOp) 12284 * PREDICATE -- predOp->ch1 = [parent::bar] 12285 * SORT 12286 * COLLECT 'parent' 'name' 'node' bar 12287 * NODE 12288 * ELEM Object is a number : 1 -- predOp->ch2 = [1] 12289 * 12290 */ 12291 maxPos = 0; 12292 predOp = NULL; 12293 hasPredicateRange = 0; 12294 hasAxisRange = 0; 12295 if (op->ch2 != -1) { 12296 /* 12297 * There's at least one predicate. 16 == XPATH_OP_PREDICATE 12298 */ 12299 predOp = &ctxt->comp->steps[op->ch2]; 12300 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) { 12301 if (predOp->ch1 != -1) { 12302 /* 12303 * Use the next inner predicate operator. 12304 */ 12305 predOp = &ctxt->comp->steps[predOp->ch1]; 12306 hasPredicateRange = 1; 12307 } else { 12308 /* 12309 * There's no other predicate than the [n] predicate. 12310 */ 12311 predOp = NULL; 12312 hasAxisRange = 1; 12313 } 12314 } 12315 } 12316 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0; 12317 /* 12318 * Axis traversal ----------------------------------------------------- 12319 */ 12320 /* 12321 * 2.3 Node Tests 12322 * - For the attribute axis, the principal node type is attribute. 12323 * - For the namespace axis, the principal node type is namespace. 12324 * - For other axes, the principal node type is element. 12325 * 12326 * A node test * is true for any node of the 12327 * principal node type. For example, child::* will 12328 * select all element children of the context node 12329 */ 12330 oldContextNode = xpctxt->node; 12331 addNode = xmlXPathNodeSetAddUnique; 12332 outSeq = NULL; 12333 seq = NULL; 12334 contextNode = NULL; 12335 contextIdx = 0; 12336 12337 12338 while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) && 12339 (ctxt->error == XPATH_EXPRESSION_OK)) { 12340 xpctxt->node = contextSeq->nodeTab[contextIdx++]; 12341 12342 if (seq == NULL) { 12343 seq = xmlXPathNodeSetCreate(NULL); 12344 if (seq == NULL) { 12345 total = 0; 12346 goto error; 12347 } 12348 } 12349 /* 12350 * Traverse the axis and test the nodes. 12351 */ 12352 pos = 0; 12353 cur = NULL; 12354 hasNsNodes = 0; 12355 do { 12356 cur = next(ctxt, cur); 12357 if (cur == NULL) 12358 break; 12359 12360 /* 12361 * QUESTION TODO: What does the "first" and "last" stuff do? 12362 */ 12363 if ((first != NULL) && (*first != NULL)) { 12364 if (*first == cur) 12365 break; 12366 if (((total % 256) == 0) && 12367 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 12368 (xmlXPathCmpNodesExt(*first, cur) >= 0)) 12369 #else 12370 (xmlXPathCmpNodes(*first, cur) >= 0)) 12371 #endif 12372 { 12373 break; 12374 } 12375 } 12376 if ((last != NULL) && (*last != NULL)) { 12377 if (*last == cur) 12378 break; 12379 if (((total % 256) == 0) && 12380 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 12381 (xmlXPathCmpNodesExt(cur, *last) >= 0)) 12382 #else 12383 (xmlXPathCmpNodes(cur, *last) >= 0)) 12384 #endif 12385 { 12386 break; 12387 } 12388 } 12389 12390 total++; 12391 12392 #ifdef DEBUG_STEP 12393 xmlGenericError(xmlGenericErrorContext, " %s", cur->name); 12394 #endif 12395 12396 switch (test) { 12397 case NODE_TEST_NONE: 12398 total = 0; 12399 STRANGE 12400 goto error; 12401 case NODE_TEST_TYPE: 12402 if (type == NODE_TYPE_NODE) { 12403 switch (cur->type) { 12404 case XML_DOCUMENT_NODE: 12405 case XML_HTML_DOCUMENT_NODE: 12406 #ifdef LIBXML_DOCB_ENABLED 12407 case XML_DOCB_DOCUMENT_NODE: 12408 #endif 12409 case XML_ELEMENT_NODE: 12410 case XML_ATTRIBUTE_NODE: 12411 case XML_PI_NODE: 12412 case XML_COMMENT_NODE: 12413 case XML_CDATA_SECTION_NODE: 12414 case XML_TEXT_NODE: 12415 XP_TEST_HIT 12416 break; 12417 case XML_NAMESPACE_DECL: { 12418 if (axis == AXIS_NAMESPACE) { 12419 XP_TEST_HIT_NS 12420 } else { 12421 hasNsNodes = 1; 12422 XP_TEST_HIT 12423 } 12424 break; 12425 } 12426 default: 12427 break; 12428 } 12429 } else if (cur->type == type) { 12430 if (cur->type == XML_NAMESPACE_DECL) 12431 XP_TEST_HIT_NS 12432 else 12433 XP_TEST_HIT 12434 } else if ((type == NODE_TYPE_TEXT) && 12435 (cur->type == XML_CDATA_SECTION_NODE)) 12436 { 12437 XP_TEST_HIT 12438 } 12439 break; 12440 case NODE_TEST_PI: 12441 if ((cur->type == XML_PI_NODE) && 12442 ((name == NULL) || xmlStrEqual(name, cur->name))) 12443 { 12444 XP_TEST_HIT 12445 } 12446 break; 12447 case NODE_TEST_ALL: 12448 if (axis == AXIS_ATTRIBUTE) { 12449 if (cur->type == XML_ATTRIBUTE_NODE) 12450 { 12451 if (prefix == NULL) 12452 { 12453 XP_TEST_HIT 12454 } else if ((cur->ns != NULL) && 12455 (xmlStrEqual(URI, cur->ns->href))) 12456 { 12457 XP_TEST_HIT 12458 } 12459 } 12460 } else if (axis == AXIS_NAMESPACE) { 12461 if (cur->type == XML_NAMESPACE_DECL) 12462 { 12463 XP_TEST_HIT_NS 12464 } 12465 } else { 12466 if (cur->type == XML_ELEMENT_NODE) { 12467 if (prefix == NULL) 12468 { 12469 XP_TEST_HIT 12470 12471 } else if ((cur->ns != NULL) && 12472 (xmlStrEqual(URI, cur->ns->href))) 12473 { 12474 XP_TEST_HIT 12475 } 12476 } 12477 } 12478 break; 12479 case NODE_TEST_NS:{ 12480 TODO; 12481 break; 12482 } 12483 case NODE_TEST_NAME: 12484 if (axis == AXIS_ATTRIBUTE) { 12485 if (cur->type != XML_ATTRIBUTE_NODE) 12486 break; 12487 } else if (axis == AXIS_NAMESPACE) { 12488 if (cur->type != XML_NAMESPACE_DECL) 12489 break; 12490 } else { 12491 if (cur->type != XML_ELEMENT_NODE) 12492 break; 12493 } 12494 switch (cur->type) { 12495 case XML_ELEMENT_NODE: 12496 if (xmlStrEqual(name, cur->name)) { 12497 if (prefix == NULL) { 12498 if (cur->ns == NULL) 12499 { 12500 XP_TEST_HIT 12501 } 12502 } else { 12503 if ((cur->ns != NULL) && 12504 (xmlStrEqual(URI, cur->ns->href))) 12505 { 12506 XP_TEST_HIT 12507 } 12508 } 12509 } 12510 break; 12511 case XML_ATTRIBUTE_NODE:{ 12512 xmlAttrPtr attr = (xmlAttrPtr) cur; 12513 12514 if (xmlStrEqual(name, attr->name)) { 12515 if (prefix == NULL) { 12516 if ((attr->ns == NULL) || 12517 (attr->ns->prefix == NULL)) 12518 { 12519 XP_TEST_HIT 12520 } 12521 } else { 12522 if ((attr->ns != NULL) && 12523 (xmlStrEqual(URI, 12524 attr->ns->href))) 12525 { 12526 XP_TEST_HIT 12527 } 12528 } 12529 } 12530 break; 12531 } 12532 case XML_NAMESPACE_DECL: 12533 if (cur->type == XML_NAMESPACE_DECL) { 12534 xmlNsPtr ns = (xmlNsPtr) cur; 12535 12536 if ((ns->prefix != NULL) && (name != NULL) 12537 && (xmlStrEqual(ns->prefix, name))) 12538 { 12539 XP_TEST_HIT_NS 12540 } 12541 } 12542 break; 12543 default: 12544 break; 12545 } 12546 break; 12547 } /* switch(test) */ 12548 } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK)); 12549 12550 goto apply_predicates; 12551 12552 axis_range_end: /* ----------------------------------------------------- */ 12553 /* 12554 * We have a "/foo[n]", and position() = n was reached. 12555 * Note that we can have as well "/foo/::parent::foo[1]", so 12556 * a duplicate-aware merge is still needed. 12557 * Merge with the result. 12558 */ 12559 if (outSeq == NULL) { 12560 outSeq = seq; 12561 seq = NULL; 12562 } else 12563 outSeq = mergeAndClear(outSeq, seq, 0); 12564 /* 12565 * Break if only a true/false result was requested. 12566 */ 12567 if (toBool) 12568 break; 12569 continue; 12570 12571 first_hit: /* ---------------------------------------------------------- */ 12572 /* 12573 * Break if only a true/false result was requested and 12574 * no predicates existed and a node test succeeded. 12575 */ 12576 if (outSeq == NULL) { 12577 outSeq = seq; 12578 seq = NULL; 12579 } else 12580 outSeq = mergeAndClear(outSeq, seq, 0); 12581 break; 12582 12583 #ifdef DEBUG_STEP 12584 if (seq != NULL) 12585 nbMatches += seq->nodeNr; 12586 #endif 12587 12588 apply_predicates: /* --------------------------------------------------- */ 12589 if (ctxt->error != XPATH_EXPRESSION_OK) 12590 goto error; 12591 12592 /* 12593 * Apply predicates. 12594 */ 12595 if ((predOp != NULL) && (seq->nodeNr > 0)) { 12596 /* 12597 * E.g. when we have a "/foo[some expression][n]". 12598 */ 12599 /* 12600 * QUESTION TODO: The old predicate evaluation took into 12601 * account location-sets. 12602 * (E.g. ctxt->value->type == XPATH_LOCATIONSET) 12603 * Do we expect such a set here? 12604 * All what I learned now from the evaluation semantics 12605 * does not indicate that a location-set will be processed 12606 * here, so this looks OK. 12607 */ 12608 /* 12609 * Iterate over all predicates, starting with the outermost 12610 * predicate. 12611 * TODO: Problem: we cannot execute the inner predicates first 12612 * since we cannot go back *up* the operator tree! 12613 * Options we have: 12614 * 1) Use of recursive functions (like is it currently done 12615 * via xmlXPathCompOpEval()) 12616 * 2) Add a predicate evaluation information stack to the 12617 * context struct 12618 * 3) Change the way the operators are linked; we need a 12619 * "parent" field on xmlXPathStepOp 12620 * 12621 * For the moment, I'll try to solve this with a recursive 12622 * function: xmlXPathCompOpEvalPredicate(). 12623 */ 12624 size = seq->nodeNr; 12625 if (hasPredicateRange != 0) 12626 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt, 12627 predOp, seq, size, maxPos, maxPos, hasNsNodes); 12628 else 12629 newSize = xmlXPathCompOpEvalPredicate(ctxt, 12630 predOp, seq, size, hasNsNodes); 12631 12632 if (ctxt->error != XPATH_EXPRESSION_OK) { 12633 total = 0; 12634 goto error; 12635 } 12636 /* 12637 * Add the filtered set of nodes to the result node set. 12638 */ 12639 if (newSize == 0) { 12640 /* 12641 * The predicates filtered all nodes out. 12642 */ 12643 xmlXPathNodeSetClear(seq, hasNsNodes); 12644 } else if (seq->nodeNr > 0) { 12645 /* 12646 * Add to result set. 12647 */ 12648 if (outSeq == NULL) { 12649 if (size != newSize) { 12650 /* 12651 * We need to merge and clear here, since 12652 * the sequence will contained NULLed entries. 12653 */ 12654 outSeq = mergeAndClear(NULL, seq, 1); 12655 } else { 12656 outSeq = seq; 12657 seq = NULL; 12658 } 12659 } else 12660 outSeq = mergeAndClear(outSeq, seq, 12661 (size != newSize) ? 1: 0); 12662 /* 12663 * Break if only a true/false result was requested. 12664 */ 12665 if (toBool) 12666 break; 12667 } 12668 } else if (seq->nodeNr > 0) { 12669 /* 12670 * Add to result set. 12671 */ 12672 if (outSeq == NULL) { 12673 outSeq = seq; 12674 seq = NULL; 12675 } else { 12676 outSeq = mergeAndClear(outSeq, seq, 0); 12677 } 12678 } 12679 } 12680 12681 error: 12682 if ((obj->boolval) && (obj->user != NULL)) { 12683 /* 12684 * QUESTION TODO: What does this do and why? 12685 * TODO: Do we have to do this also for the "error" 12686 * cleanup further down? 12687 */ 12688 ctxt->value->boolval = 1; 12689 ctxt->value->user = obj->user; 12690 obj->user = NULL; 12691 obj->boolval = 0; 12692 } 12693 xmlXPathReleaseObject(xpctxt, obj); 12694 12695 /* 12696 * Ensure we return at least an emtpy set. 12697 */ 12698 if (outSeq == NULL) { 12699 if ((seq != NULL) && (seq->nodeNr == 0)) 12700 outSeq = seq; 12701 else 12702 outSeq = xmlXPathNodeSetCreate(NULL); 12703 /* XXX what if xmlXPathNodeSetCreate returned NULL here? */ 12704 } 12705 if ((seq != NULL) && (seq != outSeq)) { 12706 xmlXPathFreeNodeSet(seq); 12707 } 12708 /* 12709 * Hand over the result. Better to push the set also in 12710 * case of errors. 12711 */ 12712 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq)); 12713 /* 12714 * Reset the context node. 12715 */ 12716 xpctxt->node = oldContextNode; 12717 /* 12718 * When traversing the namespace axis in "toBool" mode, it's 12719 * possible that tmpNsList wasn't freed. 12720 */ 12721 if (xpctxt->tmpNsList != NULL) { 12722 xmlFree(xpctxt->tmpNsList); 12723 xpctxt->tmpNsList = NULL; 12724 } 12725 12726 #ifdef DEBUG_STEP 12727 xmlGenericError(xmlGenericErrorContext, 12728 "\nExamined %d nodes, found %d nodes at that step\n", 12729 total, nbMatches); 12730 #endif 12731 12732 return(total); 12733 } 12734 12735 static int 12736 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt, 12737 xmlXPathStepOpPtr op, xmlNodePtr * first); 12738 12739 /** 12740 * xmlXPathCompOpEvalFirst: 12741 * @ctxt: the XPath parser context with the compiled expression 12742 * @op: an XPath compiled operation 12743 * @first: the first elem found so far 12744 * 12745 * Evaluate the Precompiled XPath operation searching only the first 12746 * element in document order 12747 * 12748 * Returns the number of examined objects. 12749 */ 12750 static int 12751 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt, 12752 xmlXPathStepOpPtr op, xmlNodePtr * first) 12753 { 12754 int total = 0, cur; 12755 xmlXPathCompExprPtr comp; 12756 xmlXPathObjectPtr arg1, arg2; 12757 12758 CHECK_ERROR0; 12759 comp = ctxt->comp; 12760 switch (op->op) { 12761 case XPATH_OP_END: 12762 return (0); 12763 case XPATH_OP_UNION: 12764 total = 12765 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1], 12766 first); 12767 CHECK_ERROR0; 12768 if ((ctxt->value != NULL) 12769 && (ctxt->value->type == XPATH_NODESET) 12770 && (ctxt->value->nodesetval != NULL) 12771 && (ctxt->value->nodesetval->nodeNr >= 1)) { 12772 /* 12773 * limit tree traversing to first node in the result 12774 */ 12775 /* 12776 * OPTIMIZE TODO: This implicitely sorts 12777 * the result, even if not needed. E.g. if the argument 12778 * of the count() function, no sorting is needed. 12779 * OPTIMIZE TODO: How do we know if the node-list wasn't 12780 * aready sorted? 12781 */ 12782 if (ctxt->value->nodesetval->nodeNr > 1) 12783 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12784 *first = ctxt->value->nodesetval->nodeTab[0]; 12785 } 12786 cur = 12787 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2], 12788 first); 12789 CHECK_ERROR0; 12790 12791 arg2 = valuePop(ctxt); 12792 arg1 = valuePop(ctxt); 12793 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) || 12794 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) { 12795 xmlXPathReleaseObject(ctxt->context, arg1); 12796 xmlXPathReleaseObject(ctxt->context, arg2); 12797 XP_ERROR0(XPATH_INVALID_TYPE); 12798 } 12799 12800 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 12801 arg2->nodesetval); 12802 valuePush(ctxt, arg1); 12803 xmlXPathReleaseObject(ctxt->context, arg2); 12804 /* optimizer */ 12805 if (total > cur) 12806 xmlXPathCompSwap(op); 12807 return (total + cur); 12808 case XPATH_OP_ROOT: 12809 xmlXPathRoot(ctxt); 12810 return (0); 12811 case XPATH_OP_NODE: 12812 if (op->ch1 != -1) 12813 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12814 CHECK_ERROR0; 12815 if (op->ch2 != -1) 12816 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12817 CHECK_ERROR0; 12818 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 12819 ctxt->context->node)); 12820 return (total); 12821 case XPATH_OP_RESET: 12822 if (op->ch1 != -1) 12823 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12824 CHECK_ERROR0; 12825 if (op->ch2 != -1) 12826 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12827 CHECK_ERROR0; 12828 ctxt->context->node = NULL; 12829 return (total); 12830 case XPATH_OP_COLLECT:{ 12831 if (op->ch1 == -1) 12832 return (total); 12833 12834 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12835 CHECK_ERROR0; 12836 12837 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0); 12838 return (total); 12839 } 12840 case XPATH_OP_VALUE: 12841 valuePush(ctxt, 12842 xmlXPathCacheObjectCopy(ctxt->context, 12843 (xmlXPathObjectPtr) op->value4)); 12844 return (0); 12845 case XPATH_OP_SORT: 12846 if (op->ch1 != -1) 12847 total += 12848 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1], 12849 first); 12850 CHECK_ERROR0; 12851 if ((ctxt->value != NULL) 12852 && (ctxt->value->type == XPATH_NODESET) 12853 && (ctxt->value->nodesetval != NULL) 12854 && (ctxt->value->nodesetval->nodeNr > 1)) 12855 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12856 return (total); 12857 #ifdef XP_OPTIMIZED_FILTER_FIRST 12858 case XPATH_OP_FILTER: 12859 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first); 12860 return (total); 12861 #endif 12862 default: 12863 return (xmlXPathCompOpEval(ctxt, op)); 12864 } 12865 } 12866 12867 /** 12868 * xmlXPathCompOpEvalLast: 12869 * @ctxt: the XPath parser context with the compiled expression 12870 * @op: an XPath compiled operation 12871 * @last: the last elem found so far 12872 * 12873 * Evaluate the Precompiled XPath operation searching only the last 12874 * element in document order 12875 * 12876 * Returns the number of nodes traversed 12877 */ 12878 static int 12879 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op, 12880 xmlNodePtr * last) 12881 { 12882 int total = 0, cur; 12883 xmlXPathCompExprPtr comp; 12884 xmlXPathObjectPtr arg1, arg2; 12885 xmlNodePtr bak; 12886 xmlDocPtr bakd; 12887 int pp; 12888 int cs; 12889 12890 CHECK_ERROR0; 12891 comp = ctxt->comp; 12892 switch (op->op) { 12893 case XPATH_OP_END: 12894 return (0); 12895 case XPATH_OP_UNION: 12896 bakd = ctxt->context->doc; 12897 bak = ctxt->context->node; 12898 pp = ctxt->context->proximityPosition; 12899 cs = ctxt->context->contextSize; 12900 total = 12901 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last); 12902 CHECK_ERROR0; 12903 if ((ctxt->value != NULL) 12904 && (ctxt->value->type == XPATH_NODESET) 12905 && (ctxt->value->nodesetval != NULL) 12906 && (ctxt->value->nodesetval->nodeNr >= 1)) { 12907 /* 12908 * limit tree traversing to first node in the result 12909 */ 12910 if (ctxt->value->nodesetval->nodeNr > 1) 12911 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12912 *last = 12913 ctxt->value->nodesetval->nodeTab[ctxt->value-> 12914 nodesetval->nodeNr - 12915 1]; 12916 } 12917 ctxt->context->doc = bakd; 12918 ctxt->context->node = bak; 12919 ctxt->context->proximityPosition = pp; 12920 ctxt->context->contextSize = cs; 12921 cur = 12922 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last); 12923 CHECK_ERROR0; 12924 if ((ctxt->value != NULL) 12925 && (ctxt->value->type == XPATH_NODESET) 12926 && (ctxt->value->nodesetval != NULL) 12927 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */ 12928 } 12929 12930 arg2 = valuePop(ctxt); 12931 arg1 = valuePop(ctxt); 12932 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) || 12933 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) { 12934 xmlXPathReleaseObject(ctxt->context, arg1); 12935 xmlXPathReleaseObject(ctxt->context, arg2); 12936 XP_ERROR0(XPATH_INVALID_TYPE); 12937 } 12938 12939 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 12940 arg2->nodesetval); 12941 valuePush(ctxt, arg1); 12942 xmlXPathReleaseObject(ctxt->context, arg2); 12943 /* optimizer */ 12944 if (total > cur) 12945 xmlXPathCompSwap(op); 12946 return (total + cur); 12947 case XPATH_OP_ROOT: 12948 xmlXPathRoot(ctxt); 12949 return (0); 12950 case XPATH_OP_NODE: 12951 if (op->ch1 != -1) 12952 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12953 CHECK_ERROR0; 12954 if (op->ch2 != -1) 12955 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12956 CHECK_ERROR0; 12957 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 12958 ctxt->context->node)); 12959 return (total); 12960 case XPATH_OP_RESET: 12961 if (op->ch1 != -1) 12962 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12963 CHECK_ERROR0; 12964 if (op->ch2 != -1) 12965 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12966 CHECK_ERROR0; 12967 ctxt->context->node = NULL; 12968 return (total); 12969 case XPATH_OP_COLLECT:{ 12970 if (op->ch1 == -1) 12971 return (0); 12972 12973 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12974 CHECK_ERROR0; 12975 12976 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0); 12977 return (total); 12978 } 12979 case XPATH_OP_VALUE: 12980 valuePush(ctxt, 12981 xmlXPathCacheObjectCopy(ctxt->context, 12982 (xmlXPathObjectPtr) op->value4)); 12983 return (0); 12984 case XPATH_OP_SORT: 12985 if (op->ch1 != -1) 12986 total += 12987 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], 12988 last); 12989 CHECK_ERROR0; 12990 if ((ctxt->value != NULL) 12991 && (ctxt->value->type == XPATH_NODESET) 12992 && (ctxt->value->nodesetval != NULL) 12993 && (ctxt->value->nodesetval->nodeNr > 1)) 12994 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12995 return (total); 12996 default: 12997 return (xmlXPathCompOpEval(ctxt, op)); 12998 } 12999 } 13000 13001 #ifdef XP_OPTIMIZED_FILTER_FIRST 13002 static int 13003 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt, 13004 xmlXPathStepOpPtr op, xmlNodePtr * first) 13005 { 13006 int total = 0; 13007 xmlXPathCompExprPtr comp; 13008 xmlXPathObjectPtr res; 13009 xmlXPathObjectPtr obj; 13010 xmlNodeSetPtr oldset; 13011 xmlNodePtr oldnode; 13012 xmlDocPtr oldDoc; 13013 int i; 13014 13015 CHECK_ERROR0; 13016 comp = ctxt->comp; 13017 /* 13018 * Optimization for ()[last()] selection i.e. the last elem 13019 */ 13020 if ((op->ch1 != -1) && (op->ch2 != -1) && 13021 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 13022 (comp->steps[op->ch2].op == XPATH_OP_SORT)) { 13023 int f = comp->steps[op->ch2].ch1; 13024 13025 if ((f != -1) && 13026 (comp->steps[f].op == XPATH_OP_FUNCTION) && 13027 (comp->steps[f].value5 == NULL) && 13028 (comp->steps[f].value == 0) && 13029 (comp->steps[f].value4 != NULL) && 13030 (xmlStrEqual 13031 (comp->steps[f].value4, BAD_CAST "last"))) { 13032 xmlNodePtr last = NULL; 13033 13034 total += 13035 xmlXPathCompOpEvalLast(ctxt, 13036 &comp->steps[op->ch1], 13037 &last); 13038 CHECK_ERROR0; 13039 /* 13040 * The nodeset should be in document order, 13041 * Keep only the last value 13042 */ 13043 if ((ctxt->value != NULL) && 13044 (ctxt->value->type == XPATH_NODESET) && 13045 (ctxt->value->nodesetval != NULL) && 13046 (ctxt->value->nodesetval->nodeTab != NULL) && 13047 (ctxt->value->nodesetval->nodeNr > 1)) { 13048 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval); 13049 *first = *(ctxt->value->nodesetval->nodeTab); 13050 } 13051 return (total); 13052 } 13053 } 13054 13055 if (op->ch1 != -1) 13056 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13057 CHECK_ERROR0; 13058 if (op->ch2 == -1) 13059 return (total); 13060 if (ctxt->value == NULL) 13061 return (total); 13062 13063 #ifdef LIBXML_XPTR_ENABLED 13064 oldnode = ctxt->context->node; 13065 /* 13066 * Hum are we filtering the result of an XPointer expression 13067 */ 13068 if (ctxt->value->type == XPATH_LOCATIONSET) { 13069 xmlXPathObjectPtr tmp = NULL; 13070 xmlLocationSetPtr newlocset = NULL; 13071 xmlLocationSetPtr oldlocset; 13072 13073 /* 13074 * Extract the old locset, and then evaluate the result of the 13075 * expression for all the element in the locset. use it to grow 13076 * up a new locset. 13077 */ 13078 CHECK_TYPE0(XPATH_LOCATIONSET); 13079 obj = valuePop(ctxt); 13080 oldlocset = obj->user; 13081 ctxt->context->node = NULL; 13082 13083 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) { 13084 ctxt->context->contextSize = 0; 13085 ctxt->context->proximityPosition = 0; 13086 if (op->ch2 != -1) 13087 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13088 res = valuePop(ctxt); 13089 if (res != NULL) { 13090 xmlXPathReleaseObject(ctxt->context, res); 13091 } 13092 valuePush(ctxt, obj); 13093 CHECK_ERROR0; 13094 return (total); 13095 } 13096 newlocset = xmlXPtrLocationSetCreate(NULL); 13097 13098 for (i = 0; i < oldlocset->locNr; i++) { 13099 /* 13100 * Run the evaluation with a node list made of a 13101 * single item in the nodelocset. 13102 */ 13103 ctxt->context->node = oldlocset->locTab[i]->user; 13104 ctxt->context->contextSize = oldlocset->locNr; 13105 ctxt->context->proximityPosition = i + 1; 13106 if (tmp == NULL) { 13107 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13108 ctxt->context->node); 13109 } else { 13110 if (xmlXPathNodeSetAddUnique(tmp->nodesetval, 13111 ctxt->context->node) < 0) { 13112 ctxt->error = XPATH_MEMORY_ERROR; 13113 } 13114 } 13115 valuePush(ctxt, tmp); 13116 if (op->ch2 != -1) 13117 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13118 if (ctxt->error != XPATH_EXPRESSION_OK) { 13119 xmlXPathFreeObject(obj); 13120 return(0); 13121 } 13122 /* 13123 * The result of the evaluation need to be tested to 13124 * decided whether the filter succeeded or not 13125 */ 13126 res = valuePop(ctxt); 13127 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 13128 xmlXPtrLocationSetAdd(newlocset, 13129 xmlXPathCacheObjectCopy(ctxt->context, 13130 oldlocset->locTab[i])); 13131 } 13132 /* 13133 * Cleanup 13134 */ 13135 if (res != NULL) { 13136 xmlXPathReleaseObject(ctxt->context, res); 13137 } 13138 if (ctxt->value == tmp) { 13139 valuePop(ctxt); 13140 xmlXPathNodeSetClear(tmp->nodesetval, 1); 13141 /* 13142 * REVISIT TODO: Don't create a temporary nodeset 13143 * for everly iteration. 13144 */ 13145 /* OLD: xmlXPathFreeObject(res); */ 13146 } else 13147 tmp = NULL; 13148 ctxt->context->node = NULL; 13149 /* 13150 * Only put the first node in the result, then leave. 13151 */ 13152 if (newlocset->locNr > 0) { 13153 *first = (xmlNodePtr) oldlocset->locTab[i]->user; 13154 break; 13155 } 13156 } 13157 if (tmp != NULL) { 13158 xmlXPathReleaseObject(ctxt->context, tmp); 13159 } 13160 /* 13161 * The result is used as the new evaluation locset. 13162 */ 13163 xmlXPathReleaseObject(ctxt->context, obj); 13164 ctxt->context->node = NULL; 13165 ctxt->context->contextSize = -1; 13166 ctxt->context->proximityPosition = -1; 13167 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset)); 13168 ctxt->context->node = oldnode; 13169 return (total); 13170 } 13171 #endif /* LIBXML_XPTR_ENABLED */ 13172 13173 /* 13174 * Extract the old set, and then evaluate the result of the 13175 * expression for all the element in the set. use it to grow 13176 * up a new set. 13177 */ 13178 CHECK_TYPE0(XPATH_NODESET); 13179 obj = valuePop(ctxt); 13180 oldset = obj->nodesetval; 13181 13182 oldnode = ctxt->context->node; 13183 oldDoc = ctxt->context->doc; 13184 ctxt->context->node = NULL; 13185 13186 if ((oldset == NULL) || (oldset->nodeNr == 0)) { 13187 ctxt->context->contextSize = 0; 13188 ctxt->context->proximityPosition = 0; 13189 /* QUESTION TODO: Why was this code commented out? 13190 if (op->ch2 != -1) 13191 total += 13192 xmlXPathCompOpEval(ctxt, 13193 &comp->steps[op->ch2]); 13194 CHECK_ERROR0; 13195 res = valuePop(ctxt); 13196 if (res != NULL) 13197 xmlXPathFreeObject(res); 13198 */ 13199 valuePush(ctxt, obj); 13200 ctxt->context->node = oldnode; 13201 CHECK_ERROR0; 13202 } else { 13203 xmlNodeSetPtr newset; 13204 xmlXPathObjectPtr tmp = NULL; 13205 /* 13206 * Initialize the new set. 13207 * Also set the xpath document in case things like 13208 * key() evaluation are attempted on the predicate 13209 */ 13210 newset = xmlXPathNodeSetCreate(NULL); 13211 /* XXX what if xmlXPathNodeSetCreate returned NULL? */ 13212 13213 for (i = 0; i < oldset->nodeNr; i++) { 13214 /* 13215 * Run the evaluation with a node list made of 13216 * a single item in the nodeset. 13217 */ 13218 ctxt->context->node = oldset->nodeTab[i]; 13219 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) && 13220 (oldset->nodeTab[i]->doc != NULL)) 13221 ctxt->context->doc = oldset->nodeTab[i]->doc; 13222 if (tmp == NULL) { 13223 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13224 ctxt->context->node); 13225 } else { 13226 if (xmlXPathNodeSetAddUnique(tmp->nodesetval, 13227 ctxt->context->node) < 0) { 13228 ctxt->error = XPATH_MEMORY_ERROR; 13229 } 13230 } 13231 valuePush(ctxt, tmp); 13232 ctxt->context->contextSize = oldset->nodeNr; 13233 ctxt->context->proximityPosition = i + 1; 13234 if (op->ch2 != -1) 13235 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13236 if (ctxt->error != XPATH_EXPRESSION_OK) { 13237 xmlXPathFreeNodeSet(newset); 13238 xmlXPathFreeObject(obj); 13239 return(0); 13240 } 13241 /* 13242 * The result of the evaluation needs to be tested to 13243 * decide whether the filter succeeded or not 13244 */ 13245 res = valuePop(ctxt); 13246 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 13247 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0) 13248 ctxt->error = XPATH_MEMORY_ERROR; 13249 } 13250 /* 13251 * Cleanup 13252 */ 13253 if (res != NULL) { 13254 xmlXPathReleaseObject(ctxt->context, res); 13255 } 13256 if (ctxt->value == tmp) { 13257 valuePop(ctxt); 13258 /* 13259 * Don't free the temporary nodeset 13260 * in order to avoid massive recreation inside this 13261 * loop. 13262 */ 13263 xmlXPathNodeSetClear(tmp->nodesetval, 1); 13264 } else 13265 tmp = NULL; 13266 ctxt->context->node = NULL; 13267 /* 13268 * Only put the first node in the result, then leave. 13269 */ 13270 if (newset->nodeNr > 0) { 13271 *first = *(newset->nodeTab); 13272 break; 13273 } 13274 } 13275 if (tmp != NULL) { 13276 xmlXPathReleaseObject(ctxt->context, tmp); 13277 } 13278 /* 13279 * The result is used as the new evaluation set. 13280 */ 13281 xmlXPathReleaseObject(ctxt->context, obj); 13282 ctxt->context->node = NULL; 13283 ctxt->context->contextSize = -1; 13284 ctxt->context->proximityPosition = -1; 13285 /* may want to move this past the '}' later */ 13286 ctxt->context->doc = oldDoc; 13287 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset)); 13288 } 13289 ctxt->context->node = oldnode; 13290 return(total); 13291 } 13292 #endif /* XP_OPTIMIZED_FILTER_FIRST */ 13293 13294 /** 13295 * xmlXPathCompOpEval: 13296 * @ctxt: the XPath parser context with the compiled expression 13297 * @op: an XPath compiled operation 13298 * 13299 * Evaluate the Precompiled XPath operation 13300 * Returns the number of nodes traversed 13301 */ 13302 static int 13303 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) 13304 { 13305 int total = 0; 13306 int equal, ret; 13307 xmlXPathCompExprPtr comp; 13308 xmlXPathObjectPtr arg1, arg2; 13309 xmlNodePtr bak; 13310 xmlDocPtr bakd; 13311 int pp; 13312 int cs; 13313 13314 CHECK_ERROR0; 13315 comp = ctxt->comp; 13316 switch (op->op) { 13317 case XPATH_OP_END: 13318 return (0); 13319 case XPATH_OP_AND: 13320 bakd = ctxt->context->doc; 13321 bak = ctxt->context->node; 13322 pp = ctxt->context->proximityPosition; 13323 cs = ctxt->context->contextSize; 13324 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13325 CHECK_ERROR0; 13326 xmlXPathBooleanFunction(ctxt, 1); 13327 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0)) 13328 return (total); 13329 arg2 = valuePop(ctxt); 13330 ctxt->context->doc = bakd; 13331 ctxt->context->node = bak; 13332 ctxt->context->proximityPosition = pp; 13333 ctxt->context->contextSize = cs; 13334 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13335 if (ctxt->error) { 13336 xmlXPathFreeObject(arg2); 13337 return(0); 13338 } 13339 xmlXPathBooleanFunction(ctxt, 1); 13340 arg1 = valuePop(ctxt); 13341 arg1->boolval &= arg2->boolval; 13342 valuePush(ctxt, arg1); 13343 xmlXPathReleaseObject(ctxt->context, arg2); 13344 return (total); 13345 case XPATH_OP_OR: 13346 bakd = ctxt->context->doc; 13347 bak = ctxt->context->node; 13348 pp = ctxt->context->proximityPosition; 13349 cs = ctxt->context->contextSize; 13350 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13351 CHECK_ERROR0; 13352 xmlXPathBooleanFunction(ctxt, 1); 13353 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1)) 13354 return (total); 13355 arg2 = valuePop(ctxt); 13356 ctxt->context->doc = bakd; 13357 ctxt->context->node = bak; 13358 ctxt->context->proximityPosition = pp; 13359 ctxt->context->contextSize = cs; 13360 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13361 if (ctxt->error) { 13362 xmlXPathFreeObject(arg2); 13363 return(0); 13364 } 13365 xmlXPathBooleanFunction(ctxt, 1); 13366 arg1 = valuePop(ctxt); 13367 arg1->boolval |= arg2->boolval; 13368 valuePush(ctxt, arg1); 13369 xmlXPathReleaseObject(ctxt->context, arg2); 13370 return (total); 13371 case XPATH_OP_EQUAL: 13372 bakd = ctxt->context->doc; 13373 bak = ctxt->context->node; 13374 pp = ctxt->context->proximityPosition; 13375 cs = ctxt->context->contextSize; 13376 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13377 CHECK_ERROR0; 13378 ctxt->context->doc = bakd; 13379 ctxt->context->node = bak; 13380 ctxt->context->proximityPosition = pp; 13381 ctxt->context->contextSize = cs; 13382 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13383 CHECK_ERROR0; 13384 if (op->value) 13385 equal = xmlXPathEqualValues(ctxt); 13386 else 13387 equal = xmlXPathNotEqualValues(ctxt); 13388 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal)); 13389 return (total); 13390 case XPATH_OP_CMP: 13391 bakd = ctxt->context->doc; 13392 bak = ctxt->context->node; 13393 pp = ctxt->context->proximityPosition; 13394 cs = ctxt->context->contextSize; 13395 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13396 CHECK_ERROR0; 13397 ctxt->context->doc = bakd; 13398 ctxt->context->node = bak; 13399 ctxt->context->proximityPosition = pp; 13400 ctxt->context->contextSize = cs; 13401 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13402 CHECK_ERROR0; 13403 ret = xmlXPathCompareValues(ctxt, op->value, op->value2); 13404 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret)); 13405 return (total); 13406 case XPATH_OP_PLUS: 13407 bakd = ctxt->context->doc; 13408 bak = ctxt->context->node; 13409 pp = ctxt->context->proximityPosition; 13410 cs = ctxt->context->contextSize; 13411 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13412 CHECK_ERROR0; 13413 if (op->ch2 != -1) { 13414 ctxt->context->doc = bakd; 13415 ctxt->context->node = bak; 13416 ctxt->context->proximityPosition = pp; 13417 ctxt->context->contextSize = cs; 13418 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13419 } 13420 CHECK_ERROR0; 13421 if (op->value == 0) 13422 xmlXPathSubValues(ctxt); 13423 else if (op->value == 1) 13424 xmlXPathAddValues(ctxt); 13425 else if (op->value == 2) 13426 xmlXPathValueFlipSign(ctxt); 13427 else if (op->value == 3) { 13428 CAST_TO_NUMBER; 13429 CHECK_TYPE0(XPATH_NUMBER); 13430 } 13431 return (total); 13432 case XPATH_OP_MULT: 13433 bakd = ctxt->context->doc; 13434 bak = ctxt->context->node; 13435 pp = ctxt->context->proximityPosition; 13436 cs = ctxt->context->contextSize; 13437 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13438 CHECK_ERROR0; 13439 ctxt->context->doc = bakd; 13440 ctxt->context->node = bak; 13441 ctxt->context->proximityPosition = pp; 13442 ctxt->context->contextSize = cs; 13443 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13444 CHECK_ERROR0; 13445 if (op->value == 0) 13446 xmlXPathMultValues(ctxt); 13447 else if (op->value == 1) 13448 xmlXPathDivValues(ctxt); 13449 else if (op->value == 2) 13450 xmlXPathModValues(ctxt); 13451 return (total); 13452 case XPATH_OP_UNION: 13453 bakd = ctxt->context->doc; 13454 bak = ctxt->context->node; 13455 pp = ctxt->context->proximityPosition; 13456 cs = ctxt->context->contextSize; 13457 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13458 CHECK_ERROR0; 13459 ctxt->context->doc = bakd; 13460 ctxt->context->node = bak; 13461 ctxt->context->proximityPosition = pp; 13462 ctxt->context->contextSize = cs; 13463 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13464 CHECK_ERROR0; 13465 13466 arg2 = valuePop(ctxt); 13467 arg1 = valuePop(ctxt); 13468 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) || 13469 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) { 13470 xmlXPathReleaseObject(ctxt->context, arg1); 13471 xmlXPathReleaseObject(ctxt->context, arg2); 13472 XP_ERROR0(XPATH_INVALID_TYPE); 13473 } 13474 13475 if ((arg1->nodesetval == NULL) || 13476 ((arg2->nodesetval != NULL) && 13477 (arg2->nodesetval->nodeNr != 0))) 13478 { 13479 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 13480 arg2->nodesetval); 13481 } 13482 13483 valuePush(ctxt, arg1); 13484 xmlXPathReleaseObject(ctxt->context, arg2); 13485 return (total); 13486 case XPATH_OP_ROOT: 13487 xmlXPathRoot(ctxt); 13488 return (total); 13489 case XPATH_OP_NODE: 13490 if (op->ch1 != -1) 13491 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13492 CHECK_ERROR0; 13493 if (op->ch2 != -1) 13494 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13495 CHECK_ERROR0; 13496 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 13497 ctxt->context->node)); 13498 return (total); 13499 case XPATH_OP_RESET: 13500 if (op->ch1 != -1) 13501 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13502 CHECK_ERROR0; 13503 if (op->ch2 != -1) 13504 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13505 CHECK_ERROR0; 13506 ctxt->context->node = NULL; 13507 return (total); 13508 case XPATH_OP_COLLECT:{ 13509 if (op->ch1 == -1) 13510 return (total); 13511 13512 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13513 CHECK_ERROR0; 13514 13515 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0); 13516 return (total); 13517 } 13518 case XPATH_OP_VALUE: 13519 valuePush(ctxt, 13520 xmlXPathCacheObjectCopy(ctxt->context, 13521 (xmlXPathObjectPtr) op->value4)); 13522 return (total); 13523 case XPATH_OP_VARIABLE:{ 13524 xmlXPathObjectPtr val; 13525 13526 if (op->ch1 != -1) 13527 total += 13528 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13529 if (op->value5 == NULL) { 13530 val = xmlXPathVariableLookup(ctxt->context, op->value4); 13531 if (val == NULL) 13532 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR); 13533 valuePush(ctxt, val); 13534 } else { 13535 const xmlChar *URI; 13536 13537 URI = xmlXPathNsLookup(ctxt->context, op->value5); 13538 if (URI == NULL) { 13539 xmlGenericError(xmlGenericErrorContext, 13540 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n", 13541 (char *) op->value4, (char *)op->value5); 13542 ctxt->error = XPATH_UNDEF_PREFIX_ERROR; 13543 return (total); 13544 } 13545 val = xmlXPathVariableLookupNS(ctxt->context, 13546 op->value4, URI); 13547 if (val == NULL) 13548 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR); 13549 valuePush(ctxt, val); 13550 } 13551 return (total); 13552 } 13553 case XPATH_OP_FUNCTION:{ 13554 xmlXPathFunction func; 13555 const xmlChar *oldFunc, *oldFuncURI; 13556 int i; 13557 int frame; 13558 13559 frame = xmlXPathSetFrame(ctxt); 13560 if (op->ch1 != -1) { 13561 total += 13562 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13563 if (ctxt->error != XPATH_EXPRESSION_OK) { 13564 xmlXPathPopFrame(ctxt, frame); 13565 return (total); 13566 } 13567 } 13568 if (ctxt->valueNr < ctxt->valueFrame + op->value) { 13569 xmlGenericError(xmlGenericErrorContext, 13570 "xmlXPathCompOpEval: parameter error\n"); 13571 ctxt->error = XPATH_INVALID_OPERAND; 13572 xmlXPathPopFrame(ctxt, frame); 13573 return (total); 13574 } 13575 for (i = 0; i < op->value; i++) { 13576 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) { 13577 xmlGenericError(xmlGenericErrorContext, 13578 "xmlXPathCompOpEval: parameter error\n"); 13579 ctxt->error = XPATH_INVALID_OPERAND; 13580 xmlXPathPopFrame(ctxt, frame); 13581 return (total); 13582 } 13583 } 13584 if (op->cache != NULL) 13585 func = op->cache; 13586 else { 13587 const xmlChar *URI = NULL; 13588 13589 if (op->value5 == NULL) 13590 func = 13591 xmlXPathFunctionLookup(ctxt->context, 13592 op->value4); 13593 else { 13594 URI = xmlXPathNsLookup(ctxt->context, op->value5); 13595 if (URI == NULL) { 13596 xmlGenericError(xmlGenericErrorContext, 13597 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n", 13598 (char *)op->value4, (char *)op->value5); 13599 xmlXPathPopFrame(ctxt, frame); 13600 ctxt->error = XPATH_UNDEF_PREFIX_ERROR; 13601 return (total); 13602 } 13603 func = xmlXPathFunctionLookupNS(ctxt->context, 13604 op->value4, URI); 13605 } 13606 if (func == NULL) { 13607 xmlGenericError(xmlGenericErrorContext, 13608 "xmlXPathCompOpEval: function %s not found\n", 13609 (char *)op->value4); 13610 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR); 13611 } 13612 op->cache = func; 13613 op->cacheURI = (void *) URI; 13614 } 13615 oldFunc = ctxt->context->function; 13616 oldFuncURI = ctxt->context->functionURI; 13617 ctxt->context->function = op->value4; 13618 ctxt->context->functionURI = op->cacheURI; 13619 func(ctxt, op->value); 13620 ctxt->context->function = oldFunc; 13621 ctxt->context->functionURI = oldFuncURI; 13622 xmlXPathPopFrame(ctxt, frame); 13623 return (total); 13624 } 13625 case XPATH_OP_ARG: 13626 bakd = ctxt->context->doc; 13627 bak = ctxt->context->node; 13628 pp = ctxt->context->proximityPosition; 13629 cs = ctxt->context->contextSize; 13630 if (op->ch1 != -1) { 13631 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13632 ctxt->context->contextSize = cs; 13633 ctxt->context->proximityPosition = pp; 13634 ctxt->context->node = bak; 13635 ctxt->context->doc = bakd; 13636 CHECK_ERROR0; 13637 } 13638 if (op->ch2 != -1) { 13639 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13640 ctxt->context->contextSize = cs; 13641 ctxt->context->proximityPosition = pp; 13642 ctxt->context->node = bak; 13643 ctxt->context->doc = bakd; 13644 CHECK_ERROR0; 13645 } 13646 return (total); 13647 case XPATH_OP_PREDICATE: 13648 case XPATH_OP_FILTER:{ 13649 xmlXPathObjectPtr res; 13650 xmlXPathObjectPtr obj, tmp; 13651 xmlNodeSetPtr newset = NULL; 13652 xmlNodeSetPtr oldset; 13653 xmlNodePtr oldnode; 13654 xmlDocPtr oldDoc; 13655 int i; 13656 13657 /* 13658 * Optimization for ()[1] selection i.e. the first elem 13659 */ 13660 if ((op->ch1 != -1) && (op->ch2 != -1) && 13661 #ifdef XP_OPTIMIZED_FILTER_FIRST 13662 /* 13663 * FILTER TODO: Can we assume that the inner processing 13664 * will result in an ordered list if we have an 13665 * XPATH_OP_FILTER? 13666 * What about an additional field or flag on 13667 * xmlXPathObject like @sorted ? This way we wouln'd need 13668 * to assume anything, so it would be more robust and 13669 * easier to optimize. 13670 */ 13671 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */ 13672 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */ 13673 #else 13674 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 13675 #endif 13676 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */ 13677 xmlXPathObjectPtr val; 13678 13679 val = comp->steps[op->ch2].value4; 13680 if ((val != NULL) && (val->type == XPATH_NUMBER) && 13681 (val->floatval == 1.0)) { 13682 xmlNodePtr first = NULL; 13683 13684 total += 13685 xmlXPathCompOpEvalFirst(ctxt, 13686 &comp->steps[op->ch1], 13687 &first); 13688 CHECK_ERROR0; 13689 /* 13690 * The nodeset should be in document order, 13691 * Keep only the first value 13692 */ 13693 if ((ctxt->value != NULL) && 13694 (ctxt->value->type == XPATH_NODESET) && 13695 (ctxt->value->nodesetval != NULL) && 13696 (ctxt->value->nodesetval->nodeNr > 1)) 13697 xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval, 13698 1, 1); 13699 return (total); 13700 } 13701 } 13702 /* 13703 * Optimization for ()[last()] selection i.e. the last elem 13704 */ 13705 if ((op->ch1 != -1) && (op->ch2 != -1) && 13706 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 13707 (comp->steps[op->ch2].op == XPATH_OP_SORT)) { 13708 int f = comp->steps[op->ch2].ch1; 13709 13710 if ((f != -1) && 13711 (comp->steps[f].op == XPATH_OP_FUNCTION) && 13712 (comp->steps[f].value5 == NULL) && 13713 (comp->steps[f].value == 0) && 13714 (comp->steps[f].value4 != NULL) && 13715 (xmlStrEqual 13716 (comp->steps[f].value4, BAD_CAST "last"))) { 13717 xmlNodePtr last = NULL; 13718 13719 total += 13720 xmlXPathCompOpEvalLast(ctxt, 13721 &comp->steps[op->ch1], 13722 &last); 13723 CHECK_ERROR0; 13724 /* 13725 * The nodeset should be in document order, 13726 * Keep only the last value 13727 */ 13728 if ((ctxt->value != NULL) && 13729 (ctxt->value->type == XPATH_NODESET) && 13730 (ctxt->value->nodesetval != NULL) && 13731 (ctxt->value->nodesetval->nodeTab != NULL) && 13732 (ctxt->value->nodesetval->nodeNr > 1)) 13733 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval); 13734 return (total); 13735 } 13736 } 13737 /* 13738 * Process inner predicates first. 13739 * Example "index[parent::book][1]": 13740 * ... 13741 * PREDICATE <-- we are here "[1]" 13742 * PREDICATE <-- process "[parent::book]" first 13743 * SORT 13744 * COLLECT 'parent' 'name' 'node' book 13745 * NODE 13746 * ELEM Object is a number : 1 13747 */ 13748 if (op->ch1 != -1) 13749 total += 13750 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13751 CHECK_ERROR0; 13752 if (op->ch2 == -1) 13753 return (total); 13754 if (ctxt->value == NULL) 13755 return (total); 13756 13757 oldnode = ctxt->context->node; 13758 13759 #ifdef LIBXML_XPTR_ENABLED 13760 /* 13761 * Hum are we filtering the result of an XPointer expression 13762 */ 13763 if (ctxt->value->type == XPATH_LOCATIONSET) { 13764 xmlLocationSetPtr newlocset = NULL; 13765 xmlLocationSetPtr oldlocset; 13766 13767 /* 13768 * Extract the old locset, and then evaluate the result of the 13769 * expression for all the element in the locset. use it to grow 13770 * up a new locset. 13771 */ 13772 CHECK_TYPE0(XPATH_LOCATIONSET); 13773 obj = valuePop(ctxt); 13774 oldlocset = obj->user; 13775 ctxt->context->node = NULL; 13776 13777 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) { 13778 ctxt->context->contextSize = 0; 13779 ctxt->context->proximityPosition = 0; 13780 if (op->ch2 != -1) 13781 total += 13782 xmlXPathCompOpEval(ctxt, 13783 &comp->steps[op->ch2]); 13784 res = valuePop(ctxt); 13785 if (res != NULL) { 13786 xmlXPathReleaseObject(ctxt->context, res); 13787 } 13788 valuePush(ctxt, obj); 13789 CHECK_ERROR0; 13790 return (total); 13791 } 13792 newlocset = xmlXPtrLocationSetCreate(NULL); 13793 13794 for (i = 0; i < oldlocset->locNr; i++) { 13795 /* 13796 * Run the evaluation with a node list made of a 13797 * single item in the nodelocset. 13798 */ 13799 ctxt->context->node = oldlocset->locTab[i]->user; 13800 ctxt->context->contextSize = oldlocset->locNr; 13801 ctxt->context->proximityPosition = i + 1; 13802 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13803 ctxt->context->node); 13804 valuePush(ctxt, tmp); 13805 13806 if (op->ch2 != -1) 13807 total += 13808 xmlXPathCompOpEval(ctxt, 13809 &comp->steps[op->ch2]); 13810 if (ctxt->error != XPATH_EXPRESSION_OK) { 13811 xmlXPathFreeObject(obj); 13812 return(0); 13813 } 13814 13815 /* 13816 * The result of the evaluation need to be tested to 13817 * decided whether the filter succeeded or not 13818 */ 13819 res = valuePop(ctxt); 13820 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 13821 xmlXPtrLocationSetAdd(newlocset, 13822 xmlXPathObjectCopy 13823 (oldlocset->locTab[i])); 13824 } 13825 13826 /* 13827 * Cleanup 13828 */ 13829 if (res != NULL) { 13830 xmlXPathReleaseObject(ctxt->context, res); 13831 } 13832 if (ctxt->value == tmp) { 13833 res = valuePop(ctxt); 13834 xmlXPathReleaseObject(ctxt->context, res); 13835 } 13836 13837 ctxt->context->node = NULL; 13838 } 13839 13840 /* 13841 * The result is used as the new evaluation locset. 13842 */ 13843 xmlXPathReleaseObject(ctxt->context, obj); 13844 ctxt->context->node = NULL; 13845 ctxt->context->contextSize = -1; 13846 ctxt->context->proximityPosition = -1; 13847 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset)); 13848 ctxt->context->node = oldnode; 13849 return (total); 13850 } 13851 #endif /* LIBXML_XPTR_ENABLED */ 13852 13853 /* 13854 * Extract the old set, and then evaluate the result of the 13855 * expression for all the element in the set. use it to grow 13856 * up a new set. 13857 */ 13858 CHECK_TYPE0(XPATH_NODESET); 13859 obj = valuePop(ctxt); 13860 oldset = obj->nodesetval; 13861 13862 oldnode = ctxt->context->node; 13863 oldDoc = ctxt->context->doc; 13864 ctxt->context->node = NULL; 13865 13866 if ((oldset == NULL) || (oldset->nodeNr == 0)) { 13867 ctxt->context->contextSize = 0; 13868 ctxt->context->proximityPosition = 0; 13869 /* 13870 if (op->ch2 != -1) 13871 total += 13872 xmlXPathCompOpEval(ctxt, 13873 &comp->steps[op->ch2]); 13874 CHECK_ERROR0; 13875 res = valuePop(ctxt); 13876 if (res != NULL) 13877 xmlXPathFreeObject(res); 13878 */ 13879 valuePush(ctxt, obj); 13880 ctxt->context->node = oldnode; 13881 CHECK_ERROR0; 13882 } else { 13883 tmp = NULL; 13884 /* 13885 * Initialize the new set. 13886 * Also set the xpath document in case things like 13887 * key() evaluation are attempted on the predicate 13888 */ 13889 newset = xmlXPathNodeSetCreate(NULL); 13890 /* 13891 * SPEC XPath 1.0: 13892 * "For each node in the node-set to be filtered, the 13893 * PredicateExpr is evaluated with that node as the 13894 * context node, with the number of nodes in the 13895 * node-set as the context size, and with the proximity 13896 * position of the node in the node-set with respect to 13897 * the axis as the context position;" 13898 * @oldset is the node-set" to be filtered. 13899 * 13900 * SPEC XPath 1.0: 13901 * "only predicates change the context position and 13902 * context size (see [2.4 Predicates])." 13903 * Example: 13904 * node-set context pos 13905 * nA 1 13906 * nB 2 13907 * nC 3 13908 * After applying predicate [position() > 1] : 13909 * node-set context pos 13910 * nB 1 13911 * nC 2 13912 * 13913 * removed the first node in the node-set, then 13914 * the context position of the 13915 */ 13916 for (i = 0; i < oldset->nodeNr; i++) { 13917 /* 13918 * Run the evaluation with a node list made of 13919 * a single item in the nodeset. 13920 */ 13921 ctxt->context->node = oldset->nodeTab[i]; 13922 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) && 13923 (oldset->nodeTab[i]->doc != NULL)) 13924 ctxt->context->doc = oldset->nodeTab[i]->doc; 13925 if (tmp == NULL) { 13926 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13927 ctxt->context->node); 13928 } else { 13929 if (xmlXPathNodeSetAddUnique(tmp->nodesetval, 13930 ctxt->context->node) < 0) { 13931 ctxt->error = XPATH_MEMORY_ERROR; 13932 } 13933 } 13934 valuePush(ctxt, tmp); 13935 ctxt->context->contextSize = oldset->nodeNr; 13936 ctxt->context->proximityPosition = i + 1; 13937 /* 13938 * Evaluate the predicate against the context node. 13939 * Can/should we optimize position() predicates 13940 * here (e.g. "[1]")? 13941 */ 13942 if (op->ch2 != -1) 13943 total += 13944 xmlXPathCompOpEval(ctxt, 13945 &comp->steps[op->ch2]); 13946 if (ctxt->error != XPATH_EXPRESSION_OK) { 13947 xmlXPathFreeNodeSet(newset); 13948 xmlXPathFreeObject(obj); 13949 return(0); 13950 } 13951 13952 /* 13953 * The result of the evaluation needs to be tested to 13954 * decide whether the filter succeeded or not 13955 */ 13956 /* 13957 * OPTIMIZE TODO: Can we use 13958 * xmlXPathNodeSetAdd*Unique()* instead? 13959 */ 13960 res = valuePop(ctxt); 13961 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 13962 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) 13963 < 0) 13964 ctxt->error = XPATH_MEMORY_ERROR; 13965 } 13966 13967 /* 13968 * Cleanup 13969 */ 13970 if (res != NULL) { 13971 xmlXPathReleaseObject(ctxt->context, res); 13972 } 13973 if (ctxt->value == tmp) { 13974 valuePop(ctxt); 13975 xmlXPathNodeSetClear(tmp->nodesetval, 1); 13976 /* 13977 * Don't free the temporary nodeset 13978 * in order to avoid massive recreation inside this 13979 * loop. 13980 */ 13981 } else 13982 tmp = NULL; 13983 ctxt->context->node = NULL; 13984 } 13985 if (tmp != NULL) 13986 xmlXPathReleaseObject(ctxt->context, tmp); 13987 /* 13988 * The result is used as the new evaluation set. 13989 */ 13990 xmlXPathReleaseObject(ctxt->context, obj); 13991 ctxt->context->node = NULL; 13992 ctxt->context->contextSize = -1; 13993 ctxt->context->proximityPosition = -1; 13994 /* may want to move this past the '}' later */ 13995 ctxt->context->doc = oldDoc; 13996 valuePush(ctxt, 13997 xmlXPathCacheWrapNodeSet(ctxt->context, newset)); 13998 } 13999 ctxt->context->node = oldnode; 14000 return (total); 14001 } 14002 case XPATH_OP_SORT: 14003 if (op->ch1 != -1) 14004 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 14005 CHECK_ERROR0; 14006 if ((ctxt->value != NULL) && 14007 (ctxt->value->type == XPATH_NODESET) && 14008 (ctxt->value->nodesetval != NULL) && 14009 (ctxt->value->nodesetval->nodeNr > 1)) 14010 { 14011 xmlXPathNodeSetSort(ctxt->value->nodesetval); 14012 } 14013 return (total); 14014 #ifdef LIBXML_XPTR_ENABLED 14015 case XPATH_OP_RANGETO:{ 14016 xmlXPathObjectPtr range; 14017 xmlXPathObjectPtr res, obj; 14018 xmlXPathObjectPtr tmp; 14019 xmlLocationSetPtr newlocset = NULL; 14020 xmlLocationSetPtr oldlocset; 14021 xmlNodeSetPtr oldset; 14022 int i, j; 14023 14024 if (op->ch1 != -1) { 14025 total += 14026 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 14027 CHECK_ERROR0; 14028 } 14029 if (ctxt->value == NULL) { 14030 XP_ERROR0(XPATH_INVALID_OPERAND); 14031 } 14032 if (op->ch2 == -1) 14033 return (total); 14034 14035 if (ctxt->value->type == XPATH_LOCATIONSET) { 14036 /* 14037 * Extract the old locset, and then evaluate the result of the 14038 * expression for all the element in the locset. use it to grow 14039 * up a new locset. 14040 */ 14041 CHECK_TYPE0(XPATH_LOCATIONSET); 14042 obj = valuePop(ctxt); 14043 oldlocset = obj->user; 14044 14045 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) { 14046 ctxt->context->node = NULL; 14047 ctxt->context->contextSize = 0; 14048 ctxt->context->proximityPosition = 0; 14049 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]); 14050 res = valuePop(ctxt); 14051 if (res != NULL) { 14052 xmlXPathReleaseObject(ctxt->context, res); 14053 } 14054 valuePush(ctxt, obj); 14055 CHECK_ERROR0; 14056 return (total); 14057 } 14058 newlocset = xmlXPtrLocationSetCreate(NULL); 14059 14060 for (i = 0; i < oldlocset->locNr; i++) { 14061 /* 14062 * Run the evaluation with a node list made of a 14063 * single item in the nodelocset. 14064 */ 14065 ctxt->context->node = oldlocset->locTab[i]->user; 14066 ctxt->context->contextSize = oldlocset->locNr; 14067 ctxt->context->proximityPosition = i + 1; 14068 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 14069 ctxt->context->node); 14070 valuePush(ctxt, tmp); 14071 14072 if (op->ch2 != -1) 14073 total += 14074 xmlXPathCompOpEval(ctxt, 14075 &comp->steps[op->ch2]); 14076 if (ctxt->error != XPATH_EXPRESSION_OK) { 14077 xmlXPathFreeObject(obj); 14078 return(0); 14079 } 14080 14081 res = valuePop(ctxt); 14082 if (res->type == XPATH_LOCATIONSET) { 14083 xmlLocationSetPtr rloc = 14084 (xmlLocationSetPtr)res->user; 14085 for (j=0; j<rloc->locNr; j++) { 14086 range = xmlXPtrNewRange( 14087 oldlocset->locTab[i]->user, 14088 oldlocset->locTab[i]->index, 14089 rloc->locTab[j]->user2, 14090 rloc->locTab[j]->index2); 14091 if (range != NULL) { 14092 xmlXPtrLocationSetAdd(newlocset, range); 14093 } 14094 } 14095 } else { 14096 range = xmlXPtrNewRangeNodeObject( 14097 (xmlNodePtr)oldlocset->locTab[i]->user, res); 14098 if (range != NULL) { 14099 xmlXPtrLocationSetAdd(newlocset,range); 14100 } 14101 } 14102 14103 /* 14104 * Cleanup 14105 */ 14106 if (res != NULL) { 14107 xmlXPathReleaseObject(ctxt->context, res); 14108 } 14109 if (ctxt->value == tmp) { 14110 res = valuePop(ctxt); 14111 xmlXPathReleaseObject(ctxt->context, res); 14112 } 14113 14114 ctxt->context->node = NULL; 14115 } 14116 } else { /* Not a location set */ 14117 CHECK_TYPE0(XPATH_NODESET); 14118 obj = valuePop(ctxt); 14119 oldset = obj->nodesetval; 14120 ctxt->context->node = NULL; 14121 14122 newlocset = xmlXPtrLocationSetCreate(NULL); 14123 14124 if (oldset != NULL) { 14125 for (i = 0; i < oldset->nodeNr; i++) { 14126 /* 14127 * Run the evaluation with a node list made of a single item 14128 * in the nodeset. 14129 */ 14130 ctxt->context->node = oldset->nodeTab[i]; 14131 /* 14132 * OPTIMIZE TODO: Avoid recreation for every iteration. 14133 */ 14134 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 14135 ctxt->context->node); 14136 valuePush(ctxt, tmp); 14137 14138 if (op->ch2 != -1) 14139 total += 14140 xmlXPathCompOpEval(ctxt, 14141 &comp->steps[op->ch2]); 14142 if (ctxt->error != XPATH_EXPRESSION_OK) { 14143 xmlXPathFreeObject(obj); 14144 return(0); 14145 } 14146 14147 res = valuePop(ctxt); 14148 range = 14149 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i], 14150 res); 14151 if (range != NULL) { 14152 xmlXPtrLocationSetAdd(newlocset, range); 14153 } 14154 14155 /* 14156 * Cleanup 14157 */ 14158 if (res != NULL) { 14159 xmlXPathReleaseObject(ctxt->context, res); 14160 } 14161 if (ctxt->value == tmp) { 14162 res = valuePop(ctxt); 14163 xmlXPathReleaseObject(ctxt->context, res); 14164 } 14165 14166 ctxt->context->node = NULL; 14167 } 14168 } 14169 } 14170 14171 /* 14172 * The result is used as the new evaluation set. 14173 */ 14174 xmlXPathReleaseObject(ctxt->context, obj); 14175 ctxt->context->node = NULL; 14176 ctxt->context->contextSize = -1; 14177 ctxt->context->proximityPosition = -1; 14178 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset)); 14179 return (total); 14180 } 14181 #endif /* LIBXML_XPTR_ENABLED */ 14182 } 14183 xmlGenericError(xmlGenericErrorContext, 14184 "XPath: unknown precompiled operation %d\n", op->op); 14185 ctxt->error = XPATH_INVALID_OPERAND; 14186 return (total); 14187 } 14188 14189 /** 14190 * xmlXPathCompOpEvalToBoolean: 14191 * @ctxt: the XPath parser context 14192 * 14193 * Evaluates if the expression evaluates to true. 14194 * 14195 * Returns 1 if true, 0 if false and -1 on API or internal errors. 14196 */ 14197 static int 14198 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt, 14199 xmlXPathStepOpPtr op, 14200 int isPredicate) 14201 { 14202 xmlXPathObjectPtr resObj = NULL; 14203 14204 start: 14205 /* comp = ctxt->comp; */ 14206 switch (op->op) { 14207 case XPATH_OP_END: 14208 return (0); 14209 case XPATH_OP_VALUE: 14210 resObj = (xmlXPathObjectPtr) op->value4; 14211 if (isPredicate) 14212 return(xmlXPathEvaluatePredicateResult(ctxt, resObj)); 14213 return(xmlXPathCastToBoolean(resObj)); 14214 case XPATH_OP_SORT: 14215 /* 14216 * We don't need sorting for boolean results. Skip this one. 14217 */ 14218 if (op->ch1 != -1) { 14219 op = &ctxt->comp->steps[op->ch1]; 14220 goto start; 14221 } 14222 return(0); 14223 case XPATH_OP_COLLECT: 14224 if (op->ch1 == -1) 14225 return(0); 14226 14227 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]); 14228 if (ctxt->error != XPATH_EXPRESSION_OK) 14229 return(-1); 14230 14231 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1); 14232 if (ctxt->error != XPATH_EXPRESSION_OK) 14233 return(-1); 14234 14235 resObj = valuePop(ctxt); 14236 if (resObj == NULL) 14237 return(-1); 14238 break; 14239 default: 14240 /* 14241 * Fallback to call xmlXPathCompOpEval(). 14242 */ 14243 xmlXPathCompOpEval(ctxt, op); 14244 if (ctxt->error != XPATH_EXPRESSION_OK) 14245 return(-1); 14246 14247 resObj = valuePop(ctxt); 14248 if (resObj == NULL) 14249 return(-1); 14250 break; 14251 } 14252 14253 if (resObj) { 14254 int res; 14255 14256 if (resObj->type == XPATH_BOOLEAN) { 14257 res = resObj->boolval; 14258 } else if (isPredicate) { 14259 /* 14260 * For predicates a result of type "number" is handled 14261 * differently: 14262 * SPEC XPath 1.0: 14263 * "If the result is a number, the result will be converted 14264 * to true if the number is equal to the context position 14265 * and will be converted to false otherwise;" 14266 */ 14267 res = xmlXPathEvaluatePredicateResult(ctxt, resObj); 14268 } else { 14269 res = xmlXPathCastToBoolean(resObj); 14270 } 14271 xmlXPathReleaseObject(ctxt->context, resObj); 14272 return(res); 14273 } 14274 14275 return(0); 14276 } 14277 14278 #ifdef XPATH_STREAMING 14279 /** 14280 * xmlXPathRunStreamEval: 14281 * @ctxt: the XPath parser context with the compiled expression 14282 * 14283 * Evaluate the Precompiled Streamable XPath expression in the given context. 14284 */ 14285 static int 14286 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp, 14287 xmlXPathObjectPtr *resultSeq, int toBool) 14288 { 14289 int max_depth, min_depth; 14290 int from_root; 14291 int ret, depth; 14292 int eval_all_nodes; 14293 xmlNodePtr cur = NULL, limit = NULL; 14294 xmlStreamCtxtPtr patstream = NULL; 14295 14296 int nb_nodes = 0; 14297 14298 if ((ctxt == NULL) || (comp == NULL)) 14299 return(-1); 14300 max_depth = xmlPatternMaxDepth(comp); 14301 if (max_depth == -1) 14302 return(-1); 14303 if (max_depth == -2) 14304 max_depth = 10000; 14305 min_depth = xmlPatternMinDepth(comp); 14306 if (min_depth == -1) 14307 return(-1); 14308 from_root = xmlPatternFromRoot(comp); 14309 if (from_root < 0) 14310 return(-1); 14311 #if 0 14312 printf("stream eval: depth %d from root %d\n", max_depth, from_root); 14313 #endif 14314 14315 if (! toBool) { 14316 if (resultSeq == NULL) 14317 return(-1); 14318 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL); 14319 if (*resultSeq == NULL) 14320 return(-1); 14321 } 14322 14323 /* 14324 * handle the special cases of "/" amd "." being matched 14325 */ 14326 if (min_depth == 0) { 14327 if (from_root) { 14328 /* Select "/" */ 14329 if (toBool) 14330 return(1); 14331 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, 14332 (xmlNodePtr) ctxt->doc); 14333 } else { 14334 /* Select "self::node()" */ 14335 if (toBool) 14336 return(1); 14337 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node); 14338 } 14339 } 14340 if (max_depth == 0) { 14341 return(0); 14342 } 14343 14344 if (from_root) { 14345 cur = (xmlNodePtr)ctxt->doc; 14346 } else if (ctxt->node != NULL) { 14347 switch (ctxt->node->type) { 14348 case XML_ELEMENT_NODE: 14349 case XML_DOCUMENT_NODE: 14350 case XML_DOCUMENT_FRAG_NODE: 14351 case XML_HTML_DOCUMENT_NODE: 14352 #ifdef LIBXML_DOCB_ENABLED 14353 case XML_DOCB_DOCUMENT_NODE: 14354 #endif 14355 cur = ctxt->node; 14356 break; 14357 case XML_ATTRIBUTE_NODE: 14358 case XML_TEXT_NODE: 14359 case XML_CDATA_SECTION_NODE: 14360 case XML_ENTITY_REF_NODE: 14361 case XML_ENTITY_NODE: 14362 case XML_PI_NODE: 14363 case XML_COMMENT_NODE: 14364 case XML_NOTATION_NODE: 14365 case XML_DTD_NODE: 14366 case XML_DOCUMENT_TYPE_NODE: 14367 case XML_ELEMENT_DECL: 14368 case XML_ATTRIBUTE_DECL: 14369 case XML_ENTITY_DECL: 14370 case XML_NAMESPACE_DECL: 14371 case XML_XINCLUDE_START: 14372 case XML_XINCLUDE_END: 14373 break; 14374 } 14375 limit = cur; 14376 } 14377 if (cur == NULL) { 14378 return(0); 14379 } 14380 14381 patstream = xmlPatternGetStreamCtxt(comp); 14382 if (patstream == NULL) { 14383 /* 14384 * QUESTION TODO: Is this an error? 14385 */ 14386 return(0); 14387 } 14388 14389 eval_all_nodes = xmlStreamWantsAnyNode(patstream); 14390 14391 if (from_root) { 14392 ret = xmlStreamPush(patstream, NULL, NULL); 14393 if (ret < 0) { 14394 } else if (ret == 1) { 14395 if (toBool) 14396 goto return_1; 14397 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur); 14398 } 14399 } 14400 depth = 0; 14401 goto scan_children; 14402 next_node: 14403 do { 14404 nb_nodes++; 14405 14406 switch (cur->type) { 14407 case XML_ELEMENT_NODE: 14408 case XML_TEXT_NODE: 14409 case XML_CDATA_SECTION_NODE: 14410 case XML_COMMENT_NODE: 14411 case XML_PI_NODE: 14412 if (cur->type == XML_ELEMENT_NODE) { 14413 ret = xmlStreamPush(patstream, cur->name, 14414 (cur->ns ? cur->ns->href : NULL)); 14415 } else if (eval_all_nodes) 14416 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type); 14417 else 14418 break; 14419 14420 if (ret < 0) { 14421 /* NOP. */ 14422 } else if (ret == 1) { 14423 if (toBool) 14424 goto return_1; 14425 if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur) 14426 < 0) { 14427 ctxt->lastError.domain = XML_FROM_XPATH; 14428 ctxt->lastError.code = XML_ERR_NO_MEMORY; 14429 } 14430 } 14431 if ((cur->children == NULL) || (depth >= max_depth)) { 14432 ret = xmlStreamPop(patstream); 14433 while (cur->next != NULL) { 14434 cur = cur->next; 14435 if ((cur->type != XML_ENTITY_DECL) && 14436 (cur->type != XML_DTD_NODE)) 14437 goto next_node; 14438 } 14439 } 14440 default: 14441 break; 14442 } 14443 14444 scan_children: 14445 if (cur->type == XML_NAMESPACE_DECL) break; 14446 if ((cur->children != NULL) && (depth < max_depth)) { 14447 /* 14448 * Do not descend on entities declarations 14449 */ 14450 if (cur->children->type != XML_ENTITY_DECL) { 14451 cur = cur->children; 14452 depth++; 14453 /* 14454 * Skip DTDs 14455 */ 14456 if (cur->type != XML_DTD_NODE) 14457 continue; 14458 } 14459 } 14460 14461 if (cur == limit) 14462 break; 14463 14464 while (cur->next != NULL) { 14465 cur = cur->next; 14466 if ((cur->type != XML_ENTITY_DECL) && 14467 (cur->type != XML_DTD_NODE)) 14468 goto next_node; 14469 } 14470 14471 do { 14472 cur = cur->parent; 14473 depth--; 14474 if ((cur == NULL) || (cur == limit)) 14475 goto done; 14476 if (cur->type == XML_ELEMENT_NODE) { 14477 ret = xmlStreamPop(patstream); 14478 } else if ((eval_all_nodes) && 14479 ((cur->type == XML_TEXT_NODE) || 14480 (cur->type == XML_CDATA_SECTION_NODE) || 14481 (cur->type == XML_COMMENT_NODE) || 14482 (cur->type == XML_PI_NODE))) 14483 { 14484 ret = xmlStreamPop(patstream); 14485 } 14486 if (cur->next != NULL) { 14487 cur = cur->next; 14488 break; 14489 } 14490 } while (cur != NULL); 14491 14492 } while ((cur != NULL) && (depth >= 0)); 14493 14494 done: 14495 14496 #if 0 14497 printf("stream eval: checked %d nodes selected %d\n", 14498 nb_nodes, retObj->nodesetval->nodeNr); 14499 #endif 14500 14501 if (patstream) 14502 xmlFreeStreamCtxt(patstream); 14503 return(0); 14504 14505 return_1: 14506 if (patstream) 14507 xmlFreeStreamCtxt(patstream); 14508 return(1); 14509 } 14510 #endif /* XPATH_STREAMING */ 14511 14512 /** 14513 * xmlXPathRunEval: 14514 * @ctxt: the XPath parser context with the compiled expression 14515 * @toBool: evaluate to a boolean result 14516 * 14517 * Evaluate the Precompiled XPath expression in the given context. 14518 */ 14519 static int 14520 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool) 14521 { 14522 xmlXPathCompExprPtr comp; 14523 14524 if ((ctxt == NULL) || (ctxt->comp == NULL)) 14525 return(-1); 14526 14527 if (ctxt->valueTab == NULL) { 14528 /* Allocate the value stack */ 14529 ctxt->valueTab = (xmlXPathObjectPtr *) 14530 xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); 14531 if (ctxt->valueTab == NULL) { 14532 xmlXPathPErrMemory(ctxt, "creating evaluation context\n"); 14533 xmlFree(ctxt); 14534 } 14535 ctxt->valueNr = 0; 14536 ctxt->valueMax = 10; 14537 ctxt->value = NULL; 14538 ctxt->valueFrame = 0; 14539 } 14540 #ifdef XPATH_STREAMING 14541 if (ctxt->comp->stream) { 14542 int res; 14543 14544 if (toBool) { 14545 /* 14546 * Evaluation to boolean result. 14547 */ 14548 res = xmlXPathRunStreamEval(ctxt->context, 14549 ctxt->comp->stream, NULL, 1); 14550 if (res != -1) 14551 return(res); 14552 } else { 14553 xmlXPathObjectPtr resObj = NULL; 14554 14555 /* 14556 * Evaluation to a sequence. 14557 */ 14558 res = xmlXPathRunStreamEval(ctxt->context, 14559 ctxt->comp->stream, &resObj, 0); 14560 14561 if ((res != -1) && (resObj != NULL)) { 14562 valuePush(ctxt, resObj); 14563 return(0); 14564 } 14565 if (resObj != NULL) 14566 xmlXPathReleaseObject(ctxt->context, resObj); 14567 } 14568 /* 14569 * QUESTION TODO: This falls back to normal XPath evaluation 14570 * if res == -1. Is this intended? 14571 */ 14572 } 14573 #endif 14574 comp = ctxt->comp; 14575 if (comp->last < 0) { 14576 xmlGenericError(xmlGenericErrorContext, 14577 "xmlXPathRunEval: last is less than zero\n"); 14578 return(-1); 14579 } 14580 if (toBool) 14581 return(xmlXPathCompOpEvalToBoolean(ctxt, 14582 &comp->steps[comp->last], 0)); 14583 else 14584 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]); 14585 14586 return(0); 14587 } 14588 14589 /************************************************************************ 14590 * * 14591 * Public interfaces * 14592 * * 14593 ************************************************************************/ 14594 14595 /** 14596 * xmlXPathEvalPredicate: 14597 * @ctxt: the XPath context 14598 * @res: the Predicate Expression evaluation result 14599 * 14600 * Evaluate a predicate result for the current node. 14601 * A PredicateExpr is evaluated by evaluating the Expr and converting 14602 * the result to a boolean. If the result is a number, the result will 14603 * be converted to true if the number is equal to the position of the 14604 * context node in the context node list (as returned by the position 14605 * function) and will be converted to false otherwise; if the result 14606 * is not a number, then the result will be converted as if by a call 14607 * to the boolean function. 14608 * 14609 * Returns 1 if predicate is true, 0 otherwise 14610 */ 14611 int 14612 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) { 14613 if ((ctxt == NULL) || (res == NULL)) return(0); 14614 switch (res->type) { 14615 case XPATH_BOOLEAN: 14616 return(res->boolval); 14617 case XPATH_NUMBER: 14618 return(res->floatval == ctxt->proximityPosition); 14619 case XPATH_NODESET: 14620 case XPATH_XSLT_TREE: 14621 if (res->nodesetval == NULL) 14622 return(0); 14623 return(res->nodesetval->nodeNr != 0); 14624 case XPATH_STRING: 14625 return((res->stringval != NULL) && 14626 (xmlStrlen(res->stringval) != 0)); 14627 default: 14628 STRANGE 14629 } 14630 return(0); 14631 } 14632 14633 /** 14634 * xmlXPathEvaluatePredicateResult: 14635 * @ctxt: the XPath Parser context 14636 * @res: the Predicate Expression evaluation result 14637 * 14638 * Evaluate a predicate result for the current node. 14639 * A PredicateExpr is evaluated by evaluating the Expr and converting 14640 * the result to a boolean. If the result is a number, the result will 14641 * be converted to true if the number is equal to the position of the 14642 * context node in the context node list (as returned by the position 14643 * function) and will be converted to false otherwise; if the result 14644 * is not a number, then the result will be converted as if by a call 14645 * to the boolean function. 14646 * 14647 * Returns 1 if predicate is true, 0 otherwise 14648 */ 14649 int 14650 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt, 14651 xmlXPathObjectPtr res) { 14652 if ((ctxt == NULL) || (res == NULL)) return(0); 14653 switch (res->type) { 14654 case XPATH_BOOLEAN: 14655 return(res->boolval); 14656 case XPATH_NUMBER: 14657 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200)) 14658 return((res->floatval == ctxt->context->proximityPosition) && 14659 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/ 14660 #else 14661 return(res->floatval == ctxt->context->proximityPosition); 14662 #endif 14663 case XPATH_NODESET: 14664 case XPATH_XSLT_TREE: 14665 if (res->nodesetval == NULL) 14666 return(0); 14667 return(res->nodesetval->nodeNr != 0); 14668 case XPATH_STRING: 14669 return((res->stringval != NULL) && (res->stringval[0] != 0)); 14670 #ifdef LIBXML_XPTR_ENABLED 14671 case XPATH_LOCATIONSET:{ 14672 xmlLocationSetPtr ptr = res->user; 14673 if (ptr == NULL) 14674 return(0); 14675 return (ptr->locNr != 0); 14676 } 14677 #endif 14678 default: 14679 STRANGE 14680 } 14681 return(0); 14682 } 14683 14684 #ifdef XPATH_STREAMING 14685 /** 14686 * xmlXPathTryStreamCompile: 14687 * @ctxt: an XPath context 14688 * @str: the XPath expression 14689 * 14690 * Try to compile the XPath expression as a streamable subset. 14691 * 14692 * Returns the compiled expression or NULL if failed to compile. 14693 */ 14694 static xmlXPathCompExprPtr 14695 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { 14696 /* 14697 * Optimization: use streaming patterns when the XPath expression can 14698 * be compiled to a stream lookup 14699 */ 14700 xmlPatternPtr stream; 14701 xmlXPathCompExprPtr comp; 14702 xmlDictPtr dict = NULL; 14703 const xmlChar **namespaces = NULL; 14704 xmlNsPtr ns; 14705 int i, j; 14706 14707 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) && 14708 (!xmlStrchr(str, '@'))) { 14709 const xmlChar *tmp; 14710 14711 /* 14712 * We don't try to handle expressions using the verbose axis 14713 * specifiers ("::"), just the simplied form at this point. 14714 * Additionally, if there is no list of namespaces available and 14715 * there's a ":" in the expression, indicating a prefixed QName, 14716 * then we won't try to compile either. xmlPatterncompile() needs 14717 * to have a list of namespaces at compilation time in order to 14718 * compile prefixed name tests. 14719 */ 14720 tmp = xmlStrchr(str, ':'); 14721 if ((tmp != NULL) && 14722 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':'))) 14723 return(NULL); 14724 14725 if (ctxt != NULL) { 14726 dict = ctxt->dict; 14727 if (ctxt->nsNr > 0) { 14728 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*)); 14729 if (namespaces == NULL) { 14730 xmlXPathErrMemory(ctxt, "allocating namespaces array\n"); 14731 return(NULL); 14732 } 14733 for (i = 0, j = 0; (j < ctxt->nsNr); j++) { 14734 ns = ctxt->namespaces[j]; 14735 namespaces[i++] = ns->href; 14736 namespaces[i++] = ns->prefix; 14737 } 14738 namespaces[i++] = NULL; 14739 namespaces[i] = NULL; 14740 } 14741 } 14742 14743 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, 14744 &namespaces[0]); 14745 if (namespaces != NULL) { 14746 xmlFree((xmlChar **)namespaces); 14747 } 14748 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) { 14749 comp = xmlXPathNewCompExpr(); 14750 if (comp == NULL) { 14751 xmlXPathErrMemory(ctxt, "allocating streamable expression\n"); 14752 return(NULL); 14753 } 14754 comp->stream = stream; 14755 comp->dict = dict; 14756 if (comp->dict) 14757 xmlDictReference(comp->dict); 14758 return(comp); 14759 } 14760 xmlFreePattern(stream); 14761 } 14762 return(NULL); 14763 } 14764 #endif /* XPATH_STREAMING */ 14765 14766 static void 14767 xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op) 14768 { 14769 /* 14770 * Try to rewrite "descendant-or-self::node()/foo" to an optimized 14771 * internal representation. 14772 */ 14773 14774 if ((op->op == XPATH_OP_COLLECT /* 11 */) && 14775 (op->ch1 != -1) && 14776 (op->ch2 == -1 /* no predicate */)) 14777 { 14778 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1]; 14779 14780 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) && 14781 ((xmlXPathAxisVal) prevop->value == 14782 AXIS_DESCENDANT_OR_SELF) && 14783 (prevop->ch2 == -1) && 14784 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) && 14785 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE)) 14786 { 14787 /* 14788 * This is a "descendant-or-self::node()" without predicates. 14789 * Try to eliminate it. 14790 */ 14791 14792 switch ((xmlXPathAxisVal) op->value) { 14793 case AXIS_CHILD: 14794 case AXIS_DESCENDANT: 14795 /* 14796 * Convert "descendant-or-self::node()/child::" or 14797 * "descendant-or-self::node()/descendant::" to 14798 * "descendant::" 14799 */ 14800 op->ch1 = prevop->ch1; 14801 op->value = AXIS_DESCENDANT; 14802 break; 14803 case AXIS_SELF: 14804 case AXIS_DESCENDANT_OR_SELF: 14805 /* 14806 * Convert "descendant-or-self::node()/self::" or 14807 * "descendant-or-self::node()/descendant-or-self::" to 14808 * to "descendant-or-self::" 14809 */ 14810 op->ch1 = prevop->ch1; 14811 op->value = AXIS_DESCENDANT_OR_SELF; 14812 break; 14813 default: 14814 break; 14815 } 14816 } 14817 } 14818 14819 /* OP_VALUE has invalid ch1. */ 14820 if (op->op == XPATH_OP_VALUE) 14821 return; 14822 14823 /* Recurse */ 14824 if (op->ch1 != -1) 14825 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]); 14826 if (op->ch2 != -1) 14827 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]); 14828 } 14829 14830 /** 14831 * xmlXPathCtxtCompile: 14832 * @ctxt: an XPath context 14833 * @str: the XPath expression 14834 * 14835 * Compile an XPath expression 14836 * 14837 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL. 14838 * the caller has to free the object. 14839 */ 14840 xmlXPathCompExprPtr 14841 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { 14842 xmlXPathParserContextPtr pctxt; 14843 xmlXPathCompExprPtr comp; 14844 14845 #ifdef XPATH_STREAMING 14846 comp = xmlXPathTryStreamCompile(ctxt, str); 14847 if (comp != NULL) 14848 return(comp); 14849 #endif 14850 14851 xmlXPathInit(); 14852 14853 pctxt = xmlXPathNewParserContext(str, ctxt); 14854 if (pctxt == NULL) 14855 return NULL; 14856 xmlXPathCompileExpr(pctxt, 1); 14857 14858 if( pctxt->error != XPATH_EXPRESSION_OK ) 14859 { 14860 xmlXPathFreeParserContext(pctxt); 14861 return(NULL); 14862 } 14863 14864 if (*pctxt->cur != 0) { 14865 /* 14866 * aleksey: in some cases this line prints *second* error message 14867 * (see bug #78858) and probably this should be fixed. 14868 * However, we are not sure that all error messages are printed 14869 * out in other places. It's not critical so we leave it as-is for now 14870 */ 14871 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR); 14872 comp = NULL; 14873 } else { 14874 comp = pctxt->comp; 14875 pctxt->comp = NULL; 14876 } 14877 xmlXPathFreeParserContext(pctxt); 14878 14879 if (comp != NULL) { 14880 comp->expr = xmlStrdup(str); 14881 #ifdef DEBUG_EVAL_COUNTS 14882 comp->string = xmlStrdup(str); 14883 comp->nb = 0; 14884 #endif 14885 if ((comp->nbStep > 1) && (comp->last >= 0)) { 14886 xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]); 14887 } 14888 } 14889 return(comp); 14890 } 14891 14892 /** 14893 * xmlXPathCompile: 14894 * @str: the XPath expression 14895 * 14896 * Compile an XPath expression 14897 * 14898 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL. 14899 * the caller has to free the object. 14900 */ 14901 xmlXPathCompExprPtr 14902 xmlXPathCompile(const xmlChar *str) { 14903 return(xmlXPathCtxtCompile(NULL, str)); 14904 } 14905 14906 /** 14907 * xmlXPathCompiledEvalInternal: 14908 * @comp: the compiled XPath expression 14909 * @ctxt: the XPath context 14910 * @resObj: the resulting XPath object or NULL 14911 * @toBool: 1 if only a boolean result is requested 14912 * 14913 * Evaluate the Precompiled XPath expression in the given context. 14914 * The caller has to free @resObj. 14915 * 14916 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14917 * the caller has to free the object. 14918 */ 14919 static int 14920 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp, 14921 xmlXPathContextPtr ctxt, 14922 xmlXPathObjectPtr *resObjPtr, 14923 int toBool) 14924 { 14925 xmlXPathParserContextPtr pctxt; 14926 xmlXPathObjectPtr resObj; 14927 #ifndef LIBXML_THREAD_ENABLED 14928 static int reentance = 0; 14929 #endif 14930 int res; 14931 14932 CHECK_CTXT_NEG(ctxt) 14933 14934 if (comp == NULL) 14935 return(-1); 14936 xmlXPathInit(); 14937 14938 #ifndef LIBXML_THREAD_ENABLED 14939 reentance++; 14940 if (reentance > 1) 14941 xmlXPathDisableOptimizer = 1; 14942 #endif 14943 14944 #ifdef DEBUG_EVAL_COUNTS 14945 comp->nb++; 14946 if ((comp->string != NULL) && (comp->nb > 100)) { 14947 fprintf(stderr, "100 x %s\n", comp->string); 14948 comp->nb = 0; 14949 } 14950 #endif 14951 pctxt = xmlXPathCompParserContext(comp, ctxt); 14952 res = xmlXPathRunEval(pctxt, toBool); 14953 14954 if (pctxt->error != XPATH_EXPRESSION_OK) { 14955 resObj = NULL; 14956 } else { 14957 resObj = valuePop(pctxt); 14958 if (resObj == NULL) { 14959 if (!toBool) 14960 xmlGenericError(xmlGenericErrorContext, 14961 "xmlXPathCompiledEval: No result on the stack.\n"); 14962 } else if (pctxt->valueNr > 0) { 14963 xmlGenericError(xmlGenericErrorContext, 14964 "xmlXPathCompiledEval: %d object(s) left on the stack.\n", 14965 pctxt->valueNr); 14966 } 14967 } 14968 14969 if (resObjPtr) 14970 *resObjPtr = resObj; 14971 else 14972 xmlXPathReleaseObject(ctxt, resObj); 14973 14974 pctxt->comp = NULL; 14975 xmlXPathFreeParserContext(pctxt); 14976 #ifndef LIBXML_THREAD_ENABLED 14977 reentance--; 14978 #endif 14979 14980 return(res); 14981 } 14982 14983 /** 14984 * xmlXPathCompiledEval: 14985 * @comp: the compiled XPath expression 14986 * @ctx: the XPath context 14987 * 14988 * Evaluate the Precompiled XPath expression in the given context. 14989 * 14990 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14991 * the caller has to free the object. 14992 */ 14993 xmlXPathObjectPtr 14994 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) 14995 { 14996 xmlXPathObjectPtr res = NULL; 14997 14998 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0); 14999 return(res); 15000 } 15001 15002 /** 15003 * xmlXPathCompiledEvalToBoolean: 15004 * @comp: the compiled XPath expression 15005 * @ctxt: the XPath context 15006 * 15007 * Applies the XPath boolean() function on the result of the given 15008 * compiled expression. 15009 * 15010 * Returns 1 if the expression evaluated to true, 0 if to false and 15011 * -1 in API and internal errors. 15012 */ 15013 int 15014 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp, 15015 xmlXPathContextPtr ctxt) 15016 { 15017 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1)); 15018 } 15019 15020 /** 15021 * xmlXPathEvalExpr: 15022 * @ctxt: the XPath Parser context 15023 * 15024 * Parse and evaluate an XPath expression in the given context, 15025 * then push the result on the context stack 15026 */ 15027 void 15028 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) { 15029 #ifdef XPATH_STREAMING 15030 xmlXPathCompExprPtr comp; 15031 #endif 15032 15033 if (ctxt == NULL) return; 15034 15035 #ifdef XPATH_STREAMING 15036 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base); 15037 if (comp != NULL) { 15038 if (ctxt->comp != NULL) 15039 xmlXPathFreeCompExpr(ctxt->comp); 15040 ctxt->comp = comp; 15041 } else 15042 #endif 15043 { 15044 xmlXPathCompileExpr(ctxt, 1); 15045 CHECK_ERROR; 15046 15047 /* Check for trailing characters. */ 15048 if (*ctxt->cur != 0) 15049 XP_ERROR(XPATH_EXPR_ERROR); 15050 15051 if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) 15052 xmlXPathOptimizeExpression(ctxt->comp, 15053 &ctxt->comp->steps[ctxt->comp->last]); 15054 } 15055 15056 xmlXPathRunEval(ctxt, 0); 15057 } 15058 15059 /** 15060 * xmlXPathEval: 15061 * @str: the XPath expression 15062 * @ctx: the XPath context 15063 * 15064 * Evaluate the XPath Location Path in the given context. 15065 * 15066 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 15067 * the caller has to free the object. 15068 */ 15069 xmlXPathObjectPtr 15070 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) { 15071 xmlXPathParserContextPtr ctxt; 15072 xmlXPathObjectPtr res; 15073 15074 CHECK_CTXT(ctx) 15075 15076 xmlXPathInit(); 15077 15078 ctxt = xmlXPathNewParserContext(str, ctx); 15079 if (ctxt == NULL) 15080 return NULL; 15081 xmlXPathEvalExpr(ctxt); 15082 15083 if (ctxt->error != XPATH_EXPRESSION_OK) { 15084 res = NULL; 15085 } else { 15086 res = valuePop(ctxt); 15087 if (res == NULL) { 15088 xmlGenericError(xmlGenericErrorContext, 15089 "xmlXPathCompiledEval: No result on the stack.\n"); 15090 } else if (ctxt->valueNr > 0) { 15091 xmlGenericError(xmlGenericErrorContext, 15092 "xmlXPathCompiledEval: %d object(s) left on the stack.\n", 15093 ctxt->valueNr); 15094 } 15095 } 15096 15097 xmlXPathFreeParserContext(ctxt); 15098 return(res); 15099 } 15100 15101 /** 15102 * xmlXPathSetContextNode: 15103 * @node: the node to to use as the context node 15104 * @ctx: the XPath context 15105 * 15106 * Sets 'node' as the context node. The node must be in the same 15107 * document as that associated with the context. 15108 * 15109 * Returns -1 in case of error or 0 if successful 15110 */ 15111 int 15112 xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) { 15113 if ((node == NULL) || (ctx == NULL)) 15114 return(-1); 15115 15116 if (node->doc == ctx->doc) { 15117 ctx->node = node; 15118 return(0); 15119 } 15120 return(-1); 15121 } 15122 15123 /** 15124 * xmlXPathNodeEval: 15125 * @node: the node to to use as the context node 15126 * @str: the XPath expression 15127 * @ctx: the XPath context 15128 * 15129 * Evaluate the XPath Location Path in the given context. The node 'node' 15130 * is set as the context node. The context node is not restored. 15131 * 15132 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 15133 * the caller has to free the object. 15134 */ 15135 xmlXPathObjectPtr 15136 xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) { 15137 if (str == NULL) 15138 return(NULL); 15139 if (xmlXPathSetContextNode(node, ctx) < 0) 15140 return(NULL); 15141 return(xmlXPathEval(str, ctx)); 15142 } 15143 15144 /** 15145 * xmlXPathEvalExpression: 15146 * @str: the XPath expression 15147 * @ctxt: the XPath context 15148 * 15149 * Alias for xmlXPathEval(). 15150 * 15151 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 15152 * the caller has to free the object. 15153 */ 15154 xmlXPathObjectPtr 15155 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) { 15156 return(xmlXPathEval(str, ctxt)); 15157 } 15158 15159 /************************************************************************ 15160 * * 15161 * Extra functions not pertaining to the XPath spec * 15162 * * 15163 ************************************************************************/ 15164 /** 15165 * xmlXPathEscapeUriFunction: 15166 * @ctxt: the XPath Parser context 15167 * @nargs: the number of arguments 15168 * 15169 * Implement the escape-uri() XPath function 15170 * string escape-uri(string $str, bool $escape-reserved) 15171 * 15172 * This function applies the URI escaping rules defined in section 2 of [RFC 15173 * 2396] to the string supplied as $uri-part, which typically represents all 15174 * or part of a URI. The effect of the function is to replace any special 15175 * character in the string by an escape sequence of the form %xx%yy..., 15176 * where xxyy... is the hexadecimal representation of the octets used to 15177 * represent the character in UTF-8. 15178 * 15179 * The set of characters that are escaped depends on the setting of the 15180 * boolean argument $escape-reserved. 15181 * 15182 * If $escape-reserved is true, all characters are escaped other than lower 15183 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters 15184 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!" 15185 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only 15186 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and 15187 * A-F). 15188 * 15189 * If $escape-reserved is false, the behavior differs in that characters 15190 * referred to in [RFC 2396] as reserved characters are not escaped. These 15191 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",". 15192 * 15193 * [RFC 2396] does not define whether escaped URIs should use lower case or 15194 * upper case for hexadecimal digits. To ensure that escaped URIs can be 15195 * compared using string comparison functions, this function must always use 15196 * the upper-case letters A-F. 15197 * 15198 * Generally, $escape-reserved should be set to true when escaping a string 15199 * that is to form a single part of a URI, and to false when escaping an 15200 * entire URI or URI reference. 15201 * 15202 * In the case of non-ascii characters, the string is encoded according to 15203 * utf-8 and then converted according to RFC 2396. 15204 * 15205 * Examples 15206 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true()) 15207 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean" 15208 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false()) 15209 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean" 15210 * 15211 */ 15212 static void 15213 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) { 15214 xmlXPathObjectPtr str; 15215 int escape_reserved; 15216 xmlBufPtr target; 15217 xmlChar *cptr; 15218 xmlChar escape[4]; 15219 15220 CHECK_ARITY(2); 15221 15222 escape_reserved = xmlXPathPopBoolean(ctxt); 15223 15224 CAST_TO_STRING; 15225 str = valuePop(ctxt); 15226 15227 target = xmlBufCreate(); 15228 15229 escape[0] = '%'; 15230 escape[3] = 0; 15231 15232 if (target) { 15233 for (cptr = str->stringval; *cptr; cptr++) { 15234 if ((*cptr >= 'A' && *cptr <= 'Z') || 15235 (*cptr >= 'a' && *cptr <= 'z') || 15236 (*cptr >= '0' && *cptr <= '9') || 15237 *cptr == '-' || *cptr == '_' || *cptr == '.' || 15238 *cptr == '!' || *cptr == '~' || *cptr == '*' || 15239 *cptr == '\''|| *cptr == '(' || *cptr == ')' || 15240 (*cptr == '%' && 15241 ((cptr[1] >= 'A' && cptr[1] <= 'F') || 15242 (cptr[1] >= 'a' && cptr[1] <= 'f') || 15243 (cptr[1] >= '0' && cptr[1] <= '9')) && 15244 ((cptr[2] >= 'A' && cptr[2] <= 'F') || 15245 (cptr[2] >= 'a' && cptr[2] <= 'f') || 15246 (cptr[2] >= '0' && cptr[2] <= '9'))) || 15247 (!escape_reserved && 15248 (*cptr == ';' || *cptr == '/' || *cptr == '?' || 15249 *cptr == ':' || *cptr == '@' || *cptr == '&' || 15250 *cptr == '=' || *cptr == '+' || *cptr == '$' || 15251 *cptr == ','))) { 15252 xmlBufAdd(target, cptr, 1); 15253 } else { 15254 if ((*cptr >> 4) < 10) 15255 escape[1] = '0' + (*cptr >> 4); 15256 else 15257 escape[1] = 'A' - 10 + (*cptr >> 4); 15258 if ((*cptr & 0xF) < 10) 15259 escape[2] = '0' + (*cptr & 0xF); 15260 else 15261 escape[2] = 'A' - 10 + (*cptr & 0xF); 15262 15263 xmlBufAdd(target, &escape[0], 3); 15264 } 15265 } 15266 } 15267 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 15268 xmlBufContent(target))); 15269 xmlBufFree(target); 15270 xmlXPathReleaseObject(ctxt->context, str); 15271 } 15272 15273 /** 15274 * xmlXPathRegisterAllFunctions: 15275 * @ctxt: the XPath context 15276 * 15277 * Registers all default XPath functions in this context 15278 */ 15279 void 15280 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt) 15281 { 15282 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean", 15283 xmlXPathBooleanFunction); 15284 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling", 15285 xmlXPathCeilingFunction); 15286 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count", 15287 xmlXPathCountFunction); 15288 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat", 15289 xmlXPathConcatFunction); 15290 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains", 15291 xmlXPathContainsFunction); 15292 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id", 15293 xmlXPathIdFunction); 15294 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false", 15295 xmlXPathFalseFunction); 15296 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor", 15297 xmlXPathFloorFunction); 15298 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last", 15299 xmlXPathLastFunction); 15300 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang", 15301 xmlXPathLangFunction); 15302 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name", 15303 xmlXPathLocalNameFunction); 15304 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not", 15305 xmlXPathNotFunction); 15306 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name", 15307 xmlXPathNameFunction); 15308 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri", 15309 xmlXPathNamespaceURIFunction); 15310 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space", 15311 xmlXPathNormalizeFunction); 15312 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number", 15313 xmlXPathNumberFunction); 15314 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position", 15315 xmlXPathPositionFunction); 15316 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round", 15317 xmlXPathRoundFunction); 15318 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string", 15319 xmlXPathStringFunction); 15320 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length", 15321 xmlXPathStringLengthFunction); 15322 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with", 15323 xmlXPathStartsWithFunction); 15324 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring", 15325 xmlXPathSubstringFunction); 15326 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before", 15327 xmlXPathSubstringBeforeFunction); 15328 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after", 15329 xmlXPathSubstringAfterFunction); 15330 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum", 15331 xmlXPathSumFunction); 15332 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true", 15333 xmlXPathTrueFunction); 15334 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate", 15335 xmlXPathTranslateFunction); 15336 15337 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri", 15338 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions", 15339 xmlXPathEscapeUriFunction); 15340 } 15341 15342 #endif /* LIBXML_XPATH_ENABLED */ 15343 #define bottom_xpath 15344 #include "elfgcchack.h" 15345