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 * 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 available. 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 available. 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 algorithm 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 INFINITY 481 #define INFINITY (DBL_MAX * DBL_MAX) 482 #endif 483 484 #ifndef NAN 485 #define NAN (INFINITY / INFINITY) 486 #endif 487 488 double xmlXPathNAN; 489 double xmlXPathPINF; 490 double xmlXPathNINF; 491 492 /** 493 * xmlXPathInit: 494 * 495 * Initialize the XPath environment 496 */ 497 void 498 xmlXPathInit(void) { 499 xmlXPathNAN = NAN; 500 xmlXPathPINF = INFINITY; 501 xmlXPathNINF = -INFINITY; 502 } 503 504 /** 505 * xmlXPathIsNaN: 506 * @val: a double value 507 * 508 * Returns 1 if the value is a NaN, 0 otherwise 509 */ 510 int 511 xmlXPathIsNaN(double val) { 512 #ifdef isnan 513 return isnan(val); 514 #else 515 return !(val == val); 516 #endif 517 } 518 519 /** 520 * xmlXPathIsInf: 521 * @val: a double value 522 * 523 * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise 524 */ 525 int 526 xmlXPathIsInf(double val) { 527 #ifdef isinf 528 return isinf(val) ? (val > 0 ? 1 : -1) : 0; 529 #else 530 if (val >= INFINITY) 531 return 1; 532 if (val <= -INFINITY) 533 return -1; 534 return 0; 535 #endif 536 } 537 538 #endif /* SCHEMAS or XPATH */ 539 540 #ifdef LIBXML_XPATH_ENABLED 541 542 /* 543 * TODO: when compatibility allows remove all "fake node libxslt" strings 544 * the test should just be name[0] = ' ' 545 */ 546 #ifdef DEBUG_XPATH_EXPRESSION 547 #define DEBUG_STEP 548 #define DEBUG_EXPR 549 #define DEBUG_EVAL_COUNTS 550 #endif 551 552 static xmlNs xmlXPathXMLNamespaceStruct = { 553 NULL, 554 XML_NAMESPACE_DECL, 555 XML_XML_NAMESPACE, 556 BAD_CAST "xml", 557 NULL, 558 NULL 559 }; 560 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct; 561 #ifndef LIBXML_THREAD_ENABLED 562 /* 563 * Optimizer is disabled only when threaded apps are detected while 564 * the library ain't compiled for thread safety. 565 */ 566 static int xmlXPathDisableOptimizer = 0; 567 #endif 568 569 /************************************************************************ 570 * * 571 * Error handling routines * 572 * * 573 ************************************************************************/ 574 575 /** 576 * XP_ERRORNULL: 577 * @X: the error code 578 * 579 * Macro to raise an XPath error and return NULL. 580 */ 581 #define XP_ERRORNULL(X) \ 582 { xmlXPathErr(ctxt, X); return(NULL); } 583 584 /* 585 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError 586 */ 587 static const char *xmlXPathErrorMessages[] = { 588 "Ok\n", 589 "Number encoding\n", 590 "Unfinished literal\n", 591 "Start of literal\n", 592 "Expected $ for variable reference\n", 593 "Undefined variable\n", 594 "Invalid predicate\n", 595 "Invalid expression\n", 596 "Missing closing curly brace\n", 597 "Unregistered function\n", 598 "Invalid operand\n", 599 "Invalid type\n", 600 "Invalid number of arguments\n", 601 "Invalid context size\n", 602 "Invalid context position\n", 603 "Memory allocation error\n", 604 "Syntax error\n", 605 "Resource error\n", 606 "Sub resource error\n", 607 "Undefined namespace prefix\n", 608 "Encoding error\n", 609 "Char out of XML range\n", 610 "Invalid or incomplete context\n", 611 "Stack usage error\n", 612 "Forbidden variable\n", 613 "Operation limit exceeded\n", 614 "Recursion limit exceeded\n", 615 "?? Unknown error ??\n" /* Must be last in the list! */ 616 }; 617 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \ 618 sizeof(xmlXPathErrorMessages[0])) - 1) 619 /** 620 * xmlXPathErrMemory: 621 * @ctxt: an XPath context 622 * @extra: extra informations 623 * 624 * Handle a redefinition of attribute error 625 */ 626 static void 627 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra) 628 { 629 if (ctxt != NULL) { 630 xmlResetError(&ctxt->lastError); 631 if (extra) { 632 xmlChar buf[200]; 633 634 xmlStrPrintf(buf, 200, 635 "Memory allocation failed : %s\n", 636 extra); 637 ctxt->lastError.message = (char *) xmlStrdup(buf); 638 } else { 639 ctxt->lastError.message = (char *) 640 xmlStrdup(BAD_CAST "Memory allocation failed\n"); 641 } 642 ctxt->lastError.domain = XML_FROM_XPATH; 643 ctxt->lastError.code = XML_ERR_NO_MEMORY; 644 if (ctxt->error != NULL) 645 ctxt->error(ctxt->userData, &ctxt->lastError); 646 } else { 647 if (extra) 648 __xmlRaiseError(NULL, NULL, NULL, 649 NULL, NULL, XML_FROM_XPATH, 650 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, 651 extra, NULL, NULL, 0, 0, 652 "Memory allocation failed : %s\n", extra); 653 else 654 __xmlRaiseError(NULL, NULL, NULL, 655 NULL, NULL, XML_FROM_XPATH, 656 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, 657 NULL, NULL, NULL, 0, 0, 658 "Memory allocation failed\n"); 659 } 660 } 661 662 /** 663 * xmlXPathPErrMemory: 664 * @ctxt: an XPath parser context 665 * @extra: extra informations 666 * 667 * Handle a redefinition of attribute error 668 */ 669 static void 670 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra) 671 { 672 if (ctxt == NULL) 673 xmlXPathErrMemory(NULL, extra); 674 else { 675 ctxt->error = XPATH_MEMORY_ERROR; 676 xmlXPathErrMemory(ctxt->context, extra); 677 } 678 } 679 680 /** 681 * xmlXPathErr: 682 * @ctxt: a XPath parser context 683 * @error: the error code 684 * 685 * Handle an XPath error 686 */ 687 void 688 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error) 689 { 690 if ((error < 0) || (error > MAXERRNO)) 691 error = MAXERRNO; 692 if (ctxt == NULL) { 693 __xmlRaiseError(NULL, NULL, NULL, 694 NULL, NULL, XML_FROM_XPATH, 695 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, 696 XML_ERR_ERROR, NULL, 0, 697 NULL, NULL, NULL, 0, 0, 698 "%s", xmlXPathErrorMessages[error]); 699 return; 700 } 701 ctxt->error = error; 702 if (ctxt->context == NULL) { 703 __xmlRaiseError(NULL, NULL, NULL, 704 NULL, NULL, XML_FROM_XPATH, 705 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, 706 XML_ERR_ERROR, NULL, 0, 707 (const char *) ctxt->base, NULL, NULL, 708 ctxt->cur - ctxt->base, 0, 709 "%s", xmlXPathErrorMessages[error]); 710 return; 711 } 712 713 /* cleanup current last error */ 714 xmlResetError(&ctxt->context->lastError); 715 716 ctxt->context->lastError.domain = XML_FROM_XPATH; 717 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK - 718 XPATH_EXPRESSION_OK; 719 ctxt->context->lastError.level = XML_ERR_ERROR; 720 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base); 721 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base; 722 ctxt->context->lastError.node = ctxt->context->debugNode; 723 if (ctxt->context->error != NULL) { 724 ctxt->context->error(ctxt->context->userData, 725 &ctxt->context->lastError); 726 } else { 727 __xmlRaiseError(NULL, NULL, NULL, 728 NULL, ctxt->context->debugNode, XML_FROM_XPATH, 729 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, 730 XML_ERR_ERROR, NULL, 0, 731 (const char *) ctxt->base, NULL, NULL, 732 ctxt->cur - ctxt->base, 0, 733 "%s", xmlXPathErrorMessages[error]); 734 } 735 736 } 737 738 /** 739 * xmlXPatherror: 740 * @ctxt: the XPath Parser context 741 * @file: the file name 742 * @line: the line number 743 * @no: the error number 744 * 745 * Formats an error message. 746 */ 747 void 748 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED, 749 int line ATTRIBUTE_UNUSED, int no) { 750 xmlXPathErr(ctxt, no); 751 } 752 753 /** 754 * xmlXPathCheckOpLimit: 755 * @ctxt: the XPath Parser context 756 * @opCount: the number of operations to be added 757 * 758 * Adds opCount to the running total of operations and returns -1 if the 759 * operation limit is exceeded. Returns 0 otherwise. 760 */ 761 static int 762 xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) { 763 xmlXPathContextPtr xpctxt = ctxt->context; 764 765 if ((opCount > xpctxt->opLimit) || 766 (xpctxt->opCount > xpctxt->opLimit - opCount)) { 767 xpctxt->opCount = xpctxt->opLimit; 768 xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED); 769 return(-1); 770 } 771 772 xpctxt->opCount += opCount; 773 return(0); 774 } 775 776 #define OP_LIMIT_EXCEEDED(ctxt, n) \ 777 ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0)) 778 779 /************************************************************************ 780 * * 781 * Utilities * 782 * * 783 ************************************************************************/ 784 785 /** 786 * xsltPointerList: 787 * 788 * Pointer-list for various purposes. 789 */ 790 typedef struct _xmlPointerList xmlPointerList; 791 typedef xmlPointerList *xmlPointerListPtr; 792 struct _xmlPointerList { 793 void **items; 794 int number; 795 int size; 796 }; 797 /* 798 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt 799 * and here, we should make the functions public. 800 */ 801 static int 802 xmlPointerListAddSize(xmlPointerListPtr list, 803 void *item, 804 int initialSize) 805 { 806 if (list->items == NULL) { 807 if (initialSize <= 0) 808 initialSize = 1; 809 list->items = (void **) xmlMalloc(initialSize * sizeof(void *)); 810 if (list->items == NULL) { 811 xmlXPathErrMemory(NULL, 812 "xmlPointerListCreate: allocating item\n"); 813 return(-1); 814 } 815 list->number = 0; 816 list->size = initialSize; 817 } else if (list->size <= list->number) { 818 if (list->size > 50000000) { 819 xmlXPathErrMemory(NULL, 820 "xmlPointerListAddSize: re-allocating item\n"); 821 return(-1); 822 } 823 list->size *= 2; 824 list->items = (void **) xmlRealloc(list->items, 825 list->size * sizeof(void *)); 826 if (list->items == NULL) { 827 xmlXPathErrMemory(NULL, 828 "xmlPointerListAddSize: re-allocating item\n"); 829 list->size = 0; 830 return(-1); 831 } 832 } 833 list->items[list->number++] = item; 834 return(0); 835 } 836 837 /** 838 * xsltPointerListCreate: 839 * 840 * Creates an xsltPointerList structure. 841 * 842 * Returns a xsltPointerList structure or NULL in case of an error. 843 */ 844 static xmlPointerListPtr 845 xmlPointerListCreate(int initialSize) 846 { 847 xmlPointerListPtr ret; 848 849 ret = xmlMalloc(sizeof(xmlPointerList)); 850 if (ret == NULL) { 851 xmlXPathErrMemory(NULL, 852 "xmlPointerListCreate: allocating item\n"); 853 return (NULL); 854 } 855 memset(ret, 0, sizeof(xmlPointerList)); 856 if (initialSize > 0) { 857 xmlPointerListAddSize(ret, NULL, initialSize); 858 ret->number = 0; 859 } 860 return (ret); 861 } 862 863 /** 864 * xsltPointerListFree: 865 * 866 * Frees the xsltPointerList structure. This does not free 867 * the content of the list. 868 */ 869 static void 870 xmlPointerListFree(xmlPointerListPtr list) 871 { 872 if (list == NULL) 873 return; 874 if (list->items != NULL) 875 xmlFree(list->items); 876 xmlFree(list); 877 } 878 879 /************************************************************************ 880 * * 881 * Parser Types * 882 * * 883 ************************************************************************/ 884 885 /* 886 * Types are private: 887 */ 888 889 typedef enum { 890 XPATH_OP_END=0, 891 XPATH_OP_AND, 892 XPATH_OP_OR, 893 XPATH_OP_EQUAL, 894 XPATH_OP_CMP, 895 XPATH_OP_PLUS, 896 XPATH_OP_MULT, 897 XPATH_OP_UNION, 898 XPATH_OP_ROOT, 899 XPATH_OP_NODE, 900 XPATH_OP_COLLECT, 901 XPATH_OP_VALUE, /* 11 */ 902 XPATH_OP_VARIABLE, 903 XPATH_OP_FUNCTION, 904 XPATH_OP_ARG, 905 XPATH_OP_PREDICATE, 906 XPATH_OP_FILTER, /* 16 */ 907 XPATH_OP_SORT /* 17 */ 908 #ifdef LIBXML_XPTR_ENABLED 909 ,XPATH_OP_RANGETO 910 #endif 911 } xmlXPathOp; 912 913 typedef enum { 914 AXIS_ANCESTOR = 1, 915 AXIS_ANCESTOR_OR_SELF, 916 AXIS_ATTRIBUTE, 917 AXIS_CHILD, 918 AXIS_DESCENDANT, 919 AXIS_DESCENDANT_OR_SELF, 920 AXIS_FOLLOWING, 921 AXIS_FOLLOWING_SIBLING, 922 AXIS_NAMESPACE, 923 AXIS_PARENT, 924 AXIS_PRECEDING, 925 AXIS_PRECEDING_SIBLING, 926 AXIS_SELF 927 } xmlXPathAxisVal; 928 929 typedef enum { 930 NODE_TEST_NONE = 0, 931 NODE_TEST_TYPE = 1, 932 NODE_TEST_PI = 2, 933 NODE_TEST_ALL = 3, 934 NODE_TEST_NS = 4, 935 NODE_TEST_NAME = 5 936 } xmlXPathTestVal; 937 938 typedef enum { 939 NODE_TYPE_NODE = 0, 940 NODE_TYPE_COMMENT = XML_COMMENT_NODE, 941 NODE_TYPE_TEXT = XML_TEXT_NODE, 942 NODE_TYPE_PI = XML_PI_NODE 943 } xmlXPathTypeVal; 944 945 typedef struct _xmlXPathStepOp xmlXPathStepOp; 946 typedef xmlXPathStepOp *xmlXPathStepOpPtr; 947 struct _xmlXPathStepOp { 948 xmlXPathOp op; /* The identifier of the operation */ 949 int ch1; /* First child */ 950 int ch2; /* Second child */ 951 int value; 952 int value2; 953 int value3; 954 void *value4; 955 void *value5; 956 xmlXPathFunction cache; 957 void *cacheURI; 958 }; 959 960 struct _xmlXPathCompExpr { 961 int nbStep; /* Number of steps in this expression */ 962 int maxStep; /* Maximum number of steps allocated */ 963 xmlXPathStepOp *steps; /* ops for computation of this expression */ 964 int last; /* index of last step in expression */ 965 xmlChar *expr; /* the expression being computed */ 966 xmlDictPtr dict; /* the dictionary to use if any */ 967 #ifdef DEBUG_EVAL_COUNTS 968 int nb; 969 xmlChar *string; 970 #endif 971 #ifdef XPATH_STREAMING 972 xmlPatternPtr stream; 973 #endif 974 }; 975 976 /************************************************************************ 977 * * 978 * Forward declarations * 979 * * 980 ************************************************************************/ 981 static void 982 xmlXPathFreeValueTree(xmlNodeSetPtr obj); 983 static void 984 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj); 985 static int 986 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt, 987 xmlXPathStepOpPtr op, xmlNodePtr *first); 988 static int 989 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt, 990 xmlXPathStepOpPtr op, 991 int isPredicate); 992 static void 993 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name); 994 995 /************************************************************************ 996 * * 997 * Parser Type functions * 998 * * 999 ************************************************************************/ 1000 1001 /** 1002 * xmlXPathNewCompExpr: 1003 * 1004 * Create a new Xpath component 1005 * 1006 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error 1007 */ 1008 static xmlXPathCompExprPtr 1009 xmlXPathNewCompExpr(void) { 1010 xmlXPathCompExprPtr cur; 1011 1012 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr)); 1013 if (cur == NULL) { 1014 xmlXPathErrMemory(NULL, "allocating component\n"); 1015 return(NULL); 1016 } 1017 memset(cur, 0, sizeof(xmlXPathCompExpr)); 1018 cur->maxStep = 10; 1019 cur->nbStep = 0; 1020 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep * 1021 sizeof(xmlXPathStepOp)); 1022 if (cur->steps == NULL) { 1023 xmlXPathErrMemory(NULL, "allocating steps\n"); 1024 xmlFree(cur); 1025 return(NULL); 1026 } 1027 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp)); 1028 cur->last = -1; 1029 #ifdef DEBUG_EVAL_COUNTS 1030 cur->nb = 0; 1031 #endif 1032 return(cur); 1033 } 1034 1035 /** 1036 * xmlXPathFreeCompExpr: 1037 * @comp: an XPATH comp 1038 * 1039 * Free up the memory allocated by @comp 1040 */ 1041 void 1042 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp) 1043 { 1044 xmlXPathStepOpPtr op; 1045 int i; 1046 1047 if (comp == NULL) 1048 return; 1049 if (comp->dict == NULL) { 1050 for (i = 0; i < comp->nbStep; i++) { 1051 op = &comp->steps[i]; 1052 if (op->value4 != NULL) { 1053 if (op->op == XPATH_OP_VALUE) 1054 xmlXPathFreeObject(op->value4); 1055 else 1056 xmlFree(op->value4); 1057 } 1058 if (op->value5 != NULL) 1059 xmlFree(op->value5); 1060 } 1061 } else { 1062 for (i = 0; i < comp->nbStep; i++) { 1063 op = &comp->steps[i]; 1064 if (op->value4 != NULL) { 1065 if (op->op == XPATH_OP_VALUE) 1066 xmlXPathFreeObject(op->value4); 1067 } 1068 } 1069 xmlDictFree(comp->dict); 1070 } 1071 if (comp->steps != NULL) { 1072 xmlFree(comp->steps); 1073 } 1074 #ifdef DEBUG_EVAL_COUNTS 1075 if (comp->string != NULL) { 1076 xmlFree(comp->string); 1077 } 1078 #endif 1079 #ifdef XPATH_STREAMING 1080 if (comp->stream != NULL) { 1081 xmlFreePatternList(comp->stream); 1082 } 1083 #endif 1084 if (comp->expr != NULL) { 1085 xmlFree(comp->expr); 1086 } 1087 1088 xmlFree(comp); 1089 } 1090 1091 /** 1092 * xmlXPathCompExprAdd: 1093 * @comp: the compiled expression 1094 * @ch1: first child index 1095 * @ch2: second child index 1096 * @op: an op 1097 * @value: the first int value 1098 * @value2: the second int value 1099 * @value3: the third int value 1100 * @value4: the first string value 1101 * @value5: the second string value 1102 * 1103 * Add a step to an XPath Compiled Expression 1104 * 1105 * Returns -1 in case of failure, the index otherwise 1106 */ 1107 static int 1108 xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2, 1109 xmlXPathOp op, int value, 1110 int value2, int value3, void *value4, void *value5) { 1111 xmlXPathCompExprPtr comp = ctxt->comp; 1112 if (comp->nbStep >= comp->maxStep) { 1113 xmlXPathStepOp *real; 1114 1115 if (comp->maxStep >= XPATH_MAX_STEPS) { 1116 xmlXPathPErrMemory(ctxt, "adding step\n"); 1117 return(-1); 1118 } 1119 comp->maxStep *= 2; 1120 real = (xmlXPathStepOp *) xmlRealloc(comp->steps, 1121 comp->maxStep * sizeof(xmlXPathStepOp)); 1122 if (real == NULL) { 1123 comp->maxStep /= 2; 1124 xmlXPathPErrMemory(ctxt, "adding step\n"); 1125 return(-1); 1126 } 1127 comp->steps = real; 1128 } 1129 comp->last = comp->nbStep; 1130 comp->steps[comp->nbStep].ch1 = ch1; 1131 comp->steps[comp->nbStep].ch2 = ch2; 1132 comp->steps[comp->nbStep].op = op; 1133 comp->steps[comp->nbStep].value = value; 1134 comp->steps[comp->nbStep].value2 = value2; 1135 comp->steps[comp->nbStep].value3 = value3; 1136 if ((comp->dict != NULL) && 1137 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) || 1138 (op == XPATH_OP_COLLECT))) { 1139 if (value4 != NULL) { 1140 comp->steps[comp->nbStep].value4 = (xmlChar *) 1141 (void *)xmlDictLookup(comp->dict, value4, -1); 1142 xmlFree(value4); 1143 } else 1144 comp->steps[comp->nbStep].value4 = NULL; 1145 if (value5 != NULL) { 1146 comp->steps[comp->nbStep].value5 = (xmlChar *) 1147 (void *)xmlDictLookup(comp->dict, value5, -1); 1148 xmlFree(value5); 1149 } else 1150 comp->steps[comp->nbStep].value5 = NULL; 1151 } else { 1152 comp->steps[comp->nbStep].value4 = value4; 1153 comp->steps[comp->nbStep].value5 = value5; 1154 } 1155 comp->steps[comp->nbStep].cache = NULL; 1156 return(comp->nbStep++); 1157 } 1158 1159 /** 1160 * xmlXPathCompSwap: 1161 * @comp: the compiled expression 1162 * @op: operation index 1163 * 1164 * Swaps 2 operations in the compiled expression 1165 */ 1166 static void 1167 xmlXPathCompSwap(xmlXPathStepOpPtr op) { 1168 int tmp; 1169 1170 #ifndef LIBXML_THREAD_ENABLED 1171 /* 1172 * Since this manipulates possibly shared variables, this is 1173 * disabled if one detects that the library is used in a multithreaded 1174 * application 1175 */ 1176 if (xmlXPathDisableOptimizer) 1177 return; 1178 #endif 1179 1180 tmp = op->ch1; 1181 op->ch1 = op->ch2; 1182 op->ch2 = tmp; 1183 } 1184 1185 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \ 1186 xmlXPathCompExprAdd(ctxt, (op1), (op2), \ 1187 (op), (val), (val2), (val3), (val4), (val5)) 1188 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \ 1189 xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1, \ 1190 (op), (val), (val2), (val3), (val4), (val5)) 1191 1192 #define PUSH_LEAVE_EXPR(op, val, val2) \ 1193 xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL) 1194 1195 #define PUSH_UNARY_EXPR(op, ch, val, val2) \ 1196 xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL) 1197 1198 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \ 1199 xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op), \ 1200 (val), (val2), 0 ,NULL ,NULL) 1201 1202 /************************************************************************ 1203 * * 1204 * XPath object cache structures * 1205 * * 1206 ************************************************************************/ 1207 1208 /* #define XP_DEFAULT_CACHE_ON */ 1209 1210 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL)) 1211 1212 typedef struct _xmlXPathContextCache xmlXPathContextCache; 1213 typedef xmlXPathContextCache *xmlXPathContextCachePtr; 1214 struct _xmlXPathContextCache { 1215 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */ 1216 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */ 1217 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */ 1218 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */ 1219 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */ 1220 int maxNodeset; 1221 int maxString; 1222 int maxBoolean; 1223 int maxNumber; 1224 int maxMisc; 1225 #ifdef XP_DEBUG_OBJ_USAGE 1226 int dbgCachedAll; 1227 int dbgCachedNodeset; 1228 int dbgCachedString; 1229 int dbgCachedBool; 1230 int dbgCachedNumber; 1231 int dbgCachedPoint; 1232 int dbgCachedRange; 1233 int dbgCachedLocset; 1234 int dbgCachedUsers; 1235 int dbgCachedXSLTTree; 1236 int dbgCachedUndefined; 1237 1238 1239 int dbgReusedAll; 1240 int dbgReusedNodeset; 1241 int dbgReusedString; 1242 int dbgReusedBool; 1243 int dbgReusedNumber; 1244 int dbgReusedPoint; 1245 int dbgReusedRange; 1246 int dbgReusedLocset; 1247 int dbgReusedUsers; 1248 int dbgReusedXSLTTree; 1249 int dbgReusedUndefined; 1250 1251 #endif 1252 }; 1253 1254 /************************************************************************ 1255 * * 1256 * Debugging related functions * 1257 * * 1258 ************************************************************************/ 1259 1260 #define STRANGE \ 1261 xmlGenericError(xmlGenericErrorContext, \ 1262 "Internal error at %s:%d\n", \ 1263 __FILE__, __LINE__); 1264 1265 #ifdef LIBXML_DEBUG_ENABLED 1266 static void 1267 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) { 1268 int i; 1269 char shift[100]; 1270 1271 for (i = 0;((i < depth) && (i < 25));i++) 1272 shift[2 * i] = shift[2 * i + 1] = ' '; 1273 shift[2 * i] = shift[2 * i + 1] = 0; 1274 if (cur == NULL) { 1275 fprintf(output, "%s", shift); 1276 fprintf(output, "Node is NULL !\n"); 1277 return; 1278 1279 } 1280 1281 if ((cur->type == XML_DOCUMENT_NODE) || 1282 (cur->type == XML_HTML_DOCUMENT_NODE)) { 1283 fprintf(output, "%s", shift); 1284 fprintf(output, " /\n"); 1285 } else if (cur->type == XML_ATTRIBUTE_NODE) 1286 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth); 1287 else 1288 xmlDebugDumpOneNode(output, cur, depth); 1289 } 1290 static void 1291 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) { 1292 xmlNodePtr tmp; 1293 int i; 1294 char shift[100]; 1295 1296 for (i = 0;((i < depth) && (i < 25));i++) 1297 shift[2 * i] = shift[2 * i + 1] = ' '; 1298 shift[2 * i] = shift[2 * i + 1] = 0; 1299 if (cur == NULL) { 1300 fprintf(output, "%s", shift); 1301 fprintf(output, "Node is NULL !\n"); 1302 return; 1303 1304 } 1305 1306 while (cur != NULL) { 1307 tmp = cur; 1308 cur = cur->next; 1309 xmlDebugDumpOneNode(output, tmp, depth); 1310 } 1311 } 1312 1313 static void 1314 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) { 1315 int i; 1316 char shift[100]; 1317 1318 for (i = 0;((i < depth) && (i < 25));i++) 1319 shift[2 * i] = shift[2 * i + 1] = ' '; 1320 shift[2 * i] = shift[2 * i + 1] = 0; 1321 1322 if (cur == NULL) { 1323 fprintf(output, "%s", shift); 1324 fprintf(output, "NodeSet is NULL !\n"); 1325 return; 1326 1327 } 1328 1329 if (cur != NULL) { 1330 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr); 1331 for (i = 0;i < cur->nodeNr;i++) { 1332 fprintf(output, "%s", shift); 1333 fprintf(output, "%d", i + 1); 1334 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1); 1335 } 1336 } 1337 } 1338 1339 static void 1340 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) { 1341 int i; 1342 char shift[100]; 1343 1344 for (i = 0;((i < depth) && (i < 25));i++) 1345 shift[2 * i] = shift[2 * i + 1] = ' '; 1346 shift[2 * i] = shift[2 * i + 1] = 0; 1347 1348 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) { 1349 fprintf(output, "%s", shift); 1350 fprintf(output, "Value Tree is NULL !\n"); 1351 return; 1352 1353 } 1354 1355 fprintf(output, "%s", shift); 1356 fprintf(output, "%d", i + 1); 1357 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1); 1358 } 1359 #if defined(LIBXML_XPTR_ENABLED) 1360 static void 1361 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) { 1362 int i; 1363 char shift[100]; 1364 1365 for (i = 0;((i < depth) && (i < 25));i++) 1366 shift[2 * i] = shift[2 * i + 1] = ' '; 1367 shift[2 * i] = shift[2 * i + 1] = 0; 1368 1369 if (cur == NULL) { 1370 fprintf(output, "%s", shift); 1371 fprintf(output, "LocationSet is NULL !\n"); 1372 return; 1373 1374 } 1375 1376 for (i = 0;i < cur->locNr;i++) { 1377 fprintf(output, "%s", shift); 1378 fprintf(output, "%d : ", i + 1); 1379 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1); 1380 } 1381 } 1382 #endif /* LIBXML_XPTR_ENABLED */ 1383 1384 /** 1385 * xmlXPathDebugDumpObject: 1386 * @output: the FILE * to dump the output 1387 * @cur: the object to inspect 1388 * @depth: indentation level 1389 * 1390 * Dump the content of the object for debugging purposes 1391 */ 1392 void 1393 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) { 1394 int i; 1395 char shift[100]; 1396 1397 if (output == NULL) return; 1398 1399 for (i = 0;((i < depth) && (i < 25));i++) 1400 shift[2 * i] = shift[2 * i + 1] = ' '; 1401 shift[2 * i] = shift[2 * i + 1] = 0; 1402 1403 1404 fprintf(output, "%s", shift); 1405 1406 if (cur == NULL) { 1407 fprintf(output, "Object is empty (NULL)\n"); 1408 return; 1409 } 1410 switch(cur->type) { 1411 case XPATH_UNDEFINED: 1412 fprintf(output, "Object is uninitialized\n"); 1413 break; 1414 case XPATH_NODESET: 1415 fprintf(output, "Object is a Node Set :\n"); 1416 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth); 1417 break; 1418 case XPATH_XSLT_TREE: 1419 fprintf(output, "Object is an XSLT value tree :\n"); 1420 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth); 1421 break; 1422 case XPATH_BOOLEAN: 1423 fprintf(output, "Object is a Boolean : "); 1424 if (cur->boolval) fprintf(output, "true\n"); 1425 else fprintf(output, "false\n"); 1426 break; 1427 case XPATH_NUMBER: 1428 switch (xmlXPathIsInf(cur->floatval)) { 1429 case 1: 1430 fprintf(output, "Object is a number : Infinity\n"); 1431 break; 1432 case -1: 1433 fprintf(output, "Object is a number : -Infinity\n"); 1434 break; 1435 default: 1436 if (xmlXPathIsNaN(cur->floatval)) { 1437 fprintf(output, "Object is a number : NaN\n"); 1438 } else if (cur->floatval == 0) { 1439 /* Omit sign for negative zero. */ 1440 fprintf(output, "Object is a number : 0\n"); 1441 } else { 1442 fprintf(output, "Object is a number : %0g\n", cur->floatval); 1443 } 1444 } 1445 break; 1446 case XPATH_STRING: 1447 fprintf(output, "Object is a string : "); 1448 xmlDebugDumpString(output, cur->stringval); 1449 fprintf(output, "\n"); 1450 break; 1451 case XPATH_POINT: 1452 fprintf(output, "Object is a point : index %d in node", cur->index); 1453 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1); 1454 fprintf(output, "\n"); 1455 break; 1456 case XPATH_RANGE: 1457 if ((cur->user2 == NULL) || 1458 ((cur->user2 == cur->user) && (cur->index == cur->index2))) { 1459 fprintf(output, "Object is a collapsed range :\n"); 1460 fprintf(output, "%s", shift); 1461 if (cur->index >= 0) 1462 fprintf(output, "index %d in ", cur->index); 1463 fprintf(output, "node\n"); 1464 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, 1465 depth + 1); 1466 } else { 1467 fprintf(output, "Object is a range :\n"); 1468 fprintf(output, "%s", shift); 1469 fprintf(output, "From "); 1470 if (cur->index >= 0) 1471 fprintf(output, "index %d in ", cur->index); 1472 fprintf(output, "node\n"); 1473 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, 1474 depth + 1); 1475 fprintf(output, "%s", shift); 1476 fprintf(output, "To "); 1477 if (cur->index2 >= 0) 1478 fprintf(output, "index %d in ", cur->index2); 1479 fprintf(output, "node\n"); 1480 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2, 1481 depth + 1); 1482 fprintf(output, "\n"); 1483 } 1484 break; 1485 case XPATH_LOCATIONSET: 1486 #if defined(LIBXML_XPTR_ENABLED) 1487 fprintf(output, "Object is a Location Set:\n"); 1488 xmlXPathDebugDumpLocationSet(output, 1489 (xmlLocationSetPtr) cur->user, depth); 1490 #endif 1491 break; 1492 case XPATH_USERS: 1493 fprintf(output, "Object is user defined\n"); 1494 break; 1495 } 1496 } 1497 1498 static void 1499 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp, 1500 xmlXPathStepOpPtr op, int depth) { 1501 int i; 1502 char shift[100]; 1503 1504 for (i = 0;((i < depth) && (i < 25));i++) 1505 shift[2 * i] = shift[2 * i + 1] = ' '; 1506 shift[2 * i] = shift[2 * i + 1] = 0; 1507 1508 fprintf(output, "%s", shift); 1509 if (op == NULL) { 1510 fprintf(output, "Step is NULL\n"); 1511 return; 1512 } 1513 switch (op->op) { 1514 case XPATH_OP_END: 1515 fprintf(output, "END"); break; 1516 case XPATH_OP_AND: 1517 fprintf(output, "AND"); break; 1518 case XPATH_OP_OR: 1519 fprintf(output, "OR"); break; 1520 case XPATH_OP_EQUAL: 1521 if (op->value) 1522 fprintf(output, "EQUAL ="); 1523 else 1524 fprintf(output, "EQUAL !="); 1525 break; 1526 case XPATH_OP_CMP: 1527 if (op->value) 1528 fprintf(output, "CMP <"); 1529 else 1530 fprintf(output, "CMP >"); 1531 if (!op->value2) 1532 fprintf(output, "="); 1533 break; 1534 case XPATH_OP_PLUS: 1535 if (op->value == 0) 1536 fprintf(output, "PLUS -"); 1537 else if (op->value == 1) 1538 fprintf(output, "PLUS +"); 1539 else if (op->value == 2) 1540 fprintf(output, "PLUS unary -"); 1541 else if (op->value == 3) 1542 fprintf(output, "PLUS unary - -"); 1543 break; 1544 case XPATH_OP_MULT: 1545 if (op->value == 0) 1546 fprintf(output, "MULT *"); 1547 else if (op->value == 1) 1548 fprintf(output, "MULT div"); 1549 else 1550 fprintf(output, "MULT mod"); 1551 break; 1552 case XPATH_OP_UNION: 1553 fprintf(output, "UNION"); break; 1554 case XPATH_OP_ROOT: 1555 fprintf(output, "ROOT"); break; 1556 case XPATH_OP_NODE: 1557 fprintf(output, "NODE"); break; 1558 case XPATH_OP_SORT: 1559 fprintf(output, "SORT"); break; 1560 case XPATH_OP_COLLECT: { 1561 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value; 1562 xmlXPathTestVal test = (xmlXPathTestVal)op->value2; 1563 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3; 1564 const xmlChar *prefix = op->value4; 1565 const xmlChar *name = op->value5; 1566 1567 fprintf(output, "COLLECT "); 1568 switch (axis) { 1569 case AXIS_ANCESTOR: 1570 fprintf(output, " 'ancestors' "); break; 1571 case AXIS_ANCESTOR_OR_SELF: 1572 fprintf(output, " 'ancestors-or-self' "); break; 1573 case AXIS_ATTRIBUTE: 1574 fprintf(output, " 'attributes' "); break; 1575 case AXIS_CHILD: 1576 fprintf(output, " 'child' "); break; 1577 case AXIS_DESCENDANT: 1578 fprintf(output, " 'descendant' "); break; 1579 case AXIS_DESCENDANT_OR_SELF: 1580 fprintf(output, " 'descendant-or-self' "); break; 1581 case AXIS_FOLLOWING: 1582 fprintf(output, " 'following' "); break; 1583 case AXIS_FOLLOWING_SIBLING: 1584 fprintf(output, " 'following-siblings' "); break; 1585 case AXIS_NAMESPACE: 1586 fprintf(output, " 'namespace' "); break; 1587 case AXIS_PARENT: 1588 fprintf(output, " 'parent' "); break; 1589 case AXIS_PRECEDING: 1590 fprintf(output, " 'preceding' "); break; 1591 case AXIS_PRECEDING_SIBLING: 1592 fprintf(output, " 'preceding-sibling' "); break; 1593 case AXIS_SELF: 1594 fprintf(output, " 'self' "); break; 1595 } 1596 switch (test) { 1597 case NODE_TEST_NONE: 1598 fprintf(output, "'none' "); break; 1599 case NODE_TEST_TYPE: 1600 fprintf(output, "'type' "); break; 1601 case NODE_TEST_PI: 1602 fprintf(output, "'PI' "); break; 1603 case NODE_TEST_ALL: 1604 fprintf(output, "'all' "); break; 1605 case NODE_TEST_NS: 1606 fprintf(output, "'namespace' "); break; 1607 case NODE_TEST_NAME: 1608 fprintf(output, "'name' "); break; 1609 } 1610 switch (type) { 1611 case NODE_TYPE_NODE: 1612 fprintf(output, "'node' "); break; 1613 case NODE_TYPE_COMMENT: 1614 fprintf(output, "'comment' "); break; 1615 case NODE_TYPE_TEXT: 1616 fprintf(output, "'text' "); break; 1617 case NODE_TYPE_PI: 1618 fprintf(output, "'PI' "); break; 1619 } 1620 if (prefix != NULL) 1621 fprintf(output, "%s:", prefix); 1622 if (name != NULL) 1623 fprintf(output, "%s", (const char *) name); 1624 break; 1625 1626 } 1627 case XPATH_OP_VALUE: { 1628 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4; 1629 1630 fprintf(output, "ELEM "); 1631 xmlXPathDebugDumpObject(output, object, 0); 1632 goto finish; 1633 } 1634 case XPATH_OP_VARIABLE: { 1635 const xmlChar *prefix = op->value5; 1636 const xmlChar *name = op->value4; 1637 1638 if (prefix != NULL) 1639 fprintf(output, "VARIABLE %s:%s", prefix, name); 1640 else 1641 fprintf(output, "VARIABLE %s", name); 1642 break; 1643 } 1644 case XPATH_OP_FUNCTION: { 1645 int nbargs = op->value; 1646 const xmlChar *prefix = op->value5; 1647 const xmlChar *name = op->value4; 1648 1649 if (prefix != NULL) 1650 fprintf(output, "FUNCTION %s:%s(%d args)", 1651 prefix, name, nbargs); 1652 else 1653 fprintf(output, "FUNCTION %s(%d args)", name, nbargs); 1654 break; 1655 } 1656 case XPATH_OP_ARG: fprintf(output, "ARG"); break; 1657 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break; 1658 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break; 1659 #ifdef LIBXML_XPTR_ENABLED 1660 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break; 1661 #endif 1662 default: 1663 fprintf(output, "UNKNOWN %d\n", op->op); return; 1664 } 1665 fprintf(output, "\n"); 1666 finish: 1667 if (op->ch1 >= 0) 1668 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1); 1669 if (op->ch2 >= 0) 1670 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1); 1671 } 1672 1673 /** 1674 * xmlXPathDebugDumpCompExpr: 1675 * @output: the FILE * for the output 1676 * @comp: the precompiled XPath expression 1677 * @depth: the indentation level. 1678 * 1679 * Dumps the tree of the compiled XPath expression. 1680 */ 1681 void 1682 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp, 1683 int depth) { 1684 int i; 1685 char shift[100]; 1686 1687 if ((output == NULL) || (comp == NULL)) return; 1688 1689 for (i = 0;((i < depth) && (i < 25));i++) 1690 shift[2 * i] = shift[2 * i + 1] = ' '; 1691 shift[2 * i] = shift[2 * i + 1] = 0; 1692 1693 fprintf(output, "%s", shift); 1694 1695 #ifdef XPATH_STREAMING 1696 if (comp->stream) { 1697 fprintf(output, "Streaming Expression\n"); 1698 } else 1699 #endif 1700 { 1701 fprintf(output, "Compiled Expression : %d elements\n", 1702 comp->nbStep); 1703 i = comp->last; 1704 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1); 1705 } 1706 } 1707 1708 #ifdef XP_DEBUG_OBJ_USAGE 1709 1710 /* 1711 * XPath object usage related debugging variables. 1712 */ 1713 static int xmlXPathDebugObjCounterUndefined = 0; 1714 static int xmlXPathDebugObjCounterNodeset = 0; 1715 static int xmlXPathDebugObjCounterBool = 0; 1716 static int xmlXPathDebugObjCounterNumber = 0; 1717 static int xmlXPathDebugObjCounterString = 0; 1718 static int xmlXPathDebugObjCounterPoint = 0; 1719 static int xmlXPathDebugObjCounterRange = 0; 1720 static int xmlXPathDebugObjCounterLocset = 0; 1721 static int xmlXPathDebugObjCounterUsers = 0; 1722 static int xmlXPathDebugObjCounterXSLTTree = 0; 1723 static int xmlXPathDebugObjCounterAll = 0; 1724 1725 static int xmlXPathDebugObjTotalUndefined = 0; 1726 static int xmlXPathDebugObjTotalNodeset = 0; 1727 static int xmlXPathDebugObjTotalBool = 0; 1728 static int xmlXPathDebugObjTotalNumber = 0; 1729 static int xmlXPathDebugObjTotalString = 0; 1730 static int xmlXPathDebugObjTotalPoint = 0; 1731 static int xmlXPathDebugObjTotalRange = 0; 1732 static int xmlXPathDebugObjTotalLocset = 0; 1733 static int xmlXPathDebugObjTotalUsers = 0; 1734 static int xmlXPathDebugObjTotalXSLTTree = 0; 1735 static int xmlXPathDebugObjTotalAll = 0; 1736 1737 static int xmlXPathDebugObjMaxUndefined = 0; 1738 static int xmlXPathDebugObjMaxNodeset = 0; 1739 static int xmlXPathDebugObjMaxBool = 0; 1740 static int xmlXPathDebugObjMaxNumber = 0; 1741 static int xmlXPathDebugObjMaxString = 0; 1742 static int xmlXPathDebugObjMaxPoint = 0; 1743 static int xmlXPathDebugObjMaxRange = 0; 1744 static int xmlXPathDebugObjMaxLocset = 0; 1745 static int xmlXPathDebugObjMaxUsers = 0; 1746 static int xmlXPathDebugObjMaxXSLTTree = 0; 1747 static int xmlXPathDebugObjMaxAll = 0; 1748 1749 /* REVISIT TODO: Make this static when committing */ 1750 static void 1751 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt) 1752 { 1753 if (ctxt != NULL) { 1754 if (ctxt->cache != NULL) { 1755 xmlXPathContextCachePtr cache = 1756 (xmlXPathContextCachePtr) ctxt->cache; 1757 1758 cache->dbgCachedAll = 0; 1759 cache->dbgCachedNodeset = 0; 1760 cache->dbgCachedString = 0; 1761 cache->dbgCachedBool = 0; 1762 cache->dbgCachedNumber = 0; 1763 cache->dbgCachedPoint = 0; 1764 cache->dbgCachedRange = 0; 1765 cache->dbgCachedLocset = 0; 1766 cache->dbgCachedUsers = 0; 1767 cache->dbgCachedXSLTTree = 0; 1768 cache->dbgCachedUndefined = 0; 1769 1770 cache->dbgReusedAll = 0; 1771 cache->dbgReusedNodeset = 0; 1772 cache->dbgReusedString = 0; 1773 cache->dbgReusedBool = 0; 1774 cache->dbgReusedNumber = 0; 1775 cache->dbgReusedPoint = 0; 1776 cache->dbgReusedRange = 0; 1777 cache->dbgReusedLocset = 0; 1778 cache->dbgReusedUsers = 0; 1779 cache->dbgReusedXSLTTree = 0; 1780 cache->dbgReusedUndefined = 0; 1781 } 1782 } 1783 1784 xmlXPathDebugObjCounterUndefined = 0; 1785 xmlXPathDebugObjCounterNodeset = 0; 1786 xmlXPathDebugObjCounterBool = 0; 1787 xmlXPathDebugObjCounterNumber = 0; 1788 xmlXPathDebugObjCounterString = 0; 1789 xmlXPathDebugObjCounterPoint = 0; 1790 xmlXPathDebugObjCounterRange = 0; 1791 xmlXPathDebugObjCounterLocset = 0; 1792 xmlXPathDebugObjCounterUsers = 0; 1793 xmlXPathDebugObjCounterXSLTTree = 0; 1794 xmlXPathDebugObjCounterAll = 0; 1795 1796 xmlXPathDebugObjTotalUndefined = 0; 1797 xmlXPathDebugObjTotalNodeset = 0; 1798 xmlXPathDebugObjTotalBool = 0; 1799 xmlXPathDebugObjTotalNumber = 0; 1800 xmlXPathDebugObjTotalString = 0; 1801 xmlXPathDebugObjTotalPoint = 0; 1802 xmlXPathDebugObjTotalRange = 0; 1803 xmlXPathDebugObjTotalLocset = 0; 1804 xmlXPathDebugObjTotalUsers = 0; 1805 xmlXPathDebugObjTotalXSLTTree = 0; 1806 xmlXPathDebugObjTotalAll = 0; 1807 1808 xmlXPathDebugObjMaxUndefined = 0; 1809 xmlXPathDebugObjMaxNodeset = 0; 1810 xmlXPathDebugObjMaxBool = 0; 1811 xmlXPathDebugObjMaxNumber = 0; 1812 xmlXPathDebugObjMaxString = 0; 1813 xmlXPathDebugObjMaxPoint = 0; 1814 xmlXPathDebugObjMaxRange = 0; 1815 xmlXPathDebugObjMaxLocset = 0; 1816 xmlXPathDebugObjMaxUsers = 0; 1817 xmlXPathDebugObjMaxXSLTTree = 0; 1818 xmlXPathDebugObjMaxAll = 0; 1819 1820 } 1821 1822 static void 1823 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt, 1824 xmlXPathObjectType objType) 1825 { 1826 int isCached = 0; 1827 1828 if (ctxt != NULL) { 1829 if (ctxt->cache != NULL) { 1830 xmlXPathContextCachePtr cache = 1831 (xmlXPathContextCachePtr) ctxt->cache; 1832 1833 isCached = 1; 1834 1835 cache->dbgReusedAll++; 1836 switch (objType) { 1837 case XPATH_UNDEFINED: 1838 cache->dbgReusedUndefined++; 1839 break; 1840 case XPATH_NODESET: 1841 cache->dbgReusedNodeset++; 1842 break; 1843 case XPATH_BOOLEAN: 1844 cache->dbgReusedBool++; 1845 break; 1846 case XPATH_NUMBER: 1847 cache->dbgReusedNumber++; 1848 break; 1849 case XPATH_STRING: 1850 cache->dbgReusedString++; 1851 break; 1852 case XPATH_POINT: 1853 cache->dbgReusedPoint++; 1854 break; 1855 case XPATH_RANGE: 1856 cache->dbgReusedRange++; 1857 break; 1858 case XPATH_LOCATIONSET: 1859 cache->dbgReusedLocset++; 1860 break; 1861 case XPATH_USERS: 1862 cache->dbgReusedUsers++; 1863 break; 1864 case XPATH_XSLT_TREE: 1865 cache->dbgReusedXSLTTree++; 1866 break; 1867 default: 1868 break; 1869 } 1870 } 1871 } 1872 1873 switch (objType) { 1874 case XPATH_UNDEFINED: 1875 if (! isCached) 1876 xmlXPathDebugObjTotalUndefined++; 1877 xmlXPathDebugObjCounterUndefined++; 1878 if (xmlXPathDebugObjCounterUndefined > 1879 xmlXPathDebugObjMaxUndefined) 1880 xmlXPathDebugObjMaxUndefined = 1881 xmlXPathDebugObjCounterUndefined; 1882 break; 1883 case XPATH_NODESET: 1884 if (! isCached) 1885 xmlXPathDebugObjTotalNodeset++; 1886 xmlXPathDebugObjCounterNodeset++; 1887 if (xmlXPathDebugObjCounterNodeset > 1888 xmlXPathDebugObjMaxNodeset) 1889 xmlXPathDebugObjMaxNodeset = 1890 xmlXPathDebugObjCounterNodeset; 1891 break; 1892 case XPATH_BOOLEAN: 1893 if (! isCached) 1894 xmlXPathDebugObjTotalBool++; 1895 xmlXPathDebugObjCounterBool++; 1896 if (xmlXPathDebugObjCounterBool > 1897 xmlXPathDebugObjMaxBool) 1898 xmlXPathDebugObjMaxBool = 1899 xmlXPathDebugObjCounterBool; 1900 break; 1901 case XPATH_NUMBER: 1902 if (! isCached) 1903 xmlXPathDebugObjTotalNumber++; 1904 xmlXPathDebugObjCounterNumber++; 1905 if (xmlXPathDebugObjCounterNumber > 1906 xmlXPathDebugObjMaxNumber) 1907 xmlXPathDebugObjMaxNumber = 1908 xmlXPathDebugObjCounterNumber; 1909 break; 1910 case XPATH_STRING: 1911 if (! isCached) 1912 xmlXPathDebugObjTotalString++; 1913 xmlXPathDebugObjCounterString++; 1914 if (xmlXPathDebugObjCounterString > 1915 xmlXPathDebugObjMaxString) 1916 xmlXPathDebugObjMaxString = 1917 xmlXPathDebugObjCounterString; 1918 break; 1919 case XPATH_POINT: 1920 if (! isCached) 1921 xmlXPathDebugObjTotalPoint++; 1922 xmlXPathDebugObjCounterPoint++; 1923 if (xmlXPathDebugObjCounterPoint > 1924 xmlXPathDebugObjMaxPoint) 1925 xmlXPathDebugObjMaxPoint = 1926 xmlXPathDebugObjCounterPoint; 1927 break; 1928 case XPATH_RANGE: 1929 if (! isCached) 1930 xmlXPathDebugObjTotalRange++; 1931 xmlXPathDebugObjCounterRange++; 1932 if (xmlXPathDebugObjCounterRange > 1933 xmlXPathDebugObjMaxRange) 1934 xmlXPathDebugObjMaxRange = 1935 xmlXPathDebugObjCounterRange; 1936 break; 1937 case XPATH_LOCATIONSET: 1938 if (! isCached) 1939 xmlXPathDebugObjTotalLocset++; 1940 xmlXPathDebugObjCounterLocset++; 1941 if (xmlXPathDebugObjCounterLocset > 1942 xmlXPathDebugObjMaxLocset) 1943 xmlXPathDebugObjMaxLocset = 1944 xmlXPathDebugObjCounterLocset; 1945 break; 1946 case XPATH_USERS: 1947 if (! isCached) 1948 xmlXPathDebugObjTotalUsers++; 1949 xmlXPathDebugObjCounterUsers++; 1950 if (xmlXPathDebugObjCounterUsers > 1951 xmlXPathDebugObjMaxUsers) 1952 xmlXPathDebugObjMaxUsers = 1953 xmlXPathDebugObjCounterUsers; 1954 break; 1955 case XPATH_XSLT_TREE: 1956 if (! isCached) 1957 xmlXPathDebugObjTotalXSLTTree++; 1958 xmlXPathDebugObjCounterXSLTTree++; 1959 if (xmlXPathDebugObjCounterXSLTTree > 1960 xmlXPathDebugObjMaxXSLTTree) 1961 xmlXPathDebugObjMaxXSLTTree = 1962 xmlXPathDebugObjCounterXSLTTree; 1963 break; 1964 default: 1965 break; 1966 } 1967 if (! isCached) 1968 xmlXPathDebugObjTotalAll++; 1969 xmlXPathDebugObjCounterAll++; 1970 if (xmlXPathDebugObjCounterAll > 1971 xmlXPathDebugObjMaxAll) 1972 xmlXPathDebugObjMaxAll = 1973 xmlXPathDebugObjCounterAll; 1974 } 1975 1976 static void 1977 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt, 1978 xmlXPathObjectType objType) 1979 { 1980 int isCached = 0; 1981 1982 if (ctxt != NULL) { 1983 if (ctxt->cache != NULL) { 1984 xmlXPathContextCachePtr cache = 1985 (xmlXPathContextCachePtr) ctxt->cache; 1986 1987 isCached = 1; 1988 1989 cache->dbgCachedAll++; 1990 switch (objType) { 1991 case XPATH_UNDEFINED: 1992 cache->dbgCachedUndefined++; 1993 break; 1994 case XPATH_NODESET: 1995 cache->dbgCachedNodeset++; 1996 break; 1997 case XPATH_BOOLEAN: 1998 cache->dbgCachedBool++; 1999 break; 2000 case XPATH_NUMBER: 2001 cache->dbgCachedNumber++; 2002 break; 2003 case XPATH_STRING: 2004 cache->dbgCachedString++; 2005 break; 2006 case XPATH_POINT: 2007 cache->dbgCachedPoint++; 2008 break; 2009 case XPATH_RANGE: 2010 cache->dbgCachedRange++; 2011 break; 2012 case XPATH_LOCATIONSET: 2013 cache->dbgCachedLocset++; 2014 break; 2015 case XPATH_USERS: 2016 cache->dbgCachedUsers++; 2017 break; 2018 case XPATH_XSLT_TREE: 2019 cache->dbgCachedXSLTTree++; 2020 break; 2021 default: 2022 break; 2023 } 2024 2025 } 2026 } 2027 switch (objType) { 2028 case XPATH_UNDEFINED: 2029 xmlXPathDebugObjCounterUndefined--; 2030 break; 2031 case XPATH_NODESET: 2032 xmlXPathDebugObjCounterNodeset--; 2033 break; 2034 case XPATH_BOOLEAN: 2035 xmlXPathDebugObjCounterBool--; 2036 break; 2037 case XPATH_NUMBER: 2038 xmlXPathDebugObjCounterNumber--; 2039 break; 2040 case XPATH_STRING: 2041 xmlXPathDebugObjCounterString--; 2042 break; 2043 case XPATH_POINT: 2044 xmlXPathDebugObjCounterPoint--; 2045 break; 2046 case XPATH_RANGE: 2047 xmlXPathDebugObjCounterRange--; 2048 break; 2049 case XPATH_LOCATIONSET: 2050 xmlXPathDebugObjCounterLocset--; 2051 break; 2052 case XPATH_USERS: 2053 xmlXPathDebugObjCounterUsers--; 2054 break; 2055 case XPATH_XSLT_TREE: 2056 xmlXPathDebugObjCounterXSLTTree--; 2057 break; 2058 default: 2059 break; 2060 } 2061 xmlXPathDebugObjCounterAll--; 2062 } 2063 2064 /* REVISIT TODO: Make this static when committing */ 2065 static void 2066 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt) 2067 { 2068 int reqAll, reqNodeset, reqString, reqBool, reqNumber, 2069 reqXSLTTree, reqUndefined; 2070 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0, 2071 caNumber = 0, caXSLTTree = 0, caUndefined = 0; 2072 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0, 2073 reNumber = 0, reXSLTTree = 0, reUndefined = 0; 2074 int leftObjs = xmlXPathDebugObjCounterAll; 2075 2076 reqAll = xmlXPathDebugObjTotalAll; 2077 reqNodeset = xmlXPathDebugObjTotalNodeset; 2078 reqString = xmlXPathDebugObjTotalString; 2079 reqBool = xmlXPathDebugObjTotalBool; 2080 reqNumber = xmlXPathDebugObjTotalNumber; 2081 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree; 2082 reqUndefined = xmlXPathDebugObjTotalUndefined; 2083 2084 printf("# XPath object usage:\n"); 2085 2086 if (ctxt != NULL) { 2087 if (ctxt->cache != NULL) { 2088 xmlXPathContextCachePtr cache = 2089 (xmlXPathContextCachePtr) ctxt->cache; 2090 2091 reAll = cache->dbgReusedAll; 2092 reqAll += reAll; 2093 reNodeset = cache->dbgReusedNodeset; 2094 reqNodeset += reNodeset; 2095 reString = cache->dbgReusedString; 2096 reqString += reString; 2097 reBool = cache->dbgReusedBool; 2098 reqBool += reBool; 2099 reNumber = cache->dbgReusedNumber; 2100 reqNumber += reNumber; 2101 reXSLTTree = cache->dbgReusedXSLTTree; 2102 reqXSLTTree += reXSLTTree; 2103 reUndefined = cache->dbgReusedUndefined; 2104 reqUndefined += reUndefined; 2105 2106 caAll = cache->dbgCachedAll; 2107 caBool = cache->dbgCachedBool; 2108 caNodeset = cache->dbgCachedNodeset; 2109 caString = cache->dbgCachedString; 2110 caNumber = cache->dbgCachedNumber; 2111 caXSLTTree = cache->dbgCachedXSLTTree; 2112 caUndefined = cache->dbgCachedUndefined; 2113 2114 if (cache->nodesetObjs) 2115 leftObjs -= cache->nodesetObjs->number; 2116 if (cache->stringObjs) 2117 leftObjs -= cache->stringObjs->number; 2118 if (cache->booleanObjs) 2119 leftObjs -= cache->booleanObjs->number; 2120 if (cache->numberObjs) 2121 leftObjs -= cache->numberObjs->number; 2122 if (cache->miscObjs) 2123 leftObjs -= cache->miscObjs->number; 2124 } 2125 } 2126 2127 printf("# all\n"); 2128 printf("# total : %d\n", reqAll); 2129 printf("# left : %d\n", leftObjs); 2130 printf("# created: %d\n", xmlXPathDebugObjTotalAll); 2131 printf("# reused : %d\n", reAll); 2132 printf("# max : %d\n", xmlXPathDebugObjMaxAll); 2133 2134 printf("# node-sets\n"); 2135 printf("# total : %d\n", reqNodeset); 2136 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset); 2137 printf("# reused : %d\n", reNodeset); 2138 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset); 2139 2140 printf("# strings\n"); 2141 printf("# total : %d\n", reqString); 2142 printf("# created: %d\n", xmlXPathDebugObjTotalString); 2143 printf("# reused : %d\n", reString); 2144 printf("# max : %d\n", xmlXPathDebugObjMaxString); 2145 2146 printf("# booleans\n"); 2147 printf("# total : %d\n", reqBool); 2148 printf("# created: %d\n", xmlXPathDebugObjTotalBool); 2149 printf("# reused : %d\n", reBool); 2150 printf("# max : %d\n", xmlXPathDebugObjMaxBool); 2151 2152 printf("# numbers\n"); 2153 printf("# total : %d\n", reqNumber); 2154 printf("# created: %d\n", xmlXPathDebugObjTotalNumber); 2155 printf("# reused : %d\n", reNumber); 2156 printf("# max : %d\n", xmlXPathDebugObjMaxNumber); 2157 2158 printf("# XSLT result tree fragments\n"); 2159 printf("# total : %d\n", reqXSLTTree); 2160 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree); 2161 printf("# reused : %d\n", reXSLTTree); 2162 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree); 2163 2164 printf("# undefined\n"); 2165 printf("# total : %d\n", reqUndefined); 2166 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined); 2167 printf("# reused : %d\n", reUndefined); 2168 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined); 2169 2170 } 2171 2172 #endif /* XP_DEBUG_OBJ_USAGE */ 2173 2174 #endif /* LIBXML_DEBUG_ENABLED */ 2175 2176 /************************************************************************ 2177 * * 2178 * XPath object caching * 2179 * * 2180 ************************************************************************/ 2181 2182 /** 2183 * xmlXPathNewCache: 2184 * 2185 * Create a new object cache 2186 * 2187 * Returns the xmlXPathCache just allocated. 2188 */ 2189 static xmlXPathContextCachePtr 2190 xmlXPathNewCache(void) 2191 { 2192 xmlXPathContextCachePtr ret; 2193 2194 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache)); 2195 if (ret == NULL) { 2196 xmlXPathErrMemory(NULL, "creating object cache\n"); 2197 return(NULL); 2198 } 2199 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache)); 2200 ret->maxNodeset = 100; 2201 ret->maxString = 100; 2202 ret->maxBoolean = 100; 2203 ret->maxNumber = 100; 2204 ret->maxMisc = 100; 2205 return(ret); 2206 } 2207 2208 static void 2209 xmlXPathCacheFreeObjectList(xmlPointerListPtr list) 2210 { 2211 int i; 2212 xmlXPathObjectPtr obj; 2213 2214 if (list == NULL) 2215 return; 2216 2217 for (i = 0; i < list->number; i++) { 2218 obj = list->items[i]; 2219 /* 2220 * Note that it is already assured that we don't need to 2221 * look out for namespace nodes in the node-set. 2222 */ 2223 if (obj->nodesetval != NULL) { 2224 if (obj->nodesetval->nodeTab != NULL) 2225 xmlFree(obj->nodesetval->nodeTab); 2226 xmlFree(obj->nodesetval); 2227 } 2228 xmlFree(obj); 2229 #ifdef XP_DEBUG_OBJ_USAGE 2230 xmlXPathDebugObjCounterAll--; 2231 #endif 2232 } 2233 xmlPointerListFree(list); 2234 } 2235 2236 static void 2237 xmlXPathFreeCache(xmlXPathContextCachePtr cache) 2238 { 2239 if (cache == NULL) 2240 return; 2241 if (cache->nodesetObjs) 2242 xmlXPathCacheFreeObjectList(cache->nodesetObjs); 2243 if (cache->stringObjs) 2244 xmlXPathCacheFreeObjectList(cache->stringObjs); 2245 if (cache->booleanObjs) 2246 xmlXPathCacheFreeObjectList(cache->booleanObjs); 2247 if (cache->numberObjs) 2248 xmlXPathCacheFreeObjectList(cache->numberObjs); 2249 if (cache->miscObjs) 2250 xmlXPathCacheFreeObjectList(cache->miscObjs); 2251 xmlFree(cache); 2252 } 2253 2254 /** 2255 * xmlXPathContextSetCache: 2256 * 2257 * @ctxt: the XPath context 2258 * @active: enables/disables (creates/frees) the cache 2259 * @value: a value with semantics dependent on @options 2260 * @options: options (currently only the value 0 is used) 2261 * 2262 * Creates/frees an object cache on the XPath context. 2263 * If activates XPath objects (xmlXPathObject) will be cached internally 2264 * to be reused. 2265 * @options: 2266 * 0: This will set the XPath object caching: 2267 * @value: 2268 * This will set the maximum number of XPath objects 2269 * to be cached per slot 2270 * There are 5 slots for: node-set, string, number, boolean, and 2271 * misc objects. Use <0 for the default number (100). 2272 * Other values for @options have currently no effect. 2273 * 2274 * Returns 0 if the setting succeeded, and -1 on API or internal errors. 2275 */ 2276 int 2277 xmlXPathContextSetCache(xmlXPathContextPtr ctxt, 2278 int active, 2279 int value, 2280 int options) 2281 { 2282 if (ctxt == NULL) 2283 return(-1); 2284 if (active) { 2285 xmlXPathContextCachePtr cache; 2286 2287 if (ctxt->cache == NULL) { 2288 ctxt->cache = xmlXPathNewCache(); 2289 if (ctxt->cache == NULL) 2290 return(-1); 2291 } 2292 cache = (xmlXPathContextCachePtr) ctxt->cache; 2293 if (options == 0) { 2294 if (value < 0) 2295 value = 100; 2296 cache->maxNodeset = value; 2297 cache->maxString = value; 2298 cache->maxNumber = value; 2299 cache->maxBoolean = value; 2300 cache->maxMisc = value; 2301 } 2302 } else if (ctxt->cache != NULL) { 2303 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache); 2304 ctxt->cache = NULL; 2305 } 2306 return(0); 2307 } 2308 2309 /** 2310 * xmlXPathCacheWrapNodeSet: 2311 * @ctxt: the XPath context 2312 * @val: the NodePtr value 2313 * 2314 * This is the cached version of xmlXPathWrapNodeSet(). 2315 * Wrap the Nodeset @val in a new xmlXPathObjectPtr 2316 * 2317 * Returns the created or reused object. 2318 */ 2319 static xmlXPathObjectPtr 2320 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val) 2321 { 2322 if ((ctxt != NULL) && (ctxt->cache != NULL)) { 2323 xmlXPathContextCachePtr cache = 2324 (xmlXPathContextCachePtr) ctxt->cache; 2325 2326 if ((cache->miscObjs != NULL) && 2327 (cache->miscObjs->number != 0)) 2328 { 2329 xmlXPathObjectPtr ret; 2330 2331 ret = (xmlXPathObjectPtr) 2332 cache->miscObjs->items[--cache->miscObjs->number]; 2333 ret->type = XPATH_NODESET; 2334 ret->nodesetval = val; 2335 #ifdef XP_DEBUG_OBJ_USAGE 2336 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 2337 #endif 2338 return(ret); 2339 } 2340 } 2341 2342 return(xmlXPathWrapNodeSet(val)); 2343 2344 } 2345 2346 /** 2347 * xmlXPathCacheWrapString: 2348 * @ctxt: the XPath context 2349 * @val: the xmlChar * value 2350 * 2351 * This is the cached version of xmlXPathWrapString(). 2352 * Wraps the @val string into an XPath object. 2353 * 2354 * Returns the created or reused object. 2355 */ 2356 static xmlXPathObjectPtr 2357 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val) 2358 { 2359 if ((ctxt != NULL) && (ctxt->cache != NULL)) { 2360 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2361 2362 if ((cache->stringObjs != NULL) && 2363 (cache->stringObjs->number != 0)) 2364 { 2365 2366 xmlXPathObjectPtr ret; 2367 2368 ret = (xmlXPathObjectPtr) 2369 cache->stringObjs->items[--cache->stringObjs->number]; 2370 ret->type = XPATH_STRING; 2371 ret->stringval = val; 2372 #ifdef XP_DEBUG_OBJ_USAGE 2373 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2374 #endif 2375 return(ret); 2376 } else if ((cache->miscObjs != NULL) && 2377 (cache->miscObjs->number != 0)) 2378 { 2379 xmlXPathObjectPtr ret; 2380 /* 2381 * Fallback to misc-cache. 2382 */ 2383 ret = (xmlXPathObjectPtr) 2384 cache->miscObjs->items[--cache->miscObjs->number]; 2385 2386 ret->type = XPATH_STRING; 2387 ret->stringval = val; 2388 #ifdef XP_DEBUG_OBJ_USAGE 2389 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2390 #endif 2391 return(ret); 2392 } 2393 } 2394 return(xmlXPathWrapString(val)); 2395 } 2396 2397 /** 2398 * xmlXPathCacheNewNodeSet: 2399 * @ctxt: the XPath context 2400 * @val: the NodePtr value 2401 * 2402 * This is the cached version of xmlXPathNewNodeSet(). 2403 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize 2404 * it with the single Node @val 2405 * 2406 * Returns the created or reused object. 2407 */ 2408 static xmlXPathObjectPtr 2409 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val) 2410 { 2411 if ((ctxt != NULL) && (ctxt->cache)) { 2412 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2413 2414 if ((cache->nodesetObjs != NULL) && 2415 (cache->nodesetObjs->number != 0)) 2416 { 2417 xmlXPathObjectPtr ret; 2418 /* 2419 * Use the nodeset-cache. 2420 */ 2421 ret = (xmlXPathObjectPtr) 2422 cache->nodesetObjs->items[--cache->nodesetObjs->number]; 2423 ret->type = XPATH_NODESET; 2424 ret->boolval = 0; 2425 if (val) { 2426 if ((ret->nodesetval->nodeMax == 0) || 2427 (val->type == XML_NAMESPACE_DECL)) 2428 { 2429 /* TODO: Check memory error. */ 2430 xmlXPathNodeSetAddUnique(ret->nodesetval, val); 2431 } else { 2432 ret->nodesetval->nodeTab[0] = val; 2433 ret->nodesetval->nodeNr = 1; 2434 } 2435 } 2436 #ifdef XP_DEBUG_OBJ_USAGE 2437 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 2438 #endif 2439 return(ret); 2440 } else if ((cache->miscObjs != NULL) && 2441 (cache->miscObjs->number != 0)) 2442 { 2443 xmlXPathObjectPtr ret; 2444 /* 2445 * Fallback to misc-cache. 2446 */ 2447 2448 ret = (xmlXPathObjectPtr) 2449 cache->miscObjs->items[--cache->miscObjs->number]; 2450 2451 ret->type = XPATH_NODESET; 2452 ret->boolval = 0; 2453 ret->nodesetval = xmlXPathNodeSetCreate(val); 2454 if (ret->nodesetval == NULL) { 2455 ctxt->lastError.domain = XML_FROM_XPATH; 2456 ctxt->lastError.code = XML_ERR_NO_MEMORY; 2457 return(NULL); 2458 } 2459 #ifdef XP_DEBUG_OBJ_USAGE 2460 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 2461 #endif 2462 return(ret); 2463 } 2464 } 2465 return(xmlXPathNewNodeSet(val)); 2466 } 2467 2468 /** 2469 * xmlXPathCacheNewCString: 2470 * @ctxt: the XPath context 2471 * @val: the char * value 2472 * 2473 * This is the cached version of xmlXPathNewCString(). 2474 * Acquire an xmlXPathObjectPtr of type string and of value @val 2475 * 2476 * Returns the created or reused object. 2477 */ 2478 static xmlXPathObjectPtr 2479 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val) 2480 { 2481 if ((ctxt != NULL) && (ctxt->cache)) { 2482 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2483 2484 if ((cache->stringObjs != NULL) && 2485 (cache->stringObjs->number != 0)) 2486 { 2487 xmlXPathObjectPtr ret; 2488 2489 ret = (xmlXPathObjectPtr) 2490 cache->stringObjs->items[--cache->stringObjs->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 } else if ((cache->miscObjs != NULL) && 2499 (cache->miscObjs->number != 0)) 2500 { 2501 xmlXPathObjectPtr ret; 2502 2503 ret = (xmlXPathObjectPtr) 2504 cache->miscObjs->items[--cache->miscObjs->number]; 2505 2506 ret->type = XPATH_STRING; 2507 ret->stringval = xmlStrdup(BAD_CAST val); 2508 #ifdef XP_DEBUG_OBJ_USAGE 2509 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2510 #endif 2511 return(ret); 2512 } 2513 } 2514 return(xmlXPathNewCString(val)); 2515 } 2516 2517 /** 2518 * xmlXPathCacheNewString: 2519 * @ctxt: the XPath context 2520 * @val: the xmlChar * value 2521 * 2522 * This is the cached version of xmlXPathNewString(). 2523 * Acquire an xmlXPathObjectPtr of type string and of value @val 2524 * 2525 * Returns the created or reused object. 2526 */ 2527 static xmlXPathObjectPtr 2528 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val) 2529 { 2530 if ((ctxt != NULL) && (ctxt->cache)) { 2531 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2532 2533 if ((cache->stringObjs != NULL) && 2534 (cache->stringObjs->number != 0)) 2535 { 2536 xmlXPathObjectPtr ret; 2537 2538 ret = (xmlXPathObjectPtr) 2539 cache->stringObjs->items[--cache->stringObjs->number]; 2540 ret->type = XPATH_STRING; 2541 if (val != NULL) 2542 ret->stringval = xmlStrdup(val); 2543 else 2544 ret->stringval = xmlStrdup((const xmlChar *)""); 2545 #ifdef XP_DEBUG_OBJ_USAGE 2546 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2547 #endif 2548 return(ret); 2549 } else if ((cache->miscObjs != NULL) && 2550 (cache->miscObjs->number != 0)) 2551 { 2552 xmlXPathObjectPtr ret; 2553 2554 ret = (xmlXPathObjectPtr) 2555 cache->miscObjs->items[--cache->miscObjs->number]; 2556 2557 ret->type = XPATH_STRING; 2558 if (val != NULL) 2559 ret->stringval = xmlStrdup(val); 2560 else 2561 ret->stringval = xmlStrdup((const xmlChar *)""); 2562 #ifdef XP_DEBUG_OBJ_USAGE 2563 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2564 #endif 2565 return(ret); 2566 } 2567 } 2568 return(xmlXPathNewString(val)); 2569 } 2570 2571 /** 2572 * xmlXPathCacheNewBoolean: 2573 * @ctxt: the XPath context 2574 * @val: the boolean value 2575 * 2576 * This is the cached version of xmlXPathNewBoolean(). 2577 * Acquires an xmlXPathObjectPtr of type boolean and of value @val 2578 * 2579 * Returns the created or reused object. 2580 */ 2581 static xmlXPathObjectPtr 2582 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val) 2583 { 2584 if ((ctxt != NULL) && (ctxt->cache)) { 2585 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2586 2587 if ((cache->booleanObjs != NULL) && 2588 (cache->booleanObjs->number != 0)) 2589 { 2590 xmlXPathObjectPtr ret; 2591 2592 ret = (xmlXPathObjectPtr) 2593 cache->booleanObjs->items[--cache->booleanObjs->number]; 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 } else if ((cache->miscObjs != NULL) && 2601 (cache->miscObjs->number != 0)) 2602 { 2603 xmlXPathObjectPtr ret; 2604 2605 ret = (xmlXPathObjectPtr) 2606 cache->miscObjs->items[--cache->miscObjs->number]; 2607 2608 ret->type = XPATH_BOOLEAN; 2609 ret->boolval = (val != 0); 2610 #ifdef XP_DEBUG_OBJ_USAGE 2611 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN); 2612 #endif 2613 return(ret); 2614 } 2615 } 2616 return(xmlXPathNewBoolean(val)); 2617 } 2618 2619 /** 2620 * xmlXPathCacheNewFloat: 2621 * @ctxt: the XPath context 2622 * @val: the double value 2623 * 2624 * This is the cached version of xmlXPathNewFloat(). 2625 * Acquires an xmlXPathObjectPtr of type double and of value @val 2626 * 2627 * Returns the created or reused object. 2628 */ 2629 static xmlXPathObjectPtr 2630 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val) 2631 { 2632 if ((ctxt != NULL) && (ctxt->cache)) { 2633 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2634 2635 if ((cache->numberObjs != NULL) && 2636 (cache->numberObjs->number != 0)) 2637 { 2638 xmlXPathObjectPtr ret; 2639 2640 ret = (xmlXPathObjectPtr) 2641 cache->numberObjs->items[--cache->numberObjs->number]; 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 } else if ((cache->miscObjs != NULL) && 2649 (cache->miscObjs->number != 0)) 2650 { 2651 xmlXPathObjectPtr ret; 2652 2653 ret = (xmlXPathObjectPtr) 2654 cache->miscObjs->items[--cache->miscObjs->number]; 2655 2656 ret->type = XPATH_NUMBER; 2657 ret->floatval = val; 2658 #ifdef XP_DEBUG_OBJ_USAGE 2659 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER); 2660 #endif 2661 return(ret); 2662 } 2663 } 2664 return(xmlXPathNewFloat(val)); 2665 } 2666 2667 /** 2668 * xmlXPathCacheConvertString: 2669 * @ctxt: the XPath context 2670 * @val: an XPath object 2671 * 2672 * This is the cached version of xmlXPathConvertString(). 2673 * Converts an existing object to its string() equivalent 2674 * 2675 * Returns a created or reused object, the old one is freed (cached) 2676 * (or the operation is done directly on @val) 2677 */ 2678 2679 static xmlXPathObjectPtr 2680 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 2681 xmlChar *res = NULL; 2682 2683 if (val == NULL) 2684 return(xmlXPathCacheNewCString(ctxt, "")); 2685 2686 switch (val->type) { 2687 case XPATH_UNDEFINED: 2688 #ifdef DEBUG_EXPR 2689 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n"); 2690 #endif 2691 break; 2692 case XPATH_NODESET: 2693 case XPATH_XSLT_TREE: 2694 res = xmlXPathCastNodeSetToString(val->nodesetval); 2695 break; 2696 case XPATH_STRING: 2697 return(val); 2698 case XPATH_BOOLEAN: 2699 res = xmlXPathCastBooleanToString(val->boolval); 2700 break; 2701 case XPATH_NUMBER: 2702 res = xmlXPathCastNumberToString(val->floatval); 2703 break; 2704 case XPATH_USERS: 2705 case XPATH_POINT: 2706 case XPATH_RANGE: 2707 case XPATH_LOCATIONSET: 2708 TODO; 2709 break; 2710 } 2711 xmlXPathReleaseObject(ctxt, val); 2712 if (res == NULL) 2713 return(xmlXPathCacheNewCString(ctxt, "")); 2714 return(xmlXPathCacheWrapString(ctxt, res)); 2715 } 2716 2717 /** 2718 * xmlXPathCacheObjectCopy: 2719 * @ctxt: the XPath context 2720 * @val: the original object 2721 * 2722 * This is the cached version of xmlXPathObjectCopy(). 2723 * Acquire a copy of a given object 2724 * 2725 * Returns a created or reused created object. 2726 */ 2727 static xmlXPathObjectPtr 2728 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) 2729 { 2730 if (val == NULL) 2731 return(NULL); 2732 2733 if (XP_HAS_CACHE(ctxt)) { 2734 switch (val->type) { 2735 case XPATH_NODESET: 2736 return(xmlXPathCacheWrapNodeSet(ctxt, 2737 xmlXPathNodeSetMerge(NULL, val->nodesetval))); 2738 case XPATH_STRING: 2739 return(xmlXPathCacheNewString(ctxt, val->stringval)); 2740 case XPATH_BOOLEAN: 2741 return(xmlXPathCacheNewBoolean(ctxt, val->boolval)); 2742 case XPATH_NUMBER: 2743 return(xmlXPathCacheNewFloat(ctxt, val->floatval)); 2744 default: 2745 break; 2746 } 2747 } 2748 return(xmlXPathObjectCopy(val)); 2749 } 2750 2751 /** 2752 * xmlXPathCacheConvertBoolean: 2753 * @ctxt: the XPath context 2754 * @val: an XPath object 2755 * 2756 * This is the cached version of xmlXPathConvertBoolean(). 2757 * Converts an existing object to its boolean() equivalent 2758 * 2759 * Returns a created or reused object, the old one is freed (or the operation 2760 * is done directly on @val) 2761 */ 2762 static xmlXPathObjectPtr 2763 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 2764 xmlXPathObjectPtr ret; 2765 2766 if (val == NULL) 2767 return(xmlXPathCacheNewBoolean(ctxt, 0)); 2768 if (val->type == XPATH_BOOLEAN) 2769 return(val); 2770 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val)); 2771 xmlXPathReleaseObject(ctxt, val); 2772 return(ret); 2773 } 2774 2775 /** 2776 * xmlXPathCacheConvertNumber: 2777 * @ctxt: the XPath context 2778 * @val: an XPath object 2779 * 2780 * This is the cached version of xmlXPathConvertNumber(). 2781 * Converts an existing object to its number() equivalent 2782 * 2783 * Returns a created or reused object, the old one is freed (or the operation 2784 * is done directly on @val) 2785 */ 2786 static xmlXPathObjectPtr 2787 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 2788 xmlXPathObjectPtr ret; 2789 2790 if (val == NULL) 2791 return(xmlXPathCacheNewFloat(ctxt, 0.0)); 2792 if (val->type == XPATH_NUMBER) 2793 return(val); 2794 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val)); 2795 xmlXPathReleaseObject(ctxt, val); 2796 return(ret); 2797 } 2798 2799 /************************************************************************ 2800 * * 2801 * Parser stacks related functions and macros * 2802 * * 2803 ************************************************************************/ 2804 2805 /** 2806 * xmlXPathSetFrame: 2807 * @ctxt: an XPath parser context 2808 * 2809 * Set the callee evaluation frame 2810 * 2811 * Returns the previous frame value to be restored once done 2812 */ 2813 static int 2814 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) { 2815 int ret; 2816 2817 if (ctxt == NULL) 2818 return(0); 2819 ret = ctxt->valueFrame; 2820 ctxt->valueFrame = ctxt->valueNr; 2821 return(ret); 2822 } 2823 2824 /** 2825 * xmlXPathPopFrame: 2826 * @ctxt: an XPath parser context 2827 * @frame: the previous frame value 2828 * 2829 * Remove the callee evaluation frame 2830 */ 2831 static void 2832 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) { 2833 if (ctxt == NULL) 2834 return; 2835 if (ctxt->valueNr < ctxt->valueFrame) { 2836 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR); 2837 } 2838 ctxt->valueFrame = frame; 2839 } 2840 2841 /** 2842 * valuePop: 2843 * @ctxt: an XPath evaluation context 2844 * 2845 * Pops the top XPath object from the value stack 2846 * 2847 * Returns the XPath object just removed 2848 */ 2849 xmlXPathObjectPtr 2850 valuePop(xmlXPathParserContextPtr ctxt) 2851 { 2852 xmlXPathObjectPtr ret; 2853 2854 if ((ctxt == NULL) || (ctxt->valueNr <= 0)) 2855 return (NULL); 2856 2857 if (ctxt->valueNr <= ctxt->valueFrame) { 2858 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR); 2859 return (NULL); 2860 } 2861 2862 ctxt->valueNr--; 2863 if (ctxt->valueNr > 0) 2864 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1]; 2865 else 2866 ctxt->value = NULL; 2867 ret = ctxt->valueTab[ctxt->valueNr]; 2868 ctxt->valueTab[ctxt->valueNr] = NULL; 2869 return (ret); 2870 } 2871 /** 2872 * valuePush: 2873 * @ctxt: an XPath evaluation context 2874 * @value: the XPath object 2875 * 2876 * Pushes a new XPath object on top of the value stack. If value is NULL, 2877 * a memory error is recorded in the parser context. 2878 * 2879 * Returns the number of items on the value stack, or -1 in case of error. 2880 */ 2881 int 2882 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value) 2883 { 2884 if (ctxt == NULL) return(-1); 2885 if (value == NULL) { 2886 /* 2887 * A NULL value typically indicates that a memory allocation failed, 2888 * so we set ctxt->error here to propagate the error. 2889 */ 2890 ctxt->error = XPATH_MEMORY_ERROR; 2891 return(-1); 2892 } 2893 if (ctxt->valueNr >= ctxt->valueMax) { 2894 xmlXPathObjectPtr *tmp; 2895 2896 if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) { 2897 xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n"); 2898 return (-1); 2899 } 2900 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab, 2901 2 * ctxt->valueMax * 2902 sizeof(ctxt->valueTab[0])); 2903 if (tmp == NULL) { 2904 xmlXPathPErrMemory(ctxt, "pushing value\n"); 2905 return (-1); 2906 } 2907 ctxt->valueMax *= 2; 2908 ctxt->valueTab = tmp; 2909 } 2910 ctxt->valueTab[ctxt->valueNr] = value; 2911 ctxt->value = value; 2912 return (ctxt->valueNr++); 2913 } 2914 2915 /** 2916 * xmlXPathPopBoolean: 2917 * @ctxt: an XPath parser context 2918 * 2919 * Pops a boolean from the stack, handling conversion if needed. 2920 * Check error with #xmlXPathCheckError. 2921 * 2922 * Returns the boolean 2923 */ 2924 int 2925 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) { 2926 xmlXPathObjectPtr obj; 2927 int ret; 2928 2929 obj = valuePop(ctxt); 2930 if (obj == NULL) { 2931 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2932 return(0); 2933 } 2934 if (obj->type != XPATH_BOOLEAN) 2935 ret = xmlXPathCastToBoolean(obj); 2936 else 2937 ret = obj->boolval; 2938 xmlXPathReleaseObject(ctxt->context, obj); 2939 return(ret); 2940 } 2941 2942 /** 2943 * xmlXPathPopNumber: 2944 * @ctxt: an XPath parser context 2945 * 2946 * Pops a number from the stack, handling conversion if needed. 2947 * Check error with #xmlXPathCheckError. 2948 * 2949 * Returns the number 2950 */ 2951 double 2952 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) { 2953 xmlXPathObjectPtr obj; 2954 double ret; 2955 2956 obj = valuePop(ctxt); 2957 if (obj == NULL) { 2958 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2959 return(0); 2960 } 2961 if (obj->type != XPATH_NUMBER) 2962 ret = xmlXPathCastToNumber(obj); 2963 else 2964 ret = obj->floatval; 2965 xmlXPathReleaseObject(ctxt->context, obj); 2966 return(ret); 2967 } 2968 2969 /** 2970 * xmlXPathPopString: 2971 * @ctxt: an XPath parser context 2972 * 2973 * Pops a string from the stack, handling conversion if needed. 2974 * Check error with #xmlXPathCheckError. 2975 * 2976 * Returns the string 2977 */ 2978 xmlChar * 2979 xmlXPathPopString (xmlXPathParserContextPtr ctxt) { 2980 xmlXPathObjectPtr obj; 2981 xmlChar * ret; 2982 2983 obj = valuePop(ctxt); 2984 if (obj == NULL) { 2985 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2986 return(NULL); 2987 } 2988 ret = xmlXPathCastToString(obj); /* this does required strdup */ 2989 /* TODO: needs refactoring somewhere else */ 2990 if (obj->stringval == ret) 2991 obj->stringval = NULL; 2992 xmlXPathReleaseObject(ctxt->context, obj); 2993 return(ret); 2994 } 2995 2996 /** 2997 * xmlXPathPopNodeSet: 2998 * @ctxt: an XPath parser context 2999 * 3000 * Pops a node-set from the stack, handling conversion if needed. 3001 * Check error with #xmlXPathCheckError. 3002 * 3003 * Returns the node-set 3004 */ 3005 xmlNodeSetPtr 3006 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) { 3007 xmlXPathObjectPtr obj; 3008 xmlNodeSetPtr ret; 3009 3010 if (ctxt == NULL) return(NULL); 3011 if (ctxt->value == NULL) { 3012 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 3013 return(NULL); 3014 } 3015 if (!xmlXPathStackIsNodeSet(ctxt)) { 3016 xmlXPathSetTypeError(ctxt); 3017 return(NULL); 3018 } 3019 obj = valuePop(ctxt); 3020 ret = obj->nodesetval; 3021 #if 0 3022 /* to fix memory leak of not clearing obj->user */ 3023 if (obj->boolval && obj->user != NULL) 3024 xmlFreeNodeList((xmlNodePtr) obj->user); 3025 #endif 3026 obj->nodesetval = NULL; 3027 xmlXPathReleaseObject(ctxt->context, obj); 3028 return(ret); 3029 } 3030 3031 /** 3032 * xmlXPathPopExternal: 3033 * @ctxt: an XPath parser context 3034 * 3035 * Pops an external object from the stack, handling conversion if needed. 3036 * Check error with #xmlXPathCheckError. 3037 * 3038 * Returns the object 3039 */ 3040 void * 3041 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) { 3042 xmlXPathObjectPtr obj; 3043 void * ret; 3044 3045 if ((ctxt == NULL) || (ctxt->value == NULL)) { 3046 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 3047 return(NULL); 3048 } 3049 if (ctxt->value->type != XPATH_USERS) { 3050 xmlXPathSetTypeError(ctxt); 3051 return(NULL); 3052 } 3053 obj = valuePop(ctxt); 3054 ret = obj->user; 3055 obj->user = NULL; 3056 xmlXPathReleaseObject(ctxt->context, obj); 3057 return(ret); 3058 } 3059 3060 /* 3061 * Macros for accessing the content. Those should be used only by the parser, 3062 * and not exported. 3063 * 3064 * Dirty macros, i.e. one need to make assumption on the context to use them 3065 * 3066 * CUR_PTR return the current pointer to the xmlChar to be parsed. 3067 * CUR returns the current xmlChar value, i.e. a 8 bit value 3068 * in ISO-Latin or UTF-8. 3069 * This should be used internally by the parser 3070 * only to compare to ASCII values otherwise it would break when 3071 * running with UTF-8 encoding. 3072 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only 3073 * to compare on ASCII based substring. 3074 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined 3075 * strings within the parser. 3076 * CURRENT Returns the current char value, with the full decoding of 3077 * UTF-8 if we are using this mode. It returns an int. 3078 * NEXT Skip to the next character, this does the proper decoding 3079 * in UTF-8 mode. It also pop-up unfinished entities on the fly. 3080 * It returns the pointer to the current xmlChar. 3081 */ 3082 3083 #define CUR (*ctxt->cur) 3084 #define SKIP(val) ctxt->cur += (val) 3085 #define NXT(val) ctxt->cur[(val)] 3086 #define CUR_PTR ctxt->cur 3087 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l) 3088 3089 #define COPY_BUF(l,b,i,v) \ 3090 if (l == 1) b[i++] = (xmlChar) v; \ 3091 else i += xmlCopyChar(l,&b[i],v) 3092 3093 #define NEXTL(l) ctxt->cur += l 3094 3095 #define SKIP_BLANKS \ 3096 while (IS_BLANK_CH(*(ctxt->cur))) NEXT 3097 3098 #define CURRENT (*ctxt->cur) 3099 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur) 3100 3101 3102 #ifndef DBL_DIG 3103 #define DBL_DIG 16 3104 #endif 3105 #ifndef DBL_EPSILON 3106 #define DBL_EPSILON 1E-9 3107 #endif 3108 3109 #define UPPER_DOUBLE 1E9 3110 #define LOWER_DOUBLE 1E-5 3111 #define LOWER_DOUBLE_EXP 5 3112 3113 #define INTEGER_DIGITS DBL_DIG 3114 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP)) 3115 #define EXPONENT_DIGITS (3 + 2) 3116 3117 /** 3118 * xmlXPathFormatNumber: 3119 * @number: number to format 3120 * @buffer: output buffer 3121 * @buffersize: size of output buffer 3122 * 3123 * Convert the number into a string representation. 3124 */ 3125 static void 3126 xmlXPathFormatNumber(double number, char buffer[], int buffersize) 3127 { 3128 switch (xmlXPathIsInf(number)) { 3129 case 1: 3130 if (buffersize > (int)sizeof("Infinity")) 3131 snprintf(buffer, buffersize, "Infinity"); 3132 break; 3133 case -1: 3134 if (buffersize > (int)sizeof("-Infinity")) 3135 snprintf(buffer, buffersize, "-Infinity"); 3136 break; 3137 default: 3138 if (xmlXPathIsNaN(number)) { 3139 if (buffersize > (int)sizeof("NaN")) 3140 snprintf(buffer, buffersize, "NaN"); 3141 } else if (number == 0) { 3142 /* Omit sign for negative zero. */ 3143 snprintf(buffer, buffersize, "0"); 3144 } else if ((number > INT_MIN) && (number < INT_MAX) && 3145 (number == (int) number)) { 3146 char work[30]; 3147 char *ptr, *cur; 3148 int value = (int) number; 3149 3150 ptr = &buffer[0]; 3151 if (value == 0) { 3152 *ptr++ = '0'; 3153 } else { 3154 snprintf(work, 29, "%d", value); 3155 cur = &work[0]; 3156 while ((*cur) && (ptr - buffer < buffersize)) { 3157 *ptr++ = *cur++; 3158 } 3159 } 3160 if (ptr - buffer < buffersize) { 3161 *ptr = 0; 3162 } else if (buffersize > 0) { 3163 ptr--; 3164 *ptr = 0; 3165 } 3166 } else { 3167 /* 3168 For the dimension of work, 3169 DBL_DIG is number of significant digits 3170 EXPONENT is only needed for "scientific notation" 3171 3 is sign, decimal point, and terminating zero 3172 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction 3173 Note that this dimension is slightly (a few characters) 3174 larger than actually necessary. 3175 */ 3176 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP]; 3177 int integer_place, fraction_place; 3178 char *ptr; 3179 char *after_fraction; 3180 double absolute_value; 3181 int size; 3182 3183 absolute_value = fabs(number); 3184 3185 /* 3186 * First choose format - scientific or regular floating point. 3187 * In either case, result is in work, and after_fraction points 3188 * just past the fractional part. 3189 */ 3190 if ( ((absolute_value > UPPER_DOUBLE) || 3191 (absolute_value < LOWER_DOUBLE)) && 3192 (absolute_value != 0.0) ) { 3193 /* Use scientific notation */ 3194 integer_place = DBL_DIG + EXPONENT_DIGITS + 1; 3195 fraction_place = DBL_DIG - 1; 3196 size = snprintf(work, sizeof(work),"%*.*e", 3197 integer_place, fraction_place, number); 3198 while ((size > 0) && (work[size] != 'e')) size--; 3199 3200 } 3201 else { 3202 /* Use regular notation */ 3203 if (absolute_value > 0.0) { 3204 integer_place = (int)log10(absolute_value); 3205 if (integer_place > 0) 3206 fraction_place = DBL_DIG - integer_place - 1; 3207 else 3208 fraction_place = DBL_DIG - integer_place; 3209 } else { 3210 fraction_place = 1; 3211 } 3212 size = snprintf(work, sizeof(work), "%0.*f", 3213 fraction_place, number); 3214 } 3215 3216 /* Remove leading spaces sometimes inserted by snprintf */ 3217 while (work[0] == ' ') { 3218 for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++); 3219 size--; 3220 } 3221 3222 /* Remove fractional trailing zeroes */ 3223 after_fraction = work + size; 3224 ptr = after_fraction; 3225 while (*(--ptr) == '0') 3226 ; 3227 if (*ptr != '.') 3228 ptr++; 3229 while ((*ptr++ = *after_fraction++) != 0); 3230 3231 /* Finally copy result back to caller */ 3232 size = strlen(work) + 1; 3233 if (size > buffersize) { 3234 work[buffersize - 1] = 0; 3235 size = buffersize; 3236 } 3237 memmove(buffer, work, size); 3238 } 3239 break; 3240 } 3241 } 3242 3243 3244 /************************************************************************ 3245 * * 3246 * Routines to handle NodeSets * 3247 * * 3248 ************************************************************************/ 3249 3250 /** 3251 * xmlXPathOrderDocElems: 3252 * @doc: an input document 3253 * 3254 * Call this routine to speed up XPath computation on static documents. 3255 * This stamps all the element nodes with the document order 3256 * Like for line information, the order is kept in the element->content 3257 * field, the value stored is actually - the node number (starting at -1) 3258 * to be able to differentiate from line numbers. 3259 * 3260 * Returns the number of elements found in the document or -1 in case 3261 * of error. 3262 */ 3263 long 3264 xmlXPathOrderDocElems(xmlDocPtr doc) { 3265 ptrdiff_t count = 0; 3266 xmlNodePtr cur; 3267 3268 if (doc == NULL) 3269 return(-1); 3270 cur = doc->children; 3271 while (cur != NULL) { 3272 if (cur->type == XML_ELEMENT_NODE) { 3273 cur->content = (void *) (-(++count)); 3274 if (cur->children != NULL) { 3275 cur = cur->children; 3276 continue; 3277 } 3278 } 3279 if (cur->next != NULL) { 3280 cur = cur->next; 3281 continue; 3282 } 3283 do { 3284 cur = cur->parent; 3285 if (cur == NULL) 3286 break; 3287 if (cur == (xmlNodePtr) doc) { 3288 cur = NULL; 3289 break; 3290 } 3291 if (cur->next != NULL) { 3292 cur = cur->next; 3293 break; 3294 } 3295 } while (cur != NULL); 3296 } 3297 return((long) count); 3298 } 3299 3300 /** 3301 * xmlXPathCmpNodes: 3302 * @node1: the first node 3303 * @node2: the second node 3304 * 3305 * Compare two nodes w.r.t document order 3306 * 3307 * Returns -2 in case of error 1 if first point < second point, 0 if 3308 * it's the same node, -1 otherwise 3309 */ 3310 int 3311 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) { 3312 int depth1, depth2; 3313 int attr1 = 0, attr2 = 0; 3314 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL; 3315 xmlNodePtr cur, root; 3316 3317 if ((node1 == NULL) || (node2 == NULL)) 3318 return(-2); 3319 /* 3320 * a couple of optimizations which will avoid computations in most cases 3321 */ 3322 if (node1 == node2) /* trivial case */ 3323 return(0); 3324 if (node1->type == XML_ATTRIBUTE_NODE) { 3325 attr1 = 1; 3326 attrNode1 = node1; 3327 node1 = node1->parent; 3328 } 3329 if (node2->type == XML_ATTRIBUTE_NODE) { 3330 attr2 = 1; 3331 attrNode2 = node2; 3332 node2 = node2->parent; 3333 } 3334 if (node1 == node2) { 3335 if (attr1 == attr2) { 3336 /* not required, but we keep attributes in order */ 3337 if (attr1 != 0) { 3338 cur = attrNode2->prev; 3339 while (cur != NULL) { 3340 if (cur == attrNode1) 3341 return (1); 3342 cur = cur->prev; 3343 } 3344 return (-1); 3345 } 3346 return(0); 3347 } 3348 if (attr2 == 1) 3349 return(1); 3350 return(-1); 3351 } 3352 if ((node1->type == XML_NAMESPACE_DECL) || 3353 (node2->type == XML_NAMESPACE_DECL)) 3354 return(1); 3355 if (node1 == node2->prev) 3356 return(1); 3357 if (node1 == node2->next) 3358 return(-1); 3359 3360 /* 3361 * Speedup using document order if available. 3362 */ 3363 if ((node1->type == XML_ELEMENT_NODE) && 3364 (node2->type == XML_ELEMENT_NODE) && 3365 (0 > (ptrdiff_t) node1->content) && 3366 (0 > (ptrdiff_t) node2->content) && 3367 (node1->doc == node2->doc)) { 3368 ptrdiff_t l1, l2; 3369 3370 l1 = -((ptrdiff_t) node1->content); 3371 l2 = -((ptrdiff_t) node2->content); 3372 if (l1 < l2) 3373 return(1); 3374 if (l1 > l2) 3375 return(-1); 3376 } 3377 3378 /* 3379 * compute depth to root 3380 */ 3381 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) { 3382 if (cur->parent == node1) 3383 return(1); 3384 depth2++; 3385 } 3386 root = cur; 3387 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) { 3388 if (cur->parent == node2) 3389 return(-1); 3390 depth1++; 3391 } 3392 /* 3393 * Distinct document (or distinct entities :-( ) case. 3394 */ 3395 if (root != cur) { 3396 return(-2); 3397 } 3398 /* 3399 * get the nearest common ancestor. 3400 */ 3401 while (depth1 > depth2) { 3402 depth1--; 3403 node1 = node1->parent; 3404 } 3405 while (depth2 > depth1) { 3406 depth2--; 3407 node2 = node2->parent; 3408 } 3409 while (node1->parent != node2->parent) { 3410 node1 = node1->parent; 3411 node2 = node2->parent; 3412 /* should not happen but just in case ... */ 3413 if ((node1 == NULL) || (node2 == NULL)) 3414 return(-2); 3415 } 3416 /* 3417 * Find who's first. 3418 */ 3419 if (node1 == node2->prev) 3420 return(1); 3421 if (node1 == node2->next) 3422 return(-1); 3423 /* 3424 * Speedup using document order if available. 3425 */ 3426 if ((node1->type == XML_ELEMENT_NODE) && 3427 (node2->type == XML_ELEMENT_NODE) && 3428 (0 > (ptrdiff_t) node1->content) && 3429 (0 > (ptrdiff_t) node2->content) && 3430 (node1->doc == node2->doc)) { 3431 ptrdiff_t l1, l2; 3432 3433 l1 = -((ptrdiff_t) node1->content); 3434 l2 = -((ptrdiff_t) node2->content); 3435 if (l1 < l2) 3436 return(1); 3437 if (l1 > l2) 3438 return(-1); 3439 } 3440 3441 for (cur = node1->next;cur != NULL;cur = cur->next) 3442 if (cur == node2) 3443 return(1); 3444 return(-1); /* assume there is no sibling list corruption */ 3445 } 3446 3447 /** 3448 * xmlXPathNodeSetSort: 3449 * @set: the node set 3450 * 3451 * Sort the node set in document order 3452 */ 3453 void 3454 xmlXPathNodeSetSort(xmlNodeSetPtr set) { 3455 #ifndef WITH_TIM_SORT 3456 int i, j, incr, len; 3457 xmlNodePtr tmp; 3458 #endif 3459 3460 if (set == NULL) 3461 return; 3462 3463 #ifndef WITH_TIM_SORT 3464 /* 3465 * Use the old Shell's sort implementation to sort the node-set 3466 * Timsort ought to be quite faster 3467 */ 3468 len = set->nodeNr; 3469 for (incr = len / 2; incr > 0; incr /= 2) { 3470 for (i = incr; i < len; i++) { 3471 j = i - incr; 3472 while (j >= 0) { 3473 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 3474 if (xmlXPathCmpNodesExt(set->nodeTab[j], 3475 set->nodeTab[j + incr]) == -1) 3476 #else 3477 if (xmlXPathCmpNodes(set->nodeTab[j], 3478 set->nodeTab[j + incr]) == -1) 3479 #endif 3480 { 3481 tmp = set->nodeTab[j]; 3482 set->nodeTab[j] = set->nodeTab[j + incr]; 3483 set->nodeTab[j + incr] = tmp; 3484 j -= incr; 3485 } else 3486 break; 3487 } 3488 } 3489 } 3490 #else /* WITH_TIM_SORT */ 3491 libxml_domnode_tim_sort(set->nodeTab, set->nodeNr); 3492 #endif /* WITH_TIM_SORT */ 3493 } 3494 3495 #define XML_NODESET_DEFAULT 10 3496 /** 3497 * xmlXPathNodeSetDupNs: 3498 * @node: the parent node of the namespace XPath node 3499 * @ns: the libxml namespace declaration node. 3500 * 3501 * Namespace node in libxml don't match the XPath semantic. In a node set 3502 * the namespace nodes are duplicated and the next pointer is set to the 3503 * parent node in the XPath semantic. 3504 * 3505 * Returns the newly created object. 3506 */ 3507 static xmlNodePtr 3508 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) { 3509 xmlNsPtr cur; 3510 3511 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) 3512 return(NULL); 3513 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) 3514 return((xmlNodePtr) ns); 3515 3516 /* 3517 * Allocate a new Namespace and fill the fields. 3518 */ 3519 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); 3520 if (cur == NULL) { 3521 xmlXPathErrMemory(NULL, "duplicating namespace\n"); 3522 return(NULL); 3523 } 3524 memset(cur, 0, sizeof(xmlNs)); 3525 cur->type = XML_NAMESPACE_DECL; 3526 if (ns->href != NULL) 3527 cur->href = xmlStrdup(ns->href); 3528 if (ns->prefix != NULL) 3529 cur->prefix = xmlStrdup(ns->prefix); 3530 cur->next = (xmlNsPtr) node; 3531 return((xmlNodePtr) cur); 3532 } 3533 3534 /** 3535 * xmlXPathNodeSetFreeNs: 3536 * @ns: the XPath namespace node found in a nodeset. 3537 * 3538 * Namespace nodes in libxml don't match the XPath semantic. In a node set 3539 * the namespace nodes are duplicated and the next pointer is set to the 3540 * parent node in the XPath semantic. Check if such a node needs to be freed 3541 */ 3542 void 3543 xmlXPathNodeSetFreeNs(xmlNsPtr ns) { 3544 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) 3545 return; 3546 3547 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) { 3548 if (ns->href != NULL) 3549 xmlFree((xmlChar *)ns->href); 3550 if (ns->prefix != NULL) 3551 xmlFree((xmlChar *)ns->prefix); 3552 xmlFree(ns); 3553 } 3554 } 3555 3556 /** 3557 * xmlXPathNodeSetCreate: 3558 * @val: an initial xmlNodePtr, or NULL 3559 * 3560 * Create a new xmlNodeSetPtr of type double and of value @val 3561 * 3562 * Returns the newly created object. 3563 */ 3564 xmlNodeSetPtr 3565 xmlXPathNodeSetCreate(xmlNodePtr val) { 3566 xmlNodeSetPtr ret; 3567 3568 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet)); 3569 if (ret == NULL) { 3570 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3571 return(NULL); 3572 } 3573 memset(ret, 0 , (size_t) sizeof(xmlNodeSet)); 3574 if (val != NULL) { 3575 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3576 sizeof(xmlNodePtr)); 3577 if (ret->nodeTab == NULL) { 3578 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3579 xmlFree(ret); 3580 return(NULL); 3581 } 3582 memset(ret->nodeTab, 0 , 3583 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3584 ret->nodeMax = XML_NODESET_DEFAULT; 3585 if (val->type == XML_NAMESPACE_DECL) { 3586 xmlNsPtr ns = (xmlNsPtr) val; 3587 3588 /* TODO: Check memory error. */ 3589 ret->nodeTab[ret->nodeNr++] = 3590 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3591 } else 3592 ret->nodeTab[ret->nodeNr++] = val; 3593 } 3594 return(ret); 3595 } 3596 3597 /** 3598 * xmlXPathNodeSetContains: 3599 * @cur: the node-set 3600 * @val: the node 3601 * 3602 * checks whether @cur contains @val 3603 * 3604 * Returns true (1) if @cur contains @val, false (0) otherwise 3605 */ 3606 int 3607 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) { 3608 int i; 3609 3610 if ((cur == NULL) || (val == NULL)) return(0); 3611 if (val->type == XML_NAMESPACE_DECL) { 3612 for (i = 0; i < cur->nodeNr; i++) { 3613 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) { 3614 xmlNsPtr ns1, ns2; 3615 3616 ns1 = (xmlNsPtr) val; 3617 ns2 = (xmlNsPtr) cur->nodeTab[i]; 3618 if (ns1 == ns2) 3619 return(1); 3620 if ((ns1->next != NULL) && (ns2->next == ns1->next) && 3621 (xmlStrEqual(ns1->prefix, ns2->prefix))) 3622 return(1); 3623 } 3624 } 3625 } else { 3626 for (i = 0; i < cur->nodeNr; i++) { 3627 if (cur->nodeTab[i] == val) 3628 return(1); 3629 } 3630 } 3631 return(0); 3632 } 3633 3634 /** 3635 * xmlXPathNodeSetAddNs: 3636 * @cur: the initial node set 3637 * @node: the hosting node 3638 * @ns: a the namespace node 3639 * 3640 * add a new namespace node to an existing NodeSet 3641 * 3642 * Returns 0 in case of success and -1 in case of error 3643 */ 3644 int 3645 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) { 3646 int i; 3647 3648 3649 if ((cur == NULL) || (ns == NULL) || (node == NULL) || 3650 (ns->type != XML_NAMESPACE_DECL) || 3651 (node->type != XML_ELEMENT_NODE)) 3652 return(-1); 3653 3654 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3655 /* 3656 * prevent duplicates 3657 */ 3658 for (i = 0;i < cur->nodeNr;i++) { 3659 if ((cur->nodeTab[i] != NULL) && 3660 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) && 3661 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) && 3662 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix))) 3663 return(0); 3664 } 3665 3666 /* 3667 * grow the nodeTab if needed 3668 */ 3669 if (cur->nodeMax == 0) { 3670 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3671 sizeof(xmlNodePtr)); 3672 if (cur->nodeTab == NULL) { 3673 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3674 return(-1); 3675 } 3676 memset(cur->nodeTab, 0 , 3677 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3678 cur->nodeMax = XML_NODESET_DEFAULT; 3679 } else if (cur->nodeNr == cur->nodeMax) { 3680 xmlNodePtr *temp; 3681 3682 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 3683 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n"); 3684 return(-1); 3685 } 3686 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 * 3687 sizeof(xmlNodePtr)); 3688 if (temp == NULL) { 3689 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3690 return(-1); 3691 } 3692 cur->nodeMax *= 2; 3693 cur->nodeTab = temp; 3694 } 3695 /* TODO: Check memory error. */ 3696 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns); 3697 return(0); 3698 } 3699 3700 /** 3701 * xmlXPathNodeSetAdd: 3702 * @cur: the initial node set 3703 * @val: a new xmlNodePtr 3704 * 3705 * add a new xmlNodePtr to an existing NodeSet 3706 * 3707 * Returns 0 in case of success, and -1 in case of error 3708 */ 3709 int 3710 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) { 3711 int i; 3712 3713 if ((cur == NULL) || (val == NULL)) return(-1); 3714 3715 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3716 /* 3717 * prevent duplicates 3718 */ 3719 for (i = 0;i < cur->nodeNr;i++) 3720 if (cur->nodeTab[i] == val) return(0); 3721 3722 /* 3723 * grow the nodeTab if needed 3724 */ 3725 if (cur->nodeMax == 0) { 3726 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3727 sizeof(xmlNodePtr)); 3728 if (cur->nodeTab == NULL) { 3729 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3730 return(-1); 3731 } 3732 memset(cur->nodeTab, 0 , 3733 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3734 cur->nodeMax = XML_NODESET_DEFAULT; 3735 } else if (cur->nodeNr == cur->nodeMax) { 3736 xmlNodePtr *temp; 3737 3738 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 3739 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n"); 3740 return(-1); 3741 } 3742 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 * 3743 sizeof(xmlNodePtr)); 3744 if (temp == NULL) { 3745 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3746 return(-1); 3747 } 3748 cur->nodeMax *= 2; 3749 cur->nodeTab = temp; 3750 } 3751 if (val->type == XML_NAMESPACE_DECL) { 3752 xmlNsPtr ns = (xmlNsPtr) val; 3753 3754 /* TODO: Check memory error. */ 3755 cur->nodeTab[cur->nodeNr++] = 3756 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3757 } else 3758 cur->nodeTab[cur->nodeNr++] = val; 3759 return(0); 3760 } 3761 3762 /** 3763 * xmlXPathNodeSetAddUnique: 3764 * @cur: the initial node set 3765 * @val: a new xmlNodePtr 3766 * 3767 * add a new xmlNodePtr to an existing NodeSet, optimized version 3768 * when we are sure the node is not already in the set. 3769 * 3770 * Returns 0 in case of success and -1 in case of failure 3771 */ 3772 int 3773 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) { 3774 if ((cur == NULL) || (val == NULL)) return(-1); 3775 3776 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3777 /* 3778 * grow the nodeTab if needed 3779 */ 3780 if (cur->nodeMax == 0) { 3781 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3782 sizeof(xmlNodePtr)); 3783 if (cur->nodeTab == NULL) { 3784 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3785 return(-1); 3786 } 3787 memset(cur->nodeTab, 0 , 3788 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3789 cur->nodeMax = XML_NODESET_DEFAULT; 3790 } else if (cur->nodeNr == cur->nodeMax) { 3791 xmlNodePtr *temp; 3792 3793 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 3794 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n"); 3795 return(-1); 3796 } 3797 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 * 3798 sizeof(xmlNodePtr)); 3799 if (temp == NULL) { 3800 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3801 return(-1); 3802 } 3803 cur->nodeTab = temp; 3804 cur->nodeMax *= 2; 3805 } 3806 if (val->type == XML_NAMESPACE_DECL) { 3807 xmlNsPtr ns = (xmlNsPtr) val; 3808 3809 /* TODO: Check memory error. */ 3810 cur->nodeTab[cur->nodeNr++] = 3811 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3812 } else 3813 cur->nodeTab[cur->nodeNr++] = val; 3814 return(0); 3815 } 3816 3817 /** 3818 * xmlXPathNodeSetMerge: 3819 * @val1: the first NodeSet or NULL 3820 * @val2: the second NodeSet 3821 * 3822 * Merges two nodesets, all nodes from @val2 are added to @val1 3823 * if @val1 is NULL, a new set is created and copied from @val2 3824 * 3825 * Returns @val1 once extended or NULL in case of error. 3826 */ 3827 xmlNodeSetPtr 3828 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) { 3829 int i, j, initNr, skip; 3830 xmlNodePtr n1, n2; 3831 3832 if (val2 == NULL) return(val1); 3833 if (val1 == NULL) { 3834 val1 = xmlXPathNodeSetCreate(NULL); 3835 if (val1 == NULL) 3836 return (NULL); 3837 #if 0 3838 /* 3839 * TODO: The optimization won't work in every case, since 3840 * those nasty namespace nodes need to be added with 3841 * xmlXPathNodeSetDupNs() to the set; thus a pure 3842 * memcpy is not possible. 3843 * If there was a flag on the nodesetval, indicating that 3844 * some temporary nodes are in, that would be helpful. 3845 */ 3846 /* 3847 * Optimization: Create an equally sized node-set 3848 * and memcpy the content. 3849 */ 3850 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr); 3851 if (val1 == NULL) 3852 return(NULL); 3853 if (val2->nodeNr != 0) { 3854 if (val2->nodeNr == 1) 3855 *(val1->nodeTab) = *(val2->nodeTab); 3856 else { 3857 memcpy(val1->nodeTab, val2->nodeTab, 3858 val2->nodeNr * sizeof(xmlNodePtr)); 3859 } 3860 val1->nodeNr = val2->nodeNr; 3861 } 3862 return(val1); 3863 #endif 3864 } 3865 3866 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3867 initNr = val1->nodeNr; 3868 3869 for (i = 0;i < val2->nodeNr;i++) { 3870 n2 = val2->nodeTab[i]; 3871 /* 3872 * check against duplicates 3873 */ 3874 skip = 0; 3875 for (j = 0; j < initNr; j++) { 3876 n1 = val1->nodeTab[j]; 3877 if (n1 == n2) { 3878 skip = 1; 3879 break; 3880 } else if ((n1->type == XML_NAMESPACE_DECL) && 3881 (n2->type == XML_NAMESPACE_DECL)) { 3882 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) && 3883 (xmlStrEqual(((xmlNsPtr) n1)->prefix, 3884 ((xmlNsPtr) n2)->prefix))) 3885 { 3886 skip = 1; 3887 break; 3888 } 3889 } 3890 } 3891 if (skip) 3892 continue; 3893 3894 /* 3895 * grow the nodeTab if needed 3896 */ 3897 if (val1->nodeMax == 0) { 3898 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3899 sizeof(xmlNodePtr)); 3900 if (val1->nodeTab == NULL) { 3901 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3902 return(NULL); 3903 } 3904 memset(val1->nodeTab, 0 , 3905 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3906 val1->nodeMax = XML_NODESET_DEFAULT; 3907 } else if (val1->nodeNr == val1->nodeMax) { 3908 xmlNodePtr *temp; 3909 3910 if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 3911 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n"); 3912 return(NULL); 3913 } 3914 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 * 3915 sizeof(xmlNodePtr)); 3916 if (temp == NULL) { 3917 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3918 return(NULL); 3919 } 3920 val1->nodeTab = temp; 3921 val1->nodeMax *= 2; 3922 } 3923 if (n2->type == XML_NAMESPACE_DECL) { 3924 xmlNsPtr ns = (xmlNsPtr) n2; 3925 3926 /* TODO: Check memory error. */ 3927 val1->nodeTab[val1->nodeNr++] = 3928 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3929 } else 3930 val1->nodeTab[val1->nodeNr++] = n2; 3931 } 3932 3933 return(val1); 3934 } 3935 3936 3937 /** 3938 * xmlXPathNodeSetMergeAndClear: 3939 * @set1: the first NodeSet or NULL 3940 * @set2: the second NodeSet 3941 * 3942 * Merges two nodesets, all nodes from @set2 are added to @set1. 3943 * Checks for duplicate nodes. Clears set2. 3944 * 3945 * Returns @set1 once extended or NULL in case of error. 3946 */ 3947 static xmlNodeSetPtr 3948 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2) 3949 { 3950 { 3951 int i, j, initNbSet1; 3952 xmlNodePtr n1, n2; 3953 3954 initNbSet1 = set1->nodeNr; 3955 for (i = 0;i < set2->nodeNr;i++) { 3956 n2 = set2->nodeTab[i]; 3957 /* 3958 * Skip duplicates. 3959 */ 3960 for (j = 0; j < initNbSet1; j++) { 3961 n1 = set1->nodeTab[j]; 3962 if (n1 == n2) { 3963 goto skip_node; 3964 } else if ((n1->type == XML_NAMESPACE_DECL) && 3965 (n2->type == XML_NAMESPACE_DECL)) 3966 { 3967 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) && 3968 (xmlStrEqual(((xmlNsPtr) n1)->prefix, 3969 ((xmlNsPtr) n2)->prefix))) 3970 { 3971 /* 3972 * Free the namespace node. 3973 */ 3974 set2->nodeTab[i] = NULL; 3975 xmlXPathNodeSetFreeNs((xmlNsPtr) n2); 3976 goto skip_node; 3977 } 3978 } 3979 } 3980 /* 3981 * grow the nodeTab if needed 3982 */ 3983 if (set1->nodeMax == 0) { 3984 set1->nodeTab = (xmlNodePtr *) xmlMalloc( 3985 XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); 3986 if (set1->nodeTab == NULL) { 3987 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3988 return(NULL); 3989 } 3990 memset(set1->nodeTab, 0, 3991 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3992 set1->nodeMax = XML_NODESET_DEFAULT; 3993 } else if (set1->nodeNr >= set1->nodeMax) { 3994 xmlNodePtr *temp; 3995 3996 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 3997 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n"); 3998 return(NULL); 3999 } 4000 temp = (xmlNodePtr *) xmlRealloc( 4001 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr)); 4002 if (temp == NULL) { 4003 xmlXPathErrMemory(NULL, "merging nodeset\n"); 4004 return(NULL); 4005 } 4006 set1->nodeTab = temp; 4007 set1->nodeMax *= 2; 4008 } 4009 set1->nodeTab[set1->nodeNr++] = n2; 4010 skip_node: 4011 {} 4012 } 4013 } 4014 set2->nodeNr = 0; 4015 return(set1); 4016 } 4017 4018 /** 4019 * xmlXPathNodeSetMergeAndClearNoDupls: 4020 * @set1: the first NodeSet or NULL 4021 * @set2: the second NodeSet 4022 * 4023 * Merges two nodesets, all nodes from @set2 are added to @set1. 4024 * Doesn't check for duplicate nodes. Clears set2. 4025 * 4026 * Returns @set1 once extended or NULL in case of error. 4027 */ 4028 static xmlNodeSetPtr 4029 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2) 4030 { 4031 { 4032 int i; 4033 xmlNodePtr n2; 4034 4035 for (i = 0;i < set2->nodeNr;i++) { 4036 n2 = set2->nodeTab[i]; 4037 if (set1->nodeMax == 0) { 4038 set1->nodeTab = (xmlNodePtr *) xmlMalloc( 4039 XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); 4040 if (set1->nodeTab == NULL) { 4041 xmlXPathErrMemory(NULL, "merging nodeset\n"); 4042 return(NULL); 4043 } 4044 memset(set1->nodeTab, 0, 4045 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 4046 set1->nodeMax = XML_NODESET_DEFAULT; 4047 } else if (set1->nodeNr >= set1->nodeMax) { 4048 xmlNodePtr *temp; 4049 4050 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 4051 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n"); 4052 return(NULL); 4053 } 4054 temp = (xmlNodePtr *) xmlRealloc( 4055 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr)); 4056 if (temp == NULL) { 4057 xmlXPathErrMemory(NULL, "merging nodeset\n"); 4058 return(NULL); 4059 } 4060 set1->nodeTab = temp; 4061 set1->nodeMax *= 2; 4062 } 4063 set1->nodeTab[set1->nodeNr++] = n2; 4064 } 4065 } 4066 set2->nodeNr = 0; 4067 return(set1); 4068 } 4069 4070 /** 4071 * xmlXPathNodeSetDel: 4072 * @cur: the initial node set 4073 * @val: an xmlNodePtr 4074 * 4075 * Removes an xmlNodePtr from an existing NodeSet 4076 */ 4077 void 4078 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) { 4079 int i; 4080 4081 if (cur == NULL) return; 4082 if (val == NULL) return; 4083 4084 /* 4085 * find node in nodeTab 4086 */ 4087 for (i = 0;i < cur->nodeNr;i++) 4088 if (cur->nodeTab[i] == val) break; 4089 4090 if (i >= cur->nodeNr) { /* not found */ 4091 #ifdef DEBUG 4092 xmlGenericError(xmlGenericErrorContext, 4093 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n", 4094 val->name); 4095 #endif 4096 return; 4097 } 4098 if ((cur->nodeTab[i] != NULL) && 4099 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL)) 4100 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]); 4101 cur->nodeNr--; 4102 for (;i < cur->nodeNr;i++) 4103 cur->nodeTab[i] = cur->nodeTab[i + 1]; 4104 cur->nodeTab[cur->nodeNr] = NULL; 4105 } 4106 4107 /** 4108 * xmlXPathNodeSetRemove: 4109 * @cur: the initial node set 4110 * @val: the index to remove 4111 * 4112 * Removes an entry from an existing NodeSet list. 4113 */ 4114 void 4115 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) { 4116 if (cur == NULL) return; 4117 if (val >= cur->nodeNr) return; 4118 if ((cur->nodeTab[val] != NULL) && 4119 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL)) 4120 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]); 4121 cur->nodeNr--; 4122 for (;val < cur->nodeNr;val++) 4123 cur->nodeTab[val] = cur->nodeTab[val + 1]; 4124 cur->nodeTab[cur->nodeNr] = NULL; 4125 } 4126 4127 /** 4128 * xmlXPathFreeNodeSet: 4129 * @obj: the xmlNodeSetPtr to free 4130 * 4131 * Free the NodeSet compound (not the actual nodes !). 4132 */ 4133 void 4134 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) { 4135 if (obj == NULL) return; 4136 if (obj->nodeTab != NULL) { 4137 int i; 4138 4139 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 4140 for (i = 0;i < obj->nodeNr;i++) 4141 if ((obj->nodeTab[i] != NULL) && 4142 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL)) 4143 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]); 4144 xmlFree(obj->nodeTab); 4145 } 4146 xmlFree(obj); 4147 } 4148 4149 /** 4150 * xmlXPathNodeSetClearFromPos: 4151 * @set: the node set to be cleared 4152 * @pos: the start position to clear from 4153 * 4154 * Clears the list from temporary XPath objects (e.g. namespace nodes 4155 * are feed) starting with the entry at @pos, but does *not* free the list 4156 * itself. Sets the length of the list to @pos. 4157 */ 4158 static void 4159 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes) 4160 { 4161 if ((set == NULL) || (pos >= set->nodeNr)) 4162 return; 4163 else if ((hasNsNodes)) { 4164 int i; 4165 xmlNodePtr node; 4166 4167 for (i = pos; i < set->nodeNr; i++) { 4168 node = set->nodeTab[i]; 4169 if ((node != NULL) && 4170 (node->type == XML_NAMESPACE_DECL)) 4171 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 4172 } 4173 } 4174 set->nodeNr = pos; 4175 } 4176 4177 /** 4178 * xmlXPathNodeSetClear: 4179 * @set: the node set to clear 4180 * 4181 * Clears the list from all temporary XPath objects (e.g. namespace nodes 4182 * are feed), but does *not* free the list itself. Sets the length of the 4183 * list to 0. 4184 */ 4185 static void 4186 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes) 4187 { 4188 xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes); 4189 } 4190 4191 /** 4192 * xmlXPathNodeSetKeepLast: 4193 * @set: the node set to be cleared 4194 * 4195 * Move the last node to the first position and clear temporary XPath objects 4196 * (e.g. namespace nodes) from all other nodes. Sets the length of the list 4197 * to 1. 4198 */ 4199 static void 4200 xmlXPathNodeSetKeepLast(xmlNodeSetPtr set) 4201 { 4202 int i; 4203 xmlNodePtr node; 4204 4205 if ((set == NULL) || (set->nodeNr <= 1)) 4206 return; 4207 for (i = 0; i < set->nodeNr - 1; i++) { 4208 node = set->nodeTab[i]; 4209 if ((node != NULL) && 4210 (node->type == XML_NAMESPACE_DECL)) 4211 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 4212 } 4213 set->nodeTab[0] = set->nodeTab[set->nodeNr-1]; 4214 set->nodeNr = 1; 4215 } 4216 4217 /** 4218 * xmlXPathFreeValueTree: 4219 * @obj: the xmlNodeSetPtr to free 4220 * 4221 * Free the NodeSet compound and the actual tree, this is different 4222 * from xmlXPathFreeNodeSet() 4223 */ 4224 static void 4225 xmlXPathFreeValueTree(xmlNodeSetPtr obj) { 4226 int i; 4227 4228 if (obj == NULL) return; 4229 4230 if (obj->nodeTab != NULL) { 4231 for (i = 0;i < obj->nodeNr;i++) { 4232 if (obj->nodeTab[i] != NULL) { 4233 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) { 4234 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]); 4235 } else { 4236 xmlFreeNodeList(obj->nodeTab[i]); 4237 } 4238 } 4239 } 4240 xmlFree(obj->nodeTab); 4241 } 4242 xmlFree(obj); 4243 } 4244 4245 #if defined(DEBUG) || defined(DEBUG_STEP) 4246 /** 4247 * xmlGenericErrorContextNodeSet: 4248 * @output: a FILE * for the output 4249 * @obj: the xmlNodeSetPtr to display 4250 * 4251 * Quick display of a NodeSet 4252 */ 4253 void 4254 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) { 4255 int i; 4256 4257 if (output == NULL) output = xmlGenericErrorContext; 4258 if (obj == NULL) { 4259 fprintf(output, "NodeSet == NULL !\n"); 4260 return; 4261 } 4262 if (obj->nodeNr == 0) { 4263 fprintf(output, "NodeSet is empty\n"); 4264 return; 4265 } 4266 if (obj->nodeTab == NULL) { 4267 fprintf(output, " nodeTab == NULL !\n"); 4268 return; 4269 } 4270 for (i = 0; i < obj->nodeNr; i++) { 4271 if (obj->nodeTab[i] == NULL) { 4272 fprintf(output, " NULL !\n"); 4273 return; 4274 } 4275 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) || 4276 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE)) 4277 fprintf(output, " /"); 4278 else if (obj->nodeTab[i]->name == NULL) 4279 fprintf(output, " noname!"); 4280 else fprintf(output, " %s", obj->nodeTab[i]->name); 4281 } 4282 fprintf(output, "\n"); 4283 } 4284 #endif 4285 4286 /** 4287 * xmlXPathNewNodeSet: 4288 * @val: the NodePtr value 4289 * 4290 * Create a new xmlXPathObjectPtr of type NodeSet and initialize 4291 * it with the single Node @val 4292 * 4293 * Returns the newly created object. 4294 */ 4295 xmlXPathObjectPtr 4296 xmlXPathNewNodeSet(xmlNodePtr val) { 4297 xmlXPathObjectPtr ret; 4298 4299 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4300 if (ret == NULL) { 4301 xmlXPathErrMemory(NULL, "creating nodeset\n"); 4302 return(NULL); 4303 } 4304 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4305 ret->type = XPATH_NODESET; 4306 ret->boolval = 0; 4307 /* TODO: Check memory error. */ 4308 ret->nodesetval = xmlXPathNodeSetCreate(val); 4309 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 4310 #ifdef XP_DEBUG_OBJ_USAGE 4311 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET); 4312 #endif 4313 return(ret); 4314 } 4315 4316 /** 4317 * xmlXPathNewValueTree: 4318 * @val: the NodePtr value 4319 * 4320 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize 4321 * it with the tree root @val 4322 * 4323 * Returns the newly created object. 4324 */ 4325 xmlXPathObjectPtr 4326 xmlXPathNewValueTree(xmlNodePtr val) { 4327 xmlXPathObjectPtr ret; 4328 4329 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4330 if (ret == NULL) { 4331 xmlXPathErrMemory(NULL, "creating result value tree\n"); 4332 return(NULL); 4333 } 4334 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4335 ret->type = XPATH_XSLT_TREE; 4336 ret->boolval = 1; 4337 ret->user = (void *) val; 4338 ret->nodesetval = xmlXPathNodeSetCreate(val); 4339 #ifdef XP_DEBUG_OBJ_USAGE 4340 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE); 4341 #endif 4342 return(ret); 4343 } 4344 4345 /** 4346 * xmlXPathNewNodeSetList: 4347 * @val: an existing NodeSet 4348 * 4349 * Create a new xmlXPathObjectPtr of type NodeSet and initialize 4350 * it with the Nodeset @val 4351 * 4352 * Returns the newly created object. 4353 */ 4354 xmlXPathObjectPtr 4355 xmlXPathNewNodeSetList(xmlNodeSetPtr val) 4356 { 4357 xmlXPathObjectPtr ret; 4358 int i; 4359 4360 if (val == NULL) 4361 ret = NULL; 4362 else if (val->nodeTab == NULL) 4363 ret = xmlXPathNewNodeSet(NULL); 4364 else { 4365 ret = xmlXPathNewNodeSet(val->nodeTab[0]); 4366 if (ret) { 4367 for (i = 1; i < val->nodeNr; ++i) { 4368 /* TODO: Propagate memory error. */ 4369 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]) 4370 < 0) break; 4371 } 4372 } 4373 } 4374 4375 return (ret); 4376 } 4377 4378 /** 4379 * xmlXPathWrapNodeSet: 4380 * @val: the NodePtr value 4381 * 4382 * Wrap the Nodeset @val in a new xmlXPathObjectPtr 4383 * 4384 * Returns the newly created object. 4385 */ 4386 xmlXPathObjectPtr 4387 xmlXPathWrapNodeSet(xmlNodeSetPtr val) { 4388 xmlXPathObjectPtr ret; 4389 4390 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4391 if (ret == NULL) { 4392 xmlXPathErrMemory(NULL, "creating node set object\n"); 4393 return(NULL); 4394 } 4395 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4396 ret->type = XPATH_NODESET; 4397 ret->nodesetval = val; 4398 #ifdef XP_DEBUG_OBJ_USAGE 4399 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET); 4400 #endif 4401 return(ret); 4402 } 4403 4404 /** 4405 * xmlXPathFreeNodeSetList: 4406 * @obj: an existing NodeSetList object 4407 * 4408 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in 4409 * the list contrary to xmlXPathFreeObject(). 4410 */ 4411 void 4412 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) { 4413 if (obj == NULL) return; 4414 #ifdef XP_DEBUG_OBJ_USAGE 4415 xmlXPathDebugObjUsageReleased(NULL, obj->type); 4416 #endif 4417 xmlFree(obj); 4418 } 4419 4420 /** 4421 * xmlXPathDifference: 4422 * @nodes1: a node-set 4423 * @nodes2: a node-set 4424 * 4425 * Implements the EXSLT - Sets difference() function: 4426 * node-set set:difference (node-set, node-set) 4427 * 4428 * Returns the difference between the two node sets, or nodes1 if 4429 * nodes2 is empty 4430 */ 4431 xmlNodeSetPtr 4432 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4433 xmlNodeSetPtr ret; 4434 int i, l1; 4435 xmlNodePtr cur; 4436 4437 if (xmlXPathNodeSetIsEmpty(nodes2)) 4438 return(nodes1); 4439 4440 /* TODO: Check memory error. */ 4441 ret = xmlXPathNodeSetCreate(NULL); 4442 if (xmlXPathNodeSetIsEmpty(nodes1)) 4443 return(ret); 4444 4445 l1 = xmlXPathNodeSetGetLength(nodes1); 4446 4447 for (i = 0; i < l1; i++) { 4448 cur = xmlXPathNodeSetItem(nodes1, i); 4449 if (!xmlXPathNodeSetContains(nodes2, cur)) { 4450 /* TODO: Propagate memory error. */ 4451 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) 4452 break; 4453 } 4454 } 4455 return(ret); 4456 } 4457 4458 /** 4459 * xmlXPathIntersection: 4460 * @nodes1: a node-set 4461 * @nodes2: a node-set 4462 * 4463 * Implements the EXSLT - Sets intersection() function: 4464 * node-set set:intersection (node-set, node-set) 4465 * 4466 * Returns a node set comprising the nodes that are within both the 4467 * node sets passed as arguments 4468 */ 4469 xmlNodeSetPtr 4470 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4471 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL); 4472 int i, l1; 4473 xmlNodePtr cur; 4474 4475 if (ret == NULL) 4476 return(ret); 4477 if (xmlXPathNodeSetIsEmpty(nodes1)) 4478 return(ret); 4479 if (xmlXPathNodeSetIsEmpty(nodes2)) 4480 return(ret); 4481 4482 l1 = xmlXPathNodeSetGetLength(nodes1); 4483 4484 for (i = 0; i < l1; i++) { 4485 cur = xmlXPathNodeSetItem(nodes1, i); 4486 if (xmlXPathNodeSetContains(nodes2, cur)) { 4487 /* TODO: Propagate memory error. */ 4488 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) 4489 break; 4490 } 4491 } 4492 return(ret); 4493 } 4494 4495 /** 4496 * xmlXPathDistinctSorted: 4497 * @nodes: a node-set, sorted by document order 4498 * 4499 * Implements the EXSLT - Sets distinct() function: 4500 * node-set set:distinct (node-set) 4501 * 4502 * Returns a subset of the nodes contained in @nodes, or @nodes if 4503 * it is empty 4504 */ 4505 xmlNodeSetPtr 4506 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) { 4507 xmlNodeSetPtr ret; 4508 xmlHashTablePtr hash; 4509 int i, l; 4510 xmlChar * strval; 4511 xmlNodePtr cur; 4512 4513 if (xmlXPathNodeSetIsEmpty(nodes)) 4514 return(nodes); 4515 4516 ret = xmlXPathNodeSetCreate(NULL); 4517 if (ret == NULL) 4518 return(ret); 4519 l = xmlXPathNodeSetGetLength(nodes); 4520 hash = xmlHashCreate (l); 4521 for (i = 0; i < l; i++) { 4522 cur = xmlXPathNodeSetItem(nodes, i); 4523 strval = xmlXPathCastNodeToString(cur); 4524 if (xmlHashLookup(hash, strval) == NULL) { 4525 xmlHashAddEntry(hash, strval, strval); 4526 /* TODO: Propagate memory error. */ 4527 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) 4528 break; 4529 } else { 4530 xmlFree(strval); 4531 } 4532 } 4533 xmlHashFree(hash, xmlHashDefaultDeallocator); 4534 return(ret); 4535 } 4536 4537 /** 4538 * xmlXPathDistinct: 4539 * @nodes: a node-set 4540 * 4541 * Implements the EXSLT - Sets distinct() function: 4542 * node-set set:distinct (node-set) 4543 * @nodes is sorted by document order, then #exslSetsDistinctSorted 4544 * is called with the sorted node-set 4545 * 4546 * Returns a subset of the nodes contained in @nodes, or @nodes if 4547 * it is empty 4548 */ 4549 xmlNodeSetPtr 4550 xmlXPathDistinct (xmlNodeSetPtr nodes) { 4551 if (xmlXPathNodeSetIsEmpty(nodes)) 4552 return(nodes); 4553 4554 xmlXPathNodeSetSort(nodes); 4555 return(xmlXPathDistinctSorted(nodes)); 4556 } 4557 4558 /** 4559 * xmlXPathHasSameNodes: 4560 * @nodes1: a node-set 4561 * @nodes2: a node-set 4562 * 4563 * Implements the EXSLT - Sets has-same-nodes function: 4564 * boolean set:has-same-node(node-set, node-set) 4565 * 4566 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0) 4567 * otherwise 4568 */ 4569 int 4570 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4571 int i, l; 4572 xmlNodePtr cur; 4573 4574 if (xmlXPathNodeSetIsEmpty(nodes1) || 4575 xmlXPathNodeSetIsEmpty(nodes2)) 4576 return(0); 4577 4578 l = xmlXPathNodeSetGetLength(nodes1); 4579 for (i = 0; i < l; i++) { 4580 cur = xmlXPathNodeSetItem(nodes1, i); 4581 if (xmlXPathNodeSetContains(nodes2, cur)) 4582 return(1); 4583 } 4584 return(0); 4585 } 4586 4587 /** 4588 * xmlXPathNodeLeadingSorted: 4589 * @nodes: a node-set, sorted by document order 4590 * @node: a node 4591 * 4592 * Implements the EXSLT - Sets leading() function: 4593 * node-set set:leading (node-set, node-set) 4594 * 4595 * Returns the nodes in @nodes that precede @node in document order, 4596 * @nodes if @node is NULL or an empty node-set if @nodes 4597 * doesn't contain @node 4598 */ 4599 xmlNodeSetPtr 4600 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { 4601 int i, l; 4602 xmlNodePtr cur; 4603 xmlNodeSetPtr ret; 4604 4605 if (node == NULL) 4606 return(nodes); 4607 4608 ret = xmlXPathNodeSetCreate(NULL); 4609 if (ret == NULL) 4610 return(ret); 4611 if (xmlXPathNodeSetIsEmpty(nodes) || 4612 (!xmlXPathNodeSetContains(nodes, node))) 4613 return(ret); 4614 4615 l = xmlXPathNodeSetGetLength(nodes); 4616 for (i = 0; i < l; i++) { 4617 cur = xmlXPathNodeSetItem(nodes, i); 4618 if (cur == node) 4619 break; 4620 /* TODO: Propagate memory error. */ 4621 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) 4622 break; 4623 } 4624 return(ret); 4625 } 4626 4627 /** 4628 * xmlXPathNodeLeading: 4629 * @nodes: a node-set 4630 * @node: a node 4631 * 4632 * Implements the EXSLT - Sets leading() function: 4633 * node-set set:leading (node-set, node-set) 4634 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted 4635 * is called. 4636 * 4637 * Returns the nodes in @nodes that precede @node in document order, 4638 * @nodes if @node is NULL or an empty node-set if @nodes 4639 * doesn't contain @node 4640 */ 4641 xmlNodeSetPtr 4642 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) { 4643 xmlXPathNodeSetSort(nodes); 4644 return(xmlXPathNodeLeadingSorted(nodes, node)); 4645 } 4646 4647 /** 4648 * xmlXPathLeadingSorted: 4649 * @nodes1: a node-set, sorted by document order 4650 * @nodes2: a node-set, sorted by document order 4651 * 4652 * Implements the EXSLT - Sets leading() function: 4653 * node-set set:leading (node-set, node-set) 4654 * 4655 * Returns the nodes in @nodes1 that precede the first node in @nodes2 4656 * in document order, @nodes1 if @nodes2 is NULL or empty or 4657 * an empty node-set if @nodes1 doesn't contain @nodes2 4658 */ 4659 xmlNodeSetPtr 4660 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4661 if (xmlXPathNodeSetIsEmpty(nodes2)) 4662 return(nodes1); 4663 return(xmlXPathNodeLeadingSorted(nodes1, 4664 xmlXPathNodeSetItem(nodes2, 1))); 4665 } 4666 4667 /** 4668 * xmlXPathLeading: 4669 * @nodes1: a node-set 4670 * @nodes2: a node-set 4671 * 4672 * Implements the EXSLT - Sets leading() function: 4673 * node-set set:leading (node-set, node-set) 4674 * @nodes1 and @nodes2 are sorted by document order, then 4675 * #exslSetsLeadingSorted is called. 4676 * 4677 * Returns the nodes in @nodes1 that precede the first node in @nodes2 4678 * in document order, @nodes1 if @nodes2 is NULL or empty or 4679 * an empty node-set if @nodes1 doesn't contain @nodes2 4680 */ 4681 xmlNodeSetPtr 4682 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4683 if (xmlXPathNodeSetIsEmpty(nodes2)) 4684 return(nodes1); 4685 if (xmlXPathNodeSetIsEmpty(nodes1)) 4686 return(xmlXPathNodeSetCreate(NULL)); 4687 xmlXPathNodeSetSort(nodes1); 4688 xmlXPathNodeSetSort(nodes2); 4689 return(xmlXPathNodeLeadingSorted(nodes1, 4690 xmlXPathNodeSetItem(nodes2, 1))); 4691 } 4692 4693 /** 4694 * xmlXPathNodeTrailingSorted: 4695 * @nodes: a node-set, sorted by document order 4696 * @node: a node 4697 * 4698 * Implements the EXSLT - Sets trailing() function: 4699 * node-set set:trailing (node-set, node-set) 4700 * 4701 * Returns the nodes in @nodes that follow @node in document order, 4702 * @nodes if @node is NULL or an empty node-set if @nodes 4703 * doesn't contain @node 4704 */ 4705 xmlNodeSetPtr 4706 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { 4707 int i, l; 4708 xmlNodePtr cur; 4709 xmlNodeSetPtr ret; 4710 4711 if (node == NULL) 4712 return(nodes); 4713 4714 ret = xmlXPathNodeSetCreate(NULL); 4715 if (ret == NULL) 4716 return(ret); 4717 if (xmlXPathNodeSetIsEmpty(nodes) || 4718 (!xmlXPathNodeSetContains(nodes, node))) 4719 return(ret); 4720 4721 l = xmlXPathNodeSetGetLength(nodes); 4722 for (i = l - 1; i >= 0; i--) { 4723 cur = xmlXPathNodeSetItem(nodes, i); 4724 if (cur == node) 4725 break; 4726 /* TODO: Propagate memory error. */ 4727 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) 4728 break; 4729 } 4730 xmlXPathNodeSetSort(ret); /* bug 413451 */ 4731 return(ret); 4732 } 4733 4734 /** 4735 * xmlXPathNodeTrailing: 4736 * @nodes: a node-set 4737 * @node: a node 4738 * 4739 * Implements the EXSLT - Sets trailing() function: 4740 * node-set set:trailing (node-set, node-set) 4741 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted 4742 * is called. 4743 * 4744 * Returns the nodes in @nodes that follow @node in document order, 4745 * @nodes if @node is NULL or an empty node-set if @nodes 4746 * doesn't contain @node 4747 */ 4748 xmlNodeSetPtr 4749 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) { 4750 xmlXPathNodeSetSort(nodes); 4751 return(xmlXPathNodeTrailingSorted(nodes, node)); 4752 } 4753 4754 /** 4755 * xmlXPathTrailingSorted: 4756 * @nodes1: a node-set, sorted by document order 4757 * @nodes2: a node-set, sorted by document order 4758 * 4759 * Implements the EXSLT - Sets trailing() function: 4760 * node-set set:trailing (node-set, node-set) 4761 * 4762 * Returns the nodes in @nodes1 that follow the first node in @nodes2 4763 * in document order, @nodes1 if @nodes2 is NULL or empty or 4764 * an empty node-set if @nodes1 doesn't contain @nodes2 4765 */ 4766 xmlNodeSetPtr 4767 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4768 if (xmlXPathNodeSetIsEmpty(nodes2)) 4769 return(nodes1); 4770 return(xmlXPathNodeTrailingSorted(nodes1, 4771 xmlXPathNodeSetItem(nodes2, 0))); 4772 } 4773 4774 /** 4775 * xmlXPathTrailing: 4776 * @nodes1: a node-set 4777 * @nodes2: a node-set 4778 * 4779 * Implements the EXSLT - Sets trailing() function: 4780 * node-set set:trailing (node-set, node-set) 4781 * @nodes1 and @nodes2 are sorted by document order, then 4782 * #xmlXPathTrailingSorted is called. 4783 * 4784 * Returns the nodes in @nodes1 that follow the first node in @nodes2 4785 * in document order, @nodes1 if @nodes2 is NULL or empty or 4786 * an empty node-set if @nodes1 doesn't contain @nodes2 4787 */ 4788 xmlNodeSetPtr 4789 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4790 if (xmlXPathNodeSetIsEmpty(nodes2)) 4791 return(nodes1); 4792 if (xmlXPathNodeSetIsEmpty(nodes1)) 4793 return(xmlXPathNodeSetCreate(NULL)); 4794 xmlXPathNodeSetSort(nodes1); 4795 xmlXPathNodeSetSort(nodes2); 4796 return(xmlXPathNodeTrailingSorted(nodes1, 4797 xmlXPathNodeSetItem(nodes2, 0))); 4798 } 4799 4800 /************************************************************************ 4801 * * 4802 * Routines to handle extra functions * 4803 * * 4804 ************************************************************************/ 4805 4806 /** 4807 * xmlXPathRegisterFunc: 4808 * @ctxt: the XPath context 4809 * @name: the function name 4810 * @f: the function implementation or NULL 4811 * 4812 * Register a new function. If @f is NULL it unregisters the function 4813 * 4814 * Returns 0 in case of success, -1 in case of error 4815 */ 4816 int 4817 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name, 4818 xmlXPathFunction f) { 4819 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f)); 4820 } 4821 4822 /** 4823 * xmlXPathRegisterFuncNS: 4824 * @ctxt: the XPath context 4825 * @name: the function name 4826 * @ns_uri: the function namespace URI 4827 * @f: the function implementation or NULL 4828 * 4829 * Register a new function. If @f is NULL it unregisters the function 4830 * 4831 * Returns 0 in case of success, -1 in case of error 4832 */ 4833 int 4834 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name, 4835 const xmlChar *ns_uri, xmlXPathFunction f) { 4836 if (ctxt == NULL) 4837 return(-1); 4838 if (name == NULL) 4839 return(-1); 4840 4841 if (ctxt->funcHash == NULL) 4842 ctxt->funcHash = xmlHashCreate(0); 4843 if (ctxt->funcHash == NULL) 4844 return(-1); 4845 if (f == NULL) 4846 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL)); 4847 XML_IGNORE_PEDANTIC_WARNINGS 4848 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f)); 4849 XML_POP_WARNINGS 4850 } 4851 4852 /** 4853 * xmlXPathRegisterFuncLookup: 4854 * @ctxt: the XPath context 4855 * @f: the lookup function 4856 * @funcCtxt: the lookup data 4857 * 4858 * Registers an external mechanism to do function lookup. 4859 */ 4860 void 4861 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt, 4862 xmlXPathFuncLookupFunc f, 4863 void *funcCtxt) { 4864 if (ctxt == NULL) 4865 return; 4866 ctxt->funcLookupFunc = f; 4867 ctxt->funcLookupData = funcCtxt; 4868 } 4869 4870 /** 4871 * xmlXPathFunctionLookup: 4872 * @ctxt: the XPath context 4873 * @name: the function name 4874 * 4875 * Search in the Function array of the context for the given 4876 * function. 4877 * 4878 * Returns the xmlXPathFunction or NULL if not found 4879 */ 4880 xmlXPathFunction 4881 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { 4882 if (ctxt == NULL) 4883 return (NULL); 4884 4885 if (ctxt->funcLookupFunc != NULL) { 4886 xmlXPathFunction ret; 4887 xmlXPathFuncLookupFunc f; 4888 4889 f = ctxt->funcLookupFunc; 4890 ret = f(ctxt->funcLookupData, name, NULL); 4891 if (ret != NULL) 4892 return(ret); 4893 } 4894 return(xmlXPathFunctionLookupNS(ctxt, name, NULL)); 4895 } 4896 4897 /** 4898 * xmlXPathFunctionLookupNS: 4899 * @ctxt: the XPath context 4900 * @name: the function name 4901 * @ns_uri: the function namespace URI 4902 * 4903 * Search in the Function array of the context for the given 4904 * function. 4905 * 4906 * Returns the xmlXPathFunction or NULL if not found 4907 */ 4908 xmlXPathFunction 4909 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name, 4910 const xmlChar *ns_uri) { 4911 xmlXPathFunction ret; 4912 4913 if (ctxt == NULL) 4914 return(NULL); 4915 if (name == NULL) 4916 return(NULL); 4917 4918 if (ctxt->funcLookupFunc != NULL) { 4919 xmlXPathFuncLookupFunc f; 4920 4921 f = ctxt->funcLookupFunc; 4922 ret = f(ctxt->funcLookupData, name, ns_uri); 4923 if (ret != NULL) 4924 return(ret); 4925 } 4926 4927 if (ctxt->funcHash == NULL) 4928 return(NULL); 4929 4930 XML_IGNORE_PEDANTIC_WARNINGS 4931 ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri); 4932 XML_POP_WARNINGS 4933 return(ret); 4934 } 4935 4936 /** 4937 * xmlXPathRegisteredFuncsCleanup: 4938 * @ctxt: the XPath context 4939 * 4940 * Cleanup the XPath context data associated to registered functions 4941 */ 4942 void 4943 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) { 4944 if (ctxt == NULL) 4945 return; 4946 4947 xmlHashFree(ctxt->funcHash, NULL); 4948 ctxt->funcHash = NULL; 4949 } 4950 4951 /************************************************************************ 4952 * * 4953 * Routines to handle Variables * 4954 * * 4955 ************************************************************************/ 4956 4957 /** 4958 * xmlXPathRegisterVariable: 4959 * @ctxt: the XPath context 4960 * @name: the variable name 4961 * @value: the variable value or NULL 4962 * 4963 * Register a new variable value. If @value is NULL it unregisters 4964 * the variable 4965 * 4966 * Returns 0 in case of success, -1 in case of error 4967 */ 4968 int 4969 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name, 4970 xmlXPathObjectPtr value) { 4971 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value)); 4972 } 4973 4974 /** 4975 * xmlXPathRegisterVariableNS: 4976 * @ctxt: the XPath context 4977 * @name: the variable name 4978 * @ns_uri: the variable namespace URI 4979 * @value: the variable value or NULL 4980 * 4981 * Register a new variable value. If @value is NULL it unregisters 4982 * the variable 4983 * 4984 * Returns 0 in case of success, -1 in case of error 4985 */ 4986 int 4987 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name, 4988 const xmlChar *ns_uri, 4989 xmlXPathObjectPtr value) { 4990 if (ctxt == NULL) 4991 return(-1); 4992 if (name == NULL) 4993 return(-1); 4994 4995 if (ctxt->varHash == NULL) 4996 ctxt->varHash = xmlHashCreate(0); 4997 if (ctxt->varHash == NULL) 4998 return(-1); 4999 if (value == NULL) 5000 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri, 5001 xmlXPathFreeObjectEntry)); 5002 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri, 5003 (void *) value, xmlXPathFreeObjectEntry)); 5004 } 5005 5006 /** 5007 * xmlXPathRegisterVariableLookup: 5008 * @ctxt: the XPath context 5009 * @f: the lookup function 5010 * @data: the lookup data 5011 * 5012 * register an external mechanism to do variable lookup 5013 */ 5014 void 5015 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt, 5016 xmlXPathVariableLookupFunc f, void *data) { 5017 if (ctxt == NULL) 5018 return; 5019 ctxt->varLookupFunc = f; 5020 ctxt->varLookupData = data; 5021 } 5022 5023 /** 5024 * xmlXPathVariableLookup: 5025 * @ctxt: the XPath context 5026 * @name: the variable name 5027 * 5028 * Search in the Variable array of the context for the given 5029 * variable value. 5030 * 5031 * Returns a copy of the value or NULL if not found 5032 */ 5033 xmlXPathObjectPtr 5034 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { 5035 if (ctxt == NULL) 5036 return(NULL); 5037 5038 if (ctxt->varLookupFunc != NULL) { 5039 xmlXPathObjectPtr ret; 5040 5041 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc) 5042 (ctxt->varLookupData, name, NULL); 5043 return(ret); 5044 } 5045 return(xmlXPathVariableLookupNS(ctxt, name, NULL)); 5046 } 5047 5048 /** 5049 * xmlXPathVariableLookupNS: 5050 * @ctxt: the XPath context 5051 * @name: the variable name 5052 * @ns_uri: the variable namespace URI 5053 * 5054 * Search in the Variable array of the context for the given 5055 * variable value. 5056 * 5057 * Returns the a copy of the value or NULL if not found 5058 */ 5059 xmlXPathObjectPtr 5060 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name, 5061 const xmlChar *ns_uri) { 5062 if (ctxt == NULL) 5063 return(NULL); 5064 5065 if (ctxt->varLookupFunc != NULL) { 5066 xmlXPathObjectPtr ret; 5067 5068 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc) 5069 (ctxt->varLookupData, name, ns_uri); 5070 if (ret != NULL) return(ret); 5071 } 5072 5073 if (ctxt->varHash == NULL) 5074 return(NULL); 5075 if (name == NULL) 5076 return(NULL); 5077 5078 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr) 5079 xmlHashLookup2(ctxt->varHash, name, ns_uri))); 5080 } 5081 5082 /** 5083 * xmlXPathRegisteredVariablesCleanup: 5084 * @ctxt: the XPath context 5085 * 5086 * Cleanup the XPath context data associated to registered variables 5087 */ 5088 void 5089 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) { 5090 if (ctxt == NULL) 5091 return; 5092 5093 xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry); 5094 ctxt->varHash = NULL; 5095 } 5096 5097 /** 5098 * xmlXPathRegisterNs: 5099 * @ctxt: the XPath context 5100 * @prefix: the namespace prefix cannot be NULL or empty string 5101 * @ns_uri: the namespace name 5102 * 5103 * Register a new namespace. If @ns_uri is NULL it unregisters 5104 * the namespace 5105 * 5106 * Returns 0 in case of success, -1 in case of error 5107 */ 5108 int 5109 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix, 5110 const xmlChar *ns_uri) { 5111 if (ctxt == NULL) 5112 return(-1); 5113 if (prefix == NULL) 5114 return(-1); 5115 if (prefix[0] == 0) 5116 return(-1); 5117 5118 if (ctxt->nsHash == NULL) 5119 ctxt->nsHash = xmlHashCreate(10); 5120 if (ctxt->nsHash == NULL) 5121 return(-1); 5122 if (ns_uri == NULL) 5123 return(xmlHashRemoveEntry(ctxt->nsHash, prefix, 5124 xmlHashDefaultDeallocator)); 5125 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri), 5126 xmlHashDefaultDeallocator)); 5127 } 5128 5129 /** 5130 * xmlXPathNsLookup: 5131 * @ctxt: the XPath context 5132 * @prefix: the namespace prefix value 5133 * 5134 * Search in the namespace declaration array of the context for the given 5135 * namespace name associated to the given prefix 5136 * 5137 * Returns the value or NULL if not found 5138 */ 5139 const xmlChar * 5140 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) { 5141 if (ctxt == NULL) 5142 return(NULL); 5143 if (prefix == NULL) 5144 return(NULL); 5145 5146 #ifdef XML_XML_NAMESPACE 5147 if (xmlStrEqual(prefix, (const xmlChar *) "xml")) 5148 return(XML_XML_NAMESPACE); 5149 #endif 5150 5151 if (ctxt->namespaces != NULL) { 5152 int i; 5153 5154 for (i = 0;i < ctxt->nsNr;i++) { 5155 if ((ctxt->namespaces[i] != NULL) && 5156 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix))) 5157 return(ctxt->namespaces[i]->href); 5158 } 5159 } 5160 5161 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix)); 5162 } 5163 5164 /** 5165 * xmlXPathRegisteredNsCleanup: 5166 * @ctxt: the XPath context 5167 * 5168 * Cleanup the XPath context data associated to registered variables 5169 */ 5170 void 5171 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) { 5172 if (ctxt == NULL) 5173 return; 5174 5175 xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator); 5176 ctxt->nsHash = NULL; 5177 } 5178 5179 /************************************************************************ 5180 * * 5181 * Routines to handle Values * 5182 * * 5183 ************************************************************************/ 5184 5185 /* Allocations are terrible, one needs to optimize all this !!! */ 5186 5187 /** 5188 * xmlXPathNewFloat: 5189 * @val: the double value 5190 * 5191 * Create a new xmlXPathObjectPtr of type double and of value @val 5192 * 5193 * Returns the newly created object. 5194 */ 5195 xmlXPathObjectPtr 5196 xmlXPathNewFloat(double val) { 5197 xmlXPathObjectPtr ret; 5198 5199 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5200 if (ret == NULL) { 5201 xmlXPathErrMemory(NULL, "creating float object\n"); 5202 return(NULL); 5203 } 5204 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5205 ret->type = XPATH_NUMBER; 5206 ret->floatval = val; 5207 #ifdef XP_DEBUG_OBJ_USAGE 5208 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER); 5209 #endif 5210 return(ret); 5211 } 5212 5213 /** 5214 * xmlXPathNewBoolean: 5215 * @val: the boolean value 5216 * 5217 * Create a new xmlXPathObjectPtr of type boolean and of value @val 5218 * 5219 * Returns the newly created object. 5220 */ 5221 xmlXPathObjectPtr 5222 xmlXPathNewBoolean(int val) { 5223 xmlXPathObjectPtr ret; 5224 5225 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5226 if (ret == NULL) { 5227 xmlXPathErrMemory(NULL, "creating boolean object\n"); 5228 return(NULL); 5229 } 5230 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5231 ret->type = XPATH_BOOLEAN; 5232 ret->boolval = (val != 0); 5233 #ifdef XP_DEBUG_OBJ_USAGE 5234 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN); 5235 #endif 5236 return(ret); 5237 } 5238 5239 /** 5240 * xmlXPathNewString: 5241 * @val: the xmlChar * value 5242 * 5243 * Create a new xmlXPathObjectPtr of type string and of value @val 5244 * 5245 * Returns the newly created object. 5246 */ 5247 xmlXPathObjectPtr 5248 xmlXPathNewString(const xmlChar *val) { 5249 xmlXPathObjectPtr ret; 5250 5251 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5252 if (ret == NULL) { 5253 xmlXPathErrMemory(NULL, "creating string object\n"); 5254 return(NULL); 5255 } 5256 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5257 ret->type = XPATH_STRING; 5258 if (val != NULL) 5259 ret->stringval = xmlStrdup(val); 5260 else 5261 ret->stringval = xmlStrdup((const xmlChar *)""); 5262 #ifdef XP_DEBUG_OBJ_USAGE 5263 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); 5264 #endif 5265 return(ret); 5266 } 5267 5268 /** 5269 * xmlXPathWrapString: 5270 * @val: the xmlChar * value 5271 * 5272 * Wraps the @val string into an XPath object. 5273 * 5274 * Returns the newly created object. 5275 */ 5276 xmlXPathObjectPtr 5277 xmlXPathWrapString (xmlChar *val) { 5278 xmlXPathObjectPtr ret; 5279 5280 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5281 if (ret == NULL) { 5282 xmlXPathErrMemory(NULL, "creating string object\n"); 5283 return(NULL); 5284 } 5285 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5286 ret->type = XPATH_STRING; 5287 ret->stringval = val; 5288 #ifdef XP_DEBUG_OBJ_USAGE 5289 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); 5290 #endif 5291 return(ret); 5292 } 5293 5294 /** 5295 * xmlXPathNewCString: 5296 * @val: the char * value 5297 * 5298 * Create a new xmlXPathObjectPtr of type string and of value @val 5299 * 5300 * Returns the newly created object. 5301 */ 5302 xmlXPathObjectPtr 5303 xmlXPathNewCString(const char *val) { 5304 xmlXPathObjectPtr ret; 5305 5306 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5307 if (ret == NULL) { 5308 xmlXPathErrMemory(NULL, "creating string object\n"); 5309 return(NULL); 5310 } 5311 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5312 ret->type = XPATH_STRING; 5313 ret->stringval = xmlStrdup(BAD_CAST val); 5314 #ifdef XP_DEBUG_OBJ_USAGE 5315 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); 5316 #endif 5317 return(ret); 5318 } 5319 5320 /** 5321 * xmlXPathWrapCString: 5322 * @val: the char * value 5323 * 5324 * Wraps a string into an XPath object. 5325 * 5326 * Returns the newly created object. 5327 */ 5328 xmlXPathObjectPtr 5329 xmlXPathWrapCString (char * val) { 5330 return(xmlXPathWrapString((xmlChar *)(val))); 5331 } 5332 5333 /** 5334 * xmlXPathWrapExternal: 5335 * @val: the user data 5336 * 5337 * Wraps the @val data into an XPath object. 5338 * 5339 * Returns the newly created object. 5340 */ 5341 xmlXPathObjectPtr 5342 xmlXPathWrapExternal (void *val) { 5343 xmlXPathObjectPtr ret; 5344 5345 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5346 if (ret == NULL) { 5347 xmlXPathErrMemory(NULL, "creating user object\n"); 5348 return(NULL); 5349 } 5350 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5351 ret->type = XPATH_USERS; 5352 ret->user = val; 5353 #ifdef XP_DEBUG_OBJ_USAGE 5354 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS); 5355 #endif 5356 return(ret); 5357 } 5358 5359 /** 5360 * xmlXPathObjectCopy: 5361 * @val: the original object 5362 * 5363 * allocate a new copy of a given object 5364 * 5365 * Returns the newly created object. 5366 */ 5367 xmlXPathObjectPtr 5368 xmlXPathObjectCopy(xmlXPathObjectPtr val) { 5369 xmlXPathObjectPtr ret; 5370 5371 if (val == NULL) 5372 return(NULL); 5373 5374 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5375 if (ret == NULL) { 5376 xmlXPathErrMemory(NULL, "copying object\n"); 5377 return(NULL); 5378 } 5379 memcpy(ret, val , (size_t) sizeof(xmlXPathObject)); 5380 #ifdef XP_DEBUG_OBJ_USAGE 5381 xmlXPathDebugObjUsageRequested(NULL, val->type); 5382 #endif 5383 switch (val->type) { 5384 case XPATH_BOOLEAN: 5385 case XPATH_NUMBER: 5386 case XPATH_POINT: 5387 case XPATH_RANGE: 5388 break; 5389 case XPATH_STRING: 5390 ret->stringval = xmlStrdup(val->stringval); 5391 break; 5392 case XPATH_XSLT_TREE: 5393 #if 0 5394 /* 5395 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that 5396 this previous handling is no longer correct, and can cause some serious 5397 problems (ref. bug 145547) 5398 */ 5399 if ((val->nodesetval != NULL) && 5400 (val->nodesetval->nodeTab != NULL)) { 5401 xmlNodePtr cur, tmp; 5402 xmlDocPtr top; 5403 5404 ret->boolval = 1; 5405 top = xmlNewDoc(NULL); 5406 top->name = (char *) 5407 xmlStrdup(val->nodesetval->nodeTab[0]->name); 5408 ret->user = top; 5409 if (top != NULL) { 5410 top->doc = top; 5411 cur = val->nodesetval->nodeTab[0]->children; 5412 while (cur != NULL) { 5413 tmp = xmlDocCopyNode(cur, top, 1); 5414 xmlAddChild((xmlNodePtr) top, tmp); 5415 cur = cur->next; 5416 } 5417 } 5418 5419 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top); 5420 } else 5421 ret->nodesetval = xmlXPathNodeSetCreate(NULL); 5422 /* Deallocate the copied tree value */ 5423 break; 5424 #endif 5425 case XPATH_NODESET: 5426 /* TODO: Check memory error. */ 5427 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval); 5428 /* Do not deallocate the copied tree value */ 5429 ret->boolval = 0; 5430 break; 5431 case XPATH_LOCATIONSET: 5432 #ifdef LIBXML_XPTR_ENABLED 5433 { 5434 xmlLocationSetPtr loc = val->user; 5435 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc); 5436 break; 5437 } 5438 #endif 5439 case XPATH_USERS: 5440 ret->user = val->user; 5441 break; 5442 case XPATH_UNDEFINED: 5443 xmlGenericError(xmlGenericErrorContext, 5444 "xmlXPathObjectCopy: unsupported type %d\n", 5445 val->type); 5446 break; 5447 } 5448 return(ret); 5449 } 5450 5451 /** 5452 * xmlXPathFreeObject: 5453 * @obj: the object to free 5454 * 5455 * Free up an xmlXPathObjectPtr object. 5456 */ 5457 void 5458 xmlXPathFreeObject(xmlXPathObjectPtr obj) { 5459 if (obj == NULL) return; 5460 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) { 5461 if (obj->boolval) { 5462 #if 0 5463 if (obj->user != NULL) { 5464 xmlXPathFreeNodeSet(obj->nodesetval); 5465 xmlFreeNodeList((xmlNodePtr) obj->user); 5466 } else 5467 #endif 5468 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */ 5469 if (obj->nodesetval != NULL) 5470 xmlXPathFreeValueTree(obj->nodesetval); 5471 } else { 5472 if (obj->nodesetval != NULL) 5473 xmlXPathFreeNodeSet(obj->nodesetval); 5474 } 5475 #ifdef LIBXML_XPTR_ENABLED 5476 } else if (obj->type == XPATH_LOCATIONSET) { 5477 if (obj->user != NULL) 5478 xmlXPtrFreeLocationSet(obj->user); 5479 #endif 5480 } else if (obj->type == XPATH_STRING) { 5481 if (obj->stringval != NULL) 5482 xmlFree(obj->stringval); 5483 } 5484 #ifdef XP_DEBUG_OBJ_USAGE 5485 xmlXPathDebugObjUsageReleased(NULL, obj->type); 5486 #endif 5487 xmlFree(obj); 5488 } 5489 5490 static void 5491 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) { 5492 xmlXPathFreeObject((xmlXPathObjectPtr) obj); 5493 } 5494 5495 /** 5496 * xmlXPathReleaseObject: 5497 * @obj: the xmlXPathObjectPtr to free or to cache 5498 * 5499 * Depending on the state of the cache this frees the given 5500 * XPath object or stores it in the cache. 5501 */ 5502 static void 5503 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj) 5504 { 5505 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \ 5506 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \ 5507 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj; 5508 5509 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n)) 5510 5511 if (obj == NULL) 5512 return; 5513 if ((ctxt == NULL) || (ctxt->cache == NULL)) { 5514 xmlXPathFreeObject(obj); 5515 } else { 5516 xmlXPathContextCachePtr cache = 5517 (xmlXPathContextCachePtr) ctxt->cache; 5518 5519 switch (obj->type) { 5520 case XPATH_NODESET: 5521 case XPATH_XSLT_TREE: 5522 if (obj->nodesetval != NULL) { 5523 if (obj->boolval) { 5524 /* 5525 * It looks like the @boolval is used for 5526 * evaluation if this an XSLT Result Tree Fragment. 5527 * TODO: Check if this assumption is correct. 5528 */ 5529 obj->type = XPATH_XSLT_TREE; /* just for debugging */ 5530 xmlXPathFreeValueTree(obj->nodesetval); 5531 obj->nodesetval = NULL; 5532 } else if ((obj->nodesetval->nodeMax <= 40) && 5533 (XP_CACHE_WANTS(cache->nodesetObjs, 5534 cache->maxNodeset))) 5535 { 5536 XP_CACHE_ADD(cache->nodesetObjs, obj); 5537 goto obj_cached; 5538 } else { 5539 xmlXPathFreeNodeSet(obj->nodesetval); 5540 obj->nodesetval = NULL; 5541 } 5542 } 5543 break; 5544 case XPATH_STRING: 5545 if (obj->stringval != NULL) 5546 xmlFree(obj->stringval); 5547 5548 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) { 5549 XP_CACHE_ADD(cache->stringObjs, obj); 5550 goto obj_cached; 5551 } 5552 break; 5553 case XPATH_BOOLEAN: 5554 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) { 5555 XP_CACHE_ADD(cache->booleanObjs, obj); 5556 goto obj_cached; 5557 } 5558 break; 5559 case XPATH_NUMBER: 5560 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) { 5561 XP_CACHE_ADD(cache->numberObjs, obj); 5562 goto obj_cached; 5563 } 5564 break; 5565 #ifdef LIBXML_XPTR_ENABLED 5566 case XPATH_LOCATIONSET: 5567 if (obj->user != NULL) { 5568 xmlXPtrFreeLocationSet(obj->user); 5569 } 5570 goto free_obj; 5571 #endif 5572 default: 5573 goto free_obj; 5574 } 5575 5576 /* 5577 * Fallback to adding to the misc-objects slot. 5578 */ 5579 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) { 5580 XP_CACHE_ADD(cache->miscObjs, obj); 5581 } else 5582 goto free_obj; 5583 5584 obj_cached: 5585 5586 #ifdef XP_DEBUG_OBJ_USAGE 5587 xmlXPathDebugObjUsageReleased(ctxt, obj->type); 5588 #endif 5589 5590 if (obj->nodesetval != NULL) { 5591 xmlNodeSetPtr tmpset = obj->nodesetval; 5592 5593 /* 5594 * TODO: Due to those nasty ns-nodes, we need to traverse 5595 * the list and free the ns-nodes. 5596 * URGENT TODO: Check if it's actually slowing things down. 5597 * Maybe we shouldn't try to preserve the list. 5598 */ 5599 if (tmpset->nodeNr > 1) { 5600 int i; 5601 xmlNodePtr node; 5602 5603 for (i = 0; i < tmpset->nodeNr; i++) { 5604 node = tmpset->nodeTab[i]; 5605 if ((node != NULL) && 5606 (node->type == XML_NAMESPACE_DECL)) 5607 { 5608 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 5609 } 5610 } 5611 } else if (tmpset->nodeNr == 1) { 5612 if ((tmpset->nodeTab[0] != NULL) && 5613 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL)) 5614 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]); 5615 } 5616 tmpset->nodeNr = 0; 5617 memset(obj, 0, sizeof(xmlXPathObject)); 5618 obj->nodesetval = tmpset; 5619 } else 5620 memset(obj, 0, sizeof(xmlXPathObject)); 5621 5622 return; 5623 5624 free_obj: 5625 /* 5626 * Cache is full; free the object. 5627 */ 5628 if (obj->nodesetval != NULL) 5629 xmlXPathFreeNodeSet(obj->nodesetval); 5630 #ifdef XP_DEBUG_OBJ_USAGE 5631 xmlXPathDebugObjUsageReleased(NULL, obj->type); 5632 #endif 5633 xmlFree(obj); 5634 } 5635 return; 5636 } 5637 5638 5639 /************************************************************************ 5640 * * 5641 * Type Casting Routines * 5642 * * 5643 ************************************************************************/ 5644 5645 /** 5646 * xmlXPathCastBooleanToString: 5647 * @val: a boolean 5648 * 5649 * Converts a boolean to its string value. 5650 * 5651 * Returns a newly allocated string. 5652 */ 5653 xmlChar * 5654 xmlXPathCastBooleanToString (int val) { 5655 xmlChar *ret; 5656 if (val) 5657 ret = xmlStrdup((const xmlChar *) "true"); 5658 else 5659 ret = xmlStrdup((const xmlChar *) "false"); 5660 return(ret); 5661 } 5662 5663 /** 5664 * xmlXPathCastNumberToString: 5665 * @val: a number 5666 * 5667 * Converts a number to its string value. 5668 * 5669 * Returns a newly allocated string. 5670 */ 5671 xmlChar * 5672 xmlXPathCastNumberToString (double val) { 5673 xmlChar *ret; 5674 switch (xmlXPathIsInf(val)) { 5675 case 1: 5676 ret = xmlStrdup((const xmlChar *) "Infinity"); 5677 break; 5678 case -1: 5679 ret = xmlStrdup((const xmlChar *) "-Infinity"); 5680 break; 5681 default: 5682 if (xmlXPathIsNaN(val)) { 5683 ret = xmlStrdup((const xmlChar *) "NaN"); 5684 } else if (val == 0) { 5685 /* Omit sign for negative zero. */ 5686 ret = xmlStrdup((const xmlChar *) "0"); 5687 } else { 5688 /* could be improved */ 5689 char buf[100]; 5690 xmlXPathFormatNumber(val, buf, 99); 5691 buf[99] = 0; 5692 ret = xmlStrdup((const xmlChar *) buf); 5693 } 5694 } 5695 return(ret); 5696 } 5697 5698 /** 5699 * xmlXPathCastNodeToString: 5700 * @node: a node 5701 * 5702 * Converts a node to its string value. 5703 * 5704 * Returns a newly allocated string. 5705 */ 5706 xmlChar * 5707 xmlXPathCastNodeToString (xmlNodePtr node) { 5708 xmlChar *ret; 5709 if ((ret = xmlNodeGetContent(node)) == NULL) 5710 ret = xmlStrdup((const xmlChar *) ""); 5711 return(ret); 5712 } 5713 5714 /** 5715 * xmlXPathCastNodeSetToString: 5716 * @ns: a node-set 5717 * 5718 * Converts a node-set to its string value. 5719 * 5720 * Returns a newly allocated string. 5721 */ 5722 xmlChar * 5723 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) { 5724 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL)) 5725 return(xmlStrdup((const xmlChar *) "")); 5726 5727 if (ns->nodeNr > 1) 5728 xmlXPathNodeSetSort(ns); 5729 return(xmlXPathCastNodeToString(ns->nodeTab[0])); 5730 } 5731 5732 /** 5733 * xmlXPathCastToString: 5734 * @val: an XPath object 5735 * 5736 * Converts an existing object to its string() equivalent 5737 * 5738 * Returns the allocated string value of the object, NULL in case of error. 5739 * It's up to the caller to free the string memory with xmlFree(). 5740 */ 5741 xmlChar * 5742 xmlXPathCastToString(xmlXPathObjectPtr val) { 5743 xmlChar *ret = NULL; 5744 5745 if (val == NULL) 5746 return(xmlStrdup((const xmlChar *) "")); 5747 switch (val->type) { 5748 case XPATH_UNDEFINED: 5749 #ifdef DEBUG_EXPR 5750 xmlGenericError(xmlGenericErrorContext, "String: undefined\n"); 5751 #endif 5752 ret = xmlStrdup((const xmlChar *) ""); 5753 break; 5754 case XPATH_NODESET: 5755 case XPATH_XSLT_TREE: 5756 ret = xmlXPathCastNodeSetToString(val->nodesetval); 5757 break; 5758 case XPATH_STRING: 5759 return(xmlStrdup(val->stringval)); 5760 case XPATH_BOOLEAN: 5761 ret = xmlXPathCastBooleanToString(val->boolval); 5762 break; 5763 case XPATH_NUMBER: { 5764 ret = xmlXPathCastNumberToString(val->floatval); 5765 break; 5766 } 5767 case XPATH_USERS: 5768 case XPATH_POINT: 5769 case XPATH_RANGE: 5770 case XPATH_LOCATIONSET: 5771 TODO 5772 ret = xmlStrdup((const xmlChar *) ""); 5773 break; 5774 } 5775 return(ret); 5776 } 5777 5778 /** 5779 * xmlXPathConvertString: 5780 * @val: an XPath object 5781 * 5782 * Converts an existing object to its string() equivalent 5783 * 5784 * Returns the new object, the old one is freed (or the operation 5785 * is done directly on @val) 5786 */ 5787 xmlXPathObjectPtr 5788 xmlXPathConvertString(xmlXPathObjectPtr val) { 5789 xmlChar *res = NULL; 5790 5791 if (val == NULL) 5792 return(xmlXPathNewCString("")); 5793 5794 switch (val->type) { 5795 case XPATH_UNDEFINED: 5796 #ifdef DEBUG_EXPR 5797 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n"); 5798 #endif 5799 break; 5800 case XPATH_NODESET: 5801 case XPATH_XSLT_TREE: 5802 res = xmlXPathCastNodeSetToString(val->nodesetval); 5803 break; 5804 case XPATH_STRING: 5805 return(val); 5806 case XPATH_BOOLEAN: 5807 res = xmlXPathCastBooleanToString(val->boolval); 5808 break; 5809 case XPATH_NUMBER: 5810 res = xmlXPathCastNumberToString(val->floatval); 5811 break; 5812 case XPATH_USERS: 5813 case XPATH_POINT: 5814 case XPATH_RANGE: 5815 case XPATH_LOCATIONSET: 5816 TODO; 5817 break; 5818 } 5819 xmlXPathFreeObject(val); 5820 if (res == NULL) 5821 return(xmlXPathNewCString("")); 5822 return(xmlXPathWrapString(res)); 5823 } 5824 5825 /** 5826 * xmlXPathCastBooleanToNumber: 5827 * @val: a boolean 5828 * 5829 * Converts a boolean to its number value 5830 * 5831 * Returns the number value 5832 */ 5833 double 5834 xmlXPathCastBooleanToNumber(int val) { 5835 if (val) 5836 return(1.0); 5837 return(0.0); 5838 } 5839 5840 /** 5841 * xmlXPathCastStringToNumber: 5842 * @val: a string 5843 * 5844 * Converts a string to its number value 5845 * 5846 * Returns the number value 5847 */ 5848 double 5849 xmlXPathCastStringToNumber(const xmlChar * val) { 5850 return(xmlXPathStringEvalNumber(val)); 5851 } 5852 5853 /** 5854 * xmlXPathCastNodeToNumber: 5855 * @node: a node 5856 * 5857 * Converts a node to its number value 5858 * 5859 * Returns the number value 5860 */ 5861 double 5862 xmlXPathCastNodeToNumber (xmlNodePtr node) { 5863 xmlChar *strval; 5864 double ret; 5865 5866 if (node == NULL) 5867 return(NAN); 5868 strval = xmlXPathCastNodeToString(node); 5869 if (strval == NULL) 5870 return(NAN); 5871 ret = xmlXPathCastStringToNumber(strval); 5872 xmlFree(strval); 5873 5874 return(ret); 5875 } 5876 5877 /** 5878 * xmlXPathCastNodeSetToNumber: 5879 * @ns: a node-set 5880 * 5881 * Converts a node-set to its number value 5882 * 5883 * Returns the number value 5884 */ 5885 double 5886 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) { 5887 xmlChar *str; 5888 double ret; 5889 5890 if (ns == NULL) 5891 return(NAN); 5892 str = xmlXPathCastNodeSetToString(ns); 5893 ret = xmlXPathCastStringToNumber(str); 5894 xmlFree(str); 5895 return(ret); 5896 } 5897 5898 /** 5899 * xmlXPathCastToNumber: 5900 * @val: an XPath object 5901 * 5902 * Converts an XPath object to its number value 5903 * 5904 * Returns the number value 5905 */ 5906 double 5907 xmlXPathCastToNumber(xmlXPathObjectPtr val) { 5908 double ret = 0.0; 5909 5910 if (val == NULL) 5911 return(NAN); 5912 switch (val->type) { 5913 case XPATH_UNDEFINED: 5914 #ifdef DEBUG_EXPR 5915 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n"); 5916 #endif 5917 ret = NAN; 5918 break; 5919 case XPATH_NODESET: 5920 case XPATH_XSLT_TREE: 5921 ret = xmlXPathCastNodeSetToNumber(val->nodesetval); 5922 break; 5923 case XPATH_STRING: 5924 ret = xmlXPathCastStringToNumber(val->stringval); 5925 break; 5926 case XPATH_NUMBER: 5927 ret = val->floatval; 5928 break; 5929 case XPATH_BOOLEAN: 5930 ret = xmlXPathCastBooleanToNumber(val->boolval); 5931 break; 5932 case XPATH_USERS: 5933 case XPATH_POINT: 5934 case XPATH_RANGE: 5935 case XPATH_LOCATIONSET: 5936 TODO; 5937 ret = NAN; 5938 break; 5939 } 5940 return(ret); 5941 } 5942 5943 /** 5944 * xmlXPathConvertNumber: 5945 * @val: an XPath object 5946 * 5947 * Converts an existing object to its number() equivalent 5948 * 5949 * Returns the new object, the old one is freed (or the operation 5950 * is done directly on @val) 5951 */ 5952 xmlXPathObjectPtr 5953 xmlXPathConvertNumber(xmlXPathObjectPtr val) { 5954 xmlXPathObjectPtr ret; 5955 5956 if (val == NULL) 5957 return(xmlXPathNewFloat(0.0)); 5958 if (val->type == XPATH_NUMBER) 5959 return(val); 5960 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val)); 5961 xmlXPathFreeObject(val); 5962 return(ret); 5963 } 5964 5965 /** 5966 * xmlXPathCastNumberToBoolean: 5967 * @val: a number 5968 * 5969 * Converts a number to its boolean value 5970 * 5971 * Returns the boolean value 5972 */ 5973 int 5974 xmlXPathCastNumberToBoolean (double val) { 5975 if (xmlXPathIsNaN(val) || (val == 0.0)) 5976 return(0); 5977 return(1); 5978 } 5979 5980 /** 5981 * xmlXPathCastStringToBoolean: 5982 * @val: a string 5983 * 5984 * Converts a string to its boolean value 5985 * 5986 * Returns the boolean value 5987 */ 5988 int 5989 xmlXPathCastStringToBoolean (const xmlChar *val) { 5990 if ((val == NULL) || (xmlStrlen(val) == 0)) 5991 return(0); 5992 return(1); 5993 } 5994 5995 /** 5996 * xmlXPathCastNodeSetToBoolean: 5997 * @ns: a node-set 5998 * 5999 * Converts a node-set to its boolean value 6000 * 6001 * Returns the boolean value 6002 */ 6003 int 6004 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) { 6005 if ((ns == NULL) || (ns->nodeNr == 0)) 6006 return(0); 6007 return(1); 6008 } 6009 6010 /** 6011 * xmlXPathCastToBoolean: 6012 * @val: an XPath object 6013 * 6014 * Converts an XPath object to its boolean value 6015 * 6016 * Returns the boolean value 6017 */ 6018 int 6019 xmlXPathCastToBoolean (xmlXPathObjectPtr val) { 6020 int ret = 0; 6021 6022 if (val == NULL) 6023 return(0); 6024 switch (val->type) { 6025 case XPATH_UNDEFINED: 6026 #ifdef DEBUG_EXPR 6027 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n"); 6028 #endif 6029 ret = 0; 6030 break; 6031 case XPATH_NODESET: 6032 case XPATH_XSLT_TREE: 6033 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval); 6034 break; 6035 case XPATH_STRING: 6036 ret = xmlXPathCastStringToBoolean(val->stringval); 6037 break; 6038 case XPATH_NUMBER: 6039 ret = xmlXPathCastNumberToBoolean(val->floatval); 6040 break; 6041 case XPATH_BOOLEAN: 6042 ret = val->boolval; 6043 break; 6044 case XPATH_USERS: 6045 case XPATH_POINT: 6046 case XPATH_RANGE: 6047 case XPATH_LOCATIONSET: 6048 TODO; 6049 ret = 0; 6050 break; 6051 } 6052 return(ret); 6053 } 6054 6055 6056 /** 6057 * xmlXPathConvertBoolean: 6058 * @val: an XPath object 6059 * 6060 * Converts an existing object to its boolean() equivalent 6061 * 6062 * Returns the new object, the old one is freed (or the operation 6063 * is done directly on @val) 6064 */ 6065 xmlXPathObjectPtr 6066 xmlXPathConvertBoolean(xmlXPathObjectPtr val) { 6067 xmlXPathObjectPtr ret; 6068 6069 if (val == NULL) 6070 return(xmlXPathNewBoolean(0)); 6071 if (val->type == XPATH_BOOLEAN) 6072 return(val); 6073 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val)); 6074 xmlXPathFreeObject(val); 6075 return(ret); 6076 } 6077 6078 /************************************************************************ 6079 * * 6080 * Routines to handle XPath contexts * 6081 * * 6082 ************************************************************************/ 6083 6084 /** 6085 * xmlXPathNewContext: 6086 * @doc: the XML document 6087 * 6088 * Create a new xmlXPathContext 6089 * 6090 * Returns the xmlXPathContext just allocated. The caller will need to free it. 6091 */ 6092 xmlXPathContextPtr 6093 xmlXPathNewContext(xmlDocPtr doc) { 6094 xmlXPathContextPtr ret; 6095 6096 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext)); 6097 if (ret == NULL) { 6098 xmlXPathErrMemory(NULL, "creating context\n"); 6099 return(NULL); 6100 } 6101 memset(ret, 0 , (size_t) sizeof(xmlXPathContext)); 6102 ret->doc = doc; 6103 ret->node = NULL; 6104 6105 ret->varHash = NULL; 6106 6107 ret->nb_types = 0; 6108 ret->max_types = 0; 6109 ret->types = NULL; 6110 6111 ret->funcHash = xmlHashCreate(0); 6112 6113 ret->nb_axis = 0; 6114 ret->max_axis = 0; 6115 ret->axis = NULL; 6116 6117 ret->nsHash = NULL; 6118 ret->user = NULL; 6119 6120 ret->contextSize = -1; 6121 ret->proximityPosition = -1; 6122 6123 ret->maxDepth = INT_MAX; 6124 ret->maxParserDepth = INT_MAX; 6125 6126 #ifdef XP_DEFAULT_CACHE_ON 6127 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) { 6128 xmlXPathFreeContext(ret); 6129 return(NULL); 6130 } 6131 #endif 6132 6133 xmlXPathRegisterAllFunctions(ret); 6134 6135 return(ret); 6136 } 6137 6138 /** 6139 * xmlXPathFreeContext: 6140 * @ctxt: the context to free 6141 * 6142 * Free up an xmlXPathContext 6143 */ 6144 void 6145 xmlXPathFreeContext(xmlXPathContextPtr ctxt) { 6146 if (ctxt == NULL) return; 6147 6148 if (ctxt->cache != NULL) 6149 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache); 6150 xmlXPathRegisteredNsCleanup(ctxt); 6151 xmlXPathRegisteredFuncsCleanup(ctxt); 6152 xmlXPathRegisteredVariablesCleanup(ctxt); 6153 xmlResetError(&ctxt->lastError); 6154 xmlFree(ctxt); 6155 } 6156 6157 /************************************************************************ 6158 * * 6159 * Routines to handle XPath parser contexts * 6160 * * 6161 ************************************************************************/ 6162 6163 #define CHECK_CTXT(ctxt) \ 6164 if (ctxt == NULL) { \ 6165 __xmlRaiseError(NULL, NULL, NULL, \ 6166 NULL, NULL, XML_FROM_XPATH, \ 6167 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \ 6168 __FILE__, __LINE__, \ 6169 NULL, NULL, NULL, 0, 0, \ 6170 "NULL context pointer\n"); \ 6171 return(NULL); \ 6172 } \ 6173 6174 #define CHECK_CTXT_NEG(ctxt) \ 6175 if (ctxt == NULL) { \ 6176 __xmlRaiseError(NULL, NULL, NULL, \ 6177 NULL, NULL, XML_FROM_XPATH, \ 6178 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \ 6179 __FILE__, __LINE__, \ 6180 NULL, NULL, NULL, 0, 0, \ 6181 "NULL context pointer\n"); \ 6182 return(-1); \ 6183 } \ 6184 6185 6186 #define CHECK_CONTEXT(ctxt) \ 6187 if ((ctxt == NULL) || (ctxt->doc == NULL) || \ 6188 (ctxt->doc->children == NULL)) { \ 6189 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \ 6190 return(NULL); \ 6191 } 6192 6193 6194 /** 6195 * xmlXPathNewParserContext: 6196 * @str: the XPath expression 6197 * @ctxt: the XPath context 6198 * 6199 * Create a new xmlXPathParserContext 6200 * 6201 * Returns the xmlXPathParserContext just allocated. 6202 */ 6203 xmlXPathParserContextPtr 6204 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) { 6205 xmlXPathParserContextPtr ret; 6206 6207 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext)); 6208 if (ret == NULL) { 6209 xmlXPathErrMemory(ctxt, "creating parser context\n"); 6210 return(NULL); 6211 } 6212 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext)); 6213 ret->cur = ret->base = str; 6214 ret->context = ctxt; 6215 6216 ret->comp = xmlXPathNewCompExpr(); 6217 if (ret->comp == NULL) { 6218 xmlFree(ret->valueTab); 6219 xmlFree(ret); 6220 return(NULL); 6221 } 6222 if ((ctxt != NULL) && (ctxt->dict != NULL)) { 6223 ret->comp->dict = ctxt->dict; 6224 xmlDictReference(ret->comp->dict); 6225 } 6226 6227 return(ret); 6228 } 6229 6230 /** 6231 * xmlXPathCompParserContext: 6232 * @comp: the XPath compiled expression 6233 * @ctxt: the XPath context 6234 * 6235 * Create a new xmlXPathParserContext when processing a compiled expression 6236 * 6237 * Returns the xmlXPathParserContext just allocated. 6238 */ 6239 static xmlXPathParserContextPtr 6240 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) { 6241 xmlXPathParserContextPtr ret; 6242 6243 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext)); 6244 if (ret == NULL) { 6245 xmlXPathErrMemory(ctxt, "creating evaluation context\n"); 6246 return(NULL); 6247 } 6248 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext)); 6249 6250 /* Allocate the value stack */ 6251 ret->valueTab = (xmlXPathObjectPtr *) 6252 xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); 6253 if (ret->valueTab == NULL) { 6254 xmlFree(ret); 6255 xmlXPathErrMemory(ctxt, "creating evaluation context\n"); 6256 return(NULL); 6257 } 6258 ret->valueNr = 0; 6259 ret->valueMax = 10; 6260 ret->value = NULL; 6261 ret->valueFrame = 0; 6262 6263 ret->context = ctxt; 6264 ret->comp = comp; 6265 6266 return(ret); 6267 } 6268 6269 /** 6270 * xmlXPathFreeParserContext: 6271 * @ctxt: the context to free 6272 * 6273 * Free up an xmlXPathParserContext 6274 */ 6275 void 6276 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) { 6277 int i; 6278 6279 if (ctxt->valueTab != NULL) { 6280 for (i = 0; i < ctxt->valueNr; i++) { 6281 if (ctxt->context) 6282 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]); 6283 else 6284 xmlXPathFreeObject(ctxt->valueTab[i]); 6285 } 6286 xmlFree(ctxt->valueTab); 6287 } 6288 if (ctxt->comp != NULL) { 6289 #ifdef XPATH_STREAMING 6290 if (ctxt->comp->stream != NULL) { 6291 xmlFreePatternList(ctxt->comp->stream); 6292 ctxt->comp->stream = NULL; 6293 } 6294 #endif 6295 xmlXPathFreeCompExpr(ctxt->comp); 6296 } 6297 xmlFree(ctxt); 6298 } 6299 6300 /************************************************************************ 6301 * * 6302 * The implicit core function library * 6303 * * 6304 ************************************************************************/ 6305 6306 /** 6307 * xmlXPathNodeValHash: 6308 * @node: a node pointer 6309 * 6310 * Function computing the beginning of the string value of the node, 6311 * used to speed up comparisons 6312 * 6313 * Returns an int usable as a hash 6314 */ 6315 static unsigned int 6316 xmlXPathNodeValHash(xmlNodePtr node) { 6317 int len = 2; 6318 const xmlChar * string = NULL; 6319 xmlNodePtr tmp = NULL; 6320 unsigned int ret = 0; 6321 6322 if (node == NULL) 6323 return(0); 6324 6325 if (node->type == XML_DOCUMENT_NODE) { 6326 tmp = xmlDocGetRootElement((xmlDocPtr) node); 6327 if (tmp == NULL) 6328 node = node->children; 6329 else 6330 node = tmp; 6331 6332 if (node == NULL) 6333 return(0); 6334 } 6335 6336 switch (node->type) { 6337 case XML_COMMENT_NODE: 6338 case XML_PI_NODE: 6339 case XML_CDATA_SECTION_NODE: 6340 case XML_TEXT_NODE: 6341 string = node->content; 6342 if (string == NULL) 6343 return(0); 6344 if (string[0] == 0) 6345 return(0); 6346 return(((unsigned int) string[0]) + 6347 (((unsigned int) string[1]) << 8)); 6348 case XML_NAMESPACE_DECL: 6349 string = ((xmlNsPtr)node)->href; 6350 if (string == NULL) 6351 return(0); 6352 if (string[0] == 0) 6353 return(0); 6354 return(((unsigned int) string[0]) + 6355 (((unsigned int) string[1]) << 8)); 6356 case XML_ATTRIBUTE_NODE: 6357 tmp = ((xmlAttrPtr) node)->children; 6358 break; 6359 case XML_ELEMENT_NODE: 6360 tmp = node->children; 6361 break; 6362 default: 6363 return(0); 6364 } 6365 while (tmp != NULL) { 6366 switch (tmp->type) { 6367 case XML_CDATA_SECTION_NODE: 6368 case XML_TEXT_NODE: 6369 string = tmp->content; 6370 break; 6371 default: 6372 string = NULL; 6373 break; 6374 } 6375 if ((string != NULL) && (string[0] != 0)) { 6376 if (len == 1) { 6377 return(ret + (((unsigned int) string[0]) << 8)); 6378 } 6379 if (string[1] == 0) { 6380 len = 1; 6381 ret = (unsigned int) string[0]; 6382 } else { 6383 return(((unsigned int) string[0]) + 6384 (((unsigned int) string[1]) << 8)); 6385 } 6386 } 6387 /* 6388 * Skip to next node 6389 */ 6390 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) { 6391 if (tmp->children->type != XML_ENTITY_DECL) { 6392 tmp = tmp->children; 6393 continue; 6394 } 6395 } 6396 if (tmp == node) 6397 break; 6398 6399 if (tmp->next != NULL) { 6400 tmp = tmp->next; 6401 continue; 6402 } 6403 6404 do { 6405 tmp = tmp->parent; 6406 if (tmp == NULL) 6407 break; 6408 if (tmp == node) { 6409 tmp = NULL; 6410 break; 6411 } 6412 if (tmp->next != NULL) { 6413 tmp = tmp->next; 6414 break; 6415 } 6416 } while (tmp != NULL); 6417 } 6418 return(ret); 6419 } 6420 6421 /** 6422 * xmlXPathStringHash: 6423 * @string: a string 6424 * 6425 * Function computing the beginning of the string value of the node, 6426 * used to speed up comparisons 6427 * 6428 * Returns an int usable as a hash 6429 */ 6430 static unsigned int 6431 xmlXPathStringHash(const xmlChar * string) { 6432 if (string == NULL) 6433 return((unsigned int) 0); 6434 if (string[0] == 0) 6435 return(0); 6436 return(((unsigned int) string[0]) + 6437 (((unsigned int) string[1]) << 8)); 6438 } 6439 6440 /** 6441 * xmlXPathCompareNodeSetFloat: 6442 * @ctxt: the XPath Parser context 6443 * @inf: less than (1) or greater than (0) 6444 * @strict: is the comparison strict 6445 * @arg: the node set 6446 * @f: the value 6447 * 6448 * Implement the compare operation between a nodeset and a number 6449 * @ns < @val (1, 1, ... 6450 * @ns <= @val (1, 0, ... 6451 * @ns > @val (0, 1, ... 6452 * @ns >= @val (0, 0, ... 6453 * 6454 * If one object to be compared is a node-set and the other is a number, 6455 * then the comparison will be true if and only if there is a node in the 6456 * node-set such that the result of performing the comparison on the number 6457 * to be compared and on the result of converting the string-value of that 6458 * node to a number using the number function is true. 6459 * 6460 * Returns 0 or 1 depending on the results of the test. 6461 */ 6462 static int 6463 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict, 6464 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) { 6465 int i, ret = 0; 6466 xmlNodeSetPtr ns; 6467 xmlChar *str2; 6468 6469 if ((f == NULL) || (arg == NULL) || 6470 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) { 6471 xmlXPathReleaseObject(ctxt->context, arg); 6472 xmlXPathReleaseObject(ctxt->context, f); 6473 return(0); 6474 } 6475 ns = arg->nodesetval; 6476 if (ns != NULL) { 6477 for (i = 0;i < ns->nodeNr;i++) { 6478 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 6479 if (str2 != NULL) { 6480 valuePush(ctxt, 6481 xmlXPathCacheNewString(ctxt->context, str2)); 6482 xmlFree(str2); 6483 xmlXPathNumberFunction(ctxt, 1); 6484 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f)); 6485 ret = xmlXPathCompareValues(ctxt, inf, strict); 6486 if (ret) 6487 break; 6488 } 6489 } 6490 } 6491 xmlXPathReleaseObject(ctxt->context, arg); 6492 xmlXPathReleaseObject(ctxt->context, f); 6493 return(ret); 6494 } 6495 6496 /** 6497 * xmlXPathCompareNodeSetString: 6498 * @ctxt: the XPath Parser context 6499 * @inf: less than (1) or greater than (0) 6500 * @strict: is the comparison strict 6501 * @arg: the node set 6502 * @s: the value 6503 * 6504 * Implement the compare operation between a nodeset and a string 6505 * @ns < @val (1, 1, ... 6506 * @ns <= @val (1, 0, ... 6507 * @ns > @val (0, 1, ... 6508 * @ns >= @val (0, 0, ... 6509 * 6510 * If one object to be compared is a node-set and the other is a string, 6511 * then the comparison will be true if and only if there is a node in 6512 * the node-set such that the result of performing the comparison on the 6513 * string-value of the node and the other string is true. 6514 * 6515 * Returns 0 or 1 depending on the results of the test. 6516 */ 6517 static int 6518 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict, 6519 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) { 6520 int i, ret = 0; 6521 xmlNodeSetPtr ns; 6522 xmlChar *str2; 6523 6524 if ((s == NULL) || (arg == NULL) || 6525 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) { 6526 xmlXPathReleaseObject(ctxt->context, arg); 6527 xmlXPathReleaseObject(ctxt->context, s); 6528 return(0); 6529 } 6530 ns = arg->nodesetval; 6531 if (ns != NULL) { 6532 for (i = 0;i < ns->nodeNr;i++) { 6533 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 6534 if (str2 != NULL) { 6535 valuePush(ctxt, 6536 xmlXPathCacheNewString(ctxt->context, str2)); 6537 xmlFree(str2); 6538 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s)); 6539 ret = xmlXPathCompareValues(ctxt, inf, strict); 6540 if (ret) 6541 break; 6542 } 6543 } 6544 } 6545 xmlXPathReleaseObject(ctxt->context, arg); 6546 xmlXPathReleaseObject(ctxt->context, s); 6547 return(ret); 6548 } 6549 6550 /** 6551 * xmlXPathCompareNodeSets: 6552 * @inf: less than (1) or greater than (0) 6553 * @strict: is the comparison strict 6554 * @arg1: the first node set object 6555 * @arg2: the second node set object 6556 * 6557 * Implement the compare operation on nodesets: 6558 * 6559 * If both objects to be compared are node-sets, then the comparison 6560 * will be true if and only if there is a node in the first node-set 6561 * and a node in the second node-set such that the result of performing 6562 * the comparison on the string-values of the two nodes is true. 6563 * .... 6564 * When neither object to be compared is a node-set and the operator 6565 * is <=, <, >= or >, then the objects are compared by converting both 6566 * objects to numbers and comparing the numbers according to IEEE 754. 6567 * .... 6568 * The number function converts its argument to a number as follows: 6569 * - a string that consists of optional whitespace followed by an 6570 * optional minus sign followed by a Number followed by whitespace 6571 * is converted to the IEEE 754 number that is nearest (according 6572 * to the IEEE 754 round-to-nearest rule) to the mathematical value 6573 * represented by the string; any other string is converted to NaN 6574 * 6575 * Conclusion all nodes need to be converted first to their string value 6576 * and then the comparison must be done when possible 6577 */ 6578 static int 6579 xmlXPathCompareNodeSets(int inf, int strict, 6580 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) { 6581 int i, j, init = 0; 6582 double val1; 6583 double *values2; 6584 int ret = 0; 6585 xmlNodeSetPtr ns1; 6586 xmlNodeSetPtr ns2; 6587 6588 if ((arg1 == NULL) || 6589 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) { 6590 xmlXPathFreeObject(arg2); 6591 return(0); 6592 } 6593 if ((arg2 == NULL) || 6594 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) { 6595 xmlXPathFreeObject(arg1); 6596 xmlXPathFreeObject(arg2); 6597 return(0); 6598 } 6599 6600 ns1 = arg1->nodesetval; 6601 ns2 = arg2->nodesetval; 6602 6603 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) { 6604 xmlXPathFreeObject(arg1); 6605 xmlXPathFreeObject(arg2); 6606 return(0); 6607 } 6608 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) { 6609 xmlXPathFreeObject(arg1); 6610 xmlXPathFreeObject(arg2); 6611 return(0); 6612 } 6613 6614 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double)); 6615 if (values2 == NULL) { 6616 /* TODO: Propagate memory error. */ 6617 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6618 xmlXPathFreeObject(arg1); 6619 xmlXPathFreeObject(arg2); 6620 return(0); 6621 } 6622 for (i = 0;i < ns1->nodeNr;i++) { 6623 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]); 6624 if (xmlXPathIsNaN(val1)) 6625 continue; 6626 for (j = 0;j < ns2->nodeNr;j++) { 6627 if (init == 0) { 6628 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]); 6629 } 6630 if (xmlXPathIsNaN(values2[j])) 6631 continue; 6632 if (inf && strict) 6633 ret = (val1 < values2[j]); 6634 else if (inf && !strict) 6635 ret = (val1 <= values2[j]); 6636 else if (!inf && strict) 6637 ret = (val1 > values2[j]); 6638 else if (!inf && !strict) 6639 ret = (val1 >= values2[j]); 6640 if (ret) 6641 break; 6642 } 6643 if (ret) 6644 break; 6645 init = 1; 6646 } 6647 xmlFree(values2); 6648 xmlXPathFreeObject(arg1); 6649 xmlXPathFreeObject(arg2); 6650 return(ret); 6651 } 6652 6653 /** 6654 * xmlXPathCompareNodeSetValue: 6655 * @ctxt: the XPath Parser context 6656 * @inf: less than (1) or greater than (0) 6657 * @strict: is the comparison strict 6658 * @arg: the node set 6659 * @val: the value 6660 * 6661 * Implement the compare operation between a nodeset and a value 6662 * @ns < @val (1, 1, ... 6663 * @ns <= @val (1, 0, ... 6664 * @ns > @val (0, 1, ... 6665 * @ns >= @val (0, 0, ... 6666 * 6667 * If one object to be compared is a node-set and the other is a boolean, 6668 * then the comparison will be true if and only if the result of performing 6669 * the comparison on the boolean and on the result of converting 6670 * the node-set to a boolean using the boolean function is true. 6671 * 6672 * Returns 0 or 1 depending on the results of the test. 6673 */ 6674 static int 6675 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict, 6676 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) { 6677 if ((val == NULL) || (arg == NULL) || 6678 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 6679 return(0); 6680 6681 switch(val->type) { 6682 case XPATH_NUMBER: 6683 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val)); 6684 case XPATH_NODESET: 6685 case XPATH_XSLT_TREE: 6686 return(xmlXPathCompareNodeSets(inf, strict, arg, val)); 6687 case XPATH_STRING: 6688 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val)); 6689 case XPATH_BOOLEAN: 6690 valuePush(ctxt, arg); 6691 xmlXPathBooleanFunction(ctxt, 1); 6692 valuePush(ctxt, val); 6693 return(xmlXPathCompareValues(ctxt, inf, strict)); 6694 default: 6695 xmlGenericError(xmlGenericErrorContext, 6696 "xmlXPathCompareNodeSetValue: Can't compare node set " 6697 "and object of type %d\n", 6698 val->type); 6699 xmlXPathReleaseObject(ctxt->context, arg); 6700 xmlXPathReleaseObject(ctxt->context, val); 6701 XP_ERROR0(XPATH_INVALID_TYPE); 6702 } 6703 return(0); 6704 } 6705 6706 /** 6707 * xmlXPathEqualNodeSetString: 6708 * @arg: the nodeset object argument 6709 * @str: the string to compare to. 6710 * @neq: flag to show whether for '=' (0) or '!=' (1) 6711 * 6712 * Implement the equal operation on XPath objects content: @arg1 == @arg2 6713 * If one object to be compared is a node-set and the other is a string, 6714 * then the comparison will be true if and only if there is a node in 6715 * the node-set such that the result of performing the comparison on the 6716 * string-value of the node and the other string is true. 6717 * 6718 * Returns 0 or 1 depending on the results of the test. 6719 */ 6720 static int 6721 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq) 6722 { 6723 int i; 6724 xmlNodeSetPtr ns; 6725 xmlChar *str2; 6726 unsigned int hash; 6727 6728 if ((str == NULL) || (arg == NULL) || 6729 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 6730 return (0); 6731 ns = arg->nodesetval; 6732 /* 6733 * A NULL nodeset compared with a string is always false 6734 * (since there is no node equal, and no node not equal) 6735 */ 6736 if ((ns == NULL) || (ns->nodeNr <= 0) ) 6737 return (0); 6738 hash = xmlXPathStringHash(str); 6739 for (i = 0; i < ns->nodeNr; i++) { 6740 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) { 6741 str2 = xmlNodeGetContent(ns->nodeTab[i]); 6742 if ((str2 != NULL) && (xmlStrEqual(str, str2))) { 6743 xmlFree(str2); 6744 if (neq) 6745 continue; 6746 return (1); 6747 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) { 6748 if (neq) 6749 continue; 6750 return (1); 6751 } else if (neq) { 6752 if (str2 != NULL) 6753 xmlFree(str2); 6754 return (1); 6755 } 6756 if (str2 != NULL) 6757 xmlFree(str2); 6758 } else if (neq) 6759 return (1); 6760 } 6761 return (0); 6762 } 6763 6764 /** 6765 * xmlXPathEqualNodeSetFloat: 6766 * @arg: the nodeset object argument 6767 * @f: the float to compare to 6768 * @neq: flag to show whether to compare '=' (0) or '!=' (1) 6769 * 6770 * Implement the equal operation on XPath objects content: @arg1 == @arg2 6771 * If one object to be compared is a node-set and the other is a number, 6772 * then the comparison will be true if and only if there is a node in 6773 * the node-set such that the result of performing the comparison on the 6774 * number to be compared and on the result of converting the string-value 6775 * of that node to a number using the number function is true. 6776 * 6777 * Returns 0 or 1 depending on the results of the test. 6778 */ 6779 static int 6780 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt, 6781 xmlXPathObjectPtr arg, double f, int neq) { 6782 int i, ret=0; 6783 xmlNodeSetPtr ns; 6784 xmlChar *str2; 6785 xmlXPathObjectPtr val; 6786 double v; 6787 6788 if ((arg == NULL) || 6789 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 6790 return(0); 6791 6792 ns = arg->nodesetval; 6793 if (ns != NULL) { 6794 for (i=0;i<ns->nodeNr;i++) { 6795 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 6796 if (str2 != NULL) { 6797 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2)); 6798 xmlFree(str2); 6799 xmlXPathNumberFunction(ctxt, 1); 6800 val = valuePop(ctxt); 6801 v = val->floatval; 6802 xmlXPathReleaseObject(ctxt->context, val); 6803 if (!xmlXPathIsNaN(v)) { 6804 if ((!neq) && (v==f)) { 6805 ret = 1; 6806 break; 6807 } else if ((neq) && (v!=f)) { 6808 ret = 1; 6809 break; 6810 } 6811 } else { /* NaN is unequal to any value */ 6812 if (neq) 6813 ret = 1; 6814 } 6815 } 6816 } 6817 } 6818 6819 return(ret); 6820 } 6821 6822 6823 /** 6824 * xmlXPathEqualNodeSets: 6825 * @arg1: first nodeset object argument 6826 * @arg2: second nodeset object argument 6827 * @neq: flag to show whether to test '=' (0) or '!=' (1) 6828 * 6829 * Implement the equal / not equal operation on XPath nodesets: 6830 * @arg1 == @arg2 or @arg1 != @arg2 6831 * If both objects to be compared are node-sets, then the comparison 6832 * will be true if and only if there is a node in the first node-set and 6833 * a node in the second node-set such that the result of performing the 6834 * comparison on the string-values of the two nodes is true. 6835 * 6836 * (needless to say, this is a costly operation) 6837 * 6838 * Returns 0 or 1 depending on the results of the test. 6839 */ 6840 static int 6841 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) { 6842 int i, j; 6843 unsigned int *hashs1; 6844 unsigned int *hashs2; 6845 xmlChar **values1; 6846 xmlChar **values2; 6847 int ret = 0; 6848 xmlNodeSetPtr ns1; 6849 xmlNodeSetPtr ns2; 6850 6851 if ((arg1 == NULL) || 6852 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) 6853 return(0); 6854 if ((arg2 == NULL) || 6855 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) 6856 return(0); 6857 6858 ns1 = arg1->nodesetval; 6859 ns2 = arg2->nodesetval; 6860 6861 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) 6862 return(0); 6863 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) 6864 return(0); 6865 6866 /* 6867 * for equal, check if there is a node pertaining to both sets 6868 */ 6869 if (neq == 0) 6870 for (i = 0;i < ns1->nodeNr;i++) 6871 for (j = 0;j < ns2->nodeNr;j++) 6872 if (ns1->nodeTab[i] == ns2->nodeTab[j]) 6873 return(1); 6874 6875 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *)); 6876 if (values1 == NULL) { 6877 /* TODO: Propagate memory error. */ 6878 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6879 return(0); 6880 } 6881 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int)); 6882 if (hashs1 == NULL) { 6883 /* TODO: Propagate memory error. */ 6884 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6885 xmlFree(values1); 6886 return(0); 6887 } 6888 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *)); 6889 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *)); 6890 if (values2 == NULL) { 6891 /* TODO: Propagate memory error. */ 6892 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6893 xmlFree(hashs1); 6894 xmlFree(values1); 6895 return(0); 6896 } 6897 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int)); 6898 if (hashs2 == NULL) { 6899 /* TODO: Propagate memory error. */ 6900 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6901 xmlFree(hashs1); 6902 xmlFree(values1); 6903 xmlFree(values2); 6904 return(0); 6905 } 6906 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *)); 6907 for (i = 0;i < ns1->nodeNr;i++) { 6908 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]); 6909 for (j = 0;j < ns2->nodeNr;j++) { 6910 if (i == 0) 6911 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]); 6912 if (hashs1[i] != hashs2[j]) { 6913 if (neq) { 6914 ret = 1; 6915 break; 6916 } 6917 } 6918 else { 6919 if (values1[i] == NULL) 6920 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]); 6921 if (values2[j] == NULL) 6922 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]); 6923 ret = xmlStrEqual(values1[i], values2[j]) ^ neq; 6924 if (ret) 6925 break; 6926 } 6927 } 6928 if (ret) 6929 break; 6930 } 6931 for (i = 0;i < ns1->nodeNr;i++) 6932 if (values1[i] != NULL) 6933 xmlFree(values1[i]); 6934 for (j = 0;j < ns2->nodeNr;j++) 6935 if (values2[j] != NULL) 6936 xmlFree(values2[j]); 6937 xmlFree(values1); 6938 xmlFree(values2); 6939 xmlFree(hashs1); 6940 xmlFree(hashs2); 6941 return(ret); 6942 } 6943 6944 static int 6945 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt, 6946 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) { 6947 int ret = 0; 6948 /* 6949 *At this point we are assured neither arg1 nor arg2 6950 *is a nodeset, so we can just pick the appropriate routine. 6951 */ 6952 switch (arg1->type) { 6953 case XPATH_UNDEFINED: 6954 #ifdef DEBUG_EXPR 6955 xmlGenericError(xmlGenericErrorContext, 6956 "Equal: undefined\n"); 6957 #endif 6958 break; 6959 case XPATH_BOOLEAN: 6960 switch (arg2->type) { 6961 case XPATH_UNDEFINED: 6962 #ifdef DEBUG_EXPR 6963 xmlGenericError(xmlGenericErrorContext, 6964 "Equal: undefined\n"); 6965 #endif 6966 break; 6967 case XPATH_BOOLEAN: 6968 #ifdef DEBUG_EXPR 6969 xmlGenericError(xmlGenericErrorContext, 6970 "Equal: %d boolean %d \n", 6971 arg1->boolval, arg2->boolval); 6972 #endif 6973 ret = (arg1->boolval == arg2->boolval); 6974 break; 6975 case XPATH_NUMBER: 6976 ret = (arg1->boolval == 6977 xmlXPathCastNumberToBoolean(arg2->floatval)); 6978 break; 6979 case XPATH_STRING: 6980 if ((arg2->stringval == NULL) || 6981 (arg2->stringval[0] == 0)) ret = 0; 6982 else 6983 ret = 1; 6984 ret = (arg1->boolval == ret); 6985 break; 6986 case XPATH_USERS: 6987 case XPATH_POINT: 6988 case XPATH_RANGE: 6989 case XPATH_LOCATIONSET: 6990 TODO 6991 break; 6992 case XPATH_NODESET: 6993 case XPATH_XSLT_TREE: 6994 break; 6995 } 6996 break; 6997 case XPATH_NUMBER: 6998 switch (arg2->type) { 6999 case XPATH_UNDEFINED: 7000 #ifdef DEBUG_EXPR 7001 xmlGenericError(xmlGenericErrorContext, 7002 "Equal: undefined\n"); 7003 #endif 7004 break; 7005 case XPATH_BOOLEAN: 7006 ret = (arg2->boolval== 7007 xmlXPathCastNumberToBoolean(arg1->floatval)); 7008 break; 7009 case XPATH_STRING: 7010 valuePush(ctxt, arg2); 7011 xmlXPathNumberFunction(ctxt, 1); 7012 arg2 = valuePop(ctxt); 7013 /* Falls through. */ 7014 case XPATH_NUMBER: 7015 /* Hand check NaN and Infinity equalities */ 7016 if (xmlXPathIsNaN(arg1->floatval) || 7017 xmlXPathIsNaN(arg2->floatval)) { 7018 ret = 0; 7019 } else if (xmlXPathIsInf(arg1->floatval) == 1) { 7020 if (xmlXPathIsInf(arg2->floatval) == 1) 7021 ret = 1; 7022 else 7023 ret = 0; 7024 } else if (xmlXPathIsInf(arg1->floatval) == -1) { 7025 if (xmlXPathIsInf(arg2->floatval) == -1) 7026 ret = 1; 7027 else 7028 ret = 0; 7029 } else if (xmlXPathIsInf(arg2->floatval) == 1) { 7030 if (xmlXPathIsInf(arg1->floatval) == 1) 7031 ret = 1; 7032 else 7033 ret = 0; 7034 } else if (xmlXPathIsInf(arg2->floatval) == -1) { 7035 if (xmlXPathIsInf(arg1->floatval) == -1) 7036 ret = 1; 7037 else 7038 ret = 0; 7039 } else { 7040 ret = (arg1->floatval == arg2->floatval); 7041 } 7042 break; 7043 case XPATH_USERS: 7044 case XPATH_POINT: 7045 case XPATH_RANGE: 7046 case XPATH_LOCATIONSET: 7047 TODO 7048 break; 7049 case XPATH_NODESET: 7050 case XPATH_XSLT_TREE: 7051 break; 7052 } 7053 break; 7054 case XPATH_STRING: 7055 switch (arg2->type) { 7056 case XPATH_UNDEFINED: 7057 #ifdef DEBUG_EXPR 7058 xmlGenericError(xmlGenericErrorContext, 7059 "Equal: undefined\n"); 7060 #endif 7061 break; 7062 case XPATH_BOOLEAN: 7063 if ((arg1->stringval == NULL) || 7064 (arg1->stringval[0] == 0)) ret = 0; 7065 else 7066 ret = 1; 7067 ret = (arg2->boolval == ret); 7068 break; 7069 case XPATH_STRING: 7070 ret = xmlStrEqual(arg1->stringval, arg2->stringval); 7071 break; 7072 case XPATH_NUMBER: 7073 valuePush(ctxt, arg1); 7074 xmlXPathNumberFunction(ctxt, 1); 7075 arg1 = valuePop(ctxt); 7076 /* Hand check NaN and Infinity equalities */ 7077 if (xmlXPathIsNaN(arg1->floatval) || 7078 xmlXPathIsNaN(arg2->floatval)) { 7079 ret = 0; 7080 } else if (xmlXPathIsInf(arg1->floatval) == 1) { 7081 if (xmlXPathIsInf(arg2->floatval) == 1) 7082 ret = 1; 7083 else 7084 ret = 0; 7085 } else if (xmlXPathIsInf(arg1->floatval) == -1) { 7086 if (xmlXPathIsInf(arg2->floatval) == -1) 7087 ret = 1; 7088 else 7089 ret = 0; 7090 } else if (xmlXPathIsInf(arg2->floatval) == 1) { 7091 if (xmlXPathIsInf(arg1->floatval) == 1) 7092 ret = 1; 7093 else 7094 ret = 0; 7095 } else if (xmlXPathIsInf(arg2->floatval) == -1) { 7096 if (xmlXPathIsInf(arg1->floatval) == -1) 7097 ret = 1; 7098 else 7099 ret = 0; 7100 } else { 7101 ret = (arg1->floatval == arg2->floatval); 7102 } 7103 break; 7104 case XPATH_USERS: 7105 case XPATH_POINT: 7106 case XPATH_RANGE: 7107 case XPATH_LOCATIONSET: 7108 TODO 7109 break; 7110 case XPATH_NODESET: 7111 case XPATH_XSLT_TREE: 7112 break; 7113 } 7114 break; 7115 case XPATH_USERS: 7116 case XPATH_POINT: 7117 case XPATH_RANGE: 7118 case XPATH_LOCATIONSET: 7119 TODO 7120 break; 7121 case XPATH_NODESET: 7122 case XPATH_XSLT_TREE: 7123 break; 7124 } 7125 xmlXPathReleaseObject(ctxt->context, arg1); 7126 xmlXPathReleaseObject(ctxt->context, arg2); 7127 return(ret); 7128 } 7129 7130 /** 7131 * xmlXPathEqualValues: 7132 * @ctxt: the XPath Parser context 7133 * 7134 * Implement the equal operation on XPath objects content: @arg1 == @arg2 7135 * 7136 * Returns 0 or 1 depending on the results of the test. 7137 */ 7138 int 7139 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) { 7140 xmlXPathObjectPtr arg1, arg2, argtmp; 7141 int ret = 0; 7142 7143 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); 7144 arg2 = valuePop(ctxt); 7145 arg1 = valuePop(ctxt); 7146 if ((arg1 == NULL) || (arg2 == NULL)) { 7147 if (arg1 != NULL) 7148 xmlXPathReleaseObject(ctxt->context, arg1); 7149 else 7150 xmlXPathReleaseObject(ctxt->context, arg2); 7151 XP_ERROR0(XPATH_INVALID_OPERAND); 7152 } 7153 7154 if (arg1 == arg2) { 7155 #ifdef DEBUG_EXPR 7156 xmlGenericError(xmlGenericErrorContext, 7157 "Equal: by pointer\n"); 7158 #endif 7159 xmlXPathFreeObject(arg1); 7160 return(1); 7161 } 7162 7163 /* 7164 *If either argument is a nodeset, it's a 'special case' 7165 */ 7166 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 7167 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7168 /* 7169 *Hack it to assure arg1 is the nodeset 7170 */ 7171 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) { 7172 argtmp = arg2; 7173 arg2 = arg1; 7174 arg1 = argtmp; 7175 } 7176 switch (arg2->type) { 7177 case XPATH_UNDEFINED: 7178 #ifdef DEBUG_EXPR 7179 xmlGenericError(xmlGenericErrorContext, 7180 "Equal: undefined\n"); 7181 #endif 7182 break; 7183 case XPATH_NODESET: 7184 case XPATH_XSLT_TREE: 7185 ret = xmlXPathEqualNodeSets(arg1, arg2, 0); 7186 break; 7187 case XPATH_BOOLEAN: 7188 if ((arg1->nodesetval == NULL) || 7189 (arg1->nodesetval->nodeNr == 0)) ret = 0; 7190 else 7191 ret = 1; 7192 ret = (ret == arg2->boolval); 7193 break; 7194 case XPATH_NUMBER: 7195 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0); 7196 break; 7197 case XPATH_STRING: 7198 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0); 7199 break; 7200 case XPATH_USERS: 7201 case XPATH_POINT: 7202 case XPATH_RANGE: 7203 case XPATH_LOCATIONSET: 7204 TODO 7205 break; 7206 } 7207 xmlXPathReleaseObject(ctxt->context, arg1); 7208 xmlXPathReleaseObject(ctxt->context, arg2); 7209 return(ret); 7210 } 7211 7212 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2)); 7213 } 7214 7215 /** 7216 * xmlXPathNotEqualValues: 7217 * @ctxt: the XPath Parser context 7218 * 7219 * Implement the equal operation on XPath objects content: @arg1 == @arg2 7220 * 7221 * Returns 0 or 1 depending on the results of the test. 7222 */ 7223 int 7224 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) { 7225 xmlXPathObjectPtr arg1, arg2, argtmp; 7226 int ret = 0; 7227 7228 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); 7229 arg2 = valuePop(ctxt); 7230 arg1 = valuePop(ctxt); 7231 if ((arg1 == NULL) || (arg2 == NULL)) { 7232 if (arg1 != NULL) 7233 xmlXPathReleaseObject(ctxt->context, arg1); 7234 else 7235 xmlXPathReleaseObject(ctxt->context, arg2); 7236 XP_ERROR0(XPATH_INVALID_OPERAND); 7237 } 7238 7239 if (arg1 == arg2) { 7240 #ifdef DEBUG_EXPR 7241 xmlGenericError(xmlGenericErrorContext, 7242 "NotEqual: by pointer\n"); 7243 #endif 7244 xmlXPathReleaseObject(ctxt->context, arg1); 7245 return(0); 7246 } 7247 7248 /* 7249 *If either argument is a nodeset, it's a 'special case' 7250 */ 7251 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 7252 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7253 /* 7254 *Hack it to assure arg1 is the nodeset 7255 */ 7256 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) { 7257 argtmp = arg2; 7258 arg2 = arg1; 7259 arg1 = argtmp; 7260 } 7261 switch (arg2->type) { 7262 case XPATH_UNDEFINED: 7263 #ifdef DEBUG_EXPR 7264 xmlGenericError(xmlGenericErrorContext, 7265 "NotEqual: undefined\n"); 7266 #endif 7267 break; 7268 case XPATH_NODESET: 7269 case XPATH_XSLT_TREE: 7270 ret = xmlXPathEqualNodeSets(arg1, arg2, 1); 7271 break; 7272 case XPATH_BOOLEAN: 7273 if ((arg1->nodesetval == NULL) || 7274 (arg1->nodesetval->nodeNr == 0)) ret = 0; 7275 else 7276 ret = 1; 7277 ret = (ret != arg2->boolval); 7278 break; 7279 case XPATH_NUMBER: 7280 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1); 7281 break; 7282 case XPATH_STRING: 7283 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1); 7284 break; 7285 case XPATH_USERS: 7286 case XPATH_POINT: 7287 case XPATH_RANGE: 7288 case XPATH_LOCATIONSET: 7289 TODO 7290 break; 7291 } 7292 xmlXPathReleaseObject(ctxt->context, arg1); 7293 xmlXPathReleaseObject(ctxt->context, arg2); 7294 return(ret); 7295 } 7296 7297 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2)); 7298 } 7299 7300 /** 7301 * xmlXPathCompareValues: 7302 * @ctxt: the XPath Parser context 7303 * @inf: less than (1) or greater than (0) 7304 * @strict: is the comparison strict 7305 * 7306 * Implement the compare operation on XPath objects: 7307 * @arg1 < @arg2 (1, 1, ... 7308 * @arg1 <= @arg2 (1, 0, ... 7309 * @arg1 > @arg2 (0, 1, ... 7310 * @arg1 >= @arg2 (0, 0, ... 7311 * 7312 * When neither object to be compared is a node-set and the operator is 7313 * <=, <, >=, >, then the objects are compared by converted both objects 7314 * to numbers and comparing the numbers according to IEEE 754. The < 7315 * comparison will be true if and only if the first number is less than the 7316 * second number. The <= comparison will be true if and only if the first 7317 * number is less than or equal to the second number. The > comparison 7318 * will be true if and only if the first number is greater than the second 7319 * number. The >= comparison will be true if and only if the first number 7320 * is greater than or equal to the second number. 7321 * 7322 * Returns 1 if the comparison succeeded, 0 if it failed 7323 */ 7324 int 7325 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) { 7326 int ret = 0, arg1i = 0, arg2i = 0; 7327 xmlXPathObjectPtr arg1, arg2; 7328 7329 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); 7330 arg2 = valuePop(ctxt); 7331 arg1 = valuePop(ctxt); 7332 if ((arg1 == NULL) || (arg2 == NULL)) { 7333 if (arg1 != NULL) 7334 xmlXPathReleaseObject(ctxt->context, arg1); 7335 else 7336 xmlXPathReleaseObject(ctxt->context, arg2); 7337 XP_ERROR0(XPATH_INVALID_OPERAND); 7338 } 7339 7340 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 7341 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7342 /* 7343 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments 7344 * are not freed from within this routine; they will be freed from the 7345 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue 7346 */ 7347 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) && 7348 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){ 7349 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2); 7350 } else { 7351 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7352 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict, 7353 arg1, arg2); 7354 } else { 7355 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict, 7356 arg2, arg1); 7357 } 7358 } 7359 return(ret); 7360 } 7361 7362 if (arg1->type != XPATH_NUMBER) { 7363 valuePush(ctxt, arg1); 7364 xmlXPathNumberFunction(ctxt, 1); 7365 arg1 = valuePop(ctxt); 7366 } 7367 if (arg1->type != XPATH_NUMBER) { 7368 xmlXPathFreeObject(arg1); 7369 xmlXPathFreeObject(arg2); 7370 XP_ERROR0(XPATH_INVALID_OPERAND); 7371 } 7372 if (arg2->type != XPATH_NUMBER) { 7373 valuePush(ctxt, arg2); 7374 xmlXPathNumberFunction(ctxt, 1); 7375 arg2 = valuePop(ctxt); 7376 } 7377 if (arg2->type != XPATH_NUMBER) { 7378 xmlXPathReleaseObject(ctxt->context, arg1); 7379 xmlXPathReleaseObject(ctxt->context, arg2); 7380 XP_ERROR0(XPATH_INVALID_OPERAND); 7381 } 7382 /* 7383 * Add tests for infinity and nan 7384 * => feedback on 3.4 for Inf and NaN 7385 */ 7386 /* Hand check NaN and Infinity comparisons */ 7387 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) { 7388 ret=0; 7389 } else { 7390 arg1i=xmlXPathIsInf(arg1->floatval); 7391 arg2i=xmlXPathIsInf(arg2->floatval); 7392 if (inf && strict) { 7393 if ((arg1i == -1 && arg2i != -1) || 7394 (arg2i == 1 && arg1i != 1)) { 7395 ret = 1; 7396 } else if (arg1i == 0 && arg2i == 0) { 7397 ret = (arg1->floatval < arg2->floatval); 7398 } else { 7399 ret = 0; 7400 } 7401 } 7402 else if (inf && !strict) { 7403 if (arg1i == -1 || arg2i == 1) { 7404 ret = 1; 7405 } else if (arg1i == 0 && arg2i == 0) { 7406 ret = (arg1->floatval <= arg2->floatval); 7407 } else { 7408 ret = 0; 7409 } 7410 } 7411 else if (!inf && strict) { 7412 if ((arg1i == 1 && arg2i != 1) || 7413 (arg2i == -1 && arg1i != -1)) { 7414 ret = 1; 7415 } else if (arg1i == 0 && arg2i == 0) { 7416 ret = (arg1->floatval > arg2->floatval); 7417 } else { 7418 ret = 0; 7419 } 7420 } 7421 else if (!inf && !strict) { 7422 if (arg1i == 1 || arg2i == -1) { 7423 ret = 1; 7424 } else if (arg1i == 0 && arg2i == 0) { 7425 ret = (arg1->floatval >= arg2->floatval); 7426 } else { 7427 ret = 0; 7428 } 7429 } 7430 } 7431 xmlXPathReleaseObject(ctxt->context, arg1); 7432 xmlXPathReleaseObject(ctxt->context, arg2); 7433 return(ret); 7434 } 7435 7436 /** 7437 * xmlXPathValueFlipSign: 7438 * @ctxt: the XPath Parser context 7439 * 7440 * Implement the unary - operation on an XPath object 7441 * The numeric operators convert their operands to numbers as if 7442 * by calling the number function. 7443 */ 7444 void 7445 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) { 7446 if ((ctxt == NULL) || (ctxt->context == NULL)) return; 7447 CAST_TO_NUMBER; 7448 CHECK_TYPE(XPATH_NUMBER); 7449 ctxt->value->floatval = -ctxt->value->floatval; 7450 } 7451 7452 /** 7453 * xmlXPathAddValues: 7454 * @ctxt: the XPath Parser context 7455 * 7456 * Implement the add operation on XPath objects: 7457 * The numeric operators convert their operands to numbers as if 7458 * by calling the number function. 7459 */ 7460 void 7461 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) { 7462 xmlXPathObjectPtr arg; 7463 double val; 7464 7465 arg = valuePop(ctxt); 7466 if (arg == NULL) 7467 XP_ERROR(XPATH_INVALID_OPERAND); 7468 val = xmlXPathCastToNumber(arg); 7469 xmlXPathReleaseObject(ctxt->context, arg); 7470 CAST_TO_NUMBER; 7471 CHECK_TYPE(XPATH_NUMBER); 7472 ctxt->value->floatval += val; 7473 } 7474 7475 /** 7476 * xmlXPathSubValues: 7477 * @ctxt: the XPath Parser context 7478 * 7479 * Implement the subtraction operation on XPath objects: 7480 * The numeric operators convert their operands to numbers as if 7481 * by calling the number function. 7482 */ 7483 void 7484 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) { 7485 xmlXPathObjectPtr arg; 7486 double val; 7487 7488 arg = valuePop(ctxt); 7489 if (arg == NULL) 7490 XP_ERROR(XPATH_INVALID_OPERAND); 7491 val = xmlXPathCastToNumber(arg); 7492 xmlXPathReleaseObject(ctxt->context, arg); 7493 CAST_TO_NUMBER; 7494 CHECK_TYPE(XPATH_NUMBER); 7495 ctxt->value->floatval -= val; 7496 } 7497 7498 /** 7499 * xmlXPathMultValues: 7500 * @ctxt: the XPath Parser context 7501 * 7502 * Implement the multiply operation on XPath objects: 7503 * The numeric operators convert their operands to numbers as if 7504 * by calling the number function. 7505 */ 7506 void 7507 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) { 7508 xmlXPathObjectPtr arg; 7509 double val; 7510 7511 arg = valuePop(ctxt); 7512 if (arg == NULL) 7513 XP_ERROR(XPATH_INVALID_OPERAND); 7514 val = xmlXPathCastToNumber(arg); 7515 xmlXPathReleaseObject(ctxt->context, arg); 7516 CAST_TO_NUMBER; 7517 CHECK_TYPE(XPATH_NUMBER); 7518 ctxt->value->floatval *= val; 7519 } 7520 7521 /** 7522 * xmlXPathDivValues: 7523 * @ctxt: the XPath Parser context 7524 * 7525 * Implement the div operation on XPath objects @arg1 / @arg2: 7526 * The numeric operators convert their operands to numbers as if 7527 * by calling the number function. 7528 */ 7529 ATTRIBUTE_NO_SANITIZE("float-divide-by-zero") 7530 void 7531 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) { 7532 xmlXPathObjectPtr arg; 7533 double val; 7534 7535 arg = valuePop(ctxt); 7536 if (arg == NULL) 7537 XP_ERROR(XPATH_INVALID_OPERAND); 7538 val = xmlXPathCastToNumber(arg); 7539 xmlXPathReleaseObject(ctxt->context, arg); 7540 CAST_TO_NUMBER; 7541 CHECK_TYPE(XPATH_NUMBER); 7542 ctxt->value->floatval /= val; 7543 } 7544 7545 /** 7546 * xmlXPathModValues: 7547 * @ctxt: the XPath Parser context 7548 * 7549 * Implement the mod operation on XPath objects: @arg1 / @arg2 7550 * The numeric operators convert their operands to numbers as if 7551 * by calling the number function. 7552 */ 7553 void 7554 xmlXPathModValues(xmlXPathParserContextPtr ctxt) { 7555 xmlXPathObjectPtr arg; 7556 double arg1, arg2; 7557 7558 arg = valuePop(ctxt); 7559 if (arg == NULL) 7560 XP_ERROR(XPATH_INVALID_OPERAND); 7561 arg2 = xmlXPathCastToNumber(arg); 7562 xmlXPathReleaseObject(ctxt->context, arg); 7563 CAST_TO_NUMBER; 7564 CHECK_TYPE(XPATH_NUMBER); 7565 arg1 = ctxt->value->floatval; 7566 if (arg2 == 0) 7567 ctxt->value->floatval = NAN; 7568 else { 7569 ctxt->value->floatval = fmod(arg1, arg2); 7570 } 7571 } 7572 7573 /************************************************************************ 7574 * * 7575 * The traversal functions * 7576 * * 7577 ************************************************************************/ 7578 7579 /* 7580 * A traversal function enumerates nodes along an axis. 7581 * Initially it must be called with NULL, and it indicates 7582 * termination on the axis by returning NULL. 7583 */ 7584 typedef xmlNodePtr (*xmlXPathTraversalFunction) 7585 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur); 7586 7587 /* 7588 * xmlXPathTraversalFunctionExt: 7589 * A traversal function enumerates nodes along an axis. 7590 * Initially it must be called with NULL, and it indicates 7591 * termination on the axis by returning NULL. 7592 * The context node of the traversal is specified via @contextNode. 7593 */ 7594 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt) 7595 (xmlNodePtr cur, xmlNodePtr contextNode); 7596 7597 /* 7598 * xmlXPathNodeSetMergeFunction: 7599 * Used for merging node sets in xmlXPathCollectAndTest(). 7600 */ 7601 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction) 7602 (xmlNodeSetPtr, xmlNodeSetPtr); 7603 7604 7605 /** 7606 * xmlXPathNextSelf: 7607 * @ctxt: the XPath Parser context 7608 * @cur: the current node in the traversal 7609 * 7610 * Traversal function for the "self" direction 7611 * The self axis contains just the context node itself 7612 * 7613 * Returns the next element following that axis 7614 */ 7615 xmlNodePtr 7616 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7617 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7618 if (cur == NULL) 7619 return(ctxt->context->node); 7620 return(NULL); 7621 } 7622 7623 /** 7624 * xmlXPathNextChild: 7625 * @ctxt: the XPath Parser context 7626 * @cur: the current node in the traversal 7627 * 7628 * Traversal function for the "child" direction 7629 * The child axis contains the children of the context node in document order. 7630 * 7631 * Returns the next element following that axis 7632 */ 7633 xmlNodePtr 7634 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7635 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7636 if (cur == NULL) { 7637 if (ctxt->context->node == NULL) return(NULL); 7638 switch (ctxt->context->node->type) { 7639 case XML_ELEMENT_NODE: 7640 case XML_TEXT_NODE: 7641 case XML_CDATA_SECTION_NODE: 7642 case XML_ENTITY_REF_NODE: 7643 case XML_ENTITY_NODE: 7644 case XML_PI_NODE: 7645 case XML_COMMENT_NODE: 7646 case XML_NOTATION_NODE: 7647 case XML_DTD_NODE: 7648 return(ctxt->context->node->children); 7649 case XML_DOCUMENT_NODE: 7650 case XML_DOCUMENT_TYPE_NODE: 7651 case XML_DOCUMENT_FRAG_NODE: 7652 case XML_HTML_DOCUMENT_NODE: 7653 #ifdef LIBXML_DOCB_ENABLED 7654 case XML_DOCB_DOCUMENT_NODE: 7655 #endif 7656 return(((xmlDocPtr) ctxt->context->node)->children); 7657 case XML_ELEMENT_DECL: 7658 case XML_ATTRIBUTE_DECL: 7659 case XML_ENTITY_DECL: 7660 case XML_ATTRIBUTE_NODE: 7661 case XML_NAMESPACE_DECL: 7662 case XML_XINCLUDE_START: 7663 case XML_XINCLUDE_END: 7664 return(NULL); 7665 } 7666 return(NULL); 7667 } 7668 if ((cur->type == XML_DOCUMENT_NODE) || 7669 (cur->type == XML_HTML_DOCUMENT_NODE)) 7670 return(NULL); 7671 return(cur->next); 7672 } 7673 7674 /** 7675 * xmlXPathNextChildElement: 7676 * @ctxt: the XPath Parser context 7677 * @cur: the current node in the traversal 7678 * 7679 * Traversal function for the "child" direction and nodes of type element. 7680 * The child axis contains the children of the context node in document order. 7681 * 7682 * Returns the next element following that axis 7683 */ 7684 static xmlNodePtr 7685 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7686 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7687 if (cur == NULL) { 7688 cur = ctxt->context->node; 7689 if (cur == NULL) return(NULL); 7690 /* 7691 * Get the first element child. 7692 */ 7693 switch (cur->type) { 7694 case XML_ELEMENT_NODE: 7695 case XML_DOCUMENT_FRAG_NODE: 7696 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */ 7697 case XML_ENTITY_NODE: 7698 cur = cur->children; 7699 if (cur != NULL) { 7700 if (cur->type == XML_ELEMENT_NODE) 7701 return(cur); 7702 do { 7703 cur = cur->next; 7704 } while ((cur != NULL) && 7705 (cur->type != XML_ELEMENT_NODE)); 7706 return(cur); 7707 } 7708 return(NULL); 7709 case XML_DOCUMENT_NODE: 7710 case XML_HTML_DOCUMENT_NODE: 7711 #ifdef LIBXML_DOCB_ENABLED 7712 case XML_DOCB_DOCUMENT_NODE: 7713 #endif 7714 return(xmlDocGetRootElement((xmlDocPtr) cur)); 7715 default: 7716 return(NULL); 7717 } 7718 return(NULL); 7719 } 7720 /* 7721 * Get the next sibling element node. 7722 */ 7723 switch (cur->type) { 7724 case XML_ELEMENT_NODE: 7725 case XML_TEXT_NODE: 7726 case XML_ENTITY_REF_NODE: 7727 case XML_ENTITY_NODE: 7728 case XML_CDATA_SECTION_NODE: 7729 case XML_PI_NODE: 7730 case XML_COMMENT_NODE: 7731 case XML_XINCLUDE_END: 7732 break; 7733 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */ 7734 default: 7735 return(NULL); 7736 } 7737 if (cur->next != NULL) { 7738 if (cur->next->type == XML_ELEMENT_NODE) 7739 return(cur->next); 7740 cur = cur->next; 7741 do { 7742 cur = cur->next; 7743 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE)); 7744 return(cur); 7745 } 7746 return(NULL); 7747 } 7748 7749 #if 0 7750 /** 7751 * xmlXPathNextDescendantOrSelfElemParent: 7752 * @ctxt: the XPath Parser context 7753 * @cur: the current node in the traversal 7754 * 7755 * Traversal function for the "descendant-or-self" axis. 7756 * Additionally it returns only nodes which can be parents of 7757 * element nodes. 7758 * 7759 * 7760 * Returns the next element following that axis 7761 */ 7762 static xmlNodePtr 7763 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur, 7764 xmlNodePtr contextNode) 7765 { 7766 if (cur == NULL) { 7767 if (contextNode == NULL) 7768 return(NULL); 7769 switch (contextNode->type) { 7770 case XML_ELEMENT_NODE: 7771 case XML_XINCLUDE_START: 7772 case XML_DOCUMENT_FRAG_NODE: 7773 case XML_DOCUMENT_NODE: 7774 #ifdef LIBXML_DOCB_ENABLED 7775 case XML_DOCB_DOCUMENT_NODE: 7776 #endif 7777 case XML_HTML_DOCUMENT_NODE: 7778 return(contextNode); 7779 default: 7780 return(NULL); 7781 } 7782 return(NULL); 7783 } else { 7784 xmlNodePtr start = cur; 7785 7786 while (cur != NULL) { 7787 switch (cur->type) { 7788 case XML_ELEMENT_NODE: 7789 /* TODO: OK to have XInclude here? */ 7790 case XML_XINCLUDE_START: 7791 case XML_DOCUMENT_FRAG_NODE: 7792 if (cur != start) 7793 return(cur); 7794 if (cur->children != NULL) { 7795 cur = cur->children; 7796 continue; 7797 } 7798 break; 7799 /* Not sure if we need those here. */ 7800 case XML_DOCUMENT_NODE: 7801 #ifdef LIBXML_DOCB_ENABLED 7802 case XML_DOCB_DOCUMENT_NODE: 7803 #endif 7804 case XML_HTML_DOCUMENT_NODE: 7805 if (cur != start) 7806 return(cur); 7807 return(xmlDocGetRootElement((xmlDocPtr) cur)); 7808 default: 7809 break; 7810 } 7811 7812 next_sibling: 7813 if ((cur == NULL) || (cur == contextNode)) 7814 return(NULL); 7815 if (cur->next != NULL) { 7816 cur = cur->next; 7817 } else { 7818 cur = cur->parent; 7819 goto next_sibling; 7820 } 7821 } 7822 } 7823 return(NULL); 7824 } 7825 #endif 7826 7827 /** 7828 * xmlXPathNextDescendant: 7829 * @ctxt: the XPath Parser context 7830 * @cur: the current node in the traversal 7831 * 7832 * Traversal function for the "descendant" direction 7833 * the descendant axis contains the descendants of the context node in document 7834 * order; a descendant is a child or a child of a child and so on. 7835 * 7836 * Returns the next element following that axis 7837 */ 7838 xmlNodePtr 7839 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7840 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7841 if (cur == NULL) { 7842 if (ctxt->context->node == NULL) 7843 return(NULL); 7844 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 7845 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 7846 return(NULL); 7847 7848 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc) 7849 return(ctxt->context->doc->children); 7850 return(ctxt->context->node->children); 7851 } 7852 7853 if (cur->type == XML_NAMESPACE_DECL) 7854 return(NULL); 7855 if (cur->children != NULL) { 7856 /* 7857 * Do not descend on entities declarations 7858 */ 7859 if (cur->children->type != XML_ENTITY_DECL) { 7860 cur = cur->children; 7861 /* 7862 * Skip DTDs 7863 */ 7864 if (cur->type != XML_DTD_NODE) 7865 return(cur); 7866 } 7867 } 7868 7869 if (cur == ctxt->context->node) return(NULL); 7870 7871 while (cur->next != NULL) { 7872 cur = cur->next; 7873 if ((cur->type != XML_ENTITY_DECL) && 7874 (cur->type != XML_DTD_NODE)) 7875 return(cur); 7876 } 7877 7878 do { 7879 cur = cur->parent; 7880 if (cur == NULL) break; 7881 if (cur == ctxt->context->node) return(NULL); 7882 if (cur->next != NULL) { 7883 cur = cur->next; 7884 return(cur); 7885 } 7886 } while (cur != NULL); 7887 return(cur); 7888 } 7889 7890 /** 7891 * xmlXPathNextDescendantOrSelf: 7892 * @ctxt: the XPath Parser context 7893 * @cur: the current node in the traversal 7894 * 7895 * Traversal function for the "descendant-or-self" direction 7896 * the descendant-or-self axis contains the context node and the descendants 7897 * of the context node in document order; thus the context node is the first 7898 * node on the axis, and the first child of the context node is the second node 7899 * on the axis 7900 * 7901 * Returns the next element following that axis 7902 */ 7903 xmlNodePtr 7904 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7905 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7906 if (cur == NULL) 7907 return(ctxt->context->node); 7908 7909 if (ctxt->context->node == NULL) 7910 return(NULL); 7911 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 7912 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 7913 return(NULL); 7914 7915 return(xmlXPathNextDescendant(ctxt, cur)); 7916 } 7917 7918 /** 7919 * xmlXPathNextParent: 7920 * @ctxt: the XPath Parser context 7921 * @cur: the current node in the traversal 7922 * 7923 * Traversal function for the "parent" direction 7924 * The parent axis contains the parent of the context node, if there is one. 7925 * 7926 * Returns the next element following that axis 7927 */ 7928 xmlNodePtr 7929 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7930 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7931 /* 7932 * the parent of an attribute or namespace node is the element 7933 * to which the attribute or namespace node is attached 7934 * Namespace handling !!! 7935 */ 7936 if (cur == NULL) { 7937 if (ctxt->context->node == NULL) return(NULL); 7938 switch (ctxt->context->node->type) { 7939 case XML_ELEMENT_NODE: 7940 case XML_TEXT_NODE: 7941 case XML_CDATA_SECTION_NODE: 7942 case XML_ENTITY_REF_NODE: 7943 case XML_ENTITY_NODE: 7944 case XML_PI_NODE: 7945 case XML_COMMENT_NODE: 7946 case XML_NOTATION_NODE: 7947 case XML_DTD_NODE: 7948 case XML_ELEMENT_DECL: 7949 case XML_ATTRIBUTE_DECL: 7950 case XML_XINCLUDE_START: 7951 case XML_XINCLUDE_END: 7952 case XML_ENTITY_DECL: 7953 if (ctxt->context->node->parent == NULL) 7954 return((xmlNodePtr) ctxt->context->doc); 7955 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) && 7956 ((ctxt->context->node->parent->name[0] == ' ') || 7957 (xmlStrEqual(ctxt->context->node->parent->name, 7958 BAD_CAST "fake node libxslt")))) 7959 return(NULL); 7960 return(ctxt->context->node->parent); 7961 case XML_ATTRIBUTE_NODE: { 7962 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node; 7963 7964 return(att->parent); 7965 } 7966 case XML_DOCUMENT_NODE: 7967 case XML_DOCUMENT_TYPE_NODE: 7968 case XML_DOCUMENT_FRAG_NODE: 7969 case XML_HTML_DOCUMENT_NODE: 7970 #ifdef LIBXML_DOCB_ENABLED 7971 case XML_DOCB_DOCUMENT_NODE: 7972 #endif 7973 return(NULL); 7974 case XML_NAMESPACE_DECL: { 7975 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; 7976 7977 if ((ns->next != NULL) && 7978 (ns->next->type != XML_NAMESPACE_DECL)) 7979 return((xmlNodePtr) ns->next); 7980 return(NULL); 7981 } 7982 } 7983 } 7984 return(NULL); 7985 } 7986 7987 /** 7988 * xmlXPathNextAncestor: 7989 * @ctxt: the XPath Parser context 7990 * @cur: the current node in the traversal 7991 * 7992 * Traversal function for the "ancestor" direction 7993 * the ancestor axis contains the ancestors of the context node; the ancestors 7994 * of the context node consist of the parent of context node and the parent's 7995 * parent and so on; the nodes are ordered in reverse document order; thus the 7996 * parent is the first node on the axis, and the parent's parent is the second 7997 * node on the axis 7998 * 7999 * Returns the next element following that axis 8000 */ 8001 xmlNodePtr 8002 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8003 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8004 /* 8005 * the parent of an attribute or namespace node is the element 8006 * to which the attribute or namespace node is attached 8007 * !!!!!!!!!!!!! 8008 */ 8009 if (cur == NULL) { 8010 if (ctxt->context->node == NULL) return(NULL); 8011 switch (ctxt->context->node->type) { 8012 case XML_ELEMENT_NODE: 8013 case XML_TEXT_NODE: 8014 case XML_CDATA_SECTION_NODE: 8015 case XML_ENTITY_REF_NODE: 8016 case XML_ENTITY_NODE: 8017 case XML_PI_NODE: 8018 case XML_COMMENT_NODE: 8019 case XML_DTD_NODE: 8020 case XML_ELEMENT_DECL: 8021 case XML_ATTRIBUTE_DECL: 8022 case XML_ENTITY_DECL: 8023 case XML_NOTATION_NODE: 8024 case XML_XINCLUDE_START: 8025 case XML_XINCLUDE_END: 8026 if (ctxt->context->node->parent == NULL) 8027 return((xmlNodePtr) ctxt->context->doc); 8028 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) && 8029 ((ctxt->context->node->parent->name[0] == ' ') || 8030 (xmlStrEqual(ctxt->context->node->parent->name, 8031 BAD_CAST "fake node libxslt")))) 8032 return(NULL); 8033 return(ctxt->context->node->parent); 8034 case XML_ATTRIBUTE_NODE: { 8035 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node; 8036 8037 return(tmp->parent); 8038 } 8039 case XML_DOCUMENT_NODE: 8040 case XML_DOCUMENT_TYPE_NODE: 8041 case XML_DOCUMENT_FRAG_NODE: 8042 case XML_HTML_DOCUMENT_NODE: 8043 #ifdef LIBXML_DOCB_ENABLED 8044 case XML_DOCB_DOCUMENT_NODE: 8045 #endif 8046 return(NULL); 8047 case XML_NAMESPACE_DECL: { 8048 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; 8049 8050 if ((ns->next != NULL) && 8051 (ns->next->type != XML_NAMESPACE_DECL)) 8052 return((xmlNodePtr) ns->next); 8053 /* Bad, how did that namespace end up here ? */ 8054 return(NULL); 8055 } 8056 } 8057 return(NULL); 8058 } 8059 if (cur == ctxt->context->doc->children) 8060 return((xmlNodePtr) ctxt->context->doc); 8061 if (cur == (xmlNodePtr) ctxt->context->doc) 8062 return(NULL); 8063 switch (cur->type) { 8064 case XML_ELEMENT_NODE: 8065 case XML_TEXT_NODE: 8066 case XML_CDATA_SECTION_NODE: 8067 case XML_ENTITY_REF_NODE: 8068 case XML_ENTITY_NODE: 8069 case XML_PI_NODE: 8070 case XML_COMMENT_NODE: 8071 case XML_NOTATION_NODE: 8072 case XML_DTD_NODE: 8073 case XML_ELEMENT_DECL: 8074 case XML_ATTRIBUTE_DECL: 8075 case XML_ENTITY_DECL: 8076 case XML_XINCLUDE_START: 8077 case XML_XINCLUDE_END: 8078 if (cur->parent == NULL) 8079 return(NULL); 8080 if ((cur->parent->type == XML_ELEMENT_NODE) && 8081 ((cur->parent->name[0] == ' ') || 8082 (xmlStrEqual(cur->parent->name, 8083 BAD_CAST "fake node libxslt")))) 8084 return(NULL); 8085 return(cur->parent); 8086 case XML_ATTRIBUTE_NODE: { 8087 xmlAttrPtr att = (xmlAttrPtr) cur; 8088 8089 return(att->parent); 8090 } 8091 case XML_NAMESPACE_DECL: { 8092 xmlNsPtr ns = (xmlNsPtr) cur; 8093 8094 if ((ns->next != NULL) && 8095 (ns->next->type != XML_NAMESPACE_DECL)) 8096 return((xmlNodePtr) ns->next); 8097 /* Bad, how did that namespace end up here ? */ 8098 return(NULL); 8099 } 8100 case XML_DOCUMENT_NODE: 8101 case XML_DOCUMENT_TYPE_NODE: 8102 case XML_DOCUMENT_FRAG_NODE: 8103 case XML_HTML_DOCUMENT_NODE: 8104 #ifdef LIBXML_DOCB_ENABLED 8105 case XML_DOCB_DOCUMENT_NODE: 8106 #endif 8107 return(NULL); 8108 } 8109 return(NULL); 8110 } 8111 8112 /** 8113 * xmlXPathNextAncestorOrSelf: 8114 * @ctxt: the XPath Parser context 8115 * @cur: the current node in the traversal 8116 * 8117 * Traversal function for the "ancestor-or-self" direction 8118 * he ancestor-or-self axis contains the context node and ancestors of 8119 * the context node in reverse document order; thus the context node is 8120 * the first node on the axis, and the context node's parent the second; 8121 * parent here is defined the same as with the parent axis. 8122 * 8123 * Returns the next element following that axis 8124 */ 8125 xmlNodePtr 8126 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8127 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8128 if (cur == NULL) 8129 return(ctxt->context->node); 8130 return(xmlXPathNextAncestor(ctxt, cur)); 8131 } 8132 8133 /** 8134 * xmlXPathNextFollowingSibling: 8135 * @ctxt: the XPath Parser context 8136 * @cur: the current node in the traversal 8137 * 8138 * Traversal function for the "following-sibling" direction 8139 * The following-sibling axis contains the following siblings of the context 8140 * node in document order. 8141 * 8142 * Returns the next element following that axis 8143 */ 8144 xmlNodePtr 8145 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8146 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8147 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 8148 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 8149 return(NULL); 8150 if (cur == (xmlNodePtr) ctxt->context->doc) 8151 return(NULL); 8152 if (cur == NULL) 8153 return(ctxt->context->node->next); 8154 return(cur->next); 8155 } 8156 8157 /** 8158 * xmlXPathNextPrecedingSibling: 8159 * @ctxt: the XPath Parser context 8160 * @cur: the current node in the traversal 8161 * 8162 * Traversal function for the "preceding-sibling" direction 8163 * The preceding-sibling axis contains the preceding siblings of the context 8164 * node in reverse document order; the first preceding sibling is first on the 8165 * axis; the sibling preceding that node is the second on the axis and so on. 8166 * 8167 * Returns the next element following that axis 8168 */ 8169 xmlNodePtr 8170 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8171 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8172 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 8173 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 8174 return(NULL); 8175 if (cur == (xmlNodePtr) ctxt->context->doc) 8176 return(NULL); 8177 if (cur == NULL) 8178 return(ctxt->context->node->prev); 8179 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) { 8180 cur = cur->prev; 8181 if (cur == NULL) 8182 return(ctxt->context->node->prev); 8183 } 8184 return(cur->prev); 8185 } 8186 8187 /** 8188 * xmlXPathNextFollowing: 8189 * @ctxt: the XPath Parser context 8190 * @cur: the current node in the traversal 8191 * 8192 * Traversal function for the "following" direction 8193 * The following axis contains all nodes in the same document as the context 8194 * node that are after the context node in document order, excluding any 8195 * descendants and excluding attribute nodes and namespace nodes; the nodes 8196 * are ordered in document order 8197 * 8198 * Returns the next element following that axis 8199 */ 8200 xmlNodePtr 8201 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8202 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8203 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) && 8204 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL)) 8205 return(cur->children); 8206 8207 if (cur == NULL) { 8208 cur = ctxt->context->node; 8209 if (cur->type == XML_ATTRIBUTE_NODE) { 8210 cur = cur->parent; 8211 } else if (cur->type == XML_NAMESPACE_DECL) { 8212 xmlNsPtr ns = (xmlNsPtr) cur; 8213 8214 if ((ns->next == NULL) || 8215 (ns->next->type == XML_NAMESPACE_DECL)) 8216 return (NULL); 8217 cur = (xmlNodePtr) ns->next; 8218 } 8219 } 8220 if (cur == NULL) return(NULL) ; /* ERROR */ 8221 if (cur->next != NULL) return(cur->next) ; 8222 do { 8223 cur = cur->parent; 8224 if (cur == NULL) break; 8225 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL); 8226 if (cur->next != NULL) return(cur->next); 8227 } while (cur != NULL); 8228 return(cur); 8229 } 8230 8231 /* 8232 * xmlXPathIsAncestor: 8233 * @ancestor: the ancestor node 8234 * @node: the current node 8235 * 8236 * Check that @ancestor is a @node's ancestor 8237 * 8238 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise. 8239 */ 8240 static int 8241 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) { 8242 if ((ancestor == NULL) || (node == NULL)) return(0); 8243 if (node->type == XML_NAMESPACE_DECL) 8244 return(0); 8245 if (ancestor->type == XML_NAMESPACE_DECL) 8246 return(0); 8247 /* nodes need to be in the same document */ 8248 if (ancestor->doc != node->doc) return(0); 8249 /* avoid searching if ancestor or node is the root node */ 8250 if (ancestor == (xmlNodePtr) node->doc) return(1); 8251 if (node == (xmlNodePtr) ancestor->doc) return(0); 8252 while (node->parent != NULL) { 8253 if (node->parent == ancestor) 8254 return(1); 8255 node = node->parent; 8256 } 8257 return(0); 8258 } 8259 8260 /** 8261 * xmlXPathNextPreceding: 8262 * @ctxt: the XPath Parser context 8263 * @cur: the current node in the traversal 8264 * 8265 * Traversal function for the "preceding" direction 8266 * the preceding axis contains all nodes in the same document as the context 8267 * node that are before the context node in document order, excluding any 8268 * ancestors and excluding attribute nodes and namespace nodes; the nodes are 8269 * ordered in reverse document order 8270 * 8271 * Returns the next element following that axis 8272 */ 8273 xmlNodePtr 8274 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) 8275 { 8276 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8277 if (cur == NULL) { 8278 cur = ctxt->context->node; 8279 if (cur->type == XML_ATTRIBUTE_NODE) { 8280 cur = cur->parent; 8281 } else if (cur->type == XML_NAMESPACE_DECL) { 8282 xmlNsPtr ns = (xmlNsPtr) cur; 8283 8284 if ((ns->next == NULL) || 8285 (ns->next->type == XML_NAMESPACE_DECL)) 8286 return (NULL); 8287 cur = (xmlNodePtr) ns->next; 8288 } 8289 } 8290 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) 8291 return (NULL); 8292 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) 8293 cur = cur->prev; 8294 do { 8295 if (cur->prev != NULL) { 8296 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ; 8297 return (cur); 8298 } 8299 8300 cur = cur->parent; 8301 if (cur == NULL) 8302 return (NULL); 8303 if (cur == ctxt->context->doc->children) 8304 return (NULL); 8305 } while (xmlXPathIsAncestor(cur, ctxt->context->node)); 8306 return (cur); 8307 } 8308 8309 /** 8310 * xmlXPathNextPrecedingInternal: 8311 * @ctxt: the XPath Parser context 8312 * @cur: the current node in the traversal 8313 * 8314 * Traversal function for the "preceding" direction 8315 * the preceding axis contains all nodes in the same document as the context 8316 * node that are before the context node in document order, excluding any 8317 * ancestors and excluding attribute nodes and namespace nodes; the nodes are 8318 * ordered in reverse document order 8319 * This is a faster implementation but internal only since it requires a 8320 * state kept in the parser context: ctxt->ancestor. 8321 * 8322 * Returns the next element following that axis 8323 */ 8324 static xmlNodePtr 8325 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt, 8326 xmlNodePtr cur) 8327 { 8328 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8329 if (cur == NULL) { 8330 cur = ctxt->context->node; 8331 if (cur == NULL) 8332 return (NULL); 8333 if (cur->type == XML_ATTRIBUTE_NODE) { 8334 cur = cur->parent; 8335 } else if (cur->type == XML_NAMESPACE_DECL) { 8336 xmlNsPtr ns = (xmlNsPtr) cur; 8337 8338 if ((ns->next == NULL) || 8339 (ns->next->type == XML_NAMESPACE_DECL)) 8340 return (NULL); 8341 cur = (xmlNodePtr) ns->next; 8342 } 8343 ctxt->ancestor = cur->parent; 8344 } 8345 if (cur->type == XML_NAMESPACE_DECL) 8346 return(NULL); 8347 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) 8348 cur = cur->prev; 8349 while (cur->prev == NULL) { 8350 cur = cur->parent; 8351 if (cur == NULL) 8352 return (NULL); 8353 if (cur == ctxt->context->doc->children) 8354 return (NULL); 8355 if (cur != ctxt->ancestor) 8356 return (cur); 8357 ctxt->ancestor = cur->parent; 8358 } 8359 cur = cur->prev; 8360 while (cur->last != NULL) 8361 cur = cur->last; 8362 return (cur); 8363 } 8364 8365 /** 8366 * xmlXPathNextNamespace: 8367 * @ctxt: the XPath Parser context 8368 * @cur: the current attribute in the traversal 8369 * 8370 * Traversal function for the "namespace" direction 8371 * the namespace axis contains the namespace nodes of the context node; 8372 * the order of nodes on this axis is implementation-defined; the axis will 8373 * be empty unless the context node is an element 8374 * 8375 * We keep the XML namespace node at the end of the list. 8376 * 8377 * Returns the next element following that axis 8378 */ 8379 xmlNodePtr 8380 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8381 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8382 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL); 8383 if (cur == NULL) { 8384 if (ctxt->context->tmpNsList != NULL) 8385 xmlFree(ctxt->context->tmpNsList); 8386 ctxt->context->tmpNsList = 8387 xmlGetNsList(ctxt->context->doc, ctxt->context->node); 8388 ctxt->context->tmpNsNr = 0; 8389 if (ctxt->context->tmpNsList != NULL) { 8390 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) { 8391 ctxt->context->tmpNsNr++; 8392 } 8393 } 8394 return((xmlNodePtr) xmlXPathXMLNamespace); 8395 } 8396 if (ctxt->context->tmpNsNr > 0) { 8397 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr]; 8398 } else { 8399 if (ctxt->context->tmpNsList != NULL) 8400 xmlFree(ctxt->context->tmpNsList); 8401 ctxt->context->tmpNsList = NULL; 8402 return(NULL); 8403 } 8404 } 8405 8406 /** 8407 * xmlXPathNextAttribute: 8408 * @ctxt: the XPath Parser context 8409 * @cur: the current attribute in the traversal 8410 * 8411 * Traversal function for the "attribute" direction 8412 * TODO: support DTD inherited default attributes 8413 * 8414 * Returns the next element following that axis 8415 */ 8416 xmlNodePtr 8417 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8418 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8419 if (ctxt->context->node == NULL) 8420 return(NULL); 8421 if (ctxt->context->node->type != XML_ELEMENT_NODE) 8422 return(NULL); 8423 if (cur == NULL) { 8424 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc) 8425 return(NULL); 8426 return((xmlNodePtr)ctxt->context->node->properties); 8427 } 8428 return((xmlNodePtr)cur->next); 8429 } 8430 8431 /************************************************************************ 8432 * * 8433 * NodeTest Functions * 8434 * * 8435 ************************************************************************/ 8436 8437 #define IS_FUNCTION 200 8438 8439 8440 /************************************************************************ 8441 * * 8442 * Implicit tree core function library * 8443 * * 8444 ************************************************************************/ 8445 8446 /** 8447 * xmlXPathRoot: 8448 * @ctxt: the XPath Parser context 8449 * 8450 * Initialize the context to the root of the document 8451 */ 8452 void 8453 xmlXPathRoot(xmlXPathParserContextPtr ctxt) { 8454 if ((ctxt == NULL) || (ctxt->context == NULL)) 8455 return; 8456 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8457 (xmlNodePtr) ctxt->context->doc)); 8458 } 8459 8460 /************************************************************************ 8461 * * 8462 * The explicit core function library * 8463 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib * 8464 * * 8465 ************************************************************************/ 8466 8467 8468 /** 8469 * xmlXPathLastFunction: 8470 * @ctxt: the XPath Parser context 8471 * @nargs: the number of arguments 8472 * 8473 * Implement the last() XPath function 8474 * number last() 8475 * The last function returns the number of nodes in the context node list. 8476 */ 8477 void 8478 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8479 CHECK_ARITY(0); 8480 if (ctxt->context->contextSize >= 0) { 8481 valuePush(ctxt, 8482 xmlXPathCacheNewFloat(ctxt->context, 8483 (double) ctxt->context->contextSize)); 8484 #ifdef DEBUG_EXPR 8485 xmlGenericError(xmlGenericErrorContext, 8486 "last() : %d\n", ctxt->context->contextSize); 8487 #endif 8488 } else { 8489 XP_ERROR(XPATH_INVALID_CTXT_SIZE); 8490 } 8491 } 8492 8493 /** 8494 * xmlXPathPositionFunction: 8495 * @ctxt: the XPath Parser context 8496 * @nargs: the number of arguments 8497 * 8498 * Implement the position() XPath function 8499 * number position() 8500 * The position function returns the position of the context node in the 8501 * context node list. The first position is 1, and so the last position 8502 * will be equal to last(). 8503 */ 8504 void 8505 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8506 CHECK_ARITY(0); 8507 if (ctxt->context->proximityPosition >= 0) { 8508 valuePush(ctxt, 8509 xmlXPathCacheNewFloat(ctxt->context, 8510 (double) ctxt->context->proximityPosition)); 8511 #ifdef DEBUG_EXPR 8512 xmlGenericError(xmlGenericErrorContext, "position() : %d\n", 8513 ctxt->context->proximityPosition); 8514 #endif 8515 } else { 8516 XP_ERROR(XPATH_INVALID_CTXT_POSITION); 8517 } 8518 } 8519 8520 /** 8521 * xmlXPathCountFunction: 8522 * @ctxt: the XPath Parser context 8523 * @nargs: the number of arguments 8524 * 8525 * Implement the count() XPath function 8526 * number count(node-set) 8527 */ 8528 void 8529 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8530 xmlXPathObjectPtr cur; 8531 8532 CHECK_ARITY(1); 8533 if ((ctxt->value == NULL) || 8534 ((ctxt->value->type != XPATH_NODESET) && 8535 (ctxt->value->type != XPATH_XSLT_TREE))) 8536 XP_ERROR(XPATH_INVALID_TYPE); 8537 cur = valuePop(ctxt); 8538 8539 if ((cur == NULL) || (cur->nodesetval == NULL)) 8540 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0)); 8541 else 8542 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 8543 (double) cur->nodesetval->nodeNr)); 8544 xmlXPathReleaseObject(ctxt->context, cur); 8545 } 8546 8547 /** 8548 * xmlXPathGetElementsByIds: 8549 * @doc: the document 8550 * @ids: a whitespace separated list of IDs 8551 * 8552 * Selects elements by their unique ID. 8553 * 8554 * Returns a node-set of selected elements. 8555 */ 8556 static xmlNodeSetPtr 8557 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) { 8558 xmlNodeSetPtr ret; 8559 const xmlChar *cur = ids; 8560 xmlChar *ID; 8561 xmlAttrPtr attr; 8562 xmlNodePtr elem = NULL; 8563 8564 if (ids == NULL) return(NULL); 8565 8566 ret = xmlXPathNodeSetCreate(NULL); 8567 if (ret == NULL) 8568 return(ret); 8569 8570 while (IS_BLANK_CH(*cur)) cur++; 8571 while (*cur != 0) { 8572 while ((!IS_BLANK_CH(*cur)) && (*cur != 0)) 8573 cur++; 8574 8575 ID = xmlStrndup(ids, cur - ids); 8576 if (ID != NULL) { 8577 /* 8578 * We used to check the fact that the value passed 8579 * was an NCName, but this generated much troubles for 8580 * me and Aleksey Sanin, people blatantly violated that 8581 * constraint, like Visa3D spec. 8582 * if (xmlValidateNCName(ID, 1) == 0) 8583 */ 8584 attr = xmlGetID(doc, ID); 8585 if (attr != NULL) { 8586 if (attr->type == XML_ATTRIBUTE_NODE) 8587 elem = attr->parent; 8588 else if (attr->type == XML_ELEMENT_NODE) 8589 elem = (xmlNodePtr) attr; 8590 else 8591 elem = NULL; 8592 /* TODO: Check memory error. */ 8593 if (elem != NULL) 8594 xmlXPathNodeSetAdd(ret, elem); 8595 } 8596 xmlFree(ID); 8597 } 8598 8599 while (IS_BLANK_CH(*cur)) cur++; 8600 ids = cur; 8601 } 8602 return(ret); 8603 } 8604 8605 /** 8606 * xmlXPathIdFunction: 8607 * @ctxt: the XPath Parser context 8608 * @nargs: the number of arguments 8609 * 8610 * Implement the id() XPath function 8611 * node-set id(object) 8612 * The id function selects elements by their unique ID 8613 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set, 8614 * then the result is the union of the result of applying id to the 8615 * string value of each of the nodes in the argument node-set. When the 8616 * argument to id is of any other type, the argument is converted to a 8617 * string as if by a call to the string function; the string is split 8618 * into a whitespace-separated list of tokens (whitespace is any sequence 8619 * of characters matching the production S); the result is a node-set 8620 * containing the elements in the same document as the context node that 8621 * have a unique ID equal to any of the tokens in the list. 8622 */ 8623 void 8624 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8625 xmlChar *tokens; 8626 xmlNodeSetPtr ret; 8627 xmlXPathObjectPtr obj; 8628 8629 CHECK_ARITY(1); 8630 obj = valuePop(ctxt); 8631 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 8632 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) { 8633 xmlNodeSetPtr ns; 8634 int i; 8635 8636 /* TODO: Check memory error. */ 8637 ret = xmlXPathNodeSetCreate(NULL); 8638 8639 if (obj->nodesetval != NULL) { 8640 for (i = 0; i < obj->nodesetval->nodeNr; i++) { 8641 tokens = 8642 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]); 8643 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens); 8644 /* TODO: Check memory error. */ 8645 ret = xmlXPathNodeSetMerge(ret, ns); 8646 xmlXPathFreeNodeSet(ns); 8647 if (tokens != NULL) 8648 xmlFree(tokens); 8649 } 8650 } 8651 xmlXPathReleaseObject(ctxt->context, obj); 8652 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret)); 8653 return; 8654 } 8655 obj = xmlXPathCacheConvertString(ctxt->context, obj); 8656 if (obj == NULL) return; 8657 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval); 8658 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret)); 8659 xmlXPathReleaseObject(ctxt->context, obj); 8660 return; 8661 } 8662 8663 /** 8664 * xmlXPathLocalNameFunction: 8665 * @ctxt: the XPath Parser context 8666 * @nargs: the number of arguments 8667 * 8668 * Implement the local-name() XPath function 8669 * string local-name(node-set?) 8670 * The local-name function returns a string containing the local part 8671 * of the name of the node in the argument node-set that is first in 8672 * document order. If the node-set is empty or the first node has no 8673 * name, an empty string is returned. If the argument is omitted it 8674 * defaults to the context node. 8675 */ 8676 void 8677 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8678 xmlXPathObjectPtr cur; 8679 8680 if (ctxt == NULL) return; 8681 8682 if (nargs == 0) { 8683 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8684 ctxt->context->node)); 8685 nargs = 1; 8686 } 8687 8688 CHECK_ARITY(1); 8689 if ((ctxt->value == NULL) || 8690 ((ctxt->value->type != XPATH_NODESET) && 8691 (ctxt->value->type != XPATH_XSLT_TREE))) 8692 XP_ERROR(XPATH_INVALID_TYPE); 8693 cur = valuePop(ctxt); 8694 8695 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 8696 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8697 } else { 8698 int i = 0; /* Should be first in document order !!!!! */ 8699 switch (cur->nodesetval->nodeTab[i]->type) { 8700 case XML_ELEMENT_NODE: 8701 case XML_ATTRIBUTE_NODE: 8702 case XML_PI_NODE: 8703 if (cur->nodesetval->nodeTab[i]->name[0] == ' ') 8704 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8705 else 8706 valuePush(ctxt, 8707 xmlXPathCacheNewString(ctxt->context, 8708 cur->nodesetval->nodeTab[i]->name)); 8709 break; 8710 case XML_NAMESPACE_DECL: 8711 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 8712 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix)); 8713 break; 8714 default: 8715 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8716 } 8717 } 8718 xmlXPathReleaseObject(ctxt->context, cur); 8719 } 8720 8721 /** 8722 * xmlXPathNamespaceURIFunction: 8723 * @ctxt: the XPath Parser context 8724 * @nargs: the number of arguments 8725 * 8726 * Implement the namespace-uri() XPath function 8727 * string namespace-uri(node-set?) 8728 * The namespace-uri function returns a string containing the 8729 * namespace URI of the expanded name of the node in the argument 8730 * node-set that is first in document order. If the node-set is empty, 8731 * the first node has no name, or the expanded name has no namespace 8732 * URI, an empty string is returned. If the argument is omitted it 8733 * defaults to the context node. 8734 */ 8735 void 8736 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8737 xmlXPathObjectPtr cur; 8738 8739 if (ctxt == NULL) return; 8740 8741 if (nargs == 0) { 8742 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8743 ctxt->context->node)); 8744 nargs = 1; 8745 } 8746 CHECK_ARITY(1); 8747 if ((ctxt->value == NULL) || 8748 ((ctxt->value->type != XPATH_NODESET) && 8749 (ctxt->value->type != XPATH_XSLT_TREE))) 8750 XP_ERROR(XPATH_INVALID_TYPE); 8751 cur = valuePop(ctxt); 8752 8753 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 8754 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8755 } else { 8756 int i = 0; /* Should be first in document order !!!!! */ 8757 switch (cur->nodesetval->nodeTab[i]->type) { 8758 case XML_ELEMENT_NODE: 8759 case XML_ATTRIBUTE_NODE: 8760 if (cur->nodesetval->nodeTab[i]->ns == NULL) 8761 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8762 else 8763 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 8764 cur->nodesetval->nodeTab[i]->ns->href)); 8765 break; 8766 default: 8767 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8768 } 8769 } 8770 xmlXPathReleaseObject(ctxt->context, cur); 8771 } 8772 8773 /** 8774 * xmlXPathNameFunction: 8775 * @ctxt: the XPath Parser context 8776 * @nargs: the number of arguments 8777 * 8778 * Implement the name() XPath function 8779 * string name(node-set?) 8780 * The name function returns a string containing a QName representing 8781 * the name of the node in the argument node-set that is first in document 8782 * order. The QName must represent the name with respect to the namespace 8783 * declarations in effect on the node whose name is being represented. 8784 * Typically, this will be the form in which the name occurred in the XML 8785 * source. This need not be the case if there are namespace declarations 8786 * in effect on the node that associate multiple prefixes with the same 8787 * namespace. However, an implementation may include information about 8788 * the original prefix in its representation of nodes; in this case, an 8789 * implementation can ensure that the returned string is always the same 8790 * as the QName used in the XML source. If the argument it omitted it 8791 * defaults to the context node. 8792 * Libxml keep the original prefix so the "real qualified name" used is 8793 * returned. 8794 */ 8795 static void 8796 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) 8797 { 8798 xmlXPathObjectPtr cur; 8799 8800 if (nargs == 0) { 8801 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8802 ctxt->context->node)); 8803 nargs = 1; 8804 } 8805 8806 CHECK_ARITY(1); 8807 if ((ctxt->value == NULL) || 8808 ((ctxt->value->type != XPATH_NODESET) && 8809 (ctxt->value->type != XPATH_XSLT_TREE))) 8810 XP_ERROR(XPATH_INVALID_TYPE); 8811 cur = valuePop(ctxt); 8812 8813 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 8814 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8815 } else { 8816 int i = 0; /* Should be first in document order !!!!! */ 8817 8818 switch (cur->nodesetval->nodeTab[i]->type) { 8819 case XML_ELEMENT_NODE: 8820 case XML_ATTRIBUTE_NODE: 8821 if (cur->nodesetval->nodeTab[i]->name[0] == ' ') 8822 valuePush(ctxt, 8823 xmlXPathCacheNewCString(ctxt->context, "")); 8824 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) || 8825 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) { 8826 valuePush(ctxt, 8827 xmlXPathCacheNewString(ctxt->context, 8828 cur->nodesetval->nodeTab[i]->name)); 8829 } else { 8830 xmlChar *fullname; 8831 8832 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name, 8833 cur->nodesetval->nodeTab[i]->ns->prefix, 8834 NULL, 0); 8835 if (fullname == cur->nodesetval->nodeTab[i]->name) 8836 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name); 8837 if (fullname == NULL) { 8838 XP_ERROR(XPATH_MEMORY_ERROR); 8839 } 8840 valuePush(ctxt, xmlXPathCacheWrapString( 8841 ctxt->context, fullname)); 8842 } 8843 break; 8844 default: 8845 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8846 cur->nodesetval->nodeTab[i])); 8847 xmlXPathLocalNameFunction(ctxt, 1); 8848 } 8849 } 8850 xmlXPathReleaseObject(ctxt->context, cur); 8851 } 8852 8853 8854 /** 8855 * xmlXPathStringFunction: 8856 * @ctxt: the XPath Parser context 8857 * @nargs: the number of arguments 8858 * 8859 * Implement the string() XPath function 8860 * string string(object?) 8861 * The string function converts an object to a string as follows: 8862 * - A node-set is converted to a string by returning the value of 8863 * the node in the node-set that is first in document order. 8864 * If the node-set is empty, an empty string is returned. 8865 * - A number is converted to a string as follows 8866 * + NaN is converted to the string NaN 8867 * + positive zero is converted to the string 0 8868 * + negative zero is converted to the string 0 8869 * + positive infinity is converted to the string Infinity 8870 * + negative infinity is converted to the string -Infinity 8871 * + if the number is an integer, the number is represented in 8872 * decimal form as a Number with no decimal point and no leading 8873 * zeros, preceded by a minus sign (-) if the number is negative 8874 * + otherwise, the number is represented in decimal form as a 8875 * Number including a decimal point with at least one digit 8876 * before the decimal point and at least one digit after the 8877 * decimal point, preceded by a minus sign (-) if the number 8878 * is negative; there must be no leading zeros before the decimal 8879 * point apart possibly from the one required digit immediately 8880 * before the decimal point; beyond the one required digit 8881 * after the decimal point there must be as many, but only as 8882 * many, more digits as are needed to uniquely distinguish the 8883 * number from all other IEEE 754 numeric values. 8884 * - The boolean false value is converted to the string false. 8885 * The boolean true value is converted to the string true. 8886 * 8887 * If the argument is omitted, it defaults to a node-set with the 8888 * context node as its only member. 8889 */ 8890 void 8891 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8892 xmlXPathObjectPtr cur; 8893 8894 if (ctxt == NULL) return; 8895 if (nargs == 0) { 8896 valuePush(ctxt, 8897 xmlXPathCacheWrapString(ctxt->context, 8898 xmlXPathCastNodeToString(ctxt->context->node))); 8899 return; 8900 } 8901 8902 CHECK_ARITY(1); 8903 cur = valuePop(ctxt); 8904 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 8905 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur)); 8906 } 8907 8908 /** 8909 * xmlXPathStringLengthFunction: 8910 * @ctxt: the XPath Parser context 8911 * @nargs: the number of arguments 8912 * 8913 * Implement the string-length() XPath function 8914 * number string-length(string?) 8915 * The string-length returns the number of characters in the string 8916 * (see [3.6 Strings]). If the argument is omitted, it defaults to 8917 * the context node converted to a string, in other words the value 8918 * of the context node. 8919 */ 8920 void 8921 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8922 xmlXPathObjectPtr cur; 8923 8924 if (nargs == 0) { 8925 if ((ctxt == NULL) || (ctxt->context == NULL)) 8926 return; 8927 if (ctxt->context->node == NULL) { 8928 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0)); 8929 } else { 8930 xmlChar *content; 8931 8932 content = xmlXPathCastNodeToString(ctxt->context->node); 8933 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 8934 xmlUTF8Strlen(content))); 8935 xmlFree(content); 8936 } 8937 return; 8938 } 8939 CHECK_ARITY(1); 8940 CAST_TO_STRING; 8941 CHECK_TYPE(XPATH_STRING); 8942 cur = valuePop(ctxt); 8943 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 8944 xmlUTF8Strlen(cur->stringval))); 8945 xmlXPathReleaseObject(ctxt->context, cur); 8946 } 8947 8948 /** 8949 * xmlXPathConcatFunction: 8950 * @ctxt: the XPath Parser context 8951 * @nargs: the number of arguments 8952 * 8953 * Implement the concat() XPath function 8954 * string concat(string, string, string*) 8955 * The concat function returns the concatenation of its arguments. 8956 */ 8957 void 8958 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8959 xmlXPathObjectPtr cur, newobj; 8960 xmlChar *tmp; 8961 8962 if (ctxt == NULL) return; 8963 if (nargs < 2) { 8964 CHECK_ARITY(2); 8965 } 8966 8967 CAST_TO_STRING; 8968 cur = valuePop(ctxt); 8969 if ((cur == NULL) || (cur->type != XPATH_STRING)) { 8970 xmlXPathReleaseObject(ctxt->context, cur); 8971 return; 8972 } 8973 nargs--; 8974 8975 while (nargs > 0) { 8976 CAST_TO_STRING; 8977 newobj = valuePop(ctxt); 8978 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) { 8979 xmlXPathReleaseObject(ctxt->context, newobj); 8980 xmlXPathReleaseObject(ctxt->context, cur); 8981 XP_ERROR(XPATH_INVALID_TYPE); 8982 } 8983 tmp = xmlStrcat(newobj->stringval, cur->stringval); 8984 newobj->stringval = cur->stringval; 8985 cur->stringval = tmp; 8986 xmlXPathReleaseObject(ctxt->context, newobj); 8987 nargs--; 8988 } 8989 valuePush(ctxt, cur); 8990 } 8991 8992 /** 8993 * xmlXPathContainsFunction: 8994 * @ctxt: the XPath Parser context 8995 * @nargs: the number of arguments 8996 * 8997 * Implement the contains() XPath function 8998 * boolean contains(string, string) 8999 * The contains function returns true if the first argument string 9000 * contains the second argument string, and otherwise returns false. 9001 */ 9002 void 9003 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9004 xmlXPathObjectPtr hay, needle; 9005 9006 CHECK_ARITY(2); 9007 CAST_TO_STRING; 9008 CHECK_TYPE(XPATH_STRING); 9009 needle = valuePop(ctxt); 9010 CAST_TO_STRING; 9011 hay = valuePop(ctxt); 9012 9013 if ((hay == NULL) || (hay->type != XPATH_STRING)) { 9014 xmlXPathReleaseObject(ctxt->context, hay); 9015 xmlXPathReleaseObject(ctxt->context, needle); 9016 XP_ERROR(XPATH_INVALID_TYPE); 9017 } 9018 if (xmlStrstr(hay->stringval, needle->stringval)) 9019 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); 9020 else 9021 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); 9022 xmlXPathReleaseObject(ctxt->context, hay); 9023 xmlXPathReleaseObject(ctxt->context, needle); 9024 } 9025 9026 /** 9027 * xmlXPathStartsWithFunction: 9028 * @ctxt: the XPath Parser context 9029 * @nargs: the number of arguments 9030 * 9031 * Implement the starts-with() XPath function 9032 * boolean starts-with(string, string) 9033 * The starts-with function returns true if the first argument string 9034 * starts with the second argument string, and otherwise returns false. 9035 */ 9036 void 9037 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9038 xmlXPathObjectPtr hay, needle; 9039 int n; 9040 9041 CHECK_ARITY(2); 9042 CAST_TO_STRING; 9043 CHECK_TYPE(XPATH_STRING); 9044 needle = valuePop(ctxt); 9045 CAST_TO_STRING; 9046 hay = valuePop(ctxt); 9047 9048 if ((hay == NULL) || (hay->type != XPATH_STRING)) { 9049 xmlXPathReleaseObject(ctxt->context, hay); 9050 xmlXPathReleaseObject(ctxt->context, needle); 9051 XP_ERROR(XPATH_INVALID_TYPE); 9052 } 9053 n = xmlStrlen(needle->stringval); 9054 if (xmlStrncmp(hay->stringval, needle->stringval, n)) 9055 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); 9056 else 9057 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); 9058 xmlXPathReleaseObject(ctxt->context, hay); 9059 xmlXPathReleaseObject(ctxt->context, needle); 9060 } 9061 9062 /** 9063 * xmlXPathSubstringFunction: 9064 * @ctxt: the XPath Parser context 9065 * @nargs: the number of arguments 9066 * 9067 * Implement the substring() XPath function 9068 * string substring(string, number, number?) 9069 * The substring function returns the substring of the first argument 9070 * starting at the position specified in the second argument with 9071 * length specified in the third argument. For example, 9072 * substring("12345",2,3) returns "234". If the third argument is not 9073 * specified, it returns the substring starting at the position specified 9074 * in the second argument and continuing to the end of the string. For 9075 * example, substring("12345",2) returns "2345". More precisely, each 9076 * character in the string (see [3.6 Strings]) is considered to have a 9077 * numeric position: the position of the first character is 1, the position 9078 * of the second character is 2 and so on. The returned substring contains 9079 * those characters for which the position of the character is greater than 9080 * or equal to the second argument and, if the third argument is specified, 9081 * less than the sum of the second and third arguments; the comparisons 9082 * and addition used for the above follow the standard IEEE 754 rules. Thus: 9083 * - substring("12345", 1.5, 2.6) returns "234" 9084 * - substring("12345", 0, 3) returns "12" 9085 * - substring("12345", 0 div 0, 3) returns "" 9086 * - substring("12345", 1, 0 div 0) returns "" 9087 * - substring("12345", -42, 1 div 0) returns "12345" 9088 * - substring("12345", -1 div 0, 1 div 0) returns "" 9089 */ 9090 void 9091 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9092 xmlXPathObjectPtr str, start, len; 9093 double le=0, in; 9094 int i = 1, j = INT_MAX; 9095 9096 if (nargs < 2) { 9097 CHECK_ARITY(2); 9098 } 9099 if (nargs > 3) { 9100 CHECK_ARITY(3); 9101 } 9102 /* 9103 * take care of possible last (position) argument 9104 */ 9105 if (nargs == 3) { 9106 CAST_TO_NUMBER; 9107 CHECK_TYPE(XPATH_NUMBER); 9108 len = valuePop(ctxt); 9109 le = len->floatval; 9110 xmlXPathReleaseObject(ctxt->context, len); 9111 } 9112 9113 CAST_TO_NUMBER; 9114 CHECK_TYPE(XPATH_NUMBER); 9115 start = valuePop(ctxt); 9116 in = start->floatval; 9117 xmlXPathReleaseObject(ctxt->context, start); 9118 CAST_TO_STRING; 9119 CHECK_TYPE(XPATH_STRING); 9120 str = valuePop(ctxt); 9121 9122 if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */ 9123 i = INT_MAX; 9124 } else if (in >= 1.0) { 9125 i = (int)in; 9126 if (in - floor(in) >= 0.5) 9127 i += 1; 9128 } 9129 9130 if (nargs == 3) { 9131 double rin, rle, end; 9132 9133 rin = floor(in); 9134 if (in - rin >= 0.5) 9135 rin += 1.0; 9136 9137 rle = floor(le); 9138 if (le - rle >= 0.5) 9139 rle += 1.0; 9140 9141 end = rin + rle; 9142 if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */ 9143 j = 1; 9144 } else if (end < INT_MAX) { 9145 j = (int)end; 9146 } 9147 } 9148 9149 if (i < j) { 9150 xmlChar *ret = xmlUTF8Strsub(str->stringval, i - 1, j - i); 9151 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret)); 9152 xmlFree(ret); 9153 } else { 9154 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 9155 } 9156 9157 xmlXPathReleaseObject(ctxt->context, str); 9158 } 9159 9160 /** 9161 * xmlXPathSubstringBeforeFunction: 9162 * @ctxt: the XPath Parser context 9163 * @nargs: the number of arguments 9164 * 9165 * Implement the substring-before() XPath function 9166 * string substring-before(string, string) 9167 * The substring-before function returns the substring of the first 9168 * argument string that precedes the first occurrence of the second 9169 * argument string in the first argument string, or the empty string 9170 * if the first argument string does not contain the second argument 9171 * string. For example, substring-before("1999/04/01","/") returns 1999. 9172 */ 9173 void 9174 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9175 xmlXPathObjectPtr str; 9176 xmlXPathObjectPtr find; 9177 xmlBufPtr target; 9178 const xmlChar *point; 9179 int offset; 9180 9181 CHECK_ARITY(2); 9182 CAST_TO_STRING; 9183 find = valuePop(ctxt); 9184 CAST_TO_STRING; 9185 str = valuePop(ctxt); 9186 9187 target = xmlBufCreate(); 9188 if (target) { 9189 point = xmlStrstr(str->stringval, find->stringval); 9190 if (point) { 9191 offset = (int)(point - str->stringval); 9192 xmlBufAdd(target, str->stringval, offset); 9193 } 9194 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9195 xmlBufContent(target))); 9196 xmlBufFree(target); 9197 } 9198 xmlXPathReleaseObject(ctxt->context, str); 9199 xmlXPathReleaseObject(ctxt->context, find); 9200 } 9201 9202 /** 9203 * xmlXPathSubstringAfterFunction: 9204 * @ctxt: the XPath Parser context 9205 * @nargs: the number of arguments 9206 * 9207 * Implement the substring-after() XPath function 9208 * string substring-after(string, string) 9209 * The substring-after function returns the substring of the first 9210 * argument string that follows the first occurrence of the second 9211 * argument string in the first argument string, or the empty stringi 9212 * if the first argument string does not contain the second argument 9213 * string. For example, substring-after("1999/04/01","/") returns 04/01, 9214 * and substring-after("1999/04/01","19") returns 99/04/01. 9215 */ 9216 void 9217 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9218 xmlXPathObjectPtr str; 9219 xmlXPathObjectPtr find; 9220 xmlBufPtr target; 9221 const xmlChar *point; 9222 int offset; 9223 9224 CHECK_ARITY(2); 9225 CAST_TO_STRING; 9226 find = valuePop(ctxt); 9227 CAST_TO_STRING; 9228 str = valuePop(ctxt); 9229 9230 target = xmlBufCreate(); 9231 if (target) { 9232 point = xmlStrstr(str->stringval, find->stringval); 9233 if (point) { 9234 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval); 9235 xmlBufAdd(target, &str->stringval[offset], 9236 xmlStrlen(str->stringval) - offset); 9237 } 9238 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9239 xmlBufContent(target))); 9240 xmlBufFree(target); 9241 } 9242 xmlXPathReleaseObject(ctxt->context, str); 9243 xmlXPathReleaseObject(ctxt->context, find); 9244 } 9245 9246 /** 9247 * xmlXPathNormalizeFunction: 9248 * @ctxt: the XPath Parser context 9249 * @nargs: the number of arguments 9250 * 9251 * Implement the normalize-space() XPath function 9252 * string normalize-space(string?) 9253 * The normalize-space function returns the argument string with white 9254 * space normalized by stripping leading and trailing whitespace 9255 * and replacing sequences of whitespace characters by a single 9256 * space. Whitespace characters are the same allowed by the S production 9257 * in XML. If the argument is omitted, it defaults to the context 9258 * node converted to a string, in other words the value of the context node. 9259 */ 9260 void 9261 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9262 xmlXPathObjectPtr obj = NULL; 9263 xmlChar *source = NULL; 9264 xmlBufPtr target; 9265 xmlChar blank; 9266 9267 if (ctxt == NULL) return; 9268 if (nargs == 0) { 9269 /* Use current context node */ 9270 valuePush(ctxt, 9271 xmlXPathCacheWrapString(ctxt->context, 9272 xmlXPathCastNodeToString(ctxt->context->node))); 9273 nargs = 1; 9274 } 9275 9276 CHECK_ARITY(1); 9277 CAST_TO_STRING; 9278 CHECK_TYPE(XPATH_STRING); 9279 obj = valuePop(ctxt); 9280 source = obj->stringval; 9281 9282 target = xmlBufCreate(); 9283 if (target && source) { 9284 9285 /* Skip leading whitespaces */ 9286 while (IS_BLANK_CH(*source)) 9287 source++; 9288 9289 /* Collapse intermediate whitespaces, and skip trailing whitespaces */ 9290 blank = 0; 9291 while (*source) { 9292 if (IS_BLANK_CH(*source)) { 9293 blank = 0x20; 9294 } else { 9295 if (blank) { 9296 xmlBufAdd(target, &blank, 1); 9297 blank = 0; 9298 } 9299 xmlBufAdd(target, source, 1); 9300 } 9301 source++; 9302 } 9303 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9304 xmlBufContent(target))); 9305 xmlBufFree(target); 9306 } 9307 xmlXPathReleaseObject(ctxt->context, obj); 9308 } 9309 9310 /** 9311 * xmlXPathTranslateFunction: 9312 * @ctxt: the XPath Parser context 9313 * @nargs: the number of arguments 9314 * 9315 * Implement the translate() XPath function 9316 * string translate(string, string, string) 9317 * The translate function returns the first argument string with 9318 * occurrences of characters in the second argument string replaced 9319 * by the character at the corresponding position in the third argument 9320 * string. For example, translate("bar","abc","ABC") returns the string 9321 * BAr. If there is a character in the second argument string with no 9322 * character at a corresponding position in the third argument string 9323 * (because the second argument string is longer than the third argument 9324 * string), then occurrences of that character in the first argument 9325 * string are removed. For example, translate("--aaa--","abc-","ABC") 9326 * returns "AAA". If a character occurs more than once in second 9327 * argument string, then the first occurrence determines the replacement 9328 * character. If the third argument string is longer than the second 9329 * argument string, then excess characters are ignored. 9330 */ 9331 void 9332 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9333 xmlXPathObjectPtr str; 9334 xmlXPathObjectPtr from; 9335 xmlXPathObjectPtr to; 9336 xmlBufPtr target; 9337 int offset, max; 9338 xmlChar ch; 9339 const xmlChar *point; 9340 xmlChar *cptr; 9341 9342 CHECK_ARITY(3); 9343 9344 CAST_TO_STRING; 9345 to = valuePop(ctxt); 9346 CAST_TO_STRING; 9347 from = valuePop(ctxt); 9348 CAST_TO_STRING; 9349 str = valuePop(ctxt); 9350 9351 target = xmlBufCreate(); 9352 if (target) { 9353 max = xmlUTF8Strlen(to->stringval); 9354 for (cptr = str->stringval; (ch=*cptr); ) { 9355 offset = xmlUTF8Strloc(from->stringval, cptr); 9356 if (offset >= 0) { 9357 if (offset < max) { 9358 point = xmlUTF8Strpos(to->stringval, offset); 9359 if (point) 9360 xmlBufAdd(target, point, xmlUTF8Strsize(point, 1)); 9361 } 9362 } else 9363 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1)); 9364 9365 /* Step to next character in input */ 9366 cptr++; 9367 if ( ch & 0x80 ) { 9368 /* if not simple ascii, verify proper format */ 9369 if ( (ch & 0xc0) != 0xc0 ) { 9370 xmlGenericError(xmlGenericErrorContext, 9371 "xmlXPathTranslateFunction: Invalid UTF8 string\n"); 9372 /* not asserting an XPath error is probably better */ 9373 break; 9374 } 9375 /* then skip over remaining bytes for this char */ 9376 while ( (ch <<= 1) & 0x80 ) 9377 if ( (*cptr++ & 0xc0) != 0x80 ) { 9378 xmlGenericError(xmlGenericErrorContext, 9379 "xmlXPathTranslateFunction: Invalid UTF8 string\n"); 9380 /* not asserting an XPath error is probably better */ 9381 break; 9382 } 9383 if (ch & 0x80) /* must have had error encountered */ 9384 break; 9385 } 9386 } 9387 } 9388 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9389 xmlBufContent(target))); 9390 xmlBufFree(target); 9391 xmlXPathReleaseObject(ctxt->context, str); 9392 xmlXPathReleaseObject(ctxt->context, from); 9393 xmlXPathReleaseObject(ctxt->context, to); 9394 } 9395 9396 /** 9397 * xmlXPathBooleanFunction: 9398 * @ctxt: the XPath Parser context 9399 * @nargs: the number of arguments 9400 * 9401 * Implement the boolean() XPath function 9402 * boolean boolean(object) 9403 * The boolean function converts its argument to a boolean as follows: 9404 * - a number is true if and only if it is neither positive or 9405 * negative zero nor NaN 9406 * - a node-set is true if and only if it is non-empty 9407 * - a string is true if and only if its length is non-zero 9408 */ 9409 void 9410 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9411 xmlXPathObjectPtr cur; 9412 9413 CHECK_ARITY(1); 9414 cur = valuePop(ctxt); 9415 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 9416 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur); 9417 valuePush(ctxt, cur); 9418 } 9419 9420 /** 9421 * xmlXPathNotFunction: 9422 * @ctxt: the XPath Parser context 9423 * @nargs: the number of arguments 9424 * 9425 * Implement the not() XPath function 9426 * boolean not(boolean) 9427 * The not function returns true if its argument is false, 9428 * and false otherwise. 9429 */ 9430 void 9431 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9432 CHECK_ARITY(1); 9433 CAST_TO_BOOLEAN; 9434 CHECK_TYPE(XPATH_BOOLEAN); 9435 ctxt->value->boolval = ! ctxt->value->boolval; 9436 } 9437 9438 /** 9439 * xmlXPathTrueFunction: 9440 * @ctxt: the XPath Parser context 9441 * @nargs: the number of arguments 9442 * 9443 * Implement the true() XPath function 9444 * boolean true() 9445 */ 9446 void 9447 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9448 CHECK_ARITY(0); 9449 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); 9450 } 9451 9452 /** 9453 * xmlXPathFalseFunction: 9454 * @ctxt: the XPath Parser context 9455 * @nargs: the number of arguments 9456 * 9457 * Implement the false() XPath function 9458 * boolean false() 9459 */ 9460 void 9461 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9462 CHECK_ARITY(0); 9463 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); 9464 } 9465 9466 /** 9467 * xmlXPathLangFunction: 9468 * @ctxt: the XPath Parser context 9469 * @nargs: the number of arguments 9470 * 9471 * Implement the lang() XPath function 9472 * boolean lang(string) 9473 * The lang function returns true or false depending on whether the 9474 * language of the context node as specified by xml:lang attributes 9475 * is the same as or is a sublanguage of the language specified by 9476 * the argument string. The language of the context node is determined 9477 * by the value of the xml:lang attribute on the context node, or, if 9478 * the context node has no xml:lang attribute, by the value of the 9479 * xml:lang attribute on the nearest ancestor of the context node that 9480 * has an xml:lang attribute. If there is no such attribute, then lang 9481 * returns false. If there is such an attribute, then lang returns 9482 * true if the attribute value is equal to the argument ignoring case, 9483 * or if there is some suffix starting with - such that the attribute 9484 * value is equal to the argument ignoring that suffix of the attribute 9485 * value and ignoring case. 9486 */ 9487 void 9488 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9489 xmlXPathObjectPtr val = NULL; 9490 const xmlChar *theLang = NULL; 9491 const xmlChar *lang; 9492 int ret = 0; 9493 int i; 9494 9495 CHECK_ARITY(1); 9496 CAST_TO_STRING; 9497 CHECK_TYPE(XPATH_STRING); 9498 val = valuePop(ctxt); 9499 lang = val->stringval; 9500 theLang = xmlNodeGetLang(ctxt->context->node); 9501 if ((theLang != NULL) && (lang != NULL)) { 9502 for (i = 0;lang[i] != 0;i++) 9503 if (toupper(lang[i]) != toupper(theLang[i])) 9504 goto not_equal; 9505 if ((theLang[i] == 0) || (theLang[i] == '-')) 9506 ret = 1; 9507 } 9508 not_equal: 9509 if (theLang != NULL) 9510 xmlFree((void *)theLang); 9511 9512 xmlXPathReleaseObject(ctxt->context, val); 9513 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret)); 9514 } 9515 9516 /** 9517 * xmlXPathNumberFunction: 9518 * @ctxt: the XPath Parser context 9519 * @nargs: the number of arguments 9520 * 9521 * Implement the number() XPath function 9522 * number number(object?) 9523 */ 9524 void 9525 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9526 xmlXPathObjectPtr cur; 9527 double res; 9528 9529 if (ctxt == NULL) return; 9530 if (nargs == 0) { 9531 if (ctxt->context->node == NULL) { 9532 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0)); 9533 } else { 9534 xmlChar* content = xmlNodeGetContent(ctxt->context->node); 9535 9536 res = xmlXPathStringEvalNumber(content); 9537 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res)); 9538 xmlFree(content); 9539 } 9540 return; 9541 } 9542 9543 CHECK_ARITY(1); 9544 cur = valuePop(ctxt); 9545 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur)); 9546 } 9547 9548 /** 9549 * xmlXPathSumFunction: 9550 * @ctxt: the XPath Parser context 9551 * @nargs: the number of arguments 9552 * 9553 * Implement the sum() XPath function 9554 * number sum(node-set) 9555 * The sum function returns the sum of the values of the nodes in 9556 * the argument node-set. 9557 */ 9558 void 9559 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9560 xmlXPathObjectPtr cur; 9561 int i; 9562 double res = 0.0; 9563 9564 CHECK_ARITY(1); 9565 if ((ctxt->value == NULL) || 9566 ((ctxt->value->type != XPATH_NODESET) && 9567 (ctxt->value->type != XPATH_XSLT_TREE))) 9568 XP_ERROR(XPATH_INVALID_TYPE); 9569 cur = valuePop(ctxt); 9570 9571 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) { 9572 for (i = 0; i < cur->nodesetval->nodeNr; i++) { 9573 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]); 9574 } 9575 } 9576 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res)); 9577 xmlXPathReleaseObject(ctxt->context, cur); 9578 } 9579 9580 /** 9581 * xmlXPathFloorFunction: 9582 * @ctxt: the XPath Parser context 9583 * @nargs: the number of arguments 9584 * 9585 * Implement the floor() XPath function 9586 * number floor(number) 9587 * The floor function returns the largest (closest to positive infinity) 9588 * number that is not greater than the argument and that is an integer. 9589 */ 9590 void 9591 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9592 CHECK_ARITY(1); 9593 CAST_TO_NUMBER; 9594 CHECK_TYPE(XPATH_NUMBER); 9595 9596 ctxt->value->floatval = floor(ctxt->value->floatval); 9597 } 9598 9599 /** 9600 * xmlXPathCeilingFunction: 9601 * @ctxt: the XPath Parser context 9602 * @nargs: the number of arguments 9603 * 9604 * Implement the ceiling() XPath function 9605 * number ceiling(number) 9606 * The ceiling function returns the smallest (closest to negative infinity) 9607 * number that is not less than the argument and that is an integer. 9608 */ 9609 void 9610 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9611 CHECK_ARITY(1); 9612 CAST_TO_NUMBER; 9613 CHECK_TYPE(XPATH_NUMBER); 9614 9615 #ifdef _AIX 9616 /* Work around buggy ceil() function on AIX */ 9617 ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval); 9618 #else 9619 ctxt->value->floatval = ceil(ctxt->value->floatval); 9620 #endif 9621 } 9622 9623 /** 9624 * xmlXPathRoundFunction: 9625 * @ctxt: the XPath Parser context 9626 * @nargs: the number of arguments 9627 * 9628 * Implement the round() XPath function 9629 * number round(number) 9630 * The round function returns the number that is closest to the 9631 * argument and that is an integer. If there are two such numbers, 9632 * then the one that is closest to positive infinity is returned. 9633 */ 9634 void 9635 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9636 double f; 9637 9638 CHECK_ARITY(1); 9639 CAST_TO_NUMBER; 9640 CHECK_TYPE(XPATH_NUMBER); 9641 9642 f = ctxt->value->floatval; 9643 9644 if ((f >= -0.5) && (f < 0.5)) { 9645 /* Handles negative zero. */ 9646 ctxt->value->floatval *= 0.0; 9647 } 9648 else { 9649 double rounded = floor(f); 9650 if (f - rounded >= 0.5) 9651 rounded += 1.0; 9652 ctxt->value->floatval = rounded; 9653 } 9654 } 9655 9656 /************************************************************************ 9657 * * 9658 * The Parser * 9659 * * 9660 ************************************************************************/ 9661 9662 /* 9663 * a few forward declarations since we use a recursive call based 9664 * implementation. 9665 */ 9666 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort); 9667 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter); 9668 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt); 9669 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt); 9670 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, 9671 int qualified); 9672 9673 /** 9674 * xmlXPathCurrentChar: 9675 * @ctxt: the XPath parser context 9676 * @cur: pointer to the beginning of the char 9677 * @len: pointer to the length of the char read 9678 * 9679 * The current char value, if using UTF-8 this may actually span multiple 9680 * bytes in the input buffer. 9681 * 9682 * Returns the current char value and its length 9683 */ 9684 9685 static int 9686 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) { 9687 unsigned char c; 9688 unsigned int val; 9689 const xmlChar *cur; 9690 9691 if (ctxt == NULL) 9692 return(0); 9693 cur = ctxt->cur; 9694 9695 /* 9696 * We are supposed to handle UTF8, check it's valid 9697 * From rfc2044: encoding of the Unicode values on UTF-8: 9698 * 9699 * UCS-4 range (hex.) UTF-8 octet sequence (binary) 9700 * 0000 0000-0000 007F 0xxxxxxx 9701 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx 9702 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx 9703 * 9704 * Check for the 0x110000 limit too 9705 */ 9706 c = *cur; 9707 if (c & 0x80) { 9708 if ((cur[1] & 0xc0) != 0x80) 9709 goto encoding_error; 9710 if ((c & 0xe0) == 0xe0) { 9711 9712 if ((cur[2] & 0xc0) != 0x80) 9713 goto encoding_error; 9714 if ((c & 0xf0) == 0xf0) { 9715 if (((c & 0xf8) != 0xf0) || 9716 ((cur[3] & 0xc0) != 0x80)) 9717 goto encoding_error; 9718 /* 4-byte code */ 9719 *len = 4; 9720 val = (cur[0] & 0x7) << 18; 9721 val |= (cur[1] & 0x3f) << 12; 9722 val |= (cur[2] & 0x3f) << 6; 9723 val |= cur[3] & 0x3f; 9724 } else { 9725 /* 3-byte code */ 9726 *len = 3; 9727 val = (cur[0] & 0xf) << 12; 9728 val |= (cur[1] & 0x3f) << 6; 9729 val |= cur[2] & 0x3f; 9730 } 9731 } else { 9732 /* 2-byte code */ 9733 *len = 2; 9734 val = (cur[0] & 0x1f) << 6; 9735 val |= cur[1] & 0x3f; 9736 } 9737 if (!IS_CHAR(val)) { 9738 XP_ERROR0(XPATH_INVALID_CHAR_ERROR); 9739 } 9740 return(val); 9741 } else { 9742 /* 1-byte code */ 9743 *len = 1; 9744 return((int) *cur); 9745 } 9746 encoding_error: 9747 /* 9748 * If we detect an UTF8 error that probably means that the 9749 * input encoding didn't get properly advertised in the 9750 * declaration header. Report the error and switch the encoding 9751 * to ISO-Latin-1 (if you don't like this policy, just declare the 9752 * encoding !) 9753 */ 9754 *len = 0; 9755 XP_ERROR0(XPATH_ENCODING_ERROR); 9756 } 9757 9758 /** 9759 * xmlXPathParseNCName: 9760 * @ctxt: the XPath Parser context 9761 * 9762 * parse an XML namespace non qualified name. 9763 * 9764 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)* 9765 * 9766 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' | 9767 * CombiningChar | Extender 9768 * 9769 * Returns the namespace name or NULL 9770 */ 9771 9772 xmlChar * 9773 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) { 9774 const xmlChar *in; 9775 xmlChar *ret; 9776 int count = 0; 9777 9778 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL); 9779 /* 9780 * Accelerator for simple ASCII names 9781 */ 9782 in = ctxt->cur; 9783 if (((*in >= 0x61) && (*in <= 0x7A)) || 9784 ((*in >= 0x41) && (*in <= 0x5A)) || 9785 (*in == '_')) { 9786 in++; 9787 while (((*in >= 0x61) && (*in <= 0x7A)) || 9788 ((*in >= 0x41) && (*in <= 0x5A)) || 9789 ((*in >= 0x30) && (*in <= 0x39)) || 9790 (*in == '_') || (*in == '.') || 9791 (*in == '-')) 9792 in++; 9793 if ((*in == ' ') || (*in == '>') || (*in == '/') || 9794 (*in == '[') || (*in == ']') || (*in == ':') || 9795 (*in == '@') || (*in == '*')) { 9796 count = in - ctxt->cur; 9797 if (count == 0) 9798 return(NULL); 9799 ret = xmlStrndup(ctxt->cur, count); 9800 ctxt->cur = in; 9801 return(ret); 9802 } 9803 } 9804 return(xmlXPathParseNameComplex(ctxt, 0)); 9805 } 9806 9807 9808 /** 9809 * xmlXPathParseQName: 9810 * @ctxt: the XPath Parser context 9811 * @prefix: a xmlChar ** 9812 * 9813 * parse an XML qualified name 9814 * 9815 * [NS 5] QName ::= (Prefix ':')? LocalPart 9816 * 9817 * [NS 6] Prefix ::= NCName 9818 * 9819 * [NS 7] LocalPart ::= NCName 9820 * 9821 * Returns the function returns the local part, and prefix is updated 9822 * to get the Prefix if any. 9823 */ 9824 9825 static xmlChar * 9826 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) { 9827 xmlChar *ret = NULL; 9828 9829 *prefix = NULL; 9830 ret = xmlXPathParseNCName(ctxt); 9831 if (ret && CUR == ':') { 9832 *prefix = ret; 9833 NEXT; 9834 ret = xmlXPathParseNCName(ctxt); 9835 } 9836 return(ret); 9837 } 9838 9839 /** 9840 * xmlXPathParseName: 9841 * @ctxt: the XPath Parser context 9842 * 9843 * parse an XML name 9844 * 9845 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | 9846 * CombiningChar | Extender 9847 * 9848 * [5] Name ::= (Letter | '_' | ':') (NameChar)* 9849 * 9850 * Returns the namespace name or NULL 9851 */ 9852 9853 xmlChar * 9854 xmlXPathParseName(xmlXPathParserContextPtr ctxt) { 9855 const xmlChar *in; 9856 xmlChar *ret; 9857 size_t count = 0; 9858 9859 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL); 9860 /* 9861 * Accelerator for simple ASCII names 9862 */ 9863 in = ctxt->cur; 9864 if (((*in >= 0x61) && (*in <= 0x7A)) || 9865 ((*in >= 0x41) && (*in <= 0x5A)) || 9866 (*in == '_') || (*in == ':')) { 9867 in++; 9868 while (((*in >= 0x61) && (*in <= 0x7A)) || 9869 ((*in >= 0x41) && (*in <= 0x5A)) || 9870 ((*in >= 0x30) && (*in <= 0x39)) || 9871 (*in == '_') || (*in == '-') || 9872 (*in == ':') || (*in == '.')) 9873 in++; 9874 if ((*in > 0) && (*in < 0x80)) { 9875 count = in - ctxt->cur; 9876 if (count > XML_MAX_NAME_LENGTH) { 9877 ctxt->cur = in; 9878 XP_ERRORNULL(XPATH_EXPR_ERROR); 9879 } 9880 ret = xmlStrndup(ctxt->cur, count); 9881 ctxt->cur = in; 9882 return(ret); 9883 } 9884 } 9885 return(xmlXPathParseNameComplex(ctxt, 1)); 9886 } 9887 9888 static xmlChar * 9889 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) { 9890 xmlChar buf[XML_MAX_NAMELEN + 5]; 9891 int len = 0, l; 9892 int c; 9893 9894 /* 9895 * Handler for more complex cases 9896 */ 9897 c = CUR_CHAR(l); 9898 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */ 9899 (c == '[') || (c == ']') || (c == '@') || /* accelerators */ 9900 (c == '*') || /* accelerators */ 9901 (!IS_LETTER(c) && (c != '_') && 9902 ((!qualified) || (c != ':')))) { 9903 return(NULL); 9904 } 9905 9906 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */ 9907 ((IS_LETTER(c)) || (IS_DIGIT(c)) || 9908 (c == '.') || (c == '-') || 9909 (c == '_') || ((qualified) && (c == ':')) || 9910 (IS_COMBINING(c)) || 9911 (IS_EXTENDER(c)))) { 9912 COPY_BUF(l,buf,len,c); 9913 NEXTL(l); 9914 c = CUR_CHAR(l); 9915 if (len >= XML_MAX_NAMELEN) { 9916 /* 9917 * Okay someone managed to make a huge name, so he's ready to pay 9918 * for the processing speed. 9919 */ 9920 xmlChar *buffer; 9921 int max = len * 2; 9922 9923 if (len > XML_MAX_NAME_LENGTH) { 9924 XP_ERRORNULL(XPATH_EXPR_ERROR); 9925 } 9926 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar)); 9927 if (buffer == NULL) { 9928 XP_ERRORNULL(XPATH_MEMORY_ERROR); 9929 } 9930 memcpy(buffer, buf, len); 9931 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */ 9932 (c == '.') || (c == '-') || 9933 (c == '_') || ((qualified) && (c == ':')) || 9934 (IS_COMBINING(c)) || 9935 (IS_EXTENDER(c))) { 9936 if (len + 10 > max) { 9937 xmlChar *tmp; 9938 if (max > XML_MAX_NAME_LENGTH) { 9939 xmlFree(buffer); 9940 XP_ERRORNULL(XPATH_EXPR_ERROR); 9941 } 9942 max *= 2; 9943 tmp = (xmlChar *) xmlRealloc(buffer, 9944 max * sizeof(xmlChar)); 9945 if (tmp == NULL) { 9946 xmlFree(buffer); 9947 XP_ERRORNULL(XPATH_MEMORY_ERROR); 9948 } 9949 buffer = tmp; 9950 } 9951 COPY_BUF(l,buffer,len,c); 9952 NEXTL(l); 9953 c = CUR_CHAR(l); 9954 } 9955 buffer[len] = 0; 9956 return(buffer); 9957 } 9958 } 9959 if (len == 0) 9960 return(NULL); 9961 return(xmlStrndup(buf, len)); 9962 } 9963 9964 #define MAX_FRAC 20 9965 9966 /** 9967 * xmlXPathStringEvalNumber: 9968 * @str: A string to scan 9969 * 9970 * [30a] Float ::= Number ('e' Digits?)? 9971 * 9972 * [30] Number ::= Digits ('.' Digits?)? 9973 * | '.' Digits 9974 * [31] Digits ::= [0-9]+ 9975 * 9976 * Compile a Number in the string 9977 * In complement of the Number expression, this function also handles 9978 * negative values : '-' Number. 9979 * 9980 * Returns the double value. 9981 */ 9982 double 9983 xmlXPathStringEvalNumber(const xmlChar *str) { 9984 const xmlChar *cur = str; 9985 double ret; 9986 int ok = 0; 9987 int isneg = 0; 9988 int exponent = 0; 9989 int is_exponent_negative = 0; 9990 #ifdef __GNUC__ 9991 unsigned long tmp = 0; 9992 double temp; 9993 #endif 9994 if (cur == NULL) return(0); 9995 while (IS_BLANK_CH(*cur)) cur++; 9996 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) { 9997 return(NAN); 9998 } 9999 if (*cur == '-') { 10000 isneg = 1; 10001 cur++; 10002 } 10003 10004 #ifdef __GNUC__ 10005 /* 10006 * tmp/temp is a workaround against a gcc compiler bug 10007 * http://veillard.com/gcc.bug 10008 */ 10009 ret = 0; 10010 while ((*cur >= '0') && (*cur <= '9')) { 10011 ret = ret * 10; 10012 tmp = (*cur - '0'); 10013 ok = 1; 10014 cur++; 10015 temp = (double) tmp; 10016 ret = ret + temp; 10017 } 10018 #else 10019 ret = 0; 10020 while ((*cur >= '0') && (*cur <= '9')) { 10021 ret = ret * 10 + (*cur - '0'); 10022 ok = 1; 10023 cur++; 10024 } 10025 #endif 10026 10027 if (*cur == '.') { 10028 int v, frac = 0, max; 10029 double fraction = 0; 10030 10031 cur++; 10032 if (((*cur < '0') || (*cur > '9')) && (!ok)) { 10033 return(NAN); 10034 } 10035 while (*cur == '0') { 10036 frac = frac + 1; 10037 cur++; 10038 } 10039 max = frac + MAX_FRAC; 10040 while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) { 10041 v = (*cur - '0'); 10042 fraction = fraction * 10 + v; 10043 frac = frac + 1; 10044 cur++; 10045 } 10046 fraction /= pow(10.0, frac); 10047 ret = ret + fraction; 10048 while ((*cur >= '0') && (*cur <= '9')) 10049 cur++; 10050 } 10051 if ((*cur == 'e') || (*cur == 'E')) { 10052 cur++; 10053 if (*cur == '-') { 10054 is_exponent_negative = 1; 10055 cur++; 10056 } else if (*cur == '+') { 10057 cur++; 10058 } 10059 while ((*cur >= '0') && (*cur <= '9')) { 10060 if (exponent < 1000000) 10061 exponent = exponent * 10 + (*cur - '0'); 10062 cur++; 10063 } 10064 } 10065 while (IS_BLANK_CH(*cur)) cur++; 10066 if (*cur != 0) return(NAN); 10067 if (isneg) ret = -ret; 10068 if (is_exponent_negative) exponent = -exponent; 10069 ret *= pow(10.0, (double)exponent); 10070 return(ret); 10071 } 10072 10073 /** 10074 * xmlXPathCompNumber: 10075 * @ctxt: the XPath Parser context 10076 * 10077 * [30] Number ::= Digits ('.' Digits?)? 10078 * | '.' Digits 10079 * [31] Digits ::= [0-9]+ 10080 * 10081 * Compile a Number, then push it on the stack 10082 * 10083 */ 10084 static void 10085 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt) 10086 { 10087 double ret = 0.0; 10088 int ok = 0; 10089 int exponent = 0; 10090 int is_exponent_negative = 0; 10091 #ifdef __GNUC__ 10092 unsigned long tmp = 0; 10093 double temp; 10094 #endif 10095 10096 CHECK_ERROR; 10097 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) { 10098 XP_ERROR(XPATH_NUMBER_ERROR); 10099 } 10100 #ifdef __GNUC__ 10101 /* 10102 * tmp/temp is a workaround against a gcc compiler bug 10103 * http://veillard.com/gcc.bug 10104 */ 10105 ret = 0; 10106 while ((CUR >= '0') && (CUR <= '9')) { 10107 ret = ret * 10; 10108 tmp = (CUR - '0'); 10109 ok = 1; 10110 NEXT; 10111 temp = (double) tmp; 10112 ret = ret + temp; 10113 } 10114 #else 10115 ret = 0; 10116 while ((CUR >= '0') && (CUR <= '9')) { 10117 ret = ret * 10 + (CUR - '0'); 10118 ok = 1; 10119 NEXT; 10120 } 10121 #endif 10122 if (CUR == '.') { 10123 int v, frac = 0, max; 10124 double fraction = 0; 10125 10126 NEXT; 10127 if (((CUR < '0') || (CUR > '9')) && (!ok)) { 10128 XP_ERROR(XPATH_NUMBER_ERROR); 10129 } 10130 while (CUR == '0') { 10131 frac = frac + 1; 10132 NEXT; 10133 } 10134 max = frac + MAX_FRAC; 10135 while ((CUR >= '0') && (CUR <= '9') && (frac < max)) { 10136 v = (CUR - '0'); 10137 fraction = fraction * 10 + v; 10138 frac = frac + 1; 10139 NEXT; 10140 } 10141 fraction /= pow(10.0, frac); 10142 ret = ret + fraction; 10143 while ((CUR >= '0') && (CUR <= '9')) 10144 NEXT; 10145 } 10146 if ((CUR == 'e') || (CUR == 'E')) { 10147 NEXT; 10148 if (CUR == '-') { 10149 is_exponent_negative = 1; 10150 NEXT; 10151 } else if (CUR == '+') { 10152 NEXT; 10153 } 10154 while ((CUR >= '0') && (CUR <= '9')) { 10155 if (exponent < 1000000) 10156 exponent = exponent * 10 + (CUR - '0'); 10157 NEXT; 10158 } 10159 if (is_exponent_negative) 10160 exponent = -exponent; 10161 ret *= pow(10.0, (double) exponent); 10162 } 10163 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, 10164 xmlXPathCacheNewFloat(ctxt->context, ret), NULL); 10165 } 10166 10167 /** 10168 * xmlXPathParseLiteral: 10169 * @ctxt: the XPath Parser context 10170 * 10171 * Parse a Literal 10172 * 10173 * [29] Literal ::= '"' [^"]* '"' 10174 * | "'" [^']* "'" 10175 * 10176 * Returns the value found or NULL in case of error 10177 */ 10178 static xmlChar * 10179 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) { 10180 const xmlChar *q; 10181 xmlChar *ret = NULL; 10182 10183 if (CUR == '"') { 10184 NEXT; 10185 q = CUR_PTR; 10186 while ((IS_CHAR_CH(CUR)) && (CUR != '"')) 10187 NEXT; 10188 if (!IS_CHAR_CH(CUR)) { 10189 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR); 10190 } else { 10191 ret = xmlStrndup(q, CUR_PTR - q); 10192 NEXT; 10193 } 10194 } else if (CUR == '\'') { 10195 NEXT; 10196 q = CUR_PTR; 10197 while ((IS_CHAR_CH(CUR)) && (CUR != '\'')) 10198 NEXT; 10199 if (!IS_CHAR_CH(CUR)) { 10200 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR); 10201 } else { 10202 ret = xmlStrndup(q, CUR_PTR - q); 10203 NEXT; 10204 } 10205 } else { 10206 XP_ERRORNULL(XPATH_START_LITERAL_ERROR); 10207 } 10208 return(ret); 10209 } 10210 10211 /** 10212 * xmlXPathCompLiteral: 10213 * @ctxt: the XPath Parser context 10214 * 10215 * Parse a Literal and push it on the stack. 10216 * 10217 * [29] Literal ::= '"' [^"]* '"' 10218 * | "'" [^']* "'" 10219 * 10220 * TODO: xmlXPathCompLiteral memory allocation could be improved. 10221 */ 10222 static void 10223 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) { 10224 const xmlChar *q; 10225 xmlChar *ret = NULL; 10226 10227 if (CUR == '"') { 10228 NEXT; 10229 q = CUR_PTR; 10230 while ((IS_CHAR_CH(CUR)) && (CUR != '"')) 10231 NEXT; 10232 if (!IS_CHAR_CH(CUR)) { 10233 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR); 10234 } else { 10235 ret = xmlStrndup(q, CUR_PTR - q); 10236 NEXT; 10237 } 10238 } else if (CUR == '\'') { 10239 NEXT; 10240 q = CUR_PTR; 10241 while ((IS_CHAR_CH(CUR)) && (CUR != '\'')) 10242 NEXT; 10243 if (!IS_CHAR_CH(CUR)) { 10244 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR); 10245 } else { 10246 ret = xmlStrndup(q, CUR_PTR - q); 10247 NEXT; 10248 } 10249 } else { 10250 XP_ERROR(XPATH_START_LITERAL_ERROR); 10251 } 10252 if (ret == NULL) return; 10253 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, 10254 xmlXPathCacheNewString(ctxt->context, ret), NULL); 10255 xmlFree(ret); 10256 } 10257 10258 /** 10259 * xmlXPathCompVariableReference: 10260 * @ctxt: the XPath Parser context 10261 * 10262 * Parse a VariableReference, evaluate it and push it on the stack. 10263 * 10264 * The variable bindings consist of a mapping from variable names 10265 * to variable values. The value of a variable is an object, which can be 10266 * of any of the types that are possible for the value of an expression, 10267 * and may also be of additional types not specified here. 10268 * 10269 * Early evaluation is possible since: 10270 * The variable bindings [...] used to evaluate a subexpression are 10271 * always the same as those used to evaluate the containing expression. 10272 * 10273 * [36] VariableReference ::= '$' QName 10274 */ 10275 static void 10276 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) { 10277 xmlChar *name; 10278 xmlChar *prefix; 10279 10280 SKIP_BLANKS; 10281 if (CUR != '$') { 10282 XP_ERROR(XPATH_VARIABLE_REF_ERROR); 10283 } 10284 NEXT; 10285 name = xmlXPathParseQName(ctxt, &prefix); 10286 if (name == NULL) { 10287 xmlFree(prefix); 10288 XP_ERROR(XPATH_VARIABLE_REF_ERROR); 10289 } 10290 ctxt->comp->last = -1; 10291 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, 10292 name, prefix); 10293 SKIP_BLANKS; 10294 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) { 10295 XP_ERROR(XPATH_FORBID_VARIABLE_ERROR); 10296 } 10297 } 10298 10299 /** 10300 * xmlXPathIsNodeType: 10301 * @name: a name string 10302 * 10303 * Is the name given a NodeType one. 10304 * 10305 * [38] NodeType ::= 'comment' 10306 * | 'text' 10307 * | 'processing-instruction' 10308 * | 'node' 10309 * 10310 * Returns 1 if true 0 otherwise 10311 */ 10312 int 10313 xmlXPathIsNodeType(const xmlChar *name) { 10314 if (name == NULL) 10315 return(0); 10316 10317 if (xmlStrEqual(name, BAD_CAST "node")) 10318 return(1); 10319 if (xmlStrEqual(name, BAD_CAST "text")) 10320 return(1); 10321 if (xmlStrEqual(name, BAD_CAST "comment")) 10322 return(1); 10323 if (xmlStrEqual(name, BAD_CAST "processing-instruction")) 10324 return(1); 10325 return(0); 10326 } 10327 10328 /** 10329 * xmlXPathCompFunctionCall: 10330 * @ctxt: the XPath Parser context 10331 * 10332 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')' 10333 * [17] Argument ::= Expr 10334 * 10335 * Compile a function call, the evaluation of all arguments are 10336 * pushed on the stack 10337 */ 10338 static void 10339 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) { 10340 xmlChar *name; 10341 xmlChar *prefix; 10342 int nbargs = 0; 10343 int sort = 1; 10344 10345 name = xmlXPathParseQName(ctxt, &prefix); 10346 if (name == NULL) { 10347 xmlFree(prefix); 10348 XP_ERROR(XPATH_EXPR_ERROR); 10349 } 10350 SKIP_BLANKS; 10351 #ifdef DEBUG_EXPR 10352 if (prefix == NULL) 10353 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n", 10354 name); 10355 else 10356 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n", 10357 prefix, name); 10358 #endif 10359 10360 if (CUR != '(') { 10361 xmlFree(name); 10362 xmlFree(prefix); 10363 XP_ERROR(XPATH_EXPR_ERROR); 10364 } 10365 NEXT; 10366 SKIP_BLANKS; 10367 10368 /* 10369 * Optimization for count(): we don't need the node-set to be sorted. 10370 */ 10371 if ((prefix == NULL) && (name[0] == 'c') && 10372 xmlStrEqual(name, BAD_CAST "count")) 10373 { 10374 sort = 0; 10375 } 10376 ctxt->comp->last = -1; 10377 if (CUR != ')') { 10378 while (CUR != 0) { 10379 int op1 = ctxt->comp->last; 10380 ctxt->comp->last = -1; 10381 xmlXPathCompileExpr(ctxt, sort); 10382 if (ctxt->error != XPATH_EXPRESSION_OK) { 10383 xmlFree(name); 10384 xmlFree(prefix); 10385 return; 10386 } 10387 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0); 10388 nbargs++; 10389 if (CUR == ')') break; 10390 if (CUR != ',') { 10391 xmlFree(name); 10392 xmlFree(prefix); 10393 XP_ERROR(XPATH_EXPR_ERROR); 10394 } 10395 NEXT; 10396 SKIP_BLANKS; 10397 } 10398 } 10399 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, 10400 name, prefix); 10401 NEXT; 10402 SKIP_BLANKS; 10403 } 10404 10405 /** 10406 * xmlXPathCompPrimaryExpr: 10407 * @ctxt: the XPath Parser context 10408 * 10409 * [15] PrimaryExpr ::= VariableReference 10410 * | '(' Expr ')' 10411 * | Literal 10412 * | Number 10413 * | FunctionCall 10414 * 10415 * Compile a primary expression. 10416 */ 10417 static void 10418 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) { 10419 SKIP_BLANKS; 10420 if (CUR == '$') xmlXPathCompVariableReference(ctxt); 10421 else if (CUR == '(') { 10422 NEXT; 10423 SKIP_BLANKS; 10424 xmlXPathCompileExpr(ctxt, 1); 10425 CHECK_ERROR; 10426 if (CUR != ')') { 10427 XP_ERROR(XPATH_EXPR_ERROR); 10428 } 10429 NEXT; 10430 SKIP_BLANKS; 10431 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) { 10432 xmlXPathCompNumber(ctxt); 10433 } else if ((CUR == '\'') || (CUR == '"')) { 10434 xmlXPathCompLiteral(ctxt); 10435 } else { 10436 xmlXPathCompFunctionCall(ctxt); 10437 } 10438 SKIP_BLANKS; 10439 } 10440 10441 /** 10442 * xmlXPathCompFilterExpr: 10443 * @ctxt: the XPath Parser context 10444 * 10445 * [20] FilterExpr ::= PrimaryExpr 10446 * | FilterExpr Predicate 10447 * 10448 * Compile a filter expression. 10449 * Square brackets are used to filter expressions in the same way that 10450 * they are used in location paths. It is an error if the expression to 10451 * be filtered does not evaluate to a node-set. The context node list 10452 * used for evaluating the expression in square brackets is the node-set 10453 * to be filtered listed in document order. 10454 */ 10455 10456 static void 10457 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) { 10458 xmlXPathCompPrimaryExpr(ctxt); 10459 CHECK_ERROR; 10460 SKIP_BLANKS; 10461 10462 while (CUR == '[') { 10463 xmlXPathCompPredicate(ctxt, 1); 10464 SKIP_BLANKS; 10465 } 10466 10467 10468 } 10469 10470 /** 10471 * xmlXPathScanName: 10472 * @ctxt: the XPath Parser context 10473 * 10474 * Trickery: parse an XML name but without consuming the input flow 10475 * Needed to avoid insanity in the parser state. 10476 * 10477 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | 10478 * CombiningChar | Extender 10479 * 10480 * [5] Name ::= (Letter | '_' | ':') (NameChar)* 10481 * 10482 * [6] Names ::= Name (S Name)* 10483 * 10484 * Returns the Name parsed or NULL 10485 */ 10486 10487 static xmlChar * 10488 xmlXPathScanName(xmlXPathParserContextPtr ctxt) { 10489 int len = 0, l; 10490 int c; 10491 const xmlChar *cur; 10492 xmlChar *ret; 10493 10494 cur = ctxt->cur; 10495 10496 c = CUR_CHAR(l); 10497 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */ 10498 (!IS_LETTER(c) && (c != '_') && 10499 (c != ':'))) { 10500 return(NULL); 10501 } 10502 10503 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */ 10504 ((IS_LETTER(c)) || (IS_DIGIT(c)) || 10505 (c == '.') || (c == '-') || 10506 (c == '_') || (c == ':') || 10507 (IS_COMBINING(c)) || 10508 (IS_EXTENDER(c)))) { 10509 len += l; 10510 NEXTL(l); 10511 c = CUR_CHAR(l); 10512 } 10513 ret = xmlStrndup(cur, ctxt->cur - cur); 10514 ctxt->cur = cur; 10515 return(ret); 10516 } 10517 10518 /** 10519 * xmlXPathCompPathExpr: 10520 * @ctxt: the XPath Parser context 10521 * 10522 * [19] PathExpr ::= LocationPath 10523 * | FilterExpr 10524 * | FilterExpr '/' RelativeLocationPath 10525 * | FilterExpr '//' RelativeLocationPath 10526 * 10527 * Compile a path expression. 10528 * The / operator and // operators combine an arbitrary expression 10529 * and a relative location path. It is an error if the expression 10530 * does not evaluate to a node-set. 10531 * The / operator does composition in the same way as when / is 10532 * used in a location path. As in location paths, // is short for 10533 * /descendant-or-self::node()/. 10534 */ 10535 10536 static void 10537 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) { 10538 int lc = 1; /* Should we branch to LocationPath ? */ 10539 xmlChar *name = NULL; /* we may have to preparse a name to find out */ 10540 10541 SKIP_BLANKS; 10542 if ((CUR == '$') || (CUR == '(') || 10543 (IS_ASCII_DIGIT(CUR)) || 10544 (CUR == '\'') || (CUR == '"') || 10545 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) { 10546 lc = 0; 10547 } else if (CUR == '*') { 10548 /* relative or absolute location path */ 10549 lc = 1; 10550 } else if (CUR == '/') { 10551 /* relative or absolute location path */ 10552 lc = 1; 10553 } else if (CUR == '@') { 10554 /* relative abbreviated attribute location path */ 10555 lc = 1; 10556 } else if (CUR == '.') { 10557 /* relative abbreviated attribute location path */ 10558 lc = 1; 10559 } else { 10560 /* 10561 * Problem is finding if we have a name here whether it's: 10562 * - a nodetype 10563 * - a function call in which case it's followed by '(' 10564 * - an axis in which case it's followed by ':' 10565 * - a element name 10566 * We do an a priori analysis here rather than having to 10567 * maintain parsed token content through the recursive function 10568 * calls. This looks uglier but makes the code easier to 10569 * read/write/debug. 10570 */ 10571 SKIP_BLANKS; 10572 name = xmlXPathScanName(ctxt); 10573 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) { 10574 #ifdef DEBUG_STEP 10575 xmlGenericError(xmlGenericErrorContext, 10576 "PathExpr: Axis\n"); 10577 #endif 10578 lc = 1; 10579 xmlFree(name); 10580 } else if (name != NULL) { 10581 int len =xmlStrlen(name); 10582 10583 10584 while (NXT(len) != 0) { 10585 if (NXT(len) == '/') { 10586 /* element name */ 10587 #ifdef DEBUG_STEP 10588 xmlGenericError(xmlGenericErrorContext, 10589 "PathExpr: AbbrRelLocation\n"); 10590 #endif 10591 lc = 1; 10592 break; 10593 } else if (IS_BLANK_CH(NXT(len))) { 10594 /* ignore blanks */ 10595 ; 10596 } else if (NXT(len) == ':') { 10597 #ifdef DEBUG_STEP 10598 xmlGenericError(xmlGenericErrorContext, 10599 "PathExpr: AbbrRelLocation\n"); 10600 #endif 10601 lc = 1; 10602 break; 10603 } else if ((NXT(len) == '(')) { 10604 /* Node Type or Function */ 10605 if (xmlXPathIsNodeType(name)) { 10606 #ifdef DEBUG_STEP 10607 xmlGenericError(xmlGenericErrorContext, 10608 "PathExpr: Type search\n"); 10609 #endif 10610 lc = 1; 10611 #ifdef LIBXML_XPTR_ENABLED 10612 } else if (ctxt->xptr && 10613 xmlStrEqual(name, BAD_CAST "range-to")) { 10614 lc = 1; 10615 #endif 10616 } else { 10617 #ifdef DEBUG_STEP 10618 xmlGenericError(xmlGenericErrorContext, 10619 "PathExpr: function call\n"); 10620 #endif 10621 lc = 0; 10622 } 10623 break; 10624 } else if ((NXT(len) == '[')) { 10625 /* element name */ 10626 #ifdef DEBUG_STEP 10627 xmlGenericError(xmlGenericErrorContext, 10628 "PathExpr: AbbrRelLocation\n"); 10629 #endif 10630 lc = 1; 10631 break; 10632 } else if ((NXT(len) == '<') || (NXT(len) == '>') || 10633 (NXT(len) == '=')) { 10634 lc = 1; 10635 break; 10636 } else { 10637 lc = 1; 10638 break; 10639 } 10640 len++; 10641 } 10642 if (NXT(len) == 0) { 10643 #ifdef DEBUG_STEP 10644 xmlGenericError(xmlGenericErrorContext, 10645 "PathExpr: AbbrRelLocation\n"); 10646 #endif 10647 /* element name */ 10648 lc = 1; 10649 } 10650 xmlFree(name); 10651 } else { 10652 /* make sure all cases are covered explicitly */ 10653 XP_ERROR(XPATH_EXPR_ERROR); 10654 } 10655 } 10656 10657 if (lc) { 10658 if (CUR == '/') { 10659 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0); 10660 } else { 10661 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0); 10662 } 10663 xmlXPathCompLocationPath(ctxt); 10664 } else { 10665 xmlXPathCompFilterExpr(ctxt); 10666 CHECK_ERROR; 10667 if ((CUR == '/') && (NXT(1) == '/')) { 10668 SKIP(2); 10669 SKIP_BLANKS; 10670 10671 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 10672 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 10673 10674 xmlXPathCompRelativeLocationPath(ctxt); 10675 } else if (CUR == '/') { 10676 xmlXPathCompRelativeLocationPath(ctxt); 10677 } 10678 } 10679 SKIP_BLANKS; 10680 } 10681 10682 /** 10683 * xmlXPathCompUnionExpr: 10684 * @ctxt: the XPath Parser context 10685 * 10686 * [18] UnionExpr ::= PathExpr 10687 * | UnionExpr '|' PathExpr 10688 * 10689 * Compile an union expression. 10690 */ 10691 10692 static void 10693 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) { 10694 xmlXPathCompPathExpr(ctxt); 10695 CHECK_ERROR; 10696 SKIP_BLANKS; 10697 while (CUR == '|') { 10698 int op1 = ctxt->comp->last; 10699 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0); 10700 10701 NEXT; 10702 SKIP_BLANKS; 10703 xmlXPathCompPathExpr(ctxt); 10704 10705 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0); 10706 10707 SKIP_BLANKS; 10708 } 10709 } 10710 10711 /** 10712 * xmlXPathCompUnaryExpr: 10713 * @ctxt: the XPath Parser context 10714 * 10715 * [27] UnaryExpr ::= UnionExpr 10716 * | '-' UnaryExpr 10717 * 10718 * Compile an unary expression. 10719 */ 10720 10721 static void 10722 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) { 10723 int minus = 0; 10724 int found = 0; 10725 10726 SKIP_BLANKS; 10727 while (CUR == '-') { 10728 minus = 1 - minus; 10729 found = 1; 10730 NEXT; 10731 SKIP_BLANKS; 10732 } 10733 10734 xmlXPathCompUnionExpr(ctxt); 10735 CHECK_ERROR; 10736 if (found) { 10737 if (minus) 10738 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0); 10739 else 10740 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0); 10741 } 10742 } 10743 10744 /** 10745 * xmlXPathCompMultiplicativeExpr: 10746 * @ctxt: the XPath Parser context 10747 * 10748 * [26] MultiplicativeExpr ::= UnaryExpr 10749 * | MultiplicativeExpr MultiplyOperator UnaryExpr 10750 * | MultiplicativeExpr 'div' UnaryExpr 10751 * | MultiplicativeExpr 'mod' UnaryExpr 10752 * [34] MultiplyOperator ::= '*' 10753 * 10754 * Compile an Additive expression. 10755 */ 10756 10757 static void 10758 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) { 10759 xmlXPathCompUnaryExpr(ctxt); 10760 CHECK_ERROR; 10761 SKIP_BLANKS; 10762 while ((CUR == '*') || 10763 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) || 10764 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) { 10765 int op = -1; 10766 int op1 = ctxt->comp->last; 10767 10768 if (CUR == '*') { 10769 op = 0; 10770 NEXT; 10771 } else if (CUR == 'd') { 10772 op = 1; 10773 SKIP(3); 10774 } else if (CUR == 'm') { 10775 op = 2; 10776 SKIP(3); 10777 } 10778 SKIP_BLANKS; 10779 xmlXPathCompUnaryExpr(ctxt); 10780 CHECK_ERROR; 10781 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0); 10782 SKIP_BLANKS; 10783 } 10784 } 10785 10786 /** 10787 * xmlXPathCompAdditiveExpr: 10788 * @ctxt: the XPath Parser context 10789 * 10790 * [25] AdditiveExpr ::= MultiplicativeExpr 10791 * | AdditiveExpr '+' MultiplicativeExpr 10792 * | AdditiveExpr '-' MultiplicativeExpr 10793 * 10794 * Compile an Additive expression. 10795 */ 10796 10797 static void 10798 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) { 10799 10800 xmlXPathCompMultiplicativeExpr(ctxt); 10801 CHECK_ERROR; 10802 SKIP_BLANKS; 10803 while ((CUR == '+') || (CUR == '-')) { 10804 int plus; 10805 int op1 = ctxt->comp->last; 10806 10807 if (CUR == '+') plus = 1; 10808 else plus = 0; 10809 NEXT; 10810 SKIP_BLANKS; 10811 xmlXPathCompMultiplicativeExpr(ctxt); 10812 CHECK_ERROR; 10813 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0); 10814 SKIP_BLANKS; 10815 } 10816 } 10817 10818 /** 10819 * xmlXPathCompRelationalExpr: 10820 * @ctxt: the XPath Parser context 10821 * 10822 * [24] RelationalExpr ::= AdditiveExpr 10823 * | RelationalExpr '<' AdditiveExpr 10824 * | RelationalExpr '>' AdditiveExpr 10825 * | RelationalExpr '<=' AdditiveExpr 10826 * | RelationalExpr '>=' AdditiveExpr 10827 * 10828 * A <= B > C is allowed ? Answer from James, yes with 10829 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr 10830 * which is basically what got implemented. 10831 * 10832 * Compile a Relational expression, then push the result 10833 * on the stack 10834 */ 10835 10836 static void 10837 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) { 10838 xmlXPathCompAdditiveExpr(ctxt); 10839 CHECK_ERROR; 10840 SKIP_BLANKS; 10841 while ((CUR == '<') || (CUR == '>')) { 10842 int inf, strict; 10843 int op1 = ctxt->comp->last; 10844 10845 if (CUR == '<') inf = 1; 10846 else inf = 0; 10847 if (NXT(1) == '=') strict = 0; 10848 else strict = 1; 10849 NEXT; 10850 if (!strict) NEXT; 10851 SKIP_BLANKS; 10852 xmlXPathCompAdditiveExpr(ctxt); 10853 CHECK_ERROR; 10854 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict); 10855 SKIP_BLANKS; 10856 } 10857 } 10858 10859 /** 10860 * xmlXPathCompEqualityExpr: 10861 * @ctxt: the XPath Parser context 10862 * 10863 * [23] EqualityExpr ::= RelationalExpr 10864 * | EqualityExpr '=' RelationalExpr 10865 * | EqualityExpr '!=' RelationalExpr 10866 * 10867 * A != B != C is allowed ? Answer from James, yes with 10868 * (RelationalExpr = RelationalExpr) = RelationalExpr 10869 * (RelationalExpr != RelationalExpr) != RelationalExpr 10870 * which is basically what got implemented. 10871 * 10872 * Compile an Equality expression. 10873 * 10874 */ 10875 static void 10876 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) { 10877 xmlXPathCompRelationalExpr(ctxt); 10878 CHECK_ERROR; 10879 SKIP_BLANKS; 10880 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) { 10881 int eq; 10882 int op1 = ctxt->comp->last; 10883 10884 if (CUR == '=') eq = 1; 10885 else eq = 0; 10886 NEXT; 10887 if (!eq) NEXT; 10888 SKIP_BLANKS; 10889 xmlXPathCompRelationalExpr(ctxt); 10890 CHECK_ERROR; 10891 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0); 10892 SKIP_BLANKS; 10893 } 10894 } 10895 10896 /** 10897 * xmlXPathCompAndExpr: 10898 * @ctxt: the XPath Parser context 10899 * 10900 * [22] AndExpr ::= EqualityExpr 10901 * | AndExpr 'and' EqualityExpr 10902 * 10903 * Compile an AND expression. 10904 * 10905 */ 10906 static void 10907 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) { 10908 xmlXPathCompEqualityExpr(ctxt); 10909 CHECK_ERROR; 10910 SKIP_BLANKS; 10911 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) { 10912 int op1 = ctxt->comp->last; 10913 SKIP(3); 10914 SKIP_BLANKS; 10915 xmlXPathCompEqualityExpr(ctxt); 10916 CHECK_ERROR; 10917 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0); 10918 SKIP_BLANKS; 10919 } 10920 } 10921 10922 /** 10923 * xmlXPathCompileExpr: 10924 * @ctxt: the XPath Parser context 10925 * 10926 * [14] Expr ::= OrExpr 10927 * [21] OrExpr ::= AndExpr 10928 * | OrExpr 'or' AndExpr 10929 * 10930 * Parse and compile an expression 10931 */ 10932 static void 10933 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) { 10934 xmlXPathContextPtr xpctxt = ctxt->context; 10935 10936 if (xpctxt != NULL) { 10937 if (xpctxt->depth >= xpctxt->maxParserDepth) 10938 XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED); 10939 xpctxt->depth += 1; 10940 } 10941 10942 xmlXPathCompAndExpr(ctxt); 10943 CHECK_ERROR; 10944 SKIP_BLANKS; 10945 while ((CUR == 'o') && (NXT(1) == 'r')) { 10946 int op1 = ctxt->comp->last; 10947 SKIP(2); 10948 SKIP_BLANKS; 10949 xmlXPathCompAndExpr(ctxt); 10950 CHECK_ERROR; 10951 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0); 10952 SKIP_BLANKS; 10953 } 10954 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) { 10955 /* more ops could be optimized too */ 10956 /* 10957 * This is the main place to eliminate sorting for 10958 * operations which don't require a sorted node-set. 10959 * E.g. count(). 10960 */ 10961 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0); 10962 } 10963 10964 if (xpctxt != NULL) 10965 xpctxt->depth -= 1; 10966 } 10967 10968 /** 10969 * xmlXPathCompPredicate: 10970 * @ctxt: the XPath Parser context 10971 * @filter: act as a filter 10972 * 10973 * [8] Predicate ::= '[' PredicateExpr ']' 10974 * [9] PredicateExpr ::= Expr 10975 * 10976 * Compile a predicate expression 10977 */ 10978 static void 10979 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) { 10980 int op1 = ctxt->comp->last; 10981 10982 SKIP_BLANKS; 10983 if (CUR != '[') { 10984 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); 10985 } 10986 NEXT; 10987 SKIP_BLANKS; 10988 10989 ctxt->comp->last = -1; 10990 /* 10991 * This call to xmlXPathCompileExpr() will deactivate sorting 10992 * of the predicate result. 10993 * TODO: Sorting is still activated for filters, since I'm not 10994 * sure if needed. Normally sorting should not be needed, since 10995 * a filter can only diminish the number of items in a sequence, 10996 * but won't change its order; so if the initial sequence is sorted, 10997 * subsequent sorting is not needed. 10998 */ 10999 if (! filter) 11000 xmlXPathCompileExpr(ctxt, 0); 11001 else 11002 xmlXPathCompileExpr(ctxt, 1); 11003 CHECK_ERROR; 11004 11005 if (CUR != ']') { 11006 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); 11007 } 11008 11009 if (filter) 11010 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0); 11011 else 11012 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0); 11013 11014 NEXT; 11015 SKIP_BLANKS; 11016 } 11017 11018 /** 11019 * xmlXPathCompNodeTest: 11020 * @ctxt: the XPath Parser context 11021 * @test: pointer to a xmlXPathTestVal 11022 * @type: pointer to a xmlXPathTypeVal 11023 * @prefix: placeholder for a possible name prefix 11024 * 11025 * [7] NodeTest ::= NameTest 11026 * | NodeType '(' ')' 11027 * | 'processing-instruction' '(' Literal ')' 11028 * 11029 * [37] NameTest ::= '*' 11030 * | NCName ':' '*' 11031 * | QName 11032 * [38] NodeType ::= 'comment' 11033 * | 'text' 11034 * | 'processing-instruction' 11035 * | 'node' 11036 * 11037 * Returns the name found and updates @test, @type and @prefix appropriately 11038 */ 11039 static xmlChar * 11040 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test, 11041 xmlXPathTypeVal *type, const xmlChar **prefix, 11042 xmlChar *name) { 11043 int blanks; 11044 11045 if ((test == NULL) || (type == NULL) || (prefix == NULL)) { 11046 STRANGE; 11047 return(NULL); 11048 } 11049 *type = (xmlXPathTypeVal) 0; 11050 *test = (xmlXPathTestVal) 0; 11051 *prefix = NULL; 11052 SKIP_BLANKS; 11053 11054 if ((name == NULL) && (CUR == '*')) { 11055 /* 11056 * All elements 11057 */ 11058 NEXT; 11059 *test = NODE_TEST_ALL; 11060 return(NULL); 11061 } 11062 11063 if (name == NULL) 11064 name = xmlXPathParseNCName(ctxt); 11065 if (name == NULL) { 11066 XP_ERRORNULL(XPATH_EXPR_ERROR); 11067 } 11068 11069 blanks = IS_BLANK_CH(CUR); 11070 SKIP_BLANKS; 11071 if (CUR == '(') { 11072 NEXT; 11073 /* 11074 * NodeType or PI search 11075 */ 11076 if (xmlStrEqual(name, BAD_CAST "comment")) 11077 *type = NODE_TYPE_COMMENT; 11078 else if (xmlStrEqual(name, BAD_CAST "node")) 11079 *type = NODE_TYPE_NODE; 11080 else if (xmlStrEqual(name, BAD_CAST "processing-instruction")) 11081 *type = NODE_TYPE_PI; 11082 else if (xmlStrEqual(name, BAD_CAST "text")) 11083 *type = NODE_TYPE_TEXT; 11084 else { 11085 if (name != NULL) 11086 xmlFree(name); 11087 XP_ERRORNULL(XPATH_EXPR_ERROR); 11088 } 11089 11090 *test = NODE_TEST_TYPE; 11091 11092 SKIP_BLANKS; 11093 if (*type == NODE_TYPE_PI) { 11094 /* 11095 * Specific case: search a PI by name. 11096 */ 11097 if (name != NULL) 11098 xmlFree(name); 11099 name = NULL; 11100 if (CUR != ')') { 11101 name = xmlXPathParseLiteral(ctxt); 11102 CHECK_ERROR NULL; 11103 *test = NODE_TEST_PI; 11104 SKIP_BLANKS; 11105 } 11106 } 11107 if (CUR != ')') { 11108 if (name != NULL) 11109 xmlFree(name); 11110 XP_ERRORNULL(XPATH_UNCLOSED_ERROR); 11111 } 11112 NEXT; 11113 return(name); 11114 } 11115 *test = NODE_TEST_NAME; 11116 if ((!blanks) && (CUR == ':')) { 11117 NEXT; 11118 11119 /* 11120 * Since currently the parser context don't have a 11121 * namespace list associated: 11122 * The namespace name for this prefix can be computed 11123 * only at evaluation time. The compilation is done 11124 * outside of any context. 11125 */ 11126 #if 0 11127 *prefix = xmlXPathNsLookup(ctxt->context, name); 11128 if (name != NULL) 11129 xmlFree(name); 11130 if (*prefix == NULL) { 11131 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); 11132 } 11133 #else 11134 *prefix = name; 11135 #endif 11136 11137 if (CUR == '*') { 11138 /* 11139 * All elements 11140 */ 11141 NEXT; 11142 *test = NODE_TEST_ALL; 11143 return(NULL); 11144 } 11145 11146 name = xmlXPathParseNCName(ctxt); 11147 if (name == NULL) { 11148 XP_ERRORNULL(XPATH_EXPR_ERROR); 11149 } 11150 } 11151 return(name); 11152 } 11153 11154 /** 11155 * xmlXPathIsAxisName: 11156 * @name: a preparsed name token 11157 * 11158 * [6] AxisName ::= 'ancestor' 11159 * | 'ancestor-or-self' 11160 * | 'attribute' 11161 * | 'child' 11162 * | 'descendant' 11163 * | 'descendant-or-self' 11164 * | 'following' 11165 * | 'following-sibling' 11166 * | 'namespace' 11167 * | 'parent' 11168 * | 'preceding' 11169 * | 'preceding-sibling' 11170 * | 'self' 11171 * 11172 * Returns the axis or 0 11173 */ 11174 static xmlXPathAxisVal 11175 xmlXPathIsAxisName(const xmlChar *name) { 11176 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0; 11177 switch (name[0]) { 11178 case 'a': 11179 if (xmlStrEqual(name, BAD_CAST "ancestor")) 11180 ret = AXIS_ANCESTOR; 11181 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self")) 11182 ret = AXIS_ANCESTOR_OR_SELF; 11183 if (xmlStrEqual(name, BAD_CAST "attribute")) 11184 ret = AXIS_ATTRIBUTE; 11185 break; 11186 case 'c': 11187 if (xmlStrEqual(name, BAD_CAST "child")) 11188 ret = AXIS_CHILD; 11189 break; 11190 case 'd': 11191 if (xmlStrEqual(name, BAD_CAST "descendant")) 11192 ret = AXIS_DESCENDANT; 11193 if (xmlStrEqual(name, BAD_CAST "descendant-or-self")) 11194 ret = AXIS_DESCENDANT_OR_SELF; 11195 break; 11196 case 'f': 11197 if (xmlStrEqual(name, BAD_CAST "following")) 11198 ret = AXIS_FOLLOWING; 11199 if (xmlStrEqual(name, BAD_CAST "following-sibling")) 11200 ret = AXIS_FOLLOWING_SIBLING; 11201 break; 11202 case 'n': 11203 if (xmlStrEqual(name, BAD_CAST "namespace")) 11204 ret = AXIS_NAMESPACE; 11205 break; 11206 case 'p': 11207 if (xmlStrEqual(name, BAD_CAST "parent")) 11208 ret = AXIS_PARENT; 11209 if (xmlStrEqual(name, BAD_CAST "preceding")) 11210 ret = AXIS_PRECEDING; 11211 if (xmlStrEqual(name, BAD_CAST "preceding-sibling")) 11212 ret = AXIS_PRECEDING_SIBLING; 11213 break; 11214 case 's': 11215 if (xmlStrEqual(name, BAD_CAST "self")) 11216 ret = AXIS_SELF; 11217 break; 11218 } 11219 return(ret); 11220 } 11221 11222 /** 11223 * xmlXPathCompStep: 11224 * @ctxt: the XPath Parser context 11225 * 11226 * [4] Step ::= AxisSpecifier NodeTest Predicate* 11227 * | AbbreviatedStep 11228 * 11229 * [12] AbbreviatedStep ::= '.' | '..' 11230 * 11231 * [5] AxisSpecifier ::= AxisName '::' 11232 * | AbbreviatedAxisSpecifier 11233 * 11234 * [13] AbbreviatedAxisSpecifier ::= '@'? 11235 * 11236 * Modified for XPtr range support as: 11237 * 11238 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate* 11239 * | AbbreviatedStep 11240 * | 'range-to' '(' Expr ')' Predicate* 11241 * 11242 * Compile one step in a Location Path 11243 * A location step of . is short for self::node(). This is 11244 * particularly useful in conjunction with //. For example, the 11245 * location path .//para is short for 11246 * self::node()/descendant-or-self::node()/child::para 11247 * and so will select all para descendant elements of the context 11248 * node. 11249 * Similarly, a location step of .. is short for parent::node(). 11250 * For example, ../title is short for parent::node()/child::title 11251 * and so will select the title children of the parent of the context 11252 * node. 11253 */ 11254 static void 11255 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) { 11256 #ifdef LIBXML_XPTR_ENABLED 11257 int rangeto = 0; 11258 int op2 = -1; 11259 #endif 11260 11261 SKIP_BLANKS; 11262 if ((CUR == '.') && (NXT(1) == '.')) { 11263 SKIP(2); 11264 SKIP_BLANKS; 11265 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT, 11266 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11267 } else if (CUR == '.') { 11268 NEXT; 11269 SKIP_BLANKS; 11270 } else { 11271 xmlChar *name = NULL; 11272 const xmlChar *prefix = NULL; 11273 xmlXPathTestVal test = (xmlXPathTestVal) 0; 11274 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0; 11275 xmlXPathTypeVal type = (xmlXPathTypeVal) 0; 11276 int op1; 11277 11278 /* 11279 * The modification needed for XPointer change to the production 11280 */ 11281 #ifdef LIBXML_XPTR_ENABLED 11282 if (ctxt->xptr) { 11283 name = xmlXPathParseNCName(ctxt); 11284 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) { 11285 op2 = ctxt->comp->last; 11286 xmlFree(name); 11287 SKIP_BLANKS; 11288 if (CUR != '(') { 11289 XP_ERROR(XPATH_EXPR_ERROR); 11290 } 11291 NEXT; 11292 SKIP_BLANKS; 11293 11294 xmlXPathCompileExpr(ctxt, 1); 11295 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */ 11296 CHECK_ERROR; 11297 11298 SKIP_BLANKS; 11299 if (CUR != ')') { 11300 XP_ERROR(XPATH_EXPR_ERROR); 11301 } 11302 NEXT; 11303 rangeto = 1; 11304 goto eval_predicates; 11305 } 11306 } 11307 #endif 11308 if (CUR == '*') { 11309 axis = AXIS_CHILD; 11310 } else { 11311 if (name == NULL) 11312 name = xmlXPathParseNCName(ctxt); 11313 if (name != NULL) { 11314 axis = xmlXPathIsAxisName(name); 11315 if (axis != 0) { 11316 SKIP_BLANKS; 11317 if ((CUR == ':') && (NXT(1) == ':')) { 11318 SKIP(2); 11319 xmlFree(name); 11320 name = NULL; 11321 } else { 11322 /* an element name can conflict with an axis one :-\ */ 11323 axis = AXIS_CHILD; 11324 } 11325 } else { 11326 axis = AXIS_CHILD; 11327 } 11328 } else if (CUR == '@') { 11329 NEXT; 11330 axis = AXIS_ATTRIBUTE; 11331 } else { 11332 axis = AXIS_CHILD; 11333 } 11334 } 11335 11336 if (ctxt->error != XPATH_EXPRESSION_OK) { 11337 xmlFree(name); 11338 return; 11339 } 11340 11341 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name); 11342 if (test == 0) 11343 return; 11344 11345 if ((prefix != NULL) && (ctxt->context != NULL) && 11346 (ctxt->context->flags & XML_XPATH_CHECKNS)) { 11347 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) { 11348 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR); 11349 } 11350 } 11351 #ifdef DEBUG_STEP 11352 xmlGenericError(xmlGenericErrorContext, 11353 "Basis : computing new set\n"); 11354 #endif 11355 11356 #ifdef DEBUG_STEP 11357 xmlGenericError(xmlGenericErrorContext, "Basis : "); 11358 if (ctxt->value == NULL) 11359 xmlGenericError(xmlGenericErrorContext, "no value\n"); 11360 else if (ctxt->value->nodesetval == NULL) 11361 xmlGenericError(xmlGenericErrorContext, "Empty\n"); 11362 else 11363 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval); 11364 #endif 11365 11366 #ifdef LIBXML_XPTR_ENABLED 11367 eval_predicates: 11368 #endif 11369 op1 = ctxt->comp->last; 11370 ctxt->comp->last = -1; 11371 11372 SKIP_BLANKS; 11373 while (CUR == '[') { 11374 xmlXPathCompPredicate(ctxt, 0); 11375 } 11376 11377 #ifdef LIBXML_XPTR_ENABLED 11378 if (rangeto) { 11379 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0); 11380 } else 11381 #endif 11382 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis, 11383 test, type, (void *)prefix, (void *)name); 11384 11385 } 11386 #ifdef DEBUG_STEP 11387 xmlGenericError(xmlGenericErrorContext, "Step : "); 11388 if (ctxt->value == NULL) 11389 xmlGenericError(xmlGenericErrorContext, "no value\n"); 11390 else if (ctxt->value->nodesetval == NULL) 11391 xmlGenericError(xmlGenericErrorContext, "Empty\n"); 11392 else 11393 xmlGenericErrorContextNodeSet(xmlGenericErrorContext, 11394 ctxt->value->nodesetval); 11395 #endif 11396 } 11397 11398 /** 11399 * xmlXPathCompRelativeLocationPath: 11400 * @ctxt: the XPath Parser context 11401 * 11402 * [3] RelativeLocationPath ::= Step 11403 * | RelativeLocationPath '/' Step 11404 * | AbbreviatedRelativeLocationPath 11405 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step 11406 * 11407 * Compile a relative location path. 11408 */ 11409 static void 11410 xmlXPathCompRelativeLocationPath 11411 (xmlXPathParserContextPtr ctxt) { 11412 SKIP_BLANKS; 11413 if ((CUR == '/') && (NXT(1) == '/')) { 11414 SKIP(2); 11415 SKIP_BLANKS; 11416 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 11417 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11418 } else if (CUR == '/') { 11419 NEXT; 11420 SKIP_BLANKS; 11421 } 11422 xmlXPathCompStep(ctxt); 11423 CHECK_ERROR; 11424 SKIP_BLANKS; 11425 while (CUR == '/') { 11426 if ((CUR == '/') && (NXT(1) == '/')) { 11427 SKIP(2); 11428 SKIP_BLANKS; 11429 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 11430 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11431 xmlXPathCompStep(ctxt); 11432 } else if (CUR == '/') { 11433 NEXT; 11434 SKIP_BLANKS; 11435 xmlXPathCompStep(ctxt); 11436 } 11437 SKIP_BLANKS; 11438 } 11439 } 11440 11441 /** 11442 * xmlXPathCompLocationPath: 11443 * @ctxt: the XPath Parser context 11444 * 11445 * [1] LocationPath ::= RelativeLocationPath 11446 * | AbsoluteLocationPath 11447 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath? 11448 * | AbbreviatedAbsoluteLocationPath 11449 * [10] AbbreviatedAbsoluteLocationPath ::= 11450 * '//' RelativeLocationPath 11451 * 11452 * Compile a location path 11453 * 11454 * // is short for /descendant-or-self::node()/. For example, 11455 * //para is short for /descendant-or-self::node()/child::para and 11456 * so will select any para element in the document (even a para element 11457 * that is a document element will be selected by //para since the 11458 * document element node is a child of the root node); div//para is 11459 * short for div/descendant-or-self::node()/child::para and so will 11460 * select all para descendants of div children. 11461 */ 11462 static void 11463 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) { 11464 SKIP_BLANKS; 11465 if (CUR != '/') { 11466 xmlXPathCompRelativeLocationPath(ctxt); 11467 } else { 11468 while (CUR == '/') { 11469 if ((CUR == '/') && (NXT(1) == '/')) { 11470 SKIP(2); 11471 SKIP_BLANKS; 11472 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 11473 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11474 xmlXPathCompRelativeLocationPath(ctxt); 11475 } else if (CUR == '/') { 11476 NEXT; 11477 SKIP_BLANKS; 11478 if ((CUR != 0 ) && 11479 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') || 11480 (CUR == '@') || (CUR == '*'))) 11481 xmlXPathCompRelativeLocationPath(ctxt); 11482 } 11483 CHECK_ERROR; 11484 } 11485 } 11486 } 11487 11488 /************************************************************************ 11489 * * 11490 * XPath precompiled expression evaluation * 11491 * * 11492 ************************************************************************/ 11493 11494 static int 11495 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op); 11496 11497 #ifdef DEBUG_STEP 11498 static void 11499 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op, 11500 int nbNodes) 11501 { 11502 xmlGenericError(xmlGenericErrorContext, "new step : "); 11503 switch (op->value) { 11504 case AXIS_ANCESTOR: 11505 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' "); 11506 break; 11507 case AXIS_ANCESTOR_OR_SELF: 11508 xmlGenericError(xmlGenericErrorContext, 11509 "axis 'ancestors-or-self' "); 11510 break; 11511 case AXIS_ATTRIBUTE: 11512 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' "); 11513 break; 11514 case AXIS_CHILD: 11515 xmlGenericError(xmlGenericErrorContext, "axis 'child' "); 11516 break; 11517 case AXIS_DESCENDANT: 11518 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' "); 11519 break; 11520 case AXIS_DESCENDANT_OR_SELF: 11521 xmlGenericError(xmlGenericErrorContext, 11522 "axis 'descendant-or-self' "); 11523 break; 11524 case AXIS_FOLLOWING: 11525 xmlGenericError(xmlGenericErrorContext, "axis 'following' "); 11526 break; 11527 case AXIS_FOLLOWING_SIBLING: 11528 xmlGenericError(xmlGenericErrorContext, 11529 "axis 'following-siblings' "); 11530 break; 11531 case AXIS_NAMESPACE: 11532 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' "); 11533 break; 11534 case AXIS_PARENT: 11535 xmlGenericError(xmlGenericErrorContext, "axis 'parent' "); 11536 break; 11537 case AXIS_PRECEDING: 11538 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' "); 11539 break; 11540 case AXIS_PRECEDING_SIBLING: 11541 xmlGenericError(xmlGenericErrorContext, 11542 "axis 'preceding-sibling' "); 11543 break; 11544 case AXIS_SELF: 11545 xmlGenericError(xmlGenericErrorContext, "axis 'self' "); 11546 break; 11547 } 11548 xmlGenericError(xmlGenericErrorContext, 11549 " context contains %d nodes\n", nbNodes); 11550 switch (op->value2) { 11551 case NODE_TEST_NONE: 11552 xmlGenericError(xmlGenericErrorContext, 11553 " searching for none !!!\n"); 11554 break; 11555 case NODE_TEST_TYPE: 11556 xmlGenericError(xmlGenericErrorContext, 11557 " searching for type %d\n", op->value3); 11558 break; 11559 case NODE_TEST_PI: 11560 xmlGenericError(xmlGenericErrorContext, 11561 " searching for PI !!!\n"); 11562 break; 11563 case NODE_TEST_ALL: 11564 xmlGenericError(xmlGenericErrorContext, 11565 " searching for *\n"); 11566 break; 11567 case NODE_TEST_NS: 11568 xmlGenericError(xmlGenericErrorContext, 11569 " searching for namespace %s\n", 11570 op->value5); 11571 break; 11572 case NODE_TEST_NAME: 11573 xmlGenericError(xmlGenericErrorContext, 11574 " searching for name %s\n", op->value5); 11575 if (op->value4) 11576 xmlGenericError(xmlGenericErrorContext, 11577 " with namespace %s\n", op->value4); 11578 break; 11579 } 11580 xmlGenericError(xmlGenericErrorContext, "Testing : "); 11581 } 11582 #endif /* DEBUG_STEP */ 11583 11584 /** 11585 * xmlXPathNodeSetFilter: 11586 * @ctxt: the XPath Parser context 11587 * @set: the node set to filter 11588 * @filterOpIndex: the index of the predicate/filter op 11589 * @minPos: minimum position in the filtered set (1-based) 11590 * @maxPos: maximum position in the filtered set (1-based) 11591 * @hasNsNodes: true if the node set may contain namespace nodes 11592 * 11593 * Filter a node set, keeping only nodes for which the predicate expression 11594 * matches. Afterwards, keep only nodes between minPos and maxPos in the 11595 * filtered result. 11596 */ 11597 static void 11598 xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt, 11599 xmlNodeSetPtr set, 11600 int filterOpIndex, 11601 int minPos, int maxPos, 11602 int hasNsNodes) 11603 { 11604 xmlXPathContextPtr xpctxt; 11605 xmlNodePtr oldnode; 11606 xmlDocPtr olddoc; 11607 xmlXPathStepOpPtr filterOp; 11608 int oldcs, oldpp; 11609 int i, j, pos; 11610 11611 if ((set == NULL) || (set->nodeNr == 0)) 11612 return; 11613 11614 /* 11615 * Check if the node set contains a sufficient number of nodes for 11616 * the requested range. 11617 */ 11618 if (set->nodeNr < minPos) { 11619 xmlXPathNodeSetClear(set, hasNsNodes); 11620 return; 11621 } 11622 11623 xpctxt = ctxt->context; 11624 oldnode = xpctxt->node; 11625 olddoc = xpctxt->doc; 11626 oldcs = xpctxt->contextSize; 11627 oldpp = xpctxt->proximityPosition; 11628 filterOp = &ctxt->comp->steps[filterOpIndex]; 11629 11630 xpctxt->contextSize = set->nodeNr; 11631 11632 for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) { 11633 xmlNodePtr node = set->nodeTab[i]; 11634 int res; 11635 11636 xpctxt->node = node; 11637 xpctxt->proximityPosition = i + 1; 11638 11639 /* 11640 * Also set the xpath document in case things like 11641 * key() are evaluated in the predicate. 11642 * 11643 * TODO: Get real doc for namespace nodes. 11644 */ 11645 if ((node->type != XML_NAMESPACE_DECL) && 11646 (node->doc != NULL)) 11647 xpctxt->doc = node->doc; 11648 11649 res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1); 11650 11651 if (ctxt->error != XPATH_EXPRESSION_OK) 11652 goto exit; 11653 if (res < 0) { 11654 /* Shouldn't happen */ 11655 xmlXPathErr(ctxt, XPATH_EXPR_ERROR); 11656 goto exit; 11657 } 11658 11659 if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) { 11660 if (i != j) { 11661 set->nodeTab[j] = node; 11662 set->nodeTab[i] = NULL; 11663 } 11664 11665 j += 1; 11666 } else { 11667 /* Remove the entry from the initial node set. */ 11668 set->nodeTab[i] = NULL; 11669 if (node->type == XML_NAMESPACE_DECL) 11670 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 11671 } 11672 11673 if (res != 0) { 11674 if (pos == maxPos) { 11675 /* Clear remaining nodes and exit loop. */ 11676 if (hasNsNodes) { 11677 for (i++; i < set->nodeNr; i++) { 11678 node = set->nodeTab[i]; 11679 if ((node != NULL) && 11680 (node->type == XML_NAMESPACE_DECL)) 11681 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 11682 } 11683 } 11684 break; 11685 } 11686 11687 pos += 1; 11688 } 11689 } 11690 11691 set->nodeNr = j; 11692 11693 /* If too many elements were removed, shrink table to preserve memory. */ 11694 if ((set->nodeMax > XML_NODESET_DEFAULT) && 11695 (set->nodeNr < set->nodeMax / 2)) { 11696 xmlNodePtr *tmp; 11697 int nodeMax = set->nodeNr; 11698 11699 if (nodeMax < XML_NODESET_DEFAULT) 11700 nodeMax = XML_NODESET_DEFAULT; 11701 tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab, 11702 nodeMax * sizeof(xmlNodePtr)); 11703 if (tmp == NULL) { 11704 xmlXPathPErrMemory(ctxt, "shrinking nodeset\n"); 11705 } else { 11706 set->nodeTab = tmp; 11707 set->nodeMax = nodeMax; 11708 } 11709 } 11710 11711 exit: 11712 xpctxt->node = oldnode; 11713 xpctxt->doc = olddoc; 11714 xpctxt->contextSize = oldcs; 11715 xpctxt->proximityPosition = oldpp; 11716 } 11717 11718 #ifdef LIBXML_XPTR_ENABLED 11719 /** 11720 * xmlXPathLocationSetFilter: 11721 * @ctxt: the XPath Parser context 11722 * @locset: the location set to filter 11723 * @filterOpIndex: the index of the predicate/filter op 11724 * @minPos: minimum position in the filtered set (1-based) 11725 * @maxPos: maximum position in the filtered set (1-based) 11726 * 11727 * Filter a location set, keeping only nodes for which the predicate 11728 * expression matches. Afterwards, keep only nodes between minPos and maxPos 11729 * in the filtered result. 11730 */ 11731 static void 11732 xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt, 11733 xmlLocationSetPtr locset, 11734 int filterOpIndex, 11735 int minPos, int maxPos) 11736 { 11737 xmlXPathContextPtr xpctxt; 11738 xmlNodePtr oldnode; 11739 xmlDocPtr olddoc; 11740 xmlXPathStepOpPtr filterOp; 11741 int oldcs, oldpp; 11742 int i, j, pos; 11743 11744 if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1)) 11745 return; 11746 11747 xpctxt = ctxt->context; 11748 oldnode = xpctxt->node; 11749 olddoc = xpctxt->doc; 11750 oldcs = xpctxt->contextSize; 11751 oldpp = xpctxt->proximityPosition; 11752 filterOp = &ctxt->comp->steps[filterOpIndex]; 11753 11754 xpctxt->contextSize = locset->locNr; 11755 11756 for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) { 11757 xmlNodePtr contextNode = locset->locTab[i]->user; 11758 int res; 11759 11760 xpctxt->node = contextNode; 11761 xpctxt->proximityPosition = i + 1; 11762 11763 /* 11764 * Also set the xpath document in case things like 11765 * key() are evaluated in the predicate. 11766 * 11767 * TODO: Get real doc for namespace nodes. 11768 */ 11769 if ((contextNode->type != XML_NAMESPACE_DECL) && 11770 (contextNode->doc != NULL)) 11771 xpctxt->doc = contextNode->doc; 11772 11773 res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1); 11774 11775 if (ctxt->error != XPATH_EXPRESSION_OK) 11776 goto exit; 11777 if (res < 0) { 11778 /* Shouldn't happen */ 11779 xmlXPathErr(ctxt, XPATH_EXPR_ERROR); 11780 goto exit; 11781 } 11782 11783 if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) { 11784 if (i != j) { 11785 locset->locTab[j] = locset->locTab[i]; 11786 locset->locTab[i] = NULL; 11787 } 11788 11789 j += 1; 11790 } else { 11791 /* Remove the entry from the initial location set. */ 11792 xmlXPathFreeObject(locset->locTab[i]); 11793 locset->locTab[i] = NULL; 11794 } 11795 11796 if (res != 0) { 11797 if (pos == maxPos) { 11798 /* Clear remaining nodes and exit loop. */ 11799 for (i++; i < locset->locNr; i++) { 11800 xmlXPathFreeObject(locset->locTab[i]); 11801 } 11802 break; 11803 } 11804 11805 pos += 1; 11806 } 11807 } 11808 11809 locset->locNr = j; 11810 11811 /* If too many elements were removed, shrink table to preserve memory. */ 11812 if ((locset->locMax > XML_NODESET_DEFAULT) && 11813 (locset->locNr < locset->locMax / 2)) { 11814 xmlXPathObjectPtr *tmp; 11815 int locMax = locset->locNr; 11816 11817 if (locMax < XML_NODESET_DEFAULT) 11818 locMax = XML_NODESET_DEFAULT; 11819 tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab, 11820 locMax * sizeof(xmlXPathObjectPtr)); 11821 if (tmp == NULL) { 11822 xmlXPathPErrMemory(ctxt, "shrinking locset\n"); 11823 } else { 11824 locset->locTab = tmp; 11825 locset->locMax = locMax; 11826 } 11827 } 11828 11829 exit: 11830 xpctxt->node = oldnode; 11831 xpctxt->doc = olddoc; 11832 xpctxt->contextSize = oldcs; 11833 xpctxt->proximityPosition = oldpp; 11834 } 11835 #endif /* LIBXML_XPTR_ENABLED */ 11836 11837 /** 11838 * xmlXPathCompOpEvalPredicate: 11839 * @ctxt: the XPath Parser context 11840 * @op: the predicate op 11841 * @set: the node set to filter 11842 * @minPos: minimum position in the filtered set (1-based) 11843 * @maxPos: maximum position in the filtered set (1-based) 11844 * @hasNsNodes: true if the node set may contain namespace nodes 11845 * 11846 * Filter a node set, keeping only nodes for which the sequence of predicate 11847 * expressions matches. Afterwards, keep only nodes between minPos and maxPos 11848 * in the filtered result. 11849 */ 11850 static void 11851 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt, 11852 xmlXPathStepOpPtr op, 11853 xmlNodeSetPtr set, 11854 int minPos, int maxPos, 11855 int hasNsNodes) 11856 { 11857 if (op->ch1 != -1) { 11858 xmlXPathCompExprPtr comp = ctxt->comp; 11859 /* 11860 * Process inner predicates first. 11861 */ 11862 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) { 11863 xmlGenericError(xmlGenericErrorContext, 11864 "xmlXPathCompOpEvalPredicate: Expected a predicate\n"); 11865 XP_ERROR(XPATH_INVALID_OPERAND); 11866 } 11867 if (ctxt->context->depth >= ctxt->context->maxDepth) 11868 XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED); 11869 ctxt->context->depth += 1; 11870 xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set, 11871 1, set->nodeNr, hasNsNodes); 11872 ctxt->context->depth -= 1; 11873 CHECK_ERROR; 11874 } 11875 11876 if (op->ch2 != -1) 11877 xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes); 11878 } 11879 11880 static int 11881 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt, 11882 xmlXPathStepOpPtr op, 11883 int *maxPos) 11884 { 11885 11886 xmlXPathStepOpPtr exprOp; 11887 11888 /* 11889 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet! 11890 */ 11891 11892 /* 11893 * If not -1, then ch1 will point to: 11894 * 1) For predicates (XPATH_OP_PREDICATE): 11895 * - an inner predicate operator 11896 * 2) For filters (XPATH_OP_FILTER): 11897 * - an inner filter operator OR 11898 * - an expression selecting the node set. 11899 * E.g. "key('a', 'b')" or "(//foo | //bar)". 11900 */ 11901 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER)) 11902 return(0); 11903 11904 if (op->ch2 != -1) { 11905 exprOp = &ctxt->comp->steps[op->ch2]; 11906 } else 11907 return(0); 11908 11909 if ((exprOp != NULL) && 11910 (exprOp->op == XPATH_OP_VALUE) && 11911 (exprOp->value4 != NULL) && 11912 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER)) 11913 { 11914 double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval; 11915 11916 /* 11917 * We have a "[n]" predicate here. 11918 * TODO: Unfortunately this simplistic test here is not 11919 * able to detect a position() predicate in compound 11920 * expressions like "[@attr = 'a" and position() = 1], 11921 * and even not the usage of position() in 11922 * "[position() = 1]"; thus - obviously - a position-range, 11923 * like it "[position() < 5]", is also not detected. 11924 * Maybe we could rewrite the AST to ease the optimization. 11925 */ 11926 11927 if ((floatval > INT_MIN) && (floatval < INT_MAX)) { 11928 *maxPos = (int) floatval; 11929 if (floatval == (double) *maxPos) 11930 return(1); 11931 } 11932 } 11933 return(0); 11934 } 11935 11936 static int 11937 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, 11938 xmlXPathStepOpPtr op, 11939 xmlNodePtr * first, xmlNodePtr * last, 11940 int toBool) 11941 { 11942 11943 #define XP_TEST_HIT \ 11944 if (hasAxisRange != 0) { \ 11945 if (++pos == maxPos) { \ 11946 if (addNode(seq, cur) < 0) \ 11947 ctxt->error = XPATH_MEMORY_ERROR; \ 11948 goto axis_range_end; } \ 11949 } else { \ 11950 if (addNode(seq, cur) < 0) \ 11951 ctxt->error = XPATH_MEMORY_ERROR; \ 11952 if (breakOnFirstHit) goto first_hit; } 11953 11954 #define XP_TEST_HIT_NS \ 11955 if (hasAxisRange != 0) { \ 11956 if (++pos == maxPos) { \ 11957 hasNsNodes = 1; \ 11958 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \ 11959 ctxt->error = XPATH_MEMORY_ERROR; \ 11960 goto axis_range_end; } \ 11961 } else { \ 11962 hasNsNodes = 1; \ 11963 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \ 11964 ctxt->error = XPATH_MEMORY_ERROR; \ 11965 if (breakOnFirstHit) goto first_hit; } 11966 11967 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value; 11968 xmlXPathTestVal test = (xmlXPathTestVal) op->value2; 11969 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3; 11970 const xmlChar *prefix = op->value4; 11971 const xmlChar *name = op->value5; 11972 const xmlChar *URI = NULL; 11973 11974 #ifdef DEBUG_STEP 11975 int nbMatches = 0, prevMatches = 0; 11976 #endif 11977 int total = 0, hasNsNodes = 0; 11978 /* The popped object holding the context nodes */ 11979 xmlXPathObjectPtr obj; 11980 /* The set of context nodes for the node tests */ 11981 xmlNodeSetPtr contextSeq; 11982 int contextIdx; 11983 xmlNodePtr contextNode; 11984 /* The final resulting node set wrt to all context nodes */ 11985 xmlNodeSetPtr outSeq; 11986 /* 11987 * The temporary resulting node set wrt 1 context node. 11988 * Used to feed predicate evaluation. 11989 */ 11990 xmlNodeSetPtr seq; 11991 xmlNodePtr cur; 11992 /* First predicate operator */ 11993 xmlXPathStepOpPtr predOp; 11994 int maxPos; /* The requested position() (when a "[n]" predicate) */ 11995 int hasPredicateRange, hasAxisRange, pos; 11996 int breakOnFirstHit; 11997 11998 xmlXPathTraversalFunction next = NULL; 11999 int (*addNode) (xmlNodeSetPtr, xmlNodePtr); 12000 xmlXPathNodeSetMergeFunction mergeAndClear; 12001 xmlNodePtr oldContextNode; 12002 xmlXPathContextPtr xpctxt = ctxt->context; 12003 12004 12005 CHECK_TYPE0(XPATH_NODESET); 12006 obj = valuePop(ctxt); 12007 /* 12008 * Setup namespaces. 12009 */ 12010 if (prefix != NULL) { 12011 URI = xmlXPathNsLookup(xpctxt, prefix); 12012 if (URI == NULL) { 12013 xmlXPathReleaseObject(xpctxt, obj); 12014 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); 12015 } 12016 } 12017 /* 12018 * Setup axis. 12019 * 12020 * MAYBE FUTURE TODO: merging optimizations: 12021 * - If the nodes to be traversed wrt to the initial nodes and 12022 * the current axis cannot overlap, then we could avoid searching 12023 * for duplicates during the merge. 12024 * But the question is how/when to evaluate if they cannot overlap. 12025 * Example: if we know that for two initial nodes, the one is 12026 * not in the ancestor-or-self axis of the other, then we could safely 12027 * avoid a duplicate-aware merge, if the axis to be traversed is e.g. 12028 * the descendant-or-self axis. 12029 */ 12030 mergeAndClear = xmlXPathNodeSetMergeAndClear; 12031 switch (axis) { 12032 case AXIS_ANCESTOR: 12033 first = NULL; 12034 next = xmlXPathNextAncestor; 12035 break; 12036 case AXIS_ANCESTOR_OR_SELF: 12037 first = NULL; 12038 next = xmlXPathNextAncestorOrSelf; 12039 break; 12040 case AXIS_ATTRIBUTE: 12041 first = NULL; 12042 last = NULL; 12043 next = xmlXPathNextAttribute; 12044 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12045 break; 12046 case AXIS_CHILD: 12047 last = NULL; 12048 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) && 12049 (type == NODE_TYPE_NODE)) 12050 { 12051 /* 12052 * Optimization if an element node type is 'element'. 12053 */ 12054 next = xmlXPathNextChildElement; 12055 } else 12056 next = xmlXPathNextChild; 12057 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12058 break; 12059 case AXIS_DESCENDANT: 12060 last = NULL; 12061 next = xmlXPathNextDescendant; 12062 break; 12063 case AXIS_DESCENDANT_OR_SELF: 12064 last = NULL; 12065 next = xmlXPathNextDescendantOrSelf; 12066 break; 12067 case AXIS_FOLLOWING: 12068 last = NULL; 12069 next = xmlXPathNextFollowing; 12070 break; 12071 case AXIS_FOLLOWING_SIBLING: 12072 last = NULL; 12073 next = xmlXPathNextFollowingSibling; 12074 break; 12075 case AXIS_NAMESPACE: 12076 first = NULL; 12077 last = NULL; 12078 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; 12079 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12080 break; 12081 case AXIS_PARENT: 12082 first = NULL; 12083 next = xmlXPathNextParent; 12084 break; 12085 case AXIS_PRECEDING: 12086 first = NULL; 12087 next = xmlXPathNextPrecedingInternal; 12088 break; 12089 case AXIS_PRECEDING_SIBLING: 12090 first = NULL; 12091 next = xmlXPathNextPrecedingSibling; 12092 break; 12093 case AXIS_SELF: 12094 first = NULL; 12095 last = NULL; 12096 next = xmlXPathNextSelf; 12097 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12098 break; 12099 } 12100 12101 #ifdef DEBUG_STEP 12102 xmlXPathDebugDumpStepAxis(op, 12103 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0); 12104 #endif 12105 12106 if (next == NULL) { 12107 xmlXPathReleaseObject(xpctxt, obj); 12108 return(0); 12109 } 12110 contextSeq = obj->nodesetval; 12111 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) { 12112 xmlXPathReleaseObject(xpctxt, obj); 12113 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL)); 12114 return(0); 12115 } 12116 /* 12117 * Predicate optimization --------------------------------------------- 12118 * If this step has a last predicate, which contains a position(), 12119 * then we'll optimize (although not exactly "position()", but only 12120 * the short-hand form, i.e., "[n]". 12121 * 12122 * Example - expression "/foo[parent::bar][1]": 12123 * 12124 * COLLECT 'child' 'name' 'node' foo -- op (we are here) 12125 * ROOT -- op->ch1 12126 * PREDICATE -- op->ch2 (predOp) 12127 * PREDICATE -- predOp->ch1 = [parent::bar] 12128 * SORT 12129 * COLLECT 'parent' 'name' 'node' bar 12130 * NODE 12131 * ELEM Object is a number : 1 -- predOp->ch2 = [1] 12132 * 12133 */ 12134 maxPos = 0; 12135 predOp = NULL; 12136 hasPredicateRange = 0; 12137 hasAxisRange = 0; 12138 if (op->ch2 != -1) { 12139 /* 12140 * There's at least one predicate. 16 == XPATH_OP_PREDICATE 12141 */ 12142 predOp = &ctxt->comp->steps[op->ch2]; 12143 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) { 12144 if (predOp->ch1 != -1) { 12145 /* 12146 * Use the next inner predicate operator. 12147 */ 12148 predOp = &ctxt->comp->steps[predOp->ch1]; 12149 hasPredicateRange = 1; 12150 } else { 12151 /* 12152 * There's no other predicate than the [n] predicate. 12153 */ 12154 predOp = NULL; 12155 hasAxisRange = 1; 12156 } 12157 } 12158 } 12159 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0; 12160 /* 12161 * Axis traversal ----------------------------------------------------- 12162 */ 12163 /* 12164 * 2.3 Node Tests 12165 * - For the attribute axis, the principal node type is attribute. 12166 * - For the namespace axis, the principal node type is namespace. 12167 * - For other axes, the principal node type is element. 12168 * 12169 * A node test * is true for any node of the 12170 * principal node type. For example, child::* will 12171 * select all element children of the context node 12172 */ 12173 oldContextNode = xpctxt->node; 12174 addNode = xmlXPathNodeSetAddUnique; 12175 outSeq = NULL; 12176 seq = NULL; 12177 contextNode = NULL; 12178 contextIdx = 0; 12179 12180 12181 while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) && 12182 (ctxt->error == XPATH_EXPRESSION_OK)) { 12183 xpctxt->node = contextSeq->nodeTab[contextIdx++]; 12184 12185 if (seq == NULL) { 12186 seq = xmlXPathNodeSetCreate(NULL); 12187 if (seq == NULL) { 12188 /* TODO: Propagate memory error. */ 12189 total = 0; 12190 goto error; 12191 } 12192 } 12193 /* 12194 * Traverse the axis and test the nodes. 12195 */ 12196 pos = 0; 12197 cur = NULL; 12198 hasNsNodes = 0; 12199 do { 12200 if (OP_LIMIT_EXCEEDED(ctxt, 1)) 12201 goto error; 12202 12203 cur = next(ctxt, cur); 12204 if (cur == NULL) 12205 break; 12206 12207 /* 12208 * QUESTION TODO: What does the "first" and "last" stuff do? 12209 */ 12210 if ((first != NULL) && (*first != NULL)) { 12211 if (*first == cur) 12212 break; 12213 if (((total % 256) == 0) && 12214 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 12215 (xmlXPathCmpNodesExt(*first, cur) >= 0)) 12216 #else 12217 (xmlXPathCmpNodes(*first, cur) >= 0)) 12218 #endif 12219 { 12220 break; 12221 } 12222 } 12223 if ((last != NULL) && (*last != NULL)) { 12224 if (*last == cur) 12225 break; 12226 if (((total % 256) == 0) && 12227 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 12228 (xmlXPathCmpNodesExt(cur, *last) >= 0)) 12229 #else 12230 (xmlXPathCmpNodes(cur, *last) >= 0)) 12231 #endif 12232 { 12233 break; 12234 } 12235 } 12236 12237 total++; 12238 12239 #ifdef DEBUG_STEP 12240 xmlGenericError(xmlGenericErrorContext, " %s", cur->name); 12241 #endif 12242 12243 switch (test) { 12244 case NODE_TEST_NONE: 12245 total = 0; 12246 STRANGE 12247 goto error; 12248 case NODE_TEST_TYPE: 12249 if (type == NODE_TYPE_NODE) { 12250 switch (cur->type) { 12251 case XML_DOCUMENT_NODE: 12252 case XML_HTML_DOCUMENT_NODE: 12253 #ifdef LIBXML_DOCB_ENABLED 12254 case XML_DOCB_DOCUMENT_NODE: 12255 #endif 12256 case XML_ELEMENT_NODE: 12257 case XML_ATTRIBUTE_NODE: 12258 case XML_PI_NODE: 12259 case XML_COMMENT_NODE: 12260 case XML_CDATA_SECTION_NODE: 12261 case XML_TEXT_NODE: 12262 XP_TEST_HIT 12263 break; 12264 case XML_NAMESPACE_DECL: { 12265 if (axis == AXIS_NAMESPACE) { 12266 XP_TEST_HIT_NS 12267 } else { 12268 hasNsNodes = 1; 12269 XP_TEST_HIT 12270 } 12271 break; 12272 } 12273 default: 12274 break; 12275 } 12276 } else if (cur->type == (xmlElementType) type) { 12277 if (cur->type == XML_NAMESPACE_DECL) 12278 XP_TEST_HIT_NS 12279 else 12280 XP_TEST_HIT 12281 } else if ((type == NODE_TYPE_TEXT) && 12282 (cur->type == XML_CDATA_SECTION_NODE)) 12283 { 12284 XP_TEST_HIT 12285 } 12286 break; 12287 case NODE_TEST_PI: 12288 if ((cur->type == XML_PI_NODE) && 12289 ((name == NULL) || xmlStrEqual(name, cur->name))) 12290 { 12291 XP_TEST_HIT 12292 } 12293 break; 12294 case NODE_TEST_ALL: 12295 if (axis == AXIS_ATTRIBUTE) { 12296 if (cur->type == XML_ATTRIBUTE_NODE) 12297 { 12298 if (prefix == NULL) 12299 { 12300 XP_TEST_HIT 12301 } else if ((cur->ns != NULL) && 12302 (xmlStrEqual(URI, cur->ns->href))) 12303 { 12304 XP_TEST_HIT 12305 } 12306 } 12307 } else if (axis == AXIS_NAMESPACE) { 12308 if (cur->type == XML_NAMESPACE_DECL) 12309 { 12310 XP_TEST_HIT_NS 12311 } 12312 } else { 12313 if (cur->type == XML_ELEMENT_NODE) { 12314 if (prefix == NULL) 12315 { 12316 XP_TEST_HIT 12317 12318 } else if ((cur->ns != NULL) && 12319 (xmlStrEqual(URI, cur->ns->href))) 12320 { 12321 XP_TEST_HIT 12322 } 12323 } 12324 } 12325 break; 12326 case NODE_TEST_NS:{ 12327 TODO; 12328 break; 12329 } 12330 case NODE_TEST_NAME: 12331 if (axis == AXIS_ATTRIBUTE) { 12332 if (cur->type != XML_ATTRIBUTE_NODE) 12333 break; 12334 } else if (axis == AXIS_NAMESPACE) { 12335 if (cur->type != XML_NAMESPACE_DECL) 12336 break; 12337 } else { 12338 if (cur->type != XML_ELEMENT_NODE) 12339 break; 12340 } 12341 switch (cur->type) { 12342 case XML_ELEMENT_NODE: 12343 if (xmlStrEqual(name, cur->name)) { 12344 if (prefix == NULL) { 12345 if (cur->ns == NULL) 12346 { 12347 XP_TEST_HIT 12348 } 12349 } else { 12350 if ((cur->ns != NULL) && 12351 (xmlStrEqual(URI, cur->ns->href))) 12352 { 12353 XP_TEST_HIT 12354 } 12355 } 12356 } 12357 break; 12358 case XML_ATTRIBUTE_NODE:{ 12359 xmlAttrPtr attr = (xmlAttrPtr) cur; 12360 12361 if (xmlStrEqual(name, attr->name)) { 12362 if (prefix == NULL) { 12363 if ((attr->ns == NULL) || 12364 (attr->ns->prefix == NULL)) 12365 { 12366 XP_TEST_HIT 12367 } 12368 } else { 12369 if ((attr->ns != NULL) && 12370 (xmlStrEqual(URI, 12371 attr->ns->href))) 12372 { 12373 XP_TEST_HIT 12374 } 12375 } 12376 } 12377 break; 12378 } 12379 case XML_NAMESPACE_DECL: 12380 if (cur->type == XML_NAMESPACE_DECL) { 12381 xmlNsPtr ns = (xmlNsPtr) cur; 12382 12383 if ((ns->prefix != NULL) && (name != NULL) 12384 && (xmlStrEqual(ns->prefix, name))) 12385 { 12386 XP_TEST_HIT_NS 12387 } 12388 } 12389 break; 12390 default: 12391 break; 12392 } 12393 break; 12394 } /* switch(test) */ 12395 } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK)); 12396 12397 goto apply_predicates; 12398 12399 axis_range_end: /* ----------------------------------------------------- */ 12400 /* 12401 * We have a "/foo[n]", and position() = n was reached. 12402 * Note that we can have as well "/foo/::parent::foo[1]", so 12403 * a duplicate-aware merge is still needed. 12404 * Merge with the result. 12405 */ 12406 if (outSeq == NULL) { 12407 outSeq = seq; 12408 seq = NULL; 12409 } else 12410 /* TODO: Check memory error. */ 12411 outSeq = mergeAndClear(outSeq, seq); 12412 /* 12413 * Break if only a true/false result was requested. 12414 */ 12415 if (toBool) 12416 break; 12417 continue; 12418 12419 first_hit: /* ---------------------------------------------------------- */ 12420 /* 12421 * Break if only a true/false result was requested and 12422 * no predicates existed and a node test succeeded. 12423 */ 12424 if (outSeq == NULL) { 12425 outSeq = seq; 12426 seq = NULL; 12427 } else 12428 /* TODO: Check memory error. */ 12429 outSeq = mergeAndClear(outSeq, seq); 12430 break; 12431 12432 #ifdef DEBUG_STEP 12433 if (seq != NULL) 12434 nbMatches += seq->nodeNr; 12435 #endif 12436 12437 apply_predicates: /* --------------------------------------------------- */ 12438 if (ctxt->error != XPATH_EXPRESSION_OK) 12439 goto error; 12440 12441 /* 12442 * Apply predicates. 12443 */ 12444 if ((predOp != NULL) && (seq->nodeNr > 0)) { 12445 /* 12446 * E.g. when we have a "/foo[some expression][n]". 12447 */ 12448 /* 12449 * QUESTION TODO: The old predicate evaluation took into 12450 * account location-sets. 12451 * (E.g. ctxt->value->type == XPATH_LOCATIONSET) 12452 * Do we expect such a set here? 12453 * All what I learned now from the evaluation semantics 12454 * does not indicate that a location-set will be processed 12455 * here, so this looks OK. 12456 */ 12457 /* 12458 * Iterate over all predicates, starting with the outermost 12459 * predicate. 12460 * TODO: Problem: we cannot execute the inner predicates first 12461 * since we cannot go back *up* the operator tree! 12462 * Options we have: 12463 * 1) Use of recursive functions (like is it currently done 12464 * via xmlXPathCompOpEval()) 12465 * 2) Add a predicate evaluation information stack to the 12466 * context struct 12467 * 3) Change the way the operators are linked; we need a 12468 * "parent" field on xmlXPathStepOp 12469 * 12470 * For the moment, I'll try to solve this with a recursive 12471 * function: xmlXPathCompOpEvalPredicate(). 12472 */ 12473 if (hasPredicateRange != 0) 12474 xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos, 12475 hasNsNodes); 12476 else 12477 xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr, 12478 hasNsNodes); 12479 12480 if (ctxt->error != XPATH_EXPRESSION_OK) { 12481 total = 0; 12482 goto error; 12483 } 12484 } 12485 12486 if (seq->nodeNr > 0) { 12487 /* 12488 * Add to result set. 12489 */ 12490 if (outSeq == NULL) { 12491 outSeq = seq; 12492 seq = NULL; 12493 } else { 12494 /* TODO: Check memory error. */ 12495 outSeq = mergeAndClear(outSeq, seq); 12496 } 12497 12498 if (toBool) 12499 break; 12500 } 12501 } 12502 12503 error: 12504 if ((obj->boolval) && (obj->user != NULL)) { 12505 /* 12506 * QUESTION TODO: What does this do and why? 12507 * TODO: Do we have to do this also for the "error" 12508 * cleanup further down? 12509 */ 12510 ctxt->value->boolval = 1; 12511 ctxt->value->user = obj->user; 12512 obj->user = NULL; 12513 obj->boolval = 0; 12514 } 12515 xmlXPathReleaseObject(xpctxt, obj); 12516 12517 /* 12518 * Ensure we return at least an empty set. 12519 */ 12520 if (outSeq == NULL) { 12521 if ((seq != NULL) && (seq->nodeNr == 0)) 12522 outSeq = seq; 12523 else 12524 /* TODO: Check memory error. */ 12525 outSeq = xmlXPathNodeSetCreate(NULL); 12526 } 12527 if ((seq != NULL) && (seq != outSeq)) { 12528 xmlXPathFreeNodeSet(seq); 12529 } 12530 /* 12531 * Hand over the result. Better to push the set also in 12532 * case of errors. 12533 */ 12534 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq)); 12535 /* 12536 * Reset the context node. 12537 */ 12538 xpctxt->node = oldContextNode; 12539 /* 12540 * When traversing the namespace axis in "toBool" mode, it's 12541 * possible that tmpNsList wasn't freed. 12542 */ 12543 if (xpctxt->tmpNsList != NULL) { 12544 xmlFree(xpctxt->tmpNsList); 12545 xpctxt->tmpNsList = NULL; 12546 } 12547 12548 #ifdef DEBUG_STEP 12549 xmlGenericError(xmlGenericErrorContext, 12550 "\nExamined %d nodes, found %d nodes at that step\n", 12551 total, nbMatches); 12552 #endif 12553 12554 return(total); 12555 } 12556 12557 static int 12558 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt, 12559 xmlXPathStepOpPtr op, xmlNodePtr * first); 12560 12561 /** 12562 * xmlXPathCompOpEvalFirst: 12563 * @ctxt: the XPath parser context with the compiled expression 12564 * @op: an XPath compiled operation 12565 * @first: the first elem found so far 12566 * 12567 * Evaluate the Precompiled XPath operation searching only the first 12568 * element in document order 12569 * 12570 * Returns the number of examined objects. 12571 */ 12572 static int 12573 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt, 12574 xmlXPathStepOpPtr op, xmlNodePtr * first) 12575 { 12576 int total = 0, cur; 12577 xmlXPathCompExprPtr comp; 12578 xmlXPathObjectPtr arg1, arg2; 12579 12580 CHECK_ERROR0; 12581 if (OP_LIMIT_EXCEEDED(ctxt, 1)) 12582 return(0); 12583 if (ctxt->context->depth >= ctxt->context->maxDepth) 12584 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED); 12585 ctxt->context->depth += 1; 12586 comp = ctxt->comp; 12587 switch (op->op) { 12588 case XPATH_OP_END: 12589 break; 12590 case XPATH_OP_UNION: 12591 total = 12592 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1], 12593 first); 12594 CHECK_ERROR0; 12595 if ((ctxt->value != NULL) 12596 && (ctxt->value->type == XPATH_NODESET) 12597 && (ctxt->value->nodesetval != NULL) 12598 && (ctxt->value->nodesetval->nodeNr >= 1)) { 12599 /* 12600 * limit tree traversing to first node in the result 12601 */ 12602 /* 12603 * OPTIMIZE TODO: This implicitly sorts 12604 * the result, even if not needed. E.g. if the argument 12605 * of the count() function, no sorting is needed. 12606 * OPTIMIZE TODO: How do we know if the node-list wasn't 12607 * already sorted? 12608 */ 12609 if (ctxt->value->nodesetval->nodeNr > 1) 12610 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12611 *first = ctxt->value->nodesetval->nodeTab[0]; 12612 } 12613 cur = 12614 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2], 12615 first); 12616 CHECK_ERROR0; 12617 12618 arg2 = valuePop(ctxt); 12619 arg1 = valuePop(ctxt); 12620 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) || 12621 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) { 12622 xmlXPathReleaseObject(ctxt->context, arg1); 12623 xmlXPathReleaseObject(ctxt->context, arg2); 12624 XP_ERROR0(XPATH_INVALID_TYPE); 12625 } 12626 if ((ctxt->context->opLimit != 0) && 12627 (((arg1->nodesetval != NULL) && 12628 (xmlXPathCheckOpLimit(ctxt, 12629 arg1->nodesetval->nodeNr) < 0)) || 12630 ((arg2->nodesetval != NULL) && 12631 (xmlXPathCheckOpLimit(ctxt, 12632 arg2->nodesetval->nodeNr) < 0)))) { 12633 xmlXPathReleaseObject(ctxt->context, arg1); 12634 xmlXPathReleaseObject(ctxt->context, arg2); 12635 break; 12636 } 12637 12638 /* TODO: Check memory error. */ 12639 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 12640 arg2->nodesetval); 12641 valuePush(ctxt, arg1); 12642 xmlXPathReleaseObject(ctxt->context, arg2); 12643 /* optimizer */ 12644 if (total > cur) 12645 xmlXPathCompSwap(op); 12646 total += cur; 12647 break; 12648 case XPATH_OP_ROOT: 12649 xmlXPathRoot(ctxt); 12650 break; 12651 case XPATH_OP_NODE: 12652 if (op->ch1 != -1) 12653 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12654 CHECK_ERROR0; 12655 if (op->ch2 != -1) 12656 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12657 CHECK_ERROR0; 12658 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 12659 ctxt->context->node)); 12660 break; 12661 case XPATH_OP_COLLECT:{ 12662 if (op->ch1 == -1) 12663 break; 12664 12665 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12666 CHECK_ERROR0; 12667 12668 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0); 12669 break; 12670 } 12671 case XPATH_OP_VALUE: 12672 valuePush(ctxt, 12673 xmlXPathCacheObjectCopy(ctxt->context, 12674 (xmlXPathObjectPtr) op->value4)); 12675 break; 12676 case XPATH_OP_SORT: 12677 if (op->ch1 != -1) 12678 total += 12679 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1], 12680 first); 12681 CHECK_ERROR0; 12682 if ((ctxt->value != NULL) 12683 && (ctxt->value->type == XPATH_NODESET) 12684 && (ctxt->value->nodesetval != NULL) 12685 && (ctxt->value->nodesetval->nodeNr > 1)) 12686 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12687 break; 12688 #ifdef XP_OPTIMIZED_FILTER_FIRST 12689 case XPATH_OP_FILTER: 12690 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first); 12691 break; 12692 #endif 12693 default: 12694 total += xmlXPathCompOpEval(ctxt, op); 12695 break; 12696 } 12697 12698 ctxt->context->depth -= 1; 12699 return(total); 12700 } 12701 12702 /** 12703 * xmlXPathCompOpEvalLast: 12704 * @ctxt: the XPath parser context with the compiled expression 12705 * @op: an XPath compiled operation 12706 * @last: the last elem found so far 12707 * 12708 * Evaluate the Precompiled XPath operation searching only the last 12709 * element in document order 12710 * 12711 * Returns the number of nodes traversed 12712 */ 12713 static int 12714 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op, 12715 xmlNodePtr * last) 12716 { 12717 int total = 0, cur; 12718 xmlXPathCompExprPtr comp; 12719 xmlXPathObjectPtr arg1, arg2; 12720 12721 CHECK_ERROR0; 12722 if (OP_LIMIT_EXCEEDED(ctxt, 1)) 12723 return(0); 12724 if (ctxt->context->depth >= ctxt->context->maxDepth) 12725 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED); 12726 ctxt->context->depth += 1; 12727 comp = ctxt->comp; 12728 switch (op->op) { 12729 case XPATH_OP_END: 12730 break; 12731 case XPATH_OP_UNION: 12732 total = 12733 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last); 12734 CHECK_ERROR0; 12735 if ((ctxt->value != NULL) 12736 && (ctxt->value->type == XPATH_NODESET) 12737 && (ctxt->value->nodesetval != NULL) 12738 && (ctxt->value->nodesetval->nodeNr >= 1)) { 12739 /* 12740 * limit tree traversing to first node in the result 12741 */ 12742 if (ctxt->value->nodesetval->nodeNr > 1) 12743 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12744 *last = 12745 ctxt->value->nodesetval->nodeTab[ctxt->value-> 12746 nodesetval->nodeNr - 12747 1]; 12748 } 12749 cur = 12750 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last); 12751 CHECK_ERROR0; 12752 if ((ctxt->value != NULL) 12753 && (ctxt->value->type == XPATH_NODESET) 12754 && (ctxt->value->nodesetval != NULL) 12755 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */ 12756 } 12757 12758 arg2 = valuePop(ctxt); 12759 arg1 = valuePop(ctxt); 12760 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) || 12761 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) { 12762 xmlXPathReleaseObject(ctxt->context, arg1); 12763 xmlXPathReleaseObject(ctxt->context, arg2); 12764 XP_ERROR0(XPATH_INVALID_TYPE); 12765 } 12766 if ((ctxt->context->opLimit != 0) && 12767 (((arg1->nodesetval != NULL) && 12768 (xmlXPathCheckOpLimit(ctxt, 12769 arg1->nodesetval->nodeNr) < 0)) || 12770 ((arg2->nodesetval != NULL) && 12771 (xmlXPathCheckOpLimit(ctxt, 12772 arg2->nodesetval->nodeNr) < 0)))) { 12773 xmlXPathReleaseObject(ctxt->context, arg1); 12774 xmlXPathReleaseObject(ctxt->context, arg2); 12775 break; 12776 } 12777 12778 /* TODO: Check memory error. */ 12779 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 12780 arg2->nodesetval); 12781 valuePush(ctxt, arg1); 12782 xmlXPathReleaseObject(ctxt->context, arg2); 12783 /* optimizer */ 12784 if (total > cur) 12785 xmlXPathCompSwap(op); 12786 total += cur; 12787 break; 12788 case XPATH_OP_ROOT: 12789 xmlXPathRoot(ctxt); 12790 break; 12791 case XPATH_OP_NODE: 12792 if (op->ch1 != -1) 12793 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12794 CHECK_ERROR0; 12795 if (op->ch2 != -1) 12796 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12797 CHECK_ERROR0; 12798 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 12799 ctxt->context->node)); 12800 break; 12801 case XPATH_OP_COLLECT:{ 12802 if (op->ch1 == -1) 12803 break; 12804 12805 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12806 CHECK_ERROR0; 12807 12808 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0); 12809 break; 12810 } 12811 case XPATH_OP_VALUE: 12812 valuePush(ctxt, 12813 xmlXPathCacheObjectCopy(ctxt->context, 12814 (xmlXPathObjectPtr) op->value4)); 12815 break; 12816 case XPATH_OP_SORT: 12817 if (op->ch1 != -1) 12818 total += 12819 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], 12820 last); 12821 CHECK_ERROR0; 12822 if ((ctxt->value != NULL) 12823 && (ctxt->value->type == XPATH_NODESET) 12824 && (ctxt->value->nodesetval != NULL) 12825 && (ctxt->value->nodesetval->nodeNr > 1)) 12826 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12827 break; 12828 default: 12829 total += xmlXPathCompOpEval(ctxt, op); 12830 break; 12831 } 12832 12833 ctxt->context->depth -= 1; 12834 return (total); 12835 } 12836 12837 #ifdef XP_OPTIMIZED_FILTER_FIRST 12838 static int 12839 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt, 12840 xmlXPathStepOpPtr op, xmlNodePtr * first) 12841 { 12842 int total = 0; 12843 xmlXPathCompExprPtr comp; 12844 xmlNodeSetPtr set; 12845 12846 CHECK_ERROR0; 12847 comp = ctxt->comp; 12848 /* 12849 * Optimization for ()[last()] selection i.e. the last elem 12850 */ 12851 if ((op->ch1 != -1) && (op->ch2 != -1) && 12852 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 12853 (comp->steps[op->ch2].op == XPATH_OP_SORT)) { 12854 int f = comp->steps[op->ch2].ch1; 12855 12856 if ((f != -1) && 12857 (comp->steps[f].op == XPATH_OP_FUNCTION) && 12858 (comp->steps[f].value5 == NULL) && 12859 (comp->steps[f].value == 0) && 12860 (comp->steps[f].value4 != NULL) && 12861 (xmlStrEqual 12862 (comp->steps[f].value4, BAD_CAST "last"))) { 12863 xmlNodePtr last = NULL; 12864 12865 total += 12866 xmlXPathCompOpEvalLast(ctxt, 12867 &comp->steps[op->ch1], 12868 &last); 12869 CHECK_ERROR0; 12870 /* 12871 * The nodeset should be in document order, 12872 * Keep only the last value 12873 */ 12874 if ((ctxt->value != NULL) && 12875 (ctxt->value->type == XPATH_NODESET) && 12876 (ctxt->value->nodesetval != NULL) && 12877 (ctxt->value->nodesetval->nodeTab != NULL) && 12878 (ctxt->value->nodesetval->nodeNr > 1)) { 12879 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval); 12880 *first = *(ctxt->value->nodesetval->nodeTab); 12881 } 12882 return (total); 12883 } 12884 } 12885 12886 if (op->ch1 != -1) 12887 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12888 CHECK_ERROR0; 12889 if (op->ch2 == -1) 12890 return (total); 12891 if (ctxt->value == NULL) 12892 return (total); 12893 12894 #ifdef LIBXML_XPTR_ENABLED 12895 /* 12896 * Hum are we filtering the result of an XPointer expression 12897 */ 12898 if (ctxt->value->type == XPATH_LOCATIONSET) { 12899 xmlLocationSetPtr locset = ctxt->value->user; 12900 12901 if (locset != NULL) { 12902 xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1); 12903 if (locset->locNr > 0) 12904 *first = (xmlNodePtr) locset->locTab[0]->user; 12905 } 12906 12907 return (total); 12908 } 12909 #endif /* LIBXML_XPTR_ENABLED */ 12910 12911 CHECK_TYPE0(XPATH_NODESET); 12912 set = ctxt->value->nodesetval; 12913 if (set != NULL) { 12914 xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1); 12915 if (set->nodeNr > 0) 12916 *first = set->nodeTab[0]; 12917 } 12918 12919 return (total); 12920 } 12921 #endif /* XP_OPTIMIZED_FILTER_FIRST */ 12922 12923 /** 12924 * xmlXPathCompOpEval: 12925 * @ctxt: the XPath parser context with the compiled expression 12926 * @op: an XPath compiled operation 12927 * 12928 * Evaluate the Precompiled XPath operation 12929 * Returns the number of nodes traversed 12930 */ 12931 static int 12932 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) 12933 { 12934 int total = 0; 12935 int equal, ret; 12936 xmlXPathCompExprPtr comp; 12937 xmlXPathObjectPtr arg1, arg2; 12938 12939 CHECK_ERROR0; 12940 if (OP_LIMIT_EXCEEDED(ctxt, 1)) 12941 return(0); 12942 if (ctxt->context->depth >= ctxt->context->maxDepth) 12943 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED); 12944 ctxt->context->depth += 1; 12945 comp = ctxt->comp; 12946 switch (op->op) { 12947 case XPATH_OP_END: 12948 break; 12949 case XPATH_OP_AND: 12950 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12951 CHECK_ERROR0; 12952 xmlXPathBooleanFunction(ctxt, 1); 12953 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0)) 12954 break; 12955 arg2 = valuePop(ctxt); 12956 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12957 if (ctxt->error) { 12958 xmlXPathFreeObject(arg2); 12959 break; 12960 } 12961 xmlXPathBooleanFunction(ctxt, 1); 12962 if (ctxt->value != NULL) 12963 ctxt->value->boolval &= arg2->boolval; 12964 xmlXPathReleaseObject(ctxt->context, arg2); 12965 break; 12966 case XPATH_OP_OR: 12967 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12968 CHECK_ERROR0; 12969 xmlXPathBooleanFunction(ctxt, 1); 12970 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1)) 12971 break; 12972 arg2 = valuePop(ctxt); 12973 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12974 if (ctxt->error) { 12975 xmlXPathFreeObject(arg2); 12976 break; 12977 } 12978 xmlXPathBooleanFunction(ctxt, 1); 12979 if (ctxt->value != NULL) 12980 ctxt->value->boolval |= arg2->boolval; 12981 xmlXPathReleaseObject(ctxt->context, arg2); 12982 break; 12983 case XPATH_OP_EQUAL: 12984 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12985 CHECK_ERROR0; 12986 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12987 CHECK_ERROR0; 12988 if (op->value) 12989 equal = xmlXPathEqualValues(ctxt); 12990 else 12991 equal = xmlXPathNotEqualValues(ctxt); 12992 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal)); 12993 break; 12994 case XPATH_OP_CMP: 12995 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12996 CHECK_ERROR0; 12997 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12998 CHECK_ERROR0; 12999 ret = xmlXPathCompareValues(ctxt, op->value, op->value2); 13000 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret)); 13001 break; 13002 case XPATH_OP_PLUS: 13003 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13004 CHECK_ERROR0; 13005 if (op->ch2 != -1) { 13006 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13007 } 13008 CHECK_ERROR0; 13009 if (op->value == 0) 13010 xmlXPathSubValues(ctxt); 13011 else if (op->value == 1) 13012 xmlXPathAddValues(ctxt); 13013 else if (op->value == 2) 13014 xmlXPathValueFlipSign(ctxt); 13015 else if (op->value == 3) { 13016 CAST_TO_NUMBER; 13017 CHECK_TYPE0(XPATH_NUMBER); 13018 } 13019 break; 13020 case XPATH_OP_MULT: 13021 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13022 CHECK_ERROR0; 13023 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13024 CHECK_ERROR0; 13025 if (op->value == 0) 13026 xmlXPathMultValues(ctxt); 13027 else if (op->value == 1) 13028 xmlXPathDivValues(ctxt); 13029 else if (op->value == 2) 13030 xmlXPathModValues(ctxt); 13031 break; 13032 case XPATH_OP_UNION: 13033 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13034 CHECK_ERROR0; 13035 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13036 CHECK_ERROR0; 13037 13038 arg2 = valuePop(ctxt); 13039 arg1 = valuePop(ctxt); 13040 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) || 13041 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) { 13042 xmlXPathReleaseObject(ctxt->context, arg1); 13043 xmlXPathReleaseObject(ctxt->context, arg2); 13044 XP_ERROR0(XPATH_INVALID_TYPE); 13045 } 13046 if ((ctxt->context->opLimit != 0) && 13047 (((arg1->nodesetval != NULL) && 13048 (xmlXPathCheckOpLimit(ctxt, 13049 arg1->nodesetval->nodeNr) < 0)) || 13050 ((arg2->nodesetval != NULL) && 13051 (xmlXPathCheckOpLimit(ctxt, 13052 arg2->nodesetval->nodeNr) < 0)))) { 13053 xmlXPathReleaseObject(ctxt->context, arg1); 13054 xmlXPathReleaseObject(ctxt->context, arg2); 13055 break; 13056 } 13057 13058 if ((arg1->nodesetval == NULL) || 13059 ((arg2->nodesetval != NULL) && 13060 (arg2->nodesetval->nodeNr != 0))) 13061 { 13062 /* TODO: Check memory error. */ 13063 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 13064 arg2->nodesetval); 13065 } 13066 13067 valuePush(ctxt, arg1); 13068 xmlXPathReleaseObject(ctxt->context, arg2); 13069 break; 13070 case XPATH_OP_ROOT: 13071 xmlXPathRoot(ctxt); 13072 break; 13073 case XPATH_OP_NODE: 13074 if (op->ch1 != -1) 13075 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13076 CHECK_ERROR0; 13077 if (op->ch2 != -1) 13078 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13079 CHECK_ERROR0; 13080 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 13081 ctxt->context->node)); 13082 break; 13083 case XPATH_OP_COLLECT:{ 13084 if (op->ch1 == -1) 13085 break; 13086 13087 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13088 CHECK_ERROR0; 13089 13090 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0); 13091 break; 13092 } 13093 case XPATH_OP_VALUE: 13094 valuePush(ctxt, 13095 xmlXPathCacheObjectCopy(ctxt->context, 13096 (xmlXPathObjectPtr) op->value4)); 13097 break; 13098 case XPATH_OP_VARIABLE:{ 13099 xmlXPathObjectPtr val; 13100 13101 if (op->ch1 != -1) 13102 total += 13103 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13104 if (op->value5 == NULL) { 13105 val = xmlXPathVariableLookup(ctxt->context, op->value4); 13106 if (val == NULL) 13107 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR); 13108 valuePush(ctxt, val); 13109 } else { 13110 const xmlChar *URI; 13111 13112 URI = xmlXPathNsLookup(ctxt->context, op->value5); 13113 if (URI == NULL) { 13114 xmlGenericError(xmlGenericErrorContext, 13115 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n", 13116 (char *) op->value4, (char *)op->value5); 13117 ctxt->error = XPATH_UNDEF_PREFIX_ERROR; 13118 break; 13119 } 13120 val = xmlXPathVariableLookupNS(ctxt->context, 13121 op->value4, URI); 13122 if (val == NULL) 13123 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR); 13124 valuePush(ctxt, val); 13125 } 13126 break; 13127 } 13128 case XPATH_OP_FUNCTION:{ 13129 xmlXPathFunction func; 13130 const xmlChar *oldFunc, *oldFuncURI; 13131 int i; 13132 int frame; 13133 13134 frame = xmlXPathSetFrame(ctxt); 13135 if (op->ch1 != -1) { 13136 total += 13137 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13138 if (ctxt->error != XPATH_EXPRESSION_OK) { 13139 xmlXPathPopFrame(ctxt, frame); 13140 break; 13141 } 13142 } 13143 if (ctxt->valueNr < ctxt->valueFrame + op->value) { 13144 xmlGenericError(xmlGenericErrorContext, 13145 "xmlXPathCompOpEval: parameter error\n"); 13146 ctxt->error = XPATH_INVALID_OPERAND; 13147 xmlXPathPopFrame(ctxt, frame); 13148 break; 13149 } 13150 for (i = 0; i < op->value; i++) { 13151 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) { 13152 xmlGenericError(xmlGenericErrorContext, 13153 "xmlXPathCompOpEval: parameter error\n"); 13154 ctxt->error = XPATH_INVALID_OPERAND; 13155 xmlXPathPopFrame(ctxt, frame); 13156 break; 13157 } 13158 } 13159 if (op->cache != NULL) 13160 func = op->cache; 13161 else { 13162 const xmlChar *URI = NULL; 13163 13164 if (op->value5 == NULL) 13165 func = 13166 xmlXPathFunctionLookup(ctxt->context, 13167 op->value4); 13168 else { 13169 URI = xmlXPathNsLookup(ctxt->context, op->value5); 13170 if (URI == NULL) { 13171 xmlGenericError(xmlGenericErrorContext, 13172 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n", 13173 (char *)op->value4, (char *)op->value5); 13174 xmlXPathPopFrame(ctxt, frame); 13175 ctxt->error = XPATH_UNDEF_PREFIX_ERROR; 13176 break; 13177 } 13178 func = xmlXPathFunctionLookupNS(ctxt->context, 13179 op->value4, URI); 13180 } 13181 if (func == NULL) { 13182 xmlGenericError(xmlGenericErrorContext, 13183 "xmlXPathCompOpEval: function %s not found\n", 13184 (char *)op->value4); 13185 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR); 13186 } 13187 op->cache = func; 13188 op->cacheURI = (void *) URI; 13189 } 13190 oldFunc = ctxt->context->function; 13191 oldFuncURI = ctxt->context->functionURI; 13192 ctxt->context->function = op->value4; 13193 ctxt->context->functionURI = op->cacheURI; 13194 func(ctxt, op->value); 13195 ctxt->context->function = oldFunc; 13196 ctxt->context->functionURI = oldFuncURI; 13197 if ((ctxt->error == XPATH_EXPRESSION_OK) && 13198 (ctxt->valueNr != ctxt->valueFrame + 1)) 13199 XP_ERROR0(XPATH_STACK_ERROR); 13200 xmlXPathPopFrame(ctxt, frame); 13201 break; 13202 } 13203 case XPATH_OP_ARG: 13204 if (op->ch1 != -1) { 13205 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13206 CHECK_ERROR0; 13207 } 13208 if (op->ch2 != -1) { 13209 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13210 CHECK_ERROR0; 13211 } 13212 break; 13213 case XPATH_OP_PREDICATE: 13214 case XPATH_OP_FILTER:{ 13215 xmlNodeSetPtr set; 13216 13217 /* 13218 * Optimization for ()[1] selection i.e. the first elem 13219 */ 13220 if ((op->ch1 != -1) && (op->ch2 != -1) && 13221 #ifdef XP_OPTIMIZED_FILTER_FIRST 13222 /* 13223 * FILTER TODO: Can we assume that the inner processing 13224 * will result in an ordered list if we have an 13225 * XPATH_OP_FILTER? 13226 * What about an additional field or flag on 13227 * xmlXPathObject like @sorted ? This way we wouldn't need 13228 * to assume anything, so it would be more robust and 13229 * easier to optimize. 13230 */ 13231 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */ 13232 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */ 13233 #else 13234 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 13235 #endif 13236 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */ 13237 xmlXPathObjectPtr val; 13238 13239 val = comp->steps[op->ch2].value4; 13240 if ((val != NULL) && (val->type == XPATH_NUMBER) && 13241 (val->floatval == 1.0)) { 13242 xmlNodePtr first = NULL; 13243 13244 total += 13245 xmlXPathCompOpEvalFirst(ctxt, 13246 &comp->steps[op->ch1], 13247 &first); 13248 CHECK_ERROR0; 13249 /* 13250 * The nodeset should be in document order, 13251 * Keep only the first value 13252 */ 13253 if ((ctxt->value != NULL) && 13254 (ctxt->value->type == XPATH_NODESET) && 13255 (ctxt->value->nodesetval != NULL) && 13256 (ctxt->value->nodesetval->nodeNr > 1)) 13257 xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval, 13258 1, 1); 13259 break; 13260 } 13261 } 13262 /* 13263 * Optimization for ()[last()] selection i.e. the last elem 13264 */ 13265 if ((op->ch1 != -1) && (op->ch2 != -1) && 13266 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 13267 (comp->steps[op->ch2].op == XPATH_OP_SORT)) { 13268 int f = comp->steps[op->ch2].ch1; 13269 13270 if ((f != -1) && 13271 (comp->steps[f].op == XPATH_OP_FUNCTION) && 13272 (comp->steps[f].value5 == NULL) && 13273 (comp->steps[f].value == 0) && 13274 (comp->steps[f].value4 != NULL) && 13275 (xmlStrEqual 13276 (comp->steps[f].value4, BAD_CAST "last"))) { 13277 xmlNodePtr last = NULL; 13278 13279 total += 13280 xmlXPathCompOpEvalLast(ctxt, 13281 &comp->steps[op->ch1], 13282 &last); 13283 CHECK_ERROR0; 13284 /* 13285 * The nodeset should be in document order, 13286 * Keep only the last value 13287 */ 13288 if ((ctxt->value != NULL) && 13289 (ctxt->value->type == XPATH_NODESET) && 13290 (ctxt->value->nodesetval != NULL) && 13291 (ctxt->value->nodesetval->nodeTab != NULL) && 13292 (ctxt->value->nodesetval->nodeNr > 1)) 13293 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval); 13294 break; 13295 } 13296 } 13297 /* 13298 * Process inner predicates first. 13299 * Example "index[parent::book][1]": 13300 * ... 13301 * PREDICATE <-- we are here "[1]" 13302 * PREDICATE <-- process "[parent::book]" first 13303 * SORT 13304 * COLLECT 'parent' 'name' 'node' book 13305 * NODE 13306 * ELEM Object is a number : 1 13307 */ 13308 if (op->ch1 != -1) 13309 total += 13310 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13311 CHECK_ERROR0; 13312 if (op->ch2 == -1) 13313 break; 13314 if (ctxt->value == NULL) 13315 break; 13316 13317 #ifdef LIBXML_XPTR_ENABLED 13318 /* 13319 * Hum are we filtering the result of an XPointer expression 13320 */ 13321 if (ctxt->value->type == XPATH_LOCATIONSET) { 13322 xmlLocationSetPtr locset = ctxt->value->user; 13323 xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 13324 1, locset->locNr); 13325 break; 13326 } 13327 #endif /* LIBXML_XPTR_ENABLED */ 13328 13329 CHECK_TYPE0(XPATH_NODESET); 13330 set = ctxt->value->nodesetval; 13331 if (set != NULL) 13332 xmlXPathNodeSetFilter(ctxt, set, op->ch2, 13333 1, set->nodeNr, 1); 13334 break; 13335 } 13336 case XPATH_OP_SORT: 13337 if (op->ch1 != -1) 13338 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13339 CHECK_ERROR0; 13340 if ((ctxt->value != NULL) && 13341 (ctxt->value->type == XPATH_NODESET) && 13342 (ctxt->value->nodesetval != NULL) && 13343 (ctxt->value->nodesetval->nodeNr > 1)) 13344 { 13345 xmlXPathNodeSetSort(ctxt->value->nodesetval); 13346 } 13347 break; 13348 #ifdef LIBXML_XPTR_ENABLED 13349 case XPATH_OP_RANGETO:{ 13350 xmlXPathObjectPtr range; 13351 xmlXPathObjectPtr res, obj; 13352 xmlXPathObjectPtr tmp; 13353 xmlLocationSetPtr newlocset = NULL; 13354 xmlLocationSetPtr oldlocset; 13355 xmlNodeSetPtr oldset; 13356 xmlNodePtr oldnode = ctxt->context->node; 13357 int oldcs = ctxt->context->contextSize; 13358 int oldpp = ctxt->context->proximityPosition; 13359 int i, j; 13360 13361 if (op->ch1 != -1) { 13362 total += 13363 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13364 CHECK_ERROR0; 13365 } 13366 if (ctxt->value == NULL) { 13367 XP_ERROR0(XPATH_INVALID_OPERAND); 13368 } 13369 if (op->ch2 == -1) 13370 break; 13371 13372 if (ctxt->value->type == XPATH_LOCATIONSET) { 13373 /* 13374 * Extract the old locset, and then evaluate the result of the 13375 * expression for all the element in the locset. use it to grow 13376 * up a new locset. 13377 */ 13378 CHECK_TYPE0(XPATH_LOCATIONSET); 13379 13380 if ((ctxt->value->user == NULL) || 13381 (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0)) 13382 break; 13383 13384 obj = valuePop(ctxt); 13385 oldlocset = obj->user; 13386 13387 newlocset = xmlXPtrLocationSetCreate(NULL); 13388 13389 for (i = 0; i < oldlocset->locNr; i++) { 13390 /* 13391 * Run the evaluation with a node list made of a 13392 * single item in the nodelocset. 13393 */ 13394 ctxt->context->node = oldlocset->locTab[i]->user; 13395 ctxt->context->contextSize = oldlocset->locNr; 13396 ctxt->context->proximityPosition = i + 1; 13397 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13398 ctxt->context->node); 13399 valuePush(ctxt, tmp); 13400 13401 if (op->ch2 != -1) 13402 total += 13403 xmlXPathCompOpEval(ctxt, 13404 &comp->steps[op->ch2]); 13405 if (ctxt->error != XPATH_EXPRESSION_OK) { 13406 xmlXPtrFreeLocationSet(newlocset); 13407 goto rangeto_error; 13408 } 13409 13410 res = valuePop(ctxt); 13411 if (res->type == XPATH_LOCATIONSET) { 13412 xmlLocationSetPtr rloc = 13413 (xmlLocationSetPtr)res->user; 13414 for (j=0; j<rloc->locNr; j++) { 13415 range = xmlXPtrNewRange( 13416 oldlocset->locTab[i]->user, 13417 oldlocset->locTab[i]->index, 13418 rloc->locTab[j]->user2, 13419 rloc->locTab[j]->index2); 13420 if (range != NULL) { 13421 xmlXPtrLocationSetAdd(newlocset, range); 13422 } 13423 } 13424 } else { 13425 range = xmlXPtrNewRangeNodeObject( 13426 (xmlNodePtr)oldlocset->locTab[i]->user, res); 13427 if (range != NULL) { 13428 xmlXPtrLocationSetAdd(newlocset,range); 13429 } 13430 } 13431 13432 /* 13433 * Cleanup 13434 */ 13435 if (res != NULL) { 13436 xmlXPathReleaseObject(ctxt->context, res); 13437 } 13438 if (ctxt->value == tmp) { 13439 res = valuePop(ctxt); 13440 xmlXPathReleaseObject(ctxt->context, res); 13441 } 13442 } 13443 } else { /* Not a location set */ 13444 CHECK_TYPE0(XPATH_NODESET); 13445 obj = valuePop(ctxt); 13446 oldset = obj->nodesetval; 13447 13448 newlocset = xmlXPtrLocationSetCreate(NULL); 13449 13450 if (oldset != NULL) { 13451 for (i = 0; i < oldset->nodeNr; i++) { 13452 /* 13453 * Run the evaluation with a node list made of a single item 13454 * in the nodeset. 13455 */ 13456 ctxt->context->node = oldset->nodeTab[i]; 13457 /* 13458 * OPTIMIZE TODO: Avoid recreation for every iteration. 13459 */ 13460 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13461 ctxt->context->node); 13462 valuePush(ctxt, tmp); 13463 13464 if (op->ch2 != -1) 13465 total += 13466 xmlXPathCompOpEval(ctxt, 13467 &comp->steps[op->ch2]); 13468 if (ctxt->error != XPATH_EXPRESSION_OK) { 13469 xmlXPtrFreeLocationSet(newlocset); 13470 goto rangeto_error; 13471 } 13472 13473 res = valuePop(ctxt); 13474 range = 13475 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i], 13476 res); 13477 if (range != NULL) { 13478 xmlXPtrLocationSetAdd(newlocset, range); 13479 } 13480 13481 /* 13482 * Cleanup 13483 */ 13484 if (res != NULL) { 13485 xmlXPathReleaseObject(ctxt->context, res); 13486 } 13487 if (ctxt->value == tmp) { 13488 res = valuePop(ctxt); 13489 xmlXPathReleaseObject(ctxt->context, res); 13490 } 13491 } 13492 } 13493 } 13494 13495 /* 13496 * The result is used as the new evaluation set. 13497 */ 13498 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset)); 13499 rangeto_error: 13500 xmlXPathReleaseObject(ctxt->context, obj); 13501 ctxt->context->node = oldnode; 13502 ctxt->context->contextSize = oldcs; 13503 ctxt->context->proximityPosition = oldpp; 13504 break; 13505 } 13506 #endif /* LIBXML_XPTR_ENABLED */ 13507 default: 13508 xmlGenericError(xmlGenericErrorContext, 13509 "XPath: unknown precompiled operation %d\n", op->op); 13510 ctxt->error = XPATH_INVALID_OPERAND; 13511 break; 13512 } 13513 13514 ctxt->context->depth -= 1; 13515 return (total); 13516 } 13517 13518 /** 13519 * xmlXPathCompOpEvalToBoolean: 13520 * @ctxt: the XPath parser context 13521 * 13522 * Evaluates if the expression evaluates to true. 13523 * 13524 * Returns 1 if true, 0 if false and -1 on API or internal errors. 13525 */ 13526 static int 13527 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt, 13528 xmlXPathStepOpPtr op, 13529 int isPredicate) 13530 { 13531 xmlXPathObjectPtr resObj = NULL; 13532 13533 start: 13534 if (OP_LIMIT_EXCEEDED(ctxt, 1)) 13535 return(0); 13536 /* comp = ctxt->comp; */ 13537 switch (op->op) { 13538 case XPATH_OP_END: 13539 return (0); 13540 case XPATH_OP_VALUE: 13541 resObj = (xmlXPathObjectPtr) op->value4; 13542 if (isPredicate) 13543 return(xmlXPathEvaluatePredicateResult(ctxt, resObj)); 13544 return(xmlXPathCastToBoolean(resObj)); 13545 case XPATH_OP_SORT: 13546 /* 13547 * We don't need sorting for boolean results. Skip this one. 13548 */ 13549 if (op->ch1 != -1) { 13550 op = &ctxt->comp->steps[op->ch1]; 13551 goto start; 13552 } 13553 return(0); 13554 case XPATH_OP_COLLECT: 13555 if (op->ch1 == -1) 13556 return(0); 13557 13558 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]); 13559 if (ctxt->error != XPATH_EXPRESSION_OK) 13560 return(-1); 13561 13562 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1); 13563 if (ctxt->error != XPATH_EXPRESSION_OK) 13564 return(-1); 13565 13566 resObj = valuePop(ctxt); 13567 if (resObj == NULL) 13568 return(-1); 13569 break; 13570 default: 13571 /* 13572 * Fallback to call xmlXPathCompOpEval(). 13573 */ 13574 xmlXPathCompOpEval(ctxt, op); 13575 if (ctxt->error != XPATH_EXPRESSION_OK) 13576 return(-1); 13577 13578 resObj = valuePop(ctxt); 13579 if (resObj == NULL) 13580 return(-1); 13581 break; 13582 } 13583 13584 if (resObj) { 13585 int res; 13586 13587 if (resObj->type == XPATH_BOOLEAN) { 13588 res = resObj->boolval; 13589 } else if (isPredicate) { 13590 /* 13591 * For predicates a result of type "number" is handled 13592 * differently: 13593 * SPEC XPath 1.0: 13594 * "If the result is a number, the result will be converted 13595 * to true if the number is equal to the context position 13596 * and will be converted to false otherwise;" 13597 */ 13598 res = xmlXPathEvaluatePredicateResult(ctxt, resObj); 13599 } else { 13600 res = xmlXPathCastToBoolean(resObj); 13601 } 13602 xmlXPathReleaseObject(ctxt->context, resObj); 13603 return(res); 13604 } 13605 13606 return(0); 13607 } 13608 13609 #ifdef XPATH_STREAMING 13610 /** 13611 * xmlXPathRunStreamEval: 13612 * @ctxt: the XPath parser context with the compiled expression 13613 * 13614 * Evaluate the Precompiled Streamable XPath expression in the given context. 13615 */ 13616 static int 13617 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp, 13618 xmlXPathObjectPtr *resultSeq, int toBool) 13619 { 13620 int max_depth, min_depth; 13621 int from_root; 13622 int ret, depth; 13623 int eval_all_nodes; 13624 xmlNodePtr cur = NULL, limit = NULL; 13625 xmlStreamCtxtPtr patstream = NULL; 13626 13627 int nb_nodes = 0; 13628 13629 if ((ctxt == NULL) || (comp == NULL)) 13630 return(-1); 13631 max_depth = xmlPatternMaxDepth(comp); 13632 if (max_depth == -1) 13633 return(-1); 13634 if (max_depth == -2) 13635 max_depth = 10000; 13636 min_depth = xmlPatternMinDepth(comp); 13637 if (min_depth == -1) 13638 return(-1); 13639 from_root = xmlPatternFromRoot(comp); 13640 if (from_root < 0) 13641 return(-1); 13642 #if 0 13643 printf("stream eval: depth %d from root %d\n", max_depth, from_root); 13644 #endif 13645 13646 if (! toBool) { 13647 if (resultSeq == NULL) 13648 return(-1); 13649 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL); 13650 if (*resultSeq == NULL) 13651 return(-1); 13652 } 13653 13654 /* 13655 * handle the special cases of "/" amd "." being matched 13656 */ 13657 if (min_depth == 0) { 13658 if (from_root) { 13659 /* Select "/" */ 13660 if (toBool) 13661 return(1); 13662 /* TODO: Check memory error. */ 13663 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, 13664 (xmlNodePtr) ctxt->doc); 13665 } else { 13666 /* Select "self::node()" */ 13667 if (toBool) 13668 return(1); 13669 /* TODO: Check memory error. */ 13670 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node); 13671 } 13672 } 13673 if (max_depth == 0) { 13674 return(0); 13675 } 13676 13677 if (from_root) { 13678 cur = (xmlNodePtr)ctxt->doc; 13679 } else if (ctxt->node != NULL) { 13680 switch (ctxt->node->type) { 13681 case XML_ELEMENT_NODE: 13682 case XML_DOCUMENT_NODE: 13683 case XML_DOCUMENT_FRAG_NODE: 13684 case XML_HTML_DOCUMENT_NODE: 13685 #ifdef LIBXML_DOCB_ENABLED 13686 case XML_DOCB_DOCUMENT_NODE: 13687 #endif 13688 cur = ctxt->node; 13689 break; 13690 case XML_ATTRIBUTE_NODE: 13691 case XML_TEXT_NODE: 13692 case XML_CDATA_SECTION_NODE: 13693 case XML_ENTITY_REF_NODE: 13694 case XML_ENTITY_NODE: 13695 case XML_PI_NODE: 13696 case XML_COMMENT_NODE: 13697 case XML_NOTATION_NODE: 13698 case XML_DTD_NODE: 13699 case XML_DOCUMENT_TYPE_NODE: 13700 case XML_ELEMENT_DECL: 13701 case XML_ATTRIBUTE_DECL: 13702 case XML_ENTITY_DECL: 13703 case XML_NAMESPACE_DECL: 13704 case XML_XINCLUDE_START: 13705 case XML_XINCLUDE_END: 13706 break; 13707 } 13708 limit = cur; 13709 } 13710 if (cur == NULL) { 13711 return(0); 13712 } 13713 13714 patstream = xmlPatternGetStreamCtxt(comp); 13715 if (patstream == NULL) { 13716 /* 13717 * QUESTION TODO: Is this an error? 13718 */ 13719 return(0); 13720 } 13721 13722 eval_all_nodes = xmlStreamWantsAnyNode(patstream); 13723 13724 if (from_root) { 13725 ret = xmlStreamPush(patstream, NULL, NULL); 13726 if (ret < 0) { 13727 } else if (ret == 1) { 13728 if (toBool) 13729 goto return_1; 13730 /* TODO: Check memory error. */ 13731 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur); 13732 } 13733 } 13734 depth = 0; 13735 goto scan_children; 13736 next_node: 13737 do { 13738 if (ctxt->opLimit != 0) { 13739 if (ctxt->opCount >= ctxt->opLimit) { 13740 xmlGenericError(xmlGenericErrorContext, 13741 "XPath operation limit exceeded\n"); 13742 xmlFreeStreamCtxt(patstream); 13743 return(-1); 13744 } 13745 ctxt->opCount++; 13746 } 13747 13748 nb_nodes++; 13749 13750 switch (cur->type) { 13751 case XML_ELEMENT_NODE: 13752 case XML_TEXT_NODE: 13753 case XML_CDATA_SECTION_NODE: 13754 case XML_COMMENT_NODE: 13755 case XML_PI_NODE: 13756 if (cur->type == XML_ELEMENT_NODE) { 13757 ret = xmlStreamPush(patstream, cur->name, 13758 (cur->ns ? cur->ns->href : NULL)); 13759 } else if (eval_all_nodes) 13760 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type); 13761 else 13762 break; 13763 13764 if (ret < 0) { 13765 /* NOP. */ 13766 } else if (ret == 1) { 13767 if (toBool) 13768 goto return_1; 13769 if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur) 13770 < 0) { 13771 ctxt->lastError.domain = XML_FROM_XPATH; 13772 ctxt->lastError.code = XML_ERR_NO_MEMORY; 13773 } 13774 } 13775 if ((cur->children == NULL) || (depth >= max_depth)) { 13776 ret = xmlStreamPop(patstream); 13777 while (cur->next != NULL) { 13778 cur = cur->next; 13779 if ((cur->type != XML_ENTITY_DECL) && 13780 (cur->type != XML_DTD_NODE)) 13781 goto next_node; 13782 } 13783 } 13784 default: 13785 break; 13786 } 13787 13788 scan_children: 13789 if (cur->type == XML_NAMESPACE_DECL) break; 13790 if ((cur->children != NULL) && (depth < max_depth)) { 13791 /* 13792 * Do not descend on entities declarations 13793 */ 13794 if (cur->children->type != XML_ENTITY_DECL) { 13795 cur = cur->children; 13796 depth++; 13797 /* 13798 * Skip DTDs 13799 */ 13800 if (cur->type != XML_DTD_NODE) 13801 continue; 13802 } 13803 } 13804 13805 if (cur == limit) 13806 break; 13807 13808 while (cur->next != NULL) { 13809 cur = cur->next; 13810 if ((cur->type != XML_ENTITY_DECL) && 13811 (cur->type != XML_DTD_NODE)) 13812 goto next_node; 13813 } 13814 13815 do { 13816 cur = cur->parent; 13817 depth--; 13818 if ((cur == NULL) || (cur == limit)) 13819 goto done; 13820 if (cur->type == XML_ELEMENT_NODE) { 13821 ret = xmlStreamPop(patstream); 13822 } else if ((eval_all_nodes) && 13823 ((cur->type == XML_TEXT_NODE) || 13824 (cur->type == XML_CDATA_SECTION_NODE) || 13825 (cur->type == XML_COMMENT_NODE) || 13826 (cur->type == XML_PI_NODE))) 13827 { 13828 ret = xmlStreamPop(patstream); 13829 } 13830 if (cur->next != NULL) { 13831 cur = cur->next; 13832 break; 13833 } 13834 } while (cur != NULL); 13835 13836 } while ((cur != NULL) && (depth >= 0)); 13837 13838 done: 13839 13840 #if 0 13841 printf("stream eval: checked %d nodes selected %d\n", 13842 nb_nodes, retObj->nodesetval->nodeNr); 13843 #endif 13844 13845 if (patstream) 13846 xmlFreeStreamCtxt(patstream); 13847 return(0); 13848 13849 return_1: 13850 if (patstream) 13851 xmlFreeStreamCtxt(patstream); 13852 return(1); 13853 } 13854 #endif /* XPATH_STREAMING */ 13855 13856 /** 13857 * xmlXPathRunEval: 13858 * @ctxt: the XPath parser context with the compiled expression 13859 * @toBool: evaluate to a boolean result 13860 * 13861 * Evaluate the Precompiled XPath expression in the given context. 13862 */ 13863 static int 13864 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool) 13865 { 13866 xmlXPathCompExprPtr comp; 13867 13868 if ((ctxt == NULL) || (ctxt->comp == NULL)) 13869 return(-1); 13870 13871 ctxt->context->depth = 0; 13872 13873 if (ctxt->valueTab == NULL) { 13874 /* Allocate the value stack */ 13875 ctxt->valueTab = (xmlXPathObjectPtr *) 13876 xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); 13877 if (ctxt->valueTab == NULL) { 13878 xmlXPathPErrMemory(ctxt, "creating evaluation context\n"); 13879 xmlFree(ctxt); 13880 } 13881 ctxt->valueNr = 0; 13882 ctxt->valueMax = 10; 13883 ctxt->value = NULL; 13884 ctxt->valueFrame = 0; 13885 } 13886 #ifdef XPATH_STREAMING 13887 if (ctxt->comp->stream) { 13888 int res; 13889 13890 if (toBool) { 13891 /* 13892 * Evaluation to boolean result. 13893 */ 13894 res = xmlXPathRunStreamEval(ctxt->context, 13895 ctxt->comp->stream, NULL, 1); 13896 if (res != -1) 13897 return(res); 13898 } else { 13899 xmlXPathObjectPtr resObj = NULL; 13900 13901 /* 13902 * Evaluation to a sequence. 13903 */ 13904 res = xmlXPathRunStreamEval(ctxt->context, 13905 ctxt->comp->stream, &resObj, 0); 13906 13907 if ((res != -1) && (resObj != NULL)) { 13908 valuePush(ctxt, resObj); 13909 return(0); 13910 } 13911 if (resObj != NULL) 13912 xmlXPathReleaseObject(ctxt->context, resObj); 13913 } 13914 /* 13915 * QUESTION TODO: This falls back to normal XPath evaluation 13916 * if res == -1. Is this intended? 13917 */ 13918 } 13919 #endif 13920 comp = ctxt->comp; 13921 if (comp->last < 0) { 13922 xmlGenericError(xmlGenericErrorContext, 13923 "xmlXPathRunEval: last is less than zero\n"); 13924 return(-1); 13925 } 13926 if (toBool) 13927 return(xmlXPathCompOpEvalToBoolean(ctxt, 13928 &comp->steps[comp->last], 0)); 13929 else 13930 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]); 13931 13932 return(0); 13933 } 13934 13935 /************************************************************************ 13936 * * 13937 * Public interfaces * 13938 * * 13939 ************************************************************************/ 13940 13941 /** 13942 * xmlXPathEvalPredicate: 13943 * @ctxt: the XPath context 13944 * @res: the Predicate Expression evaluation result 13945 * 13946 * Evaluate a predicate result for the current node. 13947 * A PredicateExpr is evaluated by evaluating the Expr and converting 13948 * the result to a boolean. If the result is a number, the result will 13949 * be converted to true if the number is equal to the position of the 13950 * context node in the context node list (as returned by the position 13951 * function) and will be converted to false otherwise; if the result 13952 * is not a number, then the result will be converted as if by a call 13953 * to the boolean function. 13954 * 13955 * Returns 1 if predicate is true, 0 otherwise 13956 */ 13957 int 13958 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) { 13959 if ((ctxt == NULL) || (res == NULL)) return(0); 13960 switch (res->type) { 13961 case XPATH_BOOLEAN: 13962 return(res->boolval); 13963 case XPATH_NUMBER: 13964 return(res->floatval == ctxt->proximityPosition); 13965 case XPATH_NODESET: 13966 case XPATH_XSLT_TREE: 13967 if (res->nodesetval == NULL) 13968 return(0); 13969 return(res->nodesetval->nodeNr != 0); 13970 case XPATH_STRING: 13971 return((res->stringval != NULL) && 13972 (xmlStrlen(res->stringval) != 0)); 13973 default: 13974 STRANGE 13975 } 13976 return(0); 13977 } 13978 13979 /** 13980 * xmlXPathEvaluatePredicateResult: 13981 * @ctxt: the XPath Parser context 13982 * @res: the Predicate Expression evaluation result 13983 * 13984 * Evaluate a predicate result for the current node. 13985 * A PredicateExpr is evaluated by evaluating the Expr and converting 13986 * the result to a boolean. If the result is a number, the result will 13987 * be converted to true if the number is equal to the position of the 13988 * context node in the context node list (as returned by the position 13989 * function) and will be converted to false otherwise; if the result 13990 * is not a number, then the result will be converted as if by a call 13991 * to the boolean function. 13992 * 13993 * Returns 1 if predicate is true, 0 otherwise 13994 */ 13995 int 13996 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt, 13997 xmlXPathObjectPtr res) { 13998 if ((ctxt == NULL) || (res == NULL)) return(0); 13999 switch (res->type) { 14000 case XPATH_BOOLEAN: 14001 return(res->boolval); 14002 case XPATH_NUMBER: 14003 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200)) 14004 return((res->floatval == ctxt->context->proximityPosition) && 14005 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/ 14006 #else 14007 return(res->floatval == ctxt->context->proximityPosition); 14008 #endif 14009 case XPATH_NODESET: 14010 case XPATH_XSLT_TREE: 14011 if (res->nodesetval == NULL) 14012 return(0); 14013 return(res->nodesetval->nodeNr != 0); 14014 case XPATH_STRING: 14015 return((res->stringval != NULL) && (res->stringval[0] != 0)); 14016 #ifdef LIBXML_XPTR_ENABLED 14017 case XPATH_LOCATIONSET:{ 14018 xmlLocationSetPtr ptr = res->user; 14019 if (ptr == NULL) 14020 return(0); 14021 return (ptr->locNr != 0); 14022 } 14023 #endif 14024 default: 14025 STRANGE 14026 } 14027 return(0); 14028 } 14029 14030 #ifdef XPATH_STREAMING 14031 /** 14032 * xmlXPathTryStreamCompile: 14033 * @ctxt: an XPath context 14034 * @str: the XPath expression 14035 * 14036 * Try to compile the XPath expression as a streamable subset. 14037 * 14038 * Returns the compiled expression or NULL if failed to compile. 14039 */ 14040 static xmlXPathCompExprPtr 14041 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { 14042 /* 14043 * Optimization: use streaming patterns when the XPath expression can 14044 * be compiled to a stream lookup 14045 */ 14046 xmlPatternPtr stream; 14047 xmlXPathCompExprPtr comp; 14048 xmlDictPtr dict = NULL; 14049 const xmlChar **namespaces = NULL; 14050 xmlNsPtr ns; 14051 int i, j; 14052 14053 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) && 14054 (!xmlStrchr(str, '@'))) { 14055 const xmlChar *tmp; 14056 14057 /* 14058 * We don't try to handle expressions using the verbose axis 14059 * specifiers ("::"), just the simplified form at this point. 14060 * Additionally, if there is no list of namespaces available and 14061 * there's a ":" in the expression, indicating a prefixed QName, 14062 * then we won't try to compile either. xmlPatterncompile() needs 14063 * to have a list of namespaces at compilation time in order to 14064 * compile prefixed name tests. 14065 */ 14066 tmp = xmlStrchr(str, ':'); 14067 if ((tmp != NULL) && 14068 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':'))) 14069 return(NULL); 14070 14071 if (ctxt != NULL) { 14072 dict = ctxt->dict; 14073 if (ctxt->nsNr > 0) { 14074 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*)); 14075 if (namespaces == NULL) { 14076 xmlXPathErrMemory(ctxt, "allocating namespaces array\n"); 14077 return(NULL); 14078 } 14079 for (i = 0, j = 0; (j < ctxt->nsNr); j++) { 14080 ns = ctxt->namespaces[j]; 14081 namespaces[i++] = ns->href; 14082 namespaces[i++] = ns->prefix; 14083 } 14084 namespaces[i++] = NULL; 14085 namespaces[i] = NULL; 14086 } 14087 } 14088 14089 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, 14090 &namespaces[0]); 14091 if (namespaces != NULL) { 14092 xmlFree((xmlChar **)namespaces); 14093 } 14094 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) { 14095 comp = xmlXPathNewCompExpr(); 14096 if (comp == NULL) { 14097 xmlXPathErrMemory(ctxt, "allocating streamable expression\n"); 14098 return(NULL); 14099 } 14100 comp->stream = stream; 14101 comp->dict = dict; 14102 if (comp->dict) 14103 xmlDictReference(comp->dict); 14104 return(comp); 14105 } 14106 xmlFreePattern(stream); 14107 } 14108 return(NULL); 14109 } 14110 #endif /* XPATH_STREAMING */ 14111 14112 static void 14113 xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt, 14114 xmlXPathStepOpPtr op) 14115 { 14116 xmlXPathCompExprPtr comp = pctxt->comp; 14117 xmlXPathContextPtr ctxt; 14118 14119 /* 14120 * Try to rewrite "descendant-or-self::node()/foo" to an optimized 14121 * internal representation. 14122 */ 14123 14124 if ((op->op == XPATH_OP_COLLECT /* 11 */) && 14125 (op->ch1 != -1) && 14126 (op->ch2 == -1 /* no predicate */)) 14127 { 14128 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1]; 14129 14130 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) && 14131 ((xmlXPathAxisVal) prevop->value == 14132 AXIS_DESCENDANT_OR_SELF) && 14133 (prevop->ch2 == -1) && 14134 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) && 14135 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE)) 14136 { 14137 /* 14138 * This is a "descendant-or-self::node()" without predicates. 14139 * Try to eliminate it. 14140 */ 14141 14142 switch ((xmlXPathAxisVal) op->value) { 14143 case AXIS_CHILD: 14144 case AXIS_DESCENDANT: 14145 /* 14146 * Convert "descendant-or-self::node()/child::" or 14147 * "descendant-or-self::node()/descendant::" to 14148 * "descendant::" 14149 */ 14150 op->ch1 = prevop->ch1; 14151 op->value = AXIS_DESCENDANT; 14152 break; 14153 case AXIS_SELF: 14154 case AXIS_DESCENDANT_OR_SELF: 14155 /* 14156 * Convert "descendant-or-self::node()/self::" or 14157 * "descendant-or-self::node()/descendant-or-self::" to 14158 * to "descendant-or-self::" 14159 */ 14160 op->ch1 = prevop->ch1; 14161 op->value = AXIS_DESCENDANT_OR_SELF; 14162 break; 14163 default: 14164 break; 14165 } 14166 } 14167 } 14168 14169 /* OP_VALUE has invalid ch1. */ 14170 if (op->op == XPATH_OP_VALUE) 14171 return; 14172 14173 /* Recurse */ 14174 ctxt = pctxt->context; 14175 if (ctxt != NULL) { 14176 if (ctxt->depth >= ctxt->maxDepth) 14177 return; 14178 ctxt->depth += 1; 14179 } 14180 if (op->ch1 != -1) 14181 xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]); 14182 if (op->ch2 != -1) 14183 xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]); 14184 if (ctxt != NULL) 14185 ctxt->depth -= 1; 14186 } 14187 14188 /** 14189 * xmlXPathCtxtCompile: 14190 * @ctxt: an XPath context 14191 * @str: the XPath expression 14192 * 14193 * Compile an XPath expression 14194 * 14195 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL. 14196 * the caller has to free the object. 14197 */ 14198 xmlXPathCompExprPtr 14199 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { 14200 xmlXPathParserContextPtr pctxt; 14201 xmlXPathCompExprPtr comp; 14202 14203 #ifdef XPATH_STREAMING 14204 comp = xmlXPathTryStreamCompile(ctxt, str); 14205 if (comp != NULL) 14206 return(comp); 14207 #endif 14208 14209 xmlXPathInit(); 14210 14211 pctxt = xmlXPathNewParserContext(str, ctxt); 14212 if (pctxt == NULL) 14213 return NULL; 14214 if (ctxt != NULL) 14215 ctxt->depth = 0; 14216 xmlXPathCompileExpr(pctxt, 1); 14217 14218 if( pctxt->error != XPATH_EXPRESSION_OK ) 14219 { 14220 xmlXPathFreeParserContext(pctxt); 14221 return(NULL); 14222 } 14223 14224 if (*pctxt->cur != 0) { 14225 /* 14226 * aleksey: in some cases this line prints *second* error message 14227 * (see bug #78858) and probably this should be fixed. 14228 * However, we are not sure that all error messages are printed 14229 * out in other places. It's not critical so we leave it as-is for now 14230 */ 14231 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR); 14232 comp = NULL; 14233 } else { 14234 comp = pctxt->comp; 14235 if ((comp->nbStep > 1) && (comp->last >= 0)) { 14236 if (ctxt != NULL) 14237 ctxt->depth = 0; 14238 xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]); 14239 } 14240 pctxt->comp = NULL; 14241 } 14242 xmlXPathFreeParserContext(pctxt); 14243 14244 if (comp != NULL) { 14245 comp->expr = xmlStrdup(str); 14246 #ifdef DEBUG_EVAL_COUNTS 14247 comp->string = xmlStrdup(str); 14248 comp->nb = 0; 14249 #endif 14250 } 14251 return(comp); 14252 } 14253 14254 /** 14255 * xmlXPathCompile: 14256 * @str: the XPath expression 14257 * 14258 * Compile an XPath expression 14259 * 14260 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL. 14261 * the caller has to free the object. 14262 */ 14263 xmlXPathCompExprPtr 14264 xmlXPathCompile(const xmlChar *str) { 14265 return(xmlXPathCtxtCompile(NULL, str)); 14266 } 14267 14268 /** 14269 * xmlXPathCompiledEvalInternal: 14270 * @comp: the compiled XPath expression 14271 * @ctxt: the XPath context 14272 * @resObj: the resulting XPath object or NULL 14273 * @toBool: 1 if only a boolean result is requested 14274 * 14275 * Evaluate the Precompiled XPath expression in the given context. 14276 * The caller has to free @resObj. 14277 * 14278 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14279 * the caller has to free the object. 14280 */ 14281 static int 14282 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp, 14283 xmlXPathContextPtr ctxt, 14284 xmlXPathObjectPtr *resObjPtr, 14285 int toBool) 14286 { 14287 xmlXPathParserContextPtr pctxt; 14288 xmlXPathObjectPtr resObj; 14289 #ifndef LIBXML_THREAD_ENABLED 14290 static int reentance = 0; 14291 #endif 14292 int res; 14293 14294 CHECK_CTXT_NEG(ctxt) 14295 14296 if (comp == NULL) 14297 return(-1); 14298 xmlXPathInit(); 14299 14300 #ifndef LIBXML_THREAD_ENABLED 14301 reentance++; 14302 if (reentance > 1) 14303 xmlXPathDisableOptimizer = 1; 14304 #endif 14305 14306 #ifdef DEBUG_EVAL_COUNTS 14307 comp->nb++; 14308 if ((comp->string != NULL) && (comp->nb > 100)) { 14309 fprintf(stderr, "100 x %s\n", comp->string); 14310 comp->nb = 0; 14311 } 14312 #endif 14313 pctxt = xmlXPathCompParserContext(comp, ctxt); 14314 res = xmlXPathRunEval(pctxt, toBool); 14315 14316 if (pctxt->error != XPATH_EXPRESSION_OK) { 14317 resObj = NULL; 14318 } else { 14319 resObj = valuePop(pctxt); 14320 if (resObj == NULL) { 14321 if (!toBool) 14322 xmlGenericError(xmlGenericErrorContext, 14323 "xmlXPathCompiledEval: No result on the stack.\n"); 14324 } else if (pctxt->valueNr > 0) { 14325 xmlGenericError(xmlGenericErrorContext, 14326 "xmlXPathCompiledEval: %d object(s) left on the stack.\n", 14327 pctxt->valueNr); 14328 } 14329 } 14330 14331 if (resObjPtr) 14332 *resObjPtr = resObj; 14333 else 14334 xmlXPathReleaseObject(ctxt, resObj); 14335 14336 pctxt->comp = NULL; 14337 xmlXPathFreeParserContext(pctxt); 14338 #ifndef LIBXML_THREAD_ENABLED 14339 reentance--; 14340 #endif 14341 14342 return(res); 14343 } 14344 14345 /** 14346 * xmlXPathCompiledEval: 14347 * @comp: the compiled XPath expression 14348 * @ctx: the XPath context 14349 * 14350 * Evaluate the Precompiled XPath expression in the given context. 14351 * 14352 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14353 * the caller has to free the object. 14354 */ 14355 xmlXPathObjectPtr 14356 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) 14357 { 14358 xmlXPathObjectPtr res = NULL; 14359 14360 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0); 14361 return(res); 14362 } 14363 14364 /** 14365 * xmlXPathCompiledEvalToBoolean: 14366 * @comp: the compiled XPath expression 14367 * @ctxt: the XPath context 14368 * 14369 * Applies the XPath boolean() function on the result of the given 14370 * compiled expression. 14371 * 14372 * Returns 1 if the expression evaluated to true, 0 if to false and 14373 * -1 in API and internal errors. 14374 */ 14375 int 14376 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp, 14377 xmlXPathContextPtr ctxt) 14378 { 14379 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1)); 14380 } 14381 14382 /** 14383 * xmlXPathEvalExpr: 14384 * @ctxt: the XPath Parser context 14385 * 14386 * Parse and evaluate an XPath expression in the given context, 14387 * then push the result on the context stack 14388 */ 14389 void 14390 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) { 14391 #ifdef XPATH_STREAMING 14392 xmlXPathCompExprPtr comp; 14393 #endif 14394 14395 if (ctxt == NULL) return; 14396 14397 #ifdef XPATH_STREAMING 14398 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base); 14399 if (comp != NULL) { 14400 if (ctxt->comp != NULL) 14401 xmlXPathFreeCompExpr(ctxt->comp); 14402 ctxt->comp = comp; 14403 } else 14404 #endif 14405 { 14406 if (ctxt->context != NULL) 14407 ctxt->context->depth = 0; 14408 xmlXPathCompileExpr(ctxt, 1); 14409 CHECK_ERROR; 14410 14411 /* Check for trailing characters. */ 14412 if (*ctxt->cur != 0) 14413 XP_ERROR(XPATH_EXPR_ERROR); 14414 14415 if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) { 14416 if (ctxt->context != NULL) 14417 ctxt->context->depth = 0; 14418 xmlXPathOptimizeExpression(ctxt, 14419 &ctxt->comp->steps[ctxt->comp->last]); 14420 } 14421 } 14422 14423 xmlXPathRunEval(ctxt, 0); 14424 } 14425 14426 /** 14427 * xmlXPathEval: 14428 * @str: the XPath expression 14429 * @ctx: the XPath context 14430 * 14431 * Evaluate the XPath Location Path in the given context. 14432 * 14433 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14434 * the caller has to free the object. 14435 */ 14436 xmlXPathObjectPtr 14437 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) { 14438 xmlXPathParserContextPtr ctxt; 14439 xmlXPathObjectPtr res; 14440 14441 CHECK_CTXT(ctx) 14442 14443 xmlXPathInit(); 14444 14445 ctxt = xmlXPathNewParserContext(str, ctx); 14446 if (ctxt == NULL) 14447 return NULL; 14448 xmlXPathEvalExpr(ctxt); 14449 14450 if (ctxt->error != XPATH_EXPRESSION_OK) { 14451 res = NULL; 14452 } else { 14453 res = valuePop(ctxt); 14454 if (res == NULL) { 14455 xmlGenericError(xmlGenericErrorContext, 14456 "xmlXPathCompiledEval: No result on the stack.\n"); 14457 } else if (ctxt->valueNr > 0) { 14458 xmlGenericError(xmlGenericErrorContext, 14459 "xmlXPathCompiledEval: %d object(s) left on the stack.\n", 14460 ctxt->valueNr); 14461 } 14462 } 14463 14464 xmlXPathFreeParserContext(ctxt); 14465 return(res); 14466 } 14467 14468 /** 14469 * xmlXPathSetContextNode: 14470 * @node: the node to to use as the context node 14471 * @ctx: the XPath context 14472 * 14473 * Sets 'node' as the context node. The node must be in the same 14474 * document as that associated with the context. 14475 * 14476 * Returns -1 in case of error or 0 if successful 14477 */ 14478 int 14479 xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) { 14480 if ((node == NULL) || (ctx == NULL)) 14481 return(-1); 14482 14483 if (node->doc == ctx->doc) { 14484 ctx->node = node; 14485 return(0); 14486 } 14487 return(-1); 14488 } 14489 14490 /** 14491 * xmlXPathNodeEval: 14492 * @node: the node to to use as the context node 14493 * @str: the XPath expression 14494 * @ctx: the XPath context 14495 * 14496 * Evaluate the XPath Location Path in the given context. The node 'node' 14497 * is set as the context node. The context node is not restored. 14498 * 14499 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14500 * the caller has to free the object. 14501 */ 14502 xmlXPathObjectPtr 14503 xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) { 14504 if (str == NULL) 14505 return(NULL); 14506 if (xmlXPathSetContextNode(node, ctx) < 0) 14507 return(NULL); 14508 return(xmlXPathEval(str, ctx)); 14509 } 14510 14511 /** 14512 * xmlXPathEvalExpression: 14513 * @str: the XPath expression 14514 * @ctxt: the XPath context 14515 * 14516 * Alias for xmlXPathEval(). 14517 * 14518 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14519 * the caller has to free the object. 14520 */ 14521 xmlXPathObjectPtr 14522 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) { 14523 return(xmlXPathEval(str, ctxt)); 14524 } 14525 14526 /************************************************************************ 14527 * * 14528 * Extra functions not pertaining to the XPath spec * 14529 * * 14530 ************************************************************************/ 14531 /** 14532 * xmlXPathEscapeUriFunction: 14533 * @ctxt: the XPath Parser context 14534 * @nargs: the number of arguments 14535 * 14536 * Implement the escape-uri() XPath function 14537 * string escape-uri(string $str, bool $escape-reserved) 14538 * 14539 * This function applies the URI escaping rules defined in section 2 of [RFC 14540 * 2396] to the string supplied as $uri-part, which typically represents all 14541 * or part of a URI. The effect of the function is to replace any special 14542 * character in the string by an escape sequence of the form %xx%yy..., 14543 * where xxyy... is the hexadecimal representation of the octets used to 14544 * represent the character in UTF-8. 14545 * 14546 * The set of characters that are escaped depends on the setting of the 14547 * boolean argument $escape-reserved. 14548 * 14549 * If $escape-reserved is true, all characters are escaped other than lower 14550 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters 14551 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!" 14552 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only 14553 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and 14554 * A-F). 14555 * 14556 * If $escape-reserved is false, the behavior differs in that characters 14557 * referred to in [RFC 2396] as reserved characters are not escaped. These 14558 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",". 14559 * 14560 * [RFC 2396] does not define whether escaped URIs should use lower case or 14561 * upper case for hexadecimal digits. To ensure that escaped URIs can be 14562 * compared using string comparison functions, this function must always use 14563 * the upper-case letters A-F. 14564 * 14565 * Generally, $escape-reserved should be set to true when escaping a string 14566 * that is to form a single part of a URI, and to false when escaping an 14567 * entire URI or URI reference. 14568 * 14569 * In the case of non-ascii characters, the string is encoded according to 14570 * utf-8 and then converted according to RFC 2396. 14571 * 14572 * Examples 14573 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true()) 14574 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean" 14575 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false()) 14576 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean" 14577 * 14578 */ 14579 static void 14580 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) { 14581 xmlXPathObjectPtr str; 14582 int escape_reserved; 14583 xmlBufPtr target; 14584 xmlChar *cptr; 14585 xmlChar escape[4]; 14586 14587 CHECK_ARITY(2); 14588 14589 escape_reserved = xmlXPathPopBoolean(ctxt); 14590 14591 CAST_TO_STRING; 14592 str = valuePop(ctxt); 14593 14594 target = xmlBufCreate(); 14595 14596 escape[0] = '%'; 14597 escape[3] = 0; 14598 14599 if (target) { 14600 for (cptr = str->stringval; *cptr; cptr++) { 14601 if ((*cptr >= 'A' && *cptr <= 'Z') || 14602 (*cptr >= 'a' && *cptr <= 'z') || 14603 (*cptr >= '0' && *cptr <= '9') || 14604 *cptr == '-' || *cptr == '_' || *cptr == '.' || 14605 *cptr == '!' || *cptr == '~' || *cptr == '*' || 14606 *cptr == '\''|| *cptr == '(' || *cptr == ')' || 14607 (*cptr == '%' && 14608 ((cptr[1] >= 'A' && cptr[1] <= 'F') || 14609 (cptr[1] >= 'a' && cptr[1] <= 'f') || 14610 (cptr[1] >= '0' && cptr[1] <= '9')) && 14611 ((cptr[2] >= 'A' && cptr[2] <= 'F') || 14612 (cptr[2] >= 'a' && cptr[2] <= 'f') || 14613 (cptr[2] >= '0' && cptr[2] <= '9'))) || 14614 (!escape_reserved && 14615 (*cptr == ';' || *cptr == '/' || *cptr == '?' || 14616 *cptr == ':' || *cptr == '@' || *cptr == '&' || 14617 *cptr == '=' || *cptr == '+' || *cptr == '$' || 14618 *cptr == ','))) { 14619 xmlBufAdd(target, cptr, 1); 14620 } else { 14621 if ((*cptr >> 4) < 10) 14622 escape[1] = '0' + (*cptr >> 4); 14623 else 14624 escape[1] = 'A' - 10 + (*cptr >> 4); 14625 if ((*cptr & 0xF) < 10) 14626 escape[2] = '0' + (*cptr & 0xF); 14627 else 14628 escape[2] = 'A' - 10 + (*cptr & 0xF); 14629 14630 xmlBufAdd(target, &escape[0], 3); 14631 } 14632 } 14633 } 14634 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 14635 xmlBufContent(target))); 14636 xmlBufFree(target); 14637 xmlXPathReleaseObject(ctxt->context, str); 14638 } 14639 14640 /** 14641 * xmlXPathRegisterAllFunctions: 14642 * @ctxt: the XPath context 14643 * 14644 * Registers all default XPath functions in this context 14645 */ 14646 void 14647 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt) 14648 { 14649 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean", 14650 xmlXPathBooleanFunction); 14651 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling", 14652 xmlXPathCeilingFunction); 14653 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count", 14654 xmlXPathCountFunction); 14655 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat", 14656 xmlXPathConcatFunction); 14657 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains", 14658 xmlXPathContainsFunction); 14659 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id", 14660 xmlXPathIdFunction); 14661 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false", 14662 xmlXPathFalseFunction); 14663 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor", 14664 xmlXPathFloorFunction); 14665 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last", 14666 xmlXPathLastFunction); 14667 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang", 14668 xmlXPathLangFunction); 14669 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name", 14670 xmlXPathLocalNameFunction); 14671 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not", 14672 xmlXPathNotFunction); 14673 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name", 14674 xmlXPathNameFunction); 14675 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri", 14676 xmlXPathNamespaceURIFunction); 14677 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space", 14678 xmlXPathNormalizeFunction); 14679 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number", 14680 xmlXPathNumberFunction); 14681 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position", 14682 xmlXPathPositionFunction); 14683 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round", 14684 xmlXPathRoundFunction); 14685 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string", 14686 xmlXPathStringFunction); 14687 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length", 14688 xmlXPathStringLengthFunction); 14689 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with", 14690 xmlXPathStartsWithFunction); 14691 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring", 14692 xmlXPathSubstringFunction); 14693 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before", 14694 xmlXPathSubstringBeforeFunction); 14695 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after", 14696 xmlXPathSubstringAfterFunction); 14697 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum", 14698 xmlXPathSumFunction); 14699 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true", 14700 xmlXPathTrueFunction); 14701 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate", 14702 xmlXPathTranslateFunction); 14703 14704 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri", 14705 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions", 14706 xmlXPathEscapeUriFunction); 14707 } 14708 14709 #endif /* LIBXML_XPATH_ENABLED */ 14710 #define bottom_xpath 14711 #include "elfgcchack.h" 14712