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 #include <math.h> 29 #include <float.h> 30 #include <ctype.h> 31 32 #include <libxml/xmlmemory.h> 33 #include <libxml/tree.h> 34 #include <libxml/valid.h> 35 #include <libxml/xpath.h> 36 #include <libxml/xpathInternals.h> 37 #include <libxml/parserInternals.h> 38 #include <libxml/hash.h> 39 #ifdef LIBXML_XPTR_LOCS_ENABLED 40 #include <libxml/xpointer.h> 41 #endif 42 #ifdef LIBXML_DEBUG_ENABLED 43 #include <libxml/debugXML.h> 44 #endif 45 #include <libxml/xmlerror.h> 46 #include <libxml/threads.h> 47 #include <libxml/globals.h> 48 #ifdef LIBXML_PATTERN_ENABLED 49 #include <libxml/pattern.h> 50 #endif 51 52 #include "buf.h" 53 54 #ifdef LIBXML_PATTERN_ENABLED 55 #define XPATH_STREAMING 56 #endif 57 58 #define TODO \ 59 xmlGenericError(xmlGenericErrorContext, \ 60 "Unimplemented block at %s:%d\n", \ 61 __FILE__, __LINE__); 62 63 /** 64 * WITH_TIM_SORT: 65 * 66 * Use the Timsort algorithm provided in timsort.h to sort 67 * nodeset as this is a great improvement over the old Shell sort 68 * used in xmlXPathNodeSetSort() 69 */ 70 #define WITH_TIM_SORT 71 72 /* 73 * XP_OPTIMIZED_NON_ELEM_COMPARISON: 74 * If defined, this will use xmlXPathCmpNodesExt() instead of 75 * xmlXPathCmpNodes(). The new function is optimized comparison of 76 * non-element nodes; actually it will speed up comparison only if 77 * xmlXPathOrderDocElems() was called in order to index the elements of 78 * a tree in document order; Libxslt does such an indexing, thus it will 79 * benefit from this optimization. 80 */ 81 #define XP_OPTIMIZED_NON_ELEM_COMPARISON 82 83 /* 84 * XP_OPTIMIZED_FILTER_FIRST: 85 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]" 86 * in a way, that it stop evaluation at the first node. 87 */ 88 #define XP_OPTIMIZED_FILTER_FIRST 89 90 /* 91 * XP_DEBUG_OBJ_USAGE: 92 * Internal flag to enable tracking of how much XPath objects have been 93 * created. 94 */ 95 /* #define XP_DEBUG_OBJ_USAGE */ 96 97 /* 98 * XPATH_MAX_STEPS: 99 * when compiling an XPath expression we arbitrary limit the maximum 100 * number of step operation in the compiled expression. 1000000 is 101 * an insanely large value which should never be reached under normal 102 * circumstances 103 */ 104 #define XPATH_MAX_STEPS 1000000 105 106 /* 107 * XPATH_MAX_STACK_DEPTH: 108 * when evaluating an XPath expression we arbitrary limit the maximum 109 * number of object allowed to be pushed on the stack. 1000000 is 110 * an insanely large value which should never be reached under normal 111 * circumstances 112 */ 113 #define XPATH_MAX_STACK_DEPTH 1000000 114 115 /* 116 * XPATH_MAX_NODESET_LENGTH: 117 * when evaluating an XPath expression nodesets are created and we 118 * arbitrary limit the maximum length of those node set. 10000000 is 119 * an insanely large value which should never be reached under normal 120 * circumstances, one would first need to construct an in memory tree 121 * with more than 10 millions nodes. 122 */ 123 #define XPATH_MAX_NODESET_LENGTH 10000000 124 125 /* 126 * XPATH_MAX_RECRUSION_DEPTH: 127 * Maximum amount of nested functions calls when parsing or evaluating 128 * expressions 129 */ 130 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION 131 #define XPATH_MAX_RECURSION_DEPTH 500 132 #else 133 #define XPATH_MAX_RECURSION_DEPTH 5000 134 #endif 135 136 /* 137 * TODO: 138 * There are a few spots where some tests are done which depend upon ascii 139 * data. These should be enhanced for full UTF8 support (see particularly 140 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT) 141 */ 142 143 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 144 /** 145 * xmlXPathCmpNodesExt: 146 * @node1: the first node 147 * @node2: the second node 148 * 149 * Compare two nodes w.r.t document order. 150 * This one is optimized for handling of non-element nodes. 151 * 152 * Returns -2 in case of error 1 if first point < second point, 0 if 153 * it's the same node, -1 otherwise 154 */ 155 static int 156 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) { 157 int depth1, depth2; 158 int misc = 0, precedence1 = 0, precedence2 = 0; 159 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL; 160 xmlNodePtr cur, root; 161 ptrdiff_t l1, l2; 162 163 if ((node1 == NULL) || (node2 == NULL)) 164 return(-2); 165 166 if (node1 == node2) 167 return(0); 168 169 /* 170 * a couple of optimizations which will avoid computations in most cases 171 */ 172 switch (node1->type) { 173 case XML_ELEMENT_NODE: 174 if (node2->type == XML_ELEMENT_NODE) { 175 if ((0 > (ptrdiff_t) node1->content) && 176 (0 > (ptrdiff_t) node2->content) && 177 (node1->doc == node2->doc)) 178 { 179 l1 = -((ptrdiff_t) node1->content); 180 l2 = -((ptrdiff_t) node2->content); 181 if (l1 < l2) 182 return(1); 183 if (l1 > l2) 184 return(-1); 185 } else 186 goto turtle_comparison; 187 } 188 break; 189 case XML_ATTRIBUTE_NODE: 190 precedence1 = 1; /* element is owner */ 191 miscNode1 = node1; 192 node1 = node1->parent; 193 misc = 1; 194 break; 195 case XML_TEXT_NODE: 196 case XML_CDATA_SECTION_NODE: 197 case XML_COMMENT_NODE: 198 case XML_PI_NODE: { 199 miscNode1 = node1; 200 /* 201 * Find nearest element node. 202 */ 203 if (node1->prev != NULL) { 204 do { 205 node1 = node1->prev; 206 if (node1->type == XML_ELEMENT_NODE) { 207 precedence1 = 3; /* element in prev-sibl axis */ 208 break; 209 } 210 if (node1->prev == NULL) { 211 precedence1 = 2; /* element is parent */ 212 /* 213 * URGENT TODO: Are there any cases, where the 214 * parent of such a node is not an element node? 215 */ 216 node1 = node1->parent; 217 break; 218 } 219 } while (1); 220 } else { 221 precedence1 = 2; /* element is parent */ 222 node1 = node1->parent; 223 } 224 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) || 225 (0 <= (ptrdiff_t) node1->content)) { 226 /* 227 * Fallback for whatever case. 228 */ 229 node1 = miscNode1; 230 precedence1 = 0; 231 } else 232 misc = 1; 233 } 234 break; 235 case XML_NAMESPACE_DECL: 236 /* 237 * TODO: why do we return 1 for namespace nodes? 238 */ 239 return(1); 240 default: 241 break; 242 } 243 switch (node2->type) { 244 case XML_ELEMENT_NODE: 245 break; 246 case XML_ATTRIBUTE_NODE: 247 precedence2 = 1; /* element is owner */ 248 miscNode2 = node2; 249 node2 = node2->parent; 250 misc = 1; 251 break; 252 case XML_TEXT_NODE: 253 case XML_CDATA_SECTION_NODE: 254 case XML_COMMENT_NODE: 255 case XML_PI_NODE: { 256 miscNode2 = node2; 257 if (node2->prev != NULL) { 258 do { 259 node2 = node2->prev; 260 if (node2->type == XML_ELEMENT_NODE) { 261 precedence2 = 3; /* element in prev-sibl axis */ 262 break; 263 } 264 if (node2->prev == NULL) { 265 precedence2 = 2; /* element is parent */ 266 node2 = node2->parent; 267 break; 268 } 269 } while (1); 270 } else { 271 precedence2 = 2; /* element is parent */ 272 node2 = node2->parent; 273 } 274 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) || 275 (0 <= (ptrdiff_t) node2->content)) 276 { 277 node2 = miscNode2; 278 precedence2 = 0; 279 } else 280 misc = 1; 281 } 282 break; 283 case XML_NAMESPACE_DECL: 284 return(1); 285 default: 286 break; 287 } 288 if (misc) { 289 if (node1 == node2) { 290 if (precedence1 == precedence2) { 291 /* 292 * The ugly case; but normally there aren't many 293 * adjacent non-element nodes around. 294 */ 295 cur = miscNode2->prev; 296 while (cur != NULL) { 297 if (cur == miscNode1) 298 return(1); 299 if (cur->type == XML_ELEMENT_NODE) 300 return(-1); 301 cur = cur->prev; 302 } 303 return (-1); 304 } else { 305 /* 306 * Evaluate based on higher precedence wrt to the element. 307 * TODO: This assumes attributes are sorted before content. 308 * Is this 100% correct? 309 */ 310 if (precedence1 < precedence2) 311 return(1); 312 else 313 return(-1); 314 } 315 } 316 /* 317 * Special case: One of the helper-elements is contained by the other. 318 * <foo> 319 * <node2> 320 * <node1>Text-1(precedence1 == 2)</node1> 321 * </node2> 322 * Text-6(precedence2 == 3) 323 * </foo> 324 */ 325 if ((precedence2 == 3) && (precedence1 > 1)) { 326 cur = node1->parent; 327 while (cur) { 328 if (cur == node2) 329 return(1); 330 cur = cur->parent; 331 } 332 } 333 if ((precedence1 == 3) && (precedence2 > 1)) { 334 cur = node2->parent; 335 while (cur) { 336 if (cur == node1) 337 return(-1); 338 cur = cur->parent; 339 } 340 } 341 } 342 343 /* 344 * Speedup using document order if available. 345 */ 346 if ((node1->type == XML_ELEMENT_NODE) && 347 (node2->type == XML_ELEMENT_NODE) && 348 (0 > (ptrdiff_t) node1->content) && 349 (0 > (ptrdiff_t) node2->content) && 350 (node1->doc == node2->doc)) { 351 352 l1 = -((ptrdiff_t) node1->content); 353 l2 = -((ptrdiff_t) node2->content); 354 if (l1 < l2) 355 return(1); 356 if (l1 > l2) 357 return(-1); 358 } 359 360 turtle_comparison: 361 362 if (node1 == node2->prev) 363 return(1); 364 if (node1 == node2->next) 365 return(-1); 366 /* 367 * compute depth to root 368 */ 369 for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) { 370 if (cur->parent == node1) 371 return(1); 372 depth2++; 373 } 374 root = cur; 375 for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) { 376 if (cur->parent == node2) 377 return(-1); 378 depth1++; 379 } 380 /* 381 * Distinct document (or distinct entities :-( ) case. 382 */ 383 if (root != cur) { 384 return(-2); 385 } 386 /* 387 * get the nearest common ancestor. 388 */ 389 while (depth1 > depth2) { 390 depth1--; 391 node1 = node1->parent; 392 } 393 while (depth2 > depth1) { 394 depth2--; 395 node2 = node2->parent; 396 } 397 while (node1->parent != node2->parent) { 398 node1 = node1->parent; 399 node2 = node2->parent; 400 /* should not happen but just in case ... */ 401 if ((node1 == NULL) || (node2 == NULL)) 402 return(-2); 403 } 404 /* 405 * Find who's first. 406 */ 407 if (node1 == node2->prev) 408 return(1); 409 if (node1 == node2->next) 410 return(-1); 411 /* 412 * Speedup using document order if available. 413 */ 414 if ((node1->type == XML_ELEMENT_NODE) && 415 (node2->type == XML_ELEMENT_NODE) && 416 (0 > (ptrdiff_t) node1->content) && 417 (0 > (ptrdiff_t) node2->content) && 418 (node1->doc == node2->doc)) { 419 420 l1 = -((ptrdiff_t) node1->content); 421 l2 = -((ptrdiff_t) node2->content); 422 if (l1 < l2) 423 return(1); 424 if (l1 > l2) 425 return(-1); 426 } 427 428 for (cur = node1->next;cur != NULL;cur = cur->next) 429 if (cur == node2) 430 return(1); 431 return(-1); /* assume there is no sibling list corruption */ 432 } 433 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */ 434 435 /* 436 * Wrapper for the Timsort algorithm from timsort.h 437 */ 438 #ifdef WITH_TIM_SORT 439 #define SORT_NAME libxml_domnode 440 #define SORT_TYPE xmlNodePtr 441 /** 442 * wrap_cmp: 443 * @x: a node 444 * @y: another node 445 * 446 * Comparison function for the Timsort implementation 447 * 448 * Returns -2 in case of error -1 if first point < second point, 0 if 449 * it's the same node, +1 otherwise 450 */ 451 static 452 int wrap_cmp( xmlNodePtr x, xmlNodePtr y ); 453 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 454 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y ) 455 { 456 int res = xmlXPathCmpNodesExt(x, y); 457 return res == -2 ? res : -res; 458 } 459 #else 460 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y ) 461 { 462 int res = xmlXPathCmpNodes(x, y); 463 return res == -2 ? res : -res; 464 } 465 #endif 466 #define SORT_CMP(x, y) (wrap_cmp(x, y)) 467 #include "timsort.h" 468 #endif /* WITH_TIM_SORT */ 469 470 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) 471 472 /************************************************************************ 473 * * 474 * Floating point stuff * 475 * * 476 ************************************************************************/ 477 478 double xmlXPathNAN = 0.0; 479 double xmlXPathPINF = 0.0; 480 double xmlXPathNINF = 0.0; 481 482 /** 483 * xmlXPathInit: 484 * 485 * DEPRECATED: This function will be made private. Call xmlInitParser to 486 * initialize the library. 487 * 488 * Initialize the XPath environment 489 */ 490 ATTRIBUTE_NO_SANITIZE("float-divide-by-zero") 491 void 492 xmlXPathInit(void) { 493 #if defined(NAN) && defined(INFINITY) 494 xmlXPathNAN = NAN; 495 xmlXPathPINF = INFINITY; 496 xmlXPathNINF = -INFINITY; 497 #else 498 /* MSVC doesn't allow division by zero in constant expressions. */ 499 double zero = 0.0; 500 xmlXPathNAN = 0.0 / zero; 501 xmlXPathPINF = 1.0 / zero; 502 xmlXPathNINF = -xmlXPathPINF; 503 #endif 504 } 505 506 /** 507 * xmlXPathIsNaN: 508 * @val: a double value 509 * 510 * Returns 1 if the value is a NaN, 0 otherwise 511 */ 512 int 513 xmlXPathIsNaN(double val) { 514 #ifdef isnan 515 return isnan(val); 516 #else 517 return !(val == val); 518 #endif 519 } 520 521 /** 522 * xmlXPathIsInf: 523 * @val: a double value 524 * 525 * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise 526 */ 527 int 528 xmlXPathIsInf(double val) { 529 #ifdef isinf 530 return isinf(val) ? (val > 0 ? 1 : -1) : 0; 531 #else 532 if (val >= xmlXPathPINF) 533 return 1; 534 if (val <= -xmlXPathPINF) 535 return -1; 536 return 0; 537 #endif 538 } 539 540 #endif /* SCHEMAS or XPATH */ 541 542 #ifdef LIBXML_XPATH_ENABLED 543 544 /* 545 * TODO: when compatibility allows remove all "fake node libxslt" strings 546 * the test should just be name[0] = ' ' 547 */ 548 #ifdef DEBUG_XPATH_EXPRESSION 549 #define DEBUG_STEP 550 #define DEBUG_EXPR 551 #define DEBUG_EVAL_COUNTS 552 #endif 553 554 static xmlNs xmlXPathXMLNamespaceStruct = { 555 NULL, 556 XML_NAMESPACE_DECL, 557 XML_XML_NAMESPACE, 558 BAD_CAST "xml", 559 NULL, 560 NULL 561 }; 562 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct; 563 #ifndef LIBXML_THREAD_ENABLED 564 /* 565 * Optimizer is disabled only when threaded apps are detected while 566 * the library ain't compiled for thread safety. 567 */ 568 static int xmlXPathDisableOptimizer = 0; 569 #endif 570 571 /************************************************************************ 572 * * 573 * Error handling routines * 574 * * 575 ************************************************************************/ 576 577 /** 578 * XP_ERRORNULL: 579 * @X: the error code 580 * 581 * Macro to raise an XPath error and return NULL. 582 */ 583 #define XP_ERRORNULL(X) \ 584 { xmlXPathErr(ctxt, X); return(NULL); } 585 586 /* 587 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError 588 */ 589 static const char* const xmlXPathErrorMessages[] = { 590 "Ok\n", 591 "Number encoding\n", 592 "Unfinished literal\n", 593 "Start of literal\n", 594 "Expected $ for variable reference\n", 595 "Undefined variable\n", 596 "Invalid predicate\n", 597 "Invalid expression\n", 598 "Missing closing curly brace\n", 599 "Unregistered function\n", 600 "Invalid operand\n", 601 "Invalid type\n", 602 "Invalid number of arguments\n", 603 "Invalid context size\n", 604 "Invalid context position\n", 605 "Memory allocation error\n", 606 "Syntax error\n", 607 "Resource error\n", 608 "Sub resource error\n", 609 "Undefined namespace prefix\n", 610 "Encoding error\n", 611 "Char out of XML range\n", 612 "Invalid or incomplete context\n", 613 "Stack usage error\n", 614 "Forbidden variable\n", 615 "Operation limit exceeded\n", 616 "Recursion limit exceeded\n", 617 "?? Unknown error ??\n" /* Must be last in the list! */ 618 }; 619 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \ 620 sizeof(xmlXPathErrorMessages[0])) - 1) 621 /** 622 * xmlXPathErrMemory: 623 * @ctxt: an XPath context 624 * @extra: extra information 625 * 626 * Handle a redefinition of attribute error 627 */ 628 static void 629 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra) 630 { 631 if (ctxt != NULL) { 632 xmlResetError(&ctxt->lastError); 633 if (extra) { 634 xmlChar buf[200]; 635 636 xmlStrPrintf(buf, 200, 637 "Memory allocation failed : %s\n", 638 extra); 639 ctxt->lastError.message = (char *) xmlStrdup(buf); 640 } else { 641 ctxt->lastError.message = (char *) 642 xmlStrdup(BAD_CAST "Memory allocation failed\n"); 643 } 644 ctxt->lastError.domain = XML_FROM_XPATH; 645 ctxt->lastError.code = XML_ERR_NO_MEMORY; 646 if (ctxt->error != NULL) 647 ctxt->error(ctxt->userData, &ctxt->lastError); 648 } else { 649 if (extra) 650 __xmlRaiseError(NULL, NULL, NULL, 651 NULL, NULL, XML_FROM_XPATH, 652 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, 653 extra, NULL, NULL, 0, 0, 654 "Memory allocation failed : %s\n", extra); 655 else 656 __xmlRaiseError(NULL, NULL, NULL, 657 NULL, NULL, XML_FROM_XPATH, 658 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, 659 NULL, NULL, NULL, 0, 0, 660 "Memory allocation failed\n"); 661 } 662 } 663 664 /** 665 * xmlXPathPErrMemory: 666 * @ctxt: an XPath parser context 667 * @extra: extra information 668 * 669 * Handle a redefinition of attribute error 670 */ 671 static void 672 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra) 673 { 674 if (ctxt == NULL) 675 xmlXPathErrMemory(NULL, extra); 676 else { 677 ctxt->error = XPATH_MEMORY_ERROR; 678 xmlXPathErrMemory(ctxt->context, extra); 679 } 680 } 681 682 /** 683 * xmlXPathErr: 684 * @ctxt: a XPath parser context 685 * @error: the error code 686 * 687 * Handle an XPath error 688 */ 689 void 690 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error) 691 { 692 if ((error < 0) || (error > MAXERRNO)) 693 error = MAXERRNO; 694 if (ctxt == NULL) { 695 __xmlRaiseError(NULL, NULL, NULL, 696 NULL, NULL, XML_FROM_XPATH, 697 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, 698 XML_ERR_ERROR, NULL, 0, 699 NULL, NULL, NULL, 0, 0, 700 "%s", xmlXPathErrorMessages[error]); 701 return; 702 } 703 ctxt->error = error; 704 if (ctxt->context == NULL) { 705 __xmlRaiseError(NULL, NULL, NULL, 706 NULL, NULL, XML_FROM_XPATH, 707 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, 708 XML_ERR_ERROR, NULL, 0, 709 (const char *) ctxt->base, NULL, NULL, 710 ctxt->cur - ctxt->base, 0, 711 "%s", xmlXPathErrorMessages[error]); 712 return; 713 } 714 715 /* cleanup current last error */ 716 xmlResetError(&ctxt->context->lastError); 717 718 ctxt->context->lastError.domain = XML_FROM_XPATH; 719 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK - 720 XPATH_EXPRESSION_OK; 721 ctxt->context->lastError.level = XML_ERR_ERROR; 722 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base); 723 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base; 724 ctxt->context->lastError.node = ctxt->context->debugNode; 725 if (ctxt->context->error != NULL) { 726 ctxt->context->error(ctxt->context->userData, 727 &ctxt->context->lastError); 728 } else { 729 __xmlRaiseError(NULL, NULL, NULL, 730 NULL, ctxt->context->debugNode, XML_FROM_XPATH, 731 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, 732 XML_ERR_ERROR, NULL, 0, 733 (const char *) ctxt->base, NULL, NULL, 734 ctxt->cur - ctxt->base, 0, 735 "%s", xmlXPathErrorMessages[error]); 736 } 737 738 } 739 740 /** 741 * xmlXPatherror: 742 * @ctxt: the XPath Parser context 743 * @file: the file name 744 * @line: the line number 745 * @no: the error number 746 * 747 * Formats an error message. 748 */ 749 void 750 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED, 751 int line ATTRIBUTE_UNUSED, int no) { 752 xmlXPathErr(ctxt, no); 753 } 754 755 /** 756 * xmlXPathCheckOpLimit: 757 * @ctxt: the XPath Parser context 758 * @opCount: the number of operations to be added 759 * 760 * Adds opCount to the running total of operations and returns -1 if the 761 * operation limit is exceeded. Returns 0 otherwise. 762 */ 763 static int 764 xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) { 765 xmlXPathContextPtr xpctxt = ctxt->context; 766 767 if ((opCount > xpctxt->opLimit) || 768 (xpctxt->opCount > xpctxt->opLimit - opCount)) { 769 xpctxt->opCount = xpctxt->opLimit; 770 xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED); 771 return(-1); 772 } 773 774 xpctxt->opCount += opCount; 775 return(0); 776 } 777 778 #define OP_LIMIT_EXCEEDED(ctxt, n) \ 779 ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0)) 780 781 /************************************************************************ 782 * * 783 * Utilities * 784 * * 785 ************************************************************************/ 786 787 /** 788 * xsltPointerList: 789 * 790 * Pointer-list for various purposes. 791 */ 792 typedef struct _xmlPointerList xmlPointerList; 793 typedef xmlPointerList *xmlPointerListPtr; 794 struct _xmlPointerList { 795 void **items; 796 int number; 797 int size; 798 }; 799 /* 800 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt 801 * and here, we should make the functions public. 802 */ 803 static int 804 xmlPointerListAddSize(xmlPointerListPtr list, 805 void *item, 806 int initialSize) 807 { 808 if (list->items == NULL) { 809 if (initialSize <= 0) 810 initialSize = 1; 811 list->items = (void **) xmlMalloc(initialSize * sizeof(void *)); 812 if (list->items == NULL) { 813 xmlXPathErrMemory(NULL, 814 "xmlPointerListCreate: allocating item\n"); 815 return(-1); 816 } 817 list->number = 0; 818 list->size = initialSize; 819 } else if (list->size <= list->number) { 820 if (list->size > 50000000) { 821 xmlXPathErrMemory(NULL, 822 "xmlPointerListAddSize: re-allocating item\n"); 823 return(-1); 824 } 825 list->size *= 2; 826 list->items = (void **) xmlRealloc(list->items, 827 list->size * sizeof(void *)); 828 if (list->items == NULL) { 829 xmlXPathErrMemory(NULL, 830 "xmlPointerListAddSize: re-allocating item\n"); 831 list->size = 0; 832 return(-1); 833 } 834 } 835 list->items[list->number++] = item; 836 return(0); 837 } 838 839 /** 840 * xsltPointerListCreate: 841 * 842 * Creates an xsltPointerList structure. 843 * 844 * Returns a xsltPointerList structure or NULL in case of an error. 845 */ 846 static xmlPointerListPtr 847 xmlPointerListCreate(int initialSize) 848 { 849 xmlPointerListPtr ret; 850 851 ret = xmlMalloc(sizeof(xmlPointerList)); 852 if (ret == NULL) { 853 xmlXPathErrMemory(NULL, 854 "xmlPointerListCreate: allocating item\n"); 855 return (NULL); 856 } 857 memset(ret, 0, sizeof(xmlPointerList)); 858 if (initialSize > 0) { 859 xmlPointerListAddSize(ret, NULL, initialSize); 860 ret->number = 0; 861 } 862 return (ret); 863 } 864 865 /** 866 * xsltPointerListFree: 867 * 868 * Frees the xsltPointerList structure. This does not free 869 * the content of the list. 870 */ 871 static void 872 xmlPointerListFree(xmlPointerListPtr list) 873 { 874 if (list == NULL) 875 return; 876 if (list->items != NULL) 877 xmlFree(list->items); 878 xmlFree(list); 879 } 880 881 /************************************************************************ 882 * * 883 * Parser Types * 884 * * 885 ************************************************************************/ 886 887 /* 888 * Types are private: 889 */ 890 891 typedef enum { 892 XPATH_OP_END=0, 893 XPATH_OP_AND, 894 XPATH_OP_OR, 895 XPATH_OP_EQUAL, 896 XPATH_OP_CMP, 897 XPATH_OP_PLUS, 898 XPATH_OP_MULT, 899 XPATH_OP_UNION, 900 XPATH_OP_ROOT, 901 XPATH_OP_NODE, 902 XPATH_OP_COLLECT, 903 XPATH_OP_VALUE, /* 11 */ 904 XPATH_OP_VARIABLE, 905 XPATH_OP_FUNCTION, 906 XPATH_OP_ARG, 907 XPATH_OP_PREDICATE, 908 XPATH_OP_FILTER, /* 16 */ 909 XPATH_OP_SORT /* 17 */ 910 #ifdef LIBXML_XPTR_LOCS_ENABLED 911 ,XPATH_OP_RANGETO 912 #endif 913 } xmlXPathOp; 914 915 typedef enum { 916 AXIS_ANCESTOR = 1, 917 AXIS_ANCESTOR_OR_SELF, 918 AXIS_ATTRIBUTE, 919 AXIS_CHILD, 920 AXIS_DESCENDANT, 921 AXIS_DESCENDANT_OR_SELF, 922 AXIS_FOLLOWING, 923 AXIS_FOLLOWING_SIBLING, 924 AXIS_NAMESPACE, 925 AXIS_PARENT, 926 AXIS_PRECEDING, 927 AXIS_PRECEDING_SIBLING, 928 AXIS_SELF 929 } xmlXPathAxisVal; 930 931 typedef enum { 932 NODE_TEST_NONE = 0, 933 NODE_TEST_TYPE = 1, 934 NODE_TEST_PI = 2, 935 NODE_TEST_ALL = 3, 936 NODE_TEST_NS = 4, 937 NODE_TEST_NAME = 5 938 } xmlXPathTestVal; 939 940 typedef enum { 941 NODE_TYPE_NODE = 0, 942 NODE_TYPE_COMMENT = XML_COMMENT_NODE, 943 NODE_TYPE_TEXT = XML_TEXT_NODE, 944 NODE_TYPE_PI = XML_PI_NODE 945 } xmlXPathTypeVal; 946 947 typedef struct _xmlXPathStepOp xmlXPathStepOp; 948 typedef xmlXPathStepOp *xmlXPathStepOpPtr; 949 struct _xmlXPathStepOp { 950 xmlXPathOp op; /* The identifier of the operation */ 951 int ch1; /* First child */ 952 int ch2; /* Second child */ 953 int value; 954 int value2; 955 int value3; 956 void *value4; 957 void *value5; 958 xmlXPathFunction cache; 959 void *cacheURI; 960 }; 961 962 struct _xmlXPathCompExpr { 963 int nbStep; /* Number of steps in this expression */ 964 int maxStep; /* Maximum number of steps allocated */ 965 xmlXPathStepOp *steps; /* ops for computation of this expression */ 966 int last; /* index of last step in expression */ 967 xmlChar *expr; /* the expression being computed */ 968 xmlDictPtr dict; /* the dictionary to use if any */ 969 #ifdef DEBUG_EVAL_COUNTS 970 int nb; 971 xmlChar *string; 972 #endif 973 #ifdef XPATH_STREAMING 974 xmlPatternPtr stream; 975 #endif 976 }; 977 978 /************************************************************************ 979 * * 980 * Forward declarations * 981 * * 982 ************************************************************************/ 983 static void 984 xmlXPathFreeValueTree(xmlNodeSetPtr obj); 985 static void 986 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj); 987 static int 988 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt, 989 xmlXPathStepOpPtr op, xmlNodePtr *first); 990 static int 991 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt, 992 xmlXPathStepOpPtr op, 993 int isPredicate); 994 static void 995 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name); 996 997 /************************************************************************ 998 * * 999 * Parser Type functions * 1000 * * 1001 ************************************************************************/ 1002 1003 /** 1004 * xmlXPathNewCompExpr: 1005 * 1006 * Create a new Xpath component 1007 * 1008 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error 1009 */ 1010 static xmlXPathCompExprPtr 1011 xmlXPathNewCompExpr(void) { 1012 xmlXPathCompExprPtr cur; 1013 1014 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr)); 1015 if (cur == NULL) { 1016 xmlXPathErrMemory(NULL, "allocating component\n"); 1017 return(NULL); 1018 } 1019 memset(cur, 0, sizeof(xmlXPathCompExpr)); 1020 cur->maxStep = 10; 1021 cur->nbStep = 0; 1022 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep * 1023 sizeof(xmlXPathStepOp)); 1024 if (cur->steps == NULL) { 1025 xmlXPathErrMemory(NULL, "allocating steps\n"); 1026 xmlFree(cur); 1027 return(NULL); 1028 } 1029 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp)); 1030 cur->last = -1; 1031 #ifdef DEBUG_EVAL_COUNTS 1032 cur->nb = 0; 1033 #endif 1034 return(cur); 1035 } 1036 1037 /** 1038 * xmlXPathFreeCompExpr: 1039 * @comp: an XPATH comp 1040 * 1041 * Free up the memory allocated by @comp 1042 */ 1043 void 1044 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp) 1045 { 1046 xmlXPathStepOpPtr op; 1047 int i; 1048 1049 if (comp == NULL) 1050 return; 1051 if (comp->dict == NULL) { 1052 for (i = 0; i < comp->nbStep; i++) { 1053 op = &comp->steps[i]; 1054 if (op->value4 != NULL) { 1055 if (op->op == XPATH_OP_VALUE) 1056 xmlXPathFreeObject(op->value4); 1057 else 1058 xmlFree(op->value4); 1059 } 1060 if (op->value5 != NULL) 1061 xmlFree(op->value5); 1062 } 1063 } else { 1064 for (i = 0; i < comp->nbStep; i++) { 1065 op = &comp->steps[i]; 1066 if (op->value4 != NULL) { 1067 if (op->op == XPATH_OP_VALUE) 1068 xmlXPathFreeObject(op->value4); 1069 } 1070 } 1071 xmlDictFree(comp->dict); 1072 } 1073 if (comp->steps != NULL) { 1074 xmlFree(comp->steps); 1075 } 1076 #ifdef DEBUG_EVAL_COUNTS 1077 if (comp->string != NULL) { 1078 xmlFree(comp->string); 1079 } 1080 #endif 1081 #ifdef XPATH_STREAMING 1082 if (comp->stream != NULL) { 1083 xmlFreePatternList(comp->stream); 1084 } 1085 #endif 1086 if (comp->expr != NULL) { 1087 xmlFree(comp->expr); 1088 } 1089 1090 xmlFree(comp); 1091 } 1092 1093 /** 1094 * xmlXPathCompExprAdd: 1095 * @comp: the compiled expression 1096 * @ch1: first child index 1097 * @ch2: second child index 1098 * @op: an op 1099 * @value: the first int value 1100 * @value2: the second int value 1101 * @value3: the third int value 1102 * @value4: the first string value 1103 * @value5: the second string value 1104 * 1105 * Add a step to an XPath Compiled Expression 1106 * 1107 * Returns -1 in case of failure, the index otherwise 1108 */ 1109 static int 1110 xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2, 1111 xmlXPathOp op, int value, 1112 int value2, int value3, void *value4, void *value5) { 1113 xmlXPathCompExprPtr comp = ctxt->comp; 1114 if (comp->nbStep >= comp->maxStep) { 1115 xmlXPathStepOp *real; 1116 1117 if (comp->maxStep >= XPATH_MAX_STEPS) { 1118 xmlXPathPErrMemory(ctxt, "adding step\n"); 1119 return(-1); 1120 } 1121 comp->maxStep *= 2; 1122 real = (xmlXPathStepOp *) xmlRealloc(comp->steps, 1123 comp->maxStep * sizeof(xmlXPathStepOp)); 1124 if (real == NULL) { 1125 comp->maxStep /= 2; 1126 xmlXPathPErrMemory(ctxt, "adding step\n"); 1127 return(-1); 1128 } 1129 comp->steps = real; 1130 } 1131 comp->last = comp->nbStep; 1132 comp->steps[comp->nbStep].ch1 = ch1; 1133 comp->steps[comp->nbStep].ch2 = ch2; 1134 comp->steps[comp->nbStep].op = op; 1135 comp->steps[comp->nbStep].value = value; 1136 comp->steps[comp->nbStep].value2 = value2; 1137 comp->steps[comp->nbStep].value3 = value3; 1138 if ((comp->dict != NULL) && 1139 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) || 1140 (op == XPATH_OP_COLLECT))) { 1141 if (value4 != NULL) { 1142 comp->steps[comp->nbStep].value4 = (xmlChar *) 1143 (void *)xmlDictLookup(comp->dict, value4, -1); 1144 xmlFree(value4); 1145 } else 1146 comp->steps[comp->nbStep].value4 = NULL; 1147 if (value5 != NULL) { 1148 comp->steps[comp->nbStep].value5 = (xmlChar *) 1149 (void *)xmlDictLookup(comp->dict, value5, -1); 1150 xmlFree(value5); 1151 } else 1152 comp->steps[comp->nbStep].value5 = NULL; 1153 } else { 1154 comp->steps[comp->nbStep].value4 = value4; 1155 comp->steps[comp->nbStep].value5 = value5; 1156 } 1157 comp->steps[comp->nbStep].cache = NULL; 1158 return(comp->nbStep++); 1159 } 1160 1161 /** 1162 * xmlXPathCompSwap: 1163 * @comp: the compiled expression 1164 * @op: operation index 1165 * 1166 * Swaps 2 operations in the compiled expression 1167 */ 1168 static void 1169 xmlXPathCompSwap(xmlXPathStepOpPtr op) { 1170 int tmp; 1171 1172 #ifndef LIBXML_THREAD_ENABLED 1173 /* 1174 * Since this manipulates possibly shared variables, this is 1175 * disabled if one detects that the library is used in a multithreaded 1176 * application 1177 */ 1178 if (xmlXPathDisableOptimizer) 1179 return; 1180 #endif 1181 1182 tmp = op->ch1; 1183 op->ch1 = op->ch2; 1184 op->ch2 = tmp; 1185 } 1186 1187 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \ 1188 xmlXPathCompExprAdd(ctxt, (op1), (op2), \ 1189 (op), (val), (val2), (val3), (val4), (val5)) 1190 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \ 1191 xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1, \ 1192 (op), (val), (val2), (val3), (val4), (val5)) 1193 1194 #define PUSH_LEAVE_EXPR(op, val, val2) \ 1195 xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL) 1196 1197 #define PUSH_UNARY_EXPR(op, ch, val, val2) \ 1198 xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL) 1199 1200 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \ 1201 xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op), \ 1202 (val), (val2), 0 ,NULL ,NULL) 1203 1204 /************************************************************************ 1205 * * 1206 * XPath object cache structures * 1207 * * 1208 ************************************************************************/ 1209 1210 /* #define XP_DEFAULT_CACHE_ON */ 1211 1212 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL)) 1213 1214 typedef struct _xmlXPathContextCache xmlXPathContextCache; 1215 typedef xmlXPathContextCache *xmlXPathContextCachePtr; 1216 struct _xmlXPathContextCache { 1217 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */ 1218 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */ 1219 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */ 1220 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */ 1221 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */ 1222 int maxNodeset; 1223 int maxString; 1224 int maxBoolean; 1225 int maxNumber; 1226 int maxMisc; 1227 #ifdef XP_DEBUG_OBJ_USAGE 1228 int dbgCachedAll; 1229 int dbgCachedNodeset; 1230 int dbgCachedString; 1231 int dbgCachedBool; 1232 int dbgCachedNumber; 1233 int dbgCachedPoint; 1234 int dbgCachedRange; 1235 int dbgCachedLocset; 1236 int dbgCachedUsers; 1237 int dbgCachedXSLTTree; 1238 int dbgCachedUndefined; 1239 1240 1241 int dbgReusedAll; 1242 int dbgReusedNodeset; 1243 int dbgReusedString; 1244 int dbgReusedBool; 1245 int dbgReusedNumber; 1246 int dbgReusedPoint; 1247 int dbgReusedRange; 1248 int dbgReusedLocset; 1249 int dbgReusedUsers; 1250 int dbgReusedXSLTTree; 1251 int dbgReusedUndefined; 1252 1253 #endif 1254 }; 1255 1256 /************************************************************************ 1257 * * 1258 * Debugging related functions * 1259 * * 1260 ************************************************************************/ 1261 1262 #define STRANGE \ 1263 xmlGenericError(xmlGenericErrorContext, \ 1264 "Internal error at %s:%d\n", \ 1265 __FILE__, __LINE__); 1266 1267 #ifdef LIBXML_DEBUG_ENABLED 1268 static void 1269 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) { 1270 int i; 1271 char shift[100]; 1272 1273 for (i = 0;((i < depth) && (i < 25));i++) 1274 shift[2 * i] = shift[2 * i + 1] = ' '; 1275 shift[2 * i] = shift[2 * i + 1] = 0; 1276 if (cur == NULL) { 1277 fprintf(output, "%s", shift); 1278 fprintf(output, "Node is NULL !\n"); 1279 return; 1280 1281 } 1282 1283 if ((cur->type == XML_DOCUMENT_NODE) || 1284 (cur->type == XML_HTML_DOCUMENT_NODE)) { 1285 fprintf(output, "%s", shift); 1286 fprintf(output, " /\n"); 1287 } else if (cur->type == XML_ATTRIBUTE_NODE) 1288 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth); 1289 else 1290 xmlDebugDumpOneNode(output, cur, depth); 1291 } 1292 static void 1293 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) { 1294 xmlNodePtr tmp; 1295 int i; 1296 char shift[100]; 1297 1298 for (i = 0;((i < depth) && (i < 25));i++) 1299 shift[2 * i] = shift[2 * i + 1] = ' '; 1300 shift[2 * i] = shift[2 * i + 1] = 0; 1301 if (cur == NULL) { 1302 fprintf(output, "%s", shift); 1303 fprintf(output, "Node is NULL !\n"); 1304 return; 1305 1306 } 1307 1308 while (cur != NULL) { 1309 tmp = cur; 1310 cur = cur->next; 1311 xmlDebugDumpOneNode(output, tmp, depth); 1312 } 1313 } 1314 1315 static void 1316 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) { 1317 int i; 1318 char shift[100]; 1319 1320 for (i = 0;((i < depth) && (i < 25));i++) 1321 shift[2 * i] = shift[2 * i + 1] = ' '; 1322 shift[2 * i] = shift[2 * i + 1] = 0; 1323 1324 if (cur == NULL) { 1325 fprintf(output, "%s", shift); 1326 fprintf(output, "NodeSet is NULL !\n"); 1327 return; 1328 1329 } 1330 1331 if (cur != NULL) { 1332 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr); 1333 for (i = 0;i < cur->nodeNr;i++) { 1334 fprintf(output, "%s", shift); 1335 fprintf(output, "%d", i + 1); 1336 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1); 1337 } 1338 } 1339 } 1340 1341 static void 1342 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) { 1343 int i; 1344 char shift[100]; 1345 1346 for (i = 0;((i < depth) && (i < 25));i++) 1347 shift[2 * i] = shift[2 * i + 1] = ' '; 1348 shift[2 * i] = shift[2 * i + 1] = 0; 1349 1350 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) { 1351 fprintf(output, "%s", shift); 1352 fprintf(output, "Value Tree is NULL !\n"); 1353 return; 1354 1355 } 1356 1357 fprintf(output, "%s", shift); 1358 fprintf(output, "%d", i + 1); 1359 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1); 1360 } 1361 #if defined(LIBXML_XPTR_LOCS_ENABLED) 1362 static void 1363 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) { 1364 int i; 1365 char shift[100]; 1366 1367 for (i = 0;((i < depth) && (i < 25));i++) 1368 shift[2 * i] = shift[2 * i + 1] = ' '; 1369 shift[2 * i] = shift[2 * i + 1] = 0; 1370 1371 if (cur == NULL) { 1372 fprintf(output, "%s", shift); 1373 fprintf(output, "LocationSet is NULL !\n"); 1374 return; 1375 1376 } 1377 1378 for (i = 0;i < cur->locNr;i++) { 1379 fprintf(output, "%s", shift); 1380 fprintf(output, "%d : ", i + 1); 1381 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1); 1382 } 1383 } 1384 #endif /* LIBXML_XPTR_LOCS_ENABLED */ 1385 1386 /** 1387 * xmlXPathDebugDumpObject: 1388 * @output: the FILE * to dump the output 1389 * @cur: the object to inspect 1390 * @depth: indentation level 1391 * 1392 * Dump the content of the object for debugging purposes 1393 */ 1394 void 1395 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) { 1396 int i; 1397 char shift[100]; 1398 1399 if (output == NULL) return; 1400 1401 for (i = 0;((i < depth) && (i < 25));i++) 1402 shift[2 * i] = shift[2 * i + 1] = ' '; 1403 shift[2 * i] = shift[2 * i + 1] = 0; 1404 1405 1406 fprintf(output, "%s", shift); 1407 1408 if (cur == NULL) { 1409 fprintf(output, "Object is empty (NULL)\n"); 1410 return; 1411 } 1412 switch(cur->type) { 1413 case XPATH_UNDEFINED: 1414 fprintf(output, "Object is uninitialized\n"); 1415 break; 1416 case XPATH_NODESET: 1417 fprintf(output, "Object is a Node Set :\n"); 1418 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth); 1419 break; 1420 case XPATH_XSLT_TREE: 1421 fprintf(output, "Object is an XSLT value tree :\n"); 1422 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth); 1423 break; 1424 case XPATH_BOOLEAN: 1425 fprintf(output, "Object is a Boolean : "); 1426 if (cur->boolval) fprintf(output, "true\n"); 1427 else fprintf(output, "false\n"); 1428 break; 1429 case XPATH_NUMBER: 1430 switch (xmlXPathIsInf(cur->floatval)) { 1431 case 1: 1432 fprintf(output, "Object is a number : Infinity\n"); 1433 break; 1434 case -1: 1435 fprintf(output, "Object is a number : -Infinity\n"); 1436 break; 1437 default: 1438 if (xmlXPathIsNaN(cur->floatval)) { 1439 fprintf(output, "Object is a number : NaN\n"); 1440 } else if (cur->floatval == 0) { 1441 /* Omit sign for negative zero. */ 1442 fprintf(output, "Object is a number : 0\n"); 1443 } else { 1444 fprintf(output, "Object is a number : %0g\n", cur->floatval); 1445 } 1446 } 1447 break; 1448 case XPATH_STRING: 1449 fprintf(output, "Object is a string : "); 1450 xmlDebugDumpString(output, cur->stringval); 1451 fprintf(output, "\n"); 1452 break; 1453 #ifdef LIBXML_XPTR_LOCS_ENABLED 1454 case XPATH_POINT: 1455 fprintf(output, "Object is a point : index %d in node", cur->index); 1456 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1); 1457 fprintf(output, "\n"); 1458 break; 1459 case XPATH_RANGE: 1460 if ((cur->user2 == NULL) || 1461 ((cur->user2 == cur->user) && (cur->index == cur->index2))) { 1462 fprintf(output, "Object is a collapsed range :\n"); 1463 fprintf(output, "%s", shift); 1464 if (cur->index >= 0) 1465 fprintf(output, "index %d in ", cur->index); 1466 fprintf(output, "node\n"); 1467 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, 1468 depth + 1); 1469 } else { 1470 fprintf(output, "Object is a range :\n"); 1471 fprintf(output, "%s", shift); 1472 fprintf(output, "From "); 1473 if (cur->index >= 0) 1474 fprintf(output, "index %d in ", cur->index); 1475 fprintf(output, "node\n"); 1476 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, 1477 depth + 1); 1478 fprintf(output, "%s", shift); 1479 fprintf(output, "To "); 1480 if (cur->index2 >= 0) 1481 fprintf(output, "index %d in ", cur->index2); 1482 fprintf(output, "node\n"); 1483 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2, 1484 depth + 1); 1485 fprintf(output, "\n"); 1486 } 1487 break; 1488 case XPATH_LOCATIONSET: 1489 fprintf(output, "Object is a Location Set:\n"); 1490 xmlXPathDebugDumpLocationSet(output, 1491 (xmlLocationSetPtr) cur->user, depth); 1492 break; 1493 #endif /* LIBXML_XPTR_LOCS_ENABLED */ 1494 case XPATH_USERS: 1495 fprintf(output, "Object is user defined\n"); 1496 break; 1497 } 1498 } 1499 1500 static void 1501 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp, 1502 xmlXPathStepOpPtr op, int depth) { 1503 int i; 1504 char shift[100]; 1505 1506 for (i = 0;((i < depth) && (i < 25));i++) 1507 shift[2 * i] = shift[2 * i + 1] = ' '; 1508 shift[2 * i] = shift[2 * i + 1] = 0; 1509 1510 fprintf(output, "%s", shift); 1511 if (op == NULL) { 1512 fprintf(output, "Step is NULL\n"); 1513 return; 1514 } 1515 switch (op->op) { 1516 case XPATH_OP_END: 1517 fprintf(output, "END"); break; 1518 case XPATH_OP_AND: 1519 fprintf(output, "AND"); break; 1520 case XPATH_OP_OR: 1521 fprintf(output, "OR"); break; 1522 case XPATH_OP_EQUAL: 1523 if (op->value) 1524 fprintf(output, "EQUAL ="); 1525 else 1526 fprintf(output, "EQUAL !="); 1527 break; 1528 case XPATH_OP_CMP: 1529 if (op->value) 1530 fprintf(output, "CMP <"); 1531 else 1532 fprintf(output, "CMP >"); 1533 if (!op->value2) 1534 fprintf(output, "="); 1535 break; 1536 case XPATH_OP_PLUS: 1537 if (op->value == 0) 1538 fprintf(output, "PLUS -"); 1539 else if (op->value == 1) 1540 fprintf(output, "PLUS +"); 1541 else if (op->value == 2) 1542 fprintf(output, "PLUS unary -"); 1543 else if (op->value == 3) 1544 fprintf(output, "PLUS unary - -"); 1545 break; 1546 case XPATH_OP_MULT: 1547 if (op->value == 0) 1548 fprintf(output, "MULT *"); 1549 else if (op->value == 1) 1550 fprintf(output, "MULT div"); 1551 else 1552 fprintf(output, "MULT mod"); 1553 break; 1554 case XPATH_OP_UNION: 1555 fprintf(output, "UNION"); break; 1556 case XPATH_OP_ROOT: 1557 fprintf(output, "ROOT"); break; 1558 case XPATH_OP_NODE: 1559 fprintf(output, "NODE"); break; 1560 case XPATH_OP_SORT: 1561 fprintf(output, "SORT"); break; 1562 case XPATH_OP_COLLECT: { 1563 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value; 1564 xmlXPathTestVal test = (xmlXPathTestVal)op->value2; 1565 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3; 1566 const xmlChar *prefix = op->value4; 1567 const xmlChar *name = op->value5; 1568 1569 fprintf(output, "COLLECT "); 1570 switch (axis) { 1571 case AXIS_ANCESTOR: 1572 fprintf(output, " 'ancestors' "); break; 1573 case AXIS_ANCESTOR_OR_SELF: 1574 fprintf(output, " 'ancestors-or-self' "); break; 1575 case AXIS_ATTRIBUTE: 1576 fprintf(output, " 'attributes' "); break; 1577 case AXIS_CHILD: 1578 fprintf(output, " 'child' "); break; 1579 case AXIS_DESCENDANT: 1580 fprintf(output, " 'descendant' "); break; 1581 case AXIS_DESCENDANT_OR_SELF: 1582 fprintf(output, " 'descendant-or-self' "); break; 1583 case AXIS_FOLLOWING: 1584 fprintf(output, " 'following' "); break; 1585 case AXIS_FOLLOWING_SIBLING: 1586 fprintf(output, " 'following-siblings' "); break; 1587 case AXIS_NAMESPACE: 1588 fprintf(output, " 'namespace' "); break; 1589 case AXIS_PARENT: 1590 fprintf(output, " 'parent' "); break; 1591 case AXIS_PRECEDING: 1592 fprintf(output, " 'preceding' "); break; 1593 case AXIS_PRECEDING_SIBLING: 1594 fprintf(output, " 'preceding-sibling' "); break; 1595 case AXIS_SELF: 1596 fprintf(output, " 'self' "); break; 1597 } 1598 switch (test) { 1599 case NODE_TEST_NONE: 1600 fprintf(output, "'none' "); break; 1601 case NODE_TEST_TYPE: 1602 fprintf(output, "'type' "); break; 1603 case NODE_TEST_PI: 1604 fprintf(output, "'PI' "); break; 1605 case NODE_TEST_ALL: 1606 fprintf(output, "'all' "); break; 1607 case NODE_TEST_NS: 1608 fprintf(output, "'namespace' "); break; 1609 case NODE_TEST_NAME: 1610 fprintf(output, "'name' "); break; 1611 } 1612 switch (type) { 1613 case NODE_TYPE_NODE: 1614 fprintf(output, "'node' "); break; 1615 case NODE_TYPE_COMMENT: 1616 fprintf(output, "'comment' "); break; 1617 case NODE_TYPE_TEXT: 1618 fprintf(output, "'text' "); break; 1619 case NODE_TYPE_PI: 1620 fprintf(output, "'PI' "); break; 1621 } 1622 if (prefix != NULL) 1623 fprintf(output, "%s:", prefix); 1624 if (name != NULL) 1625 fprintf(output, "%s", (const char *) name); 1626 break; 1627 1628 } 1629 case XPATH_OP_VALUE: { 1630 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4; 1631 1632 fprintf(output, "ELEM "); 1633 xmlXPathDebugDumpObject(output, object, 0); 1634 goto finish; 1635 } 1636 case XPATH_OP_VARIABLE: { 1637 const xmlChar *prefix = op->value5; 1638 const xmlChar *name = op->value4; 1639 1640 if (prefix != NULL) 1641 fprintf(output, "VARIABLE %s:%s", prefix, name); 1642 else 1643 fprintf(output, "VARIABLE %s", name); 1644 break; 1645 } 1646 case XPATH_OP_FUNCTION: { 1647 int nbargs = op->value; 1648 const xmlChar *prefix = op->value5; 1649 const xmlChar *name = op->value4; 1650 1651 if (prefix != NULL) 1652 fprintf(output, "FUNCTION %s:%s(%d args)", 1653 prefix, name, nbargs); 1654 else 1655 fprintf(output, "FUNCTION %s(%d args)", name, nbargs); 1656 break; 1657 } 1658 case XPATH_OP_ARG: fprintf(output, "ARG"); break; 1659 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break; 1660 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break; 1661 #ifdef LIBXML_XPTR_LOCS_ENABLED 1662 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break; 1663 #endif 1664 default: 1665 fprintf(output, "UNKNOWN %d\n", op->op); return; 1666 } 1667 fprintf(output, "\n"); 1668 finish: 1669 if (op->ch1 >= 0) 1670 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1); 1671 if (op->ch2 >= 0) 1672 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1); 1673 } 1674 1675 /** 1676 * xmlXPathDebugDumpCompExpr: 1677 * @output: the FILE * for the output 1678 * @comp: the precompiled XPath expression 1679 * @depth: the indentation level. 1680 * 1681 * Dumps the tree of the compiled XPath expression. 1682 */ 1683 void 1684 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp, 1685 int depth) { 1686 int i; 1687 char shift[100]; 1688 1689 if ((output == NULL) || (comp == NULL)) return; 1690 1691 for (i = 0;((i < depth) && (i < 25));i++) 1692 shift[2 * i] = shift[2 * i + 1] = ' '; 1693 shift[2 * i] = shift[2 * i + 1] = 0; 1694 1695 fprintf(output, "%s", shift); 1696 1697 #ifdef XPATH_STREAMING 1698 if (comp->stream) { 1699 fprintf(output, "Streaming Expression\n"); 1700 } else 1701 #endif 1702 { 1703 fprintf(output, "Compiled Expression : %d elements\n", 1704 comp->nbStep); 1705 i = comp->last; 1706 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1); 1707 } 1708 } 1709 1710 #ifdef XP_DEBUG_OBJ_USAGE 1711 1712 /* 1713 * XPath object usage related debugging variables. 1714 */ 1715 static int xmlXPathDebugObjCounterUndefined = 0; 1716 static int xmlXPathDebugObjCounterNodeset = 0; 1717 static int xmlXPathDebugObjCounterBool = 0; 1718 static int xmlXPathDebugObjCounterNumber = 0; 1719 static int xmlXPathDebugObjCounterString = 0; 1720 static int xmlXPathDebugObjCounterPoint = 0; 1721 static int xmlXPathDebugObjCounterRange = 0; 1722 static int xmlXPathDebugObjCounterLocset = 0; 1723 static int xmlXPathDebugObjCounterUsers = 0; 1724 static int xmlXPathDebugObjCounterXSLTTree = 0; 1725 static int xmlXPathDebugObjCounterAll = 0; 1726 1727 static int xmlXPathDebugObjTotalUndefined = 0; 1728 static int xmlXPathDebugObjTotalNodeset = 0; 1729 static int xmlXPathDebugObjTotalBool = 0; 1730 static int xmlXPathDebugObjTotalNumber = 0; 1731 static int xmlXPathDebugObjTotalString = 0; 1732 static int xmlXPathDebugObjTotalPoint = 0; 1733 static int xmlXPathDebugObjTotalRange = 0; 1734 static int xmlXPathDebugObjTotalLocset = 0; 1735 static int xmlXPathDebugObjTotalUsers = 0; 1736 static int xmlXPathDebugObjTotalXSLTTree = 0; 1737 static int xmlXPathDebugObjTotalAll = 0; 1738 1739 static int xmlXPathDebugObjMaxUndefined = 0; 1740 static int xmlXPathDebugObjMaxNodeset = 0; 1741 static int xmlXPathDebugObjMaxBool = 0; 1742 static int xmlXPathDebugObjMaxNumber = 0; 1743 static int xmlXPathDebugObjMaxString = 0; 1744 static int xmlXPathDebugObjMaxPoint = 0; 1745 static int xmlXPathDebugObjMaxRange = 0; 1746 static int xmlXPathDebugObjMaxLocset = 0; 1747 static int xmlXPathDebugObjMaxUsers = 0; 1748 static int xmlXPathDebugObjMaxXSLTTree = 0; 1749 static int xmlXPathDebugObjMaxAll = 0; 1750 1751 static void 1752 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt) 1753 { 1754 if (ctxt != NULL) { 1755 if (ctxt->cache != NULL) { 1756 xmlXPathContextCachePtr cache = 1757 (xmlXPathContextCachePtr) ctxt->cache; 1758 1759 cache->dbgCachedAll = 0; 1760 cache->dbgCachedNodeset = 0; 1761 cache->dbgCachedString = 0; 1762 cache->dbgCachedBool = 0; 1763 cache->dbgCachedNumber = 0; 1764 cache->dbgCachedPoint = 0; 1765 cache->dbgCachedRange = 0; 1766 cache->dbgCachedLocset = 0; 1767 cache->dbgCachedUsers = 0; 1768 cache->dbgCachedXSLTTree = 0; 1769 cache->dbgCachedUndefined = 0; 1770 1771 cache->dbgReusedAll = 0; 1772 cache->dbgReusedNodeset = 0; 1773 cache->dbgReusedString = 0; 1774 cache->dbgReusedBool = 0; 1775 cache->dbgReusedNumber = 0; 1776 cache->dbgReusedPoint = 0; 1777 cache->dbgReusedRange = 0; 1778 cache->dbgReusedLocset = 0; 1779 cache->dbgReusedUsers = 0; 1780 cache->dbgReusedXSLTTree = 0; 1781 cache->dbgReusedUndefined = 0; 1782 } 1783 } 1784 1785 xmlXPathDebugObjCounterUndefined = 0; 1786 xmlXPathDebugObjCounterNodeset = 0; 1787 xmlXPathDebugObjCounterBool = 0; 1788 xmlXPathDebugObjCounterNumber = 0; 1789 xmlXPathDebugObjCounterString = 0; 1790 xmlXPathDebugObjCounterPoint = 0; 1791 xmlXPathDebugObjCounterRange = 0; 1792 xmlXPathDebugObjCounterLocset = 0; 1793 xmlXPathDebugObjCounterUsers = 0; 1794 xmlXPathDebugObjCounterXSLTTree = 0; 1795 xmlXPathDebugObjCounterAll = 0; 1796 1797 xmlXPathDebugObjTotalUndefined = 0; 1798 xmlXPathDebugObjTotalNodeset = 0; 1799 xmlXPathDebugObjTotalBool = 0; 1800 xmlXPathDebugObjTotalNumber = 0; 1801 xmlXPathDebugObjTotalString = 0; 1802 xmlXPathDebugObjTotalPoint = 0; 1803 xmlXPathDebugObjTotalRange = 0; 1804 xmlXPathDebugObjTotalLocset = 0; 1805 xmlXPathDebugObjTotalUsers = 0; 1806 xmlXPathDebugObjTotalXSLTTree = 0; 1807 xmlXPathDebugObjTotalAll = 0; 1808 1809 xmlXPathDebugObjMaxUndefined = 0; 1810 xmlXPathDebugObjMaxNodeset = 0; 1811 xmlXPathDebugObjMaxBool = 0; 1812 xmlXPathDebugObjMaxNumber = 0; 1813 xmlXPathDebugObjMaxString = 0; 1814 xmlXPathDebugObjMaxPoint = 0; 1815 xmlXPathDebugObjMaxRange = 0; 1816 xmlXPathDebugObjMaxLocset = 0; 1817 xmlXPathDebugObjMaxUsers = 0; 1818 xmlXPathDebugObjMaxXSLTTree = 0; 1819 xmlXPathDebugObjMaxAll = 0; 1820 1821 } 1822 1823 static void 1824 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt, 1825 xmlXPathObjectType objType) 1826 { 1827 int isCached = 0; 1828 1829 if (ctxt != NULL) { 1830 if (ctxt->cache != NULL) { 1831 xmlXPathContextCachePtr cache = 1832 (xmlXPathContextCachePtr) ctxt->cache; 1833 1834 isCached = 1; 1835 1836 cache->dbgReusedAll++; 1837 switch (objType) { 1838 case XPATH_UNDEFINED: 1839 cache->dbgReusedUndefined++; 1840 break; 1841 case XPATH_NODESET: 1842 cache->dbgReusedNodeset++; 1843 break; 1844 case XPATH_BOOLEAN: 1845 cache->dbgReusedBool++; 1846 break; 1847 case XPATH_NUMBER: 1848 cache->dbgReusedNumber++; 1849 break; 1850 case XPATH_STRING: 1851 cache->dbgReusedString++; 1852 break; 1853 #ifdef LIBXML_XPTR_LOCS_ENABLED 1854 case XPATH_POINT: 1855 cache->dbgReusedPoint++; 1856 break; 1857 case XPATH_RANGE: 1858 cache->dbgReusedRange++; 1859 break; 1860 case XPATH_LOCATIONSET: 1861 cache->dbgReusedLocset++; 1862 break; 1863 #endif /* LIBXML_XPTR_LOCS_ENABLED */ 1864 case XPATH_USERS: 1865 cache->dbgReusedUsers++; 1866 break; 1867 case XPATH_XSLT_TREE: 1868 cache->dbgReusedXSLTTree++; 1869 break; 1870 default: 1871 break; 1872 } 1873 } 1874 } 1875 1876 switch (objType) { 1877 case XPATH_UNDEFINED: 1878 if (! isCached) 1879 xmlXPathDebugObjTotalUndefined++; 1880 xmlXPathDebugObjCounterUndefined++; 1881 if (xmlXPathDebugObjCounterUndefined > 1882 xmlXPathDebugObjMaxUndefined) 1883 xmlXPathDebugObjMaxUndefined = 1884 xmlXPathDebugObjCounterUndefined; 1885 break; 1886 case XPATH_NODESET: 1887 if (! isCached) 1888 xmlXPathDebugObjTotalNodeset++; 1889 xmlXPathDebugObjCounterNodeset++; 1890 if (xmlXPathDebugObjCounterNodeset > 1891 xmlXPathDebugObjMaxNodeset) 1892 xmlXPathDebugObjMaxNodeset = 1893 xmlXPathDebugObjCounterNodeset; 1894 break; 1895 case XPATH_BOOLEAN: 1896 if (! isCached) 1897 xmlXPathDebugObjTotalBool++; 1898 xmlXPathDebugObjCounterBool++; 1899 if (xmlXPathDebugObjCounterBool > 1900 xmlXPathDebugObjMaxBool) 1901 xmlXPathDebugObjMaxBool = 1902 xmlXPathDebugObjCounterBool; 1903 break; 1904 case XPATH_NUMBER: 1905 if (! isCached) 1906 xmlXPathDebugObjTotalNumber++; 1907 xmlXPathDebugObjCounterNumber++; 1908 if (xmlXPathDebugObjCounterNumber > 1909 xmlXPathDebugObjMaxNumber) 1910 xmlXPathDebugObjMaxNumber = 1911 xmlXPathDebugObjCounterNumber; 1912 break; 1913 case XPATH_STRING: 1914 if (! isCached) 1915 xmlXPathDebugObjTotalString++; 1916 xmlXPathDebugObjCounterString++; 1917 if (xmlXPathDebugObjCounterString > 1918 xmlXPathDebugObjMaxString) 1919 xmlXPathDebugObjMaxString = 1920 xmlXPathDebugObjCounterString; 1921 break; 1922 #ifdef LIBXML_XPTR_LOCS_ENABLED 1923 case XPATH_POINT: 1924 if (! isCached) 1925 xmlXPathDebugObjTotalPoint++; 1926 xmlXPathDebugObjCounterPoint++; 1927 if (xmlXPathDebugObjCounterPoint > 1928 xmlXPathDebugObjMaxPoint) 1929 xmlXPathDebugObjMaxPoint = 1930 xmlXPathDebugObjCounterPoint; 1931 break; 1932 case XPATH_RANGE: 1933 if (! isCached) 1934 xmlXPathDebugObjTotalRange++; 1935 xmlXPathDebugObjCounterRange++; 1936 if (xmlXPathDebugObjCounterRange > 1937 xmlXPathDebugObjMaxRange) 1938 xmlXPathDebugObjMaxRange = 1939 xmlXPathDebugObjCounterRange; 1940 break; 1941 case XPATH_LOCATIONSET: 1942 if (! isCached) 1943 xmlXPathDebugObjTotalLocset++; 1944 xmlXPathDebugObjCounterLocset++; 1945 if (xmlXPathDebugObjCounterLocset > 1946 xmlXPathDebugObjMaxLocset) 1947 xmlXPathDebugObjMaxLocset = 1948 xmlXPathDebugObjCounterLocset; 1949 break; 1950 #endif /* LIBXML_XPTR_LOCS_ENABLED */ 1951 case XPATH_USERS: 1952 if (! isCached) 1953 xmlXPathDebugObjTotalUsers++; 1954 xmlXPathDebugObjCounterUsers++; 1955 if (xmlXPathDebugObjCounterUsers > 1956 xmlXPathDebugObjMaxUsers) 1957 xmlXPathDebugObjMaxUsers = 1958 xmlXPathDebugObjCounterUsers; 1959 break; 1960 case XPATH_XSLT_TREE: 1961 if (! isCached) 1962 xmlXPathDebugObjTotalXSLTTree++; 1963 xmlXPathDebugObjCounterXSLTTree++; 1964 if (xmlXPathDebugObjCounterXSLTTree > 1965 xmlXPathDebugObjMaxXSLTTree) 1966 xmlXPathDebugObjMaxXSLTTree = 1967 xmlXPathDebugObjCounterXSLTTree; 1968 break; 1969 default: 1970 break; 1971 } 1972 if (! isCached) 1973 xmlXPathDebugObjTotalAll++; 1974 xmlXPathDebugObjCounterAll++; 1975 if (xmlXPathDebugObjCounterAll > 1976 xmlXPathDebugObjMaxAll) 1977 xmlXPathDebugObjMaxAll = 1978 xmlXPathDebugObjCounterAll; 1979 } 1980 1981 static void 1982 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt, 1983 xmlXPathObjectType objType) 1984 { 1985 int isCached = 0; 1986 1987 if (ctxt != NULL) { 1988 if (ctxt->cache != NULL) { 1989 xmlXPathContextCachePtr cache = 1990 (xmlXPathContextCachePtr) ctxt->cache; 1991 1992 isCached = 1; 1993 1994 cache->dbgCachedAll++; 1995 switch (objType) { 1996 case XPATH_UNDEFINED: 1997 cache->dbgCachedUndefined++; 1998 break; 1999 case XPATH_NODESET: 2000 cache->dbgCachedNodeset++; 2001 break; 2002 case XPATH_BOOLEAN: 2003 cache->dbgCachedBool++; 2004 break; 2005 case XPATH_NUMBER: 2006 cache->dbgCachedNumber++; 2007 break; 2008 case XPATH_STRING: 2009 cache->dbgCachedString++; 2010 break; 2011 #ifdef LIBXML_XPTR_LOCS_ENABLED 2012 case XPATH_POINT: 2013 cache->dbgCachedPoint++; 2014 break; 2015 case XPATH_RANGE: 2016 cache->dbgCachedRange++; 2017 break; 2018 case XPATH_LOCATIONSET: 2019 cache->dbgCachedLocset++; 2020 break; 2021 #endif /* LIBXML_XPTR_LOCS_ENABLED */ 2022 case XPATH_USERS: 2023 cache->dbgCachedUsers++; 2024 break; 2025 case XPATH_XSLT_TREE: 2026 cache->dbgCachedXSLTTree++; 2027 break; 2028 default: 2029 break; 2030 } 2031 2032 } 2033 } 2034 switch (objType) { 2035 case XPATH_UNDEFINED: 2036 xmlXPathDebugObjCounterUndefined--; 2037 break; 2038 case XPATH_NODESET: 2039 xmlXPathDebugObjCounterNodeset--; 2040 break; 2041 case XPATH_BOOLEAN: 2042 xmlXPathDebugObjCounterBool--; 2043 break; 2044 case XPATH_NUMBER: 2045 xmlXPathDebugObjCounterNumber--; 2046 break; 2047 case XPATH_STRING: 2048 xmlXPathDebugObjCounterString--; 2049 break; 2050 #ifdef LIBXML_XPTR_LOCS_ENABLED 2051 case XPATH_POINT: 2052 xmlXPathDebugObjCounterPoint--; 2053 break; 2054 case XPATH_RANGE: 2055 xmlXPathDebugObjCounterRange--; 2056 break; 2057 case XPATH_LOCATIONSET: 2058 xmlXPathDebugObjCounterLocset--; 2059 break; 2060 #endif /* LIBXML_XPTR_LOCS_ENABLED */ 2061 case XPATH_USERS: 2062 xmlXPathDebugObjCounterUsers--; 2063 break; 2064 case XPATH_XSLT_TREE: 2065 xmlXPathDebugObjCounterXSLTTree--; 2066 break; 2067 default: 2068 break; 2069 } 2070 xmlXPathDebugObjCounterAll--; 2071 } 2072 2073 static void 2074 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt) 2075 { 2076 int reqAll, reqNodeset, reqString, reqBool, reqNumber, 2077 reqXSLTTree, reqUndefined; 2078 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0, 2079 caNumber = 0, caXSLTTree = 0, caUndefined = 0; 2080 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0, 2081 reNumber = 0, reXSLTTree = 0, reUndefined = 0; 2082 int leftObjs = xmlXPathDebugObjCounterAll; 2083 2084 reqAll = xmlXPathDebugObjTotalAll; 2085 reqNodeset = xmlXPathDebugObjTotalNodeset; 2086 reqString = xmlXPathDebugObjTotalString; 2087 reqBool = xmlXPathDebugObjTotalBool; 2088 reqNumber = xmlXPathDebugObjTotalNumber; 2089 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree; 2090 reqUndefined = xmlXPathDebugObjTotalUndefined; 2091 2092 printf("# XPath object usage:\n"); 2093 2094 if (ctxt != NULL) { 2095 if (ctxt->cache != NULL) { 2096 xmlXPathContextCachePtr cache = 2097 (xmlXPathContextCachePtr) ctxt->cache; 2098 2099 reAll = cache->dbgReusedAll; 2100 reqAll += reAll; 2101 reNodeset = cache->dbgReusedNodeset; 2102 reqNodeset += reNodeset; 2103 reString = cache->dbgReusedString; 2104 reqString += reString; 2105 reBool = cache->dbgReusedBool; 2106 reqBool += reBool; 2107 reNumber = cache->dbgReusedNumber; 2108 reqNumber += reNumber; 2109 reXSLTTree = cache->dbgReusedXSLTTree; 2110 reqXSLTTree += reXSLTTree; 2111 reUndefined = cache->dbgReusedUndefined; 2112 reqUndefined += reUndefined; 2113 2114 caAll = cache->dbgCachedAll; 2115 caBool = cache->dbgCachedBool; 2116 caNodeset = cache->dbgCachedNodeset; 2117 caString = cache->dbgCachedString; 2118 caNumber = cache->dbgCachedNumber; 2119 caXSLTTree = cache->dbgCachedXSLTTree; 2120 caUndefined = cache->dbgCachedUndefined; 2121 2122 if (cache->nodesetObjs) 2123 leftObjs -= cache->nodesetObjs->number; 2124 if (cache->stringObjs) 2125 leftObjs -= cache->stringObjs->number; 2126 if (cache->booleanObjs) 2127 leftObjs -= cache->booleanObjs->number; 2128 if (cache->numberObjs) 2129 leftObjs -= cache->numberObjs->number; 2130 if (cache->miscObjs) 2131 leftObjs -= cache->miscObjs->number; 2132 } 2133 } 2134 2135 printf("# all\n"); 2136 printf("# total : %d\n", reqAll); 2137 printf("# left : %d\n", leftObjs); 2138 printf("# created: %d\n", xmlXPathDebugObjTotalAll); 2139 printf("# reused : %d\n", reAll); 2140 printf("# max : %d\n", xmlXPathDebugObjMaxAll); 2141 2142 printf("# node-sets\n"); 2143 printf("# total : %d\n", reqNodeset); 2144 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset); 2145 printf("# reused : %d\n", reNodeset); 2146 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset); 2147 2148 printf("# strings\n"); 2149 printf("# total : %d\n", reqString); 2150 printf("# created: %d\n", xmlXPathDebugObjTotalString); 2151 printf("# reused : %d\n", reString); 2152 printf("# max : %d\n", xmlXPathDebugObjMaxString); 2153 2154 printf("# booleans\n"); 2155 printf("# total : %d\n", reqBool); 2156 printf("# created: %d\n", xmlXPathDebugObjTotalBool); 2157 printf("# reused : %d\n", reBool); 2158 printf("# max : %d\n", xmlXPathDebugObjMaxBool); 2159 2160 printf("# numbers\n"); 2161 printf("# total : %d\n", reqNumber); 2162 printf("# created: %d\n", xmlXPathDebugObjTotalNumber); 2163 printf("# reused : %d\n", reNumber); 2164 printf("# max : %d\n", xmlXPathDebugObjMaxNumber); 2165 2166 printf("# XSLT result tree fragments\n"); 2167 printf("# total : %d\n", reqXSLTTree); 2168 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree); 2169 printf("# reused : %d\n", reXSLTTree); 2170 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree); 2171 2172 printf("# undefined\n"); 2173 printf("# total : %d\n", reqUndefined); 2174 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined); 2175 printf("# reused : %d\n", reUndefined); 2176 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined); 2177 2178 } 2179 2180 #endif /* XP_DEBUG_OBJ_USAGE */ 2181 2182 #endif /* LIBXML_DEBUG_ENABLED */ 2183 2184 /************************************************************************ 2185 * * 2186 * XPath object caching * 2187 * * 2188 ************************************************************************/ 2189 2190 /** 2191 * xmlXPathNewCache: 2192 * 2193 * Create a new object cache 2194 * 2195 * Returns the xmlXPathCache just allocated. 2196 */ 2197 static xmlXPathContextCachePtr 2198 xmlXPathNewCache(void) 2199 { 2200 xmlXPathContextCachePtr ret; 2201 2202 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache)); 2203 if (ret == NULL) { 2204 xmlXPathErrMemory(NULL, "creating object cache\n"); 2205 return(NULL); 2206 } 2207 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache)); 2208 ret->maxNodeset = 100; 2209 ret->maxString = 100; 2210 ret->maxBoolean = 100; 2211 ret->maxNumber = 100; 2212 ret->maxMisc = 100; 2213 return(ret); 2214 } 2215 2216 static void 2217 xmlXPathCacheFreeObjectList(xmlPointerListPtr list) 2218 { 2219 int i; 2220 xmlXPathObjectPtr obj; 2221 2222 if (list == NULL) 2223 return; 2224 2225 for (i = 0; i < list->number; i++) { 2226 obj = list->items[i]; 2227 /* 2228 * Note that it is already assured that we don't need to 2229 * look out for namespace nodes in the node-set. 2230 */ 2231 if (obj->nodesetval != NULL) { 2232 if (obj->nodesetval->nodeTab != NULL) 2233 xmlFree(obj->nodesetval->nodeTab); 2234 xmlFree(obj->nodesetval); 2235 } 2236 xmlFree(obj); 2237 #ifdef XP_DEBUG_OBJ_USAGE 2238 xmlXPathDebugObjCounterAll--; 2239 #endif 2240 } 2241 xmlPointerListFree(list); 2242 } 2243 2244 static void 2245 xmlXPathFreeCache(xmlXPathContextCachePtr cache) 2246 { 2247 if (cache == NULL) 2248 return; 2249 if (cache->nodesetObjs) 2250 xmlXPathCacheFreeObjectList(cache->nodesetObjs); 2251 if (cache->stringObjs) 2252 xmlXPathCacheFreeObjectList(cache->stringObjs); 2253 if (cache->booleanObjs) 2254 xmlXPathCacheFreeObjectList(cache->booleanObjs); 2255 if (cache->numberObjs) 2256 xmlXPathCacheFreeObjectList(cache->numberObjs); 2257 if (cache->miscObjs) 2258 xmlXPathCacheFreeObjectList(cache->miscObjs); 2259 xmlFree(cache); 2260 } 2261 2262 /** 2263 * xmlXPathContextSetCache: 2264 * 2265 * @ctxt: the XPath context 2266 * @active: enables/disables (creates/frees) the cache 2267 * @value: a value with semantics dependent on @options 2268 * @options: options (currently only the value 0 is used) 2269 * 2270 * Creates/frees an object cache on the XPath context. 2271 * If activates XPath objects (xmlXPathObject) will be cached internally 2272 * to be reused. 2273 * @options: 2274 * 0: This will set the XPath object caching: 2275 * @value: 2276 * This will set the maximum number of XPath objects 2277 * to be cached per slot 2278 * There are 5 slots for: node-set, string, number, boolean, and 2279 * misc objects. Use <0 for the default number (100). 2280 * Other values for @options have currently no effect. 2281 * 2282 * Returns 0 if the setting succeeded, and -1 on API or internal errors. 2283 */ 2284 int 2285 xmlXPathContextSetCache(xmlXPathContextPtr ctxt, 2286 int active, 2287 int value, 2288 int options) 2289 { 2290 if (ctxt == NULL) 2291 return(-1); 2292 if (active) { 2293 xmlXPathContextCachePtr cache; 2294 2295 if (ctxt->cache == NULL) { 2296 ctxt->cache = xmlXPathNewCache(); 2297 if (ctxt->cache == NULL) 2298 return(-1); 2299 } 2300 cache = (xmlXPathContextCachePtr) ctxt->cache; 2301 if (options == 0) { 2302 if (value < 0) 2303 value = 100; 2304 cache->maxNodeset = value; 2305 cache->maxString = value; 2306 cache->maxNumber = value; 2307 cache->maxBoolean = value; 2308 cache->maxMisc = value; 2309 } 2310 } else if (ctxt->cache != NULL) { 2311 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache); 2312 ctxt->cache = NULL; 2313 } 2314 return(0); 2315 } 2316 2317 /** 2318 * xmlXPathCacheWrapNodeSet: 2319 * @ctxt: the XPath context 2320 * @val: the NodePtr value 2321 * 2322 * This is the cached version of xmlXPathWrapNodeSet(). 2323 * Wrap the Nodeset @val in a new xmlXPathObjectPtr 2324 * 2325 * Returns the created or reused object. 2326 */ 2327 static xmlXPathObjectPtr 2328 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val) 2329 { 2330 if ((ctxt != NULL) && (ctxt->cache != NULL)) { 2331 xmlXPathContextCachePtr cache = 2332 (xmlXPathContextCachePtr) ctxt->cache; 2333 2334 if ((cache->miscObjs != NULL) && 2335 (cache->miscObjs->number != 0)) 2336 { 2337 xmlXPathObjectPtr ret; 2338 2339 ret = (xmlXPathObjectPtr) 2340 cache->miscObjs->items[--cache->miscObjs->number]; 2341 ret->type = XPATH_NODESET; 2342 ret->nodesetval = val; 2343 #ifdef XP_DEBUG_OBJ_USAGE 2344 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 2345 #endif 2346 return(ret); 2347 } 2348 } 2349 2350 return(xmlXPathWrapNodeSet(val)); 2351 2352 } 2353 2354 /** 2355 * xmlXPathCacheWrapString: 2356 * @ctxt: the XPath context 2357 * @val: the xmlChar * value 2358 * 2359 * This is the cached version of xmlXPathWrapString(). 2360 * Wraps the @val string into an XPath object. 2361 * 2362 * Returns the created or reused object. 2363 */ 2364 static xmlXPathObjectPtr 2365 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val) 2366 { 2367 if ((ctxt != NULL) && (ctxt->cache != NULL)) { 2368 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2369 2370 if ((cache->stringObjs != NULL) && 2371 (cache->stringObjs->number != 0)) 2372 { 2373 2374 xmlXPathObjectPtr ret; 2375 2376 ret = (xmlXPathObjectPtr) 2377 cache->stringObjs->items[--cache->stringObjs->number]; 2378 ret->type = XPATH_STRING; 2379 ret->stringval = val; 2380 #ifdef XP_DEBUG_OBJ_USAGE 2381 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2382 #endif 2383 return(ret); 2384 } else if ((cache->miscObjs != NULL) && 2385 (cache->miscObjs->number != 0)) 2386 { 2387 xmlXPathObjectPtr ret; 2388 /* 2389 * Fallback to misc-cache. 2390 */ 2391 ret = (xmlXPathObjectPtr) 2392 cache->miscObjs->items[--cache->miscObjs->number]; 2393 2394 ret->type = XPATH_STRING; 2395 ret->stringval = val; 2396 #ifdef XP_DEBUG_OBJ_USAGE 2397 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2398 #endif 2399 return(ret); 2400 } 2401 } 2402 return(xmlXPathWrapString(val)); 2403 } 2404 2405 /** 2406 * xmlXPathCacheNewNodeSet: 2407 * @ctxt: the XPath context 2408 * @val: the NodePtr value 2409 * 2410 * This is the cached version of xmlXPathNewNodeSet(). 2411 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize 2412 * it with the single Node @val 2413 * 2414 * Returns the created or reused object. 2415 */ 2416 static xmlXPathObjectPtr 2417 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val) 2418 { 2419 if ((ctxt != NULL) && (ctxt->cache)) { 2420 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2421 2422 if ((cache->nodesetObjs != NULL) && 2423 (cache->nodesetObjs->number != 0)) 2424 { 2425 xmlXPathObjectPtr ret; 2426 /* 2427 * Use the nodeset-cache. 2428 */ 2429 ret = (xmlXPathObjectPtr) 2430 cache->nodesetObjs->items[--cache->nodesetObjs->number]; 2431 ret->type = XPATH_NODESET; 2432 ret->boolval = 0; 2433 if (val) { 2434 if ((ret->nodesetval->nodeMax == 0) || 2435 (val->type == XML_NAMESPACE_DECL)) 2436 { 2437 /* TODO: Check memory error. */ 2438 xmlXPathNodeSetAddUnique(ret->nodesetval, val); 2439 } else { 2440 ret->nodesetval->nodeTab[0] = val; 2441 ret->nodesetval->nodeNr = 1; 2442 } 2443 } 2444 #ifdef XP_DEBUG_OBJ_USAGE 2445 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 2446 #endif 2447 return(ret); 2448 } else if ((cache->miscObjs != NULL) && 2449 (cache->miscObjs->number != 0)) 2450 { 2451 xmlXPathObjectPtr ret; 2452 /* 2453 * Fallback to misc-cache. 2454 */ 2455 2456 ret = (xmlXPathObjectPtr) 2457 cache->miscObjs->items[--cache->miscObjs->number]; 2458 2459 ret->type = XPATH_NODESET; 2460 ret->boolval = 0; 2461 ret->nodesetval = xmlXPathNodeSetCreate(val); 2462 if (ret->nodesetval == NULL) { 2463 ctxt->lastError.domain = XML_FROM_XPATH; 2464 ctxt->lastError.code = XML_ERR_NO_MEMORY; 2465 return(NULL); 2466 } 2467 #ifdef XP_DEBUG_OBJ_USAGE 2468 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 2469 #endif 2470 return(ret); 2471 } 2472 } 2473 return(xmlXPathNewNodeSet(val)); 2474 } 2475 2476 /** 2477 * xmlXPathCacheNewCString: 2478 * @ctxt: the XPath context 2479 * @val: the char * value 2480 * 2481 * This is the cached version of xmlXPathNewCString(). 2482 * Acquire an xmlXPathObjectPtr of type string and of value @val 2483 * 2484 * Returns the created or reused object. 2485 */ 2486 static xmlXPathObjectPtr 2487 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val) 2488 { 2489 if ((ctxt != NULL) && (ctxt->cache)) { 2490 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2491 2492 if ((cache->stringObjs != NULL) && 2493 (cache->stringObjs->number != 0)) 2494 { 2495 xmlXPathObjectPtr ret; 2496 2497 ret = (xmlXPathObjectPtr) 2498 cache->stringObjs->items[--cache->stringObjs->number]; 2499 2500 ret->type = XPATH_STRING; 2501 ret->stringval = xmlStrdup(BAD_CAST val); 2502 #ifdef XP_DEBUG_OBJ_USAGE 2503 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2504 #endif 2505 return(ret); 2506 } else if ((cache->miscObjs != NULL) && 2507 (cache->miscObjs->number != 0)) 2508 { 2509 xmlXPathObjectPtr ret; 2510 2511 ret = (xmlXPathObjectPtr) 2512 cache->miscObjs->items[--cache->miscObjs->number]; 2513 2514 ret->type = XPATH_STRING; 2515 ret->stringval = xmlStrdup(BAD_CAST val); 2516 #ifdef XP_DEBUG_OBJ_USAGE 2517 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2518 #endif 2519 return(ret); 2520 } 2521 } 2522 return(xmlXPathNewCString(val)); 2523 } 2524 2525 /** 2526 * xmlXPathCacheNewString: 2527 * @ctxt: the XPath context 2528 * @val: the xmlChar * value 2529 * 2530 * This is the cached version of xmlXPathNewString(). 2531 * Acquire an xmlXPathObjectPtr of type string and of value @val 2532 * 2533 * Returns the created or reused object. 2534 */ 2535 static xmlXPathObjectPtr 2536 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val) 2537 { 2538 if ((ctxt != NULL) && (ctxt->cache)) { 2539 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2540 2541 if ((cache->stringObjs != NULL) && 2542 (cache->stringObjs->number != 0)) 2543 { 2544 xmlXPathObjectPtr ret; 2545 2546 ret = (xmlXPathObjectPtr) 2547 cache->stringObjs->items[--cache->stringObjs->number]; 2548 ret->type = XPATH_STRING; 2549 if (val != NULL) 2550 ret->stringval = xmlStrdup(val); 2551 else 2552 ret->stringval = xmlStrdup((const xmlChar *)""); 2553 #ifdef XP_DEBUG_OBJ_USAGE 2554 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2555 #endif 2556 return(ret); 2557 } else if ((cache->miscObjs != NULL) && 2558 (cache->miscObjs->number != 0)) 2559 { 2560 xmlXPathObjectPtr ret; 2561 2562 ret = (xmlXPathObjectPtr) 2563 cache->miscObjs->items[--cache->miscObjs->number]; 2564 2565 ret->type = XPATH_STRING; 2566 if (val != NULL) 2567 ret->stringval = xmlStrdup(val); 2568 else 2569 ret->stringval = xmlStrdup((const xmlChar *)""); 2570 #ifdef XP_DEBUG_OBJ_USAGE 2571 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2572 #endif 2573 return(ret); 2574 } 2575 } 2576 return(xmlXPathNewString(val)); 2577 } 2578 2579 /** 2580 * xmlXPathCacheNewBoolean: 2581 * @ctxt: the XPath context 2582 * @val: the boolean value 2583 * 2584 * This is the cached version of xmlXPathNewBoolean(). 2585 * Acquires an xmlXPathObjectPtr of type boolean and of value @val 2586 * 2587 * Returns the created or reused object. 2588 */ 2589 static xmlXPathObjectPtr 2590 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val) 2591 { 2592 if ((ctxt != NULL) && (ctxt->cache)) { 2593 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2594 2595 if ((cache->booleanObjs != NULL) && 2596 (cache->booleanObjs->number != 0)) 2597 { 2598 xmlXPathObjectPtr ret; 2599 2600 ret = (xmlXPathObjectPtr) 2601 cache->booleanObjs->items[--cache->booleanObjs->number]; 2602 ret->type = XPATH_BOOLEAN; 2603 ret->boolval = (val != 0); 2604 #ifdef XP_DEBUG_OBJ_USAGE 2605 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN); 2606 #endif 2607 return(ret); 2608 } else if ((cache->miscObjs != NULL) && 2609 (cache->miscObjs->number != 0)) 2610 { 2611 xmlXPathObjectPtr ret; 2612 2613 ret = (xmlXPathObjectPtr) 2614 cache->miscObjs->items[--cache->miscObjs->number]; 2615 2616 ret->type = XPATH_BOOLEAN; 2617 ret->boolval = (val != 0); 2618 #ifdef XP_DEBUG_OBJ_USAGE 2619 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN); 2620 #endif 2621 return(ret); 2622 } 2623 } 2624 return(xmlXPathNewBoolean(val)); 2625 } 2626 2627 /** 2628 * xmlXPathCacheNewFloat: 2629 * @ctxt: the XPath context 2630 * @val: the double value 2631 * 2632 * This is the cached version of xmlXPathNewFloat(). 2633 * Acquires an xmlXPathObjectPtr of type double and of value @val 2634 * 2635 * Returns the created or reused object. 2636 */ 2637 static xmlXPathObjectPtr 2638 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val) 2639 { 2640 if ((ctxt != NULL) && (ctxt->cache)) { 2641 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2642 2643 if ((cache->numberObjs != NULL) && 2644 (cache->numberObjs->number != 0)) 2645 { 2646 xmlXPathObjectPtr ret; 2647 2648 ret = (xmlXPathObjectPtr) 2649 cache->numberObjs->items[--cache->numberObjs->number]; 2650 ret->type = XPATH_NUMBER; 2651 ret->floatval = val; 2652 #ifdef XP_DEBUG_OBJ_USAGE 2653 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER); 2654 #endif 2655 return(ret); 2656 } else if ((cache->miscObjs != NULL) && 2657 (cache->miscObjs->number != 0)) 2658 { 2659 xmlXPathObjectPtr ret; 2660 2661 ret = (xmlXPathObjectPtr) 2662 cache->miscObjs->items[--cache->miscObjs->number]; 2663 2664 ret->type = XPATH_NUMBER; 2665 ret->floatval = val; 2666 #ifdef XP_DEBUG_OBJ_USAGE 2667 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER); 2668 #endif 2669 return(ret); 2670 } 2671 } 2672 return(xmlXPathNewFloat(val)); 2673 } 2674 2675 /** 2676 * xmlXPathCacheConvertString: 2677 * @ctxt: the XPath context 2678 * @val: an XPath object 2679 * 2680 * This is the cached version of xmlXPathConvertString(). 2681 * Converts an existing object to its string() equivalent 2682 * 2683 * Returns a created or reused object, the old one is freed (cached) 2684 * (or the operation is done directly on @val) 2685 */ 2686 2687 static xmlXPathObjectPtr 2688 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 2689 xmlChar *res = NULL; 2690 2691 if (val == NULL) 2692 return(xmlXPathCacheNewCString(ctxt, "")); 2693 2694 switch (val->type) { 2695 case XPATH_UNDEFINED: 2696 #ifdef DEBUG_EXPR 2697 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n"); 2698 #endif 2699 break; 2700 case XPATH_NODESET: 2701 case XPATH_XSLT_TREE: 2702 res = xmlXPathCastNodeSetToString(val->nodesetval); 2703 break; 2704 case XPATH_STRING: 2705 return(val); 2706 case XPATH_BOOLEAN: 2707 res = xmlXPathCastBooleanToString(val->boolval); 2708 break; 2709 case XPATH_NUMBER: 2710 res = xmlXPathCastNumberToString(val->floatval); 2711 break; 2712 case XPATH_USERS: 2713 #ifdef LIBXML_XPTR_LOCS_ENABLED 2714 case XPATH_POINT: 2715 case XPATH_RANGE: 2716 case XPATH_LOCATIONSET: 2717 #endif /* LIBXML_XPTR_LOCS_ENABLED */ 2718 TODO; 2719 break; 2720 } 2721 xmlXPathReleaseObject(ctxt, val); 2722 if (res == NULL) 2723 return(xmlXPathCacheNewCString(ctxt, "")); 2724 return(xmlXPathCacheWrapString(ctxt, res)); 2725 } 2726 2727 /** 2728 * xmlXPathCacheObjectCopy: 2729 * @ctxt: the XPath context 2730 * @val: the original object 2731 * 2732 * This is the cached version of xmlXPathObjectCopy(). 2733 * Acquire a copy of a given object 2734 * 2735 * Returns a created or reused created object. 2736 */ 2737 static xmlXPathObjectPtr 2738 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) 2739 { 2740 if (val == NULL) 2741 return(NULL); 2742 2743 if (XP_HAS_CACHE(ctxt)) { 2744 switch (val->type) { 2745 case XPATH_NODESET: 2746 return(xmlXPathCacheWrapNodeSet(ctxt, 2747 xmlXPathNodeSetMerge(NULL, val->nodesetval))); 2748 case XPATH_STRING: 2749 return(xmlXPathCacheNewString(ctxt, val->stringval)); 2750 case XPATH_BOOLEAN: 2751 return(xmlXPathCacheNewBoolean(ctxt, val->boolval)); 2752 case XPATH_NUMBER: 2753 return(xmlXPathCacheNewFloat(ctxt, val->floatval)); 2754 default: 2755 break; 2756 } 2757 } 2758 return(xmlXPathObjectCopy(val)); 2759 } 2760 2761 /** 2762 * xmlXPathCacheConvertBoolean: 2763 * @ctxt: the XPath context 2764 * @val: an XPath object 2765 * 2766 * This is the cached version of xmlXPathConvertBoolean(). 2767 * Converts an existing object to its boolean() equivalent 2768 * 2769 * Returns a created or reused object, the old one is freed (or the operation 2770 * is done directly on @val) 2771 */ 2772 static xmlXPathObjectPtr 2773 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 2774 xmlXPathObjectPtr ret; 2775 2776 if (val == NULL) 2777 return(xmlXPathCacheNewBoolean(ctxt, 0)); 2778 if (val->type == XPATH_BOOLEAN) 2779 return(val); 2780 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val)); 2781 xmlXPathReleaseObject(ctxt, val); 2782 return(ret); 2783 } 2784 2785 /** 2786 * xmlXPathCacheConvertNumber: 2787 * @ctxt: the XPath context 2788 * @val: an XPath object 2789 * 2790 * This is the cached version of xmlXPathConvertNumber(). 2791 * Converts an existing object to its number() equivalent 2792 * 2793 * Returns a created or reused object, the old one is freed (or the operation 2794 * is done directly on @val) 2795 */ 2796 static xmlXPathObjectPtr 2797 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 2798 xmlXPathObjectPtr ret; 2799 2800 if (val == NULL) 2801 return(xmlXPathCacheNewFloat(ctxt, 0.0)); 2802 if (val->type == XPATH_NUMBER) 2803 return(val); 2804 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val)); 2805 xmlXPathReleaseObject(ctxt, val); 2806 return(ret); 2807 } 2808 2809 /************************************************************************ 2810 * * 2811 * Parser stacks related functions and macros * 2812 * * 2813 ************************************************************************/ 2814 2815 /** 2816 * xmlXPathSetFrame: 2817 * @ctxt: an XPath parser context 2818 * 2819 * Set the callee evaluation frame 2820 * 2821 * Returns the previous frame value to be restored once done 2822 */ 2823 static int 2824 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) { 2825 int ret; 2826 2827 if (ctxt == NULL) 2828 return(0); 2829 ret = ctxt->valueFrame; 2830 ctxt->valueFrame = ctxt->valueNr; 2831 return(ret); 2832 } 2833 2834 /** 2835 * xmlXPathPopFrame: 2836 * @ctxt: an XPath parser context 2837 * @frame: the previous frame value 2838 * 2839 * Remove the callee evaluation frame 2840 */ 2841 static void 2842 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) { 2843 if (ctxt == NULL) 2844 return; 2845 if (ctxt->valueNr < ctxt->valueFrame) { 2846 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR); 2847 } 2848 ctxt->valueFrame = frame; 2849 } 2850 2851 /** 2852 * valuePop: 2853 * @ctxt: an XPath evaluation context 2854 * 2855 * Pops the top XPath object from the value stack 2856 * 2857 * Returns the XPath object just removed 2858 */ 2859 xmlXPathObjectPtr 2860 valuePop(xmlXPathParserContextPtr ctxt) 2861 { 2862 xmlXPathObjectPtr ret; 2863 2864 if ((ctxt == NULL) || (ctxt->valueNr <= 0)) 2865 return (NULL); 2866 2867 if (ctxt->valueNr <= ctxt->valueFrame) { 2868 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR); 2869 return (NULL); 2870 } 2871 2872 ctxt->valueNr--; 2873 if (ctxt->valueNr > 0) 2874 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1]; 2875 else 2876 ctxt->value = NULL; 2877 ret = ctxt->valueTab[ctxt->valueNr]; 2878 ctxt->valueTab[ctxt->valueNr] = NULL; 2879 return (ret); 2880 } 2881 /** 2882 * valuePush: 2883 * @ctxt: an XPath evaluation context 2884 * @value: the XPath object 2885 * 2886 * Pushes a new XPath object on top of the value stack. If value is NULL, 2887 * a memory error is recorded in the parser context. 2888 * 2889 * Returns the number of items on the value stack, or -1 in case of error. 2890 */ 2891 int 2892 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value) 2893 { 2894 if (ctxt == NULL) return(-1); 2895 if (value == NULL) { 2896 /* 2897 * A NULL value typically indicates that a memory allocation failed, 2898 * so we set ctxt->error here to propagate the error. 2899 */ 2900 ctxt->error = XPATH_MEMORY_ERROR; 2901 return(-1); 2902 } 2903 if (ctxt->valueNr >= ctxt->valueMax) { 2904 xmlXPathObjectPtr *tmp; 2905 2906 if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) { 2907 xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n"); 2908 return (-1); 2909 } 2910 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab, 2911 2 * ctxt->valueMax * 2912 sizeof(ctxt->valueTab[0])); 2913 if (tmp == NULL) { 2914 xmlXPathPErrMemory(ctxt, "pushing value\n"); 2915 return (-1); 2916 } 2917 ctxt->valueMax *= 2; 2918 ctxt->valueTab = tmp; 2919 } 2920 ctxt->valueTab[ctxt->valueNr] = value; 2921 ctxt->value = value; 2922 return (ctxt->valueNr++); 2923 } 2924 2925 /** 2926 * xmlXPathPopBoolean: 2927 * @ctxt: an XPath parser context 2928 * 2929 * Pops a boolean from the stack, handling conversion if needed. 2930 * Check error with #xmlXPathCheckError. 2931 * 2932 * Returns the boolean 2933 */ 2934 int 2935 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) { 2936 xmlXPathObjectPtr obj; 2937 int ret; 2938 2939 obj = valuePop(ctxt); 2940 if (obj == NULL) { 2941 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2942 return(0); 2943 } 2944 if (obj->type != XPATH_BOOLEAN) 2945 ret = xmlXPathCastToBoolean(obj); 2946 else 2947 ret = obj->boolval; 2948 xmlXPathReleaseObject(ctxt->context, obj); 2949 return(ret); 2950 } 2951 2952 /** 2953 * xmlXPathPopNumber: 2954 * @ctxt: an XPath parser context 2955 * 2956 * Pops a number from the stack, handling conversion if needed. 2957 * Check error with #xmlXPathCheckError. 2958 * 2959 * Returns the number 2960 */ 2961 double 2962 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) { 2963 xmlXPathObjectPtr obj; 2964 double ret; 2965 2966 obj = valuePop(ctxt); 2967 if (obj == NULL) { 2968 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2969 return(0); 2970 } 2971 if (obj->type != XPATH_NUMBER) 2972 ret = xmlXPathCastToNumber(obj); 2973 else 2974 ret = obj->floatval; 2975 xmlXPathReleaseObject(ctxt->context, obj); 2976 return(ret); 2977 } 2978 2979 /** 2980 * xmlXPathPopString: 2981 * @ctxt: an XPath parser context 2982 * 2983 * Pops a string from the stack, handling conversion if needed. 2984 * Check error with #xmlXPathCheckError. 2985 * 2986 * Returns the string 2987 */ 2988 xmlChar * 2989 xmlXPathPopString (xmlXPathParserContextPtr ctxt) { 2990 xmlXPathObjectPtr obj; 2991 xmlChar * ret; 2992 2993 obj = valuePop(ctxt); 2994 if (obj == NULL) { 2995 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2996 return(NULL); 2997 } 2998 ret = xmlXPathCastToString(obj); /* this does required strdup */ 2999 /* TODO: needs refactoring somewhere else */ 3000 if (obj->stringval == ret) 3001 obj->stringval = NULL; 3002 xmlXPathReleaseObject(ctxt->context, obj); 3003 return(ret); 3004 } 3005 3006 /** 3007 * xmlXPathPopNodeSet: 3008 * @ctxt: an XPath parser context 3009 * 3010 * Pops a node-set from the stack, handling conversion if needed. 3011 * Check error with #xmlXPathCheckError. 3012 * 3013 * Returns the node-set 3014 */ 3015 xmlNodeSetPtr 3016 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) { 3017 xmlXPathObjectPtr obj; 3018 xmlNodeSetPtr ret; 3019 3020 if (ctxt == NULL) return(NULL); 3021 if (ctxt->value == NULL) { 3022 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 3023 return(NULL); 3024 } 3025 if (!xmlXPathStackIsNodeSet(ctxt)) { 3026 xmlXPathSetTypeError(ctxt); 3027 return(NULL); 3028 } 3029 obj = valuePop(ctxt); 3030 ret = obj->nodesetval; 3031 #if 0 3032 /* to fix memory leak of not clearing obj->user */ 3033 if (obj->boolval && obj->user != NULL) 3034 xmlFreeNodeList((xmlNodePtr) obj->user); 3035 #endif 3036 obj->nodesetval = NULL; 3037 xmlXPathReleaseObject(ctxt->context, obj); 3038 return(ret); 3039 } 3040 3041 /** 3042 * xmlXPathPopExternal: 3043 * @ctxt: an XPath parser context 3044 * 3045 * Pops an external object from the stack, handling conversion if needed. 3046 * Check error with #xmlXPathCheckError. 3047 * 3048 * Returns the object 3049 */ 3050 void * 3051 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) { 3052 xmlXPathObjectPtr obj; 3053 void * ret; 3054 3055 if ((ctxt == NULL) || (ctxt->value == NULL)) { 3056 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 3057 return(NULL); 3058 } 3059 if (ctxt->value->type != XPATH_USERS) { 3060 xmlXPathSetTypeError(ctxt); 3061 return(NULL); 3062 } 3063 obj = valuePop(ctxt); 3064 ret = obj->user; 3065 obj->user = NULL; 3066 xmlXPathReleaseObject(ctxt->context, obj); 3067 return(ret); 3068 } 3069 3070 /* 3071 * Macros for accessing the content. Those should be used only by the parser, 3072 * and not exported. 3073 * 3074 * Dirty macros, i.e. one need to make assumption on the context to use them 3075 * 3076 * CUR_PTR return the current pointer to the xmlChar to be parsed. 3077 * CUR returns the current xmlChar value, i.e. a 8 bit value 3078 * in ISO-Latin or UTF-8. 3079 * This should be used internally by the parser 3080 * only to compare to ASCII values otherwise it would break when 3081 * running with UTF-8 encoding. 3082 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only 3083 * to compare on ASCII based substring. 3084 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined 3085 * strings within the parser. 3086 * CURRENT Returns the current char value, with the full decoding of 3087 * UTF-8 if we are using this mode. It returns an int. 3088 * NEXT Skip to the next character, this does the proper decoding 3089 * in UTF-8 mode. It also pop-up unfinished entities on the fly. 3090 * It returns the pointer to the current xmlChar. 3091 */ 3092 3093 #define CUR (*ctxt->cur) 3094 #define SKIP(val) ctxt->cur += (val) 3095 #define NXT(val) ctxt->cur[(val)] 3096 #define CUR_PTR ctxt->cur 3097 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l) 3098 3099 #define COPY_BUF(l,b,i,v) \ 3100 if (l == 1) b[i++] = (xmlChar) v; \ 3101 else i += xmlCopyChar(l,&b[i],v) 3102 3103 #define NEXTL(l) ctxt->cur += l 3104 3105 #define SKIP_BLANKS \ 3106 while (IS_BLANK_CH(*(ctxt->cur))) NEXT 3107 3108 #define CURRENT (*ctxt->cur) 3109 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur) 3110 3111 3112 #ifndef DBL_DIG 3113 #define DBL_DIG 16 3114 #endif 3115 #ifndef DBL_EPSILON 3116 #define DBL_EPSILON 1E-9 3117 #endif 3118 3119 #define UPPER_DOUBLE 1E9 3120 #define LOWER_DOUBLE 1E-5 3121 #define LOWER_DOUBLE_EXP 5 3122 3123 #define INTEGER_DIGITS DBL_DIG 3124 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP)) 3125 #define EXPONENT_DIGITS (3 + 2) 3126 3127 /** 3128 * xmlXPathFormatNumber: 3129 * @number: number to format 3130 * @buffer: output buffer 3131 * @buffersize: size of output buffer 3132 * 3133 * Convert the number into a string representation. 3134 */ 3135 static void 3136 xmlXPathFormatNumber(double number, char buffer[], int buffersize) 3137 { 3138 switch (xmlXPathIsInf(number)) { 3139 case 1: 3140 if (buffersize > (int)sizeof("Infinity")) 3141 snprintf(buffer, buffersize, "Infinity"); 3142 break; 3143 case -1: 3144 if (buffersize > (int)sizeof("-Infinity")) 3145 snprintf(buffer, buffersize, "-Infinity"); 3146 break; 3147 default: 3148 if (xmlXPathIsNaN(number)) { 3149 if (buffersize > (int)sizeof("NaN")) 3150 snprintf(buffer, buffersize, "NaN"); 3151 } else if (number == 0) { 3152 /* Omit sign for negative zero. */ 3153 snprintf(buffer, buffersize, "0"); 3154 } else if ((number > INT_MIN) && (number < INT_MAX) && 3155 (number == (int) number)) { 3156 char work[30]; 3157 char *ptr, *cur; 3158 int value = (int) number; 3159 3160 ptr = &buffer[0]; 3161 if (value == 0) { 3162 *ptr++ = '0'; 3163 } else { 3164 snprintf(work, 29, "%d", value); 3165 cur = &work[0]; 3166 while ((*cur) && (ptr - buffer < buffersize)) { 3167 *ptr++ = *cur++; 3168 } 3169 } 3170 if (ptr - buffer < buffersize) { 3171 *ptr = 0; 3172 } else if (buffersize > 0) { 3173 ptr--; 3174 *ptr = 0; 3175 } 3176 } else { 3177 /* 3178 For the dimension of work, 3179 DBL_DIG is number of significant digits 3180 EXPONENT is only needed for "scientific notation" 3181 3 is sign, decimal point, and terminating zero 3182 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction 3183 Note that this dimension is slightly (a few characters) 3184 larger than actually necessary. 3185 */ 3186 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP]; 3187 int integer_place, fraction_place; 3188 char *ptr; 3189 char *after_fraction; 3190 double absolute_value; 3191 int size; 3192 3193 absolute_value = fabs(number); 3194 3195 /* 3196 * First choose format - scientific or regular floating point. 3197 * In either case, result is in work, and after_fraction points 3198 * just past the fractional part. 3199 */ 3200 if ( ((absolute_value > UPPER_DOUBLE) || 3201 (absolute_value < LOWER_DOUBLE)) && 3202 (absolute_value != 0.0) ) { 3203 /* Use scientific notation */ 3204 integer_place = DBL_DIG + EXPONENT_DIGITS + 1; 3205 fraction_place = DBL_DIG - 1; 3206 size = snprintf(work, sizeof(work),"%*.*e", 3207 integer_place, fraction_place, number); 3208 while ((size > 0) && (work[size] != 'e')) size--; 3209 3210 } 3211 else { 3212 /* Use regular notation */ 3213 if (absolute_value > 0.0) { 3214 integer_place = (int)log10(absolute_value); 3215 if (integer_place > 0) 3216 fraction_place = DBL_DIG - integer_place - 1; 3217 else 3218 fraction_place = DBL_DIG - integer_place; 3219 } else { 3220 fraction_place = 1; 3221 } 3222 size = snprintf(work, sizeof(work), "%0.*f", 3223 fraction_place, number); 3224 } 3225 3226 /* Remove leading spaces sometimes inserted by snprintf */ 3227 while (work[0] == ' ') { 3228 for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++); 3229 size--; 3230 } 3231 3232 /* Remove fractional trailing zeroes */ 3233 after_fraction = work + size; 3234 ptr = after_fraction; 3235 while (*(--ptr) == '0') 3236 ; 3237 if (*ptr != '.') 3238 ptr++; 3239 while ((*ptr++ = *after_fraction++) != 0); 3240 3241 /* Finally copy result back to caller */ 3242 size = strlen(work) + 1; 3243 if (size > buffersize) { 3244 work[buffersize - 1] = 0; 3245 size = buffersize; 3246 } 3247 memmove(buffer, work, size); 3248 } 3249 break; 3250 } 3251 } 3252 3253 3254 /************************************************************************ 3255 * * 3256 * Routines to handle NodeSets * 3257 * * 3258 ************************************************************************/ 3259 3260 /** 3261 * xmlXPathOrderDocElems: 3262 * @doc: an input document 3263 * 3264 * Call this routine to speed up XPath computation on static documents. 3265 * This stamps all the element nodes with the document order 3266 * Like for line information, the order is kept in the element->content 3267 * field, the value stored is actually - the node number (starting at -1) 3268 * to be able to differentiate from line numbers. 3269 * 3270 * Returns the number of elements found in the document or -1 in case 3271 * of error. 3272 */ 3273 long 3274 xmlXPathOrderDocElems(xmlDocPtr doc) { 3275 ptrdiff_t count = 0; 3276 xmlNodePtr cur; 3277 3278 if (doc == NULL) 3279 return(-1); 3280 cur = doc->children; 3281 while (cur != NULL) { 3282 if (cur->type == XML_ELEMENT_NODE) { 3283 cur->content = (void *) (-(++count)); 3284 if (cur->children != NULL) { 3285 cur = cur->children; 3286 continue; 3287 } 3288 } 3289 if (cur->next != NULL) { 3290 cur = cur->next; 3291 continue; 3292 } 3293 do { 3294 cur = cur->parent; 3295 if (cur == NULL) 3296 break; 3297 if (cur == (xmlNodePtr) doc) { 3298 cur = NULL; 3299 break; 3300 } 3301 if (cur->next != NULL) { 3302 cur = cur->next; 3303 break; 3304 } 3305 } while (cur != NULL); 3306 } 3307 return((long) count); 3308 } 3309 3310 /** 3311 * xmlXPathCmpNodes: 3312 * @node1: the first node 3313 * @node2: the second node 3314 * 3315 * Compare two nodes w.r.t document order 3316 * 3317 * Returns -2 in case of error 1 if first point < second point, 0 if 3318 * it's the same node, -1 otherwise 3319 */ 3320 int 3321 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) { 3322 int depth1, depth2; 3323 int attr1 = 0, attr2 = 0; 3324 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL; 3325 xmlNodePtr cur, root; 3326 3327 if ((node1 == NULL) || (node2 == NULL)) 3328 return(-2); 3329 /* 3330 * a couple of optimizations which will avoid computations in most cases 3331 */ 3332 if (node1 == node2) /* trivial case */ 3333 return(0); 3334 if (node1->type == XML_ATTRIBUTE_NODE) { 3335 attr1 = 1; 3336 attrNode1 = node1; 3337 node1 = node1->parent; 3338 } 3339 if (node2->type == XML_ATTRIBUTE_NODE) { 3340 attr2 = 1; 3341 attrNode2 = node2; 3342 node2 = node2->parent; 3343 } 3344 if (node1 == node2) { 3345 if (attr1 == attr2) { 3346 /* not required, but we keep attributes in order */ 3347 if (attr1 != 0) { 3348 cur = attrNode2->prev; 3349 while (cur != NULL) { 3350 if (cur == attrNode1) 3351 return (1); 3352 cur = cur->prev; 3353 } 3354 return (-1); 3355 } 3356 return(0); 3357 } 3358 if (attr2 == 1) 3359 return(1); 3360 return(-1); 3361 } 3362 if ((node1->type == XML_NAMESPACE_DECL) || 3363 (node2->type == XML_NAMESPACE_DECL)) 3364 return(1); 3365 if (node1 == node2->prev) 3366 return(1); 3367 if (node1 == node2->next) 3368 return(-1); 3369 3370 /* 3371 * Speedup using document order if available. 3372 */ 3373 if ((node1->type == XML_ELEMENT_NODE) && 3374 (node2->type == XML_ELEMENT_NODE) && 3375 (0 > (ptrdiff_t) node1->content) && 3376 (0 > (ptrdiff_t) node2->content) && 3377 (node1->doc == node2->doc)) { 3378 ptrdiff_t l1, l2; 3379 3380 l1 = -((ptrdiff_t) node1->content); 3381 l2 = -((ptrdiff_t) node2->content); 3382 if (l1 < l2) 3383 return(1); 3384 if (l1 > l2) 3385 return(-1); 3386 } 3387 3388 /* 3389 * compute depth to root 3390 */ 3391 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) { 3392 if (cur->parent == node1) 3393 return(1); 3394 depth2++; 3395 } 3396 root = cur; 3397 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) { 3398 if (cur->parent == node2) 3399 return(-1); 3400 depth1++; 3401 } 3402 /* 3403 * Distinct document (or distinct entities :-( ) case. 3404 */ 3405 if (root != cur) { 3406 return(-2); 3407 } 3408 /* 3409 * get the nearest common ancestor. 3410 */ 3411 while (depth1 > depth2) { 3412 depth1--; 3413 node1 = node1->parent; 3414 } 3415 while (depth2 > depth1) { 3416 depth2--; 3417 node2 = node2->parent; 3418 } 3419 while (node1->parent != node2->parent) { 3420 node1 = node1->parent; 3421 node2 = node2->parent; 3422 /* should not happen but just in case ... */ 3423 if ((node1 == NULL) || (node2 == NULL)) 3424 return(-2); 3425 } 3426 /* 3427 * Find who's first. 3428 */ 3429 if (node1 == node2->prev) 3430 return(1); 3431 if (node1 == node2->next) 3432 return(-1); 3433 /* 3434 * Speedup using document order if available. 3435 */ 3436 if ((node1->type == XML_ELEMENT_NODE) && 3437 (node2->type == XML_ELEMENT_NODE) && 3438 (0 > (ptrdiff_t) node1->content) && 3439 (0 > (ptrdiff_t) node2->content) && 3440 (node1->doc == node2->doc)) { 3441 ptrdiff_t l1, l2; 3442 3443 l1 = -((ptrdiff_t) node1->content); 3444 l2 = -((ptrdiff_t) node2->content); 3445 if (l1 < l2) 3446 return(1); 3447 if (l1 > l2) 3448 return(-1); 3449 } 3450 3451 for (cur = node1->next;cur != NULL;cur = cur->next) 3452 if (cur == node2) 3453 return(1); 3454 return(-1); /* assume there is no sibling list corruption */ 3455 } 3456 3457 /** 3458 * xmlXPathNodeSetSort: 3459 * @set: the node set 3460 * 3461 * Sort the node set in document order 3462 */ 3463 void 3464 xmlXPathNodeSetSort(xmlNodeSetPtr set) { 3465 #ifndef WITH_TIM_SORT 3466 int i, j, incr, len; 3467 xmlNodePtr tmp; 3468 #endif 3469 3470 if (set == NULL) 3471 return; 3472 3473 #ifndef WITH_TIM_SORT 3474 /* 3475 * Use the old Shell's sort implementation to sort the node-set 3476 * Timsort ought to be quite faster 3477 */ 3478 len = set->nodeNr; 3479 for (incr = len / 2; incr > 0; incr /= 2) { 3480 for (i = incr; i < len; i++) { 3481 j = i - incr; 3482 while (j >= 0) { 3483 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 3484 if (xmlXPathCmpNodesExt(set->nodeTab[j], 3485 set->nodeTab[j + incr]) == -1) 3486 #else 3487 if (xmlXPathCmpNodes(set->nodeTab[j], 3488 set->nodeTab[j + incr]) == -1) 3489 #endif 3490 { 3491 tmp = set->nodeTab[j]; 3492 set->nodeTab[j] = set->nodeTab[j + incr]; 3493 set->nodeTab[j + incr] = tmp; 3494 j -= incr; 3495 } else 3496 break; 3497 } 3498 } 3499 } 3500 #else /* WITH_TIM_SORT */ 3501 libxml_domnode_tim_sort(set->nodeTab, set->nodeNr); 3502 #endif /* WITH_TIM_SORT */ 3503 } 3504 3505 #define XML_NODESET_DEFAULT 10 3506 /** 3507 * xmlXPathNodeSetDupNs: 3508 * @node: the parent node of the namespace XPath node 3509 * @ns: the libxml namespace declaration node. 3510 * 3511 * Namespace node in libxml don't match the XPath semantic. In a node set 3512 * the namespace nodes are duplicated and the next pointer is set to the 3513 * parent node in the XPath semantic. 3514 * 3515 * Returns the newly created object. 3516 */ 3517 static xmlNodePtr 3518 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) { 3519 xmlNsPtr cur; 3520 3521 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) 3522 return(NULL); 3523 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) 3524 return((xmlNodePtr) ns); 3525 3526 /* 3527 * Allocate a new Namespace and fill the fields. 3528 */ 3529 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); 3530 if (cur == NULL) { 3531 xmlXPathErrMemory(NULL, "duplicating namespace\n"); 3532 return(NULL); 3533 } 3534 memset(cur, 0, sizeof(xmlNs)); 3535 cur->type = XML_NAMESPACE_DECL; 3536 if (ns->href != NULL) 3537 cur->href = xmlStrdup(ns->href); 3538 if (ns->prefix != NULL) 3539 cur->prefix = xmlStrdup(ns->prefix); 3540 cur->next = (xmlNsPtr) node; 3541 return((xmlNodePtr) cur); 3542 } 3543 3544 /** 3545 * xmlXPathNodeSetFreeNs: 3546 * @ns: the XPath namespace node found in a nodeset. 3547 * 3548 * Namespace nodes in libxml don't match the XPath semantic. In a node set 3549 * the namespace nodes are duplicated and the next pointer is set to the 3550 * parent node in the XPath semantic. Check if such a node needs to be freed 3551 */ 3552 void 3553 xmlXPathNodeSetFreeNs(xmlNsPtr ns) { 3554 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) 3555 return; 3556 3557 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) { 3558 if (ns->href != NULL) 3559 xmlFree((xmlChar *)ns->href); 3560 if (ns->prefix != NULL) 3561 xmlFree((xmlChar *)ns->prefix); 3562 xmlFree(ns); 3563 } 3564 } 3565 3566 /** 3567 * xmlXPathNodeSetCreate: 3568 * @val: an initial xmlNodePtr, or NULL 3569 * 3570 * Create a new xmlNodeSetPtr of type double and of value @val 3571 * 3572 * Returns the newly created object. 3573 */ 3574 xmlNodeSetPtr 3575 xmlXPathNodeSetCreate(xmlNodePtr val) { 3576 xmlNodeSetPtr ret; 3577 3578 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet)); 3579 if (ret == NULL) { 3580 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3581 return(NULL); 3582 } 3583 memset(ret, 0 , (size_t) sizeof(xmlNodeSet)); 3584 if (val != NULL) { 3585 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3586 sizeof(xmlNodePtr)); 3587 if (ret->nodeTab == NULL) { 3588 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3589 xmlFree(ret); 3590 return(NULL); 3591 } 3592 memset(ret->nodeTab, 0 , 3593 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3594 ret->nodeMax = XML_NODESET_DEFAULT; 3595 if (val->type == XML_NAMESPACE_DECL) { 3596 xmlNsPtr ns = (xmlNsPtr) val; 3597 3598 /* TODO: Check memory error. */ 3599 ret->nodeTab[ret->nodeNr++] = 3600 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3601 } else 3602 ret->nodeTab[ret->nodeNr++] = val; 3603 } 3604 return(ret); 3605 } 3606 3607 /** 3608 * xmlXPathNodeSetContains: 3609 * @cur: the node-set 3610 * @val: the node 3611 * 3612 * checks whether @cur contains @val 3613 * 3614 * Returns true (1) if @cur contains @val, false (0) otherwise 3615 */ 3616 int 3617 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) { 3618 int i; 3619 3620 if ((cur == NULL) || (val == NULL)) return(0); 3621 if (val->type == XML_NAMESPACE_DECL) { 3622 for (i = 0; i < cur->nodeNr; i++) { 3623 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) { 3624 xmlNsPtr ns1, ns2; 3625 3626 ns1 = (xmlNsPtr) val; 3627 ns2 = (xmlNsPtr) cur->nodeTab[i]; 3628 if (ns1 == ns2) 3629 return(1); 3630 if ((ns1->next != NULL) && (ns2->next == ns1->next) && 3631 (xmlStrEqual(ns1->prefix, ns2->prefix))) 3632 return(1); 3633 } 3634 } 3635 } else { 3636 for (i = 0; i < cur->nodeNr; i++) { 3637 if (cur->nodeTab[i] == val) 3638 return(1); 3639 } 3640 } 3641 return(0); 3642 } 3643 3644 /** 3645 * xmlXPathNodeSetAddNs: 3646 * @cur: the initial node set 3647 * @node: the hosting node 3648 * @ns: a the namespace node 3649 * 3650 * add a new namespace node to an existing NodeSet 3651 * 3652 * Returns 0 in case of success and -1 in case of error 3653 */ 3654 int 3655 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) { 3656 int i; 3657 3658 3659 if ((cur == NULL) || (ns == NULL) || (node == NULL) || 3660 (ns->type != XML_NAMESPACE_DECL) || 3661 (node->type != XML_ELEMENT_NODE)) 3662 return(-1); 3663 3664 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3665 /* 3666 * prevent duplicates 3667 */ 3668 for (i = 0;i < cur->nodeNr;i++) { 3669 if ((cur->nodeTab[i] != NULL) && 3670 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) && 3671 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) && 3672 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix))) 3673 return(0); 3674 } 3675 3676 /* 3677 * grow the nodeTab if needed 3678 */ 3679 if (cur->nodeMax == 0) { 3680 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3681 sizeof(xmlNodePtr)); 3682 if (cur->nodeTab == NULL) { 3683 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3684 return(-1); 3685 } 3686 memset(cur->nodeTab, 0 , 3687 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3688 cur->nodeMax = XML_NODESET_DEFAULT; 3689 } else if (cur->nodeNr == cur->nodeMax) { 3690 xmlNodePtr *temp; 3691 3692 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 3693 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n"); 3694 return(-1); 3695 } 3696 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 * 3697 sizeof(xmlNodePtr)); 3698 if (temp == NULL) { 3699 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3700 return(-1); 3701 } 3702 cur->nodeMax *= 2; 3703 cur->nodeTab = temp; 3704 } 3705 /* TODO: Check memory error. */ 3706 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns); 3707 return(0); 3708 } 3709 3710 /** 3711 * xmlXPathNodeSetAdd: 3712 * @cur: the initial node set 3713 * @val: a new xmlNodePtr 3714 * 3715 * add a new xmlNodePtr to an existing NodeSet 3716 * 3717 * Returns 0 in case of success, and -1 in case of error 3718 */ 3719 int 3720 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) { 3721 int i; 3722 3723 if ((cur == NULL) || (val == NULL)) return(-1); 3724 3725 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3726 /* 3727 * prevent duplicates 3728 */ 3729 for (i = 0;i < cur->nodeNr;i++) 3730 if (cur->nodeTab[i] == val) return(0); 3731 3732 /* 3733 * grow the nodeTab if needed 3734 */ 3735 if (cur->nodeMax == 0) { 3736 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3737 sizeof(xmlNodePtr)); 3738 if (cur->nodeTab == NULL) { 3739 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3740 return(-1); 3741 } 3742 memset(cur->nodeTab, 0 , 3743 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3744 cur->nodeMax = XML_NODESET_DEFAULT; 3745 } else if (cur->nodeNr == cur->nodeMax) { 3746 xmlNodePtr *temp; 3747 3748 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 3749 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n"); 3750 return(-1); 3751 } 3752 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 * 3753 sizeof(xmlNodePtr)); 3754 if (temp == NULL) { 3755 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3756 return(-1); 3757 } 3758 cur->nodeMax *= 2; 3759 cur->nodeTab = temp; 3760 } 3761 if (val->type == XML_NAMESPACE_DECL) { 3762 xmlNsPtr ns = (xmlNsPtr) val; 3763 3764 /* TODO: Check memory error. */ 3765 cur->nodeTab[cur->nodeNr++] = 3766 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3767 } else 3768 cur->nodeTab[cur->nodeNr++] = val; 3769 return(0); 3770 } 3771 3772 /** 3773 * xmlXPathNodeSetAddUnique: 3774 * @cur: the initial node set 3775 * @val: a new xmlNodePtr 3776 * 3777 * add a new xmlNodePtr to an existing NodeSet, optimized version 3778 * when we are sure the node is not already in the set. 3779 * 3780 * Returns 0 in case of success and -1 in case of failure 3781 */ 3782 int 3783 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) { 3784 if ((cur == NULL) || (val == NULL)) return(-1); 3785 3786 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3787 /* 3788 * grow the nodeTab if needed 3789 */ 3790 if (cur->nodeMax == 0) { 3791 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3792 sizeof(xmlNodePtr)); 3793 if (cur->nodeTab == NULL) { 3794 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3795 return(-1); 3796 } 3797 memset(cur->nodeTab, 0 , 3798 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3799 cur->nodeMax = XML_NODESET_DEFAULT; 3800 } else if (cur->nodeNr == cur->nodeMax) { 3801 xmlNodePtr *temp; 3802 3803 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 3804 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n"); 3805 return(-1); 3806 } 3807 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 * 3808 sizeof(xmlNodePtr)); 3809 if (temp == NULL) { 3810 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3811 return(-1); 3812 } 3813 cur->nodeTab = temp; 3814 cur->nodeMax *= 2; 3815 } 3816 if (val->type == XML_NAMESPACE_DECL) { 3817 xmlNsPtr ns = (xmlNsPtr) val; 3818 3819 /* TODO: Check memory error. */ 3820 cur->nodeTab[cur->nodeNr++] = 3821 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3822 } else 3823 cur->nodeTab[cur->nodeNr++] = val; 3824 return(0); 3825 } 3826 3827 /** 3828 * xmlXPathNodeSetMerge: 3829 * @val1: the first NodeSet or NULL 3830 * @val2: the second NodeSet 3831 * 3832 * Merges two nodesets, all nodes from @val2 are added to @val1 3833 * if @val1 is NULL, a new set is created and copied from @val2 3834 * 3835 * Returns @val1 once extended or NULL in case of error. 3836 */ 3837 xmlNodeSetPtr 3838 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) { 3839 int i, j, initNr, skip; 3840 xmlNodePtr n1, n2; 3841 3842 if (val2 == NULL) return(val1); 3843 if (val1 == NULL) { 3844 val1 = xmlXPathNodeSetCreate(NULL); 3845 if (val1 == NULL) 3846 return (NULL); 3847 #if 0 3848 /* 3849 * TODO: The optimization won't work in every case, since 3850 * those nasty namespace nodes need to be added with 3851 * xmlXPathNodeSetDupNs() to the set; thus a pure 3852 * memcpy is not possible. 3853 * If there was a flag on the nodesetval, indicating that 3854 * some temporary nodes are in, that would be helpful. 3855 */ 3856 /* 3857 * Optimization: Create an equally sized node-set 3858 * and memcpy the content. 3859 */ 3860 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr); 3861 if (val1 == NULL) 3862 return(NULL); 3863 if (val2->nodeNr != 0) { 3864 if (val2->nodeNr == 1) 3865 *(val1->nodeTab) = *(val2->nodeTab); 3866 else { 3867 memcpy(val1->nodeTab, val2->nodeTab, 3868 val2->nodeNr * sizeof(xmlNodePtr)); 3869 } 3870 val1->nodeNr = val2->nodeNr; 3871 } 3872 return(val1); 3873 #endif 3874 } 3875 3876 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3877 initNr = val1->nodeNr; 3878 3879 for (i = 0;i < val2->nodeNr;i++) { 3880 n2 = val2->nodeTab[i]; 3881 /* 3882 * check against duplicates 3883 */ 3884 skip = 0; 3885 for (j = 0; j < initNr; j++) { 3886 n1 = val1->nodeTab[j]; 3887 if (n1 == n2) { 3888 skip = 1; 3889 break; 3890 } else if ((n1->type == XML_NAMESPACE_DECL) && 3891 (n2->type == XML_NAMESPACE_DECL)) { 3892 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) && 3893 (xmlStrEqual(((xmlNsPtr) n1)->prefix, 3894 ((xmlNsPtr) n2)->prefix))) 3895 { 3896 skip = 1; 3897 break; 3898 } 3899 } 3900 } 3901 if (skip) 3902 continue; 3903 3904 /* 3905 * grow the nodeTab if needed 3906 */ 3907 if (val1->nodeMax == 0) { 3908 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3909 sizeof(xmlNodePtr)); 3910 if (val1->nodeTab == NULL) { 3911 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3912 return(NULL); 3913 } 3914 memset(val1->nodeTab, 0 , 3915 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3916 val1->nodeMax = XML_NODESET_DEFAULT; 3917 } else if (val1->nodeNr == val1->nodeMax) { 3918 xmlNodePtr *temp; 3919 3920 if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 3921 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n"); 3922 return(NULL); 3923 } 3924 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 * 3925 sizeof(xmlNodePtr)); 3926 if (temp == NULL) { 3927 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3928 return(NULL); 3929 } 3930 val1->nodeTab = temp; 3931 val1->nodeMax *= 2; 3932 } 3933 if (n2->type == XML_NAMESPACE_DECL) { 3934 xmlNsPtr ns = (xmlNsPtr) n2; 3935 3936 /* TODO: Check memory error. */ 3937 val1->nodeTab[val1->nodeNr++] = 3938 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3939 } else 3940 val1->nodeTab[val1->nodeNr++] = n2; 3941 } 3942 3943 return(val1); 3944 } 3945 3946 3947 /** 3948 * xmlXPathNodeSetMergeAndClear: 3949 * @set1: the first NodeSet or NULL 3950 * @set2: the second NodeSet 3951 * 3952 * Merges two nodesets, all nodes from @set2 are added to @set1. 3953 * Checks for duplicate nodes. Clears set2. 3954 * 3955 * Returns @set1 once extended or NULL in case of error. 3956 */ 3957 static xmlNodeSetPtr 3958 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2) 3959 { 3960 { 3961 int i, j, initNbSet1; 3962 xmlNodePtr n1, n2; 3963 3964 initNbSet1 = set1->nodeNr; 3965 for (i = 0;i < set2->nodeNr;i++) { 3966 n2 = set2->nodeTab[i]; 3967 /* 3968 * Skip duplicates. 3969 */ 3970 for (j = 0; j < initNbSet1; j++) { 3971 n1 = set1->nodeTab[j]; 3972 if (n1 == n2) { 3973 goto skip_node; 3974 } else if ((n1->type == XML_NAMESPACE_DECL) && 3975 (n2->type == XML_NAMESPACE_DECL)) 3976 { 3977 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) && 3978 (xmlStrEqual(((xmlNsPtr) n1)->prefix, 3979 ((xmlNsPtr) n2)->prefix))) 3980 { 3981 /* 3982 * Free the namespace node. 3983 */ 3984 set2->nodeTab[i] = NULL; 3985 xmlXPathNodeSetFreeNs((xmlNsPtr) n2); 3986 goto skip_node; 3987 } 3988 } 3989 } 3990 /* 3991 * grow the nodeTab if needed 3992 */ 3993 if (set1->nodeMax == 0) { 3994 set1->nodeTab = (xmlNodePtr *) xmlMalloc( 3995 XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); 3996 if (set1->nodeTab == NULL) { 3997 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3998 return(NULL); 3999 } 4000 memset(set1->nodeTab, 0, 4001 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 4002 set1->nodeMax = XML_NODESET_DEFAULT; 4003 } else if (set1->nodeNr >= set1->nodeMax) { 4004 xmlNodePtr *temp; 4005 4006 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 4007 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n"); 4008 return(NULL); 4009 } 4010 temp = (xmlNodePtr *) xmlRealloc( 4011 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr)); 4012 if (temp == NULL) { 4013 xmlXPathErrMemory(NULL, "merging nodeset\n"); 4014 return(NULL); 4015 } 4016 set1->nodeTab = temp; 4017 set1->nodeMax *= 2; 4018 } 4019 set1->nodeTab[set1->nodeNr++] = n2; 4020 skip_node: 4021 {} 4022 } 4023 } 4024 set2->nodeNr = 0; 4025 return(set1); 4026 } 4027 4028 /** 4029 * xmlXPathNodeSetMergeAndClearNoDupls: 4030 * @set1: the first NodeSet or NULL 4031 * @set2: the second NodeSet 4032 * 4033 * Merges two nodesets, all nodes from @set2 are added to @set1. 4034 * Doesn't check for duplicate nodes. Clears set2. 4035 * 4036 * Returns @set1 once extended or NULL in case of error. 4037 */ 4038 static xmlNodeSetPtr 4039 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2) 4040 { 4041 { 4042 int i; 4043 xmlNodePtr n2; 4044 4045 for (i = 0;i < set2->nodeNr;i++) { 4046 n2 = set2->nodeTab[i]; 4047 if (set1->nodeMax == 0) { 4048 set1->nodeTab = (xmlNodePtr *) xmlMalloc( 4049 XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); 4050 if (set1->nodeTab == NULL) { 4051 xmlXPathErrMemory(NULL, "merging nodeset\n"); 4052 return(NULL); 4053 } 4054 memset(set1->nodeTab, 0, 4055 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 4056 set1->nodeMax = XML_NODESET_DEFAULT; 4057 } else if (set1->nodeNr >= set1->nodeMax) { 4058 xmlNodePtr *temp; 4059 4060 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 4061 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n"); 4062 return(NULL); 4063 } 4064 temp = (xmlNodePtr *) xmlRealloc( 4065 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr)); 4066 if (temp == NULL) { 4067 xmlXPathErrMemory(NULL, "merging nodeset\n"); 4068 return(NULL); 4069 } 4070 set1->nodeTab = temp; 4071 set1->nodeMax *= 2; 4072 } 4073 set1->nodeTab[set1->nodeNr++] = n2; 4074 } 4075 } 4076 set2->nodeNr = 0; 4077 return(set1); 4078 } 4079 4080 /** 4081 * xmlXPathNodeSetDel: 4082 * @cur: the initial node set 4083 * @val: an xmlNodePtr 4084 * 4085 * Removes an xmlNodePtr from an existing NodeSet 4086 */ 4087 void 4088 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) { 4089 int i; 4090 4091 if (cur == NULL) return; 4092 if (val == NULL) return; 4093 4094 /* 4095 * find node in nodeTab 4096 */ 4097 for (i = 0;i < cur->nodeNr;i++) 4098 if (cur->nodeTab[i] == val) break; 4099 4100 if (i >= cur->nodeNr) { /* not found */ 4101 #ifdef DEBUG 4102 xmlGenericError(xmlGenericErrorContext, 4103 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n", 4104 val->name); 4105 #endif 4106 return; 4107 } 4108 if ((cur->nodeTab[i] != NULL) && 4109 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL)) 4110 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]); 4111 cur->nodeNr--; 4112 for (;i < cur->nodeNr;i++) 4113 cur->nodeTab[i] = cur->nodeTab[i + 1]; 4114 cur->nodeTab[cur->nodeNr] = NULL; 4115 } 4116 4117 /** 4118 * xmlXPathNodeSetRemove: 4119 * @cur: the initial node set 4120 * @val: the index to remove 4121 * 4122 * Removes an entry from an existing NodeSet list. 4123 */ 4124 void 4125 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) { 4126 if (cur == NULL) return; 4127 if (val >= cur->nodeNr) return; 4128 if ((cur->nodeTab[val] != NULL) && 4129 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL)) 4130 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]); 4131 cur->nodeNr--; 4132 for (;val < cur->nodeNr;val++) 4133 cur->nodeTab[val] = cur->nodeTab[val + 1]; 4134 cur->nodeTab[cur->nodeNr] = NULL; 4135 } 4136 4137 /** 4138 * xmlXPathFreeNodeSet: 4139 * @obj: the xmlNodeSetPtr to free 4140 * 4141 * Free the NodeSet compound (not the actual nodes !). 4142 */ 4143 void 4144 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) { 4145 if (obj == NULL) return; 4146 if (obj->nodeTab != NULL) { 4147 int i; 4148 4149 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 4150 for (i = 0;i < obj->nodeNr;i++) 4151 if ((obj->nodeTab[i] != NULL) && 4152 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL)) 4153 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]); 4154 xmlFree(obj->nodeTab); 4155 } 4156 xmlFree(obj); 4157 } 4158 4159 /** 4160 * xmlXPathNodeSetClearFromPos: 4161 * @set: the node set to be cleared 4162 * @pos: the start position to clear from 4163 * 4164 * Clears the list from temporary XPath objects (e.g. namespace nodes 4165 * are feed) starting with the entry at @pos, but does *not* free the list 4166 * itself. Sets the length of the list to @pos. 4167 */ 4168 static void 4169 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes) 4170 { 4171 if ((set == NULL) || (pos >= set->nodeNr)) 4172 return; 4173 else if ((hasNsNodes)) { 4174 int i; 4175 xmlNodePtr node; 4176 4177 for (i = pos; i < set->nodeNr; i++) { 4178 node = set->nodeTab[i]; 4179 if ((node != NULL) && 4180 (node->type == XML_NAMESPACE_DECL)) 4181 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 4182 } 4183 } 4184 set->nodeNr = pos; 4185 } 4186 4187 /** 4188 * xmlXPathNodeSetClear: 4189 * @set: the node set to clear 4190 * 4191 * Clears the list from all temporary XPath objects (e.g. namespace nodes 4192 * are feed), but does *not* free the list itself. Sets the length of the 4193 * list to 0. 4194 */ 4195 static void 4196 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes) 4197 { 4198 xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes); 4199 } 4200 4201 /** 4202 * xmlXPathNodeSetKeepLast: 4203 * @set: the node set to be cleared 4204 * 4205 * Move the last node to the first position and clear temporary XPath objects 4206 * (e.g. namespace nodes) from all other nodes. Sets the length of the list 4207 * to 1. 4208 */ 4209 static void 4210 xmlXPathNodeSetKeepLast(xmlNodeSetPtr set) 4211 { 4212 int i; 4213 xmlNodePtr node; 4214 4215 if ((set == NULL) || (set->nodeNr <= 1)) 4216 return; 4217 for (i = 0; i < set->nodeNr - 1; i++) { 4218 node = set->nodeTab[i]; 4219 if ((node != NULL) && 4220 (node->type == XML_NAMESPACE_DECL)) 4221 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 4222 } 4223 set->nodeTab[0] = set->nodeTab[set->nodeNr-1]; 4224 set->nodeNr = 1; 4225 } 4226 4227 /** 4228 * xmlXPathFreeValueTree: 4229 * @obj: the xmlNodeSetPtr to free 4230 * 4231 * Free the NodeSet compound and the actual tree, this is different 4232 * from xmlXPathFreeNodeSet() 4233 */ 4234 static void 4235 xmlXPathFreeValueTree(xmlNodeSetPtr obj) { 4236 int i; 4237 4238 if (obj == NULL) return; 4239 4240 if (obj->nodeTab != NULL) { 4241 for (i = 0;i < obj->nodeNr;i++) { 4242 if (obj->nodeTab[i] != NULL) { 4243 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) { 4244 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]); 4245 } else { 4246 xmlFreeNodeList(obj->nodeTab[i]); 4247 } 4248 } 4249 } 4250 xmlFree(obj->nodeTab); 4251 } 4252 xmlFree(obj); 4253 } 4254 4255 #if defined(DEBUG) || defined(DEBUG_STEP) 4256 /** 4257 * xmlGenericErrorContextNodeSet: 4258 * @output: a FILE * for the output 4259 * @obj: the xmlNodeSetPtr to display 4260 * 4261 * Quick display of a NodeSet 4262 */ 4263 void 4264 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) { 4265 int i; 4266 4267 if (output == NULL) output = xmlGenericErrorContext; 4268 if (obj == NULL) { 4269 fprintf(output, "NodeSet == NULL !\n"); 4270 return; 4271 } 4272 if (obj->nodeNr == 0) { 4273 fprintf(output, "NodeSet is empty\n"); 4274 return; 4275 } 4276 if (obj->nodeTab == NULL) { 4277 fprintf(output, " nodeTab == NULL !\n"); 4278 return; 4279 } 4280 for (i = 0; i < obj->nodeNr; i++) { 4281 if (obj->nodeTab[i] == NULL) { 4282 fprintf(output, " NULL !\n"); 4283 return; 4284 } 4285 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) || 4286 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE)) 4287 fprintf(output, " /"); 4288 else if (obj->nodeTab[i]->name == NULL) 4289 fprintf(output, " noname!"); 4290 else fprintf(output, " %s", obj->nodeTab[i]->name); 4291 } 4292 fprintf(output, "\n"); 4293 } 4294 #endif 4295 4296 /** 4297 * xmlXPathNewNodeSet: 4298 * @val: the NodePtr value 4299 * 4300 * Create a new xmlXPathObjectPtr of type NodeSet and initialize 4301 * it with the single Node @val 4302 * 4303 * Returns the newly created object. 4304 */ 4305 xmlXPathObjectPtr 4306 xmlXPathNewNodeSet(xmlNodePtr val) { 4307 xmlXPathObjectPtr ret; 4308 4309 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4310 if (ret == NULL) { 4311 xmlXPathErrMemory(NULL, "creating nodeset\n"); 4312 return(NULL); 4313 } 4314 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4315 ret->type = XPATH_NODESET; 4316 ret->boolval = 0; 4317 /* TODO: Check memory error. */ 4318 ret->nodesetval = xmlXPathNodeSetCreate(val); 4319 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 4320 #ifdef XP_DEBUG_OBJ_USAGE 4321 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET); 4322 #endif 4323 return(ret); 4324 } 4325 4326 /** 4327 * xmlXPathNewValueTree: 4328 * @val: the NodePtr value 4329 * 4330 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize 4331 * it with the tree root @val 4332 * 4333 * Returns the newly created object. 4334 */ 4335 xmlXPathObjectPtr 4336 xmlXPathNewValueTree(xmlNodePtr val) { 4337 xmlXPathObjectPtr ret; 4338 4339 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4340 if (ret == NULL) { 4341 xmlXPathErrMemory(NULL, "creating result value tree\n"); 4342 return(NULL); 4343 } 4344 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4345 ret->type = XPATH_XSLT_TREE; 4346 ret->boolval = 1; 4347 ret->user = (void *) val; 4348 ret->nodesetval = xmlXPathNodeSetCreate(val); 4349 #ifdef XP_DEBUG_OBJ_USAGE 4350 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE); 4351 #endif 4352 return(ret); 4353 } 4354 4355 /** 4356 * xmlXPathNewNodeSetList: 4357 * @val: an existing NodeSet 4358 * 4359 * Create a new xmlXPathObjectPtr of type NodeSet and initialize 4360 * it with the Nodeset @val 4361 * 4362 * Returns the newly created object. 4363 */ 4364 xmlXPathObjectPtr 4365 xmlXPathNewNodeSetList(xmlNodeSetPtr val) 4366 { 4367 xmlXPathObjectPtr ret; 4368 int i; 4369 4370 if (val == NULL) 4371 ret = NULL; 4372 else if (val->nodeTab == NULL) 4373 ret = xmlXPathNewNodeSet(NULL); 4374 else { 4375 ret = xmlXPathNewNodeSet(val->nodeTab[0]); 4376 if (ret) { 4377 for (i = 1; i < val->nodeNr; ++i) { 4378 /* TODO: Propagate memory error. */ 4379 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]) 4380 < 0) break; 4381 } 4382 } 4383 } 4384 4385 return (ret); 4386 } 4387 4388 /** 4389 * xmlXPathWrapNodeSet: 4390 * @val: the NodePtr value 4391 * 4392 * Wrap the Nodeset @val in a new xmlXPathObjectPtr 4393 * 4394 * Returns the newly created object. 4395 */ 4396 xmlXPathObjectPtr 4397 xmlXPathWrapNodeSet(xmlNodeSetPtr val) { 4398 xmlXPathObjectPtr ret; 4399 4400 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4401 if (ret == NULL) { 4402 xmlXPathErrMemory(NULL, "creating node set object\n"); 4403 return(NULL); 4404 } 4405 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4406 ret->type = XPATH_NODESET; 4407 ret->nodesetval = val; 4408 #ifdef XP_DEBUG_OBJ_USAGE 4409 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET); 4410 #endif 4411 return(ret); 4412 } 4413 4414 /** 4415 * xmlXPathFreeNodeSetList: 4416 * @obj: an existing NodeSetList object 4417 * 4418 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in 4419 * the list contrary to xmlXPathFreeObject(). 4420 */ 4421 void 4422 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) { 4423 if (obj == NULL) return; 4424 #ifdef XP_DEBUG_OBJ_USAGE 4425 xmlXPathDebugObjUsageReleased(NULL, obj->type); 4426 #endif 4427 xmlFree(obj); 4428 } 4429 4430 /** 4431 * xmlXPathDifference: 4432 * @nodes1: a node-set 4433 * @nodes2: a node-set 4434 * 4435 * Implements the EXSLT - Sets difference() function: 4436 * node-set set:difference (node-set, node-set) 4437 * 4438 * Returns the difference between the two node sets, or nodes1 if 4439 * nodes2 is empty 4440 */ 4441 xmlNodeSetPtr 4442 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4443 xmlNodeSetPtr ret; 4444 int i, l1; 4445 xmlNodePtr cur; 4446 4447 if (xmlXPathNodeSetIsEmpty(nodes2)) 4448 return(nodes1); 4449 4450 /* TODO: Check memory error. */ 4451 ret = xmlXPathNodeSetCreate(NULL); 4452 if (xmlXPathNodeSetIsEmpty(nodes1)) 4453 return(ret); 4454 4455 l1 = xmlXPathNodeSetGetLength(nodes1); 4456 4457 for (i = 0; i < l1; i++) { 4458 cur = xmlXPathNodeSetItem(nodes1, i); 4459 if (!xmlXPathNodeSetContains(nodes2, cur)) { 4460 /* TODO: Propagate memory error. */ 4461 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) 4462 break; 4463 } 4464 } 4465 return(ret); 4466 } 4467 4468 /** 4469 * xmlXPathIntersection: 4470 * @nodes1: a node-set 4471 * @nodes2: a node-set 4472 * 4473 * Implements the EXSLT - Sets intersection() function: 4474 * node-set set:intersection (node-set, node-set) 4475 * 4476 * Returns a node set comprising the nodes that are within both the 4477 * node sets passed as arguments 4478 */ 4479 xmlNodeSetPtr 4480 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4481 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL); 4482 int i, l1; 4483 xmlNodePtr cur; 4484 4485 if (ret == NULL) 4486 return(ret); 4487 if (xmlXPathNodeSetIsEmpty(nodes1)) 4488 return(ret); 4489 if (xmlXPathNodeSetIsEmpty(nodes2)) 4490 return(ret); 4491 4492 l1 = xmlXPathNodeSetGetLength(nodes1); 4493 4494 for (i = 0; i < l1; i++) { 4495 cur = xmlXPathNodeSetItem(nodes1, i); 4496 if (xmlXPathNodeSetContains(nodes2, cur)) { 4497 /* TODO: Propagate memory error. */ 4498 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) 4499 break; 4500 } 4501 } 4502 return(ret); 4503 } 4504 4505 /** 4506 * xmlXPathDistinctSorted: 4507 * @nodes: a node-set, sorted by document order 4508 * 4509 * Implements the EXSLT - Sets distinct() function: 4510 * node-set set:distinct (node-set) 4511 * 4512 * Returns a subset of the nodes contained in @nodes, or @nodes if 4513 * it is empty 4514 */ 4515 xmlNodeSetPtr 4516 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) { 4517 xmlNodeSetPtr ret; 4518 xmlHashTablePtr hash; 4519 int i, l; 4520 xmlChar * strval; 4521 xmlNodePtr cur; 4522 4523 if (xmlXPathNodeSetIsEmpty(nodes)) 4524 return(nodes); 4525 4526 ret = xmlXPathNodeSetCreate(NULL); 4527 if (ret == NULL) 4528 return(ret); 4529 l = xmlXPathNodeSetGetLength(nodes); 4530 hash = xmlHashCreate (l); 4531 for (i = 0; i < l; i++) { 4532 cur = xmlXPathNodeSetItem(nodes, i); 4533 strval = xmlXPathCastNodeToString(cur); 4534 if (xmlHashLookup(hash, strval) == NULL) { 4535 xmlHashAddEntry(hash, strval, strval); 4536 /* TODO: Propagate memory error. */ 4537 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) 4538 break; 4539 } else { 4540 xmlFree(strval); 4541 } 4542 } 4543 xmlHashFree(hash, xmlHashDefaultDeallocator); 4544 return(ret); 4545 } 4546 4547 /** 4548 * xmlXPathDistinct: 4549 * @nodes: a node-set 4550 * 4551 * Implements the EXSLT - Sets distinct() function: 4552 * node-set set:distinct (node-set) 4553 * @nodes is sorted by document order, then #exslSetsDistinctSorted 4554 * is called with the sorted node-set 4555 * 4556 * Returns a subset of the nodes contained in @nodes, or @nodes if 4557 * it is empty 4558 */ 4559 xmlNodeSetPtr 4560 xmlXPathDistinct (xmlNodeSetPtr nodes) { 4561 if (xmlXPathNodeSetIsEmpty(nodes)) 4562 return(nodes); 4563 4564 xmlXPathNodeSetSort(nodes); 4565 return(xmlXPathDistinctSorted(nodes)); 4566 } 4567 4568 /** 4569 * xmlXPathHasSameNodes: 4570 * @nodes1: a node-set 4571 * @nodes2: a node-set 4572 * 4573 * Implements the EXSLT - Sets has-same-nodes function: 4574 * boolean set:has-same-node(node-set, node-set) 4575 * 4576 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0) 4577 * otherwise 4578 */ 4579 int 4580 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4581 int i, l; 4582 xmlNodePtr cur; 4583 4584 if (xmlXPathNodeSetIsEmpty(nodes1) || 4585 xmlXPathNodeSetIsEmpty(nodes2)) 4586 return(0); 4587 4588 l = xmlXPathNodeSetGetLength(nodes1); 4589 for (i = 0; i < l; i++) { 4590 cur = xmlXPathNodeSetItem(nodes1, i); 4591 if (xmlXPathNodeSetContains(nodes2, cur)) 4592 return(1); 4593 } 4594 return(0); 4595 } 4596 4597 /** 4598 * xmlXPathNodeLeadingSorted: 4599 * @nodes: a node-set, sorted by document order 4600 * @node: a node 4601 * 4602 * Implements the EXSLT - Sets leading() function: 4603 * node-set set:leading (node-set, node-set) 4604 * 4605 * Returns the nodes in @nodes that precede @node in document order, 4606 * @nodes if @node is NULL or an empty node-set if @nodes 4607 * doesn't contain @node 4608 */ 4609 xmlNodeSetPtr 4610 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { 4611 int i, l; 4612 xmlNodePtr cur; 4613 xmlNodeSetPtr ret; 4614 4615 if (node == NULL) 4616 return(nodes); 4617 4618 ret = xmlXPathNodeSetCreate(NULL); 4619 if (ret == NULL) 4620 return(ret); 4621 if (xmlXPathNodeSetIsEmpty(nodes) || 4622 (!xmlXPathNodeSetContains(nodes, node))) 4623 return(ret); 4624 4625 l = xmlXPathNodeSetGetLength(nodes); 4626 for (i = 0; i < l; i++) { 4627 cur = xmlXPathNodeSetItem(nodes, i); 4628 if (cur == node) 4629 break; 4630 /* TODO: Propagate memory error. */ 4631 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) 4632 break; 4633 } 4634 return(ret); 4635 } 4636 4637 /** 4638 * xmlXPathNodeLeading: 4639 * @nodes: a node-set 4640 * @node: a node 4641 * 4642 * Implements the EXSLT - Sets leading() function: 4643 * node-set set:leading (node-set, node-set) 4644 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted 4645 * is called. 4646 * 4647 * Returns the nodes in @nodes that precede @node in document order, 4648 * @nodes if @node is NULL or an empty node-set if @nodes 4649 * doesn't contain @node 4650 */ 4651 xmlNodeSetPtr 4652 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) { 4653 xmlXPathNodeSetSort(nodes); 4654 return(xmlXPathNodeLeadingSorted(nodes, node)); 4655 } 4656 4657 /** 4658 * xmlXPathLeadingSorted: 4659 * @nodes1: a node-set, sorted by document order 4660 * @nodes2: a node-set, sorted by document order 4661 * 4662 * Implements the EXSLT - Sets leading() function: 4663 * node-set set:leading (node-set, node-set) 4664 * 4665 * Returns the nodes in @nodes1 that precede the first node in @nodes2 4666 * in document order, @nodes1 if @nodes2 is NULL or empty or 4667 * an empty node-set if @nodes1 doesn't contain @nodes2 4668 */ 4669 xmlNodeSetPtr 4670 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4671 if (xmlXPathNodeSetIsEmpty(nodes2)) 4672 return(nodes1); 4673 return(xmlXPathNodeLeadingSorted(nodes1, 4674 xmlXPathNodeSetItem(nodes2, 1))); 4675 } 4676 4677 /** 4678 * xmlXPathLeading: 4679 * @nodes1: a node-set 4680 * @nodes2: a node-set 4681 * 4682 * Implements the EXSLT - Sets leading() function: 4683 * node-set set:leading (node-set, node-set) 4684 * @nodes1 and @nodes2 are sorted by document order, then 4685 * #exslSetsLeadingSorted is called. 4686 * 4687 * Returns the nodes in @nodes1 that precede the first node in @nodes2 4688 * in document order, @nodes1 if @nodes2 is NULL or empty or 4689 * an empty node-set if @nodes1 doesn't contain @nodes2 4690 */ 4691 xmlNodeSetPtr 4692 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4693 if (xmlXPathNodeSetIsEmpty(nodes2)) 4694 return(nodes1); 4695 if (xmlXPathNodeSetIsEmpty(nodes1)) 4696 return(xmlXPathNodeSetCreate(NULL)); 4697 xmlXPathNodeSetSort(nodes1); 4698 xmlXPathNodeSetSort(nodes2); 4699 return(xmlXPathNodeLeadingSorted(nodes1, 4700 xmlXPathNodeSetItem(nodes2, 1))); 4701 } 4702 4703 /** 4704 * xmlXPathNodeTrailingSorted: 4705 * @nodes: a node-set, sorted by document order 4706 * @node: a node 4707 * 4708 * Implements the EXSLT - Sets trailing() function: 4709 * node-set set:trailing (node-set, node-set) 4710 * 4711 * Returns the nodes in @nodes that follow @node in document order, 4712 * @nodes if @node is NULL or an empty node-set if @nodes 4713 * doesn't contain @node 4714 */ 4715 xmlNodeSetPtr 4716 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { 4717 int i, l; 4718 xmlNodePtr cur; 4719 xmlNodeSetPtr ret; 4720 4721 if (node == NULL) 4722 return(nodes); 4723 4724 ret = xmlXPathNodeSetCreate(NULL); 4725 if (ret == NULL) 4726 return(ret); 4727 if (xmlXPathNodeSetIsEmpty(nodes) || 4728 (!xmlXPathNodeSetContains(nodes, node))) 4729 return(ret); 4730 4731 l = xmlXPathNodeSetGetLength(nodes); 4732 for (i = l - 1; i >= 0; i--) { 4733 cur = xmlXPathNodeSetItem(nodes, i); 4734 if (cur == node) 4735 break; 4736 /* TODO: Propagate memory error. */ 4737 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) 4738 break; 4739 } 4740 xmlXPathNodeSetSort(ret); /* bug 413451 */ 4741 return(ret); 4742 } 4743 4744 /** 4745 * xmlXPathNodeTrailing: 4746 * @nodes: a node-set 4747 * @node: a node 4748 * 4749 * Implements the EXSLT - Sets trailing() function: 4750 * node-set set:trailing (node-set, node-set) 4751 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted 4752 * is called. 4753 * 4754 * Returns the nodes in @nodes that follow @node in document order, 4755 * @nodes if @node is NULL or an empty node-set if @nodes 4756 * doesn't contain @node 4757 */ 4758 xmlNodeSetPtr 4759 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) { 4760 xmlXPathNodeSetSort(nodes); 4761 return(xmlXPathNodeTrailingSorted(nodes, node)); 4762 } 4763 4764 /** 4765 * xmlXPathTrailingSorted: 4766 * @nodes1: a node-set, sorted by document order 4767 * @nodes2: a node-set, sorted by document order 4768 * 4769 * Implements the EXSLT - Sets trailing() function: 4770 * node-set set:trailing (node-set, node-set) 4771 * 4772 * Returns the nodes in @nodes1 that follow the first node in @nodes2 4773 * in document order, @nodes1 if @nodes2 is NULL or empty or 4774 * an empty node-set if @nodes1 doesn't contain @nodes2 4775 */ 4776 xmlNodeSetPtr 4777 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4778 if (xmlXPathNodeSetIsEmpty(nodes2)) 4779 return(nodes1); 4780 return(xmlXPathNodeTrailingSorted(nodes1, 4781 xmlXPathNodeSetItem(nodes2, 0))); 4782 } 4783 4784 /** 4785 * xmlXPathTrailing: 4786 * @nodes1: a node-set 4787 * @nodes2: a node-set 4788 * 4789 * Implements the EXSLT - Sets trailing() function: 4790 * node-set set:trailing (node-set, node-set) 4791 * @nodes1 and @nodes2 are sorted by document order, then 4792 * #xmlXPathTrailingSorted is called. 4793 * 4794 * Returns the nodes in @nodes1 that follow the first node in @nodes2 4795 * in document order, @nodes1 if @nodes2 is NULL or empty or 4796 * an empty node-set if @nodes1 doesn't contain @nodes2 4797 */ 4798 xmlNodeSetPtr 4799 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4800 if (xmlXPathNodeSetIsEmpty(nodes2)) 4801 return(nodes1); 4802 if (xmlXPathNodeSetIsEmpty(nodes1)) 4803 return(xmlXPathNodeSetCreate(NULL)); 4804 xmlXPathNodeSetSort(nodes1); 4805 xmlXPathNodeSetSort(nodes2); 4806 return(xmlXPathNodeTrailingSorted(nodes1, 4807 xmlXPathNodeSetItem(nodes2, 0))); 4808 } 4809 4810 /************************************************************************ 4811 * * 4812 * Routines to handle extra functions * 4813 * * 4814 ************************************************************************/ 4815 4816 /** 4817 * xmlXPathRegisterFunc: 4818 * @ctxt: the XPath context 4819 * @name: the function name 4820 * @f: the function implementation or NULL 4821 * 4822 * Register a new function. If @f is NULL it unregisters the function 4823 * 4824 * Returns 0 in case of success, -1 in case of error 4825 */ 4826 int 4827 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name, 4828 xmlXPathFunction f) { 4829 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f)); 4830 } 4831 4832 /** 4833 * xmlXPathRegisterFuncNS: 4834 * @ctxt: the XPath context 4835 * @name: the function name 4836 * @ns_uri: the function namespace URI 4837 * @f: the function implementation or NULL 4838 * 4839 * Register a new function. If @f is NULL it unregisters the function 4840 * 4841 * Returns 0 in case of success, -1 in case of error 4842 */ 4843 int 4844 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name, 4845 const xmlChar *ns_uri, xmlXPathFunction f) { 4846 if (ctxt == NULL) 4847 return(-1); 4848 if (name == NULL) 4849 return(-1); 4850 4851 if (ctxt->funcHash == NULL) 4852 ctxt->funcHash = xmlHashCreate(0); 4853 if (ctxt->funcHash == NULL) 4854 return(-1); 4855 if (f == NULL) 4856 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL)); 4857 XML_IGNORE_PEDANTIC_WARNINGS 4858 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f)); 4859 XML_POP_WARNINGS 4860 } 4861 4862 /** 4863 * xmlXPathRegisterFuncLookup: 4864 * @ctxt: the XPath context 4865 * @f: the lookup function 4866 * @funcCtxt: the lookup data 4867 * 4868 * Registers an external mechanism to do function lookup. 4869 */ 4870 void 4871 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt, 4872 xmlXPathFuncLookupFunc f, 4873 void *funcCtxt) { 4874 if (ctxt == NULL) 4875 return; 4876 ctxt->funcLookupFunc = f; 4877 ctxt->funcLookupData = funcCtxt; 4878 } 4879 4880 /** 4881 * xmlXPathFunctionLookup: 4882 * @ctxt: the XPath context 4883 * @name: the function name 4884 * 4885 * Search in the Function array of the context for the given 4886 * function. 4887 * 4888 * Returns the xmlXPathFunction or NULL if not found 4889 */ 4890 xmlXPathFunction 4891 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { 4892 if (ctxt == NULL) 4893 return (NULL); 4894 4895 if (ctxt->funcLookupFunc != NULL) { 4896 xmlXPathFunction ret; 4897 xmlXPathFuncLookupFunc f; 4898 4899 f = ctxt->funcLookupFunc; 4900 ret = f(ctxt->funcLookupData, name, NULL); 4901 if (ret != NULL) 4902 return(ret); 4903 } 4904 return(xmlXPathFunctionLookupNS(ctxt, name, NULL)); 4905 } 4906 4907 /** 4908 * xmlXPathFunctionLookupNS: 4909 * @ctxt: the XPath context 4910 * @name: the function name 4911 * @ns_uri: the function namespace URI 4912 * 4913 * Search in the Function array of the context for the given 4914 * function. 4915 * 4916 * Returns the xmlXPathFunction or NULL if not found 4917 */ 4918 xmlXPathFunction 4919 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name, 4920 const xmlChar *ns_uri) { 4921 xmlXPathFunction ret; 4922 4923 if (ctxt == NULL) 4924 return(NULL); 4925 if (name == NULL) 4926 return(NULL); 4927 4928 if (ctxt->funcLookupFunc != NULL) { 4929 xmlXPathFuncLookupFunc f; 4930 4931 f = ctxt->funcLookupFunc; 4932 ret = f(ctxt->funcLookupData, name, ns_uri); 4933 if (ret != NULL) 4934 return(ret); 4935 } 4936 4937 if (ctxt->funcHash == NULL) 4938 return(NULL); 4939 4940 XML_IGNORE_PEDANTIC_WARNINGS 4941 ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri); 4942 XML_POP_WARNINGS 4943 return(ret); 4944 } 4945 4946 /** 4947 * xmlXPathRegisteredFuncsCleanup: 4948 * @ctxt: the XPath context 4949 * 4950 * Cleanup the XPath context data associated to registered functions 4951 */ 4952 void 4953 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) { 4954 if (ctxt == NULL) 4955 return; 4956 4957 xmlHashFree(ctxt->funcHash, NULL); 4958 ctxt->funcHash = NULL; 4959 } 4960 4961 /************************************************************************ 4962 * * 4963 * Routines to handle Variables * 4964 * * 4965 ************************************************************************/ 4966 4967 /** 4968 * xmlXPathRegisterVariable: 4969 * @ctxt: the XPath context 4970 * @name: the variable name 4971 * @value: the variable value or NULL 4972 * 4973 * Register a new variable value. If @value is NULL it unregisters 4974 * the variable 4975 * 4976 * Returns 0 in case of success, -1 in case of error 4977 */ 4978 int 4979 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name, 4980 xmlXPathObjectPtr value) { 4981 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value)); 4982 } 4983 4984 /** 4985 * xmlXPathRegisterVariableNS: 4986 * @ctxt: the XPath context 4987 * @name: the variable name 4988 * @ns_uri: the variable namespace URI 4989 * @value: the variable value or NULL 4990 * 4991 * Register a new variable value. If @value is NULL it unregisters 4992 * the variable 4993 * 4994 * Returns 0 in case of success, -1 in case of error 4995 */ 4996 int 4997 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name, 4998 const xmlChar *ns_uri, 4999 xmlXPathObjectPtr value) { 5000 if (ctxt == NULL) 5001 return(-1); 5002 if (name == NULL) 5003 return(-1); 5004 5005 if (ctxt->varHash == NULL) 5006 ctxt->varHash = xmlHashCreate(0); 5007 if (ctxt->varHash == NULL) 5008 return(-1); 5009 if (value == NULL) 5010 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri, 5011 xmlXPathFreeObjectEntry)); 5012 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri, 5013 (void *) value, xmlXPathFreeObjectEntry)); 5014 } 5015 5016 /** 5017 * xmlXPathRegisterVariableLookup: 5018 * @ctxt: the XPath context 5019 * @f: the lookup function 5020 * @data: the lookup data 5021 * 5022 * register an external mechanism to do variable lookup 5023 */ 5024 void 5025 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt, 5026 xmlXPathVariableLookupFunc f, void *data) { 5027 if (ctxt == NULL) 5028 return; 5029 ctxt->varLookupFunc = f; 5030 ctxt->varLookupData = data; 5031 } 5032 5033 /** 5034 * xmlXPathVariableLookup: 5035 * @ctxt: the XPath context 5036 * @name: the variable name 5037 * 5038 * Search in the Variable array of the context for the given 5039 * variable value. 5040 * 5041 * Returns a copy of the value or NULL if not found 5042 */ 5043 xmlXPathObjectPtr 5044 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { 5045 if (ctxt == NULL) 5046 return(NULL); 5047 5048 if (ctxt->varLookupFunc != NULL) { 5049 xmlXPathObjectPtr ret; 5050 5051 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc) 5052 (ctxt->varLookupData, name, NULL); 5053 return(ret); 5054 } 5055 return(xmlXPathVariableLookupNS(ctxt, name, NULL)); 5056 } 5057 5058 /** 5059 * xmlXPathVariableLookupNS: 5060 * @ctxt: the XPath context 5061 * @name: the variable name 5062 * @ns_uri: the variable namespace URI 5063 * 5064 * Search in the Variable array of the context for the given 5065 * variable value. 5066 * 5067 * Returns the a copy of the value or NULL if not found 5068 */ 5069 xmlXPathObjectPtr 5070 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name, 5071 const xmlChar *ns_uri) { 5072 if (ctxt == NULL) 5073 return(NULL); 5074 5075 if (ctxt->varLookupFunc != NULL) { 5076 xmlXPathObjectPtr ret; 5077 5078 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc) 5079 (ctxt->varLookupData, name, ns_uri); 5080 if (ret != NULL) return(ret); 5081 } 5082 5083 if (ctxt->varHash == NULL) 5084 return(NULL); 5085 if (name == NULL) 5086 return(NULL); 5087 5088 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr) 5089 xmlHashLookup2(ctxt->varHash, name, ns_uri))); 5090 } 5091 5092 /** 5093 * xmlXPathRegisteredVariablesCleanup: 5094 * @ctxt: the XPath context 5095 * 5096 * Cleanup the XPath context data associated to registered variables 5097 */ 5098 void 5099 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) { 5100 if (ctxt == NULL) 5101 return; 5102 5103 xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry); 5104 ctxt->varHash = NULL; 5105 } 5106 5107 /** 5108 * xmlXPathRegisterNs: 5109 * @ctxt: the XPath context 5110 * @prefix: the namespace prefix cannot be NULL or empty string 5111 * @ns_uri: the namespace name 5112 * 5113 * Register a new namespace. If @ns_uri is NULL it unregisters 5114 * the namespace 5115 * 5116 * Returns 0 in case of success, -1 in case of error 5117 */ 5118 int 5119 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix, 5120 const xmlChar *ns_uri) { 5121 if (ctxt == NULL) 5122 return(-1); 5123 if (prefix == NULL) 5124 return(-1); 5125 if (prefix[0] == 0) 5126 return(-1); 5127 5128 if (ctxt->nsHash == NULL) 5129 ctxt->nsHash = xmlHashCreate(10); 5130 if (ctxt->nsHash == NULL) 5131 return(-1); 5132 if (ns_uri == NULL) 5133 return(xmlHashRemoveEntry(ctxt->nsHash, prefix, 5134 xmlHashDefaultDeallocator)); 5135 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri), 5136 xmlHashDefaultDeallocator)); 5137 } 5138 5139 /** 5140 * xmlXPathNsLookup: 5141 * @ctxt: the XPath context 5142 * @prefix: the namespace prefix value 5143 * 5144 * Search in the namespace declaration array of the context for the given 5145 * namespace name associated to the given prefix 5146 * 5147 * Returns the value or NULL if not found 5148 */ 5149 const xmlChar * 5150 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) { 5151 if (ctxt == NULL) 5152 return(NULL); 5153 if (prefix == NULL) 5154 return(NULL); 5155 5156 #ifdef XML_XML_NAMESPACE 5157 if (xmlStrEqual(prefix, (const xmlChar *) "xml")) 5158 return(XML_XML_NAMESPACE); 5159 #endif 5160 5161 if (ctxt->namespaces != NULL) { 5162 int i; 5163 5164 for (i = 0;i < ctxt->nsNr;i++) { 5165 if ((ctxt->namespaces[i] != NULL) && 5166 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix))) 5167 return(ctxt->namespaces[i]->href); 5168 } 5169 } 5170 5171 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix)); 5172 } 5173 5174 /** 5175 * xmlXPathRegisteredNsCleanup: 5176 * @ctxt: the XPath context 5177 * 5178 * Cleanup the XPath context data associated to registered variables 5179 */ 5180 void 5181 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) { 5182 if (ctxt == NULL) 5183 return; 5184 5185 xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator); 5186 ctxt->nsHash = NULL; 5187 } 5188 5189 /************************************************************************ 5190 * * 5191 * Routines to handle Values * 5192 * * 5193 ************************************************************************/ 5194 5195 /* Allocations are terrible, one needs to optimize all this !!! */ 5196 5197 /** 5198 * xmlXPathNewFloat: 5199 * @val: the double value 5200 * 5201 * Create a new xmlXPathObjectPtr of type double and of value @val 5202 * 5203 * Returns the newly created object. 5204 */ 5205 xmlXPathObjectPtr 5206 xmlXPathNewFloat(double val) { 5207 xmlXPathObjectPtr ret; 5208 5209 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5210 if (ret == NULL) { 5211 xmlXPathErrMemory(NULL, "creating float object\n"); 5212 return(NULL); 5213 } 5214 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5215 ret->type = XPATH_NUMBER; 5216 ret->floatval = val; 5217 #ifdef XP_DEBUG_OBJ_USAGE 5218 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER); 5219 #endif 5220 return(ret); 5221 } 5222 5223 /** 5224 * xmlXPathNewBoolean: 5225 * @val: the boolean value 5226 * 5227 * Create a new xmlXPathObjectPtr of type boolean and of value @val 5228 * 5229 * Returns the newly created object. 5230 */ 5231 xmlXPathObjectPtr 5232 xmlXPathNewBoolean(int val) { 5233 xmlXPathObjectPtr ret; 5234 5235 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5236 if (ret == NULL) { 5237 xmlXPathErrMemory(NULL, "creating boolean object\n"); 5238 return(NULL); 5239 } 5240 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5241 ret->type = XPATH_BOOLEAN; 5242 ret->boolval = (val != 0); 5243 #ifdef XP_DEBUG_OBJ_USAGE 5244 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN); 5245 #endif 5246 return(ret); 5247 } 5248 5249 /** 5250 * xmlXPathNewString: 5251 * @val: the xmlChar * value 5252 * 5253 * Create a new xmlXPathObjectPtr of type string and of value @val 5254 * 5255 * Returns the newly created object. 5256 */ 5257 xmlXPathObjectPtr 5258 xmlXPathNewString(const xmlChar *val) { 5259 xmlXPathObjectPtr ret; 5260 5261 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5262 if (ret == NULL) { 5263 xmlXPathErrMemory(NULL, "creating string object\n"); 5264 return(NULL); 5265 } 5266 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5267 ret->type = XPATH_STRING; 5268 if (val != NULL) 5269 ret->stringval = xmlStrdup(val); 5270 else 5271 ret->stringval = xmlStrdup((const xmlChar *)""); 5272 #ifdef XP_DEBUG_OBJ_USAGE 5273 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); 5274 #endif 5275 return(ret); 5276 } 5277 5278 /** 5279 * xmlXPathWrapString: 5280 * @val: the xmlChar * value 5281 * 5282 * Wraps the @val string into an XPath object. 5283 * 5284 * Returns the newly created object. 5285 */ 5286 xmlXPathObjectPtr 5287 xmlXPathWrapString (xmlChar *val) { 5288 xmlXPathObjectPtr ret; 5289 5290 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5291 if (ret == NULL) { 5292 xmlXPathErrMemory(NULL, "creating string object\n"); 5293 return(NULL); 5294 } 5295 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5296 ret->type = XPATH_STRING; 5297 ret->stringval = val; 5298 #ifdef XP_DEBUG_OBJ_USAGE 5299 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); 5300 #endif 5301 return(ret); 5302 } 5303 5304 /** 5305 * xmlXPathNewCString: 5306 * @val: the char * value 5307 * 5308 * Create a new xmlXPathObjectPtr of type string and of value @val 5309 * 5310 * Returns the newly created object. 5311 */ 5312 xmlXPathObjectPtr 5313 xmlXPathNewCString(const char *val) { 5314 xmlXPathObjectPtr ret; 5315 5316 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5317 if (ret == NULL) { 5318 xmlXPathErrMemory(NULL, "creating string object\n"); 5319 return(NULL); 5320 } 5321 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5322 ret->type = XPATH_STRING; 5323 ret->stringval = xmlStrdup(BAD_CAST val); 5324 #ifdef XP_DEBUG_OBJ_USAGE 5325 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); 5326 #endif 5327 return(ret); 5328 } 5329 5330 /** 5331 * xmlXPathWrapCString: 5332 * @val: the char * value 5333 * 5334 * Wraps a string into an XPath object. 5335 * 5336 * Returns the newly created object. 5337 */ 5338 xmlXPathObjectPtr 5339 xmlXPathWrapCString (char * val) { 5340 return(xmlXPathWrapString((xmlChar *)(val))); 5341 } 5342 5343 /** 5344 * xmlXPathWrapExternal: 5345 * @val: the user data 5346 * 5347 * Wraps the @val data into an XPath object. 5348 * 5349 * Returns the newly created object. 5350 */ 5351 xmlXPathObjectPtr 5352 xmlXPathWrapExternal (void *val) { 5353 xmlXPathObjectPtr ret; 5354 5355 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5356 if (ret == NULL) { 5357 xmlXPathErrMemory(NULL, "creating user object\n"); 5358 return(NULL); 5359 } 5360 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5361 ret->type = XPATH_USERS; 5362 ret->user = val; 5363 #ifdef XP_DEBUG_OBJ_USAGE 5364 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS); 5365 #endif 5366 return(ret); 5367 } 5368 5369 /** 5370 * xmlXPathObjectCopy: 5371 * @val: the original object 5372 * 5373 * allocate a new copy of a given object 5374 * 5375 * Returns the newly created object. 5376 */ 5377 xmlXPathObjectPtr 5378 xmlXPathObjectCopy(xmlXPathObjectPtr val) { 5379 xmlXPathObjectPtr ret; 5380 5381 if (val == NULL) 5382 return(NULL); 5383 5384 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5385 if (ret == NULL) { 5386 xmlXPathErrMemory(NULL, "copying object\n"); 5387 return(NULL); 5388 } 5389 memcpy(ret, val , (size_t) sizeof(xmlXPathObject)); 5390 #ifdef XP_DEBUG_OBJ_USAGE 5391 xmlXPathDebugObjUsageRequested(NULL, val->type); 5392 #endif 5393 switch (val->type) { 5394 case XPATH_BOOLEAN: 5395 case XPATH_NUMBER: 5396 #ifdef LIBXML_XPTR_LOCS_ENABLED 5397 case XPATH_POINT: 5398 case XPATH_RANGE: 5399 #endif /* LIBXML_XPTR_LOCS_ENABLED */ 5400 break; 5401 case XPATH_STRING: 5402 ret->stringval = xmlStrdup(val->stringval); 5403 break; 5404 case XPATH_XSLT_TREE: 5405 #if 0 5406 /* 5407 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that 5408 this previous handling is no longer correct, and can cause some serious 5409 problems (ref. bug 145547) 5410 */ 5411 if ((val->nodesetval != NULL) && 5412 (val->nodesetval->nodeTab != NULL)) { 5413 xmlNodePtr cur, tmp; 5414 xmlDocPtr top; 5415 5416 ret->boolval = 1; 5417 top = xmlNewDoc(NULL); 5418 top->name = (char *) 5419 xmlStrdup(val->nodesetval->nodeTab[0]->name); 5420 ret->user = top; 5421 if (top != NULL) { 5422 top->doc = top; 5423 cur = val->nodesetval->nodeTab[0]->children; 5424 while (cur != NULL) { 5425 tmp = xmlDocCopyNode(cur, top, 1); 5426 xmlAddChild((xmlNodePtr) top, tmp); 5427 cur = cur->next; 5428 } 5429 } 5430 5431 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top); 5432 } else 5433 ret->nodesetval = xmlXPathNodeSetCreate(NULL); 5434 /* Deallocate the copied tree value */ 5435 break; 5436 #endif 5437 case XPATH_NODESET: 5438 /* TODO: Check memory error. */ 5439 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval); 5440 /* Do not deallocate the copied tree value */ 5441 ret->boolval = 0; 5442 break; 5443 #ifdef LIBXML_XPTR_LOCS_ENABLED 5444 case XPATH_LOCATIONSET: 5445 { 5446 xmlLocationSetPtr loc = val->user; 5447 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc); 5448 break; 5449 } 5450 #endif 5451 case XPATH_USERS: 5452 ret->user = val->user; 5453 break; 5454 case XPATH_UNDEFINED: 5455 xmlGenericError(xmlGenericErrorContext, 5456 "xmlXPathObjectCopy: unsupported type %d\n", 5457 val->type); 5458 break; 5459 } 5460 return(ret); 5461 } 5462 5463 /** 5464 * xmlXPathFreeObject: 5465 * @obj: the object to free 5466 * 5467 * Free up an xmlXPathObjectPtr object. 5468 */ 5469 void 5470 xmlXPathFreeObject(xmlXPathObjectPtr obj) { 5471 if (obj == NULL) return; 5472 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) { 5473 if (obj->boolval) { 5474 #if 0 5475 if (obj->user != NULL) { 5476 xmlXPathFreeNodeSet(obj->nodesetval); 5477 xmlFreeNodeList((xmlNodePtr) obj->user); 5478 } else 5479 #endif 5480 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */ 5481 if (obj->nodesetval != NULL) 5482 xmlXPathFreeValueTree(obj->nodesetval); 5483 } else { 5484 if (obj->nodesetval != NULL) 5485 xmlXPathFreeNodeSet(obj->nodesetval); 5486 } 5487 #ifdef LIBXML_XPTR_LOCS_ENABLED 5488 } else if (obj->type == XPATH_LOCATIONSET) { 5489 if (obj->user != NULL) 5490 xmlXPtrFreeLocationSet(obj->user); 5491 #endif 5492 } else if (obj->type == XPATH_STRING) { 5493 if (obj->stringval != NULL) 5494 xmlFree(obj->stringval); 5495 } 5496 #ifdef XP_DEBUG_OBJ_USAGE 5497 xmlXPathDebugObjUsageReleased(NULL, obj->type); 5498 #endif 5499 xmlFree(obj); 5500 } 5501 5502 static void 5503 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) { 5504 xmlXPathFreeObject((xmlXPathObjectPtr) obj); 5505 } 5506 5507 /** 5508 * xmlXPathReleaseObject: 5509 * @obj: the xmlXPathObjectPtr to free or to cache 5510 * 5511 * Depending on the state of the cache this frees the given 5512 * XPath object or stores it in the cache. 5513 */ 5514 static void 5515 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj) 5516 { 5517 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \ 5518 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \ 5519 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj; 5520 5521 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n)) 5522 5523 if (obj == NULL) 5524 return; 5525 if ((ctxt == NULL) || (ctxt->cache == NULL)) { 5526 xmlXPathFreeObject(obj); 5527 } else { 5528 xmlXPathContextCachePtr cache = 5529 (xmlXPathContextCachePtr) ctxt->cache; 5530 5531 switch (obj->type) { 5532 case XPATH_NODESET: 5533 case XPATH_XSLT_TREE: 5534 if (obj->nodesetval != NULL) { 5535 if (obj->boolval) { 5536 /* 5537 * It looks like the @boolval is used for 5538 * evaluation if this an XSLT Result Tree Fragment. 5539 * TODO: Check if this assumption is correct. 5540 */ 5541 obj->type = XPATH_XSLT_TREE; /* just for debugging */ 5542 xmlXPathFreeValueTree(obj->nodesetval); 5543 obj->nodesetval = NULL; 5544 } else if ((obj->nodesetval->nodeMax <= 40) && 5545 (XP_CACHE_WANTS(cache->nodesetObjs, 5546 cache->maxNodeset))) 5547 { 5548 XP_CACHE_ADD(cache->nodesetObjs, obj); 5549 goto obj_cached; 5550 } else { 5551 xmlXPathFreeNodeSet(obj->nodesetval); 5552 obj->nodesetval = NULL; 5553 } 5554 } 5555 break; 5556 case XPATH_STRING: 5557 if (obj->stringval != NULL) 5558 xmlFree(obj->stringval); 5559 5560 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) { 5561 XP_CACHE_ADD(cache->stringObjs, obj); 5562 goto obj_cached; 5563 } 5564 break; 5565 case XPATH_BOOLEAN: 5566 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) { 5567 XP_CACHE_ADD(cache->booleanObjs, obj); 5568 goto obj_cached; 5569 } 5570 break; 5571 case XPATH_NUMBER: 5572 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) { 5573 XP_CACHE_ADD(cache->numberObjs, obj); 5574 goto obj_cached; 5575 } 5576 break; 5577 #ifdef LIBXML_XPTR_LOCS_ENABLED 5578 case XPATH_LOCATIONSET: 5579 if (obj->user != NULL) { 5580 xmlXPtrFreeLocationSet(obj->user); 5581 } 5582 goto free_obj; 5583 #endif 5584 default: 5585 goto free_obj; 5586 } 5587 5588 /* 5589 * Fallback to adding to the misc-objects slot. 5590 */ 5591 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) { 5592 XP_CACHE_ADD(cache->miscObjs, obj); 5593 } else 5594 goto free_obj; 5595 5596 obj_cached: 5597 5598 #ifdef XP_DEBUG_OBJ_USAGE 5599 xmlXPathDebugObjUsageReleased(ctxt, obj->type); 5600 #endif 5601 5602 if (obj->nodesetval != NULL) { 5603 xmlNodeSetPtr tmpset = obj->nodesetval; 5604 5605 /* 5606 * TODO: Due to those nasty ns-nodes, we need to traverse 5607 * the list and free the ns-nodes. 5608 * URGENT TODO: Check if it's actually slowing things down. 5609 * Maybe we shouldn't try to preserve the list. 5610 */ 5611 if (tmpset->nodeNr > 1) { 5612 int i; 5613 xmlNodePtr node; 5614 5615 for (i = 0; i < tmpset->nodeNr; i++) { 5616 node = tmpset->nodeTab[i]; 5617 if ((node != NULL) && 5618 (node->type == XML_NAMESPACE_DECL)) 5619 { 5620 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 5621 } 5622 } 5623 } else if (tmpset->nodeNr == 1) { 5624 if ((tmpset->nodeTab[0] != NULL) && 5625 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL)) 5626 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]); 5627 } 5628 tmpset->nodeNr = 0; 5629 memset(obj, 0, sizeof(xmlXPathObject)); 5630 obj->nodesetval = tmpset; 5631 } else 5632 memset(obj, 0, sizeof(xmlXPathObject)); 5633 5634 return; 5635 5636 free_obj: 5637 /* 5638 * Cache is full; free the object. 5639 */ 5640 if (obj->nodesetval != NULL) 5641 xmlXPathFreeNodeSet(obj->nodesetval); 5642 #ifdef XP_DEBUG_OBJ_USAGE 5643 xmlXPathDebugObjUsageReleased(NULL, obj->type); 5644 #endif 5645 xmlFree(obj); 5646 } 5647 return; 5648 } 5649 5650 5651 /************************************************************************ 5652 * * 5653 * Type Casting Routines * 5654 * * 5655 ************************************************************************/ 5656 5657 /** 5658 * xmlXPathCastBooleanToString: 5659 * @val: a boolean 5660 * 5661 * Converts a boolean to its string value. 5662 * 5663 * Returns a newly allocated string. 5664 */ 5665 xmlChar * 5666 xmlXPathCastBooleanToString (int val) { 5667 xmlChar *ret; 5668 if (val) 5669 ret = xmlStrdup((const xmlChar *) "true"); 5670 else 5671 ret = xmlStrdup((const xmlChar *) "false"); 5672 return(ret); 5673 } 5674 5675 /** 5676 * xmlXPathCastNumberToString: 5677 * @val: a number 5678 * 5679 * Converts a number to its string value. 5680 * 5681 * Returns a newly allocated string. 5682 */ 5683 xmlChar * 5684 xmlXPathCastNumberToString (double val) { 5685 xmlChar *ret; 5686 switch (xmlXPathIsInf(val)) { 5687 case 1: 5688 ret = xmlStrdup((const xmlChar *) "Infinity"); 5689 break; 5690 case -1: 5691 ret = xmlStrdup((const xmlChar *) "-Infinity"); 5692 break; 5693 default: 5694 if (xmlXPathIsNaN(val)) { 5695 ret = xmlStrdup((const xmlChar *) "NaN"); 5696 } else if (val == 0) { 5697 /* Omit sign for negative zero. */ 5698 ret = xmlStrdup((const xmlChar *) "0"); 5699 } else { 5700 /* could be improved */ 5701 char buf[100]; 5702 xmlXPathFormatNumber(val, buf, 99); 5703 buf[99] = 0; 5704 ret = xmlStrdup((const xmlChar *) buf); 5705 } 5706 } 5707 return(ret); 5708 } 5709 5710 /** 5711 * xmlXPathCastNodeToString: 5712 * @node: a node 5713 * 5714 * Converts a node to its string value. 5715 * 5716 * Returns a newly allocated string. 5717 */ 5718 xmlChar * 5719 xmlXPathCastNodeToString (xmlNodePtr node) { 5720 xmlChar *ret; 5721 if ((ret = xmlNodeGetContent(node)) == NULL) 5722 ret = xmlStrdup((const xmlChar *) ""); 5723 return(ret); 5724 } 5725 5726 /** 5727 * xmlXPathCastNodeSetToString: 5728 * @ns: a node-set 5729 * 5730 * Converts a node-set to its string value. 5731 * 5732 * Returns a newly allocated string. 5733 */ 5734 xmlChar * 5735 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) { 5736 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL)) 5737 return(xmlStrdup((const xmlChar *) "")); 5738 5739 if (ns->nodeNr > 1) 5740 xmlXPathNodeSetSort(ns); 5741 return(xmlXPathCastNodeToString(ns->nodeTab[0])); 5742 } 5743 5744 /** 5745 * xmlXPathCastToString: 5746 * @val: an XPath object 5747 * 5748 * Converts an existing object to its string() equivalent 5749 * 5750 * Returns the allocated string value of the object, NULL in case of error. 5751 * It's up to the caller to free the string memory with xmlFree(). 5752 */ 5753 xmlChar * 5754 xmlXPathCastToString(xmlXPathObjectPtr val) { 5755 xmlChar *ret = NULL; 5756 5757 if (val == NULL) 5758 return(xmlStrdup((const xmlChar *) "")); 5759 switch (val->type) { 5760 case XPATH_UNDEFINED: 5761 #ifdef DEBUG_EXPR 5762 xmlGenericError(xmlGenericErrorContext, "String: undefined\n"); 5763 #endif 5764 ret = xmlStrdup((const xmlChar *) ""); 5765 break; 5766 case XPATH_NODESET: 5767 case XPATH_XSLT_TREE: 5768 ret = xmlXPathCastNodeSetToString(val->nodesetval); 5769 break; 5770 case XPATH_STRING: 5771 return(xmlStrdup(val->stringval)); 5772 case XPATH_BOOLEAN: 5773 ret = xmlXPathCastBooleanToString(val->boolval); 5774 break; 5775 case XPATH_NUMBER: { 5776 ret = xmlXPathCastNumberToString(val->floatval); 5777 break; 5778 } 5779 case XPATH_USERS: 5780 #ifdef LIBXML_XPTR_LOCS_ENABLED 5781 case XPATH_POINT: 5782 case XPATH_RANGE: 5783 case XPATH_LOCATIONSET: 5784 #endif /* LIBXML_XPTR_LOCS_ENABLED */ 5785 TODO 5786 ret = xmlStrdup((const xmlChar *) ""); 5787 break; 5788 } 5789 return(ret); 5790 } 5791 5792 /** 5793 * xmlXPathConvertString: 5794 * @val: an XPath object 5795 * 5796 * Converts an existing object to its string() equivalent 5797 * 5798 * Returns the new object, the old one is freed (or the operation 5799 * is done directly on @val) 5800 */ 5801 xmlXPathObjectPtr 5802 xmlXPathConvertString(xmlXPathObjectPtr val) { 5803 xmlChar *res = NULL; 5804 5805 if (val == NULL) 5806 return(xmlXPathNewCString("")); 5807 5808 switch (val->type) { 5809 case XPATH_UNDEFINED: 5810 #ifdef DEBUG_EXPR 5811 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n"); 5812 #endif 5813 break; 5814 case XPATH_NODESET: 5815 case XPATH_XSLT_TREE: 5816 res = xmlXPathCastNodeSetToString(val->nodesetval); 5817 break; 5818 case XPATH_STRING: 5819 return(val); 5820 case XPATH_BOOLEAN: 5821 res = xmlXPathCastBooleanToString(val->boolval); 5822 break; 5823 case XPATH_NUMBER: 5824 res = xmlXPathCastNumberToString(val->floatval); 5825 break; 5826 case XPATH_USERS: 5827 #ifdef LIBXML_XPTR_LOCS_ENABLED 5828 case XPATH_POINT: 5829 case XPATH_RANGE: 5830 case XPATH_LOCATIONSET: 5831 #endif /* LIBXML_XPTR_LOCS_ENABLED */ 5832 TODO; 5833 break; 5834 } 5835 xmlXPathFreeObject(val); 5836 if (res == NULL) 5837 return(xmlXPathNewCString("")); 5838 return(xmlXPathWrapString(res)); 5839 } 5840 5841 /** 5842 * xmlXPathCastBooleanToNumber: 5843 * @val: a boolean 5844 * 5845 * Converts a boolean to its number value 5846 * 5847 * Returns the number value 5848 */ 5849 double 5850 xmlXPathCastBooleanToNumber(int val) { 5851 if (val) 5852 return(1.0); 5853 return(0.0); 5854 } 5855 5856 /** 5857 * xmlXPathCastStringToNumber: 5858 * @val: a string 5859 * 5860 * Converts a string to its number value 5861 * 5862 * Returns the number value 5863 */ 5864 double 5865 xmlXPathCastStringToNumber(const xmlChar * val) { 5866 return(xmlXPathStringEvalNumber(val)); 5867 } 5868 5869 /** 5870 * xmlXPathCastNodeToNumber: 5871 * @node: a node 5872 * 5873 * Converts a node to its number value 5874 * 5875 * Returns the number value 5876 */ 5877 double 5878 xmlXPathCastNodeToNumber (xmlNodePtr node) { 5879 xmlChar *strval; 5880 double ret; 5881 5882 if (node == NULL) 5883 return(xmlXPathNAN); 5884 strval = xmlXPathCastNodeToString(node); 5885 if (strval == NULL) 5886 return(xmlXPathNAN); 5887 ret = xmlXPathCastStringToNumber(strval); 5888 xmlFree(strval); 5889 5890 return(ret); 5891 } 5892 5893 /** 5894 * xmlXPathCastNodeSetToNumber: 5895 * @ns: a node-set 5896 * 5897 * Converts a node-set to its number value 5898 * 5899 * Returns the number value 5900 */ 5901 double 5902 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) { 5903 xmlChar *str; 5904 double ret; 5905 5906 if (ns == NULL) 5907 return(xmlXPathNAN); 5908 str = xmlXPathCastNodeSetToString(ns); 5909 ret = xmlXPathCastStringToNumber(str); 5910 xmlFree(str); 5911 return(ret); 5912 } 5913 5914 /** 5915 * xmlXPathCastToNumber: 5916 * @val: an XPath object 5917 * 5918 * Converts an XPath object to its number value 5919 * 5920 * Returns the number value 5921 */ 5922 double 5923 xmlXPathCastToNumber(xmlXPathObjectPtr val) { 5924 double ret = 0.0; 5925 5926 if (val == NULL) 5927 return(xmlXPathNAN); 5928 switch (val->type) { 5929 case XPATH_UNDEFINED: 5930 #ifdef DEBUG_EXPR 5931 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n"); 5932 #endif 5933 ret = xmlXPathNAN; 5934 break; 5935 case XPATH_NODESET: 5936 case XPATH_XSLT_TREE: 5937 ret = xmlXPathCastNodeSetToNumber(val->nodesetval); 5938 break; 5939 case XPATH_STRING: 5940 ret = xmlXPathCastStringToNumber(val->stringval); 5941 break; 5942 case XPATH_NUMBER: 5943 ret = val->floatval; 5944 break; 5945 case XPATH_BOOLEAN: 5946 ret = xmlXPathCastBooleanToNumber(val->boolval); 5947 break; 5948 case XPATH_USERS: 5949 #ifdef LIBXML_XPTR_LOCS_ENABLED 5950 case XPATH_POINT: 5951 case XPATH_RANGE: 5952 case XPATH_LOCATIONSET: 5953 #endif /* LIBXML_XPTR_LOCS_ENABLED */ 5954 TODO; 5955 ret = xmlXPathNAN; 5956 break; 5957 } 5958 return(ret); 5959 } 5960 5961 /** 5962 * xmlXPathConvertNumber: 5963 * @val: an XPath object 5964 * 5965 * Converts an existing object to its number() equivalent 5966 * 5967 * Returns the new object, the old one is freed (or the operation 5968 * is done directly on @val) 5969 */ 5970 xmlXPathObjectPtr 5971 xmlXPathConvertNumber(xmlXPathObjectPtr val) { 5972 xmlXPathObjectPtr ret; 5973 5974 if (val == NULL) 5975 return(xmlXPathNewFloat(0.0)); 5976 if (val->type == XPATH_NUMBER) 5977 return(val); 5978 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val)); 5979 xmlXPathFreeObject(val); 5980 return(ret); 5981 } 5982 5983 /** 5984 * xmlXPathCastNumberToBoolean: 5985 * @val: a number 5986 * 5987 * Converts a number to its boolean value 5988 * 5989 * Returns the boolean value 5990 */ 5991 int 5992 xmlXPathCastNumberToBoolean (double val) { 5993 if (xmlXPathIsNaN(val) || (val == 0.0)) 5994 return(0); 5995 return(1); 5996 } 5997 5998 /** 5999 * xmlXPathCastStringToBoolean: 6000 * @val: a string 6001 * 6002 * Converts a string to its boolean value 6003 * 6004 * Returns the boolean value 6005 */ 6006 int 6007 xmlXPathCastStringToBoolean (const xmlChar *val) { 6008 if ((val == NULL) || (xmlStrlen(val) == 0)) 6009 return(0); 6010 return(1); 6011 } 6012 6013 /** 6014 * xmlXPathCastNodeSetToBoolean: 6015 * @ns: a node-set 6016 * 6017 * Converts a node-set to its boolean value 6018 * 6019 * Returns the boolean value 6020 */ 6021 int 6022 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) { 6023 if ((ns == NULL) || (ns->nodeNr == 0)) 6024 return(0); 6025 return(1); 6026 } 6027 6028 /** 6029 * xmlXPathCastToBoolean: 6030 * @val: an XPath object 6031 * 6032 * Converts an XPath object to its boolean value 6033 * 6034 * Returns the boolean value 6035 */ 6036 int 6037 xmlXPathCastToBoolean (xmlXPathObjectPtr val) { 6038 int ret = 0; 6039 6040 if (val == NULL) 6041 return(0); 6042 switch (val->type) { 6043 case XPATH_UNDEFINED: 6044 #ifdef DEBUG_EXPR 6045 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n"); 6046 #endif 6047 ret = 0; 6048 break; 6049 case XPATH_NODESET: 6050 case XPATH_XSLT_TREE: 6051 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval); 6052 break; 6053 case XPATH_STRING: 6054 ret = xmlXPathCastStringToBoolean(val->stringval); 6055 break; 6056 case XPATH_NUMBER: 6057 ret = xmlXPathCastNumberToBoolean(val->floatval); 6058 break; 6059 case XPATH_BOOLEAN: 6060 ret = val->boolval; 6061 break; 6062 case XPATH_USERS: 6063 #ifdef LIBXML_XPTR_LOCS_ENABLED 6064 case XPATH_POINT: 6065 case XPATH_RANGE: 6066 case XPATH_LOCATIONSET: 6067 #endif /* LIBXML_XPTR_LOCS_ENABLED */ 6068 TODO; 6069 ret = 0; 6070 break; 6071 } 6072 return(ret); 6073 } 6074 6075 6076 /** 6077 * xmlXPathConvertBoolean: 6078 * @val: an XPath object 6079 * 6080 * Converts an existing object to its boolean() equivalent 6081 * 6082 * Returns the new object, the old one is freed (or the operation 6083 * is done directly on @val) 6084 */ 6085 xmlXPathObjectPtr 6086 xmlXPathConvertBoolean(xmlXPathObjectPtr val) { 6087 xmlXPathObjectPtr ret; 6088 6089 if (val == NULL) 6090 return(xmlXPathNewBoolean(0)); 6091 if (val->type == XPATH_BOOLEAN) 6092 return(val); 6093 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val)); 6094 xmlXPathFreeObject(val); 6095 return(ret); 6096 } 6097 6098 /************************************************************************ 6099 * * 6100 * Routines to handle XPath contexts * 6101 * * 6102 ************************************************************************/ 6103 6104 /** 6105 * xmlXPathNewContext: 6106 * @doc: the XML document 6107 * 6108 * Create a new xmlXPathContext 6109 * 6110 * Returns the xmlXPathContext just allocated. The caller will need to free it. 6111 */ 6112 xmlXPathContextPtr 6113 xmlXPathNewContext(xmlDocPtr doc) { 6114 xmlXPathContextPtr ret; 6115 6116 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext)); 6117 if (ret == NULL) { 6118 xmlXPathErrMemory(NULL, "creating context\n"); 6119 return(NULL); 6120 } 6121 memset(ret, 0 , (size_t) sizeof(xmlXPathContext)); 6122 ret->doc = doc; 6123 ret->node = NULL; 6124 6125 ret->varHash = NULL; 6126 6127 ret->nb_types = 0; 6128 ret->max_types = 0; 6129 ret->types = NULL; 6130 6131 ret->funcHash = xmlHashCreate(0); 6132 6133 ret->nb_axis = 0; 6134 ret->max_axis = 0; 6135 ret->axis = NULL; 6136 6137 ret->nsHash = NULL; 6138 ret->user = NULL; 6139 6140 ret->contextSize = -1; 6141 ret->proximityPosition = -1; 6142 6143 #ifdef XP_DEFAULT_CACHE_ON 6144 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) { 6145 xmlXPathFreeContext(ret); 6146 return(NULL); 6147 } 6148 #endif 6149 6150 xmlXPathRegisterAllFunctions(ret); 6151 6152 return(ret); 6153 } 6154 6155 /** 6156 * xmlXPathFreeContext: 6157 * @ctxt: the context to free 6158 * 6159 * Free up an xmlXPathContext 6160 */ 6161 void 6162 xmlXPathFreeContext(xmlXPathContextPtr ctxt) { 6163 if (ctxt == NULL) return; 6164 6165 if (ctxt->cache != NULL) 6166 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache); 6167 xmlXPathRegisteredNsCleanup(ctxt); 6168 xmlXPathRegisteredFuncsCleanup(ctxt); 6169 xmlXPathRegisteredVariablesCleanup(ctxt); 6170 xmlResetError(&ctxt->lastError); 6171 xmlFree(ctxt); 6172 } 6173 6174 /************************************************************************ 6175 * * 6176 * Routines to handle XPath parser contexts * 6177 * * 6178 ************************************************************************/ 6179 6180 #define CHECK_CTXT(ctxt) \ 6181 if (ctxt == NULL) { \ 6182 __xmlRaiseError(NULL, NULL, NULL, \ 6183 NULL, NULL, XML_FROM_XPATH, \ 6184 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \ 6185 __FILE__, __LINE__, \ 6186 NULL, NULL, NULL, 0, 0, \ 6187 "NULL context pointer\n"); \ 6188 return(NULL); \ 6189 } \ 6190 6191 #define CHECK_CTXT_NEG(ctxt) \ 6192 if (ctxt == NULL) { \ 6193 __xmlRaiseError(NULL, NULL, NULL, \ 6194 NULL, NULL, XML_FROM_XPATH, \ 6195 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \ 6196 __FILE__, __LINE__, \ 6197 NULL, NULL, NULL, 0, 0, \ 6198 "NULL context pointer\n"); \ 6199 return(-1); \ 6200 } \ 6201 6202 6203 #define CHECK_CONTEXT(ctxt) \ 6204 if ((ctxt == NULL) || (ctxt->doc == NULL) || \ 6205 (ctxt->doc->children == NULL)) { \ 6206 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \ 6207 return(NULL); \ 6208 } 6209 6210 6211 /** 6212 * xmlXPathNewParserContext: 6213 * @str: the XPath expression 6214 * @ctxt: the XPath context 6215 * 6216 * Create a new xmlXPathParserContext 6217 * 6218 * Returns the xmlXPathParserContext just allocated. 6219 */ 6220 xmlXPathParserContextPtr 6221 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) { 6222 xmlXPathParserContextPtr ret; 6223 6224 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext)); 6225 if (ret == NULL) { 6226 xmlXPathErrMemory(ctxt, "creating parser context\n"); 6227 return(NULL); 6228 } 6229 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext)); 6230 ret->cur = ret->base = str; 6231 ret->context = ctxt; 6232 6233 ret->comp = xmlXPathNewCompExpr(); 6234 if (ret->comp == NULL) { 6235 xmlFree(ret->valueTab); 6236 xmlFree(ret); 6237 return(NULL); 6238 } 6239 if ((ctxt != NULL) && (ctxt->dict != NULL)) { 6240 ret->comp->dict = ctxt->dict; 6241 xmlDictReference(ret->comp->dict); 6242 } 6243 6244 return(ret); 6245 } 6246 6247 /** 6248 * xmlXPathCompParserContext: 6249 * @comp: the XPath compiled expression 6250 * @ctxt: the XPath context 6251 * 6252 * Create a new xmlXPathParserContext when processing a compiled expression 6253 * 6254 * Returns the xmlXPathParserContext just allocated. 6255 */ 6256 static xmlXPathParserContextPtr 6257 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) { 6258 xmlXPathParserContextPtr ret; 6259 6260 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext)); 6261 if (ret == NULL) { 6262 xmlXPathErrMemory(ctxt, "creating evaluation context\n"); 6263 return(NULL); 6264 } 6265 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext)); 6266 6267 /* Allocate the value stack */ 6268 ret->valueTab = (xmlXPathObjectPtr *) 6269 xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); 6270 if (ret->valueTab == NULL) { 6271 xmlFree(ret); 6272 xmlXPathErrMemory(ctxt, "creating evaluation context\n"); 6273 return(NULL); 6274 } 6275 ret->valueNr = 0; 6276 ret->valueMax = 10; 6277 ret->value = NULL; 6278 ret->valueFrame = 0; 6279 6280 ret->context = ctxt; 6281 ret->comp = comp; 6282 6283 return(ret); 6284 } 6285 6286 /** 6287 * xmlXPathFreeParserContext: 6288 * @ctxt: the context to free 6289 * 6290 * Free up an xmlXPathParserContext 6291 */ 6292 void 6293 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) { 6294 int i; 6295 6296 if (ctxt->valueTab != NULL) { 6297 for (i = 0; i < ctxt->valueNr; i++) { 6298 if (ctxt->context) 6299 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]); 6300 else 6301 xmlXPathFreeObject(ctxt->valueTab[i]); 6302 } 6303 xmlFree(ctxt->valueTab); 6304 } 6305 if (ctxt->comp != NULL) { 6306 #ifdef XPATH_STREAMING 6307 if (ctxt->comp->stream != NULL) { 6308 xmlFreePatternList(ctxt->comp->stream); 6309 ctxt->comp->stream = NULL; 6310 } 6311 #endif 6312 xmlXPathFreeCompExpr(ctxt->comp); 6313 } 6314 xmlFree(ctxt); 6315 } 6316 6317 /************************************************************************ 6318 * * 6319 * The implicit core function library * 6320 * * 6321 ************************************************************************/ 6322 6323 /** 6324 * xmlXPathNodeValHash: 6325 * @node: a node pointer 6326 * 6327 * Function computing the beginning of the string value of the node, 6328 * used to speed up comparisons 6329 * 6330 * Returns an int usable as a hash 6331 */ 6332 static unsigned int 6333 xmlXPathNodeValHash(xmlNodePtr node) { 6334 int len = 2; 6335 const xmlChar * string = NULL; 6336 xmlNodePtr tmp = NULL; 6337 unsigned int ret = 0; 6338 6339 if (node == NULL) 6340 return(0); 6341 6342 if (node->type == XML_DOCUMENT_NODE) { 6343 tmp = xmlDocGetRootElement((xmlDocPtr) node); 6344 if (tmp == NULL) 6345 node = node->children; 6346 else 6347 node = tmp; 6348 6349 if (node == NULL) 6350 return(0); 6351 } 6352 6353 switch (node->type) { 6354 case XML_COMMENT_NODE: 6355 case XML_PI_NODE: 6356 case XML_CDATA_SECTION_NODE: 6357 case XML_TEXT_NODE: 6358 string = node->content; 6359 if (string == NULL) 6360 return(0); 6361 if (string[0] == 0) 6362 return(0); 6363 return(((unsigned int) string[0]) + 6364 (((unsigned int) string[1]) << 8)); 6365 case XML_NAMESPACE_DECL: 6366 string = ((xmlNsPtr)node)->href; 6367 if (string == NULL) 6368 return(0); 6369 if (string[0] == 0) 6370 return(0); 6371 return(((unsigned int) string[0]) + 6372 (((unsigned int) string[1]) << 8)); 6373 case XML_ATTRIBUTE_NODE: 6374 tmp = ((xmlAttrPtr) node)->children; 6375 break; 6376 case XML_ELEMENT_NODE: 6377 tmp = node->children; 6378 break; 6379 default: 6380 return(0); 6381 } 6382 while (tmp != NULL) { 6383 switch (tmp->type) { 6384 case XML_CDATA_SECTION_NODE: 6385 case XML_TEXT_NODE: 6386 string = tmp->content; 6387 break; 6388 default: 6389 string = NULL; 6390 break; 6391 } 6392 if ((string != NULL) && (string[0] != 0)) { 6393 if (len == 1) { 6394 return(ret + (((unsigned int) string[0]) << 8)); 6395 } 6396 if (string[1] == 0) { 6397 len = 1; 6398 ret = (unsigned int) string[0]; 6399 } else { 6400 return(((unsigned int) string[0]) + 6401 (((unsigned int) string[1]) << 8)); 6402 } 6403 } 6404 /* 6405 * Skip to next node 6406 */ 6407 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) { 6408 if (tmp->children->type != XML_ENTITY_DECL) { 6409 tmp = tmp->children; 6410 continue; 6411 } 6412 } 6413 if (tmp == node) 6414 break; 6415 6416 if (tmp->next != NULL) { 6417 tmp = tmp->next; 6418 continue; 6419 } 6420 6421 do { 6422 tmp = tmp->parent; 6423 if (tmp == NULL) 6424 break; 6425 if (tmp == node) { 6426 tmp = NULL; 6427 break; 6428 } 6429 if (tmp->next != NULL) { 6430 tmp = tmp->next; 6431 break; 6432 } 6433 } while (tmp != NULL); 6434 } 6435 return(ret); 6436 } 6437 6438 /** 6439 * xmlXPathStringHash: 6440 * @string: a string 6441 * 6442 * Function computing the beginning of the string value of the node, 6443 * used to speed up comparisons 6444 * 6445 * Returns an int usable as a hash 6446 */ 6447 static unsigned int 6448 xmlXPathStringHash(const xmlChar * string) { 6449 if (string == NULL) 6450 return((unsigned int) 0); 6451 if (string[0] == 0) 6452 return(0); 6453 return(((unsigned int) string[0]) + 6454 (((unsigned int) string[1]) << 8)); 6455 } 6456 6457 /** 6458 * xmlXPathCompareNodeSetFloat: 6459 * @ctxt: the XPath Parser context 6460 * @inf: less than (1) or greater than (0) 6461 * @strict: is the comparison strict 6462 * @arg: the node set 6463 * @f: the value 6464 * 6465 * Implement the compare operation between a nodeset and a number 6466 * @ns < @val (1, 1, ... 6467 * @ns <= @val (1, 0, ... 6468 * @ns > @val (0, 1, ... 6469 * @ns >= @val (0, 0, ... 6470 * 6471 * If one object to be compared is a node-set and the other is a number, 6472 * then the comparison will be true if and only if there is a node in the 6473 * node-set such that the result of performing the comparison on the number 6474 * to be compared and on the result of converting the string-value of that 6475 * node to a number using the number function is true. 6476 * 6477 * Returns 0 or 1 depending on the results of the test. 6478 */ 6479 static int 6480 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict, 6481 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) { 6482 int i, ret = 0; 6483 xmlNodeSetPtr ns; 6484 xmlChar *str2; 6485 6486 if ((f == NULL) || (arg == NULL) || 6487 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) { 6488 xmlXPathReleaseObject(ctxt->context, arg); 6489 xmlXPathReleaseObject(ctxt->context, f); 6490 return(0); 6491 } 6492 ns = arg->nodesetval; 6493 if (ns != NULL) { 6494 for (i = 0;i < ns->nodeNr;i++) { 6495 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 6496 if (str2 != NULL) { 6497 valuePush(ctxt, 6498 xmlXPathCacheNewString(ctxt->context, str2)); 6499 xmlFree(str2); 6500 xmlXPathNumberFunction(ctxt, 1); 6501 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f)); 6502 ret = xmlXPathCompareValues(ctxt, inf, strict); 6503 if (ret) 6504 break; 6505 } 6506 } 6507 } 6508 xmlXPathReleaseObject(ctxt->context, arg); 6509 xmlXPathReleaseObject(ctxt->context, f); 6510 return(ret); 6511 } 6512 6513 /** 6514 * xmlXPathCompareNodeSetString: 6515 * @ctxt: the XPath Parser context 6516 * @inf: less than (1) or greater than (0) 6517 * @strict: is the comparison strict 6518 * @arg: the node set 6519 * @s: the value 6520 * 6521 * Implement the compare operation between a nodeset and a string 6522 * @ns < @val (1, 1, ... 6523 * @ns <= @val (1, 0, ... 6524 * @ns > @val (0, 1, ... 6525 * @ns >= @val (0, 0, ... 6526 * 6527 * If one object to be compared is a node-set and the other is a string, 6528 * then the comparison will be true if and only if there is a node in 6529 * the node-set such that the result of performing the comparison on the 6530 * string-value of the node and the other string is true. 6531 * 6532 * Returns 0 or 1 depending on the results of the test. 6533 */ 6534 static int 6535 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict, 6536 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) { 6537 int i, ret = 0; 6538 xmlNodeSetPtr ns; 6539 xmlChar *str2; 6540 6541 if ((s == NULL) || (arg == NULL) || 6542 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) { 6543 xmlXPathReleaseObject(ctxt->context, arg); 6544 xmlXPathReleaseObject(ctxt->context, s); 6545 return(0); 6546 } 6547 ns = arg->nodesetval; 6548 if (ns != NULL) { 6549 for (i = 0;i < ns->nodeNr;i++) { 6550 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 6551 if (str2 != NULL) { 6552 valuePush(ctxt, 6553 xmlXPathCacheNewString(ctxt->context, str2)); 6554 xmlFree(str2); 6555 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s)); 6556 ret = xmlXPathCompareValues(ctxt, inf, strict); 6557 if (ret) 6558 break; 6559 } 6560 } 6561 } 6562 xmlXPathReleaseObject(ctxt->context, arg); 6563 xmlXPathReleaseObject(ctxt->context, s); 6564 return(ret); 6565 } 6566 6567 /** 6568 * xmlXPathCompareNodeSets: 6569 * @inf: less than (1) or greater than (0) 6570 * @strict: is the comparison strict 6571 * @arg1: the first node set object 6572 * @arg2: the second node set object 6573 * 6574 * Implement the compare operation on nodesets: 6575 * 6576 * If both objects to be compared are node-sets, then the comparison 6577 * will be true if and only if there is a node in the first node-set 6578 * and a node in the second node-set such that the result of performing 6579 * the comparison on the string-values of the two nodes is true. 6580 * .... 6581 * When neither object to be compared is a node-set and the operator 6582 * is <=, <, >= or >, then the objects are compared by converting both 6583 * objects to numbers and comparing the numbers according to IEEE 754. 6584 * .... 6585 * The number function converts its argument to a number as follows: 6586 * - a string that consists of optional whitespace followed by an 6587 * optional minus sign followed by a Number followed by whitespace 6588 * is converted to the IEEE 754 number that is nearest (according 6589 * to the IEEE 754 round-to-nearest rule) to the mathematical value 6590 * represented by the string; any other string is converted to NaN 6591 * 6592 * Conclusion all nodes need to be converted first to their string value 6593 * and then the comparison must be done when possible 6594 */ 6595 static int 6596 xmlXPathCompareNodeSets(int inf, int strict, 6597 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) { 6598 int i, j, init = 0; 6599 double val1; 6600 double *values2; 6601 int ret = 0; 6602 xmlNodeSetPtr ns1; 6603 xmlNodeSetPtr ns2; 6604 6605 if ((arg1 == NULL) || 6606 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) { 6607 xmlXPathFreeObject(arg2); 6608 return(0); 6609 } 6610 if ((arg2 == NULL) || 6611 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) { 6612 xmlXPathFreeObject(arg1); 6613 xmlXPathFreeObject(arg2); 6614 return(0); 6615 } 6616 6617 ns1 = arg1->nodesetval; 6618 ns2 = arg2->nodesetval; 6619 6620 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) { 6621 xmlXPathFreeObject(arg1); 6622 xmlXPathFreeObject(arg2); 6623 return(0); 6624 } 6625 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) { 6626 xmlXPathFreeObject(arg1); 6627 xmlXPathFreeObject(arg2); 6628 return(0); 6629 } 6630 6631 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double)); 6632 if (values2 == NULL) { 6633 /* TODO: Propagate memory error. */ 6634 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6635 xmlXPathFreeObject(arg1); 6636 xmlXPathFreeObject(arg2); 6637 return(0); 6638 } 6639 for (i = 0;i < ns1->nodeNr;i++) { 6640 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]); 6641 if (xmlXPathIsNaN(val1)) 6642 continue; 6643 for (j = 0;j < ns2->nodeNr;j++) { 6644 if (init == 0) { 6645 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]); 6646 } 6647 if (xmlXPathIsNaN(values2[j])) 6648 continue; 6649 if (inf && strict) 6650 ret = (val1 < values2[j]); 6651 else if (inf && !strict) 6652 ret = (val1 <= values2[j]); 6653 else if (!inf && strict) 6654 ret = (val1 > values2[j]); 6655 else if (!inf && !strict) 6656 ret = (val1 >= values2[j]); 6657 if (ret) 6658 break; 6659 } 6660 if (ret) 6661 break; 6662 init = 1; 6663 } 6664 xmlFree(values2); 6665 xmlXPathFreeObject(arg1); 6666 xmlXPathFreeObject(arg2); 6667 return(ret); 6668 } 6669 6670 /** 6671 * xmlXPathCompareNodeSetValue: 6672 * @ctxt: the XPath Parser context 6673 * @inf: less than (1) or greater than (0) 6674 * @strict: is the comparison strict 6675 * @arg: the node set 6676 * @val: the value 6677 * 6678 * Implement the compare operation between a nodeset and a value 6679 * @ns < @val (1, 1, ... 6680 * @ns <= @val (1, 0, ... 6681 * @ns > @val (0, 1, ... 6682 * @ns >= @val (0, 0, ... 6683 * 6684 * If one object to be compared is a node-set and the other is a boolean, 6685 * then the comparison will be true if and only if the result of performing 6686 * the comparison on the boolean and on the result of converting 6687 * the node-set to a boolean using the boolean function is true. 6688 * 6689 * Returns 0 or 1 depending on the results of the test. 6690 */ 6691 static int 6692 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict, 6693 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) { 6694 if ((val == NULL) || (arg == NULL) || 6695 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 6696 return(0); 6697 6698 switch(val->type) { 6699 case XPATH_NUMBER: 6700 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val)); 6701 case XPATH_NODESET: 6702 case XPATH_XSLT_TREE: 6703 return(xmlXPathCompareNodeSets(inf, strict, arg, val)); 6704 case XPATH_STRING: 6705 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val)); 6706 case XPATH_BOOLEAN: 6707 valuePush(ctxt, arg); 6708 xmlXPathBooleanFunction(ctxt, 1); 6709 valuePush(ctxt, val); 6710 return(xmlXPathCompareValues(ctxt, inf, strict)); 6711 default: 6712 xmlGenericError(xmlGenericErrorContext, 6713 "xmlXPathCompareNodeSetValue: Can't compare node set " 6714 "and object of type %d\n", 6715 val->type); 6716 xmlXPathReleaseObject(ctxt->context, arg); 6717 xmlXPathReleaseObject(ctxt->context, val); 6718 XP_ERROR0(XPATH_INVALID_TYPE); 6719 } 6720 return(0); 6721 } 6722 6723 /** 6724 * xmlXPathEqualNodeSetString: 6725 * @arg: the nodeset object argument 6726 * @str: the string to compare to. 6727 * @neq: flag to show whether for '=' (0) or '!=' (1) 6728 * 6729 * Implement the equal operation on XPath objects content: @arg1 == @arg2 6730 * If one object to be compared is a node-set and the other is a string, 6731 * then the comparison will be true if and only if there is a node in 6732 * the node-set such that the result of performing the comparison on the 6733 * string-value of the node and the other string is true. 6734 * 6735 * Returns 0 or 1 depending on the results of the test. 6736 */ 6737 static int 6738 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq) 6739 { 6740 int i; 6741 xmlNodeSetPtr ns; 6742 xmlChar *str2; 6743 unsigned int hash; 6744 6745 if ((str == NULL) || (arg == NULL) || 6746 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 6747 return (0); 6748 ns = arg->nodesetval; 6749 /* 6750 * A NULL nodeset compared with a string is always false 6751 * (since there is no node equal, and no node not equal) 6752 */ 6753 if ((ns == NULL) || (ns->nodeNr <= 0) ) 6754 return (0); 6755 hash = xmlXPathStringHash(str); 6756 for (i = 0; i < ns->nodeNr; i++) { 6757 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) { 6758 str2 = xmlNodeGetContent(ns->nodeTab[i]); 6759 if ((str2 != NULL) && (xmlStrEqual(str, str2))) { 6760 xmlFree(str2); 6761 if (neq) 6762 continue; 6763 return (1); 6764 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) { 6765 if (neq) 6766 continue; 6767 return (1); 6768 } else if (neq) { 6769 if (str2 != NULL) 6770 xmlFree(str2); 6771 return (1); 6772 } 6773 if (str2 != NULL) 6774 xmlFree(str2); 6775 } else if (neq) 6776 return (1); 6777 } 6778 return (0); 6779 } 6780 6781 /** 6782 * xmlXPathEqualNodeSetFloat: 6783 * @arg: the nodeset object argument 6784 * @f: the float to compare to 6785 * @neq: flag to show whether to compare '=' (0) or '!=' (1) 6786 * 6787 * Implement the equal operation on XPath objects content: @arg1 == @arg2 6788 * If one object to be compared is a node-set and the other is a number, 6789 * then the comparison will be true if and only if there is a node in 6790 * the node-set such that the result of performing the comparison on the 6791 * number to be compared and on the result of converting the string-value 6792 * of that node to a number using the number function is true. 6793 * 6794 * Returns 0 or 1 depending on the results of the test. 6795 */ 6796 static int 6797 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt, 6798 xmlXPathObjectPtr arg, double f, int neq) { 6799 int i, ret=0; 6800 xmlNodeSetPtr ns; 6801 xmlChar *str2; 6802 xmlXPathObjectPtr val; 6803 double v; 6804 6805 if ((arg == NULL) || 6806 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 6807 return(0); 6808 6809 ns = arg->nodesetval; 6810 if (ns != NULL) { 6811 for (i=0;i<ns->nodeNr;i++) { 6812 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 6813 if (str2 != NULL) { 6814 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2)); 6815 xmlFree(str2); 6816 xmlXPathNumberFunction(ctxt, 1); 6817 val = valuePop(ctxt); 6818 v = val->floatval; 6819 xmlXPathReleaseObject(ctxt->context, val); 6820 if (!xmlXPathIsNaN(v)) { 6821 if ((!neq) && (v==f)) { 6822 ret = 1; 6823 break; 6824 } else if ((neq) && (v!=f)) { 6825 ret = 1; 6826 break; 6827 } 6828 } else { /* NaN is unequal to any value */ 6829 if (neq) 6830 ret = 1; 6831 } 6832 } 6833 } 6834 } 6835 6836 return(ret); 6837 } 6838 6839 6840 /** 6841 * xmlXPathEqualNodeSets: 6842 * @arg1: first nodeset object argument 6843 * @arg2: second nodeset object argument 6844 * @neq: flag to show whether to test '=' (0) or '!=' (1) 6845 * 6846 * Implement the equal / not equal operation on XPath nodesets: 6847 * @arg1 == @arg2 or @arg1 != @arg2 6848 * If both objects to be compared are node-sets, then the comparison 6849 * will be true if and only if there is a node in the first node-set and 6850 * a node in the second node-set such that the result of performing the 6851 * comparison on the string-values of the two nodes is true. 6852 * 6853 * (needless to say, this is a costly operation) 6854 * 6855 * Returns 0 or 1 depending on the results of the test. 6856 */ 6857 static int 6858 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) { 6859 int i, j; 6860 unsigned int *hashs1; 6861 unsigned int *hashs2; 6862 xmlChar **values1; 6863 xmlChar **values2; 6864 int ret = 0; 6865 xmlNodeSetPtr ns1; 6866 xmlNodeSetPtr ns2; 6867 6868 if ((arg1 == NULL) || 6869 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) 6870 return(0); 6871 if ((arg2 == NULL) || 6872 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) 6873 return(0); 6874 6875 ns1 = arg1->nodesetval; 6876 ns2 = arg2->nodesetval; 6877 6878 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) 6879 return(0); 6880 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) 6881 return(0); 6882 6883 /* 6884 * for equal, check if there is a node pertaining to both sets 6885 */ 6886 if (neq == 0) 6887 for (i = 0;i < ns1->nodeNr;i++) 6888 for (j = 0;j < ns2->nodeNr;j++) 6889 if (ns1->nodeTab[i] == ns2->nodeTab[j]) 6890 return(1); 6891 6892 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *)); 6893 if (values1 == NULL) { 6894 /* TODO: Propagate memory error. */ 6895 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6896 return(0); 6897 } 6898 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int)); 6899 if (hashs1 == NULL) { 6900 /* TODO: Propagate memory error. */ 6901 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6902 xmlFree(values1); 6903 return(0); 6904 } 6905 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *)); 6906 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *)); 6907 if (values2 == NULL) { 6908 /* TODO: Propagate memory error. */ 6909 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6910 xmlFree(hashs1); 6911 xmlFree(values1); 6912 return(0); 6913 } 6914 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int)); 6915 if (hashs2 == NULL) { 6916 /* TODO: Propagate memory error. */ 6917 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6918 xmlFree(hashs1); 6919 xmlFree(values1); 6920 xmlFree(values2); 6921 return(0); 6922 } 6923 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *)); 6924 for (i = 0;i < ns1->nodeNr;i++) { 6925 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]); 6926 for (j = 0;j < ns2->nodeNr;j++) { 6927 if (i == 0) 6928 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]); 6929 if (hashs1[i] != hashs2[j]) { 6930 if (neq) { 6931 ret = 1; 6932 break; 6933 } 6934 } 6935 else { 6936 if (values1[i] == NULL) 6937 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]); 6938 if (values2[j] == NULL) 6939 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]); 6940 ret = xmlStrEqual(values1[i], values2[j]) ^ neq; 6941 if (ret) 6942 break; 6943 } 6944 } 6945 if (ret) 6946 break; 6947 } 6948 for (i = 0;i < ns1->nodeNr;i++) 6949 if (values1[i] != NULL) 6950 xmlFree(values1[i]); 6951 for (j = 0;j < ns2->nodeNr;j++) 6952 if (values2[j] != NULL) 6953 xmlFree(values2[j]); 6954 xmlFree(values1); 6955 xmlFree(values2); 6956 xmlFree(hashs1); 6957 xmlFree(hashs2); 6958 return(ret); 6959 } 6960 6961 static int 6962 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt, 6963 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) { 6964 int ret = 0; 6965 /* 6966 *At this point we are assured neither arg1 nor arg2 6967 *is a nodeset, so we can just pick the appropriate routine. 6968 */ 6969 switch (arg1->type) { 6970 case XPATH_UNDEFINED: 6971 #ifdef DEBUG_EXPR 6972 xmlGenericError(xmlGenericErrorContext, 6973 "Equal: undefined\n"); 6974 #endif 6975 break; 6976 case XPATH_BOOLEAN: 6977 switch (arg2->type) { 6978 case XPATH_UNDEFINED: 6979 #ifdef DEBUG_EXPR 6980 xmlGenericError(xmlGenericErrorContext, 6981 "Equal: undefined\n"); 6982 #endif 6983 break; 6984 case XPATH_BOOLEAN: 6985 #ifdef DEBUG_EXPR 6986 xmlGenericError(xmlGenericErrorContext, 6987 "Equal: %d boolean %d \n", 6988 arg1->boolval, arg2->boolval); 6989 #endif 6990 ret = (arg1->boolval == arg2->boolval); 6991 break; 6992 case XPATH_NUMBER: 6993 ret = (arg1->boolval == 6994 xmlXPathCastNumberToBoolean(arg2->floatval)); 6995 break; 6996 case XPATH_STRING: 6997 if ((arg2->stringval == NULL) || 6998 (arg2->stringval[0] == 0)) ret = 0; 6999 else 7000 ret = 1; 7001 ret = (arg1->boolval == ret); 7002 break; 7003 case XPATH_USERS: 7004 #ifdef LIBXML_XPTR_LOCS_ENABLED 7005 case XPATH_POINT: 7006 case XPATH_RANGE: 7007 case XPATH_LOCATIONSET: 7008 #endif /* LIBXML_XPTR_LOCS_ENABLED */ 7009 TODO 7010 break; 7011 case XPATH_NODESET: 7012 case XPATH_XSLT_TREE: 7013 break; 7014 } 7015 break; 7016 case XPATH_NUMBER: 7017 switch (arg2->type) { 7018 case XPATH_UNDEFINED: 7019 #ifdef DEBUG_EXPR 7020 xmlGenericError(xmlGenericErrorContext, 7021 "Equal: undefined\n"); 7022 #endif 7023 break; 7024 case XPATH_BOOLEAN: 7025 ret = (arg2->boolval== 7026 xmlXPathCastNumberToBoolean(arg1->floatval)); 7027 break; 7028 case XPATH_STRING: 7029 valuePush(ctxt, arg2); 7030 xmlXPathNumberFunction(ctxt, 1); 7031 arg2 = valuePop(ctxt); 7032 /* Falls through. */ 7033 case XPATH_NUMBER: 7034 /* Hand check NaN and Infinity equalities */ 7035 if (xmlXPathIsNaN(arg1->floatval) || 7036 xmlXPathIsNaN(arg2->floatval)) { 7037 ret = 0; 7038 } else if (xmlXPathIsInf(arg1->floatval) == 1) { 7039 if (xmlXPathIsInf(arg2->floatval) == 1) 7040 ret = 1; 7041 else 7042 ret = 0; 7043 } else if (xmlXPathIsInf(arg1->floatval) == -1) { 7044 if (xmlXPathIsInf(arg2->floatval) == -1) 7045 ret = 1; 7046 else 7047 ret = 0; 7048 } else if (xmlXPathIsInf(arg2->floatval) == 1) { 7049 if (xmlXPathIsInf(arg1->floatval) == 1) 7050 ret = 1; 7051 else 7052 ret = 0; 7053 } else if (xmlXPathIsInf(arg2->floatval) == -1) { 7054 if (xmlXPathIsInf(arg1->floatval) == -1) 7055 ret = 1; 7056 else 7057 ret = 0; 7058 } else { 7059 ret = (arg1->floatval == arg2->floatval); 7060 } 7061 break; 7062 case XPATH_USERS: 7063 #ifdef LIBXML_XPTR_LOCS_ENABLED 7064 case XPATH_POINT: 7065 case XPATH_RANGE: 7066 case XPATH_LOCATIONSET: 7067 #endif /* LIBXML_XPTR_LOCS_ENABLED */ 7068 TODO 7069 break; 7070 case XPATH_NODESET: 7071 case XPATH_XSLT_TREE: 7072 break; 7073 } 7074 break; 7075 case XPATH_STRING: 7076 switch (arg2->type) { 7077 case XPATH_UNDEFINED: 7078 #ifdef DEBUG_EXPR 7079 xmlGenericError(xmlGenericErrorContext, 7080 "Equal: undefined\n"); 7081 #endif 7082 break; 7083 case XPATH_BOOLEAN: 7084 if ((arg1->stringval == NULL) || 7085 (arg1->stringval[0] == 0)) ret = 0; 7086 else 7087 ret = 1; 7088 ret = (arg2->boolval == ret); 7089 break; 7090 case XPATH_STRING: 7091 ret = xmlStrEqual(arg1->stringval, arg2->stringval); 7092 break; 7093 case XPATH_NUMBER: 7094 valuePush(ctxt, arg1); 7095 xmlXPathNumberFunction(ctxt, 1); 7096 arg1 = valuePop(ctxt); 7097 /* Hand check NaN and Infinity equalities */ 7098 if (xmlXPathIsNaN(arg1->floatval) || 7099 xmlXPathIsNaN(arg2->floatval)) { 7100 ret = 0; 7101 } else if (xmlXPathIsInf(arg1->floatval) == 1) { 7102 if (xmlXPathIsInf(arg2->floatval) == 1) 7103 ret = 1; 7104 else 7105 ret = 0; 7106 } else if (xmlXPathIsInf(arg1->floatval) == -1) { 7107 if (xmlXPathIsInf(arg2->floatval) == -1) 7108 ret = 1; 7109 else 7110 ret = 0; 7111 } else if (xmlXPathIsInf(arg2->floatval) == 1) { 7112 if (xmlXPathIsInf(arg1->floatval) == 1) 7113 ret = 1; 7114 else 7115 ret = 0; 7116 } else if (xmlXPathIsInf(arg2->floatval) == -1) { 7117 if (xmlXPathIsInf(arg1->floatval) == -1) 7118 ret = 1; 7119 else 7120 ret = 0; 7121 } else { 7122 ret = (arg1->floatval == arg2->floatval); 7123 } 7124 break; 7125 case XPATH_USERS: 7126 #ifdef LIBXML_XPTR_LOCS_ENABLED 7127 case XPATH_POINT: 7128 case XPATH_RANGE: 7129 case XPATH_LOCATIONSET: 7130 #endif /* LIBXML_XPTR_LOCS_ENABLED */ 7131 TODO 7132 break; 7133 case XPATH_NODESET: 7134 case XPATH_XSLT_TREE: 7135 break; 7136 } 7137 break; 7138 case XPATH_USERS: 7139 #ifdef LIBXML_XPTR_LOCS_ENABLED 7140 case XPATH_POINT: 7141 case XPATH_RANGE: 7142 case XPATH_LOCATIONSET: 7143 #endif /* LIBXML_XPTR_LOCS_ENABLED */ 7144 TODO 7145 break; 7146 case XPATH_NODESET: 7147 case XPATH_XSLT_TREE: 7148 break; 7149 } 7150 xmlXPathReleaseObject(ctxt->context, arg1); 7151 xmlXPathReleaseObject(ctxt->context, arg2); 7152 return(ret); 7153 } 7154 7155 /** 7156 * xmlXPathEqualValues: 7157 * @ctxt: the XPath Parser context 7158 * 7159 * Implement the equal operation on XPath objects content: @arg1 == @arg2 7160 * 7161 * Returns 0 or 1 depending on the results of the test. 7162 */ 7163 int 7164 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) { 7165 xmlXPathObjectPtr arg1, arg2, argtmp; 7166 int ret = 0; 7167 7168 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); 7169 arg2 = valuePop(ctxt); 7170 arg1 = valuePop(ctxt); 7171 if ((arg1 == NULL) || (arg2 == NULL)) { 7172 if (arg1 != NULL) 7173 xmlXPathReleaseObject(ctxt->context, arg1); 7174 else 7175 xmlXPathReleaseObject(ctxt->context, arg2); 7176 XP_ERROR0(XPATH_INVALID_OPERAND); 7177 } 7178 7179 if (arg1 == arg2) { 7180 #ifdef DEBUG_EXPR 7181 xmlGenericError(xmlGenericErrorContext, 7182 "Equal: by pointer\n"); 7183 #endif 7184 xmlXPathFreeObject(arg1); 7185 return(1); 7186 } 7187 7188 /* 7189 *If either argument is a nodeset, it's a 'special case' 7190 */ 7191 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 7192 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7193 /* 7194 *Hack it to assure arg1 is the nodeset 7195 */ 7196 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) { 7197 argtmp = arg2; 7198 arg2 = arg1; 7199 arg1 = argtmp; 7200 } 7201 switch (arg2->type) { 7202 case XPATH_UNDEFINED: 7203 #ifdef DEBUG_EXPR 7204 xmlGenericError(xmlGenericErrorContext, 7205 "Equal: undefined\n"); 7206 #endif 7207 break; 7208 case XPATH_NODESET: 7209 case XPATH_XSLT_TREE: 7210 ret = xmlXPathEqualNodeSets(arg1, arg2, 0); 7211 break; 7212 case XPATH_BOOLEAN: 7213 if ((arg1->nodesetval == NULL) || 7214 (arg1->nodesetval->nodeNr == 0)) ret = 0; 7215 else 7216 ret = 1; 7217 ret = (ret == arg2->boolval); 7218 break; 7219 case XPATH_NUMBER: 7220 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0); 7221 break; 7222 case XPATH_STRING: 7223 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0); 7224 break; 7225 case XPATH_USERS: 7226 #ifdef LIBXML_XPTR_LOCS_ENABLED 7227 case XPATH_POINT: 7228 case XPATH_RANGE: 7229 case XPATH_LOCATIONSET: 7230 #endif /* LIBXML_XPTR_LOCS_ENABLED */ 7231 TODO 7232 break; 7233 } 7234 xmlXPathReleaseObject(ctxt->context, arg1); 7235 xmlXPathReleaseObject(ctxt->context, arg2); 7236 return(ret); 7237 } 7238 7239 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2)); 7240 } 7241 7242 /** 7243 * xmlXPathNotEqualValues: 7244 * @ctxt: the XPath Parser context 7245 * 7246 * Implement the equal operation on XPath objects content: @arg1 == @arg2 7247 * 7248 * Returns 0 or 1 depending on the results of the test. 7249 */ 7250 int 7251 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) { 7252 xmlXPathObjectPtr arg1, arg2, argtmp; 7253 int ret = 0; 7254 7255 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); 7256 arg2 = valuePop(ctxt); 7257 arg1 = valuePop(ctxt); 7258 if ((arg1 == NULL) || (arg2 == NULL)) { 7259 if (arg1 != NULL) 7260 xmlXPathReleaseObject(ctxt->context, arg1); 7261 else 7262 xmlXPathReleaseObject(ctxt->context, arg2); 7263 XP_ERROR0(XPATH_INVALID_OPERAND); 7264 } 7265 7266 if (arg1 == arg2) { 7267 #ifdef DEBUG_EXPR 7268 xmlGenericError(xmlGenericErrorContext, 7269 "NotEqual: by pointer\n"); 7270 #endif 7271 xmlXPathReleaseObject(ctxt->context, arg1); 7272 return(0); 7273 } 7274 7275 /* 7276 *If either argument is a nodeset, it's a 'special case' 7277 */ 7278 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 7279 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7280 /* 7281 *Hack it to assure arg1 is the nodeset 7282 */ 7283 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) { 7284 argtmp = arg2; 7285 arg2 = arg1; 7286 arg1 = argtmp; 7287 } 7288 switch (arg2->type) { 7289 case XPATH_UNDEFINED: 7290 #ifdef DEBUG_EXPR 7291 xmlGenericError(xmlGenericErrorContext, 7292 "NotEqual: undefined\n"); 7293 #endif 7294 break; 7295 case XPATH_NODESET: 7296 case XPATH_XSLT_TREE: 7297 ret = xmlXPathEqualNodeSets(arg1, arg2, 1); 7298 break; 7299 case XPATH_BOOLEAN: 7300 if ((arg1->nodesetval == NULL) || 7301 (arg1->nodesetval->nodeNr == 0)) ret = 0; 7302 else 7303 ret = 1; 7304 ret = (ret != arg2->boolval); 7305 break; 7306 case XPATH_NUMBER: 7307 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1); 7308 break; 7309 case XPATH_STRING: 7310 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1); 7311 break; 7312 case XPATH_USERS: 7313 #ifdef LIBXML_XPTR_LOCS_ENABLED 7314 case XPATH_POINT: 7315 case XPATH_RANGE: 7316 case XPATH_LOCATIONSET: 7317 #endif /* LIBXML_XPTR_LOCS_ENABLED */ 7318 TODO 7319 break; 7320 } 7321 xmlXPathReleaseObject(ctxt->context, arg1); 7322 xmlXPathReleaseObject(ctxt->context, arg2); 7323 return(ret); 7324 } 7325 7326 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2)); 7327 } 7328 7329 /** 7330 * xmlXPathCompareValues: 7331 * @ctxt: the XPath Parser context 7332 * @inf: less than (1) or greater than (0) 7333 * @strict: is the comparison strict 7334 * 7335 * Implement the compare operation on XPath objects: 7336 * @arg1 < @arg2 (1, 1, ... 7337 * @arg1 <= @arg2 (1, 0, ... 7338 * @arg1 > @arg2 (0, 1, ... 7339 * @arg1 >= @arg2 (0, 0, ... 7340 * 7341 * When neither object to be compared is a node-set and the operator is 7342 * <=, <, >=, >, then the objects are compared by converted both objects 7343 * to numbers and comparing the numbers according to IEEE 754. The < 7344 * comparison will be true if and only if the first number is less than the 7345 * second number. The <= comparison will be true if and only if the first 7346 * number is less than or equal to the second number. The > comparison 7347 * will be true if and only if the first number is greater than the second 7348 * number. The >= comparison will be true if and only if the first number 7349 * is greater than or equal to the second number. 7350 * 7351 * Returns 1 if the comparison succeeded, 0 if it failed 7352 */ 7353 int 7354 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) { 7355 int ret = 0, arg1i = 0, arg2i = 0; 7356 xmlXPathObjectPtr arg1, arg2; 7357 7358 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); 7359 arg2 = valuePop(ctxt); 7360 arg1 = valuePop(ctxt); 7361 if ((arg1 == NULL) || (arg2 == NULL)) { 7362 if (arg1 != NULL) 7363 xmlXPathReleaseObject(ctxt->context, arg1); 7364 else 7365 xmlXPathReleaseObject(ctxt->context, arg2); 7366 XP_ERROR0(XPATH_INVALID_OPERAND); 7367 } 7368 7369 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 7370 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7371 /* 7372 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments 7373 * are not freed from within this routine; they will be freed from the 7374 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue 7375 */ 7376 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) && 7377 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){ 7378 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2); 7379 } else { 7380 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7381 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict, 7382 arg1, arg2); 7383 } else { 7384 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict, 7385 arg2, arg1); 7386 } 7387 } 7388 return(ret); 7389 } 7390 7391 if (arg1->type != XPATH_NUMBER) { 7392 valuePush(ctxt, arg1); 7393 xmlXPathNumberFunction(ctxt, 1); 7394 arg1 = valuePop(ctxt); 7395 } 7396 if (arg1->type != XPATH_NUMBER) { 7397 xmlXPathFreeObject(arg1); 7398 xmlXPathFreeObject(arg2); 7399 XP_ERROR0(XPATH_INVALID_OPERAND); 7400 } 7401 if (arg2->type != XPATH_NUMBER) { 7402 valuePush(ctxt, arg2); 7403 xmlXPathNumberFunction(ctxt, 1); 7404 arg2 = valuePop(ctxt); 7405 } 7406 if (arg2->type != XPATH_NUMBER) { 7407 xmlXPathReleaseObject(ctxt->context, arg1); 7408 xmlXPathReleaseObject(ctxt->context, arg2); 7409 XP_ERROR0(XPATH_INVALID_OPERAND); 7410 } 7411 /* 7412 * Add tests for infinity and nan 7413 * => feedback on 3.4 for Inf and NaN 7414 */ 7415 /* Hand check NaN and Infinity comparisons */ 7416 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) { 7417 ret=0; 7418 } else { 7419 arg1i=xmlXPathIsInf(arg1->floatval); 7420 arg2i=xmlXPathIsInf(arg2->floatval); 7421 if (inf && strict) { 7422 if ((arg1i == -1 && arg2i != -1) || 7423 (arg2i == 1 && arg1i != 1)) { 7424 ret = 1; 7425 } else if (arg1i == 0 && arg2i == 0) { 7426 ret = (arg1->floatval < arg2->floatval); 7427 } else { 7428 ret = 0; 7429 } 7430 } 7431 else if (inf && !strict) { 7432 if (arg1i == -1 || arg2i == 1) { 7433 ret = 1; 7434 } else if (arg1i == 0 && arg2i == 0) { 7435 ret = (arg1->floatval <= arg2->floatval); 7436 } else { 7437 ret = 0; 7438 } 7439 } 7440 else if (!inf && strict) { 7441 if ((arg1i == 1 && arg2i != 1) || 7442 (arg2i == -1 && arg1i != -1)) { 7443 ret = 1; 7444 } else if (arg1i == 0 && arg2i == 0) { 7445 ret = (arg1->floatval > arg2->floatval); 7446 } else { 7447 ret = 0; 7448 } 7449 } 7450 else if (!inf && !strict) { 7451 if (arg1i == 1 || arg2i == -1) { 7452 ret = 1; 7453 } else if (arg1i == 0 && arg2i == 0) { 7454 ret = (arg1->floatval >= arg2->floatval); 7455 } else { 7456 ret = 0; 7457 } 7458 } 7459 } 7460 xmlXPathReleaseObject(ctxt->context, arg1); 7461 xmlXPathReleaseObject(ctxt->context, arg2); 7462 return(ret); 7463 } 7464 7465 /** 7466 * xmlXPathValueFlipSign: 7467 * @ctxt: the XPath Parser context 7468 * 7469 * Implement the unary - operation on an XPath object 7470 * The numeric operators convert their operands to numbers as if 7471 * by calling the number function. 7472 */ 7473 void 7474 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) { 7475 if ((ctxt == NULL) || (ctxt->context == NULL)) return; 7476 CAST_TO_NUMBER; 7477 CHECK_TYPE(XPATH_NUMBER); 7478 ctxt->value->floatval = -ctxt->value->floatval; 7479 } 7480 7481 /** 7482 * xmlXPathAddValues: 7483 * @ctxt: the XPath Parser context 7484 * 7485 * Implement the add operation on XPath objects: 7486 * The numeric operators convert their operands to numbers as if 7487 * by calling the number function. 7488 */ 7489 void 7490 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) { 7491 xmlXPathObjectPtr arg; 7492 double val; 7493 7494 arg = valuePop(ctxt); 7495 if (arg == NULL) 7496 XP_ERROR(XPATH_INVALID_OPERAND); 7497 val = xmlXPathCastToNumber(arg); 7498 xmlXPathReleaseObject(ctxt->context, arg); 7499 CAST_TO_NUMBER; 7500 CHECK_TYPE(XPATH_NUMBER); 7501 ctxt->value->floatval += val; 7502 } 7503 7504 /** 7505 * xmlXPathSubValues: 7506 * @ctxt: the XPath Parser context 7507 * 7508 * Implement the subtraction operation on XPath objects: 7509 * The numeric operators convert their operands to numbers as if 7510 * by calling the number function. 7511 */ 7512 void 7513 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) { 7514 xmlXPathObjectPtr arg; 7515 double val; 7516 7517 arg = valuePop(ctxt); 7518 if (arg == NULL) 7519 XP_ERROR(XPATH_INVALID_OPERAND); 7520 val = xmlXPathCastToNumber(arg); 7521 xmlXPathReleaseObject(ctxt->context, arg); 7522 CAST_TO_NUMBER; 7523 CHECK_TYPE(XPATH_NUMBER); 7524 ctxt->value->floatval -= val; 7525 } 7526 7527 /** 7528 * xmlXPathMultValues: 7529 * @ctxt: the XPath Parser context 7530 * 7531 * Implement the multiply operation on XPath objects: 7532 * The numeric operators convert their operands to numbers as if 7533 * by calling the number function. 7534 */ 7535 void 7536 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) { 7537 xmlXPathObjectPtr arg; 7538 double val; 7539 7540 arg = valuePop(ctxt); 7541 if (arg == NULL) 7542 XP_ERROR(XPATH_INVALID_OPERAND); 7543 val = xmlXPathCastToNumber(arg); 7544 xmlXPathReleaseObject(ctxt->context, arg); 7545 CAST_TO_NUMBER; 7546 CHECK_TYPE(XPATH_NUMBER); 7547 ctxt->value->floatval *= val; 7548 } 7549 7550 /** 7551 * xmlXPathDivValues: 7552 * @ctxt: the XPath Parser context 7553 * 7554 * Implement the div operation on XPath objects @arg1 / @arg2: 7555 * The numeric operators convert their operands to numbers as if 7556 * by calling the number function. 7557 */ 7558 ATTRIBUTE_NO_SANITIZE("float-divide-by-zero") 7559 void 7560 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) { 7561 xmlXPathObjectPtr arg; 7562 double val; 7563 7564 arg = valuePop(ctxt); 7565 if (arg == NULL) 7566 XP_ERROR(XPATH_INVALID_OPERAND); 7567 val = xmlXPathCastToNumber(arg); 7568 xmlXPathReleaseObject(ctxt->context, arg); 7569 CAST_TO_NUMBER; 7570 CHECK_TYPE(XPATH_NUMBER); 7571 ctxt->value->floatval /= val; 7572 } 7573 7574 /** 7575 * xmlXPathModValues: 7576 * @ctxt: the XPath Parser context 7577 * 7578 * Implement the mod operation on XPath objects: @arg1 / @arg2 7579 * The numeric operators convert their operands to numbers as if 7580 * by calling the number function. 7581 */ 7582 void 7583 xmlXPathModValues(xmlXPathParserContextPtr ctxt) { 7584 xmlXPathObjectPtr arg; 7585 double arg1, arg2; 7586 7587 arg = valuePop(ctxt); 7588 if (arg == NULL) 7589 XP_ERROR(XPATH_INVALID_OPERAND); 7590 arg2 = xmlXPathCastToNumber(arg); 7591 xmlXPathReleaseObject(ctxt->context, arg); 7592 CAST_TO_NUMBER; 7593 CHECK_TYPE(XPATH_NUMBER); 7594 arg1 = ctxt->value->floatval; 7595 if (arg2 == 0) 7596 ctxt->value->floatval = xmlXPathNAN; 7597 else { 7598 ctxt->value->floatval = fmod(arg1, arg2); 7599 } 7600 } 7601 7602 /************************************************************************ 7603 * * 7604 * The traversal functions * 7605 * * 7606 ************************************************************************/ 7607 7608 /* 7609 * A traversal function enumerates nodes along an axis. 7610 * Initially it must be called with NULL, and it indicates 7611 * termination on the axis by returning NULL. 7612 */ 7613 typedef xmlNodePtr (*xmlXPathTraversalFunction) 7614 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur); 7615 7616 /* 7617 * xmlXPathTraversalFunctionExt: 7618 * A traversal function enumerates nodes along an axis. 7619 * Initially it must be called with NULL, and it indicates 7620 * termination on the axis by returning NULL. 7621 * The context node of the traversal is specified via @contextNode. 7622 */ 7623 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt) 7624 (xmlNodePtr cur, xmlNodePtr contextNode); 7625 7626 /* 7627 * xmlXPathNodeSetMergeFunction: 7628 * Used for merging node sets in xmlXPathCollectAndTest(). 7629 */ 7630 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction) 7631 (xmlNodeSetPtr, xmlNodeSetPtr); 7632 7633 7634 /** 7635 * xmlXPathNextSelf: 7636 * @ctxt: the XPath Parser context 7637 * @cur: the current node in the traversal 7638 * 7639 * Traversal function for the "self" direction 7640 * The self axis contains just the context node itself 7641 * 7642 * Returns the next element following that axis 7643 */ 7644 xmlNodePtr 7645 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7646 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7647 if (cur == NULL) 7648 return(ctxt->context->node); 7649 return(NULL); 7650 } 7651 7652 /** 7653 * xmlXPathNextChild: 7654 * @ctxt: the XPath Parser context 7655 * @cur: the current node in the traversal 7656 * 7657 * Traversal function for the "child" direction 7658 * The child axis contains the children of the context node in document order. 7659 * 7660 * Returns the next element following that axis 7661 */ 7662 xmlNodePtr 7663 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7664 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7665 if (cur == NULL) { 7666 if (ctxt->context->node == NULL) return(NULL); 7667 switch (ctxt->context->node->type) { 7668 case XML_ELEMENT_NODE: 7669 case XML_TEXT_NODE: 7670 case XML_CDATA_SECTION_NODE: 7671 case XML_ENTITY_REF_NODE: 7672 case XML_ENTITY_NODE: 7673 case XML_PI_NODE: 7674 case XML_COMMENT_NODE: 7675 case XML_NOTATION_NODE: 7676 case XML_DTD_NODE: 7677 return(ctxt->context->node->children); 7678 case XML_DOCUMENT_NODE: 7679 case XML_DOCUMENT_TYPE_NODE: 7680 case XML_DOCUMENT_FRAG_NODE: 7681 case XML_HTML_DOCUMENT_NODE: 7682 return(((xmlDocPtr) ctxt->context->node)->children); 7683 case XML_ELEMENT_DECL: 7684 case XML_ATTRIBUTE_DECL: 7685 case XML_ENTITY_DECL: 7686 case XML_ATTRIBUTE_NODE: 7687 case XML_NAMESPACE_DECL: 7688 case XML_XINCLUDE_START: 7689 case XML_XINCLUDE_END: 7690 return(NULL); 7691 } 7692 return(NULL); 7693 } 7694 if ((cur->type == XML_DOCUMENT_NODE) || 7695 (cur->type == XML_HTML_DOCUMENT_NODE)) 7696 return(NULL); 7697 return(cur->next); 7698 } 7699 7700 /** 7701 * xmlXPathNextChildElement: 7702 * @ctxt: the XPath Parser context 7703 * @cur: the current node in the traversal 7704 * 7705 * Traversal function for the "child" direction and nodes of type element. 7706 * The child axis contains the children of the context node in document order. 7707 * 7708 * Returns the next element following that axis 7709 */ 7710 static xmlNodePtr 7711 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7712 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7713 if (cur == NULL) { 7714 cur = ctxt->context->node; 7715 if (cur == NULL) return(NULL); 7716 /* 7717 * Get the first element child. 7718 */ 7719 switch (cur->type) { 7720 case XML_ELEMENT_NODE: 7721 case XML_DOCUMENT_FRAG_NODE: 7722 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */ 7723 case XML_ENTITY_NODE: 7724 cur = cur->children; 7725 if (cur != NULL) { 7726 if (cur->type == XML_ELEMENT_NODE) 7727 return(cur); 7728 do { 7729 cur = cur->next; 7730 } while ((cur != NULL) && 7731 (cur->type != XML_ELEMENT_NODE)); 7732 return(cur); 7733 } 7734 return(NULL); 7735 case XML_DOCUMENT_NODE: 7736 case XML_HTML_DOCUMENT_NODE: 7737 return(xmlDocGetRootElement((xmlDocPtr) cur)); 7738 default: 7739 return(NULL); 7740 } 7741 return(NULL); 7742 } 7743 /* 7744 * Get the next sibling element node. 7745 */ 7746 switch (cur->type) { 7747 case XML_ELEMENT_NODE: 7748 case XML_TEXT_NODE: 7749 case XML_ENTITY_REF_NODE: 7750 case XML_ENTITY_NODE: 7751 case XML_CDATA_SECTION_NODE: 7752 case XML_PI_NODE: 7753 case XML_COMMENT_NODE: 7754 case XML_XINCLUDE_END: 7755 break; 7756 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */ 7757 default: 7758 return(NULL); 7759 } 7760 if (cur->next != NULL) { 7761 if (cur->next->type == XML_ELEMENT_NODE) 7762 return(cur->next); 7763 cur = cur->next; 7764 do { 7765 cur = cur->next; 7766 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE)); 7767 return(cur); 7768 } 7769 return(NULL); 7770 } 7771 7772 #if 0 7773 /** 7774 * xmlXPathNextDescendantOrSelfElemParent: 7775 * @ctxt: the XPath Parser context 7776 * @cur: the current node in the traversal 7777 * 7778 * Traversal function for the "descendant-or-self" axis. 7779 * Additionally it returns only nodes which can be parents of 7780 * element nodes. 7781 * 7782 * 7783 * Returns the next element following that axis 7784 */ 7785 static xmlNodePtr 7786 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur, 7787 xmlNodePtr contextNode) 7788 { 7789 if (cur == NULL) { 7790 if (contextNode == NULL) 7791 return(NULL); 7792 switch (contextNode->type) { 7793 case XML_ELEMENT_NODE: 7794 case XML_XINCLUDE_START: 7795 case XML_DOCUMENT_FRAG_NODE: 7796 case XML_DOCUMENT_NODE: 7797 case XML_HTML_DOCUMENT_NODE: 7798 return(contextNode); 7799 default: 7800 return(NULL); 7801 } 7802 return(NULL); 7803 } else { 7804 xmlNodePtr start = cur; 7805 7806 while (cur != NULL) { 7807 switch (cur->type) { 7808 case XML_ELEMENT_NODE: 7809 /* TODO: OK to have XInclude here? */ 7810 case XML_XINCLUDE_START: 7811 case XML_DOCUMENT_FRAG_NODE: 7812 if (cur != start) 7813 return(cur); 7814 if (cur->children != NULL) { 7815 cur = cur->children; 7816 continue; 7817 } 7818 break; 7819 /* Not sure if we need those here. */ 7820 case XML_DOCUMENT_NODE: 7821 case XML_HTML_DOCUMENT_NODE: 7822 if (cur != start) 7823 return(cur); 7824 return(xmlDocGetRootElement((xmlDocPtr) cur)); 7825 default: 7826 break; 7827 } 7828 7829 next_sibling: 7830 if ((cur == NULL) || (cur == contextNode)) 7831 return(NULL); 7832 if (cur->next != NULL) { 7833 cur = cur->next; 7834 } else { 7835 cur = cur->parent; 7836 goto next_sibling; 7837 } 7838 } 7839 } 7840 return(NULL); 7841 } 7842 #endif 7843 7844 /** 7845 * xmlXPathNextDescendant: 7846 * @ctxt: the XPath Parser context 7847 * @cur: the current node in the traversal 7848 * 7849 * Traversal function for the "descendant" direction 7850 * the descendant axis contains the descendants of the context node in document 7851 * order; a descendant is a child or a child of a child and so on. 7852 * 7853 * Returns the next element following that axis 7854 */ 7855 xmlNodePtr 7856 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7857 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7858 if (cur == NULL) { 7859 if (ctxt->context->node == NULL) 7860 return(NULL); 7861 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 7862 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 7863 return(NULL); 7864 7865 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc) 7866 return(ctxt->context->doc->children); 7867 return(ctxt->context->node->children); 7868 } 7869 7870 if (cur->type == XML_NAMESPACE_DECL) 7871 return(NULL); 7872 if (cur->children != NULL) { 7873 /* 7874 * Do not descend on entities declarations 7875 */ 7876 if (cur->children->type != XML_ENTITY_DECL) { 7877 cur = cur->children; 7878 /* 7879 * Skip DTDs 7880 */ 7881 if (cur->type != XML_DTD_NODE) 7882 return(cur); 7883 } 7884 } 7885 7886 if (cur == ctxt->context->node) return(NULL); 7887 7888 while (cur->next != NULL) { 7889 cur = cur->next; 7890 if ((cur->type != XML_ENTITY_DECL) && 7891 (cur->type != XML_DTD_NODE)) 7892 return(cur); 7893 } 7894 7895 do { 7896 cur = cur->parent; 7897 if (cur == NULL) break; 7898 if (cur == ctxt->context->node) return(NULL); 7899 if (cur->next != NULL) { 7900 cur = cur->next; 7901 return(cur); 7902 } 7903 } while (cur != NULL); 7904 return(cur); 7905 } 7906 7907 /** 7908 * xmlXPathNextDescendantOrSelf: 7909 * @ctxt: the XPath Parser context 7910 * @cur: the current node in the traversal 7911 * 7912 * Traversal function for the "descendant-or-self" direction 7913 * the descendant-or-self axis contains the context node and the descendants 7914 * of the context node in document order; thus the context node is the first 7915 * node on the axis, and the first child of the context node is the second node 7916 * on the axis 7917 * 7918 * Returns the next element following that axis 7919 */ 7920 xmlNodePtr 7921 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7922 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7923 if (cur == NULL) 7924 return(ctxt->context->node); 7925 7926 if (ctxt->context->node == NULL) 7927 return(NULL); 7928 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 7929 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 7930 return(NULL); 7931 7932 return(xmlXPathNextDescendant(ctxt, cur)); 7933 } 7934 7935 /** 7936 * xmlXPathNextParent: 7937 * @ctxt: the XPath Parser context 7938 * @cur: the current node in the traversal 7939 * 7940 * Traversal function for the "parent" direction 7941 * The parent axis contains the parent of the context node, if there is one. 7942 * 7943 * Returns the next element following that axis 7944 */ 7945 xmlNodePtr 7946 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7947 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7948 /* 7949 * the parent of an attribute or namespace node is the element 7950 * to which the attribute or namespace node is attached 7951 * Namespace handling !!! 7952 */ 7953 if (cur == NULL) { 7954 if (ctxt->context->node == NULL) return(NULL); 7955 switch (ctxt->context->node->type) { 7956 case XML_ELEMENT_NODE: 7957 case XML_TEXT_NODE: 7958 case XML_CDATA_SECTION_NODE: 7959 case XML_ENTITY_REF_NODE: 7960 case XML_ENTITY_NODE: 7961 case XML_PI_NODE: 7962 case XML_COMMENT_NODE: 7963 case XML_NOTATION_NODE: 7964 case XML_DTD_NODE: 7965 case XML_ELEMENT_DECL: 7966 case XML_ATTRIBUTE_DECL: 7967 case XML_XINCLUDE_START: 7968 case XML_XINCLUDE_END: 7969 case XML_ENTITY_DECL: 7970 if (ctxt->context->node->parent == NULL) 7971 return((xmlNodePtr) ctxt->context->doc); 7972 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) && 7973 ((ctxt->context->node->parent->name[0] == ' ') || 7974 (xmlStrEqual(ctxt->context->node->parent->name, 7975 BAD_CAST "fake node libxslt")))) 7976 return(NULL); 7977 return(ctxt->context->node->parent); 7978 case XML_ATTRIBUTE_NODE: { 7979 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node; 7980 7981 return(att->parent); 7982 } 7983 case XML_DOCUMENT_NODE: 7984 case XML_DOCUMENT_TYPE_NODE: 7985 case XML_DOCUMENT_FRAG_NODE: 7986 case XML_HTML_DOCUMENT_NODE: 7987 return(NULL); 7988 case XML_NAMESPACE_DECL: { 7989 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; 7990 7991 if ((ns->next != NULL) && 7992 (ns->next->type != XML_NAMESPACE_DECL)) 7993 return((xmlNodePtr) ns->next); 7994 return(NULL); 7995 } 7996 } 7997 } 7998 return(NULL); 7999 } 8000 8001 /** 8002 * xmlXPathNextAncestor: 8003 * @ctxt: the XPath Parser context 8004 * @cur: the current node in the traversal 8005 * 8006 * Traversal function for the "ancestor" direction 8007 * the ancestor axis contains the ancestors of the context node; the ancestors 8008 * of the context node consist of the parent of context node and the parent's 8009 * parent and so on; the nodes are ordered in reverse document order; thus the 8010 * parent is the first node on the axis, and the parent's parent is the second 8011 * node on the axis 8012 * 8013 * Returns the next element following that axis 8014 */ 8015 xmlNodePtr 8016 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8017 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8018 /* 8019 * the parent of an attribute or namespace node is the element 8020 * to which the attribute or namespace node is attached 8021 * !!!!!!!!!!!!! 8022 */ 8023 if (cur == NULL) { 8024 if (ctxt->context->node == NULL) return(NULL); 8025 switch (ctxt->context->node->type) { 8026 case XML_ELEMENT_NODE: 8027 case XML_TEXT_NODE: 8028 case XML_CDATA_SECTION_NODE: 8029 case XML_ENTITY_REF_NODE: 8030 case XML_ENTITY_NODE: 8031 case XML_PI_NODE: 8032 case XML_COMMENT_NODE: 8033 case XML_DTD_NODE: 8034 case XML_ELEMENT_DECL: 8035 case XML_ATTRIBUTE_DECL: 8036 case XML_ENTITY_DECL: 8037 case XML_NOTATION_NODE: 8038 case XML_XINCLUDE_START: 8039 case XML_XINCLUDE_END: 8040 if (ctxt->context->node->parent == NULL) 8041 return((xmlNodePtr) ctxt->context->doc); 8042 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) && 8043 ((ctxt->context->node->parent->name[0] == ' ') || 8044 (xmlStrEqual(ctxt->context->node->parent->name, 8045 BAD_CAST "fake node libxslt")))) 8046 return(NULL); 8047 return(ctxt->context->node->parent); 8048 case XML_ATTRIBUTE_NODE: { 8049 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node; 8050 8051 return(tmp->parent); 8052 } 8053 case XML_DOCUMENT_NODE: 8054 case XML_DOCUMENT_TYPE_NODE: 8055 case XML_DOCUMENT_FRAG_NODE: 8056 case XML_HTML_DOCUMENT_NODE: 8057 return(NULL); 8058 case XML_NAMESPACE_DECL: { 8059 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; 8060 8061 if ((ns->next != NULL) && 8062 (ns->next->type != XML_NAMESPACE_DECL)) 8063 return((xmlNodePtr) ns->next); 8064 /* Bad, how did that namespace end up here ? */ 8065 return(NULL); 8066 } 8067 } 8068 return(NULL); 8069 } 8070 if (cur == ctxt->context->doc->children) 8071 return((xmlNodePtr) ctxt->context->doc); 8072 if (cur == (xmlNodePtr) ctxt->context->doc) 8073 return(NULL); 8074 switch (cur->type) { 8075 case XML_ELEMENT_NODE: 8076 case XML_TEXT_NODE: 8077 case XML_CDATA_SECTION_NODE: 8078 case XML_ENTITY_REF_NODE: 8079 case XML_ENTITY_NODE: 8080 case XML_PI_NODE: 8081 case XML_COMMENT_NODE: 8082 case XML_NOTATION_NODE: 8083 case XML_DTD_NODE: 8084 case XML_ELEMENT_DECL: 8085 case XML_ATTRIBUTE_DECL: 8086 case XML_ENTITY_DECL: 8087 case XML_XINCLUDE_START: 8088 case XML_XINCLUDE_END: 8089 if (cur->parent == NULL) 8090 return(NULL); 8091 if ((cur->parent->type == XML_ELEMENT_NODE) && 8092 ((cur->parent->name[0] == ' ') || 8093 (xmlStrEqual(cur->parent->name, 8094 BAD_CAST "fake node libxslt")))) 8095 return(NULL); 8096 return(cur->parent); 8097 case XML_ATTRIBUTE_NODE: { 8098 xmlAttrPtr att = (xmlAttrPtr) cur; 8099 8100 return(att->parent); 8101 } 8102 case XML_NAMESPACE_DECL: { 8103 xmlNsPtr ns = (xmlNsPtr) cur; 8104 8105 if ((ns->next != NULL) && 8106 (ns->next->type != XML_NAMESPACE_DECL)) 8107 return((xmlNodePtr) ns->next); 8108 /* Bad, how did that namespace end up here ? */ 8109 return(NULL); 8110 } 8111 case XML_DOCUMENT_NODE: 8112 case XML_DOCUMENT_TYPE_NODE: 8113 case XML_DOCUMENT_FRAG_NODE: 8114 case XML_HTML_DOCUMENT_NODE: 8115 return(NULL); 8116 } 8117 return(NULL); 8118 } 8119 8120 /** 8121 * xmlXPathNextAncestorOrSelf: 8122 * @ctxt: the XPath Parser context 8123 * @cur: the current node in the traversal 8124 * 8125 * Traversal function for the "ancestor-or-self" direction 8126 * he ancestor-or-self axis contains the context node and ancestors of 8127 * the context node in reverse document order; thus the context node is 8128 * the first node on the axis, and the context node's parent the second; 8129 * parent here is defined the same as with the parent axis. 8130 * 8131 * Returns the next element following that axis 8132 */ 8133 xmlNodePtr 8134 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8135 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8136 if (cur == NULL) 8137 return(ctxt->context->node); 8138 return(xmlXPathNextAncestor(ctxt, cur)); 8139 } 8140 8141 /** 8142 * xmlXPathNextFollowingSibling: 8143 * @ctxt: the XPath Parser context 8144 * @cur: the current node in the traversal 8145 * 8146 * Traversal function for the "following-sibling" direction 8147 * The following-sibling axis contains the following siblings of the context 8148 * node in document order. 8149 * 8150 * Returns the next element following that axis 8151 */ 8152 xmlNodePtr 8153 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8154 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8155 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 8156 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 8157 return(NULL); 8158 if (cur == (xmlNodePtr) ctxt->context->doc) 8159 return(NULL); 8160 if (cur == NULL) 8161 return(ctxt->context->node->next); 8162 return(cur->next); 8163 } 8164 8165 /** 8166 * xmlXPathNextPrecedingSibling: 8167 * @ctxt: the XPath Parser context 8168 * @cur: the current node in the traversal 8169 * 8170 * Traversal function for the "preceding-sibling" direction 8171 * The preceding-sibling axis contains the preceding siblings of the context 8172 * node in reverse document order; the first preceding sibling is first on the 8173 * axis; the sibling preceding that node is the second on the axis and so on. 8174 * 8175 * Returns the next element following that axis 8176 */ 8177 xmlNodePtr 8178 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8179 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8180 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 8181 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 8182 return(NULL); 8183 if (cur == (xmlNodePtr) ctxt->context->doc) 8184 return(NULL); 8185 if (cur == NULL) 8186 return(ctxt->context->node->prev); 8187 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) { 8188 cur = cur->prev; 8189 if (cur == NULL) 8190 return(ctxt->context->node->prev); 8191 } 8192 return(cur->prev); 8193 } 8194 8195 /** 8196 * xmlXPathNextFollowing: 8197 * @ctxt: the XPath Parser context 8198 * @cur: the current node in the traversal 8199 * 8200 * Traversal function for the "following" direction 8201 * The following axis contains all nodes in the same document as the context 8202 * node that are after the context node in document order, excluding any 8203 * descendants and excluding attribute nodes and namespace nodes; the nodes 8204 * are ordered in document order 8205 * 8206 * Returns the next element following that axis 8207 */ 8208 xmlNodePtr 8209 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8210 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8211 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) && 8212 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL)) 8213 return(cur->children); 8214 8215 if (cur == NULL) { 8216 cur = ctxt->context->node; 8217 if (cur->type == XML_ATTRIBUTE_NODE) { 8218 cur = cur->parent; 8219 } else if (cur->type == XML_NAMESPACE_DECL) { 8220 xmlNsPtr ns = (xmlNsPtr) cur; 8221 8222 if ((ns->next == NULL) || 8223 (ns->next->type == XML_NAMESPACE_DECL)) 8224 return (NULL); 8225 cur = (xmlNodePtr) ns->next; 8226 } 8227 } 8228 if (cur == NULL) return(NULL) ; /* ERROR */ 8229 if (cur->next != NULL) return(cur->next) ; 8230 do { 8231 cur = cur->parent; 8232 if (cur == NULL) break; 8233 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL); 8234 if (cur->next != NULL) return(cur->next); 8235 } while (cur != NULL); 8236 return(cur); 8237 } 8238 8239 /* 8240 * xmlXPathIsAncestor: 8241 * @ancestor: the ancestor node 8242 * @node: the current node 8243 * 8244 * Check that @ancestor is a @node's ancestor 8245 * 8246 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise. 8247 */ 8248 static int 8249 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) { 8250 if ((ancestor == NULL) || (node == NULL)) return(0); 8251 if (node->type == XML_NAMESPACE_DECL) 8252 return(0); 8253 if (ancestor->type == XML_NAMESPACE_DECL) 8254 return(0); 8255 /* nodes need to be in the same document */ 8256 if (ancestor->doc != node->doc) return(0); 8257 /* avoid searching if ancestor or node is the root node */ 8258 if (ancestor == (xmlNodePtr) node->doc) return(1); 8259 if (node == (xmlNodePtr) ancestor->doc) return(0); 8260 while (node->parent != NULL) { 8261 if (node->parent == ancestor) 8262 return(1); 8263 node = node->parent; 8264 } 8265 return(0); 8266 } 8267 8268 /** 8269 * xmlXPathNextPreceding: 8270 * @ctxt: the XPath Parser context 8271 * @cur: the current node in the traversal 8272 * 8273 * Traversal function for the "preceding" direction 8274 * the preceding axis contains all nodes in the same document as the context 8275 * node that are before the context node in document order, excluding any 8276 * ancestors and excluding attribute nodes and namespace nodes; the nodes are 8277 * ordered in reverse document order 8278 * 8279 * Returns the next element following that axis 8280 */ 8281 xmlNodePtr 8282 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) 8283 { 8284 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8285 if (cur == NULL) { 8286 cur = ctxt->context->node; 8287 if (cur->type == XML_ATTRIBUTE_NODE) { 8288 cur = cur->parent; 8289 } else if (cur->type == XML_NAMESPACE_DECL) { 8290 xmlNsPtr ns = (xmlNsPtr) cur; 8291 8292 if ((ns->next == NULL) || 8293 (ns->next->type == XML_NAMESPACE_DECL)) 8294 return (NULL); 8295 cur = (xmlNodePtr) ns->next; 8296 } 8297 } 8298 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) 8299 return (NULL); 8300 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) 8301 cur = cur->prev; 8302 do { 8303 if (cur->prev != NULL) { 8304 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ; 8305 return (cur); 8306 } 8307 8308 cur = cur->parent; 8309 if (cur == NULL) 8310 return (NULL); 8311 if (cur == ctxt->context->doc->children) 8312 return (NULL); 8313 } while (xmlXPathIsAncestor(cur, ctxt->context->node)); 8314 return (cur); 8315 } 8316 8317 /** 8318 * xmlXPathNextPrecedingInternal: 8319 * @ctxt: the XPath Parser context 8320 * @cur: the current node in the traversal 8321 * 8322 * Traversal function for the "preceding" direction 8323 * the preceding axis contains all nodes in the same document as the context 8324 * node that are before the context node in document order, excluding any 8325 * ancestors and excluding attribute nodes and namespace nodes; the nodes are 8326 * ordered in reverse document order 8327 * This is a faster implementation but internal only since it requires a 8328 * state kept in the parser context: ctxt->ancestor. 8329 * 8330 * Returns the next element following that axis 8331 */ 8332 static xmlNodePtr 8333 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt, 8334 xmlNodePtr cur) 8335 { 8336 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8337 if (cur == NULL) { 8338 cur = ctxt->context->node; 8339 if (cur == NULL) 8340 return (NULL); 8341 if (cur->type == XML_ATTRIBUTE_NODE) { 8342 cur = cur->parent; 8343 } else if (cur->type == XML_NAMESPACE_DECL) { 8344 xmlNsPtr ns = (xmlNsPtr) cur; 8345 8346 if ((ns->next == NULL) || 8347 (ns->next->type == XML_NAMESPACE_DECL)) 8348 return (NULL); 8349 cur = (xmlNodePtr) ns->next; 8350 } 8351 ctxt->ancestor = cur->parent; 8352 } 8353 if (cur->type == XML_NAMESPACE_DECL) 8354 return(NULL); 8355 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) 8356 cur = cur->prev; 8357 while (cur->prev == NULL) { 8358 cur = cur->parent; 8359 if (cur == NULL) 8360 return (NULL); 8361 if (cur == ctxt->context->doc->children) 8362 return (NULL); 8363 if (cur != ctxt->ancestor) 8364 return (cur); 8365 ctxt->ancestor = cur->parent; 8366 } 8367 cur = cur->prev; 8368 while (cur->last != NULL) 8369 cur = cur->last; 8370 return (cur); 8371 } 8372 8373 /** 8374 * xmlXPathNextNamespace: 8375 * @ctxt: the XPath Parser context 8376 * @cur: the current attribute in the traversal 8377 * 8378 * Traversal function for the "namespace" direction 8379 * the namespace axis contains the namespace nodes of the context node; 8380 * the order of nodes on this axis is implementation-defined; the axis will 8381 * be empty unless the context node is an element 8382 * 8383 * We keep the XML namespace node at the end of the list. 8384 * 8385 * Returns the next element following that axis 8386 */ 8387 xmlNodePtr 8388 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8389 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8390 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL); 8391 if (cur == NULL) { 8392 if (ctxt->context->tmpNsList != NULL) 8393 xmlFree(ctxt->context->tmpNsList); 8394 ctxt->context->tmpNsList = 8395 xmlGetNsList(ctxt->context->doc, ctxt->context->node); 8396 ctxt->context->tmpNsNr = 0; 8397 if (ctxt->context->tmpNsList != NULL) { 8398 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) { 8399 ctxt->context->tmpNsNr++; 8400 } 8401 } 8402 return((xmlNodePtr) xmlXPathXMLNamespace); 8403 } 8404 if (ctxt->context->tmpNsNr > 0) { 8405 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr]; 8406 } else { 8407 if (ctxt->context->tmpNsList != NULL) 8408 xmlFree(ctxt->context->tmpNsList); 8409 ctxt->context->tmpNsList = NULL; 8410 return(NULL); 8411 } 8412 } 8413 8414 /** 8415 * xmlXPathNextAttribute: 8416 * @ctxt: the XPath Parser context 8417 * @cur: the current attribute in the traversal 8418 * 8419 * Traversal function for the "attribute" direction 8420 * TODO: support DTD inherited default attributes 8421 * 8422 * Returns the next element following that axis 8423 */ 8424 xmlNodePtr 8425 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8426 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8427 if (ctxt->context->node == NULL) 8428 return(NULL); 8429 if (ctxt->context->node->type != XML_ELEMENT_NODE) 8430 return(NULL); 8431 if (cur == NULL) { 8432 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc) 8433 return(NULL); 8434 return((xmlNodePtr)ctxt->context->node->properties); 8435 } 8436 return((xmlNodePtr)cur->next); 8437 } 8438 8439 /************************************************************************ 8440 * * 8441 * NodeTest Functions * 8442 * * 8443 ************************************************************************/ 8444 8445 #define IS_FUNCTION 200 8446 8447 8448 /************************************************************************ 8449 * * 8450 * Implicit tree core function library * 8451 * * 8452 ************************************************************************/ 8453 8454 /** 8455 * xmlXPathRoot: 8456 * @ctxt: the XPath Parser context 8457 * 8458 * Initialize the context to the root of the document 8459 */ 8460 void 8461 xmlXPathRoot(xmlXPathParserContextPtr ctxt) { 8462 if ((ctxt == NULL) || (ctxt->context == NULL)) 8463 return; 8464 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8465 (xmlNodePtr) ctxt->context->doc)); 8466 } 8467 8468 /************************************************************************ 8469 * * 8470 * The explicit core function library * 8471 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib * 8472 * * 8473 ************************************************************************/ 8474 8475 8476 /** 8477 * xmlXPathLastFunction: 8478 * @ctxt: the XPath Parser context 8479 * @nargs: the number of arguments 8480 * 8481 * Implement the last() XPath function 8482 * number last() 8483 * The last function returns the number of nodes in the context node list. 8484 */ 8485 void 8486 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8487 CHECK_ARITY(0); 8488 if (ctxt->context->contextSize >= 0) { 8489 valuePush(ctxt, 8490 xmlXPathCacheNewFloat(ctxt->context, 8491 (double) ctxt->context->contextSize)); 8492 #ifdef DEBUG_EXPR 8493 xmlGenericError(xmlGenericErrorContext, 8494 "last() : %d\n", ctxt->context->contextSize); 8495 #endif 8496 } else { 8497 XP_ERROR(XPATH_INVALID_CTXT_SIZE); 8498 } 8499 } 8500 8501 /** 8502 * xmlXPathPositionFunction: 8503 * @ctxt: the XPath Parser context 8504 * @nargs: the number of arguments 8505 * 8506 * Implement the position() XPath function 8507 * number position() 8508 * The position function returns the position of the context node in the 8509 * context node list. The first position is 1, and so the last position 8510 * will be equal to last(). 8511 */ 8512 void 8513 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8514 CHECK_ARITY(0); 8515 if (ctxt->context->proximityPosition >= 0) { 8516 valuePush(ctxt, 8517 xmlXPathCacheNewFloat(ctxt->context, 8518 (double) ctxt->context->proximityPosition)); 8519 #ifdef DEBUG_EXPR 8520 xmlGenericError(xmlGenericErrorContext, "position() : %d\n", 8521 ctxt->context->proximityPosition); 8522 #endif 8523 } else { 8524 XP_ERROR(XPATH_INVALID_CTXT_POSITION); 8525 } 8526 } 8527 8528 /** 8529 * xmlXPathCountFunction: 8530 * @ctxt: the XPath Parser context 8531 * @nargs: the number of arguments 8532 * 8533 * Implement the count() XPath function 8534 * number count(node-set) 8535 */ 8536 void 8537 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8538 xmlXPathObjectPtr cur; 8539 8540 CHECK_ARITY(1); 8541 if ((ctxt->value == NULL) || 8542 ((ctxt->value->type != XPATH_NODESET) && 8543 (ctxt->value->type != XPATH_XSLT_TREE))) 8544 XP_ERROR(XPATH_INVALID_TYPE); 8545 cur = valuePop(ctxt); 8546 8547 if ((cur == NULL) || (cur->nodesetval == NULL)) 8548 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0)); 8549 else 8550 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 8551 (double) cur->nodesetval->nodeNr)); 8552 xmlXPathReleaseObject(ctxt->context, cur); 8553 } 8554 8555 /** 8556 * xmlXPathGetElementsByIds: 8557 * @doc: the document 8558 * @ids: a whitespace separated list of IDs 8559 * 8560 * Selects elements by their unique ID. 8561 * 8562 * Returns a node-set of selected elements. 8563 */ 8564 static xmlNodeSetPtr 8565 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) { 8566 xmlNodeSetPtr ret; 8567 const xmlChar *cur = ids; 8568 xmlChar *ID; 8569 xmlAttrPtr attr; 8570 xmlNodePtr elem = NULL; 8571 8572 if (ids == NULL) return(NULL); 8573 8574 ret = xmlXPathNodeSetCreate(NULL); 8575 if (ret == NULL) 8576 return(ret); 8577 8578 while (IS_BLANK_CH(*cur)) cur++; 8579 while (*cur != 0) { 8580 while ((!IS_BLANK_CH(*cur)) && (*cur != 0)) 8581 cur++; 8582 8583 ID = xmlStrndup(ids, cur - ids); 8584 if (ID != NULL) { 8585 /* 8586 * We used to check the fact that the value passed 8587 * was an NCName, but this generated much troubles for 8588 * me and Aleksey Sanin, people blatantly violated that 8589 * constraint, like Visa3D spec. 8590 * if (xmlValidateNCName(ID, 1) == 0) 8591 */ 8592 attr = xmlGetID(doc, ID); 8593 if (attr != NULL) { 8594 if (attr->type == XML_ATTRIBUTE_NODE) 8595 elem = attr->parent; 8596 else if (attr->type == XML_ELEMENT_NODE) 8597 elem = (xmlNodePtr) attr; 8598 else 8599 elem = NULL; 8600 /* TODO: Check memory error. */ 8601 if (elem != NULL) 8602 xmlXPathNodeSetAdd(ret, elem); 8603 } 8604 xmlFree(ID); 8605 } 8606 8607 while (IS_BLANK_CH(*cur)) cur++; 8608 ids = cur; 8609 } 8610 return(ret); 8611 } 8612 8613 /** 8614 * xmlXPathIdFunction: 8615 * @ctxt: the XPath Parser context 8616 * @nargs: the number of arguments 8617 * 8618 * Implement the id() XPath function 8619 * node-set id(object) 8620 * The id function selects elements by their unique ID 8621 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set, 8622 * then the result is the union of the result of applying id to the 8623 * string value of each of the nodes in the argument node-set. When the 8624 * argument to id is of any other type, the argument is converted to a 8625 * string as if by a call to the string function; the string is split 8626 * into a whitespace-separated list of tokens (whitespace is any sequence 8627 * of characters matching the production S); the result is a node-set 8628 * containing the elements in the same document as the context node that 8629 * have a unique ID equal to any of the tokens in the list. 8630 */ 8631 void 8632 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8633 xmlChar *tokens; 8634 xmlNodeSetPtr ret; 8635 xmlXPathObjectPtr obj; 8636 8637 CHECK_ARITY(1); 8638 obj = valuePop(ctxt); 8639 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 8640 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) { 8641 xmlNodeSetPtr ns; 8642 int i; 8643 8644 /* TODO: Check memory error. */ 8645 ret = xmlXPathNodeSetCreate(NULL); 8646 8647 if (obj->nodesetval != NULL) { 8648 for (i = 0; i < obj->nodesetval->nodeNr; i++) { 8649 tokens = 8650 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]); 8651 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens); 8652 /* TODO: Check memory error. */ 8653 ret = xmlXPathNodeSetMerge(ret, ns); 8654 xmlXPathFreeNodeSet(ns); 8655 if (tokens != NULL) 8656 xmlFree(tokens); 8657 } 8658 } 8659 xmlXPathReleaseObject(ctxt->context, obj); 8660 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret)); 8661 return; 8662 } 8663 obj = xmlXPathCacheConvertString(ctxt->context, obj); 8664 if (obj == NULL) return; 8665 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval); 8666 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret)); 8667 xmlXPathReleaseObject(ctxt->context, obj); 8668 return; 8669 } 8670 8671 /** 8672 * xmlXPathLocalNameFunction: 8673 * @ctxt: the XPath Parser context 8674 * @nargs: the number of arguments 8675 * 8676 * Implement the local-name() XPath function 8677 * string local-name(node-set?) 8678 * The local-name function returns a string containing the local part 8679 * of the name of the node in the argument node-set that is first in 8680 * document order. If the node-set is empty or the first node has no 8681 * name, an empty string is returned. If the argument is omitted it 8682 * defaults to the context node. 8683 */ 8684 void 8685 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8686 xmlXPathObjectPtr cur; 8687 8688 if (ctxt == NULL) return; 8689 8690 if (nargs == 0) { 8691 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8692 ctxt->context->node)); 8693 nargs = 1; 8694 } 8695 8696 CHECK_ARITY(1); 8697 if ((ctxt->value == NULL) || 8698 ((ctxt->value->type != XPATH_NODESET) && 8699 (ctxt->value->type != XPATH_XSLT_TREE))) 8700 XP_ERROR(XPATH_INVALID_TYPE); 8701 cur = valuePop(ctxt); 8702 8703 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 8704 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8705 } else { 8706 int i = 0; /* Should be first in document order !!!!! */ 8707 switch (cur->nodesetval->nodeTab[i]->type) { 8708 case XML_ELEMENT_NODE: 8709 case XML_ATTRIBUTE_NODE: 8710 case XML_PI_NODE: 8711 if (cur->nodesetval->nodeTab[i]->name[0] == ' ') 8712 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8713 else 8714 valuePush(ctxt, 8715 xmlXPathCacheNewString(ctxt->context, 8716 cur->nodesetval->nodeTab[i]->name)); 8717 break; 8718 case XML_NAMESPACE_DECL: 8719 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 8720 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix)); 8721 break; 8722 default: 8723 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8724 } 8725 } 8726 xmlXPathReleaseObject(ctxt->context, cur); 8727 } 8728 8729 /** 8730 * xmlXPathNamespaceURIFunction: 8731 * @ctxt: the XPath Parser context 8732 * @nargs: the number of arguments 8733 * 8734 * Implement the namespace-uri() XPath function 8735 * string namespace-uri(node-set?) 8736 * The namespace-uri function returns a string containing the 8737 * namespace URI of the expanded name of the node in the argument 8738 * node-set that is first in document order. If the node-set is empty, 8739 * the first node has no name, or the expanded name has no namespace 8740 * URI, an empty string is returned. If the argument is omitted it 8741 * defaults to the context node. 8742 */ 8743 void 8744 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8745 xmlXPathObjectPtr cur; 8746 8747 if (ctxt == NULL) return; 8748 8749 if (nargs == 0) { 8750 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8751 ctxt->context->node)); 8752 nargs = 1; 8753 } 8754 CHECK_ARITY(1); 8755 if ((ctxt->value == NULL) || 8756 ((ctxt->value->type != XPATH_NODESET) && 8757 (ctxt->value->type != XPATH_XSLT_TREE))) 8758 XP_ERROR(XPATH_INVALID_TYPE); 8759 cur = valuePop(ctxt); 8760 8761 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 8762 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8763 } else { 8764 int i = 0; /* Should be first in document order !!!!! */ 8765 switch (cur->nodesetval->nodeTab[i]->type) { 8766 case XML_ELEMENT_NODE: 8767 case XML_ATTRIBUTE_NODE: 8768 if (cur->nodesetval->nodeTab[i]->ns == NULL) 8769 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8770 else 8771 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 8772 cur->nodesetval->nodeTab[i]->ns->href)); 8773 break; 8774 default: 8775 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8776 } 8777 } 8778 xmlXPathReleaseObject(ctxt->context, cur); 8779 } 8780 8781 /** 8782 * xmlXPathNameFunction: 8783 * @ctxt: the XPath Parser context 8784 * @nargs: the number of arguments 8785 * 8786 * Implement the name() XPath function 8787 * string name(node-set?) 8788 * The name function returns a string containing a QName representing 8789 * the name of the node in the argument node-set that is first in document 8790 * order. The QName must represent the name with respect to the namespace 8791 * declarations in effect on the node whose name is being represented. 8792 * Typically, this will be the form in which the name occurred in the XML 8793 * source. This need not be the case if there are namespace declarations 8794 * in effect on the node that associate multiple prefixes with the same 8795 * namespace. However, an implementation may include information about 8796 * the original prefix in its representation of nodes; in this case, an 8797 * implementation can ensure that the returned string is always the same 8798 * as the QName used in the XML source. If the argument it omitted it 8799 * defaults to the context node. 8800 * Libxml keep the original prefix so the "real qualified name" used is 8801 * returned. 8802 */ 8803 static void 8804 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) 8805 { 8806 xmlXPathObjectPtr cur; 8807 8808 if (nargs == 0) { 8809 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8810 ctxt->context->node)); 8811 nargs = 1; 8812 } 8813 8814 CHECK_ARITY(1); 8815 if ((ctxt->value == NULL) || 8816 ((ctxt->value->type != XPATH_NODESET) && 8817 (ctxt->value->type != XPATH_XSLT_TREE))) 8818 XP_ERROR(XPATH_INVALID_TYPE); 8819 cur = valuePop(ctxt); 8820 8821 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 8822 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8823 } else { 8824 int i = 0; /* Should be first in document order !!!!! */ 8825 8826 switch (cur->nodesetval->nodeTab[i]->type) { 8827 case XML_ELEMENT_NODE: 8828 case XML_ATTRIBUTE_NODE: 8829 if (cur->nodesetval->nodeTab[i]->name[0] == ' ') 8830 valuePush(ctxt, 8831 xmlXPathCacheNewCString(ctxt->context, "")); 8832 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) || 8833 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) { 8834 valuePush(ctxt, 8835 xmlXPathCacheNewString(ctxt->context, 8836 cur->nodesetval->nodeTab[i]->name)); 8837 } else { 8838 xmlChar *fullname; 8839 8840 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name, 8841 cur->nodesetval->nodeTab[i]->ns->prefix, 8842 NULL, 0); 8843 if (fullname == cur->nodesetval->nodeTab[i]->name) 8844 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name); 8845 if (fullname == NULL) { 8846 XP_ERROR(XPATH_MEMORY_ERROR); 8847 } 8848 valuePush(ctxt, xmlXPathCacheWrapString( 8849 ctxt->context, fullname)); 8850 } 8851 break; 8852 default: 8853 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8854 cur->nodesetval->nodeTab[i])); 8855 xmlXPathLocalNameFunction(ctxt, 1); 8856 } 8857 } 8858 xmlXPathReleaseObject(ctxt->context, cur); 8859 } 8860 8861 8862 /** 8863 * xmlXPathStringFunction: 8864 * @ctxt: the XPath Parser context 8865 * @nargs: the number of arguments 8866 * 8867 * Implement the string() XPath function 8868 * string string(object?) 8869 * The string function converts an object to a string as follows: 8870 * - A node-set is converted to a string by returning the value of 8871 * the node in the node-set that is first in document order. 8872 * If the node-set is empty, an empty string is returned. 8873 * - A number is converted to a string as follows 8874 * + NaN is converted to the string NaN 8875 * + positive zero is converted to the string 0 8876 * + negative zero is converted to the string 0 8877 * + positive infinity is converted to the string Infinity 8878 * + negative infinity is converted to the string -Infinity 8879 * + if the number is an integer, the number is represented in 8880 * decimal form as a Number with no decimal point and no leading 8881 * zeros, preceded by a minus sign (-) if the number is negative 8882 * + otherwise, the number is represented in decimal form as a 8883 * Number including a decimal point with at least one digit 8884 * before the decimal point and at least one digit after the 8885 * decimal point, preceded by a minus sign (-) if the number 8886 * is negative; there must be no leading zeros before the decimal 8887 * point apart possibly from the one required digit immediately 8888 * before the decimal point; beyond the one required digit 8889 * after the decimal point there must be as many, but only as 8890 * many, more digits as are needed to uniquely distinguish the 8891 * number from all other IEEE 754 numeric values. 8892 * - The boolean false value is converted to the string false. 8893 * The boolean true value is converted to the string true. 8894 * 8895 * If the argument is omitted, it defaults to a node-set with the 8896 * context node as its only member. 8897 */ 8898 void 8899 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8900 xmlXPathObjectPtr cur; 8901 8902 if (ctxt == NULL) return; 8903 if (nargs == 0) { 8904 valuePush(ctxt, 8905 xmlXPathCacheWrapString(ctxt->context, 8906 xmlXPathCastNodeToString(ctxt->context->node))); 8907 return; 8908 } 8909 8910 CHECK_ARITY(1); 8911 cur = valuePop(ctxt); 8912 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 8913 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur)); 8914 } 8915 8916 /** 8917 * xmlXPathStringLengthFunction: 8918 * @ctxt: the XPath Parser context 8919 * @nargs: the number of arguments 8920 * 8921 * Implement the string-length() XPath function 8922 * number string-length(string?) 8923 * The string-length returns the number of characters in the string 8924 * (see [3.6 Strings]). If the argument is omitted, it defaults to 8925 * the context node converted to a string, in other words the value 8926 * of the context node. 8927 */ 8928 void 8929 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8930 xmlXPathObjectPtr cur; 8931 8932 if (nargs == 0) { 8933 if ((ctxt == NULL) || (ctxt->context == NULL)) 8934 return; 8935 if (ctxt->context->node == NULL) { 8936 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0)); 8937 } else { 8938 xmlChar *content; 8939 8940 content = xmlXPathCastNodeToString(ctxt->context->node); 8941 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 8942 xmlUTF8Strlen(content))); 8943 xmlFree(content); 8944 } 8945 return; 8946 } 8947 CHECK_ARITY(1); 8948 CAST_TO_STRING; 8949 CHECK_TYPE(XPATH_STRING); 8950 cur = valuePop(ctxt); 8951 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 8952 xmlUTF8Strlen(cur->stringval))); 8953 xmlXPathReleaseObject(ctxt->context, cur); 8954 } 8955 8956 /** 8957 * xmlXPathConcatFunction: 8958 * @ctxt: the XPath Parser context 8959 * @nargs: the number of arguments 8960 * 8961 * Implement the concat() XPath function 8962 * string concat(string, string, string*) 8963 * The concat function returns the concatenation of its arguments. 8964 */ 8965 void 8966 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8967 xmlXPathObjectPtr cur, newobj; 8968 xmlChar *tmp; 8969 8970 if (ctxt == NULL) return; 8971 if (nargs < 2) { 8972 CHECK_ARITY(2); 8973 } 8974 8975 CAST_TO_STRING; 8976 cur = valuePop(ctxt); 8977 if ((cur == NULL) || (cur->type != XPATH_STRING)) { 8978 xmlXPathReleaseObject(ctxt->context, cur); 8979 return; 8980 } 8981 nargs--; 8982 8983 while (nargs > 0) { 8984 CAST_TO_STRING; 8985 newobj = valuePop(ctxt); 8986 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) { 8987 xmlXPathReleaseObject(ctxt->context, newobj); 8988 xmlXPathReleaseObject(ctxt->context, cur); 8989 XP_ERROR(XPATH_INVALID_TYPE); 8990 } 8991 tmp = xmlStrcat(newobj->stringval, cur->stringval); 8992 newobj->stringval = cur->stringval; 8993 cur->stringval = tmp; 8994 xmlXPathReleaseObject(ctxt->context, newobj); 8995 nargs--; 8996 } 8997 valuePush(ctxt, cur); 8998 } 8999 9000 /** 9001 * xmlXPathContainsFunction: 9002 * @ctxt: the XPath Parser context 9003 * @nargs: the number of arguments 9004 * 9005 * Implement the contains() XPath function 9006 * boolean contains(string, string) 9007 * The contains function returns true if the first argument string 9008 * contains the second argument string, and otherwise returns false. 9009 */ 9010 void 9011 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9012 xmlXPathObjectPtr hay, needle; 9013 9014 CHECK_ARITY(2); 9015 CAST_TO_STRING; 9016 CHECK_TYPE(XPATH_STRING); 9017 needle = valuePop(ctxt); 9018 CAST_TO_STRING; 9019 hay = valuePop(ctxt); 9020 9021 if ((hay == NULL) || (hay->type != XPATH_STRING)) { 9022 xmlXPathReleaseObject(ctxt->context, hay); 9023 xmlXPathReleaseObject(ctxt->context, needle); 9024 XP_ERROR(XPATH_INVALID_TYPE); 9025 } 9026 if (xmlStrstr(hay->stringval, needle->stringval)) 9027 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); 9028 else 9029 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); 9030 xmlXPathReleaseObject(ctxt->context, hay); 9031 xmlXPathReleaseObject(ctxt->context, needle); 9032 } 9033 9034 /** 9035 * xmlXPathStartsWithFunction: 9036 * @ctxt: the XPath Parser context 9037 * @nargs: the number of arguments 9038 * 9039 * Implement the starts-with() XPath function 9040 * boolean starts-with(string, string) 9041 * The starts-with function returns true if the first argument string 9042 * starts with the second argument string, and otherwise returns false. 9043 */ 9044 void 9045 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9046 xmlXPathObjectPtr hay, needle; 9047 int n; 9048 9049 CHECK_ARITY(2); 9050 CAST_TO_STRING; 9051 CHECK_TYPE(XPATH_STRING); 9052 needle = valuePop(ctxt); 9053 CAST_TO_STRING; 9054 hay = valuePop(ctxt); 9055 9056 if ((hay == NULL) || (hay->type != XPATH_STRING)) { 9057 xmlXPathReleaseObject(ctxt->context, hay); 9058 xmlXPathReleaseObject(ctxt->context, needle); 9059 XP_ERROR(XPATH_INVALID_TYPE); 9060 } 9061 n = xmlStrlen(needle->stringval); 9062 if (xmlStrncmp(hay->stringval, needle->stringval, n)) 9063 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); 9064 else 9065 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); 9066 xmlXPathReleaseObject(ctxt->context, hay); 9067 xmlXPathReleaseObject(ctxt->context, needle); 9068 } 9069 9070 /** 9071 * xmlXPathSubstringFunction: 9072 * @ctxt: the XPath Parser context 9073 * @nargs: the number of arguments 9074 * 9075 * Implement the substring() XPath function 9076 * string substring(string, number, number?) 9077 * The substring function returns the substring of the first argument 9078 * starting at the position specified in the second argument with 9079 * length specified in the third argument. For example, 9080 * substring("12345",2,3) returns "234". If the third argument is not 9081 * specified, it returns the substring starting at the position specified 9082 * in the second argument and continuing to the end of the string. For 9083 * example, substring("12345",2) returns "2345". More precisely, each 9084 * character in the string (see [3.6 Strings]) is considered to have a 9085 * numeric position: the position of the first character is 1, the position 9086 * of the second character is 2 and so on. The returned substring contains 9087 * those characters for which the position of the character is greater than 9088 * or equal to the second argument and, if the third argument is specified, 9089 * less than the sum of the second and third arguments; the comparisons 9090 * and addition used for the above follow the standard IEEE 754 rules. Thus: 9091 * - substring("12345", 1.5, 2.6) returns "234" 9092 * - substring("12345", 0, 3) returns "12" 9093 * - substring("12345", 0 div 0, 3) returns "" 9094 * - substring("12345", 1, 0 div 0) returns "" 9095 * - substring("12345", -42, 1 div 0) returns "12345" 9096 * - substring("12345", -1 div 0, 1 div 0) returns "" 9097 */ 9098 void 9099 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9100 xmlXPathObjectPtr str, start, len; 9101 double le=0, in; 9102 int i = 1, j = INT_MAX; 9103 9104 if (nargs < 2) { 9105 CHECK_ARITY(2); 9106 } 9107 if (nargs > 3) { 9108 CHECK_ARITY(3); 9109 } 9110 /* 9111 * take care of possible last (position) argument 9112 */ 9113 if (nargs == 3) { 9114 CAST_TO_NUMBER; 9115 CHECK_TYPE(XPATH_NUMBER); 9116 len = valuePop(ctxt); 9117 le = len->floatval; 9118 xmlXPathReleaseObject(ctxt->context, len); 9119 } 9120 9121 CAST_TO_NUMBER; 9122 CHECK_TYPE(XPATH_NUMBER); 9123 start = valuePop(ctxt); 9124 in = start->floatval; 9125 xmlXPathReleaseObject(ctxt->context, start); 9126 CAST_TO_STRING; 9127 CHECK_TYPE(XPATH_STRING); 9128 str = valuePop(ctxt); 9129 9130 if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */ 9131 i = INT_MAX; 9132 } else if (in >= 1.0) { 9133 i = (int)in; 9134 if (in - floor(in) >= 0.5) 9135 i += 1; 9136 } 9137 9138 if (nargs == 3) { 9139 double rin, rle, end; 9140 9141 rin = floor(in); 9142 if (in - rin >= 0.5) 9143 rin += 1.0; 9144 9145 rle = floor(le); 9146 if (le - rle >= 0.5) 9147 rle += 1.0; 9148 9149 end = rin + rle; 9150 if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */ 9151 j = 1; 9152 } else if (end < INT_MAX) { 9153 j = (int)end; 9154 } 9155 } 9156 9157 if (i < j) { 9158 xmlChar *ret = xmlUTF8Strsub(str->stringval, i - 1, j - i); 9159 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret)); 9160 xmlFree(ret); 9161 } else { 9162 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 9163 } 9164 9165 xmlXPathReleaseObject(ctxt->context, str); 9166 } 9167 9168 /** 9169 * xmlXPathSubstringBeforeFunction: 9170 * @ctxt: the XPath Parser context 9171 * @nargs: the number of arguments 9172 * 9173 * Implement the substring-before() XPath function 9174 * string substring-before(string, string) 9175 * The substring-before function returns the substring of the first 9176 * argument string that precedes the first occurrence of the second 9177 * argument string in the first argument string, or the empty string 9178 * if the first argument string does not contain the second argument 9179 * string. For example, substring-before("1999/04/01","/") returns 1999. 9180 */ 9181 void 9182 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9183 xmlXPathObjectPtr str; 9184 xmlXPathObjectPtr find; 9185 xmlBufPtr target; 9186 const xmlChar *point; 9187 int offset; 9188 9189 CHECK_ARITY(2); 9190 CAST_TO_STRING; 9191 find = valuePop(ctxt); 9192 CAST_TO_STRING; 9193 str = valuePop(ctxt); 9194 9195 target = xmlBufCreate(); 9196 if (target) { 9197 point = xmlStrstr(str->stringval, find->stringval); 9198 if (point) { 9199 offset = (int)(point - str->stringval); 9200 xmlBufAdd(target, str->stringval, offset); 9201 } 9202 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9203 xmlBufContent(target))); 9204 xmlBufFree(target); 9205 } 9206 xmlXPathReleaseObject(ctxt->context, str); 9207 xmlXPathReleaseObject(ctxt->context, find); 9208 } 9209 9210 /** 9211 * xmlXPathSubstringAfterFunction: 9212 * @ctxt: the XPath Parser context 9213 * @nargs: the number of arguments 9214 * 9215 * Implement the substring-after() XPath function 9216 * string substring-after(string, string) 9217 * The substring-after function returns the substring of the first 9218 * argument string that follows the first occurrence of the second 9219 * argument string in the first argument string, or the empty stringi 9220 * if the first argument string does not contain the second argument 9221 * string. For example, substring-after("1999/04/01","/") returns 04/01, 9222 * and substring-after("1999/04/01","19") returns 99/04/01. 9223 */ 9224 void 9225 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9226 xmlXPathObjectPtr str; 9227 xmlXPathObjectPtr find; 9228 xmlBufPtr target; 9229 const xmlChar *point; 9230 int offset; 9231 9232 CHECK_ARITY(2); 9233 CAST_TO_STRING; 9234 find = valuePop(ctxt); 9235 CAST_TO_STRING; 9236 str = valuePop(ctxt); 9237 9238 target = xmlBufCreate(); 9239 if (target) { 9240 point = xmlStrstr(str->stringval, find->stringval); 9241 if (point) { 9242 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval); 9243 xmlBufAdd(target, &str->stringval[offset], 9244 xmlStrlen(str->stringval) - offset); 9245 } 9246 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9247 xmlBufContent(target))); 9248 xmlBufFree(target); 9249 } 9250 xmlXPathReleaseObject(ctxt->context, str); 9251 xmlXPathReleaseObject(ctxt->context, find); 9252 } 9253 9254 /** 9255 * xmlXPathNormalizeFunction: 9256 * @ctxt: the XPath Parser context 9257 * @nargs: the number of arguments 9258 * 9259 * Implement the normalize-space() XPath function 9260 * string normalize-space(string?) 9261 * The normalize-space function returns the argument string with white 9262 * space normalized by stripping leading and trailing whitespace 9263 * and replacing sequences of whitespace characters by a single 9264 * space. Whitespace characters are the same allowed by the S production 9265 * in XML. If the argument is omitted, it defaults to the context 9266 * node converted to a string, in other words the value of the context node. 9267 */ 9268 void 9269 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9270 xmlChar *source, *target; 9271 int blank; 9272 9273 if (ctxt == NULL) return; 9274 if (nargs == 0) { 9275 /* Use current context node */ 9276 valuePush(ctxt, 9277 xmlXPathCacheWrapString(ctxt->context, 9278 xmlXPathCastNodeToString(ctxt->context->node))); 9279 nargs = 1; 9280 } 9281 9282 CHECK_ARITY(1); 9283 CAST_TO_STRING; 9284 CHECK_TYPE(XPATH_STRING); 9285 source = ctxt->value->stringval; 9286 if (source == NULL) 9287 return; 9288 target = source; 9289 9290 /* Skip leading whitespaces */ 9291 while (IS_BLANK_CH(*source)) 9292 source++; 9293 9294 /* Collapse intermediate whitespaces, and skip trailing whitespaces */ 9295 blank = 0; 9296 while (*source) { 9297 if (IS_BLANK_CH(*source)) { 9298 blank = 1; 9299 } else { 9300 if (blank) { 9301 *target++ = 0x20; 9302 blank = 0; 9303 } 9304 *target++ = *source; 9305 } 9306 source++; 9307 } 9308 *target = 0; 9309 } 9310 9311 /** 9312 * xmlXPathTranslateFunction: 9313 * @ctxt: the XPath Parser context 9314 * @nargs: the number of arguments 9315 * 9316 * Implement the translate() XPath function 9317 * string translate(string, string, string) 9318 * The translate function returns the first argument string with 9319 * occurrences of characters in the second argument string replaced 9320 * by the character at the corresponding position in the third argument 9321 * string. For example, translate("bar","abc","ABC") returns the string 9322 * BAr. If there is a character in the second argument string with no 9323 * character at a corresponding position in the third argument string 9324 * (because the second argument string is longer than the third argument 9325 * string), then occurrences of that character in the first argument 9326 * string are removed. For example, translate("--aaa--","abc-","ABC") 9327 * returns "AAA". If a character occurs more than once in second 9328 * argument string, then the first occurrence determines the replacement 9329 * character. If the third argument string is longer than the second 9330 * argument string, then excess characters are ignored. 9331 */ 9332 void 9333 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9334 xmlXPathObjectPtr str; 9335 xmlXPathObjectPtr from; 9336 xmlXPathObjectPtr to; 9337 xmlBufPtr target; 9338 int offset, max; 9339 xmlChar ch; 9340 const xmlChar *point; 9341 xmlChar *cptr; 9342 9343 CHECK_ARITY(3); 9344 9345 CAST_TO_STRING; 9346 to = valuePop(ctxt); 9347 CAST_TO_STRING; 9348 from = valuePop(ctxt); 9349 CAST_TO_STRING; 9350 str = valuePop(ctxt); 9351 9352 target = xmlBufCreate(); 9353 if (target) { 9354 max = xmlUTF8Strlen(to->stringval); 9355 for (cptr = str->stringval; (ch=*cptr); ) { 9356 offset = xmlUTF8Strloc(from->stringval, cptr); 9357 if (offset >= 0) { 9358 if (offset < max) { 9359 point = xmlUTF8Strpos(to->stringval, offset); 9360 if (point) 9361 xmlBufAdd(target, point, xmlUTF8Strsize(point, 1)); 9362 } 9363 } else 9364 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1)); 9365 9366 /* Step to next character in input */ 9367 cptr++; 9368 if ( ch & 0x80 ) { 9369 /* if not simple ascii, verify proper format */ 9370 if ( (ch & 0xc0) != 0xc0 ) { 9371 xmlGenericError(xmlGenericErrorContext, 9372 "xmlXPathTranslateFunction: Invalid UTF8 string\n"); 9373 /* not asserting an XPath error is probably better */ 9374 break; 9375 } 9376 /* then skip over remaining bytes for this char */ 9377 while ( (ch <<= 1) & 0x80 ) 9378 if ( (*cptr++ & 0xc0) != 0x80 ) { 9379 xmlGenericError(xmlGenericErrorContext, 9380 "xmlXPathTranslateFunction: Invalid UTF8 string\n"); 9381 /* not asserting an XPath error is probably better */ 9382 break; 9383 } 9384 if (ch & 0x80) /* must have had error encountered */ 9385 break; 9386 } 9387 } 9388 } 9389 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9390 xmlBufContent(target))); 9391 xmlBufFree(target); 9392 xmlXPathReleaseObject(ctxt->context, str); 9393 xmlXPathReleaseObject(ctxt->context, from); 9394 xmlXPathReleaseObject(ctxt->context, to); 9395 } 9396 9397 /** 9398 * xmlXPathBooleanFunction: 9399 * @ctxt: the XPath Parser context 9400 * @nargs: the number of arguments 9401 * 9402 * Implement the boolean() XPath function 9403 * boolean boolean(object) 9404 * The boolean function converts its argument to a boolean as follows: 9405 * - a number is true if and only if it is neither positive or 9406 * negative zero nor NaN 9407 * - a node-set is true if and only if it is non-empty 9408 * - a string is true if and only if its length is non-zero 9409 */ 9410 void 9411 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9412 xmlXPathObjectPtr cur; 9413 9414 CHECK_ARITY(1); 9415 cur = valuePop(ctxt); 9416 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 9417 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur); 9418 valuePush(ctxt, cur); 9419 } 9420 9421 /** 9422 * xmlXPathNotFunction: 9423 * @ctxt: the XPath Parser context 9424 * @nargs: the number of arguments 9425 * 9426 * Implement the not() XPath function 9427 * boolean not(boolean) 9428 * The not function returns true if its argument is false, 9429 * and false otherwise. 9430 */ 9431 void 9432 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9433 CHECK_ARITY(1); 9434 CAST_TO_BOOLEAN; 9435 CHECK_TYPE(XPATH_BOOLEAN); 9436 ctxt->value->boolval = ! ctxt->value->boolval; 9437 } 9438 9439 /** 9440 * xmlXPathTrueFunction: 9441 * @ctxt: the XPath Parser context 9442 * @nargs: the number of arguments 9443 * 9444 * Implement the true() XPath function 9445 * boolean true() 9446 */ 9447 void 9448 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9449 CHECK_ARITY(0); 9450 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); 9451 } 9452 9453 /** 9454 * xmlXPathFalseFunction: 9455 * @ctxt: the XPath Parser context 9456 * @nargs: the number of arguments 9457 * 9458 * Implement the false() XPath function 9459 * boolean false() 9460 */ 9461 void 9462 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9463 CHECK_ARITY(0); 9464 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); 9465 } 9466 9467 /** 9468 * xmlXPathLangFunction: 9469 * @ctxt: the XPath Parser context 9470 * @nargs: the number of arguments 9471 * 9472 * Implement the lang() XPath function 9473 * boolean lang(string) 9474 * The lang function returns true or false depending on whether the 9475 * language of the context node as specified by xml:lang attributes 9476 * is the same as or is a sublanguage of the language specified by 9477 * the argument string. The language of the context node is determined 9478 * by the value of the xml:lang attribute on the context node, or, if 9479 * the context node has no xml:lang attribute, by the value of the 9480 * xml:lang attribute on the nearest ancestor of the context node that 9481 * has an xml:lang attribute. If there is no such attribute, then lang 9482 * returns false. If there is such an attribute, then lang returns 9483 * true if the attribute value is equal to the argument ignoring case, 9484 * or if there is some suffix starting with - such that the attribute 9485 * value is equal to the argument ignoring that suffix of the attribute 9486 * value and ignoring case. 9487 */ 9488 void 9489 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9490 xmlXPathObjectPtr val = NULL; 9491 const xmlChar *theLang = NULL; 9492 const xmlChar *lang; 9493 int ret = 0; 9494 int i; 9495 9496 CHECK_ARITY(1); 9497 CAST_TO_STRING; 9498 CHECK_TYPE(XPATH_STRING); 9499 val = valuePop(ctxt); 9500 lang = val->stringval; 9501 theLang = xmlNodeGetLang(ctxt->context->node); 9502 if ((theLang != NULL) && (lang != NULL)) { 9503 for (i = 0;lang[i] != 0;i++) 9504 if (toupper(lang[i]) != toupper(theLang[i])) 9505 goto not_equal; 9506 if ((theLang[i] == 0) || (theLang[i] == '-')) 9507 ret = 1; 9508 } 9509 not_equal: 9510 if (theLang != NULL) 9511 xmlFree((void *)theLang); 9512 9513 xmlXPathReleaseObject(ctxt->context, val); 9514 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret)); 9515 } 9516 9517 /** 9518 * xmlXPathNumberFunction: 9519 * @ctxt: the XPath Parser context 9520 * @nargs: the number of arguments 9521 * 9522 * Implement the number() XPath function 9523 * number number(object?) 9524 */ 9525 void 9526 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9527 xmlXPathObjectPtr cur; 9528 double res; 9529 9530 if (ctxt == NULL) return; 9531 if (nargs == 0) { 9532 if (ctxt->context->node == NULL) { 9533 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0)); 9534 } else { 9535 xmlChar* content = xmlNodeGetContent(ctxt->context->node); 9536 9537 res = xmlXPathStringEvalNumber(content); 9538 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res)); 9539 xmlFree(content); 9540 } 9541 return; 9542 } 9543 9544 CHECK_ARITY(1); 9545 cur = valuePop(ctxt); 9546 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur)); 9547 } 9548 9549 /** 9550 * xmlXPathSumFunction: 9551 * @ctxt: the XPath Parser context 9552 * @nargs: the number of arguments 9553 * 9554 * Implement the sum() XPath function 9555 * number sum(node-set) 9556 * The sum function returns the sum of the values of the nodes in 9557 * the argument node-set. 9558 */ 9559 void 9560 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9561 xmlXPathObjectPtr cur; 9562 int i; 9563 double res = 0.0; 9564 9565 CHECK_ARITY(1); 9566 if ((ctxt->value == NULL) || 9567 ((ctxt->value->type != XPATH_NODESET) && 9568 (ctxt->value->type != XPATH_XSLT_TREE))) 9569 XP_ERROR(XPATH_INVALID_TYPE); 9570 cur = valuePop(ctxt); 9571 9572 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) { 9573 for (i = 0; i < cur->nodesetval->nodeNr; i++) { 9574 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]); 9575 } 9576 } 9577 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res)); 9578 xmlXPathReleaseObject(ctxt->context, cur); 9579 } 9580 9581 /** 9582 * xmlXPathFloorFunction: 9583 * @ctxt: the XPath Parser context 9584 * @nargs: the number of arguments 9585 * 9586 * Implement the floor() XPath function 9587 * number floor(number) 9588 * The floor function returns the largest (closest to positive infinity) 9589 * number that is not greater than the argument and that is an integer. 9590 */ 9591 void 9592 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9593 CHECK_ARITY(1); 9594 CAST_TO_NUMBER; 9595 CHECK_TYPE(XPATH_NUMBER); 9596 9597 ctxt->value->floatval = floor(ctxt->value->floatval); 9598 } 9599 9600 /** 9601 * xmlXPathCeilingFunction: 9602 * @ctxt: the XPath Parser context 9603 * @nargs: the number of arguments 9604 * 9605 * Implement the ceiling() XPath function 9606 * number ceiling(number) 9607 * The ceiling function returns the smallest (closest to negative infinity) 9608 * number that is not less than the argument and that is an integer. 9609 */ 9610 void 9611 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9612 CHECK_ARITY(1); 9613 CAST_TO_NUMBER; 9614 CHECK_TYPE(XPATH_NUMBER); 9615 9616 #ifdef _AIX 9617 /* Work around buggy ceil() function on AIX */ 9618 ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval); 9619 #else 9620 ctxt->value->floatval = ceil(ctxt->value->floatval); 9621 #endif 9622 } 9623 9624 /** 9625 * xmlXPathRoundFunction: 9626 * @ctxt: the XPath Parser context 9627 * @nargs: the number of arguments 9628 * 9629 * Implement the round() XPath function 9630 * number round(number) 9631 * The round function returns the number that is closest to the 9632 * argument and that is an integer. If there are two such numbers, 9633 * then the one that is closest to positive infinity is returned. 9634 */ 9635 void 9636 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9637 double f; 9638 9639 CHECK_ARITY(1); 9640 CAST_TO_NUMBER; 9641 CHECK_TYPE(XPATH_NUMBER); 9642 9643 f = ctxt->value->floatval; 9644 9645 if ((f >= -0.5) && (f < 0.5)) { 9646 /* Handles negative zero. */ 9647 ctxt->value->floatval *= 0.0; 9648 } 9649 else { 9650 double rounded = floor(f); 9651 if (f - rounded >= 0.5) 9652 rounded += 1.0; 9653 ctxt->value->floatval = rounded; 9654 } 9655 } 9656 9657 /************************************************************************ 9658 * * 9659 * The Parser * 9660 * * 9661 ************************************************************************/ 9662 9663 /* 9664 * a few forward declarations since we use a recursive call based 9665 * implementation. 9666 */ 9667 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort); 9668 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter); 9669 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt); 9670 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt); 9671 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, 9672 int qualified); 9673 9674 /** 9675 * xmlXPathCurrentChar: 9676 * @ctxt: the XPath parser context 9677 * @cur: pointer to the beginning of the char 9678 * @len: pointer to the length of the char read 9679 * 9680 * The current char value, if using UTF-8 this may actually span multiple 9681 * bytes in the input buffer. 9682 * 9683 * Returns the current char value and its length 9684 */ 9685 9686 static int 9687 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) { 9688 unsigned char c; 9689 unsigned int val; 9690 const xmlChar *cur; 9691 9692 if (ctxt == NULL) 9693 return(0); 9694 cur = ctxt->cur; 9695 9696 /* 9697 * We are supposed to handle UTF8, check it's valid 9698 * From rfc2044: encoding of the Unicode values on UTF-8: 9699 * 9700 * UCS-4 range (hex.) UTF-8 octet sequence (binary) 9701 * 0000 0000-0000 007F 0xxxxxxx 9702 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx 9703 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx 9704 * 9705 * Check for the 0x110000 limit too 9706 */ 9707 c = *cur; 9708 if (c & 0x80) { 9709 if ((cur[1] & 0xc0) != 0x80) 9710 goto encoding_error; 9711 if ((c & 0xe0) == 0xe0) { 9712 9713 if ((cur[2] & 0xc0) != 0x80) 9714 goto encoding_error; 9715 if ((c & 0xf0) == 0xf0) { 9716 if (((c & 0xf8) != 0xf0) || 9717 ((cur[3] & 0xc0) != 0x80)) 9718 goto encoding_error; 9719 /* 4-byte code */ 9720 *len = 4; 9721 val = (cur[0] & 0x7) << 18; 9722 val |= (cur[1] & 0x3f) << 12; 9723 val |= (cur[2] & 0x3f) << 6; 9724 val |= cur[3] & 0x3f; 9725 } else { 9726 /* 3-byte code */ 9727 *len = 3; 9728 val = (cur[0] & 0xf) << 12; 9729 val |= (cur[1] & 0x3f) << 6; 9730 val |= cur[2] & 0x3f; 9731 } 9732 } else { 9733 /* 2-byte code */ 9734 *len = 2; 9735 val = (cur[0] & 0x1f) << 6; 9736 val |= cur[1] & 0x3f; 9737 } 9738 if (!IS_CHAR(val)) { 9739 XP_ERROR0(XPATH_INVALID_CHAR_ERROR); 9740 } 9741 return(val); 9742 } else { 9743 /* 1-byte code */ 9744 *len = 1; 9745 return((int) *cur); 9746 } 9747 encoding_error: 9748 /* 9749 * If we detect an UTF8 error that probably means that the 9750 * input encoding didn't get properly advertised in the 9751 * declaration header. Report the error and switch the encoding 9752 * to ISO-Latin-1 (if you don't like this policy, just declare the 9753 * encoding !) 9754 */ 9755 *len = 0; 9756 XP_ERROR0(XPATH_ENCODING_ERROR); 9757 } 9758 9759 /** 9760 * xmlXPathParseNCName: 9761 * @ctxt: the XPath Parser context 9762 * 9763 * parse an XML namespace non qualified name. 9764 * 9765 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)* 9766 * 9767 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' | 9768 * CombiningChar | Extender 9769 * 9770 * Returns the namespace name or NULL 9771 */ 9772 9773 xmlChar * 9774 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) { 9775 const xmlChar *in; 9776 xmlChar *ret; 9777 int count = 0; 9778 9779 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL); 9780 /* 9781 * Accelerator for simple ASCII names 9782 */ 9783 in = ctxt->cur; 9784 if (((*in >= 0x61) && (*in <= 0x7A)) || 9785 ((*in >= 0x41) && (*in <= 0x5A)) || 9786 (*in == '_')) { 9787 in++; 9788 while (((*in >= 0x61) && (*in <= 0x7A)) || 9789 ((*in >= 0x41) && (*in <= 0x5A)) || 9790 ((*in >= 0x30) && (*in <= 0x39)) || 9791 (*in == '_') || (*in == '.') || 9792 (*in == '-')) 9793 in++; 9794 if ((*in == ' ') || (*in == '>') || (*in == '/') || 9795 (*in == '[') || (*in == ']') || (*in == ':') || 9796 (*in == '@') || (*in == '*')) { 9797 count = in - ctxt->cur; 9798 if (count == 0) 9799 return(NULL); 9800 ret = xmlStrndup(ctxt->cur, count); 9801 ctxt->cur = in; 9802 return(ret); 9803 } 9804 } 9805 return(xmlXPathParseNameComplex(ctxt, 0)); 9806 } 9807 9808 9809 /** 9810 * xmlXPathParseQName: 9811 * @ctxt: the XPath Parser context 9812 * @prefix: a xmlChar ** 9813 * 9814 * parse an XML qualified name 9815 * 9816 * [NS 5] QName ::= (Prefix ':')? LocalPart 9817 * 9818 * [NS 6] Prefix ::= NCName 9819 * 9820 * [NS 7] LocalPart ::= NCName 9821 * 9822 * Returns the function returns the local part, and prefix is updated 9823 * to get the Prefix if any. 9824 */ 9825 9826 static xmlChar * 9827 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) { 9828 xmlChar *ret = NULL; 9829 9830 *prefix = NULL; 9831 ret = xmlXPathParseNCName(ctxt); 9832 if (ret && CUR == ':') { 9833 *prefix = ret; 9834 NEXT; 9835 ret = xmlXPathParseNCName(ctxt); 9836 } 9837 return(ret); 9838 } 9839 9840 /** 9841 * xmlXPathParseName: 9842 * @ctxt: the XPath Parser context 9843 * 9844 * parse an XML name 9845 * 9846 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | 9847 * CombiningChar | Extender 9848 * 9849 * [5] Name ::= (Letter | '_' | ':') (NameChar)* 9850 * 9851 * Returns the namespace name or NULL 9852 */ 9853 9854 xmlChar * 9855 xmlXPathParseName(xmlXPathParserContextPtr ctxt) { 9856 const xmlChar *in; 9857 xmlChar *ret; 9858 size_t count = 0; 9859 9860 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL); 9861 /* 9862 * Accelerator for simple ASCII names 9863 */ 9864 in = ctxt->cur; 9865 if (((*in >= 0x61) && (*in <= 0x7A)) || 9866 ((*in >= 0x41) && (*in <= 0x5A)) || 9867 (*in == '_') || (*in == ':')) { 9868 in++; 9869 while (((*in >= 0x61) && (*in <= 0x7A)) || 9870 ((*in >= 0x41) && (*in <= 0x5A)) || 9871 ((*in >= 0x30) && (*in <= 0x39)) || 9872 (*in == '_') || (*in == '-') || 9873 (*in == ':') || (*in == '.')) 9874 in++; 9875 if ((*in > 0) && (*in < 0x80)) { 9876 count = in - ctxt->cur; 9877 if (count > XML_MAX_NAME_LENGTH) { 9878 ctxt->cur = in; 9879 XP_ERRORNULL(XPATH_EXPR_ERROR); 9880 } 9881 ret = xmlStrndup(ctxt->cur, count); 9882 ctxt->cur = in; 9883 return(ret); 9884 } 9885 } 9886 return(xmlXPathParseNameComplex(ctxt, 1)); 9887 } 9888 9889 static xmlChar * 9890 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) { 9891 xmlChar buf[XML_MAX_NAMELEN + 5]; 9892 int len = 0, l; 9893 int c; 9894 9895 /* 9896 * Handler for more complex cases 9897 */ 9898 c = CUR_CHAR(l); 9899 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */ 9900 (c == '[') || (c == ']') || (c == '@') || /* accelerators */ 9901 (c == '*') || /* accelerators */ 9902 (!IS_LETTER(c) && (c != '_') && 9903 ((!qualified) || (c != ':')))) { 9904 return(NULL); 9905 } 9906 9907 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */ 9908 ((IS_LETTER(c)) || (IS_DIGIT(c)) || 9909 (c == '.') || (c == '-') || 9910 (c == '_') || ((qualified) && (c == ':')) || 9911 (IS_COMBINING(c)) || 9912 (IS_EXTENDER(c)))) { 9913 COPY_BUF(l,buf,len,c); 9914 NEXTL(l); 9915 c = CUR_CHAR(l); 9916 if (len >= XML_MAX_NAMELEN) { 9917 /* 9918 * Okay someone managed to make a huge name, so he's ready to pay 9919 * for the processing speed. 9920 */ 9921 xmlChar *buffer; 9922 int max = len * 2; 9923 9924 if (len > XML_MAX_NAME_LENGTH) { 9925 XP_ERRORNULL(XPATH_EXPR_ERROR); 9926 } 9927 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar)); 9928 if (buffer == NULL) { 9929 XP_ERRORNULL(XPATH_MEMORY_ERROR); 9930 } 9931 memcpy(buffer, buf, len); 9932 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */ 9933 (c == '.') || (c == '-') || 9934 (c == '_') || ((qualified) && (c == ':')) || 9935 (IS_COMBINING(c)) || 9936 (IS_EXTENDER(c))) { 9937 if (len + 10 > max) { 9938 xmlChar *tmp; 9939 if (max > XML_MAX_NAME_LENGTH) { 9940 xmlFree(buffer); 9941 XP_ERRORNULL(XPATH_EXPR_ERROR); 9942 } 9943 max *= 2; 9944 tmp = (xmlChar *) xmlRealloc(buffer, 9945 max * sizeof(xmlChar)); 9946 if (tmp == NULL) { 9947 xmlFree(buffer); 9948 XP_ERRORNULL(XPATH_MEMORY_ERROR); 9949 } 9950 buffer = tmp; 9951 } 9952 COPY_BUF(l,buffer,len,c); 9953 NEXTL(l); 9954 c = CUR_CHAR(l); 9955 } 9956 buffer[len] = 0; 9957 return(buffer); 9958 } 9959 } 9960 if (len == 0) 9961 return(NULL); 9962 return(xmlStrndup(buf, len)); 9963 } 9964 9965 #define MAX_FRAC 20 9966 9967 /** 9968 * xmlXPathStringEvalNumber: 9969 * @str: A string to scan 9970 * 9971 * [30a] Float ::= Number ('e' Digits?)? 9972 * 9973 * [30] Number ::= Digits ('.' Digits?)? 9974 * | '.' Digits 9975 * [31] Digits ::= [0-9]+ 9976 * 9977 * Compile a Number in the string 9978 * In complement of the Number expression, this function also handles 9979 * negative values : '-' Number. 9980 * 9981 * Returns the double value. 9982 */ 9983 double 9984 xmlXPathStringEvalNumber(const xmlChar *str) { 9985 const xmlChar *cur = str; 9986 double ret; 9987 int ok = 0; 9988 int isneg = 0; 9989 int exponent = 0; 9990 int is_exponent_negative = 0; 9991 #ifdef __GNUC__ 9992 unsigned long tmp = 0; 9993 double temp; 9994 #endif 9995 if (cur == NULL) return(0); 9996 while (IS_BLANK_CH(*cur)) cur++; 9997 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) { 9998 return(xmlXPathNAN); 9999 } 10000 if (*cur == '-') { 10001 isneg = 1; 10002 cur++; 10003 } 10004 10005 #ifdef __GNUC__ 10006 /* 10007 * tmp/temp is a workaround against a gcc compiler bug 10008 * http://veillard.com/gcc.bug 10009 */ 10010 ret = 0; 10011 while ((*cur >= '0') && (*cur <= '9')) { 10012 ret = ret * 10; 10013 tmp = (*cur - '0'); 10014 ok = 1; 10015 cur++; 10016 temp = (double) tmp; 10017 ret = ret + temp; 10018 } 10019 #else 10020 ret = 0; 10021 while ((*cur >= '0') && (*cur <= '9')) { 10022 ret = ret * 10 + (*cur - '0'); 10023 ok = 1; 10024 cur++; 10025 } 10026 #endif 10027 10028 if (*cur == '.') { 10029 int v, frac = 0, max; 10030 double fraction = 0; 10031 10032 cur++; 10033 if (((*cur < '0') || (*cur > '9')) && (!ok)) { 10034 return(xmlXPathNAN); 10035 } 10036 while (*cur == '0') { 10037 frac = frac + 1; 10038 cur++; 10039 } 10040 max = frac + MAX_FRAC; 10041 while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) { 10042 v = (*cur - '0'); 10043 fraction = fraction * 10 + v; 10044 frac = frac + 1; 10045 cur++; 10046 } 10047 fraction /= pow(10.0, frac); 10048 ret = ret + fraction; 10049 while ((*cur >= '0') && (*cur <= '9')) 10050 cur++; 10051 } 10052 if ((*cur == 'e') || (*cur == 'E')) { 10053 cur++; 10054 if (*cur == '-') { 10055 is_exponent_negative = 1; 10056 cur++; 10057 } else if (*cur == '+') { 10058 cur++; 10059 } 10060 while ((*cur >= '0') && (*cur <= '9')) { 10061 if (exponent < 1000000) 10062 exponent = exponent * 10 + (*cur - '0'); 10063 cur++; 10064 } 10065 } 10066 while (IS_BLANK_CH(*cur)) cur++; 10067 if (*cur != 0) return(xmlXPathNAN); 10068 if (isneg) ret = -ret; 10069 if (is_exponent_negative) exponent = -exponent; 10070 ret *= pow(10.0, (double)exponent); 10071 return(ret); 10072 } 10073 10074 /** 10075 * xmlXPathCompNumber: 10076 * @ctxt: the XPath Parser context 10077 * 10078 * [30] Number ::= Digits ('.' Digits?)? 10079 * | '.' Digits 10080 * [31] Digits ::= [0-9]+ 10081 * 10082 * Compile a Number, then push it on the stack 10083 * 10084 */ 10085 static void 10086 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt) 10087 { 10088 double ret = 0.0; 10089 int ok = 0; 10090 int exponent = 0; 10091 int is_exponent_negative = 0; 10092 xmlXPathObjectPtr num; 10093 #ifdef __GNUC__ 10094 unsigned long tmp = 0; 10095 double temp; 10096 #endif 10097 10098 CHECK_ERROR; 10099 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) { 10100 XP_ERROR(XPATH_NUMBER_ERROR); 10101 } 10102 #ifdef __GNUC__ 10103 /* 10104 * tmp/temp is a workaround against a gcc compiler bug 10105 * http://veillard.com/gcc.bug 10106 */ 10107 ret = 0; 10108 while ((CUR >= '0') && (CUR <= '9')) { 10109 ret = ret * 10; 10110 tmp = (CUR - '0'); 10111 ok = 1; 10112 NEXT; 10113 temp = (double) tmp; 10114 ret = ret + temp; 10115 } 10116 #else 10117 ret = 0; 10118 while ((CUR >= '0') && (CUR <= '9')) { 10119 ret = ret * 10 + (CUR - '0'); 10120 ok = 1; 10121 NEXT; 10122 } 10123 #endif 10124 if (CUR == '.') { 10125 int v, frac = 0, max; 10126 double fraction = 0; 10127 10128 NEXT; 10129 if (((CUR < '0') || (CUR > '9')) && (!ok)) { 10130 XP_ERROR(XPATH_NUMBER_ERROR); 10131 } 10132 while (CUR == '0') { 10133 frac = frac + 1; 10134 NEXT; 10135 } 10136 max = frac + MAX_FRAC; 10137 while ((CUR >= '0') && (CUR <= '9') && (frac < max)) { 10138 v = (CUR - '0'); 10139 fraction = fraction * 10 + v; 10140 frac = frac + 1; 10141 NEXT; 10142 } 10143 fraction /= pow(10.0, frac); 10144 ret = ret + fraction; 10145 while ((CUR >= '0') && (CUR <= '9')) 10146 NEXT; 10147 } 10148 if ((CUR == 'e') || (CUR == 'E')) { 10149 NEXT; 10150 if (CUR == '-') { 10151 is_exponent_negative = 1; 10152 NEXT; 10153 } else if (CUR == '+') { 10154 NEXT; 10155 } 10156 while ((CUR >= '0') && (CUR <= '9')) { 10157 if (exponent < 1000000) 10158 exponent = exponent * 10 + (CUR - '0'); 10159 NEXT; 10160 } 10161 if (is_exponent_negative) 10162 exponent = -exponent; 10163 ret *= pow(10.0, (double) exponent); 10164 } 10165 num = xmlXPathCacheNewFloat(ctxt->context, ret); 10166 if (num == NULL) { 10167 ctxt->error = XPATH_MEMORY_ERROR; 10168 } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num, 10169 NULL) == -1) { 10170 xmlXPathReleaseObject(ctxt->context, num); 10171 } 10172 } 10173 10174 /** 10175 * xmlXPathParseLiteral: 10176 * @ctxt: the XPath Parser context 10177 * 10178 * Parse a Literal 10179 * 10180 * [29] Literal ::= '"' [^"]* '"' 10181 * | "'" [^']* "'" 10182 * 10183 * Returns the value found or NULL in case of error 10184 */ 10185 static xmlChar * 10186 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) { 10187 const xmlChar *q; 10188 xmlChar *ret = NULL; 10189 10190 if (CUR == '"') { 10191 NEXT; 10192 q = CUR_PTR; 10193 while ((IS_CHAR_CH(CUR)) && (CUR != '"')) 10194 NEXT; 10195 if (!IS_CHAR_CH(CUR)) { 10196 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR); 10197 } else { 10198 ret = xmlStrndup(q, CUR_PTR - q); 10199 NEXT; 10200 } 10201 } else if (CUR == '\'') { 10202 NEXT; 10203 q = CUR_PTR; 10204 while ((IS_CHAR_CH(CUR)) && (CUR != '\'')) 10205 NEXT; 10206 if (!IS_CHAR_CH(CUR)) { 10207 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR); 10208 } else { 10209 ret = xmlStrndup(q, CUR_PTR - q); 10210 NEXT; 10211 } 10212 } else { 10213 XP_ERRORNULL(XPATH_START_LITERAL_ERROR); 10214 } 10215 return(ret); 10216 } 10217 10218 /** 10219 * xmlXPathCompLiteral: 10220 * @ctxt: the XPath Parser context 10221 * 10222 * Parse a Literal and push it on the stack. 10223 * 10224 * [29] Literal ::= '"' [^"]* '"' 10225 * | "'" [^']* "'" 10226 * 10227 * TODO: xmlXPathCompLiteral memory allocation could be improved. 10228 */ 10229 static void 10230 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) { 10231 const xmlChar *q; 10232 xmlChar *ret = NULL; 10233 xmlXPathObjectPtr lit; 10234 10235 if (CUR == '"') { 10236 NEXT; 10237 q = CUR_PTR; 10238 while ((IS_CHAR_CH(CUR)) && (CUR != '"')) 10239 NEXT; 10240 if (!IS_CHAR_CH(CUR)) { 10241 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR); 10242 } else { 10243 ret = xmlStrndup(q, CUR_PTR - q); 10244 NEXT; 10245 } 10246 } else if (CUR == '\'') { 10247 NEXT; 10248 q = CUR_PTR; 10249 while ((IS_CHAR_CH(CUR)) && (CUR != '\'')) 10250 NEXT; 10251 if (!IS_CHAR_CH(CUR)) { 10252 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR); 10253 } else { 10254 ret = xmlStrndup(q, CUR_PTR - q); 10255 NEXT; 10256 } 10257 } else { 10258 XP_ERROR(XPATH_START_LITERAL_ERROR); 10259 } 10260 if (ret == NULL) return; 10261 lit = xmlXPathCacheNewString(ctxt->context, ret); 10262 if (lit == NULL) { 10263 ctxt->error = XPATH_MEMORY_ERROR; 10264 } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit, 10265 NULL) == -1) { 10266 xmlXPathReleaseObject(ctxt->context, lit); 10267 } 10268 xmlFree(ret); 10269 } 10270 10271 /** 10272 * xmlXPathCompVariableReference: 10273 * @ctxt: the XPath Parser context 10274 * 10275 * Parse a VariableReference, evaluate it and push it on the stack. 10276 * 10277 * The variable bindings consist of a mapping from variable names 10278 * to variable values. The value of a variable is an object, which can be 10279 * of any of the types that are possible for the value of an expression, 10280 * and may also be of additional types not specified here. 10281 * 10282 * Early evaluation is possible since: 10283 * The variable bindings [...] used to evaluate a subexpression are 10284 * always the same as those used to evaluate the containing expression. 10285 * 10286 * [36] VariableReference ::= '$' QName 10287 */ 10288 static void 10289 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) { 10290 xmlChar *name; 10291 xmlChar *prefix; 10292 10293 SKIP_BLANKS; 10294 if (CUR != '$') { 10295 XP_ERROR(XPATH_VARIABLE_REF_ERROR); 10296 } 10297 NEXT; 10298 name = xmlXPathParseQName(ctxt, &prefix); 10299 if (name == NULL) { 10300 xmlFree(prefix); 10301 XP_ERROR(XPATH_VARIABLE_REF_ERROR); 10302 } 10303 ctxt->comp->last = -1; 10304 if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) { 10305 xmlFree(prefix); 10306 xmlFree(name); 10307 } 10308 SKIP_BLANKS; 10309 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) { 10310 XP_ERROR(XPATH_FORBID_VARIABLE_ERROR); 10311 } 10312 } 10313 10314 /** 10315 * xmlXPathIsNodeType: 10316 * @name: a name string 10317 * 10318 * Is the name given a NodeType one. 10319 * 10320 * [38] NodeType ::= 'comment' 10321 * | 'text' 10322 * | 'processing-instruction' 10323 * | 'node' 10324 * 10325 * Returns 1 if true 0 otherwise 10326 */ 10327 int 10328 xmlXPathIsNodeType(const xmlChar *name) { 10329 if (name == NULL) 10330 return(0); 10331 10332 if (xmlStrEqual(name, BAD_CAST "node")) 10333 return(1); 10334 if (xmlStrEqual(name, BAD_CAST "text")) 10335 return(1); 10336 if (xmlStrEqual(name, BAD_CAST "comment")) 10337 return(1); 10338 if (xmlStrEqual(name, BAD_CAST "processing-instruction")) 10339 return(1); 10340 return(0); 10341 } 10342 10343 /** 10344 * xmlXPathCompFunctionCall: 10345 * @ctxt: the XPath Parser context 10346 * 10347 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')' 10348 * [17] Argument ::= Expr 10349 * 10350 * Compile a function call, the evaluation of all arguments are 10351 * pushed on the stack 10352 */ 10353 static void 10354 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) { 10355 xmlChar *name; 10356 xmlChar *prefix; 10357 int nbargs = 0; 10358 int sort = 1; 10359 10360 name = xmlXPathParseQName(ctxt, &prefix); 10361 if (name == NULL) { 10362 xmlFree(prefix); 10363 XP_ERROR(XPATH_EXPR_ERROR); 10364 } 10365 SKIP_BLANKS; 10366 #ifdef DEBUG_EXPR 10367 if (prefix == NULL) 10368 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n", 10369 name); 10370 else 10371 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n", 10372 prefix, name); 10373 #endif 10374 10375 if (CUR != '(') { 10376 xmlFree(name); 10377 xmlFree(prefix); 10378 XP_ERROR(XPATH_EXPR_ERROR); 10379 } 10380 NEXT; 10381 SKIP_BLANKS; 10382 10383 /* 10384 * Optimization for count(): we don't need the node-set to be sorted. 10385 */ 10386 if ((prefix == NULL) && (name[0] == 'c') && 10387 xmlStrEqual(name, BAD_CAST "count")) 10388 { 10389 sort = 0; 10390 } 10391 ctxt->comp->last = -1; 10392 if (CUR != ')') { 10393 while (CUR != 0) { 10394 int op1 = ctxt->comp->last; 10395 ctxt->comp->last = -1; 10396 xmlXPathCompileExpr(ctxt, sort); 10397 if (ctxt->error != XPATH_EXPRESSION_OK) { 10398 xmlFree(name); 10399 xmlFree(prefix); 10400 return; 10401 } 10402 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0); 10403 nbargs++; 10404 if (CUR == ')') break; 10405 if (CUR != ',') { 10406 xmlFree(name); 10407 xmlFree(prefix); 10408 XP_ERROR(XPATH_EXPR_ERROR); 10409 } 10410 NEXT; 10411 SKIP_BLANKS; 10412 } 10413 } 10414 if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) { 10415 xmlFree(prefix); 10416 xmlFree(name); 10417 } 10418 NEXT; 10419 SKIP_BLANKS; 10420 } 10421 10422 /** 10423 * xmlXPathCompPrimaryExpr: 10424 * @ctxt: the XPath Parser context 10425 * 10426 * [15] PrimaryExpr ::= VariableReference 10427 * | '(' Expr ')' 10428 * | Literal 10429 * | Number 10430 * | FunctionCall 10431 * 10432 * Compile a primary expression. 10433 */ 10434 static void 10435 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) { 10436 SKIP_BLANKS; 10437 if (CUR == '$') xmlXPathCompVariableReference(ctxt); 10438 else if (CUR == '(') { 10439 NEXT; 10440 SKIP_BLANKS; 10441 xmlXPathCompileExpr(ctxt, 1); 10442 CHECK_ERROR; 10443 if (CUR != ')') { 10444 XP_ERROR(XPATH_EXPR_ERROR); 10445 } 10446 NEXT; 10447 SKIP_BLANKS; 10448 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) { 10449 xmlXPathCompNumber(ctxt); 10450 } else if ((CUR == '\'') || (CUR == '"')) { 10451 xmlXPathCompLiteral(ctxt); 10452 } else { 10453 xmlXPathCompFunctionCall(ctxt); 10454 } 10455 SKIP_BLANKS; 10456 } 10457 10458 /** 10459 * xmlXPathCompFilterExpr: 10460 * @ctxt: the XPath Parser context 10461 * 10462 * [20] FilterExpr ::= PrimaryExpr 10463 * | FilterExpr Predicate 10464 * 10465 * Compile a filter expression. 10466 * Square brackets are used to filter expressions in the same way that 10467 * they are used in location paths. It is an error if the expression to 10468 * be filtered does not evaluate to a node-set. The context node list 10469 * used for evaluating the expression in square brackets is the node-set 10470 * to be filtered listed in document order. 10471 */ 10472 10473 static void 10474 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) { 10475 xmlXPathCompPrimaryExpr(ctxt); 10476 CHECK_ERROR; 10477 SKIP_BLANKS; 10478 10479 while (CUR == '[') { 10480 xmlXPathCompPredicate(ctxt, 1); 10481 SKIP_BLANKS; 10482 } 10483 10484 10485 } 10486 10487 /** 10488 * xmlXPathScanName: 10489 * @ctxt: the XPath Parser context 10490 * 10491 * Trickery: parse an XML name but without consuming the input flow 10492 * Needed to avoid insanity in the parser state. 10493 * 10494 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | 10495 * CombiningChar | Extender 10496 * 10497 * [5] Name ::= (Letter | '_' | ':') (NameChar)* 10498 * 10499 * [6] Names ::= Name (S Name)* 10500 * 10501 * Returns the Name parsed or NULL 10502 */ 10503 10504 static xmlChar * 10505 xmlXPathScanName(xmlXPathParserContextPtr ctxt) { 10506 int l; 10507 int c; 10508 const xmlChar *cur; 10509 xmlChar *ret; 10510 10511 cur = ctxt->cur; 10512 10513 c = CUR_CHAR(l); 10514 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */ 10515 (!IS_LETTER(c) && (c != '_') && 10516 (c != ':'))) { 10517 return(NULL); 10518 } 10519 10520 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */ 10521 ((IS_LETTER(c)) || (IS_DIGIT(c)) || 10522 (c == '.') || (c == '-') || 10523 (c == '_') || (c == ':') || 10524 (IS_COMBINING(c)) || 10525 (IS_EXTENDER(c)))) { 10526 NEXTL(l); 10527 c = CUR_CHAR(l); 10528 } 10529 ret = xmlStrndup(cur, ctxt->cur - cur); 10530 ctxt->cur = cur; 10531 return(ret); 10532 } 10533 10534 /** 10535 * xmlXPathCompPathExpr: 10536 * @ctxt: the XPath Parser context 10537 * 10538 * [19] PathExpr ::= LocationPath 10539 * | FilterExpr 10540 * | FilterExpr '/' RelativeLocationPath 10541 * | FilterExpr '//' RelativeLocationPath 10542 * 10543 * Compile a path expression. 10544 * The / operator and // operators combine an arbitrary expression 10545 * and a relative location path. It is an error if the expression 10546 * does not evaluate to a node-set. 10547 * The / operator does composition in the same way as when / is 10548 * used in a location path. As in location paths, // is short for 10549 * /descendant-or-self::node()/. 10550 */ 10551 10552 static void 10553 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) { 10554 int lc = 1; /* Should we branch to LocationPath ? */ 10555 xmlChar *name = NULL; /* we may have to preparse a name to find out */ 10556 10557 SKIP_BLANKS; 10558 if ((CUR == '$') || (CUR == '(') || 10559 (IS_ASCII_DIGIT(CUR)) || 10560 (CUR == '\'') || (CUR == '"') || 10561 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) { 10562 lc = 0; 10563 } else if (CUR == '*') { 10564 /* relative or absolute location path */ 10565 lc = 1; 10566 } else if (CUR == '/') { 10567 /* relative or absolute location path */ 10568 lc = 1; 10569 } else if (CUR == '@') { 10570 /* relative abbreviated attribute location path */ 10571 lc = 1; 10572 } else if (CUR == '.') { 10573 /* relative abbreviated attribute location path */ 10574 lc = 1; 10575 } else { 10576 /* 10577 * Problem is finding if we have a name here whether it's: 10578 * - a nodetype 10579 * - a function call in which case it's followed by '(' 10580 * - an axis in which case it's followed by ':' 10581 * - a element name 10582 * We do an a priori analysis here rather than having to 10583 * maintain parsed token content through the recursive function 10584 * calls. This looks uglier but makes the code easier to 10585 * read/write/debug. 10586 */ 10587 SKIP_BLANKS; 10588 name = xmlXPathScanName(ctxt); 10589 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) { 10590 #ifdef DEBUG_STEP 10591 xmlGenericError(xmlGenericErrorContext, 10592 "PathExpr: Axis\n"); 10593 #endif 10594 lc = 1; 10595 xmlFree(name); 10596 } else if (name != NULL) { 10597 int len =xmlStrlen(name); 10598 10599 10600 while (NXT(len) != 0) { 10601 if (NXT(len) == '/') { 10602 /* element name */ 10603 #ifdef DEBUG_STEP 10604 xmlGenericError(xmlGenericErrorContext, 10605 "PathExpr: AbbrRelLocation\n"); 10606 #endif 10607 lc = 1; 10608 break; 10609 } else if (IS_BLANK_CH(NXT(len))) { 10610 /* ignore blanks */ 10611 ; 10612 } else if (NXT(len) == ':') { 10613 #ifdef DEBUG_STEP 10614 xmlGenericError(xmlGenericErrorContext, 10615 "PathExpr: AbbrRelLocation\n"); 10616 #endif 10617 lc = 1; 10618 break; 10619 } else if ((NXT(len) == '(')) { 10620 /* Node Type or Function */ 10621 if (xmlXPathIsNodeType(name)) { 10622 #ifdef DEBUG_STEP 10623 xmlGenericError(xmlGenericErrorContext, 10624 "PathExpr: Type search\n"); 10625 #endif 10626 lc = 1; 10627 #ifdef LIBXML_XPTR_LOCS_ENABLED 10628 } else if (ctxt->xptr && 10629 xmlStrEqual(name, BAD_CAST "range-to")) { 10630 lc = 1; 10631 #endif 10632 } else { 10633 #ifdef DEBUG_STEP 10634 xmlGenericError(xmlGenericErrorContext, 10635 "PathExpr: function call\n"); 10636 #endif 10637 lc = 0; 10638 } 10639 break; 10640 } else if ((NXT(len) == '[')) { 10641 /* element name */ 10642 #ifdef DEBUG_STEP 10643 xmlGenericError(xmlGenericErrorContext, 10644 "PathExpr: AbbrRelLocation\n"); 10645 #endif 10646 lc = 1; 10647 break; 10648 } else if ((NXT(len) == '<') || (NXT(len) == '>') || 10649 (NXT(len) == '=')) { 10650 lc = 1; 10651 break; 10652 } else { 10653 lc = 1; 10654 break; 10655 } 10656 len++; 10657 } 10658 if (NXT(len) == 0) { 10659 #ifdef DEBUG_STEP 10660 xmlGenericError(xmlGenericErrorContext, 10661 "PathExpr: AbbrRelLocation\n"); 10662 #endif 10663 /* element name */ 10664 lc = 1; 10665 } 10666 xmlFree(name); 10667 } else { 10668 /* make sure all cases are covered explicitly */ 10669 XP_ERROR(XPATH_EXPR_ERROR); 10670 } 10671 } 10672 10673 if (lc) { 10674 if (CUR == '/') { 10675 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0); 10676 } else { 10677 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0); 10678 } 10679 xmlXPathCompLocationPath(ctxt); 10680 } else { 10681 xmlXPathCompFilterExpr(ctxt); 10682 CHECK_ERROR; 10683 if ((CUR == '/') && (NXT(1) == '/')) { 10684 SKIP(2); 10685 SKIP_BLANKS; 10686 10687 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 10688 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 10689 10690 xmlXPathCompRelativeLocationPath(ctxt); 10691 } else if (CUR == '/') { 10692 xmlXPathCompRelativeLocationPath(ctxt); 10693 } 10694 } 10695 SKIP_BLANKS; 10696 } 10697 10698 /** 10699 * xmlXPathCompUnionExpr: 10700 * @ctxt: the XPath Parser context 10701 * 10702 * [18] UnionExpr ::= PathExpr 10703 * | UnionExpr '|' PathExpr 10704 * 10705 * Compile an union expression. 10706 */ 10707 10708 static void 10709 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) { 10710 xmlXPathCompPathExpr(ctxt); 10711 CHECK_ERROR; 10712 SKIP_BLANKS; 10713 while (CUR == '|') { 10714 int op1 = ctxt->comp->last; 10715 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0); 10716 10717 NEXT; 10718 SKIP_BLANKS; 10719 xmlXPathCompPathExpr(ctxt); 10720 10721 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0); 10722 10723 SKIP_BLANKS; 10724 } 10725 } 10726 10727 /** 10728 * xmlXPathCompUnaryExpr: 10729 * @ctxt: the XPath Parser context 10730 * 10731 * [27] UnaryExpr ::= UnionExpr 10732 * | '-' UnaryExpr 10733 * 10734 * Compile an unary expression. 10735 */ 10736 10737 static void 10738 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) { 10739 int minus = 0; 10740 int found = 0; 10741 10742 SKIP_BLANKS; 10743 while (CUR == '-') { 10744 minus = 1 - minus; 10745 found = 1; 10746 NEXT; 10747 SKIP_BLANKS; 10748 } 10749 10750 xmlXPathCompUnionExpr(ctxt); 10751 CHECK_ERROR; 10752 if (found) { 10753 if (minus) 10754 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0); 10755 else 10756 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0); 10757 } 10758 } 10759 10760 /** 10761 * xmlXPathCompMultiplicativeExpr: 10762 * @ctxt: the XPath Parser context 10763 * 10764 * [26] MultiplicativeExpr ::= UnaryExpr 10765 * | MultiplicativeExpr MultiplyOperator UnaryExpr 10766 * | MultiplicativeExpr 'div' UnaryExpr 10767 * | MultiplicativeExpr 'mod' UnaryExpr 10768 * [34] MultiplyOperator ::= '*' 10769 * 10770 * Compile an Additive expression. 10771 */ 10772 10773 static void 10774 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) { 10775 xmlXPathCompUnaryExpr(ctxt); 10776 CHECK_ERROR; 10777 SKIP_BLANKS; 10778 while ((CUR == '*') || 10779 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) || 10780 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) { 10781 int op = -1; 10782 int op1 = ctxt->comp->last; 10783 10784 if (CUR == '*') { 10785 op = 0; 10786 NEXT; 10787 } else if (CUR == 'd') { 10788 op = 1; 10789 SKIP(3); 10790 } else if (CUR == 'm') { 10791 op = 2; 10792 SKIP(3); 10793 } 10794 SKIP_BLANKS; 10795 xmlXPathCompUnaryExpr(ctxt); 10796 CHECK_ERROR; 10797 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0); 10798 SKIP_BLANKS; 10799 } 10800 } 10801 10802 /** 10803 * xmlXPathCompAdditiveExpr: 10804 * @ctxt: the XPath Parser context 10805 * 10806 * [25] AdditiveExpr ::= MultiplicativeExpr 10807 * | AdditiveExpr '+' MultiplicativeExpr 10808 * | AdditiveExpr '-' MultiplicativeExpr 10809 * 10810 * Compile an Additive expression. 10811 */ 10812 10813 static void 10814 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) { 10815 10816 xmlXPathCompMultiplicativeExpr(ctxt); 10817 CHECK_ERROR; 10818 SKIP_BLANKS; 10819 while ((CUR == '+') || (CUR == '-')) { 10820 int plus; 10821 int op1 = ctxt->comp->last; 10822 10823 if (CUR == '+') plus = 1; 10824 else plus = 0; 10825 NEXT; 10826 SKIP_BLANKS; 10827 xmlXPathCompMultiplicativeExpr(ctxt); 10828 CHECK_ERROR; 10829 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0); 10830 SKIP_BLANKS; 10831 } 10832 } 10833 10834 /** 10835 * xmlXPathCompRelationalExpr: 10836 * @ctxt: the XPath Parser context 10837 * 10838 * [24] RelationalExpr ::= AdditiveExpr 10839 * | RelationalExpr '<' AdditiveExpr 10840 * | RelationalExpr '>' AdditiveExpr 10841 * | RelationalExpr '<=' AdditiveExpr 10842 * | RelationalExpr '>=' AdditiveExpr 10843 * 10844 * A <= B > C is allowed ? Answer from James, yes with 10845 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr 10846 * which is basically what got implemented. 10847 * 10848 * Compile a Relational expression, then push the result 10849 * on the stack 10850 */ 10851 10852 static void 10853 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) { 10854 xmlXPathCompAdditiveExpr(ctxt); 10855 CHECK_ERROR; 10856 SKIP_BLANKS; 10857 while ((CUR == '<') || (CUR == '>')) { 10858 int inf, strict; 10859 int op1 = ctxt->comp->last; 10860 10861 if (CUR == '<') inf = 1; 10862 else inf = 0; 10863 if (NXT(1) == '=') strict = 0; 10864 else strict = 1; 10865 NEXT; 10866 if (!strict) NEXT; 10867 SKIP_BLANKS; 10868 xmlXPathCompAdditiveExpr(ctxt); 10869 CHECK_ERROR; 10870 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict); 10871 SKIP_BLANKS; 10872 } 10873 } 10874 10875 /** 10876 * xmlXPathCompEqualityExpr: 10877 * @ctxt: the XPath Parser context 10878 * 10879 * [23] EqualityExpr ::= RelationalExpr 10880 * | EqualityExpr '=' RelationalExpr 10881 * | EqualityExpr '!=' RelationalExpr 10882 * 10883 * A != B != C is allowed ? Answer from James, yes with 10884 * (RelationalExpr = RelationalExpr) = RelationalExpr 10885 * (RelationalExpr != RelationalExpr) != RelationalExpr 10886 * which is basically what got implemented. 10887 * 10888 * Compile an Equality expression. 10889 * 10890 */ 10891 static void 10892 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) { 10893 xmlXPathCompRelationalExpr(ctxt); 10894 CHECK_ERROR; 10895 SKIP_BLANKS; 10896 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) { 10897 int eq; 10898 int op1 = ctxt->comp->last; 10899 10900 if (CUR == '=') eq = 1; 10901 else eq = 0; 10902 NEXT; 10903 if (!eq) NEXT; 10904 SKIP_BLANKS; 10905 xmlXPathCompRelationalExpr(ctxt); 10906 CHECK_ERROR; 10907 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0); 10908 SKIP_BLANKS; 10909 } 10910 } 10911 10912 /** 10913 * xmlXPathCompAndExpr: 10914 * @ctxt: the XPath Parser context 10915 * 10916 * [22] AndExpr ::= EqualityExpr 10917 * | AndExpr 'and' EqualityExpr 10918 * 10919 * Compile an AND expression. 10920 * 10921 */ 10922 static void 10923 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) { 10924 xmlXPathCompEqualityExpr(ctxt); 10925 CHECK_ERROR; 10926 SKIP_BLANKS; 10927 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) { 10928 int op1 = ctxt->comp->last; 10929 SKIP(3); 10930 SKIP_BLANKS; 10931 xmlXPathCompEqualityExpr(ctxt); 10932 CHECK_ERROR; 10933 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0); 10934 SKIP_BLANKS; 10935 } 10936 } 10937 10938 /** 10939 * xmlXPathCompileExpr: 10940 * @ctxt: the XPath Parser context 10941 * 10942 * [14] Expr ::= OrExpr 10943 * [21] OrExpr ::= AndExpr 10944 * | OrExpr 'or' AndExpr 10945 * 10946 * Parse and compile an expression 10947 */ 10948 static void 10949 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) { 10950 xmlXPathContextPtr xpctxt = ctxt->context; 10951 10952 if (xpctxt != NULL) { 10953 if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH) 10954 XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED); 10955 /* 10956 * Parsing a single '(' pushes about 10 functions on the call stack 10957 * before recursing! 10958 */ 10959 xpctxt->depth += 10; 10960 } 10961 10962 xmlXPathCompAndExpr(ctxt); 10963 CHECK_ERROR; 10964 SKIP_BLANKS; 10965 while ((CUR == 'o') && (NXT(1) == 'r')) { 10966 int op1 = ctxt->comp->last; 10967 SKIP(2); 10968 SKIP_BLANKS; 10969 xmlXPathCompAndExpr(ctxt); 10970 CHECK_ERROR; 10971 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0); 10972 SKIP_BLANKS; 10973 } 10974 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) { 10975 /* more ops could be optimized too */ 10976 /* 10977 * This is the main place to eliminate sorting for 10978 * operations which don't require a sorted node-set. 10979 * E.g. count(). 10980 */ 10981 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0); 10982 } 10983 10984 if (xpctxt != NULL) 10985 xpctxt->depth -= 10; 10986 } 10987 10988 /** 10989 * xmlXPathCompPredicate: 10990 * @ctxt: the XPath Parser context 10991 * @filter: act as a filter 10992 * 10993 * [8] Predicate ::= '[' PredicateExpr ']' 10994 * [9] PredicateExpr ::= Expr 10995 * 10996 * Compile a predicate expression 10997 */ 10998 static void 10999 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) { 11000 int op1 = ctxt->comp->last; 11001 11002 SKIP_BLANKS; 11003 if (CUR != '[') { 11004 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); 11005 } 11006 NEXT; 11007 SKIP_BLANKS; 11008 11009 ctxt->comp->last = -1; 11010 /* 11011 * This call to xmlXPathCompileExpr() will deactivate sorting 11012 * of the predicate result. 11013 * TODO: Sorting is still activated for filters, since I'm not 11014 * sure if needed. Normally sorting should not be needed, since 11015 * a filter can only diminish the number of items in a sequence, 11016 * but won't change its order; so if the initial sequence is sorted, 11017 * subsequent sorting is not needed. 11018 */ 11019 if (! filter) 11020 xmlXPathCompileExpr(ctxt, 0); 11021 else 11022 xmlXPathCompileExpr(ctxt, 1); 11023 CHECK_ERROR; 11024 11025 if (CUR != ']') { 11026 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); 11027 } 11028 11029 if (filter) 11030 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0); 11031 else 11032 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0); 11033 11034 NEXT; 11035 SKIP_BLANKS; 11036 } 11037 11038 /** 11039 * xmlXPathCompNodeTest: 11040 * @ctxt: the XPath Parser context 11041 * @test: pointer to a xmlXPathTestVal 11042 * @type: pointer to a xmlXPathTypeVal 11043 * @prefix: placeholder for a possible name prefix 11044 * 11045 * [7] NodeTest ::= NameTest 11046 * | NodeType '(' ')' 11047 * | 'processing-instruction' '(' Literal ')' 11048 * 11049 * [37] NameTest ::= '*' 11050 * | NCName ':' '*' 11051 * | QName 11052 * [38] NodeType ::= 'comment' 11053 * | 'text' 11054 * | 'processing-instruction' 11055 * | 'node' 11056 * 11057 * Returns the name found and updates @test, @type and @prefix appropriately 11058 */ 11059 static xmlChar * 11060 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test, 11061 xmlXPathTypeVal *type, xmlChar **prefix, 11062 xmlChar *name) { 11063 int blanks; 11064 11065 if ((test == NULL) || (type == NULL) || (prefix == NULL)) { 11066 STRANGE; 11067 return(NULL); 11068 } 11069 *type = (xmlXPathTypeVal) 0; 11070 *test = (xmlXPathTestVal) 0; 11071 *prefix = NULL; 11072 SKIP_BLANKS; 11073 11074 if ((name == NULL) && (CUR == '*')) { 11075 /* 11076 * All elements 11077 */ 11078 NEXT; 11079 *test = NODE_TEST_ALL; 11080 return(NULL); 11081 } 11082 11083 if (name == NULL) 11084 name = xmlXPathParseNCName(ctxt); 11085 if (name == NULL) { 11086 XP_ERRORNULL(XPATH_EXPR_ERROR); 11087 } 11088 11089 blanks = IS_BLANK_CH(CUR); 11090 SKIP_BLANKS; 11091 if (CUR == '(') { 11092 NEXT; 11093 /* 11094 * NodeType or PI search 11095 */ 11096 if (xmlStrEqual(name, BAD_CAST "comment")) 11097 *type = NODE_TYPE_COMMENT; 11098 else if (xmlStrEqual(name, BAD_CAST "node")) 11099 *type = NODE_TYPE_NODE; 11100 else if (xmlStrEqual(name, BAD_CAST "processing-instruction")) 11101 *type = NODE_TYPE_PI; 11102 else if (xmlStrEqual(name, BAD_CAST "text")) 11103 *type = NODE_TYPE_TEXT; 11104 else { 11105 if (name != NULL) 11106 xmlFree(name); 11107 XP_ERRORNULL(XPATH_EXPR_ERROR); 11108 } 11109 11110 *test = NODE_TEST_TYPE; 11111 11112 SKIP_BLANKS; 11113 if (*type == NODE_TYPE_PI) { 11114 /* 11115 * Specific case: search a PI by name. 11116 */ 11117 if (name != NULL) 11118 xmlFree(name); 11119 name = NULL; 11120 if (CUR != ')') { 11121 name = xmlXPathParseLiteral(ctxt); 11122 if (name == NULL) { 11123 XP_ERRORNULL(XPATH_EXPR_ERROR); 11124 } 11125 *test = NODE_TEST_PI; 11126 SKIP_BLANKS; 11127 } 11128 } 11129 if (CUR != ')') { 11130 if (name != NULL) 11131 xmlFree(name); 11132 XP_ERRORNULL(XPATH_UNCLOSED_ERROR); 11133 } 11134 NEXT; 11135 return(name); 11136 } 11137 *test = NODE_TEST_NAME; 11138 if ((!blanks) && (CUR == ':')) { 11139 NEXT; 11140 11141 /* 11142 * Since currently the parser context don't have a 11143 * namespace list associated: 11144 * The namespace name for this prefix can be computed 11145 * only at evaluation time. The compilation is done 11146 * outside of any context. 11147 */ 11148 #if 0 11149 *prefix = xmlXPathNsLookup(ctxt->context, name); 11150 if (name != NULL) 11151 xmlFree(name); 11152 if (*prefix == NULL) { 11153 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); 11154 } 11155 #else 11156 *prefix = name; 11157 #endif 11158 11159 if (CUR == '*') { 11160 /* 11161 * All elements 11162 */ 11163 NEXT; 11164 *test = NODE_TEST_ALL; 11165 return(NULL); 11166 } 11167 11168 name = xmlXPathParseNCName(ctxt); 11169 if (name == NULL) { 11170 XP_ERRORNULL(XPATH_EXPR_ERROR); 11171 } 11172 } 11173 return(name); 11174 } 11175 11176 /** 11177 * xmlXPathIsAxisName: 11178 * @name: a preparsed name token 11179 * 11180 * [6] AxisName ::= 'ancestor' 11181 * | 'ancestor-or-self' 11182 * | 'attribute' 11183 * | 'child' 11184 * | 'descendant' 11185 * | 'descendant-or-self' 11186 * | 'following' 11187 * | 'following-sibling' 11188 * | 'namespace' 11189 * | 'parent' 11190 * | 'preceding' 11191 * | 'preceding-sibling' 11192 * | 'self' 11193 * 11194 * Returns the axis or 0 11195 */ 11196 static xmlXPathAxisVal 11197 xmlXPathIsAxisName(const xmlChar *name) { 11198 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0; 11199 switch (name[0]) { 11200 case 'a': 11201 if (xmlStrEqual(name, BAD_CAST "ancestor")) 11202 ret = AXIS_ANCESTOR; 11203 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self")) 11204 ret = AXIS_ANCESTOR_OR_SELF; 11205 if (xmlStrEqual(name, BAD_CAST "attribute")) 11206 ret = AXIS_ATTRIBUTE; 11207 break; 11208 case 'c': 11209 if (xmlStrEqual(name, BAD_CAST "child")) 11210 ret = AXIS_CHILD; 11211 break; 11212 case 'd': 11213 if (xmlStrEqual(name, BAD_CAST "descendant")) 11214 ret = AXIS_DESCENDANT; 11215 if (xmlStrEqual(name, BAD_CAST "descendant-or-self")) 11216 ret = AXIS_DESCENDANT_OR_SELF; 11217 break; 11218 case 'f': 11219 if (xmlStrEqual(name, BAD_CAST "following")) 11220 ret = AXIS_FOLLOWING; 11221 if (xmlStrEqual(name, BAD_CAST "following-sibling")) 11222 ret = AXIS_FOLLOWING_SIBLING; 11223 break; 11224 case 'n': 11225 if (xmlStrEqual(name, BAD_CAST "namespace")) 11226 ret = AXIS_NAMESPACE; 11227 break; 11228 case 'p': 11229 if (xmlStrEqual(name, BAD_CAST "parent")) 11230 ret = AXIS_PARENT; 11231 if (xmlStrEqual(name, BAD_CAST "preceding")) 11232 ret = AXIS_PRECEDING; 11233 if (xmlStrEqual(name, BAD_CAST "preceding-sibling")) 11234 ret = AXIS_PRECEDING_SIBLING; 11235 break; 11236 case 's': 11237 if (xmlStrEqual(name, BAD_CAST "self")) 11238 ret = AXIS_SELF; 11239 break; 11240 } 11241 return(ret); 11242 } 11243 11244 /** 11245 * xmlXPathCompStep: 11246 * @ctxt: the XPath Parser context 11247 * 11248 * [4] Step ::= AxisSpecifier NodeTest Predicate* 11249 * | AbbreviatedStep 11250 * 11251 * [12] AbbreviatedStep ::= '.' | '..' 11252 * 11253 * [5] AxisSpecifier ::= AxisName '::' 11254 * | AbbreviatedAxisSpecifier 11255 * 11256 * [13] AbbreviatedAxisSpecifier ::= '@'? 11257 * 11258 * Modified for XPtr range support as: 11259 * 11260 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate* 11261 * | AbbreviatedStep 11262 * | 'range-to' '(' Expr ')' Predicate* 11263 * 11264 * Compile one step in a Location Path 11265 * A location step of . is short for self::node(). This is 11266 * particularly useful in conjunction with //. For example, the 11267 * location path .//para is short for 11268 * self::node()/descendant-or-self::node()/child::para 11269 * and so will select all para descendant elements of the context 11270 * node. 11271 * Similarly, a location step of .. is short for parent::node(). 11272 * For example, ../title is short for parent::node()/child::title 11273 * and so will select the title children of the parent of the context 11274 * node. 11275 */ 11276 static void 11277 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) { 11278 #ifdef LIBXML_XPTR_LOCS_ENABLED 11279 int rangeto = 0; 11280 int op2 = -1; 11281 #endif 11282 11283 SKIP_BLANKS; 11284 if ((CUR == '.') && (NXT(1) == '.')) { 11285 SKIP(2); 11286 SKIP_BLANKS; 11287 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT, 11288 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11289 } else if (CUR == '.') { 11290 NEXT; 11291 SKIP_BLANKS; 11292 } else { 11293 xmlChar *name = NULL; 11294 xmlChar *prefix = NULL; 11295 xmlXPathTestVal test = (xmlXPathTestVal) 0; 11296 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0; 11297 xmlXPathTypeVal type = (xmlXPathTypeVal) 0; 11298 int op1; 11299 11300 /* 11301 * The modification needed for XPointer change to the production 11302 */ 11303 #ifdef LIBXML_XPTR_LOCS_ENABLED 11304 if (ctxt->xptr) { 11305 name = xmlXPathParseNCName(ctxt); 11306 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) { 11307 op2 = ctxt->comp->last; 11308 xmlFree(name); 11309 SKIP_BLANKS; 11310 if (CUR != '(') { 11311 XP_ERROR(XPATH_EXPR_ERROR); 11312 } 11313 NEXT; 11314 SKIP_BLANKS; 11315 11316 xmlXPathCompileExpr(ctxt, 1); 11317 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */ 11318 CHECK_ERROR; 11319 11320 SKIP_BLANKS; 11321 if (CUR != ')') { 11322 XP_ERROR(XPATH_EXPR_ERROR); 11323 } 11324 NEXT; 11325 rangeto = 1; 11326 goto eval_predicates; 11327 } 11328 } 11329 #endif 11330 if (CUR == '*') { 11331 axis = AXIS_CHILD; 11332 } else { 11333 if (name == NULL) 11334 name = xmlXPathParseNCName(ctxt); 11335 if (name != NULL) { 11336 axis = xmlXPathIsAxisName(name); 11337 if (axis != 0) { 11338 SKIP_BLANKS; 11339 if ((CUR == ':') && (NXT(1) == ':')) { 11340 SKIP(2); 11341 xmlFree(name); 11342 name = NULL; 11343 } else { 11344 /* an element name can conflict with an axis one :-\ */ 11345 axis = AXIS_CHILD; 11346 } 11347 } else { 11348 axis = AXIS_CHILD; 11349 } 11350 } else if (CUR == '@') { 11351 NEXT; 11352 axis = AXIS_ATTRIBUTE; 11353 } else { 11354 axis = AXIS_CHILD; 11355 } 11356 } 11357 11358 if (ctxt->error != XPATH_EXPRESSION_OK) { 11359 xmlFree(name); 11360 return; 11361 } 11362 11363 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name); 11364 if (test == 0) 11365 return; 11366 11367 if ((prefix != NULL) && (ctxt->context != NULL) && 11368 (ctxt->context->flags & XML_XPATH_CHECKNS)) { 11369 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) { 11370 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR); 11371 } 11372 } 11373 #ifdef DEBUG_STEP 11374 xmlGenericError(xmlGenericErrorContext, 11375 "Basis : computing new set\n"); 11376 #endif 11377 11378 #ifdef DEBUG_STEP 11379 xmlGenericError(xmlGenericErrorContext, "Basis : "); 11380 if (ctxt->value == NULL) 11381 xmlGenericError(xmlGenericErrorContext, "no value\n"); 11382 else if (ctxt->value->nodesetval == NULL) 11383 xmlGenericError(xmlGenericErrorContext, "Empty\n"); 11384 else 11385 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval); 11386 #endif 11387 11388 #ifdef LIBXML_XPTR_LOCS_ENABLED 11389 eval_predicates: 11390 #endif 11391 op1 = ctxt->comp->last; 11392 ctxt->comp->last = -1; 11393 11394 SKIP_BLANKS; 11395 while (CUR == '[') { 11396 xmlXPathCompPredicate(ctxt, 0); 11397 } 11398 11399 #ifdef LIBXML_XPTR_LOCS_ENABLED 11400 if (rangeto) { 11401 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0); 11402 } else 11403 #endif 11404 if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis, 11405 test, type, (void *)prefix, (void *)name) == -1) { 11406 xmlFree(prefix); 11407 xmlFree(name); 11408 } 11409 } 11410 #ifdef DEBUG_STEP 11411 xmlGenericError(xmlGenericErrorContext, "Step : "); 11412 if (ctxt->value == NULL) 11413 xmlGenericError(xmlGenericErrorContext, "no value\n"); 11414 else if (ctxt->value->nodesetval == NULL) 11415 xmlGenericError(xmlGenericErrorContext, "Empty\n"); 11416 else 11417 xmlGenericErrorContextNodeSet(xmlGenericErrorContext, 11418 ctxt->value->nodesetval); 11419 #endif 11420 } 11421 11422 /** 11423 * xmlXPathCompRelativeLocationPath: 11424 * @ctxt: the XPath Parser context 11425 * 11426 * [3] RelativeLocationPath ::= Step 11427 * | RelativeLocationPath '/' Step 11428 * | AbbreviatedRelativeLocationPath 11429 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step 11430 * 11431 * Compile a relative location path. 11432 */ 11433 static void 11434 xmlXPathCompRelativeLocationPath 11435 (xmlXPathParserContextPtr ctxt) { 11436 SKIP_BLANKS; 11437 if ((CUR == '/') && (NXT(1) == '/')) { 11438 SKIP(2); 11439 SKIP_BLANKS; 11440 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 11441 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11442 } else if (CUR == '/') { 11443 NEXT; 11444 SKIP_BLANKS; 11445 } 11446 xmlXPathCompStep(ctxt); 11447 CHECK_ERROR; 11448 SKIP_BLANKS; 11449 while (CUR == '/') { 11450 if ((CUR == '/') && (NXT(1) == '/')) { 11451 SKIP(2); 11452 SKIP_BLANKS; 11453 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 11454 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11455 xmlXPathCompStep(ctxt); 11456 } else if (CUR == '/') { 11457 NEXT; 11458 SKIP_BLANKS; 11459 xmlXPathCompStep(ctxt); 11460 } 11461 SKIP_BLANKS; 11462 } 11463 } 11464 11465 /** 11466 * xmlXPathCompLocationPath: 11467 * @ctxt: the XPath Parser context 11468 * 11469 * [1] LocationPath ::= RelativeLocationPath 11470 * | AbsoluteLocationPath 11471 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath? 11472 * | AbbreviatedAbsoluteLocationPath 11473 * [10] AbbreviatedAbsoluteLocationPath ::= 11474 * '//' RelativeLocationPath 11475 * 11476 * Compile a location path 11477 * 11478 * // is short for /descendant-or-self::node()/. For example, 11479 * //para is short for /descendant-or-self::node()/child::para and 11480 * so will select any para element in the document (even a para element 11481 * that is a document element will be selected by //para since the 11482 * document element node is a child of the root node); div//para is 11483 * short for div/descendant-or-self::node()/child::para and so will 11484 * select all para descendants of div children. 11485 */ 11486 static void 11487 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) { 11488 SKIP_BLANKS; 11489 if (CUR != '/') { 11490 xmlXPathCompRelativeLocationPath(ctxt); 11491 } else { 11492 while (CUR == '/') { 11493 if ((CUR == '/') && (NXT(1) == '/')) { 11494 SKIP(2); 11495 SKIP_BLANKS; 11496 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 11497 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11498 xmlXPathCompRelativeLocationPath(ctxt); 11499 } else if (CUR == '/') { 11500 NEXT; 11501 SKIP_BLANKS; 11502 if ((CUR != 0 ) && 11503 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') || 11504 (CUR == '@') || (CUR == '*'))) 11505 xmlXPathCompRelativeLocationPath(ctxt); 11506 } 11507 CHECK_ERROR; 11508 } 11509 } 11510 } 11511 11512 /************************************************************************ 11513 * * 11514 * XPath precompiled expression evaluation * 11515 * * 11516 ************************************************************************/ 11517 11518 static int 11519 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op); 11520 11521 #ifdef DEBUG_STEP 11522 static void 11523 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op, 11524 int nbNodes) 11525 { 11526 xmlGenericError(xmlGenericErrorContext, "new step : "); 11527 switch (op->value) { 11528 case AXIS_ANCESTOR: 11529 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' "); 11530 break; 11531 case AXIS_ANCESTOR_OR_SELF: 11532 xmlGenericError(xmlGenericErrorContext, 11533 "axis 'ancestors-or-self' "); 11534 break; 11535 case AXIS_ATTRIBUTE: 11536 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' "); 11537 break; 11538 case AXIS_CHILD: 11539 xmlGenericError(xmlGenericErrorContext, "axis 'child' "); 11540 break; 11541 case AXIS_DESCENDANT: 11542 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' "); 11543 break; 11544 case AXIS_DESCENDANT_OR_SELF: 11545 xmlGenericError(xmlGenericErrorContext, 11546 "axis 'descendant-or-self' "); 11547 break; 11548 case AXIS_FOLLOWING: 11549 xmlGenericError(xmlGenericErrorContext, "axis 'following' "); 11550 break; 11551 case AXIS_FOLLOWING_SIBLING: 11552 xmlGenericError(xmlGenericErrorContext, 11553 "axis 'following-siblings' "); 11554 break; 11555 case AXIS_NAMESPACE: 11556 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' "); 11557 break; 11558 case AXIS_PARENT: 11559 xmlGenericError(xmlGenericErrorContext, "axis 'parent' "); 11560 break; 11561 case AXIS_PRECEDING: 11562 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' "); 11563 break; 11564 case AXIS_PRECEDING_SIBLING: 11565 xmlGenericError(xmlGenericErrorContext, 11566 "axis 'preceding-sibling' "); 11567 break; 11568 case AXIS_SELF: 11569 xmlGenericError(xmlGenericErrorContext, "axis 'self' "); 11570 break; 11571 } 11572 xmlGenericError(xmlGenericErrorContext, 11573 " context contains %d nodes\n", nbNodes); 11574 switch (op->value2) { 11575 case NODE_TEST_NONE: 11576 xmlGenericError(xmlGenericErrorContext, 11577 " searching for none !!!\n"); 11578 break; 11579 case NODE_TEST_TYPE: 11580 xmlGenericError(xmlGenericErrorContext, 11581 " searching for type %d\n", op->value3); 11582 break; 11583 case NODE_TEST_PI: 11584 xmlGenericError(xmlGenericErrorContext, 11585 " searching for PI !!!\n"); 11586 break; 11587 case NODE_TEST_ALL: 11588 xmlGenericError(xmlGenericErrorContext, 11589 " searching for *\n"); 11590 break; 11591 case NODE_TEST_NS: 11592 xmlGenericError(xmlGenericErrorContext, 11593 " searching for namespace %s\n", 11594 op->value5); 11595 break; 11596 case NODE_TEST_NAME: 11597 xmlGenericError(xmlGenericErrorContext, 11598 " searching for name %s\n", op->value5); 11599 if (op->value4) 11600 xmlGenericError(xmlGenericErrorContext, 11601 " with namespace %s\n", op->value4); 11602 break; 11603 } 11604 xmlGenericError(xmlGenericErrorContext, "Testing : "); 11605 } 11606 #endif /* DEBUG_STEP */ 11607 11608 /** 11609 * xmlXPathNodeSetFilter: 11610 * @ctxt: the XPath Parser context 11611 * @set: the node set to filter 11612 * @filterOpIndex: the index of the predicate/filter op 11613 * @minPos: minimum position in the filtered set (1-based) 11614 * @maxPos: maximum position in the filtered set (1-based) 11615 * @hasNsNodes: true if the node set may contain namespace nodes 11616 * 11617 * Filter a node set, keeping only nodes for which the predicate expression 11618 * matches. Afterwards, keep only nodes between minPos and maxPos in the 11619 * filtered result. 11620 */ 11621 static void 11622 xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt, 11623 xmlNodeSetPtr set, 11624 int filterOpIndex, 11625 int minPos, int maxPos, 11626 int hasNsNodes) 11627 { 11628 xmlXPathContextPtr xpctxt; 11629 xmlNodePtr oldnode; 11630 xmlDocPtr olddoc; 11631 xmlXPathStepOpPtr filterOp; 11632 int oldcs, oldpp; 11633 int i, j, pos; 11634 11635 if ((set == NULL) || (set->nodeNr == 0)) 11636 return; 11637 11638 /* 11639 * Check if the node set contains a sufficient number of nodes for 11640 * the requested range. 11641 */ 11642 if (set->nodeNr < minPos) { 11643 xmlXPathNodeSetClear(set, hasNsNodes); 11644 return; 11645 } 11646 11647 xpctxt = ctxt->context; 11648 oldnode = xpctxt->node; 11649 olddoc = xpctxt->doc; 11650 oldcs = xpctxt->contextSize; 11651 oldpp = xpctxt->proximityPosition; 11652 filterOp = &ctxt->comp->steps[filterOpIndex]; 11653 11654 xpctxt->contextSize = set->nodeNr; 11655 11656 for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) { 11657 xmlNodePtr node = set->nodeTab[i]; 11658 int res; 11659 11660 xpctxt->node = node; 11661 xpctxt->proximityPosition = i + 1; 11662 11663 /* 11664 * Also set the xpath document in case things like 11665 * key() are evaluated in the predicate. 11666 * 11667 * TODO: Get real doc for namespace nodes. 11668 */ 11669 if ((node->type != XML_NAMESPACE_DECL) && 11670 (node->doc != NULL)) 11671 xpctxt->doc = node->doc; 11672 11673 res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1); 11674 11675 if (ctxt->error != XPATH_EXPRESSION_OK) 11676 break; 11677 if (res < 0) { 11678 /* Shouldn't happen */ 11679 xmlXPathErr(ctxt, XPATH_EXPR_ERROR); 11680 break; 11681 } 11682 11683 if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) { 11684 if (i != j) { 11685 set->nodeTab[j] = node; 11686 set->nodeTab[i] = NULL; 11687 } 11688 11689 j += 1; 11690 } else { 11691 /* Remove the entry from the initial node set. */ 11692 set->nodeTab[i] = NULL; 11693 if (node->type == XML_NAMESPACE_DECL) 11694 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 11695 } 11696 11697 if (res != 0) { 11698 if (pos == maxPos) { 11699 i += 1; 11700 break; 11701 } 11702 11703 pos += 1; 11704 } 11705 } 11706 11707 /* Free remaining nodes. */ 11708 if (hasNsNodes) { 11709 for (; i < set->nodeNr; i++) { 11710 xmlNodePtr node = set->nodeTab[i]; 11711 if ((node != NULL) && (node->type == XML_NAMESPACE_DECL)) 11712 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 11713 } 11714 } 11715 11716 set->nodeNr = j; 11717 11718 /* If too many elements were removed, shrink table to preserve memory. */ 11719 if ((set->nodeMax > XML_NODESET_DEFAULT) && 11720 (set->nodeNr < set->nodeMax / 2)) { 11721 xmlNodePtr *tmp; 11722 int nodeMax = set->nodeNr; 11723 11724 if (nodeMax < XML_NODESET_DEFAULT) 11725 nodeMax = XML_NODESET_DEFAULT; 11726 tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab, 11727 nodeMax * sizeof(xmlNodePtr)); 11728 if (tmp == NULL) { 11729 xmlXPathPErrMemory(ctxt, "shrinking nodeset\n"); 11730 } else { 11731 set->nodeTab = tmp; 11732 set->nodeMax = nodeMax; 11733 } 11734 } 11735 11736 xpctxt->node = oldnode; 11737 xpctxt->doc = olddoc; 11738 xpctxt->contextSize = oldcs; 11739 xpctxt->proximityPosition = oldpp; 11740 } 11741 11742 #ifdef LIBXML_XPTR_LOCS_ENABLED 11743 /** 11744 * xmlXPathLocationSetFilter: 11745 * @ctxt: the XPath Parser context 11746 * @locset: the location set to filter 11747 * @filterOpIndex: the index of the predicate/filter op 11748 * @minPos: minimum position in the filtered set (1-based) 11749 * @maxPos: maximum position in the filtered set (1-based) 11750 * 11751 * Filter a location set, keeping only nodes for which the predicate 11752 * expression matches. Afterwards, keep only nodes between minPos and maxPos 11753 * in the filtered result. 11754 */ 11755 static void 11756 xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt, 11757 xmlLocationSetPtr locset, 11758 int filterOpIndex, 11759 int minPos, int maxPos) 11760 { 11761 xmlXPathContextPtr xpctxt; 11762 xmlNodePtr oldnode; 11763 xmlDocPtr olddoc; 11764 xmlXPathStepOpPtr filterOp; 11765 int oldcs, oldpp; 11766 int i, j, pos; 11767 11768 if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1)) 11769 return; 11770 11771 xpctxt = ctxt->context; 11772 oldnode = xpctxt->node; 11773 olddoc = xpctxt->doc; 11774 oldcs = xpctxt->contextSize; 11775 oldpp = xpctxt->proximityPosition; 11776 filterOp = &ctxt->comp->steps[filterOpIndex]; 11777 11778 xpctxt->contextSize = locset->locNr; 11779 11780 for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) { 11781 xmlNodePtr contextNode = locset->locTab[i]->user; 11782 int res; 11783 11784 xpctxt->node = contextNode; 11785 xpctxt->proximityPosition = i + 1; 11786 11787 /* 11788 * Also set the xpath document in case things like 11789 * key() are evaluated in the predicate. 11790 * 11791 * TODO: Get real doc for namespace nodes. 11792 */ 11793 if ((contextNode->type != XML_NAMESPACE_DECL) && 11794 (contextNode->doc != NULL)) 11795 xpctxt->doc = contextNode->doc; 11796 11797 res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1); 11798 11799 if (ctxt->error != XPATH_EXPRESSION_OK) 11800 break; 11801 if (res < 0) { 11802 /* Shouldn't happen */ 11803 xmlXPathErr(ctxt, XPATH_EXPR_ERROR); 11804 break; 11805 } 11806 11807 if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) { 11808 if (i != j) { 11809 locset->locTab[j] = locset->locTab[i]; 11810 locset->locTab[i] = NULL; 11811 } 11812 11813 j += 1; 11814 } else { 11815 /* Remove the entry from the initial location set. */ 11816 xmlXPathFreeObject(locset->locTab[i]); 11817 locset->locTab[i] = NULL; 11818 } 11819 11820 if (res != 0) { 11821 if (pos == maxPos) { 11822 i += 1; 11823 break; 11824 } 11825 11826 pos += 1; 11827 } 11828 } 11829 11830 /* Free remaining nodes. */ 11831 for (; i < locset->locNr; i++) 11832 xmlXPathFreeObject(locset->locTab[i]); 11833 11834 locset->locNr = j; 11835 11836 /* If too many elements were removed, shrink table to preserve memory. */ 11837 if ((locset->locMax > XML_NODESET_DEFAULT) && 11838 (locset->locNr < locset->locMax / 2)) { 11839 xmlXPathObjectPtr *tmp; 11840 int locMax = locset->locNr; 11841 11842 if (locMax < XML_NODESET_DEFAULT) 11843 locMax = XML_NODESET_DEFAULT; 11844 tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab, 11845 locMax * sizeof(xmlXPathObjectPtr)); 11846 if (tmp == NULL) { 11847 xmlXPathPErrMemory(ctxt, "shrinking locset\n"); 11848 } else { 11849 locset->locTab = tmp; 11850 locset->locMax = locMax; 11851 } 11852 } 11853 11854 xpctxt->node = oldnode; 11855 xpctxt->doc = olddoc; 11856 xpctxt->contextSize = oldcs; 11857 xpctxt->proximityPosition = oldpp; 11858 } 11859 #endif /* LIBXML_XPTR_LOCS_ENABLED */ 11860 11861 /** 11862 * xmlXPathCompOpEvalPredicate: 11863 * @ctxt: the XPath Parser context 11864 * @op: the predicate op 11865 * @set: the node set to filter 11866 * @minPos: minimum position in the filtered set (1-based) 11867 * @maxPos: maximum position in the filtered set (1-based) 11868 * @hasNsNodes: true if the node set may contain namespace nodes 11869 * 11870 * Filter a node set, keeping only nodes for which the sequence of predicate 11871 * expressions matches. Afterwards, keep only nodes between minPos and maxPos 11872 * in the filtered result. 11873 */ 11874 static void 11875 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt, 11876 xmlXPathStepOpPtr op, 11877 xmlNodeSetPtr set, 11878 int minPos, int maxPos, 11879 int hasNsNodes) 11880 { 11881 if (op->ch1 != -1) { 11882 xmlXPathCompExprPtr comp = ctxt->comp; 11883 /* 11884 * Process inner predicates first. 11885 */ 11886 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) { 11887 xmlGenericError(xmlGenericErrorContext, 11888 "xmlXPathCompOpEvalPredicate: Expected a predicate\n"); 11889 XP_ERROR(XPATH_INVALID_OPERAND); 11890 } 11891 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH) 11892 XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED); 11893 ctxt->context->depth += 1; 11894 xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set, 11895 1, set->nodeNr, hasNsNodes); 11896 ctxt->context->depth -= 1; 11897 CHECK_ERROR; 11898 } 11899 11900 if (op->ch2 != -1) 11901 xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes); 11902 } 11903 11904 static int 11905 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt, 11906 xmlXPathStepOpPtr op, 11907 int *maxPos) 11908 { 11909 11910 xmlXPathStepOpPtr exprOp; 11911 11912 /* 11913 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet! 11914 */ 11915 11916 /* 11917 * If not -1, then ch1 will point to: 11918 * 1) For predicates (XPATH_OP_PREDICATE): 11919 * - an inner predicate operator 11920 * 2) For filters (XPATH_OP_FILTER): 11921 * - an inner filter operator OR 11922 * - an expression selecting the node set. 11923 * E.g. "key('a', 'b')" or "(//foo | //bar)". 11924 */ 11925 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER)) 11926 return(0); 11927 11928 if (op->ch2 != -1) { 11929 exprOp = &ctxt->comp->steps[op->ch2]; 11930 } else 11931 return(0); 11932 11933 if ((exprOp != NULL) && 11934 (exprOp->op == XPATH_OP_VALUE) && 11935 (exprOp->value4 != NULL) && 11936 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER)) 11937 { 11938 double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval; 11939 11940 /* 11941 * We have a "[n]" predicate here. 11942 * TODO: Unfortunately this simplistic test here is not 11943 * able to detect a position() predicate in compound 11944 * expressions like "[@attr = 'a" and position() = 1], 11945 * and even not the usage of position() in 11946 * "[position() = 1]"; thus - obviously - a position-range, 11947 * like it "[position() < 5]", is also not detected. 11948 * Maybe we could rewrite the AST to ease the optimization. 11949 */ 11950 11951 if ((floatval > INT_MIN) && (floatval < INT_MAX)) { 11952 *maxPos = (int) floatval; 11953 if (floatval == (double) *maxPos) 11954 return(1); 11955 } 11956 } 11957 return(0); 11958 } 11959 11960 static int 11961 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, 11962 xmlXPathStepOpPtr op, 11963 xmlNodePtr * first, xmlNodePtr * last, 11964 int toBool) 11965 { 11966 11967 #define XP_TEST_HIT \ 11968 if (hasAxisRange != 0) { \ 11969 if (++pos == maxPos) { \ 11970 if (addNode(seq, cur) < 0) \ 11971 ctxt->error = XPATH_MEMORY_ERROR; \ 11972 goto axis_range_end; } \ 11973 } else { \ 11974 if (addNode(seq, cur) < 0) \ 11975 ctxt->error = XPATH_MEMORY_ERROR; \ 11976 if (breakOnFirstHit) goto first_hit; } 11977 11978 #define XP_TEST_HIT_NS \ 11979 if (hasAxisRange != 0) { \ 11980 if (++pos == maxPos) { \ 11981 hasNsNodes = 1; \ 11982 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \ 11983 ctxt->error = XPATH_MEMORY_ERROR; \ 11984 goto axis_range_end; } \ 11985 } else { \ 11986 hasNsNodes = 1; \ 11987 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \ 11988 ctxt->error = XPATH_MEMORY_ERROR; \ 11989 if (breakOnFirstHit) goto first_hit; } 11990 11991 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value; 11992 xmlXPathTestVal test = (xmlXPathTestVal) op->value2; 11993 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3; 11994 const xmlChar *prefix = op->value4; 11995 const xmlChar *name = op->value5; 11996 const xmlChar *URI = NULL; 11997 11998 #ifdef DEBUG_STEP 11999 int nbMatches = 0, prevMatches = 0; 12000 #endif 12001 int total = 0, hasNsNodes = 0; 12002 /* The popped object holding the context nodes */ 12003 xmlXPathObjectPtr obj; 12004 /* The set of context nodes for the node tests */ 12005 xmlNodeSetPtr contextSeq; 12006 int contextIdx; 12007 xmlNodePtr contextNode; 12008 /* The final resulting node set wrt to all context nodes */ 12009 xmlNodeSetPtr outSeq; 12010 /* 12011 * The temporary resulting node set wrt 1 context node. 12012 * Used to feed predicate evaluation. 12013 */ 12014 xmlNodeSetPtr seq; 12015 xmlNodePtr cur; 12016 /* First predicate operator */ 12017 xmlXPathStepOpPtr predOp; 12018 int maxPos; /* The requested position() (when a "[n]" predicate) */ 12019 int hasPredicateRange, hasAxisRange, pos; 12020 int breakOnFirstHit; 12021 12022 xmlXPathTraversalFunction next = NULL; 12023 int (*addNode) (xmlNodeSetPtr, xmlNodePtr); 12024 xmlXPathNodeSetMergeFunction mergeAndClear; 12025 xmlNodePtr oldContextNode; 12026 xmlXPathContextPtr xpctxt = ctxt->context; 12027 12028 12029 CHECK_TYPE0(XPATH_NODESET); 12030 obj = valuePop(ctxt); 12031 /* 12032 * Setup namespaces. 12033 */ 12034 if (prefix != NULL) { 12035 URI = xmlXPathNsLookup(xpctxt, prefix); 12036 if (URI == NULL) { 12037 xmlXPathReleaseObject(xpctxt, obj); 12038 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); 12039 } 12040 } 12041 /* 12042 * Setup axis. 12043 * 12044 * MAYBE FUTURE TODO: merging optimizations: 12045 * - If the nodes to be traversed wrt to the initial nodes and 12046 * the current axis cannot overlap, then we could avoid searching 12047 * for duplicates during the merge. 12048 * But the question is how/when to evaluate if they cannot overlap. 12049 * Example: if we know that for two initial nodes, the one is 12050 * not in the ancestor-or-self axis of the other, then we could safely 12051 * avoid a duplicate-aware merge, if the axis to be traversed is e.g. 12052 * the descendant-or-self axis. 12053 */ 12054 mergeAndClear = xmlXPathNodeSetMergeAndClear; 12055 switch (axis) { 12056 case AXIS_ANCESTOR: 12057 first = NULL; 12058 next = xmlXPathNextAncestor; 12059 break; 12060 case AXIS_ANCESTOR_OR_SELF: 12061 first = NULL; 12062 next = xmlXPathNextAncestorOrSelf; 12063 break; 12064 case AXIS_ATTRIBUTE: 12065 first = NULL; 12066 last = NULL; 12067 next = xmlXPathNextAttribute; 12068 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12069 break; 12070 case AXIS_CHILD: 12071 last = NULL; 12072 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) && 12073 (type == NODE_TYPE_NODE)) 12074 { 12075 /* 12076 * Optimization if an element node type is 'element'. 12077 */ 12078 next = xmlXPathNextChildElement; 12079 } else 12080 next = xmlXPathNextChild; 12081 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12082 break; 12083 case AXIS_DESCENDANT: 12084 last = NULL; 12085 next = xmlXPathNextDescendant; 12086 break; 12087 case AXIS_DESCENDANT_OR_SELF: 12088 last = NULL; 12089 next = xmlXPathNextDescendantOrSelf; 12090 break; 12091 case AXIS_FOLLOWING: 12092 last = NULL; 12093 next = xmlXPathNextFollowing; 12094 break; 12095 case AXIS_FOLLOWING_SIBLING: 12096 last = NULL; 12097 next = xmlXPathNextFollowingSibling; 12098 break; 12099 case AXIS_NAMESPACE: 12100 first = NULL; 12101 last = NULL; 12102 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; 12103 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12104 break; 12105 case AXIS_PARENT: 12106 first = NULL; 12107 next = xmlXPathNextParent; 12108 break; 12109 case AXIS_PRECEDING: 12110 first = NULL; 12111 next = xmlXPathNextPrecedingInternal; 12112 break; 12113 case AXIS_PRECEDING_SIBLING: 12114 first = NULL; 12115 next = xmlXPathNextPrecedingSibling; 12116 break; 12117 case AXIS_SELF: 12118 first = NULL; 12119 last = NULL; 12120 next = xmlXPathNextSelf; 12121 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12122 break; 12123 } 12124 12125 #ifdef DEBUG_STEP 12126 xmlXPathDebugDumpStepAxis(op, 12127 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0); 12128 #endif 12129 12130 if (next == NULL) { 12131 xmlXPathReleaseObject(xpctxt, obj); 12132 return(0); 12133 } 12134 contextSeq = obj->nodesetval; 12135 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) { 12136 xmlXPathReleaseObject(xpctxt, obj); 12137 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL)); 12138 return(0); 12139 } 12140 /* 12141 * Predicate optimization --------------------------------------------- 12142 * If this step has a last predicate, which contains a position(), 12143 * then we'll optimize (although not exactly "position()", but only 12144 * the short-hand form, i.e., "[n]". 12145 * 12146 * Example - expression "/foo[parent::bar][1]": 12147 * 12148 * COLLECT 'child' 'name' 'node' foo -- op (we are here) 12149 * ROOT -- op->ch1 12150 * PREDICATE -- op->ch2 (predOp) 12151 * PREDICATE -- predOp->ch1 = [parent::bar] 12152 * SORT 12153 * COLLECT 'parent' 'name' 'node' bar 12154 * NODE 12155 * ELEM Object is a number : 1 -- predOp->ch2 = [1] 12156 * 12157 */ 12158 maxPos = 0; 12159 predOp = NULL; 12160 hasPredicateRange = 0; 12161 hasAxisRange = 0; 12162 if (op->ch2 != -1) { 12163 /* 12164 * There's at least one predicate. 16 == XPATH_OP_PREDICATE 12165 */ 12166 predOp = &ctxt->comp->steps[op->ch2]; 12167 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) { 12168 if (predOp->ch1 != -1) { 12169 /* 12170 * Use the next inner predicate operator. 12171 */ 12172 predOp = &ctxt->comp->steps[predOp->ch1]; 12173 hasPredicateRange = 1; 12174 } else { 12175 /* 12176 * There's no other predicate than the [n] predicate. 12177 */ 12178 predOp = NULL; 12179 hasAxisRange = 1; 12180 } 12181 } 12182 } 12183 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0; 12184 /* 12185 * Axis traversal ----------------------------------------------------- 12186 */ 12187 /* 12188 * 2.3 Node Tests 12189 * - For the attribute axis, the principal node type is attribute. 12190 * - For the namespace axis, the principal node type is namespace. 12191 * - For other axes, the principal node type is element. 12192 * 12193 * A node test * is true for any node of the 12194 * principal node type. For example, child::* will 12195 * select all element children of the context node 12196 */ 12197 oldContextNode = xpctxt->node; 12198 addNode = xmlXPathNodeSetAddUnique; 12199 outSeq = NULL; 12200 seq = NULL; 12201 contextNode = NULL; 12202 contextIdx = 0; 12203 12204 12205 while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) && 12206 (ctxt->error == XPATH_EXPRESSION_OK)) { 12207 xpctxt->node = contextSeq->nodeTab[contextIdx++]; 12208 12209 if (seq == NULL) { 12210 seq = xmlXPathNodeSetCreate(NULL); 12211 if (seq == NULL) { 12212 /* TODO: Propagate memory error. */ 12213 total = 0; 12214 goto error; 12215 } 12216 } 12217 /* 12218 * Traverse the axis and test the nodes. 12219 */ 12220 pos = 0; 12221 cur = NULL; 12222 hasNsNodes = 0; 12223 do { 12224 if (OP_LIMIT_EXCEEDED(ctxt, 1)) 12225 goto error; 12226 12227 cur = next(ctxt, cur); 12228 if (cur == NULL) 12229 break; 12230 12231 /* 12232 * QUESTION TODO: What does the "first" and "last" stuff do? 12233 */ 12234 if ((first != NULL) && (*first != NULL)) { 12235 if (*first == cur) 12236 break; 12237 if (((total % 256) == 0) && 12238 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 12239 (xmlXPathCmpNodesExt(*first, cur) >= 0)) 12240 #else 12241 (xmlXPathCmpNodes(*first, cur) >= 0)) 12242 #endif 12243 { 12244 break; 12245 } 12246 } 12247 if ((last != NULL) && (*last != NULL)) { 12248 if (*last == cur) 12249 break; 12250 if (((total % 256) == 0) && 12251 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 12252 (xmlXPathCmpNodesExt(cur, *last) >= 0)) 12253 #else 12254 (xmlXPathCmpNodes(cur, *last) >= 0)) 12255 #endif 12256 { 12257 break; 12258 } 12259 } 12260 12261 total++; 12262 12263 #ifdef DEBUG_STEP 12264 xmlGenericError(xmlGenericErrorContext, " %s", cur->name); 12265 #endif 12266 12267 switch (test) { 12268 case NODE_TEST_NONE: 12269 total = 0; 12270 STRANGE 12271 goto error; 12272 case NODE_TEST_TYPE: 12273 if (type == NODE_TYPE_NODE) { 12274 switch (cur->type) { 12275 case XML_DOCUMENT_NODE: 12276 case XML_HTML_DOCUMENT_NODE: 12277 case XML_ELEMENT_NODE: 12278 case XML_ATTRIBUTE_NODE: 12279 case XML_PI_NODE: 12280 case XML_COMMENT_NODE: 12281 case XML_CDATA_SECTION_NODE: 12282 case XML_TEXT_NODE: 12283 XP_TEST_HIT 12284 break; 12285 case XML_NAMESPACE_DECL: { 12286 if (axis == AXIS_NAMESPACE) { 12287 XP_TEST_HIT_NS 12288 } else { 12289 hasNsNodes = 1; 12290 XP_TEST_HIT 12291 } 12292 break; 12293 } 12294 default: 12295 break; 12296 } 12297 } else if (cur->type == (xmlElementType) type) { 12298 if (cur->type == XML_NAMESPACE_DECL) 12299 XP_TEST_HIT_NS 12300 else 12301 XP_TEST_HIT 12302 } else if ((type == NODE_TYPE_TEXT) && 12303 (cur->type == XML_CDATA_SECTION_NODE)) 12304 { 12305 XP_TEST_HIT 12306 } 12307 break; 12308 case NODE_TEST_PI: 12309 if ((cur->type == XML_PI_NODE) && 12310 ((name == NULL) || xmlStrEqual(name, cur->name))) 12311 { 12312 XP_TEST_HIT 12313 } 12314 break; 12315 case NODE_TEST_ALL: 12316 if (axis == AXIS_ATTRIBUTE) { 12317 if (cur->type == XML_ATTRIBUTE_NODE) 12318 { 12319 if (prefix == NULL) 12320 { 12321 XP_TEST_HIT 12322 } else if ((cur->ns != NULL) && 12323 (xmlStrEqual(URI, cur->ns->href))) 12324 { 12325 XP_TEST_HIT 12326 } 12327 } 12328 } else if (axis == AXIS_NAMESPACE) { 12329 if (cur->type == XML_NAMESPACE_DECL) 12330 { 12331 XP_TEST_HIT_NS 12332 } 12333 } else { 12334 if (cur->type == XML_ELEMENT_NODE) { 12335 if (prefix == NULL) 12336 { 12337 XP_TEST_HIT 12338 12339 } else if ((cur->ns != NULL) && 12340 (xmlStrEqual(URI, cur->ns->href))) 12341 { 12342 XP_TEST_HIT 12343 } 12344 } 12345 } 12346 break; 12347 case NODE_TEST_NS:{ 12348 TODO; 12349 break; 12350 } 12351 case NODE_TEST_NAME: 12352 if (axis == AXIS_ATTRIBUTE) { 12353 if (cur->type != XML_ATTRIBUTE_NODE) 12354 break; 12355 } else if (axis == AXIS_NAMESPACE) { 12356 if (cur->type != XML_NAMESPACE_DECL) 12357 break; 12358 } else { 12359 if (cur->type != XML_ELEMENT_NODE) 12360 break; 12361 } 12362 switch (cur->type) { 12363 case XML_ELEMENT_NODE: 12364 if (xmlStrEqual(name, cur->name)) { 12365 if (prefix == NULL) { 12366 if (cur->ns == NULL) 12367 { 12368 XP_TEST_HIT 12369 } 12370 } else { 12371 if ((cur->ns != NULL) && 12372 (xmlStrEqual(URI, cur->ns->href))) 12373 { 12374 XP_TEST_HIT 12375 } 12376 } 12377 } 12378 break; 12379 case XML_ATTRIBUTE_NODE:{ 12380 xmlAttrPtr attr = (xmlAttrPtr) cur; 12381 12382 if (xmlStrEqual(name, attr->name)) { 12383 if (prefix == NULL) { 12384 if ((attr->ns == NULL) || 12385 (attr->ns->prefix == NULL)) 12386 { 12387 XP_TEST_HIT 12388 } 12389 } else { 12390 if ((attr->ns != NULL) && 12391 (xmlStrEqual(URI, 12392 attr->ns->href))) 12393 { 12394 XP_TEST_HIT 12395 } 12396 } 12397 } 12398 break; 12399 } 12400 case XML_NAMESPACE_DECL: 12401 if (cur->type == XML_NAMESPACE_DECL) { 12402 xmlNsPtr ns = (xmlNsPtr) cur; 12403 12404 if ((ns->prefix != NULL) && (name != NULL) 12405 && (xmlStrEqual(ns->prefix, name))) 12406 { 12407 XP_TEST_HIT_NS 12408 } 12409 } 12410 break; 12411 default: 12412 break; 12413 } 12414 break; 12415 } /* switch(test) */ 12416 } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK)); 12417 12418 goto apply_predicates; 12419 12420 axis_range_end: /* ----------------------------------------------------- */ 12421 /* 12422 * We have a "/foo[n]", and position() = n was reached. 12423 * Note that we can have as well "/foo/::parent::foo[1]", so 12424 * a duplicate-aware merge is still needed. 12425 * Merge with the result. 12426 */ 12427 if (outSeq == NULL) { 12428 outSeq = seq; 12429 seq = NULL; 12430 } else 12431 /* TODO: Check memory error. */ 12432 outSeq = mergeAndClear(outSeq, seq); 12433 /* 12434 * Break if only a true/false result was requested. 12435 */ 12436 if (toBool) 12437 break; 12438 continue; 12439 12440 first_hit: /* ---------------------------------------------------------- */ 12441 /* 12442 * Break if only a true/false result was requested and 12443 * no predicates existed and a node test succeeded. 12444 */ 12445 if (outSeq == NULL) { 12446 outSeq = seq; 12447 seq = NULL; 12448 } else 12449 /* TODO: Check memory error. */ 12450 outSeq = mergeAndClear(outSeq, seq); 12451 break; 12452 12453 #ifdef DEBUG_STEP 12454 if (seq != NULL) 12455 nbMatches += seq->nodeNr; 12456 #endif 12457 12458 apply_predicates: /* --------------------------------------------------- */ 12459 if (ctxt->error != XPATH_EXPRESSION_OK) 12460 goto error; 12461 12462 /* 12463 * Apply predicates. 12464 */ 12465 if ((predOp != NULL) && (seq->nodeNr > 0)) { 12466 /* 12467 * E.g. when we have a "/foo[some expression][n]". 12468 */ 12469 /* 12470 * QUESTION TODO: The old predicate evaluation took into 12471 * account location-sets. 12472 * (E.g. ctxt->value->type == XPATH_LOCATIONSET) 12473 * Do we expect such a set here? 12474 * All what I learned now from the evaluation semantics 12475 * does not indicate that a location-set will be processed 12476 * here, so this looks OK. 12477 */ 12478 /* 12479 * Iterate over all predicates, starting with the outermost 12480 * predicate. 12481 * TODO: Problem: we cannot execute the inner predicates first 12482 * since we cannot go back *up* the operator tree! 12483 * Options we have: 12484 * 1) Use of recursive functions (like is it currently done 12485 * via xmlXPathCompOpEval()) 12486 * 2) Add a predicate evaluation information stack to the 12487 * context struct 12488 * 3) Change the way the operators are linked; we need a 12489 * "parent" field on xmlXPathStepOp 12490 * 12491 * For the moment, I'll try to solve this with a recursive 12492 * function: xmlXPathCompOpEvalPredicate(). 12493 */ 12494 if (hasPredicateRange != 0) 12495 xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos, 12496 hasNsNodes); 12497 else 12498 xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr, 12499 hasNsNodes); 12500 12501 if (ctxt->error != XPATH_EXPRESSION_OK) { 12502 total = 0; 12503 goto error; 12504 } 12505 } 12506 12507 if (seq->nodeNr > 0) { 12508 /* 12509 * Add to result set. 12510 */ 12511 if (outSeq == NULL) { 12512 outSeq = seq; 12513 seq = NULL; 12514 } else { 12515 /* TODO: Check memory error. */ 12516 outSeq = mergeAndClear(outSeq, seq); 12517 } 12518 12519 if (toBool) 12520 break; 12521 } 12522 } 12523 12524 error: 12525 if ((obj->boolval) && (obj->user != NULL)) { 12526 /* 12527 * QUESTION TODO: What does this do and why? 12528 * TODO: Do we have to do this also for the "error" 12529 * cleanup further down? 12530 */ 12531 ctxt->value->boolval = 1; 12532 ctxt->value->user = obj->user; 12533 obj->user = NULL; 12534 obj->boolval = 0; 12535 } 12536 xmlXPathReleaseObject(xpctxt, obj); 12537 12538 /* 12539 * Ensure we return at least an empty set. 12540 */ 12541 if (outSeq == NULL) { 12542 if ((seq != NULL) && (seq->nodeNr == 0)) 12543 outSeq = seq; 12544 else 12545 /* TODO: Check memory error. */ 12546 outSeq = xmlXPathNodeSetCreate(NULL); 12547 } 12548 if ((seq != NULL) && (seq != outSeq)) { 12549 xmlXPathFreeNodeSet(seq); 12550 } 12551 /* 12552 * Hand over the result. Better to push the set also in 12553 * case of errors. 12554 */ 12555 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq)); 12556 /* 12557 * Reset the context node. 12558 */ 12559 xpctxt->node = oldContextNode; 12560 /* 12561 * When traversing the namespace axis in "toBool" mode, it's 12562 * possible that tmpNsList wasn't freed. 12563 */ 12564 if (xpctxt->tmpNsList != NULL) { 12565 xmlFree(xpctxt->tmpNsList); 12566 xpctxt->tmpNsList = NULL; 12567 } 12568 12569 #ifdef DEBUG_STEP 12570 xmlGenericError(xmlGenericErrorContext, 12571 "\nExamined %d nodes, found %d nodes at that step\n", 12572 total, nbMatches); 12573 #endif 12574 12575 return(total); 12576 } 12577 12578 static int 12579 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt, 12580 xmlXPathStepOpPtr op, xmlNodePtr * first); 12581 12582 /** 12583 * xmlXPathCompOpEvalFirst: 12584 * @ctxt: the XPath parser context with the compiled expression 12585 * @op: an XPath compiled operation 12586 * @first: the first elem found so far 12587 * 12588 * Evaluate the Precompiled XPath operation searching only the first 12589 * element in document order 12590 * 12591 * Returns the number of examined objects. 12592 */ 12593 static int 12594 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt, 12595 xmlXPathStepOpPtr op, xmlNodePtr * first) 12596 { 12597 int total = 0, cur; 12598 xmlXPathCompExprPtr comp; 12599 xmlXPathObjectPtr arg1, arg2; 12600 12601 CHECK_ERROR0; 12602 if (OP_LIMIT_EXCEEDED(ctxt, 1)) 12603 return(0); 12604 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH) 12605 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED); 12606 ctxt->context->depth += 1; 12607 comp = ctxt->comp; 12608 switch (op->op) { 12609 case XPATH_OP_END: 12610 break; 12611 case XPATH_OP_UNION: 12612 total = 12613 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1], 12614 first); 12615 CHECK_ERROR0; 12616 if ((ctxt->value != NULL) 12617 && (ctxt->value->type == XPATH_NODESET) 12618 && (ctxt->value->nodesetval != NULL) 12619 && (ctxt->value->nodesetval->nodeNr >= 1)) { 12620 /* 12621 * limit tree traversing to first node in the result 12622 */ 12623 /* 12624 * OPTIMIZE TODO: This implicitly sorts 12625 * the result, even if not needed. E.g. if the argument 12626 * of the count() function, no sorting is needed. 12627 * OPTIMIZE TODO: How do we know if the node-list wasn't 12628 * already sorted? 12629 */ 12630 if (ctxt->value->nodesetval->nodeNr > 1) 12631 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12632 *first = ctxt->value->nodesetval->nodeTab[0]; 12633 } 12634 cur = 12635 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2], 12636 first); 12637 CHECK_ERROR0; 12638 12639 arg2 = valuePop(ctxt); 12640 arg1 = valuePop(ctxt); 12641 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) || 12642 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) { 12643 xmlXPathReleaseObject(ctxt->context, arg1); 12644 xmlXPathReleaseObject(ctxt->context, arg2); 12645 XP_ERROR0(XPATH_INVALID_TYPE); 12646 } 12647 if ((ctxt->context->opLimit != 0) && 12648 (((arg1->nodesetval != NULL) && 12649 (xmlXPathCheckOpLimit(ctxt, 12650 arg1->nodesetval->nodeNr) < 0)) || 12651 ((arg2->nodesetval != NULL) && 12652 (xmlXPathCheckOpLimit(ctxt, 12653 arg2->nodesetval->nodeNr) < 0)))) { 12654 xmlXPathReleaseObject(ctxt->context, arg1); 12655 xmlXPathReleaseObject(ctxt->context, arg2); 12656 break; 12657 } 12658 12659 /* TODO: Check memory error. */ 12660 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 12661 arg2->nodesetval); 12662 valuePush(ctxt, arg1); 12663 xmlXPathReleaseObject(ctxt->context, arg2); 12664 /* optimizer */ 12665 if (total > cur) 12666 xmlXPathCompSwap(op); 12667 total += cur; 12668 break; 12669 case XPATH_OP_ROOT: 12670 xmlXPathRoot(ctxt); 12671 break; 12672 case XPATH_OP_NODE: 12673 if (op->ch1 != -1) 12674 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12675 CHECK_ERROR0; 12676 if (op->ch2 != -1) 12677 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12678 CHECK_ERROR0; 12679 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 12680 ctxt->context->node)); 12681 break; 12682 case XPATH_OP_COLLECT:{ 12683 if (op->ch1 == -1) 12684 break; 12685 12686 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12687 CHECK_ERROR0; 12688 12689 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0); 12690 break; 12691 } 12692 case XPATH_OP_VALUE: 12693 valuePush(ctxt, 12694 xmlXPathCacheObjectCopy(ctxt->context, 12695 (xmlXPathObjectPtr) op->value4)); 12696 break; 12697 case XPATH_OP_SORT: 12698 if (op->ch1 != -1) 12699 total += 12700 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1], 12701 first); 12702 CHECK_ERROR0; 12703 if ((ctxt->value != NULL) 12704 && (ctxt->value->type == XPATH_NODESET) 12705 && (ctxt->value->nodesetval != NULL) 12706 && (ctxt->value->nodesetval->nodeNr > 1)) 12707 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12708 break; 12709 #ifdef XP_OPTIMIZED_FILTER_FIRST 12710 case XPATH_OP_FILTER: 12711 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first); 12712 break; 12713 #endif 12714 default: 12715 total += xmlXPathCompOpEval(ctxt, op); 12716 break; 12717 } 12718 12719 ctxt->context->depth -= 1; 12720 return(total); 12721 } 12722 12723 /** 12724 * xmlXPathCompOpEvalLast: 12725 * @ctxt: the XPath parser context with the compiled expression 12726 * @op: an XPath compiled operation 12727 * @last: the last elem found so far 12728 * 12729 * Evaluate the Precompiled XPath operation searching only the last 12730 * element in document order 12731 * 12732 * Returns the number of nodes traversed 12733 */ 12734 static int 12735 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op, 12736 xmlNodePtr * last) 12737 { 12738 int total = 0, cur; 12739 xmlXPathCompExprPtr comp; 12740 xmlXPathObjectPtr arg1, arg2; 12741 12742 CHECK_ERROR0; 12743 if (OP_LIMIT_EXCEEDED(ctxt, 1)) 12744 return(0); 12745 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH) 12746 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED); 12747 ctxt->context->depth += 1; 12748 comp = ctxt->comp; 12749 switch (op->op) { 12750 case XPATH_OP_END: 12751 break; 12752 case XPATH_OP_UNION: 12753 total = 12754 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last); 12755 CHECK_ERROR0; 12756 if ((ctxt->value != NULL) 12757 && (ctxt->value->type == XPATH_NODESET) 12758 && (ctxt->value->nodesetval != NULL) 12759 && (ctxt->value->nodesetval->nodeNr >= 1)) { 12760 /* 12761 * limit tree traversing to first node in the result 12762 */ 12763 if (ctxt->value->nodesetval->nodeNr > 1) 12764 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12765 *last = 12766 ctxt->value->nodesetval->nodeTab[ctxt->value-> 12767 nodesetval->nodeNr - 12768 1]; 12769 } 12770 cur = 12771 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last); 12772 CHECK_ERROR0; 12773 if ((ctxt->value != NULL) 12774 && (ctxt->value->type == XPATH_NODESET) 12775 && (ctxt->value->nodesetval != NULL) 12776 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */ 12777 } 12778 12779 arg2 = valuePop(ctxt); 12780 arg1 = valuePop(ctxt); 12781 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) || 12782 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) { 12783 xmlXPathReleaseObject(ctxt->context, arg1); 12784 xmlXPathReleaseObject(ctxt->context, arg2); 12785 XP_ERROR0(XPATH_INVALID_TYPE); 12786 } 12787 if ((ctxt->context->opLimit != 0) && 12788 (((arg1->nodesetval != NULL) && 12789 (xmlXPathCheckOpLimit(ctxt, 12790 arg1->nodesetval->nodeNr) < 0)) || 12791 ((arg2->nodesetval != NULL) && 12792 (xmlXPathCheckOpLimit(ctxt, 12793 arg2->nodesetval->nodeNr) < 0)))) { 12794 xmlXPathReleaseObject(ctxt->context, arg1); 12795 xmlXPathReleaseObject(ctxt->context, arg2); 12796 break; 12797 } 12798 12799 /* TODO: Check memory error. */ 12800 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 12801 arg2->nodesetval); 12802 valuePush(ctxt, arg1); 12803 xmlXPathReleaseObject(ctxt->context, arg2); 12804 /* optimizer */ 12805 if (total > cur) 12806 xmlXPathCompSwap(op); 12807 total += cur; 12808 break; 12809 case XPATH_OP_ROOT: 12810 xmlXPathRoot(ctxt); 12811 break; 12812 case XPATH_OP_NODE: 12813 if (op->ch1 != -1) 12814 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12815 CHECK_ERROR0; 12816 if (op->ch2 != -1) 12817 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12818 CHECK_ERROR0; 12819 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 12820 ctxt->context->node)); 12821 break; 12822 case XPATH_OP_COLLECT:{ 12823 if (op->ch1 == -1) 12824 break; 12825 12826 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12827 CHECK_ERROR0; 12828 12829 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0); 12830 break; 12831 } 12832 case XPATH_OP_VALUE: 12833 valuePush(ctxt, 12834 xmlXPathCacheObjectCopy(ctxt->context, 12835 (xmlXPathObjectPtr) op->value4)); 12836 break; 12837 case XPATH_OP_SORT: 12838 if (op->ch1 != -1) 12839 total += 12840 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], 12841 last); 12842 CHECK_ERROR0; 12843 if ((ctxt->value != NULL) 12844 && (ctxt->value->type == XPATH_NODESET) 12845 && (ctxt->value->nodesetval != NULL) 12846 && (ctxt->value->nodesetval->nodeNr > 1)) 12847 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12848 break; 12849 default: 12850 total += xmlXPathCompOpEval(ctxt, op); 12851 break; 12852 } 12853 12854 ctxt->context->depth -= 1; 12855 return (total); 12856 } 12857 12858 #ifdef XP_OPTIMIZED_FILTER_FIRST 12859 static int 12860 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt, 12861 xmlXPathStepOpPtr op, xmlNodePtr * first) 12862 { 12863 int total = 0; 12864 xmlXPathCompExprPtr comp; 12865 xmlNodeSetPtr set; 12866 12867 CHECK_ERROR0; 12868 comp = ctxt->comp; 12869 /* 12870 * Optimization for ()[last()] selection i.e. the last elem 12871 */ 12872 if ((op->ch1 != -1) && (op->ch2 != -1) && 12873 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 12874 (comp->steps[op->ch2].op == XPATH_OP_SORT)) { 12875 int f = comp->steps[op->ch2].ch1; 12876 12877 if ((f != -1) && 12878 (comp->steps[f].op == XPATH_OP_FUNCTION) && 12879 (comp->steps[f].value5 == NULL) && 12880 (comp->steps[f].value == 0) && 12881 (comp->steps[f].value4 != NULL) && 12882 (xmlStrEqual 12883 (comp->steps[f].value4, BAD_CAST "last"))) { 12884 xmlNodePtr last = NULL; 12885 12886 total += 12887 xmlXPathCompOpEvalLast(ctxt, 12888 &comp->steps[op->ch1], 12889 &last); 12890 CHECK_ERROR0; 12891 /* 12892 * The nodeset should be in document order, 12893 * Keep only the last value 12894 */ 12895 if ((ctxt->value != NULL) && 12896 (ctxt->value->type == XPATH_NODESET) && 12897 (ctxt->value->nodesetval != NULL) && 12898 (ctxt->value->nodesetval->nodeTab != NULL) && 12899 (ctxt->value->nodesetval->nodeNr > 1)) { 12900 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval); 12901 *first = *(ctxt->value->nodesetval->nodeTab); 12902 } 12903 return (total); 12904 } 12905 } 12906 12907 if (op->ch1 != -1) 12908 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12909 CHECK_ERROR0; 12910 if (op->ch2 == -1) 12911 return (total); 12912 if (ctxt->value == NULL) 12913 return (total); 12914 12915 #ifdef LIBXML_XPTR_LOCS_ENABLED 12916 /* 12917 * Hum are we filtering the result of an XPointer expression 12918 */ 12919 if (ctxt->value->type == XPATH_LOCATIONSET) { 12920 xmlLocationSetPtr locset = ctxt->value->user; 12921 12922 if (locset != NULL) { 12923 xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1); 12924 if (locset->locNr > 0) 12925 *first = (xmlNodePtr) locset->locTab[0]->user; 12926 } 12927 12928 return (total); 12929 } 12930 #endif /* LIBXML_XPTR_LOCS_ENABLED */ 12931 12932 CHECK_TYPE0(XPATH_NODESET); 12933 set = ctxt->value->nodesetval; 12934 if (set != NULL) { 12935 xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1); 12936 if (set->nodeNr > 0) 12937 *first = set->nodeTab[0]; 12938 } 12939 12940 return (total); 12941 } 12942 #endif /* XP_OPTIMIZED_FILTER_FIRST */ 12943 12944 /** 12945 * xmlXPathCompOpEval: 12946 * @ctxt: the XPath parser context with the compiled expression 12947 * @op: an XPath compiled operation 12948 * 12949 * Evaluate the Precompiled XPath operation 12950 * Returns the number of nodes traversed 12951 */ 12952 static int 12953 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) 12954 { 12955 int total = 0; 12956 int equal, ret; 12957 xmlXPathCompExprPtr comp; 12958 xmlXPathObjectPtr arg1, arg2; 12959 12960 CHECK_ERROR0; 12961 if (OP_LIMIT_EXCEEDED(ctxt, 1)) 12962 return(0); 12963 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH) 12964 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED); 12965 ctxt->context->depth += 1; 12966 comp = ctxt->comp; 12967 switch (op->op) { 12968 case XPATH_OP_END: 12969 break; 12970 case XPATH_OP_AND: 12971 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12972 CHECK_ERROR0; 12973 xmlXPathBooleanFunction(ctxt, 1); 12974 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0)) 12975 break; 12976 arg2 = valuePop(ctxt); 12977 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12978 if (ctxt->error) { 12979 xmlXPathFreeObject(arg2); 12980 break; 12981 } 12982 xmlXPathBooleanFunction(ctxt, 1); 12983 if (ctxt->value != NULL) 12984 ctxt->value->boolval &= arg2->boolval; 12985 xmlXPathReleaseObject(ctxt->context, arg2); 12986 break; 12987 case XPATH_OP_OR: 12988 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12989 CHECK_ERROR0; 12990 xmlXPathBooleanFunction(ctxt, 1); 12991 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1)) 12992 break; 12993 arg2 = valuePop(ctxt); 12994 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12995 if (ctxt->error) { 12996 xmlXPathFreeObject(arg2); 12997 break; 12998 } 12999 xmlXPathBooleanFunction(ctxt, 1); 13000 if (ctxt->value != NULL) 13001 ctxt->value->boolval |= arg2->boolval; 13002 xmlXPathReleaseObject(ctxt->context, arg2); 13003 break; 13004 case XPATH_OP_EQUAL: 13005 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13006 CHECK_ERROR0; 13007 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13008 CHECK_ERROR0; 13009 if (op->value) 13010 equal = xmlXPathEqualValues(ctxt); 13011 else 13012 equal = xmlXPathNotEqualValues(ctxt); 13013 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal)); 13014 break; 13015 case XPATH_OP_CMP: 13016 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13017 CHECK_ERROR0; 13018 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13019 CHECK_ERROR0; 13020 ret = xmlXPathCompareValues(ctxt, op->value, op->value2); 13021 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret)); 13022 break; 13023 case XPATH_OP_PLUS: 13024 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13025 CHECK_ERROR0; 13026 if (op->ch2 != -1) { 13027 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13028 } 13029 CHECK_ERROR0; 13030 if (op->value == 0) 13031 xmlXPathSubValues(ctxt); 13032 else if (op->value == 1) 13033 xmlXPathAddValues(ctxt); 13034 else if (op->value == 2) 13035 xmlXPathValueFlipSign(ctxt); 13036 else if (op->value == 3) { 13037 CAST_TO_NUMBER; 13038 CHECK_TYPE0(XPATH_NUMBER); 13039 } 13040 break; 13041 case XPATH_OP_MULT: 13042 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13043 CHECK_ERROR0; 13044 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13045 CHECK_ERROR0; 13046 if (op->value == 0) 13047 xmlXPathMultValues(ctxt); 13048 else if (op->value == 1) 13049 xmlXPathDivValues(ctxt); 13050 else if (op->value == 2) 13051 xmlXPathModValues(ctxt); 13052 break; 13053 case XPATH_OP_UNION: 13054 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13055 CHECK_ERROR0; 13056 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13057 CHECK_ERROR0; 13058 13059 arg2 = valuePop(ctxt); 13060 arg1 = valuePop(ctxt); 13061 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) || 13062 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) { 13063 xmlXPathReleaseObject(ctxt->context, arg1); 13064 xmlXPathReleaseObject(ctxt->context, arg2); 13065 XP_ERROR0(XPATH_INVALID_TYPE); 13066 } 13067 if ((ctxt->context->opLimit != 0) && 13068 (((arg1->nodesetval != NULL) && 13069 (xmlXPathCheckOpLimit(ctxt, 13070 arg1->nodesetval->nodeNr) < 0)) || 13071 ((arg2->nodesetval != NULL) && 13072 (xmlXPathCheckOpLimit(ctxt, 13073 arg2->nodesetval->nodeNr) < 0)))) { 13074 xmlXPathReleaseObject(ctxt->context, arg1); 13075 xmlXPathReleaseObject(ctxt->context, arg2); 13076 break; 13077 } 13078 13079 if ((arg1->nodesetval == NULL) || 13080 ((arg2->nodesetval != NULL) && 13081 (arg2->nodesetval->nodeNr != 0))) 13082 { 13083 /* TODO: Check memory error. */ 13084 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 13085 arg2->nodesetval); 13086 } 13087 13088 valuePush(ctxt, arg1); 13089 xmlXPathReleaseObject(ctxt->context, arg2); 13090 break; 13091 case XPATH_OP_ROOT: 13092 xmlXPathRoot(ctxt); 13093 break; 13094 case XPATH_OP_NODE: 13095 if (op->ch1 != -1) 13096 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13097 CHECK_ERROR0; 13098 if (op->ch2 != -1) 13099 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13100 CHECK_ERROR0; 13101 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 13102 ctxt->context->node)); 13103 break; 13104 case XPATH_OP_COLLECT:{ 13105 if (op->ch1 == -1) 13106 break; 13107 13108 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13109 CHECK_ERROR0; 13110 13111 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0); 13112 break; 13113 } 13114 case XPATH_OP_VALUE: 13115 valuePush(ctxt, 13116 xmlXPathCacheObjectCopy(ctxt->context, 13117 (xmlXPathObjectPtr) op->value4)); 13118 break; 13119 case XPATH_OP_VARIABLE:{ 13120 xmlXPathObjectPtr val; 13121 13122 if (op->ch1 != -1) 13123 total += 13124 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13125 if (op->value5 == NULL) { 13126 val = xmlXPathVariableLookup(ctxt->context, op->value4); 13127 if (val == NULL) 13128 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR); 13129 valuePush(ctxt, val); 13130 } else { 13131 const xmlChar *URI; 13132 13133 URI = xmlXPathNsLookup(ctxt->context, op->value5); 13134 if (URI == NULL) { 13135 xmlGenericError(xmlGenericErrorContext, 13136 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n", 13137 (char *) op->value4, (char *)op->value5); 13138 ctxt->error = XPATH_UNDEF_PREFIX_ERROR; 13139 break; 13140 } 13141 val = xmlXPathVariableLookupNS(ctxt->context, 13142 op->value4, URI); 13143 if (val == NULL) 13144 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR); 13145 valuePush(ctxt, val); 13146 } 13147 break; 13148 } 13149 case XPATH_OP_FUNCTION:{ 13150 xmlXPathFunction func; 13151 const xmlChar *oldFunc, *oldFuncURI; 13152 int i; 13153 int frame; 13154 13155 frame = xmlXPathSetFrame(ctxt); 13156 if (op->ch1 != -1) { 13157 total += 13158 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13159 if (ctxt->error != XPATH_EXPRESSION_OK) { 13160 xmlXPathPopFrame(ctxt, frame); 13161 break; 13162 } 13163 } 13164 if (ctxt->valueNr < ctxt->valueFrame + op->value) { 13165 xmlGenericError(xmlGenericErrorContext, 13166 "xmlXPathCompOpEval: parameter error\n"); 13167 ctxt->error = XPATH_INVALID_OPERAND; 13168 xmlXPathPopFrame(ctxt, frame); 13169 break; 13170 } 13171 for (i = 0; i < op->value; i++) { 13172 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) { 13173 xmlGenericError(xmlGenericErrorContext, 13174 "xmlXPathCompOpEval: parameter error\n"); 13175 ctxt->error = XPATH_INVALID_OPERAND; 13176 xmlXPathPopFrame(ctxt, frame); 13177 break; 13178 } 13179 } 13180 if (op->cache != NULL) 13181 func = op->cache; 13182 else { 13183 const xmlChar *URI = NULL; 13184 13185 if (op->value5 == NULL) 13186 func = 13187 xmlXPathFunctionLookup(ctxt->context, 13188 op->value4); 13189 else { 13190 URI = xmlXPathNsLookup(ctxt->context, op->value5); 13191 if (URI == NULL) { 13192 xmlGenericError(xmlGenericErrorContext, 13193 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n", 13194 (char *)op->value4, (char *)op->value5); 13195 xmlXPathPopFrame(ctxt, frame); 13196 ctxt->error = XPATH_UNDEF_PREFIX_ERROR; 13197 break; 13198 } 13199 func = xmlXPathFunctionLookupNS(ctxt->context, 13200 op->value4, URI); 13201 } 13202 if (func == NULL) { 13203 xmlGenericError(xmlGenericErrorContext, 13204 "xmlXPathCompOpEval: function %s not found\n", 13205 (char *)op->value4); 13206 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR); 13207 } 13208 op->cache = func; 13209 op->cacheURI = (void *) URI; 13210 } 13211 oldFunc = ctxt->context->function; 13212 oldFuncURI = ctxt->context->functionURI; 13213 ctxt->context->function = op->value4; 13214 ctxt->context->functionURI = op->cacheURI; 13215 func(ctxt, op->value); 13216 ctxt->context->function = oldFunc; 13217 ctxt->context->functionURI = oldFuncURI; 13218 if ((ctxt->error == XPATH_EXPRESSION_OK) && 13219 (ctxt->valueNr != ctxt->valueFrame + 1)) 13220 XP_ERROR0(XPATH_STACK_ERROR); 13221 xmlXPathPopFrame(ctxt, frame); 13222 break; 13223 } 13224 case XPATH_OP_ARG: 13225 if (op->ch1 != -1) { 13226 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13227 CHECK_ERROR0; 13228 } 13229 if (op->ch2 != -1) { 13230 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13231 CHECK_ERROR0; 13232 } 13233 break; 13234 case XPATH_OP_PREDICATE: 13235 case XPATH_OP_FILTER:{ 13236 xmlNodeSetPtr set; 13237 13238 /* 13239 * Optimization for ()[1] selection i.e. the first elem 13240 */ 13241 if ((op->ch1 != -1) && (op->ch2 != -1) && 13242 #ifdef XP_OPTIMIZED_FILTER_FIRST 13243 /* 13244 * FILTER TODO: Can we assume that the inner processing 13245 * will result in an ordered list if we have an 13246 * XPATH_OP_FILTER? 13247 * What about an additional field or flag on 13248 * xmlXPathObject like @sorted ? This way we wouldn't need 13249 * to assume anything, so it would be more robust and 13250 * easier to optimize. 13251 */ 13252 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */ 13253 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */ 13254 #else 13255 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 13256 #endif 13257 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */ 13258 xmlXPathObjectPtr val; 13259 13260 val = comp->steps[op->ch2].value4; 13261 if ((val != NULL) && (val->type == XPATH_NUMBER) && 13262 (val->floatval == 1.0)) { 13263 xmlNodePtr first = NULL; 13264 13265 total += 13266 xmlXPathCompOpEvalFirst(ctxt, 13267 &comp->steps[op->ch1], 13268 &first); 13269 CHECK_ERROR0; 13270 /* 13271 * The nodeset should be in document order, 13272 * Keep only the first value 13273 */ 13274 if ((ctxt->value != NULL) && 13275 (ctxt->value->type == XPATH_NODESET) && 13276 (ctxt->value->nodesetval != NULL) && 13277 (ctxt->value->nodesetval->nodeNr > 1)) 13278 xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval, 13279 1, 1); 13280 break; 13281 } 13282 } 13283 /* 13284 * Optimization for ()[last()] selection i.e. the last elem 13285 */ 13286 if ((op->ch1 != -1) && (op->ch2 != -1) && 13287 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 13288 (comp->steps[op->ch2].op == XPATH_OP_SORT)) { 13289 int f = comp->steps[op->ch2].ch1; 13290 13291 if ((f != -1) && 13292 (comp->steps[f].op == XPATH_OP_FUNCTION) && 13293 (comp->steps[f].value5 == NULL) && 13294 (comp->steps[f].value == 0) && 13295 (comp->steps[f].value4 != NULL) && 13296 (xmlStrEqual 13297 (comp->steps[f].value4, BAD_CAST "last"))) { 13298 xmlNodePtr last = NULL; 13299 13300 total += 13301 xmlXPathCompOpEvalLast(ctxt, 13302 &comp->steps[op->ch1], 13303 &last); 13304 CHECK_ERROR0; 13305 /* 13306 * The nodeset should be in document order, 13307 * Keep only the last value 13308 */ 13309 if ((ctxt->value != NULL) && 13310 (ctxt->value->type == XPATH_NODESET) && 13311 (ctxt->value->nodesetval != NULL) && 13312 (ctxt->value->nodesetval->nodeTab != NULL) && 13313 (ctxt->value->nodesetval->nodeNr > 1)) 13314 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval); 13315 break; 13316 } 13317 } 13318 /* 13319 * Process inner predicates first. 13320 * Example "index[parent::book][1]": 13321 * ... 13322 * PREDICATE <-- we are here "[1]" 13323 * PREDICATE <-- process "[parent::book]" first 13324 * SORT 13325 * COLLECT 'parent' 'name' 'node' book 13326 * NODE 13327 * ELEM Object is a number : 1 13328 */ 13329 if (op->ch1 != -1) 13330 total += 13331 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13332 CHECK_ERROR0; 13333 if (op->ch2 == -1) 13334 break; 13335 if (ctxt->value == NULL) 13336 break; 13337 13338 #ifdef LIBXML_XPTR_LOCS_ENABLED 13339 /* 13340 * Hum are we filtering the result of an XPointer expression 13341 */ 13342 if (ctxt->value->type == XPATH_LOCATIONSET) { 13343 xmlLocationSetPtr locset = ctxt->value->user; 13344 xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 13345 1, locset->locNr); 13346 break; 13347 } 13348 #endif /* LIBXML_XPTR_LOCS_ENABLED */ 13349 13350 CHECK_TYPE0(XPATH_NODESET); 13351 set = ctxt->value->nodesetval; 13352 if (set != NULL) 13353 xmlXPathNodeSetFilter(ctxt, set, op->ch2, 13354 1, set->nodeNr, 1); 13355 break; 13356 } 13357 case XPATH_OP_SORT: 13358 if (op->ch1 != -1) 13359 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13360 CHECK_ERROR0; 13361 if ((ctxt->value != NULL) && 13362 (ctxt->value->type == XPATH_NODESET) && 13363 (ctxt->value->nodesetval != NULL) && 13364 (ctxt->value->nodesetval->nodeNr > 1)) 13365 { 13366 xmlXPathNodeSetSort(ctxt->value->nodesetval); 13367 } 13368 break; 13369 #ifdef LIBXML_XPTR_LOCS_ENABLED 13370 case XPATH_OP_RANGETO:{ 13371 xmlXPathObjectPtr range; 13372 xmlXPathObjectPtr res, obj; 13373 xmlXPathObjectPtr tmp; 13374 xmlLocationSetPtr newlocset = NULL; 13375 xmlLocationSetPtr oldlocset; 13376 xmlNodeSetPtr oldset; 13377 xmlNodePtr oldnode = ctxt->context->node; 13378 int oldcs = ctxt->context->contextSize; 13379 int oldpp = ctxt->context->proximityPosition; 13380 int i, j; 13381 13382 if (op->ch1 != -1) { 13383 total += 13384 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13385 CHECK_ERROR0; 13386 } 13387 if (ctxt->value == NULL) { 13388 XP_ERROR0(XPATH_INVALID_OPERAND); 13389 } 13390 if (op->ch2 == -1) 13391 break; 13392 13393 if (ctxt->value->type == XPATH_LOCATIONSET) { 13394 /* 13395 * Extract the old locset, and then evaluate the result of the 13396 * expression for all the element in the locset. use it to grow 13397 * up a new locset. 13398 */ 13399 CHECK_TYPE0(XPATH_LOCATIONSET); 13400 13401 if ((ctxt->value->user == NULL) || 13402 (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0)) 13403 break; 13404 13405 obj = valuePop(ctxt); 13406 oldlocset = obj->user; 13407 13408 newlocset = xmlXPtrLocationSetCreate(NULL); 13409 13410 for (i = 0; i < oldlocset->locNr; i++) { 13411 /* 13412 * Run the evaluation with a node list made of a 13413 * single item in the nodelocset. 13414 */ 13415 ctxt->context->node = oldlocset->locTab[i]->user; 13416 ctxt->context->contextSize = oldlocset->locNr; 13417 ctxt->context->proximityPosition = i + 1; 13418 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13419 ctxt->context->node); 13420 valuePush(ctxt, tmp); 13421 13422 if (op->ch2 != -1) 13423 total += 13424 xmlXPathCompOpEval(ctxt, 13425 &comp->steps[op->ch2]); 13426 if (ctxt->error != XPATH_EXPRESSION_OK) { 13427 xmlXPtrFreeLocationSet(newlocset); 13428 goto rangeto_error; 13429 } 13430 13431 res = valuePop(ctxt); 13432 if (res->type == XPATH_LOCATIONSET) { 13433 xmlLocationSetPtr rloc = 13434 (xmlLocationSetPtr)res->user; 13435 for (j=0; j<rloc->locNr; j++) { 13436 range = xmlXPtrNewRange( 13437 oldlocset->locTab[i]->user, 13438 oldlocset->locTab[i]->index, 13439 rloc->locTab[j]->user2, 13440 rloc->locTab[j]->index2); 13441 if (range != NULL) { 13442 xmlXPtrLocationSetAdd(newlocset, range); 13443 } 13444 } 13445 } else { 13446 range = xmlXPtrNewRangeNodeObject( 13447 (xmlNodePtr)oldlocset->locTab[i]->user, res); 13448 if (range != NULL) { 13449 xmlXPtrLocationSetAdd(newlocset,range); 13450 } 13451 } 13452 13453 /* 13454 * Cleanup 13455 */ 13456 if (res != NULL) { 13457 xmlXPathReleaseObject(ctxt->context, res); 13458 } 13459 if (ctxt->value == tmp) { 13460 res = valuePop(ctxt); 13461 xmlXPathReleaseObject(ctxt->context, res); 13462 } 13463 } 13464 } else { /* Not a location set */ 13465 CHECK_TYPE0(XPATH_NODESET); 13466 obj = valuePop(ctxt); 13467 oldset = obj->nodesetval; 13468 13469 newlocset = xmlXPtrLocationSetCreate(NULL); 13470 13471 if (oldset != NULL) { 13472 for (i = 0; i < oldset->nodeNr; i++) { 13473 /* 13474 * Run the evaluation with a node list made of a single item 13475 * in the nodeset. 13476 */ 13477 ctxt->context->node = oldset->nodeTab[i]; 13478 /* 13479 * OPTIMIZE TODO: Avoid recreation for every iteration. 13480 */ 13481 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13482 ctxt->context->node); 13483 valuePush(ctxt, tmp); 13484 13485 if (op->ch2 != -1) 13486 total += 13487 xmlXPathCompOpEval(ctxt, 13488 &comp->steps[op->ch2]); 13489 if (ctxt->error != XPATH_EXPRESSION_OK) { 13490 xmlXPtrFreeLocationSet(newlocset); 13491 goto rangeto_error; 13492 } 13493 13494 res = valuePop(ctxt); 13495 range = 13496 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i], 13497 res); 13498 if (range != NULL) { 13499 xmlXPtrLocationSetAdd(newlocset, range); 13500 } 13501 13502 /* 13503 * Cleanup 13504 */ 13505 if (res != NULL) { 13506 xmlXPathReleaseObject(ctxt->context, res); 13507 } 13508 if (ctxt->value == tmp) { 13509 res = valuePop(ctxt); 13510 xmlXPathReleaseObject(ctxt->context, res); 13511 } 13512 } 13513 } 13514 } 13515 13516 /* 13517 * The result is used as the new evaluation set. 13518 */ 13519 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset)); 13520 rangeto_error: 13521 xmlXPathReleaseObject(ctxt->context, obj); 13522 ctxt->context->node = oldnode; 13523 ctxt->context->contextSize = oldcs; 13524 ctxt->context->proximityPosition = oldpp; 13525 break; 13526 } 13527 #endif /* LIBXML_XPTR_LOCS_ENABLED */ 13528 default: 13529 xmlGenericError(xmlGenericErrorContext, 13530 "XPath: unknown precompiled operation %d\n", op->op); 13531 ctxt->error = XPATH_INVALID_OPERAND; 13532 break; 13533 } 13534 13535 ctxt->context->depth -= 1; 13536 return (total); 13537 } 13538 13539 /** 13540 * xmlXPathCompOpEvalToBoolean: 13541 * @ctxt: the XPath parser context 13542 * 13543 * Evaluates if the expression evaluates to true. 13544 * 13545 * Returns 1 if true, 0 if false and -1 on API or internal errors. 13546 */ 13547 static int 13548 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt, 13549 xmlXPathStepOpPtr op, 13550 int isPredicate) 13551 { 13552 xmlXPathObjectPtr resObj = NULL; 13553 13554 start: 13555 if (OP_LIMIT_EXCEEDED(ctxt, 1)) 13556 return(0); 13557 /* comp = ctxt->comp; */ 13558 switch (op->op) { 13559 case XPATH_OP_END: 13560 return (0); 13561 case XPATH_OP_VALUE: 13562 resObj = (xmlXPathObjectPtr) op->value4; 13563 if (isPredicate) 13564 return(xmlXPathEvaluatePredicateResult(ctxt, resObj)); 13565 return(xmlXPathCastToBoolean(resObj)); 13566 case XPATH_OP_SORT: 13567 /* 13568 * We don't need sorting for boolean results. Skip this one. 13569 */ 13570 if (op->ch1 != -1) { 13571 op = &ctxt->comp->steps[op->ch1]; 13572 goto start; 13573 } 13574 return(0); 13575 case XPATH_OP_COLLECT: 13576 if (op->ch1 == -1) 13577 return(0); 13578 13579 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]); 13580 if (ctxt->error != XPATH_EXPRESSION_OK) 13581 return(-1); 13582 13583 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1); 13584 if (ctxt->error != XPATH_EXPRESSION_OK) 13585 return(-1); 13586 13587 resObj = valuePop(ctxt); 13588 if (resObj == NULL) 13589 return(-1); 13590 break; 13591 default: 13592 /* 13593 * Fallback to call xmlXPathCompOpEval(). 13594 */ 13595 xmlXPathCompOpEval(ctxt, op); 13596 if (ctxt->error != XPATH_EXPRESSION_OK) 13597 return(-1); 13598 13599 resObj = valuePop(ctxt); 13600 if (resObj == NULL) 13601 return(-1); 13602 break; 13603 } 13604 13605 if (resObj) { 13606 int res; 13607 13608 if (resObj->type == XPATH_BOOLEAN) { 13609 res = resObj->boolval; 13610 } else if (isPredicate) { 13611 /* 13612 * For predicates a result of type "number" is handled 13613 * differently: 13614 * SPEC XPath 1.0: 13615 * "If the result is a number, the result will be converted 13616 * to true if the number is equal to the context position 13617 * and will be converted to false otherwise;" 13618 */ 13619 res = xmlXPathEvaluatePredicateResult(ctxt, resObj); 13620 } else { 13621 res = xmlXPathCastToBoolean(resObj); 13622 } 13623 xmlXPathReleaseObject(ctxt->context, resObj); 13624 return(res); 13625 } 13626 13627 return(0); 13628 } 13629 13630 #ifdef XPATH_STREAMING 13631 /** 13632 * xmlXPathRunStreamEval: 13633 * @ctxt: the XPath parser context with the compiled expression 13634 * 13635 * Evaluate the Precompiled Streamable XPath expression in the given context. 13636 */ 13637 static int 13638 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp, 13639 xmlXPathObjectPtr *resultSeq, int toBool) 13640 { 13641 int max_depth, min_depth; 13642 int from_root; 13643 int ret, depth; 13644 int eval_all_nodes; 13645 xmlNodePtr cur = NULL, limit = NULL; 13646 xmlStreamCtxtPtr patstream = NULL; 13647 13648 int nb_nodes = 0; 13649 13650 if ((ctxt == NULL) || (comp == NULL)) 13651 return(-1); 13652 max_depth = xmlPatternMaxDepth(comp); 13653 if (max_depth == -1) 13654 return(-1); 13655 if (max_depth == -2) 13656 max_depth = 10000; 13657 min_depth = xmlPatternMinDepth(comp); 13658 if (min_depth == -1) 13659 return(-1); 13660 from_root = xmlPatternFromRoot(comp); 13661 if (from_root < 0) 13662 return(-1); 13663 #if 0 13664 printf("stream eval: depth %d from root %d\n", max_depth, from_root); 13665 #endif 13666 13667 if (! toBool) { 13668 if (resultSeq == NULL) 13669 return(-1); 13670 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL); 13671 if (*resultSeq == NULL) 13672 return(-1); 13673 } 13674 13675 /* 13676 * handle the special cases of "/" amd "." being matched 13677 */ 13678 if (min_depth == 0) { 13679 if (from_root) { 13680 /* Select "/" */ 13681 if (toBool) 13682 return(1); 13683 /* TODO: Check memory error. */ 13684 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, 13685 (xmlNodePtr) ctxt->doc); 13686 } else { 13687 /* Select "self::node()" */ 13688 if (toBool) 13689 return(1); 13690 /* TODO: Check memory error. */ 13691 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node); 13692 } 13693 } 13694 if (max_depth == 0) { 13695 return(0); 13696 } 13697 13698 if (from_root) { 13699 cur = (xmlNodePtr)ctxt->doc; 13700 } else if (ctxt->node != NULL) { 13701 switch (ctxt->node->type) { 13702 case XML_ELEMENT_NODE: 13703 case XML_DOCUMENT_NODE: 13704 case XML_DOCUMENT_FRAG_NODE: 13705 case XML_HTML_DOCUMENT_NODE: 13706 cur = ctxt->node; 13707 break; 13708 case XML_ATTRIBUTE_NODE: 13709 case XML_TEXT_NODE: 13710 case XML_CDATA_SECTION_NODE: 13711 case XML_ENTITY_REF_NODE: 13712 case XML_ENTITY_NODE: 13713 case XML_PI_NODE: 13714 case XML_COMMENT_NODE: 13715 case XML_NOTATION_NODE: 13716 case XML_DTD_NODE: 13717 case XML_DOCUMENT_TYPE_NODE: 13718 case XML_ELEMENT_DECL: 13719 case XML_ATTRIBUTE_DECL: 13720 case XML_ENTITY_DECL: 13721 case XML_NAMESPACE_DECL: 13722 case XML_XINCLUDE_START: 13723 case XML_XINCLUDE_END: 13724 break; 13725 } 13726 limit = cur; 13727 } 13728 if (cur == NULL) { 13729 return(0); 13730 } 13731 13732 patstream = xmlPatternGetStreamCtxt(comp); 13733 if (patstream == NULL) { 13734 /* 13735 * QUESTION TODO: Is this an error? 13736 */ 13737 return(0); 13738 } 13739 13740 eval_all_nodes = xmlStreamWantsAnyNode(patstream); 13741 13742 if (from_root) { 13743 ret = xmlStreamPush(patstream, NULL, NULL); 13744 if (ret < 0) { 13745 } else if (ret == 1) { 13746 if (toBool) 13747 goto return_1; 13748 /* TODO: Check memory error. */ 13749 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur); 13750 } 13751 } 13752 depth = 0; 13753 goto scan_children; 13754 next_node: 13755 do { 13756 if (ctxt->opLimit != 0) { 13757 if (ctxt->opCount >= ctxt->opLimit) { 13758 xmlGenericError(xmlGenericErrorContext, 13759 "XPath operation limit exceeded\n"); 13760 xmlFreeStreamCtxt(patstream); 13761 return(-1); 13762 } 13763 ctxt->opCount++; 13764 } 13765 13766 nb_nodes++; 13767 13768 switch (cur->type) { 13769 case XML_ELEMENT_NODE: 13770 case XML_TEXT_NODE: 13771 case XML_CDATA_SECTION_NODE: 13772 case XML_COMMENT_NODE: 13773 case XML_PI_NODE: 13774 if (cur->type == XML_ELEMENT_NODE) { 13775 ret = xmlStreamPush(patstream, cur->name, 13776 (cur->ns ? cur->ns->href : NULL)); 13777 } else if (eval_all_nodes) 13778 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type); 13779 else 13780 break; 13781 13782 if (ret < 0) { 13783 /* NOP. */ 13784 } else if (ret == 1) { 13785 if (toBool) 13786 goto return_1; 13787 if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur) 13788 < 0) { 13789 ctxt->lastError.domain = XML_FROM_XPATH; 13790 ctxt->lastError.code = XML_ERR_NO_MEMORY; 13791 } 13792 } 13793 if ((cur->children == NULL) || (depth >= max_depth)) { 13794 ret = xmlStreamPop(patstream); 13795 while (cur->next != NULL) { 13796 cur = cur->next; 13797 if ((cur->type != XML_ENTITY_DECL) && 13798 (cur->type != XML_DTD_NODE)) 13799 goto next_node; 13800 } 13801 } 13802 default: 13803 break; 13804 } 13805 13806 scan_children: 13807 if (cur->type == XML_NAMESPACE_DECL) break; 13808 if ((cur->children != NULL) && (depth < max_depth)) { 13809 /* 13810 * Do not descend on entities declarations 13811 */ 13812 if (cur->children->type != XML_ENTITY_DECL) { 13813 cur = cur->children; 13814 depth++; 13815 /* 13816 * Skip DTDs 13817 */ 13818 if (cur->type != XML_DTD_NODE) 13819 continue; 13820 } 13821 } 13822 13823 if (cur == limit) 13824 break; 13825 13826 while (cur->next != NULL) { 13827 cur = cur->next; 13828 if ((cur->type != XML_ENTITY_DECL) && 13829 (cur->type != XML_DTD_NODE)) 13830 goto next_node; 13831 } 13832 13833 do { 13834 cur = cur->parent; 13835 depth--; 13836 if ((cur == NULL) || (cur == limit) || 13837 (cur->type == XML_DOCUMENT_NODE)) 13838 goto done; 13839 if (cur->type == XML_ELEMENT_NODE) { 13840 ret = xmlStreamPop(patstream); 13841 } else if ((eval_all_nodes) && 13842 ((cur->type == XML_TEXT_NODE) || 13843 (cur->type == XML_CDATA_SECTION_NODE) || 13844 (cur->type == XML_COMMENT_NODE) || 13845 (cur->type == XML_PI_NODE))) 13846 { 13847 ret = xmlStreamPop(patstream); 13848 } 13849 if (cur->next != NULL) { 13850 cur = cur->next; 13851 break; 13852 } 13853 } while (cur != NULL); 13854 13855 } while ((cur != NULL) && (depth >= 0)); 13856 13857 done: 13858 13859 #if 0 13860 printf("stream eval: checked %d nodes selected %d\n", 13861 nb_nodes, retObj->nodesetval->nodeNr); 13862 #endif 13863 13864 if (patstream) 13865 xmlFreeStreamCtxt(patstream); 13866 return(0); 13867 13868 return_1: 13869 if (patstream) 13870 xmlFreeStreamCtxt(patstream); 13871 return(1); 13872 } 13873 #endif /* XPATH_STREAMING */ 13874 13875 /** 13876 * xmlXPathRunEval: 13877 * @ctxt: the XPath parser context with the compiled expression 13878 * @toBool: evaluate to a boolean result 13879 * 13880 * Evaluate the Precompiled XPath expression in the given context. 13881 */ 13882 static int 13883 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool) 13884 { 13885 xmlXPathCompExprPtr comp; 13886 int oldDepth; 13887 13888 if ((ctxt == NULL) || (ctxt->comp == NULL)) 13889 return(-1); 13890 13891 if (ctxt->valueTab == NULL) { 13892 /* Allocate the value stack */ 13893 ctxt->valueTab = (xmlXPathObjectPtr *) 13894 xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); 13895 if (ctxt->valueTab == NULL) { 13896 xmlXPathPErrMemory(ctxt, "creating evaluation context\n"); 13897 return(-1); 13898 } 13899 ctxt->valueNr = 0; 13900 ctxt->valueMax = 10; 13901 ctxt->value = NULL; 13902 ctxt->valueFrame = 0; 13903 } 13904 #ifdef XPATH_STREAMING 13905 if (ctxt->comp->stream) { 13906 int res; 13907 13908 if (toBool) { 13909 /* 13910 * Evaluation to boolean result. 13911 */ 13912 res = xmlXPathRunStreamEval(ctxt->context, 13913 ctxt->comp->stream, NULL, 1); 13914 if (res != -1) 13915 return(res); 13916 } else { 13917 xmlXPathObjectPtr resObj = NULL; 13918 13919 /* 13920 * Evaluation to a sequence. 13921 */ 13922 res = xmlXPathRunStreamEval(ctxt->context, 13923 ctxt->comp->stream, &resObj, 0); 13924 13925 if ((res != -1) && (resObj != NULL)) { 13926 valuePush(ctxt, resObj); 13927 return(0); 13928 } 13929 if (resObj != NULL) 13930 xmlXPathReleaseObject(ctxt->context, resObj); 13931 } 13932 /* 13933 * QUESTION TODO: This falls back to normal XPath evaluation 13934 * if res == -1. Is this intended? 13935 */ 13936 } 13937 #endif 13938 comp = ctxt->comp; 13939 if (comp->last < 0) { 13940 xmlGenericError(xmlGenericErrorContext, 13941 "xmlXPathRunEval: last is less than zero\n"); 13942 return(-1); 13943 } 13944 oldDepth = ctxt->context->depth; 13945 if (toBool) 13946 return(xmlXPathCompOpEvalToBoolean(ctxt, 13947 &comp->steps[comp->last], 0)); 13948 else 13949 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]); 13950 ctxt->context->depth = oldDepth; 13951 13952 return(0); 13953 } 13954 13955 /************************************************************************ 13956 * * 13957 * Public interfaces * 13958 * * 13959 ************************************************************************/ 13960 13961 /** 13962 * xmlXPathEvalPredicate: 13963 * @ctxt: the XPath context 13964 * @res: the Predicate Expression evaluation result 13965 * 13966 * Evaluate a predicate result for the current node. 13967 * A PredicateExpr is evaluated by evaluating the Expr and converting 13968 * the result to a boolean. If the result is a number, the result will 13969 * be converted to true if the number is equal to the position of the 13970 * context node in the context node list (as returned by the position 13971 * function) and will be converted to false otherwise; if the result 13972 * is not a number, then the result will be converted as if by a call 13973 * to the boolean function. 13974 * 13975 * Returns 1 if predicate is true, 0 otherwise 13976 */ 13977 int 13978 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) { 13979 if ((ctxt == NULL) || (res == NULL)) return(0); 13980 switch (res->type) { 13981 case XPATH_BOOLEAN: 13982 return(res->boolval); 13983 case XPATH_NUMBER: 13984 return(res->floatval == ctxt->proximityPosition); 13985 case XPATH_NODESET: 13986 case XPATH_XSLT_TREE: 13987 if (res->nodesetval == NULL) 13988 return(0); 13989 return(res->nodesetval->nodeNr != 0); 13990 case XPATH_STRING: 13991 return((res->stringval != NULL) && 13992 (xmlStrlen(res->stringval) != 0)); 13993 default: 13994 STRANGE 13995 } 13996 return(0); 13997 } 13998 13999 /** 14000 * xmlXPathEvaluatePredicateResult: 14001 * @ctxt: the XPath Parser context 14002 * @res: the Predicate Expression evaluation result 14003 * 14004 * Evaluate a predicate result for the current node. 14005 * A PredicateExpr is evaluated by evaluating the Expr and converting 14006 * the result to a boolean. If the result is a number, the result will 14007 * be converted to true if the number is equal to the position of the 14008 * context node in the context node list (as returned by the position 14009 * function) and will be converted to false otherwise; if the result 14010 * is not a number, then the result will be converted as if by a call 14011 * to the boolean function. 14012 * 14013 * Returns 1 if predicate is true, 0 otherwise 14014 */ 14015 int 14016 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt, 14017 xmlXPathObjectPtr res) { 14018 if ((ctxt == NULL) || (res == NULL)) return(0); 14019 switch (res->type) { 14020 case XPATH_BOOLEAN: 14021 return(res->boolval); 14022 case XPATH_NUMBER: 14023 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200)) 14024 return((res->floatval == ctxt->context->proximityPosition) && 14025 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/ 14026 #else 14027 return(res->floatval == ctxt->context->proximityPosition); 14028 #endif 14029 case XPATH_NODESET: 14030 case XPATH_XSLT_TREE: 14031 if (res->nodesetval == NULL) 14032 return(0); 14033 return(res->nodesetval->nodeNr != 0); 14034 case XPATH_STRING: 14035 return((res->stringval != NULL) && (res->stringval[0] != 0)); 14036 #ifdef LIBXML_XPTR_LOCS_ENABLED 14037 case XPATH_LOCATIONSET:{ 14038 xmlLocationSetPtr ptr = res->user; 14039 if (ptr == NULL) 14040 return(0); 14041 return (ptr->locNr != 0); 14042 } 14043 #endif 14044 default: 14045 STRANGE 14046 } 14047 return(0); 14048 } 14049 14050 #ifdef XPATH_STREAMING 14051 /** 14052 * xmlXPathTryStreamCompile: 14053 * @ctxt: an XPath context 14054 * @str: the XPath expression 14055 * 14056 * Try to compile the XPath expression as a streamable subset. 14057 * 14058 * Returns the compiled expression or NULL if failed to compile. 14059 */ 14060 static xmlXPathCompExprPtr 14061 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { 14062 /* 14063 * Optimization: use streaming patterns when the XPath expression can 14064 * be compiled to a stream lookup 14065 */ 14066 xmlPatternPtr stream; 14067 xmlXPathCompExprPtr comp; 14068 xmlDictPtr dict = NULL; 14069 const xmlChar **namespaces = NULL; 14070 xmlNsPtr ns; 14071 int i, j; 14072 14073 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) && 14074 (!xmlStrchr(str, '@'))) { 14075 const xmlChar *tmp; 14076 14077 /* 14078 * We don't try to handle expressions using the verbose axis 14079 * specifiers ("::"), just the simplified form at this point. 14080 * Additionally, if there is no list of namespaces available and 14081 * there's a ":" in the expression, indicating a prefixed QName, 14082 * then we won't try to compile either. xmlPatterncompile() needs 14083 * to have a list of namespaces at compilation time in order to 14084 * compile prefixed name tests. 14085 */ 14086 tmp = xmlStrchr(str, ':'); 14087 if ((tmp != NULL) && 14088 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':'))) 14089 return(NULL); 14090 14091 if (ctxt != NULL) { 14092 dict = ctxt->dict; 14093 if (ctxt->nsNr > 0) { 14094 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*)); 14095 if (namespaces == NULL) { 14096 xmlXPathErrMemory(ctxt, "allocating namespaces array\n"); 14097 return(NULL); 14098 } 14099 for (i = 0, j = 0; (j < ctxt->nsNr); j++) { 14100 ns = ctxt->namespaces[j]; 14101 namespaces[i++] = ns->href; 14102 namespaces[i++] = ns->prefix; 14103 } 14104 namespaces[i++] = NULL; 14105 namespaces[i] = NULL; 14106 } 14107 } 14108 14109 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces); 14110 if (namespaces != NULL) { 14111 xmlFree((xmlChar **)namespaces); 14112 } 14113 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) { 14114 comp = xmlXPathNewCompExpr(); 14115 if (comp == NULL) { 14116 xmlXPathErrMemory(ctxt, "allocating streamable expression\n"); 14117 return(NULL); 14118 } 14119 comp->stream = stream; 14120 comp->dict = dict; 14121 if (comp->dict) 14122 xmlDictReference(comp->dict); 14123 return(comp); 14124 } 14125 xmlFreePattern(stream); 14126 } 14127 return(NULL); 14128 } 14129 #endif /* XPATH_STREAMING */ 14130 14131 static void 14132 xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt, 14133 xmlXPathStepOpPtr op) 14134 { 14135 xmlXPathCompExprPtr comp = pctxt->comp; 14136 xmlXPathContextPtr ctxt; 14137 14138 /* 14139 * Try to rewrite "descendant-or-self::node()/foo" to an optimized 14140 * internal representation. 14141 */ 14142 14143 if ((op->op == XPATH_OP_COLLECT /* 11 */) && 14144 (op->ch1 != -1) && 14145 (op->ch2 == -1 /* no predicate */)) 14146 { 14147 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1]; 14148 14149 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) && 14150 ((xmlXPathAxisVal) prevop->value == 14151 AXIS_DESCENDANT_OR_SELF) && 14152 (prevop->ch2 == -1) && 14153 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) && 14154 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE)) 14155 { 14156 /* 14157 * This is a "descendant-or-self::node()" without predicates. 14158 * Try to eliminate it. 14159 */ 14160 14161 switch ((xmlXPathAxisVal) op->value) { 14162 case AXIS_CHILD: 14163 case AXIS_DESCENDANT: 14164 /* 14165 * Convert "descendant-or-self::node()/child::" or 14166 * "descendant-or-self::node()/descendant::" to 14167 * "descendant::" 14168 */ 14169 op->ch1 = prevop->ch1; 14170 op->value = AXIS_DESCENDANT; 14171 break; 14172 case AXIS_SELF: 14173 case AXIS_DESCENDANT_OR_SELF: 14174 /* 14175 * Convert "descendant-or-self::node()/self::" or 14176 * "descendant-or-self::node()/descendant-or-self::" to 14177 * to "descendant-or-self::" 14178 */ 14179 op->ch1 = prevop->ch1; 14180 op->value = AXIS_DESCENDANT_OR_SELF; 14181 break; 14182 default: 14183 break; 14184 } 14185 } 14186 } 14187 14188 /* OP_VALUE has invalid ch1. */ 14189 if (op->op == XPATH_OP_VALUE) 14190 return; 14191 14192 /* Recurse */ 14193 ctxt = pctxt->context; 14194 if (ctxt != NULL) { 14195 if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH) 14196 return; 14197 ctxt->depth += 1; 14198 } 14199 if (op->ch1 != -1) 14200 xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]); 14201 if (op->ch2 != -1) 14202 xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]); 14203 if (ctxt != NULL) 14204 ctxt->depth -= 1; 14205 } 14206 14207 /** 14208 * xmlXPathCtxtCompile: 14209 * @ctxt: an XPath context 14210 * @str: the XPath expression 14211 * 14212 * Compile an XPath expression 14213 * 14214 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL. 14215 * the caller has to free the object. 14216 */ 14217 xmlXPathCompExprPtr 14218 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { 14219 xmlXPathParserContextPtr pctxt; 14220 xmlXPathCompExprPtr comp; 14221 int oldDepth = 0; 14222 14223 #ifdef XPATH_STREAMING 14224 comp = xmlXPathTryStreamCompile(ctxt, str); 14225 if (comp != NULL) 14226 return(comp); 14227 #endif 14228 14229 xmlInitParser(); 14230 14231 pctxt = xmlXPathNewParserContext(str, ctxt); 14232 if (pctxt == NULL) 14233 return NULL; 14234 if (ctxt != NULL) 14235 oldDepth = ctxt->depth; 14236 xmlXPathCompileExpr(pctxt, 1); 14237 if (ctxt != NULL) 14238 ctxt->depth = oldDepth; 14239 14240 if( pctxt->error != XPATH_EXPRESSION_OK ) 14241 { 14242 xmlXPathFreeParserContext(pctxt); 14243 return(NULL); 14244 } 14245 14246 if (*pctxt->cur != 0) { 14247 /* 14248 * aleksey: in some cases this line prints *second* error message 14249 * (see bug #78858) and probably this should be fixed. 14250 * However, we are not sure that all error messages are printed 14251 * out in other places. It's not critical so we leave it as-is for now 14252 */ 14253 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR); 14254 comp = NULL; 14255 } else { 14256 comp = pctxt->comp; 14257 if ((comp->nbStep > 1) && (comp->last >= 0)) { 14258 if (ctxt != NULL) 14259 oldDepth = ctxt->depth; 14260 xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]); 14261 if (ctxt != NULL) 14262 ctxt->depth = oldDepth; 14263 } 14264 pctxt->comp = NULL; 14265 } 14266 xmlXPathFreeParserContext(pctxt); 14267 14268 if (comp != NULL) { 14269 comp->expr = xmlStrdup(str); 14270 #ifdef DEBUG_EVAL_COUNTS 14271 comp->string = xmlStrdup(str); 14272 comp->nb = 0; 14273 #endif 14274 } 14275 return(comp); 14276 } 14277 14278 /** 14279 * xmlXPathCompile: 14280 * @str: the XPath expression 14281 * 14282 * Compile an XPath expression 14283 * 14284 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL. 14285 * the caller has to free the object. 14286 */ 14287 xmlXPathCompExprPtr 14288 xmlXPathCompile(const xmlChar *str) { 14289 return(xmlXPathCtxtCompile(NULL, str)); 14290 } 14291 14292 /** 14293 * xmlXPathCompiledEvalInternal: 14294 * @comp: the compiled XPath expression 14295 * @ctxt: the XPath context 14296 * @resObj: the resulting XPath object or NULL 14297 * @toBool: 1 if only a boolean result is requested 14298 * 14299 * Evaluate the Precompiled XPath expression in the given context. 14300 * The caller has to free @resObj. 14301 * 14302 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14303 * the caller has to free the object. 14304 */ 14305 static int 14306 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp, 14307 xmlXPathContextPtr ctxt, 14308 xmlXPathObjectPtr *resObjPtr, 14309 int toBool) 14310 { 14311 xmlXPathParserContextPtr pctxt; 14312 xmlXPathObjectPtr resObj; 14313 #ifndef LIBXML_THREAD_ENABLED 14314 static int reentance = 0; 14315 #endif 14316 int res; 14317 14318 CHECK_CTXT_NEG(ctxt) 14319 14320 if (comp == NULL) 14321 return(-1); 14322 xmlInitParser(); 14323 14324 #ifndef LIBXML_THREAD_ENABLED 14325 reentance++; 14326 if (reentance > 1) 14327 xmlXPathDisableOptimizer = 1; 14328 #endif 14329 14330 #ifdef DEBUG_EVAL_COUNTS 14331 comp->nb++; 14332 if ((comp->string != NULL) && (comp->nb > 100)) { 14333 fprintf(stderr, "100 x %s\n", comp->string); 14334 comp->nb = 0; 14335 } 14336 #endif 14337 pctxt = xmlXPathCompParserContext(comp, ctxt); 14338 res = xmlXPathRunEval(pctxt, toBool); 14339 14340 if (pctxt->error != XPATH_EXPRESSION_OK) { 14341 resObj = NULL; 14342 } else { 14343 resObj = valuePop(pctxt); 14344 if (resObj == NULL) { 14345 if (!toBool) 14346 xmlGenericError(xmlGenericErrorContext, 14347 "xmlXPathCompiledEval: No result on the stack.\n"); 14348 } else if (pctxt->valueNr > 0) { 14349 xmlGenericError(xmlGenericErrorContext, 14350 "xmlXPathCompiledEval: %d object(s) left on the stack.\n", 14351 pctxt->valueNr); 14352 } 14353 } 14354 14355 if (resObjPtr) 14356 *resObjPtr = resObj; 14357 else 14358 xmlXPathReleaseObject(ctxt, resObj); 14359 14360 pctxt->comp = NULL; 14361 xmlXPathFreeParserContext(pctxt); 14362 #ifndef LIBXML_THREAD_ENABLED 14363 reentance--; 14364 #endif 14365 14366 return(res); 14367 } 14368 14369 /** 14370 * xmlXPathCompiledEval: 14371 * @comp: the compiled XPath expression 14372 * @ctx: the XPath context 14373 * 14374 * Evaluate the Precompiled XPath expression in the given context. 14375 * 14376 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14377 * the caller has to free the object. 14378 */ 14379 xmlXPathObjectPtr 14380 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) 14381 { 14382 xmlXPathObjectPtr res = NULL; 14383 14384 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0); 14385 return(res); 14386 } 14387 14388 /** 14389 * xmlXPathCompiledEvalToBoolean: 14390 * @comp: the compiled XPath expression 14391 * @ctxt: the XPath context 14392 * 14393 * Applies the XPath boolean() function on the result of the given 14394 * compiled expression. 14395 * 14396 * Returns 1 if the expression evaluated to true, 0 if to false and 14397 * -1 in API and internal errors. 14398 */ 14399 int 14400 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp, 14401 xmlXPathContextPtr ctxt) 14402 { 14403 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1)); 14404 } 14405 14406 /** 14407 * xmlXPathEvalExpr: 14408 * @ctxt: the XPath Parser context 14409 * 14410 * Parse and evaluate an XPath expression in the given context, 14411 * then push the result on the context stack 14412 */ 14413 void 14414 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) { 14415 #ifdef XPATH_STREAMING 14416 xmlXPathCompExprPtr comp; 14417 #endif 14418 int oldDepth = 0; 14419 14420 if (ctxt == NULL) return; 14421 14422 #ifdef XPATH_STREAMING 14423 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base); 14424 if (comp != NULL) { 14425 if (ctxt->comp != NULL) 14426 xmlXPathFreeCompExpr(ctxt->comp); 14427 ctxt->comp = comp; 14428 } else 14429 #endif 14430 { 14431 if (ctxt->context != NULL) 14432 oldDepth = ctxt->context->depth; 14433 xmlXPathCompileExpr(ctxt, 1); 14434 if (ctxt->context != NULL) 14435 ctxt->context->depth = oldDepth; 14436 CHECK_ERROR; 14437 14438 /* Check for trailing characters. */ 14439 if (*ctxt->cur != 0) 14440 XP_ERROR(XPATH_EXPR_ERROR); 14441 14442 if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) { 14443 if (ctxt->context != NULL) 14444 oldDepth = ctxt->context->depth; 14445 xmlXPathOptimizeExpression(ctxt, 14446 &ctxt->comp->steps[ctxt->comp->last]); 14447 if (ctxt->context != NULL) 14448 ctxt->context->depth = oldDepth; 14449 } 14450 } 14451 14452 xmlXPathRunEval(ctxt, 0); 14453 } 14454 14455 /** 14456 * xmlXPathEval: 14457 * @str: the XPath expression 14458 * @ctx: the XPath context 14459 * 14460 * Evaluate the XPath Location Path in the given context. 14461 * 14462 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14463 * the caller has to free the object. 14464 */ 14465 xmlXPathObjectPtr 14466 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) { 14467 xmlXPathParserContextPtr ctxt; 14468 xmlXPathObjectPtr res; 14469 14470 CHECK_CTXT(ctx) 14471 14472 xmlInitParser(); 14473 14474 ctxt = xmlXPathNewParserContext(str, ctx); 14475 if (ctxt == NULL) 14476 return NULL; 14477 xmlXPathEvalExpr(ctxt); 14478 14479 if (ctxt->error != XPATH_EXPRESSION_OK) { 14480 res = NULL; 14481 } else { 14482 res = valuePop(ctxt); 14483 if (res == NULL) { 14484 xmlGenericError(xmlGenericErrorContext, 14485 "xmlXPathCompiledEval: No result on the stack.\n"); 14486 } else if (ctxt->valueNr > 0) { 14487 xmlGenericError(xmlGenericErrorContext, 14488 "xmlXPathCompiledEval: %d object(s) left on the stack.\n", 14489 ctxt->valueNr); 14490 } 14491 } 14492 14493 xmlXPathFreeParserContext(ctxt); 14494 return(res); 14495 } 14496 14497 /** 14498 * xmlXPathSetContextNode: 14499 * @node: the node to to use as the context node 14500 * @ctx: the XPath context 14501 * 14502 * Sets 'node' as the context node. The node must be in the same 14503 * document as that associated with the context. 14504 * 14505 * Returns -1 in case of error or 0 if successful 14506 */ 14507 int 14508 xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) { 14509 if ((node == NULL) || (ctx == NULL)) 14510 return(-1); 14511 14512 if (node->doc == ctx->doc) { 14513 ctx->node = node; 14514 return(0); 14515 } 14516 return(-1); 14517 } 14518 14519 /** 14520 * xmlXPathNodeEval: 14521 * @node: the node to to use as the context node 14522 * @str: the XPath expression 14523 * @ctx: the XPath context 14524 * 14525 * Evaluate the XPath Location Path in the given context. The node 'node' 14526 * is set as the context node. The context node is not restored. 14527 * 14528 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14529 * the caller has to free the object. 14530 */ 14531 xmlXPathObjectPtr 14532 xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) { 14533 if (str == NULL) 14534 return(NULL); 14535 if (xmlXPathSetContextNode(node, ctx) < 0) 14536 return(NULL); 14537 return(xmlXPathEval(str, ctx)); 14538 } 14539 14540 /** 14541 * xmlXPathEvalExpression: 14542 * @str: the XPath expression 14543 * @ctxt: the XPath context 14544 * 14545 * Alias for xmlXPathEval(). 14546 * 14547 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14548 * the caller has to free the object. 14549 */ 14550 xmlXPathObjectPtr 14551 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) { 14552 return(xmlXPathEval(str, ctxt)); 14553 } 14554 14555 /************************************************************************ 14556 * * 14557 * Extra functions not pertaining to the XPath spec * 14558 * * 14559 ************************************************************************/ 14560 /** 14561 * xmlXPathEscapeUriFunction: 14562 * @ctxt: the XPath Parser context 14563 * @nargs: the number of arguments 14564 * 14565 * Implement the escape-uri() XPath function 14566 * string escape-uri(string $str, bool $escape-reserved) 14567 * 14568 * This function applies the URI escaping rules defined in section 2 of [RFC 14569 * 2396] to the string supplied as $uri-part, which typically represents all 14570 * or part of a URI. The effect of the function is to replace any special 14571 * character in the string by an escape sequence of the form %xx%yy..., 14572 * where xxyy... is the hexadecimal representation of the octets used to 14573 * represent the character in UTF-8. 14574 * 14575 * The set of characters that are escaped depends on the setting of the 14576 * boolean argument $escape-reserved. 14577 * 14578 * If $escape-reserved is true, all characters are escaped other than lower 14579 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters 14580 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!" 14581 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only 14582 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and 14583 * A-F). 14584 * 14585 * If $escape-reserved is false, the behavior differs in that characters 14586 * referred to in [RFC 2396] as reserved characters are not escaped. These 14587 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",". 14588 * 14589 * [RFC 2396] does not define whether escaped URIs should use lower case or 14590 * upper case for hexadecimal digits. To ensure that escaped URIs can be 14591 * compared using string comparison functions, this function must always use 14592 * the upper-case letters A-F. 14593 * 14594 * Generally, $escape-reserved should be set to true when escaping a string 14595 * that is to form a single part of a URI, and to false when escaping an 14596 * entire URI or URI reference. 14597 * 14598 * In the case of non-ascii characters, the string is encoded according to 14599 * utf-8 and then converted according to RFC 2396. 14600 * 14601 * Examples 14602 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true()) 14603 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean" 14604 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false()) 14605 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean" 14606 * 14607 */ 14608 static void 14609 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) { 14610 xmlXPathObjectPtr str; 14611 int escape_reserved; 14612 xmlBufPtr target; 14613 xmlChar *cptr; 14614 xmlChar escape[4]; 14615 14616 CHECK_ARITY(2); 14617 14618 escape_reserved = xmlXPathPopBoolean(ctxt); 14619 14620 CAST_TO_STRING; 14621 str = valuePop(ctxt); 14622 14623 target = xmlBufCreate(); 14624 14625 escape[0] = '%'; 14626 escape[3] = 0; 14627 14628 if (target) { 14629 for (cptr = str->stringval; *cptr; cptr++) { 14630 if ((*cptr >= 'A' && *cptr <= 'Z') || 14631 (*cptr >= 'a' && *cptr <= 'z') || 14632 (*cptr >= '0' && *cptr <= '9') || 14633 *cptr == '-' || *cptr == '_' || *cptr == '.' || 14634 *cptr == '!' || *cptr == '~' || *cptr == '*' || 14635 *cptr == '\''|| *cptr == '(' || *cptr == ')' || 14636 (*cptr == '%' && 14637 ((cptr[1] >= 'A' && cptr[1] <= 'F') || 14638 (cptr[1] >= 'a' && cptr[1] <= 'f') || 14639 (cptr[1] >= '0' && cptr[1] <= '9')) && 14640 ((cptr[2] >= 'A' && cptr[2] <= 'F') || 14641 (cptr[2] >= 'a' && cptr[2] <= 'f') || 14642 (cptr[2] >= '0' && cptr[2] <= '9'))) || 14643 (!escape_reserved && 14644 (*cptr == ';' || *cptr == '/' || *cptr == '?' || 14645 *cptr == ':' || *cptr == '@' || *cptr == '&' || 14646 *cptr == '=' || *cptr == '+' || *cptr == '$' || 14647 *cptr == ','))) { 14648 xmlBufAdd(target, cptr, 1); 14649 } else { 14650 if ((*cptr >> 4) < 10) 14651 escape[1] = '0' + (*cptr >> 4); 14652 else 14653 escape[1] = 'A' - 10 + (*cptr >> 4); 14654 if ((*cptr & 0xF) < 10) 14655 escape[2] = '0' + (*cptr & 0xF); 14656 else 14657 escape[2] = 'A' - 10 + (*cptr & 0xF); 14658 14659 xmlBufAdd(target, &escape[0], 3); 14660 } 14661 } 14662 } 14663 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 14664 xmlBufContent(target))); 14665 xmlBufFree(target); 14666 xmlXPathReleaseObject(ctxt->context, str); 14667 } 14668 14669 /** 14670 * xmlXPathRegisterAllFunctions: 14671 * @ctxt: the XPath context 14672 * 14673 * Registers all default XPath functions in this context 14674 */ 14675 void 14676 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt) 14677 { 14678 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean", 14679 xmlXPathBooleanFunction); 14680 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling", 14681 xmlXPathCeilingFunction); 14682 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count", 14683 xmlXPathCountFunction); 14684 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat", 14685 xmlXPathConcatFunction); 14686 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains", 14687 xmlXPathContainsFunction); 14688 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id", 14689 xmlXPathIdFunction); 14690 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false", 14691 xmlXPathFalseFunction); 14692 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor", 14693 xmlXPathFloorFunction); 14694 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last", 14695 xmlXPathLastFunction); 14696 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang", 14697 xmlXPathLangFunction); 14698 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name", 14699 xmlXPathLocalNameFunction); 14700 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not", 14701 xmlXPathNotFunction); 14702 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name", 14703 xmlXPathNameFunction); 14704 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri", 14705 xmlXPathNamespaceURIFunction); 14706 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space", 14707 xmlXPathNormalizeFunction); 14708 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number", 14709 xmlXPathNumberFunction); 14710 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position", 14711 xmlXPathPositionFunction); 14712 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round", 14713 xmlXPathRoundFunction); 14714 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string", 14715 xmlXPathStringFunction); 14716 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length", 14717 xmlXPathStringLengthFunction); 14718 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with", 14719 xmlXPathStartsWithFunction); 14720 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring", 14721 xmlXPathSubstringFunction); 14722 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before", 14723 xmlXPathSubstringBeforeFunction); 14724 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after", 14725 xmlXPathSubstringAfterFunction); 14726 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum", 14727 xmlXPathSumFunction); 14728 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true", 14729 xmlXPathTrueFunction); 14730 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate", 14731 xmlXPathTranslateFunction); 14732 14733 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri", 14734 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions", 14735 xmlXPathEscapeUriFunction); 14736 } 14737 14738 #endif /* LIBXML_XPATH_ENABLED */ 14739