1 /* 2 * xpath.c: XML Path Language implementation 3 * XPath is a language for addressing parts of an XML document, 4 * designed to be used by both XSLT and XPointer 5 * 6 * Reference: W3C Recommendation 16 November 1999 7 * http://www.w3.org/TR/1999/REC-xpath-19991116 8 * Public reference: 9 * http://www.w3.org/TR/xpath 10 * 11 * See Copyright for the status of this software 12 * 13 * Author: daniel@veillard.com 14 * 15 */ 16 17 /* To avoid EBCDIC trouble when parsing on zOS */ 18 #if defined(__MVS__) 19 #pragma convert("ISO8859-1") 20 #endif 21 22 #define IN_LIBXML 23 #include "libxml.h" 24 25 #include <limits.h> 26 #include <string.h> 27 #include <stddef.h> 28 29 #ifdef HAVE_SYS_TYPES_H 30 #include <sys/types.h> 31 #endif 32 #ifdef HAVE_MATH_H 33 #include <math.h> 34 #endif 35 #ifdef HAVE_FLOAT_H 36 #include <float.h> 37 #endif 38 #ifdef HAVE_CTYPE_H 39 #include <ctype.h> 40 #endif 41 #ifdef HAVE_SIGNAL_H 42 #include <signal.h> 43 #endif 44 45 #include <libxml/xmlmemory.h> 46 #include <libxml/tree.h> 47 #include <libxml/valid.h> 48 #include <libxml/xpath.h> 49 #include <libxml/xpathInternals.h> 50 #include <libxml/parserInternals.h> 51 #include <libxml/hash.h> 52 #ifdef LIBXML_XPTR_ENABLED 53 #include <libxml/xpointer.h> 54 #endif 55 #ifdef LIBXML_DEBUG_ENABLED 56 #include <libxml/debugXML.h> 57 #endif 58 #include <libxml/xmlerror.h> 59 #include <libxml/threads.h> 60 #include <libxml/globals.h> 61 #ifdef LIBXML_PATTERN_ENABLED 62 #include <libxml/pattern.h> 63 #endif 64 65 #include "buf.h" 66 67 #ifdef LIBXML_PATTERN_ENABLED 68 #define XPATH_STREAMING 69 #endif 70 71 #define TODO \ 72 xmlGenericError(xmlGenericErrorContext, \ 73 "Unimplemented block at %s:%d\n", \ 74 __FILE__, __LINE__); 75 76 /** 77 * WITH_TIM_SORT: 78 * 79 * Use the Timsort algorithm provided in timsort.h to sort 80 * nodeset as this is a great improvement over the old Shell sort 81 * used in xmlXPathNodeSetSort() 82 */ 83 #define WITH_TIM_SORT 84 85 /* 86 * XP_OPTIMIZED_NON_ELEM_COMPARISON: 87 * If defined, this will use xmlXPathCmpNodesExt() instead of 88 * xmlXPathCmpNodes(). The new function is optimized comparison of 89 * non-element nodes; actually it will speed up comparison only if 90 * xmlXPathOrderDocElems() was called in order to index the elements of 91 * a tree in document order; Libxslt does such an indexing, thus it will 92 * benefit from this optimization. 93 */ 94 #define XP_OPTIMIZED_NON_ELEM_COMPARISON 95 96 /* 97 * XP_OPTIMIZED_FILTER_FIRST: 98 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]" 99 * in a way, that it stop evaluation at the first node. 100 */ 101 #define XP_OPTIMIZED_FILTER_FIRST 102 103 /* 104 * XP_DEBUG_OBJ_USAGE: 105 * Internal flag to enable tracking of how much XPath objects have been 106 * created. 107 */ 108 /* #define XP_DEBUG_OBJ_USAGE */ 109 110 /* 111 * XPATH_MAX_STEPS: 112 * when compiling an XPath expression we arbitrary limit the maximum 113 * number of step operation in the compiled expression. 1000000 is 114 * an insanely large value which should never be reached under normal 115 * circumstances 116 */ 117 #define XPATH_MAX_STEPS 1000000 118 119 /* 120 * XPATH_MAX_STACK_DEPTH: 121 * when evaluating an XPath expression we arbitrary limit the maximum 122 * number of object allowed to be pushed on the stack. 1000000 is 123 * an insanely large value which should never be reached under normal 124 * circumstances 125 */ 126 #define XPATH_MAX_STACK_DEPTH 1000000 127 128 /* 129 * XPATH_MAX_NODESET_LENGTH: 130 * when evaluating an XPath expression nodesets are created and we 131 * arbitrary limit the maximum length of those node set. 10000000 is 132 * an insanely large value which should never be reached under normal 133 * circumstances, one would first need to construct an in memory tree 134 * with more than 10 millions nodes. 135 */ 136 #define XPATH_MAX_NODESET_LENGTH 10000000 137 138 /* 139 * XPATH_MAX_RECRUSION_DEPTH: 140 * Maximum amount of nested functions calls when parsing or evaluating 141 * expressions 142 */ 143 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION 144 #define XPATH_MAX_RECURSION_DEPTH 500 145 #else 146 #define XPATH_MAX_RECURSION_DEPTH 5000 147 #endif 148 149 /* 150 * TODO: 151 * There are a few spots where some tests are done which depend upon ascii 152 * data. These should be enhanced for full UTF8 support (see particularly 153 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT) 154 */ 155 156 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 157 /** 158 * xmlXPathCmpNodesExt: 159 * @node1: the first node 160 * @node2: the second node 161 * 162 * Compare two nodes w.r.t document order. 163 * This one is optimized for handling of non-element nodes. 164 * 165 * Returns -2 in case of error 1 if first point < second point, 0 if 166 * it's the same node, -1 otherwise 167 */ 168 static int 169 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) { 170 int depth1, depth2; 171 int misc = 0, precedence1 = 0, precedence2 = 0; 172 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL; 173 xmlNodePtr cur, root; 174 ptrdiff_t l1, l2; 175 176 if ((node1 == NULL) || (node2 == NULL)) 177 return(-2); 178 179 if (node1 == node2) 180 return(0); 181 182 /* 183 * a couple of optimizations which will avoid computations in most cases 184 */ 185 switch (node1->type) { 186 case XML_ELEMENT_NODE: 187 if (node2->type == XML_ELEMENT_NODE) { 188 if ((0 > (ptrdiff_t) node1->content) && 189 (0 > (ptrdiff_t) node2->content) && 190 (node1->doc == node2->doc)) 191 { 192 l1 = -((ptrdiff_t) node1->content); 193 l2 = -((ptrdiff_t) node2->content); 194 if (l1 < l2) 195 return(1); 196 if (l1 > l2) 197 return(-1); 198 } else 199 goto turtle_comparison; 200 } 201 break; 202 case XML_ATTRIBUTE_NODE: 203 precedence1 = 1; /* element is owner */ 204 miscNode1 = node1; 205 node1 = node1->parent; 206 misc = 1; 207 break; 208 case XML_TEXT_NODE: 209 case XML_CDATA_SECTION_NODE: 210 case XML_COMMENT_NODE: 211 case XML_PI_NODE: { 212 miscNode1 = node1; 213 /* 214 * Find nearest element node. 215 */ 216 if (node1->prev != NULL) { 217 do { 218 node1 = node1->prev; 219 if (node1->type == XML_ELEMENT_NODE) { 220 precedence1 = 3; /* element in prev-sibl axis */ 221 break; 222 } 223 if (node1->prev == NULL) { 224 precedence1 = 2; /* element is parent */ 225 /* 226 * URGENT TODO: Are there any cases, where the 227 * parent of such a node is not an element node? 228 */ 229 node1 = node1->parent; 230 break; 231 } 232 } while (1); 233 } else { 234 precedence1 = 2; /* element is parent */ 235 node1 = node1->parent; 236 } 237 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) || 238 (0 <= (ptrdiff_t) node1->content)) { 239 /* 240 * Fallback for whatever case. 241 */ 242 node1 = miscNode1; 243 precedence1 = 0; 244 } else 245 misc = 1; 246 } 247 break; 248 case XML_NAMESPACE_DECL: 249 /* 250 * TODO: why do we return 1 for namespace nodes? 251 */ 252 return(1); 253 default: 254 break; 255 } 256 switch (node2->type) { 257 case XML_ELEMENT_NODE: 258 break; 259 case XML_ATTRIBUTE_NODE: 260 precedence2 = 1; /* element is owner */ 261 miscNode2 = node2; 262 node2 = node2->parent; 263 misc = 1; 264 break; 265 case XML_TEXT_NODE: 266 case XML_CDATA_SECTION_NODE: 267 case XML_COMMENT_NODE: 268 case XML_PI_NODE: { 269 miscNode2 = node2; 270 if (node2->prev != NULL) { 271 do { 272 node2 = node2->prev; 273 if (node2->type == XML_ELEMENT_NODE) { 274 precedence2 = 3; /* element in prev-sibl axis */ 275 break; 276 } 277 if (node2->prev == NULL) { 278 precedence2 = 2; /* element is parent */ 279 node2 = node2->parent; 280 break; 281 } 282 } while (1); 283 } else { 284 precedence2 = 2; /* element is parent */ 285 node2 = node2->parent; 286 } 287 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) || 288 (0 <= (ptrdiff_t) node2->content)) 289 { 290 node2 = miscNode2; 291 precedence2 = 0; 292 } else 293 misc = 1; 294 } 295 break; 296 case XML_NAMESPACE_DECL: 297 return(1); 298 default: 299 break; 300 } 301 if (misc) { 302 if (node1 == node2) { 303 if (precedence1 == precedence2) { 304 /* 305 * The ugly case; but normally there aren't many 306 * adjacent non-element nodes around. 307 */ 308 cur = miscNode2->prev; 309 while (cur != NULL) { 310 if (cur == miscNode1) 311 return(1); 312 if (cur->type == XML_ELEMENT_NODE) 313 return(-1); 314 cur = cur->prev; 315 } 316 return (-1); 317 } else { 318 /* 319 * Evaluate based on higher precedence wrt to the element. 320 * TODO: This assumes attributes are sorted before content. 321 * Is this 100% correct? 322 */ 323 if (precedence1 < precedence2) 324 return(1); 325 else 326 return(-1); 327 } 328 } 329 /* 330 * Special case: One of the helper-elements is contained by the other. 331 * <foo> 332 * <node2> 333 * <node1>Text-1(precedence1 == 2)</node1> 334 * </node2> 335 * Text-6(precedence2 == 3) 336 * </foo> 337 */ 338 if ((precedence2 == 3) && (precedence1 > 1)) { 339 cur = node1->parent; 340 while (cur) { 341 if (cur == node2) 342 return(1); 343 cur = cur->parent; 344 } 345 } 346 if ((precedence1 == 3) && (precedence2 > 1)) { 347 cur = node2->parent; 348 while (cur) { 349 if (cur == node1) 350 return(-1); 351 cur = cur->parent; 352 } 353 } 354 } 355 356 /* 357 * Speedup using document order if available. 358 */ 359 if ((node1->type == XML_ELEMENT_NODE) && 360 (node2->type == XML_ELEMENT_NODE) && 361 (0 > (ptrdiff_t) node1->content) && 362 (0 > (ptrdiff_t) node2->content) && 363 (node1->doc == node2->doc)) { 364 365 l1 = -((ptrdiff_t) node1->content); 366 l2 = -((ptrdiff_t) node2->content); 367 if (l1 < l2) 368 return(1); 369 if (l1 > l2) 370 return(-1); 371 } 372 373 turtle_comparison: 374 375 if (node1 == node2->prev) 376 return(1); 377 if (node1 == node2->next) 378 return(-1); 379 /* 380 * compute depth to root 381 */ 382 for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) { 383 if (cur->parent == node1) 384 return(1); 385 depth2++; 386 } 387 root = cur; 388 for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) { 389 if (cur->parent == node2) 390 return(-1); 391 depth1++; 392 } 393 /* 394 * Distinct document (or distinct entities :-( ) case. 395 */ 396 if (root != cur) { 397 return(-2); 398 } 399 /* 400 * get the nearest common ancestor. 401 */ 402 while (depth1 > depth2) { 403 depth1--; 404 node1 = node1->parent; 405 } 406 while (depth2 > depth1) { 407 depth2--; 408 node2 = node2->parent; 409 } 410 while (node1->parent != node2->parent) { 411 node1 = node1->parent; 412 node2 = node2->parent; 413 /* should not happen but just in case ... */ 414 if ((node1 == NULL) || (node2 == NULL)) 415 return(-2); 416 } 417 /* 418 * Find who's first. 419 */ 420 if (node1 == node2->prev) 421 return(1); 422 if (node1 == node2->next) 423 return(-1); 424 /* 425 * Speedup using document order if available. 426 */ 427 if ((node1->type == XML_ELEMENT_NODE) && 428 (node2->type == XML_ELEMENT_NODE) && 429 (0 > (ptrdiff_t) node1->content) && 430 (0 > (ptrdiff_t) node2->content) && 431 (node1->doc == node2->doc)) { 432 433 l1 = -((ptrdiff_t) node1->content); 434 l2 = -((ptrdiff_t) node2->content); 435 if (l1 < l2) 436 return(1); 437 if (l1 > l2) 438 return(-1); 439 } 440 441 for (cur = node1->next;cur != NULL;cur = cur->next) 442 if (cur == node2) 443 return(1); 444 return(-1); /* assume there is no sibling list corruption */ 445 } 446 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */ 447 448 /* 449 * Wrapper for the Timsort algorithm from timsort.h 450 */ 451 #ifdef WITH_TIM_SORT 452 #define SORT_NAME libxml_domnode 453 #define SORT_TYPE xmlNodePtr 454 /** 455 * wrap_cmp: 456 * @x: a node 457 * @y: another node 458 * 459 * Comparison function for the Timsort implementation 460 * 461 * Returns -2 in case of error -1 if first point < second point, 0 if 462 * it's the same node, +1 otherwise 463 */ 464 static 465 int wrap_cmp( xmlNodePtr x, xmlNodePtr y ); 466 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 467 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y ) 468 { 469 int res = xmlXPathCmpNodesExt(x, y); 470 return res == -2 ? res : -res; 471 } 472 #else 473 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y ) 474 { 475 int res = xmlXPathCmpNodes(x, y); 476 return res == -2 ? res : -res; 477 } 478 #endif 479 #define SORT_CMP(x, y) (wrap_cmp(x, y)) 480 #include "timsort.h" 481 #endif /* WITH_TIM_SORT */ 482 483 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) 484 485 /************************************************************************ 486 * * 487 * Floating point stuff * 488 * * 489 ************************************************************************/ 490 491 double xmlXPathNAN; 492 double xmlXPathPINF; 493 double xmlXPathNINF; 494 495 /** 496 * xmlXPathInit: 497 * 498 * Initialize the XPath environment 499 */ 500 ATTRIBUTE_NO_SANITIZE("float-divide-by-zero") 501 void 502 xmlXPathInit(void) { 503 /* MSVC doesn't allow division by zero in constant expressions. */ 504 double zero = 0.0; 505 xmlXPathNAN = 0.0 / zero; 506 xmlXPathPINF = 1.0 / zero; 507 xmlXPathNINF = -xmlXPathPINF; 508 } 509 510 /** 511 * xmlXPathIsNaN: 512 * @val: a double value 513 * 514 * Returns 1 if the value is a NaN, 0 otherwise 515 */ 516 int 517 xmlXPathIsNaN(double val) { 518 #ifdef isnan 519 return isnan(val); 520 #else 521 return !(val == val); 522 #endif 523 } 524 525 /** 526 * xmlXPathIsInf: 527 * @val: a double value 528 * 529 * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise 530 */ 531 int 532 xmlXPathIsInf(double val) { 533 #ifdef isinf 534 return isinf(val) ? (val > 0 ? 1 : -1) : 0; 535 #else 536 if (val >= xmlXPathPINF) 537 return 1; 538 if (val <= -xmlXPathPINF) 539 return -1; 540 return 0; 541 #endif 542 } 543 544 #endif /* SCHEMAS or XPATH */ 545 546 #ifdef LIBXML_XPATH_ENABLED 547 548 /* 549 * TODO: when compatibility allows remove all "fake node libxslt" strings 550 * the test should just be name[0] = ' ' 551 */ 552 #ifdef DEBUG_XPATH_EXPRESSION 553 #define DEBUG_STEP 554 #define DEBUG_EXPR 555 #define DEBUG_EVAL_COUNTS 556 #endif 557 558 static xmlNs xmlXPathXMLNamespaceStruct = { 559 NULL, 560 XML_NAMESPACE_DECL, 561 XML_XML_NAMESPACE, 562 BAD_CAST "xml", 563 NULL, 564 NULL 565 }; 566 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct; 567 #ifndef LIBXML_THREAD_ENABLED 568 /* 569 * Optimizer is disabled only when threaded apps are detected while 570 * the library ain't compiled for thread safety. 571 */ 572 static int xmlXPathDisableOptimizer = 0; 573 #endif 574 575 /************************************************************************ 576 * * 577 * Error handling routines * 578 * * 579 ************************************************************************/ 580 581 /** 582 * XP_ERRORNULL: 583 * @X: the error code 584 * 585 * Macro to raise an XPath error and return NULL. 586 */ 587 #define XP_ERRORNULL(X) \ 588 { xmlXPathErr(ctxt, X); return(NULL); } 589 590 /* 591 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError 592 */ 593 static const char *xmlXPathErrorMessages[] = { 594 "Ok\n", 595 "Number encoding\n", 596 "Unfinished literal\n", 597 "Start of literal\n", 598 "Expected $ for variable reference\n", 599 "Undefined variable\n", 600 "Invalid predicate\n", 601 "Invalid expression\n", 602 "Missing closing curly brace\n", 603 "Unregistered function\n", 604 "Invalid operand\n", 605 "Invalid type\n", 606 "Invalid number of arguments\n", 607 "Invalid context size\n", 608 "Invalid context position\n", 609 "Memory allocation error\n", 610 "Syntax error\n", 611 "Resource error\n", 612 "Sub resource error\n", 613 "Undefined namespace prefix\n", 614 "Encoding error\n", 615 "Char out of XML range\n", 616 "Invalid or incomplete context\n", 617 "Stack usage error\n", 618 "Forbidden variable\n", 619 "Operation limit exceeded\n", 620 "Recursion limit exceeded\n", 621 "?? Unknown error ??\n" /* Must be last in the list! */ 622 }; 623 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \ 624 sizeof(xmlXPathErrorMessages[0])) - 1) 625 /** 626 * xmlXPathErrMemory: 627 * @ctxt: an XPath context 628 * @extra: extra information 629 * 630 * Handle a redefinition of attribute error 631 */ 632 static void 633 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra) 634 { 635 if (ctxt != NULL) { 636 xmlResetError(&ctxt->lastError); 637 if (extra) { 638 xmlChar buf[200]; 639 640 xmlStrPrintf(buf, 200, 641 "Memory allocation failed : %s\n", 642 extra); 643 ctxt->lastError.message = (char *) xmlStrdup(buf); 644 } else { 645 ctxt->lastError.message = (char *) 646 xmlStrdup(BAD_CAST "Memory allocation failed\n"); 647 } 648 ctxt->lastError.domain = XML_FROM_XPATH; 649 ctxt->lastError.code = XML_ERR_NO_MEMORY; 650 if (ctxt->error != NULL) 651 ctxt->error(ctxt->userData, &ctxt->lastError); 652 } else { 653 if (extra) 654 __xmlRaiseError(NULL, NULL, NULL, 655 NULL, NULL, XML_FROM_XPATH, 656 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, 657 extra, NULL, NULL, 0, 0, 658 "Memory allocation failed : %s\n", extra); 659 else 660 __xmlRaiseError(NULL, NULL, NULL, 661 NULL, NULL, XML_FROM_XPATH, 662 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, 663 NULL, NULL, NULL, 0, 0, 664 "Memory allocation failed\n"); 665 } 666 } 667 668 /** 669 * xmlXPathPErrMemory: 670 * @ctxt: an XPath parser context 671 * @extra: extra information 672 * 673 * Handle a redefinition of attribute error 674 */ 675 static void 676 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra) 677 { 678 if (ctxt == NULL) 679 xmlXPathErrMemory(NULL, extra); 680 else { 681 ctxt->error = XPATH_MEMORY_ERROR; 682 xmlXPathErrMemory(ctxt->context, extra); 683 } 684 } 685 686 /** 687 * xmlXPathErr: 688 * @ctxt: a XPath parser context 689 * @error: the error code 690 * 691 * Handle an XPath error 692 */ 693 void 694 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error) 695 { 696 if ((error < 0) || (error > MAXERRNO)) 697 error = MAXERRNO; 698 if (ctxt == NULL) { 699 __xmlRaiseError(NULL, NULL, NULL, 700 NULL, NULL, XML_FROM_XPATH, 701 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, 702 XML_ERR_ERROR, NULL, 0, 703 NULL, NULL, NULL, 0, 0, 704 "%s", xmlXPathErrorMessages[error]); 705 return; 706 } 707 ctxt->error = error; 708 if (ctxt->context == NULL) { 709 __xmlRaiseError(NULL, NULL, NULL, 710 NULL, NULL, XML_FROM_XPATH, 711 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, 712 XML_ERR_ERROR, NULL, 0, 713 (const char *) ctxt->base, NULL, NULL, 714 ctxt->cur - ctxt->base, 0, 715 "%s", xmlXPathErrorMessages[error]); 716 return; 717 } 718 719 /* cleanup current last error */ 720 xmlResetError(&ctxt->context->lastError); 721 722 ctxt->context->lastError.domain = XML_FROM_XPATH; 723 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK - 724 XPATH_EXPRESSION_OK; 725 ctxt->context->lastError.level = XML_ERR_ERROR; 726 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base); 727 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base; 728 ctxt->context->lastError.node = ctxt->context->debugNode; 729 if (ctxt->context->error != NULL) { 730 ctxt->context->error(ctxt->context->userData, 731 &ctxt->context->lastError); 732 } else { 733 __xmlRaiseError(NULL, NULL, NULL, 734 NULL, ctxt->context->debugNode, XML_FROM_XPATH, 735 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, 736 XML_ERR_ERROR, NULL, 0, 737 (const char *) ctxt->base, NULL, NULL, 738 ctxt->cur - ctxt->base, 0, 739 "%s", xmlXPathErrorMessages[error]); 740 } 741 742 } 743 744 /** 745 * xmlXPatherror: 746 * @ctxt: the XPath Parser context 747 * @file: the file name 748 * @line: the line number 749 * @no: the error number 750 * 751 * Formats an error message. 752 */ 753 void 754 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED, 755 int line ATTRIBUTE_UNUSED, int no) { 756 xmlXPathErr(ctxt, no); 757 } 758 759 /** 760 * xmlXPathCheckOpLimit: 761 * @ctxt: the XPath Parser context 762 * @opCount: the number of operations to be added 763 * 764 * Adds opCount to the running total of operations and returns -1 if the 765 * operation limit is exceeded. Returns 0 otherwise. 766 */ 767 static int 768 xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) { 769 xmlXPathContextPtr xpctxt = ctxt->context; 770 771 if ((opCount > xpctxt->opLimit) || 772 (xpctxt->opCount > xpctxt->opLimit - opCount)) { 773 xpctxt->opCount = xpctxt->opLimit; 774 xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED); 775 return(-1); 776 } 777 778 xpctxt->opCount += opCount; 779 return(0); 780 } 781 782 #define OP_LIMIT_EXCEEDED(ctxt, n) \ 783 ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0)) 784 785 /************************************************************************ 786 * * 787 * Utilities * 788 * * 789 ************************************************************************/ 790 791 /** 792 * xsltPointerList: 793 * 794 * Pointer-list for various purposes. 795 */ 796 typedef struct _xmlPointerList xmlPointerList; 797 typedef xmlPointerList *xmlPointerListPtr; 798 struct _xmlPointerList { 799 void **items; 800 int number; 801 int size; 802 }; 803 /* 804 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt 805 * and here, we should make the functions public. 806 */ 807 static int 808 xmlPointerListAddSize(xmlPointerListPtr list, 809 void *item, 810 int initialSize) 811 { 812 if (list->items == NULL) { 813 if (initialSize <= 0) 814 initialSize = 1; 815 list->items = (void **) xmlMalloc(initialSize * sizeof(void *)); 816 if (list->items == NULL) { 817 xmlXPathErrMemory(NULL, 818 "xmlPointerListCreate: allocating item\n"); 819 return(-1); 820 } 821 list->number = 0; 822 list->size = initialSize; 823 } else if (list->size <= list->number) { 824 if (list->size > 50000000) { 825 xmlXPathErrMemory(NULL, 826 "xmlPointerListAddSize: re-allocating item\n"); 827 return(-1); 828 } 829 list->size *= 2; 830 list->items = (void **) xmlRealloc(list->items, 831 list->size * sizeof(void *)); 832 if (list->items == NULL) { 833 xmlXPathErrMemory(NULL, 834 "xmlPointerListAddSize: re-allocating item\n"); 835 list->size = 0; 836 return(-1); 837 } 838 } 839 list->items[list->number++] = item; 840 return(0); 841 } 842 843 /** 844 * xsltPointerListCreate: 845 * 846 * Creates an xsltPointerList structure. 847 * 848 * Returns a xsltPointerList structure or NULL in case of an error. 849 */ 850 static xmlPointerListPtr 851 xmlPointerListCreate(int initialSize) 852 { 853 xmlPointerListPtr ret; 854 855 ret = xmlMalloc(sizeof(xmlPointerList)); 856 if (ret == NULL) { 857 xmlXPathErrMemory(NULL, 858 "xmlPointerListCreate: allocating item\n"); 859 return (NULL); 860 } 861 memset(ret, 0, sizeof(xmlPointerList)); 862 if (initialSize > 0) { 863 xmlPointerListAddSize(ret, NULL, initialSize); 864 ret->number = 0; 865 } 866 return (ret); 867 } 868 869 /** 870 * xsltPointerListFree: 871 * 872 * Frees the xsltPointerList structure. This does not free 873 * the content of the list. 874 */ 875 static void 876 xmlPointerListFree(xmlPointerListPtr list) 877 { 878 if (list == NULL) 879 return; 880 if (list->items != NULL) 881 xmlFree(list->items); 882 xmlFree(list); 883 } 884 885 /************************************************************************ 886 * * 887 * Parser Types * 888 * * 889 ************************************************************************/ 890 891 /* 892 * Types are private: 893 */ 894 895 typedef enum { 896 XPATH_OP_END=0, 897 XPATH_OP_AND, 898 XPATH_OP_OR, 899 XPATH_OP_EQUAL, 900 XPATH_OP_CMP, 901 XPATH_OP_PLUS, 902 XPATH_OP_MULT, 903 XPATH_OP_UNION, 904 XPATH_OP_ROOT, 905 XPATH_OP_NODE, 906 XPATH_OP_COLLECT, 907 XPATH_OP_VALUE, /* 11 */ 908 XPATH_OP_VARIABLE, 909 XPATH_OP_FUNCTION, 910 XPATH_OP_ARG, 911 XPATH_OP_PREDICATE, 912 XPATH_OP_FILTER, /* 16 */ 913 XPATH_OP_SORT /* 17 */ 914 #ifdef LIBXML_XPTR_ENABLED 915 ,XPATH_OP_RANGETO 916 #endif 917 } xmlXPathOp; 918 919 typedef enum { 920 AXIS_ANCESTOR = 1, 921 AXIS_ANCESTOR_OR_SELF, 922 AXIS_ATTRIBUTE, 923 AXIS_CHILD, 924 AXIS_DESCENDANT, 925 AXIS_DESCENDANT_OR_SELF, 926 AXIS_FOLLOWING, 927 AXIS_FOLLOWING_SIBLING, 928 AXIS_NAMESPACE, 929 AXIS_PARENT, 930 AXIS_PRECEDING, 931 AXIS_PRECEDING_SIBLING, 932 AXIS_SELF 933 } xmlXPathAxisVal; 934 935 typedef enum { 936 NODE_TEST_NONE = 0, 937 NODE_TEST_TYPE = 1, 938 NODE_TEST_PI = 2, 939 NODE_TEST_ALL = 3, 940 NODE_TEST_NS = 4, 941 NODE_TEST_NAME = 5 942 } xmlXPathTestVal; 943 944 typedef enum { 945 NODE_TYPE_NODE = 0, 946 NODE_TYPE_COMMENT = XML_COMMENT_NODE, 947 NODE_TYPE_TEXT = XML_TEXT_NODE, 948 NODE_TYPE_PI = XML_PI_NODE 949 } xmlXPathTypeVal; 950 951 typedef struct _xmlXPathStepOp xmlXPathStepOp; 952 typedef xmlXPathStepOp *xmlXPathStepOpPtr; 953 struct _xmlXPathStepOp { 954 xmlXPathOp op; /* The identifier of the operation */ 955 int ch1; /* First child */ 956 int ch2; /* Second child */ 957 int value; 958 int value2; 959 int value3; 960 void *value4; 961 void *value5; 962 xmlXPathFunction cache; 963 void *cacheURI; 964 }; 965 966 struct _xmlXPathCompExpr { 967 int nbStep; /* Number of steps in this expression */ 968 int maxStep; /* Maximum number of steps allocated */ 969 xmlXPathStepOp *steps; /* ops for computation of this expression */ 970 int last; /* index of last step in expression */ 971 xmlChar *expr; /* the expression being computed */ 972 xmlDictPtr dict; /* the dictionary to use if any */ 973 #ifdef DEBUG_EVAL_COUNTS 974 int nb; 975 xmlChar *string; 976 #endif 977 #ifdef XPATH_STREAMING 978 xmlPatternPtr stream; 979 #endif 980 }; 981 982 /************************************************************************ 983 * * 984 * Forward declarations * 985 * * 986 ************************************************************************/ 987 static void 988 xmlXPathFreeValueTree(xmlNodeSetPtr obj); 989 static void 990 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj); 991 static int 992 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt, 993 xmlXPathStepOpPtr op, xmlNodePtr *first); 994 static int 995 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt, 996 xmlXPathStepOpPtr op, 997 int isPredicate); 998 static void 999 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name); 1000 1001 /************************************************************************ 1002 * * 1003 * Parser Type functions * 1004 * * 1005 ************************************************************************/ 1006 1007 /** 1008 * xmlXPathNewCompExpr: 1009 * 1010 * Create a new Xpath component 1011 * 1012 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error 1013 */ 1014 static xmlXPathCompExprPtr 1015 xmlXPathNewCompExpr(void) { 1016 xmlXPathCompExprPtr cur; 1017 1018 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr)); 1019 if (cur == NULL) { 1020 xmlXPathErrMemory(NULL, "allocating component\n"); 1021 return(NULL); 1022 } 1023 memset(cur, 0, sizeof(xmlXPathCompExpr)); 1024 cur->maxStep = 10; 1025 cur->nbStep = 0; 1026 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep * 1027 sizeof(xmlXPathStepOp)); 1028 if (cur->steps == NULL) { 1029 xmlXPathErrMemory(NULL, "allocating steps\n"); 1030 xmlFree(cur); 1031 return(NULL); 1032 } 1033 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp)); 1034 cur->last = -1; 1035 #ifdef DEBUG_EVAL_COUNTS 1036 cur->nb = 0; 1037 #endif 1038 return(cur); 1039 } 1040 1041 /** 1042 * xmlXPathFreeCompExpr: 1043 * @comp: an XPATH comp 1044 * 1045 * Free up the memory allocated by @comp 1046 */ 1047 void 1048 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp) 1049 { 1050 xmlXPathStepOpPtr op; 1051 int i; 1052 1053 if (comp == NULL) 1054 return; 1055 if (comp->dict == NULL) { 1056 for (i = 0; i < comp->nbStep; i++) { 1057 op = &comp->steps[i]; 1058 if (op->value4 != NULL) { 1059 if (op->op == XPATH_OP_VALUE) 1060 xmlXPathFreeObject(op->value4); 1061 else 1062 xmlFree(op->value4); 1063 } 1064 if (op->value5 != NULL) 1065 xmlFree(op->value5); 1066 } 1067 } else { 1068 for (i = 0; i < comp->nbStep; i++) { 1069 op = &comp->steps[i]; 1070 if (op->value4 != NULL) { 1071 if (op->op == XPATH_OP_VALUE) 1072 xmlXPathFreeObject(op->value4); 1073 } 1074 } 1075 xmlDictFree(comp->dict); 1076 } 1077 if (comp->steps != NULL) { 1078 xmlFree(comp->steps); 1079 } 1080 #ifdef DEBUG_EVAL_COUNTS 1081 if (comp->string != NULL) { 1082 xmlFree(comp->string); 1083 } 1084 #endif 1085 #ifdef XPATH_STREAMING 1086 if (comp->stream != NULL) { 1087 xmlFreePatternList(comp->stream); 1088 } 1089 #endif 1090 if (comp->expr != NULL) { 1091 xmlFree(comp->expr); 1092 } 1093 1094 xmlFree(comp); 1095 } 1096 1097 /** 1098 * xmlXPathCompExprAdd: 1099 * @comp: the compiled expression 1100 * @ch1: first child index 1101 * @ch2: second child index 1102 * @op: an op 1103 * @value: the first int value 1104 * @value2: the second int value 1105 * @value3: the third int value 1106 * @value4: the first string value 1107 * @value5: the second string value 1108 * 1109 * Add a step to an XPath Compiled Expression 1110 * 1111 * Returns -1 in case of failure, the index otherwise 1112 */ 1113 static int 1114 xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2, 1115 xmlXPathOp op, int value, 1116 int value2, int value3, void *value4, void *value5) { 1117 xmlXPathCompExprPtr comp = ctxt->comp; 1118 if (comp->nbStep >= comp->maxStep) { 1119 xmlXPathStepOp *real; 1120 1121 if (comp->maxStep >= XPATH_MAX_STEPS) { 1122 xmlXPathPErrMemory(ctxt, "adding step\n"); 1123 return(-1); 1124 } 1125 comp->maxStep *= 2; 1126 real = (xmlXPathStepOp *) xmlRealloc(comp->steps, 1127 comp->maxStep * sizeof(xmlXPathStepOp)); 1128 if (real == NULL) { 1129 comp->maxStep /= 2; 1130 xmlXPathPErrMemory(ctxt, "adding step\n"); 1131 return(-1); 1132 } 1133 comp->steps = real; 1134 } 1135 comp->last = comp->nbStep; 1136 comp->steps[comp->nbStep].ch1 = ch1; 1137 comp->steps[comp->nbStep].ch2 = ch2; 1138 comp->steps[comp->nbStep].op = op; 1139 comp->steps[comp->nbStep].value = value; 1140 comp->steps[comp->nbStep].value2 = value2; 1141 comp->steps[comp->nbStep].value3 = value3; 1142 if ((comp->dict != NULL) && 1143 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) || 1144 (op == XPATH_OP_COLLECT))) { 1145 if (value4 != NULL) { 1146 comp->steps[comp->nbStep].value4 = (xmlChar *) 1147 (void *)xmlDictLookup(comp->dict, value4, -1); 1148 xmlFree(value4); 1149 } else 1150 comp->steps[comp->nbStep].value4 = NULL; 1151 if (value5 != NULL) { 1152 comp->steps[comp->nbStep].value5 = (xmlChar *) 1153 (void *)xmlDictLookup(comp->dict, value5, -1); 1154 xmlFree(value5); 1155 } else 1156 comp->steps[comp->nbStep].value5 = NULL; 1157 } else { 1158 comp->steps[comp->nbStep].value4 = value4; 1159 comp->steps[comp->nbStep].value5 = value5; 1160 } 1161 comp->steps[comp->nbStep].cache = NULL; 1162 return(comp->nbStep++); 1163 } 1164 1165 /** 1166 * xmlXPathCompSwap: 1167 * @comp: the compiled expression 1168 * @op: operation index 1169 * 1170 * Swaps 2 operations in the compiled expression 1171 */ 1172 static void 1173 xmlXPathCompSwap(xmlXPathStepOpPtr op) { 1174 int tmp; 1175 1176 #ifndef LIBXML_THREAD_ENABLED 1177 /* 1178 * Since this manipulates possibly shared variables, this is 1179 * disabled if one detects that the library is used in a multithreaded 1180 * application 1181 */ 1182 if (xmlXPathDisableOptimizer) 1183 return; 1184 #endif 1185 1186 tmp = op->ch1; 1187 op->ch1 = op->ch2; 1188 op->ch2 = tmp; 1189 } 1190 1191 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \ 1192 xmlXPathCompExprAdd(ctxt, (op1), (op2), \ 1193 (op), (val), (val2), (val3), (val4), (val5)) 1194 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \ 1195 xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1, \ 1196 (op), (val), (val2), (val3), (val4), (val5)) 1197 1198 #define PUSH_LEAVE_EXPR(op, val, val2) \ 1199 xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL) 1200 1201 #define PUSH_UNARY_EXPR(op, ch, val, val2) \ 1202 xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL) 1203 1204 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \ 1205 xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op), \ 1206 (val), (val2), 0 ,NULL ,NULL) 1207 1208 /************************************************************************ 1209 * * 1210 * XPath object cache structures * 1211 * * 1212 ************************************************************************/ 1213 1214 /* #define XP_DEFAULT_CACHE_ON */ 1215 1216 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL)) 1217 1218 typedef struct _xmlXPathContextCache xmlXPathContextCache; 1219 typedef xmlXPathContextCache *xmlXPathContextCachePtr; 1220 struct _xmlXPathContextCache { 1221 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */ 1222 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */ 1223 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */ 1224 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */ 1225 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */ 1226 int maxNodeset; 1227 int maxString; 1228 int maxBoolean; 1229 int maxNumber; 1230 int maxMisc; 1231 #ifdef XP_DEBUG_OBJ_USAGE 1232 int dbgCachedAll; 1233 int dbgCachedNodeset; 1234 int dbgCachedString; 1235 int dbgCachedBool; 1236 int dbgCachedNumber; 1237 int dbgCachedPoint; 1238 int dbgCachedRange; 1239 int dbgCachedLocset; 1240 int dbgCachedUsers; 1241 int dbgCachedXSLTTree; 1242 int dbgCachedUndefined; 1243 1244 1245 int dbgReusedAll; 1246 int dbgReusedNodeset; 1247 int dbgReusedString; 1248 int dbgReusedBool; 1249 int dbgReusedNumber; 1250 int dbgReusedPoint; 1251 int dbgReusedRange; 1252 int dbgReusedLocset; 1253 int dbgReusedUsers; 1254 int dbgReusedXSLTTree; 1255 int dbgReusedUndefined; 1256 1257 #endif 1258 }; 1259 1260 /************************************************************************ 1261 * * 1262 * Debugging related functions * 1263 * * 1264 ************************************************************************/ 1265 1266 #define STRANGE \ 1267 xmlGenericError(xmlGenericErrorContext, \ 1268 "Internal error at %s:%d\n", \ 1269 __FILE__, __LINE__); 1270 1271 #ifdef LIBXML_DEBUG_ENABLED 1272 static void 1273 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) { 1274 int i; 1275 char shift[100]; 1276 1277 for (i = 0;((i < depth) && (i < 25));i++) 1278 shift[2 * i] = shift[2 * i + 1] = ' '; 1279 shift[2 * i] = shift[2 * i + 1] = 0; 1280 if (cur == NULL) { 1281 fprintf(output, "%s", shift); 1282 fprintf(output, "Node is NULL !\n"); 1283 return; 1284 1285 } 1286 1287 if ((cur->type == XML_DOCUMENT_NODE) || 1288 (cur->type == XML_HTML_DOCUMENT_NODE)) { 1289 fprintf(output, "%s", shift); 1290 fprintf(output, " /\n"); 1291 } else if (cur->type == XML_ATTRIBUTE_NODE) 1292 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth); 1293 else 1294 xmlDebugDumpOneNode(output, cur, depth); 1295 } 1296 static void 1297 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) { 1298 xmlNodePtr tmp; 1299 int i; 1300 char shift[100]; 1301 1302 for (i = 0;((i < depth) && (i < 25));i++) 1303 shift[2 * i] = shift[2 * i + 1] = ' '; 1304 shift[2 * i] = shift[2 * i + 1] = 0; 1305 if (cur == NULL) { 1306 fprintf(output, "%s", shift); 1307 fprintf(output, "Node is NULL !\n"); 1308 return; 1309 1310 } 1311 1312 while (cur != NULL) { 1313 tmp = cur; 1314 cur = cur->next; 1315 xmlDebugDumpOneNode(output, tmp, depth); 1316 } 1317 } 1318 1319 static void 1320 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) { 1321 int i; 1322 char shift[100]; 1323 1324 for (i = 0;((i < depth) && (i < 25));i++) 1325 shift[2 * i] = shift[2 * i + 1] = ' '; 1326 shift[2 * i] = shift[2 * i + 1] = 0; 1327 1328 if (cur == NULL) { 1329 fprintf(output, "%s", shift); 1330 fprintf(output, "NodeSet is NULL !\n"); 1331 return; 1332 1333 } 1334 1335 if (cur != NULL) { 1336 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr); 1337 for (i = 0;i < cur->nodeNr;i++) { 1338 fprintf(output, "%s", shift); 1339 fprintf(output, "%d", i + 1); 1340 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1); 1341 } 1342 } 1343 } 1344 1345 static void 1346 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) { 1347 int i; 1348 char shift[100]; 1349 1350 for (i = 0;((i < depth) && (i < 25));i++) 1351 shift[2 * i] = shift[2 * i + 1] = ' '; 1352 shift[2 * i] = shift[2 * i + 1] = 0; 1353 1354 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) { 1355 fprintf(output, "%s", shift); 1356 fprintf(output, "Value Tree is NULL !\n"); 1357 return; 1358 1359 } 1360 1361 fprintf(output, "%s", shift); 1362 fprintf(output, "%d", i + 1); 1363 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1); 1364 } 1365 #if defined(LIBXML_XPTR_ENABLED) 1366 static void 1367 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) { 1368 int i; 1369 char shift[100]; 1370 1371 for (i = 0;((i < depth) && (i < 25));i++) 1372 shift[2 * i] = shift[2 * i + 1] = ' '; 1373 shift[2 * i] = shift[2 * i + 1] = 0; 1374 1375 if (cur == NULL) { 1376 fprintf(output, "%s", shift); 1377 fprintf(output, "LocationSet is NULL !\n"); 1378 return; 1379 1380 } 1381 1382 for (i = 0;i < cur->locNr;i++) { 1383 fprintf(output, "%s", shift); 1384 fprintf(output, "%d : ", i + 1); 1385 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1); 1386 } 1387 } 1388 #endif /* LIBXML_XPTR_ENABLED */ 1389 1390 /** 1391 * xmlXPathDebugDumpObject: 1392 * @output: the FILE * to dump the output 1393 * @cur: the object to inspect 1394 * @depth: indentation level 1395 * 1396 * Dump the content of the object for debugging purposes 1397 */ 1398 void 1399 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) { 1400 int i; 1401 char shift[100]; 1402 1403 if (output == NULL) return; 1404 1405 for (i = 0;((i < depth) && (i < 25));i++) 1406 shift[2 * i] = shift[2 * i + 1] = ' '; 1407 shift[2 * i] = shift[2 * i + 1] = 0; 1408 1409 1410 fprintf(output, "%s", shift); 1411 1412 if (cur == NULL) { 1413 fprintf(output, "Object is empty (NULL)\n"); 1414 return; 1415 } 1416 switch(cur->type) { 1417 case XPATH_UNDEFINED: 1418 fprintf(output, "Object is uninitialized\n"); 1419 break; 1420 case XPATH_NODESET: 1421 fprintf(output, "Object is a Node Set :\n"); 1422 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth); 1423 break; 1424 case XPATH_XSLT_TREE: 1425 fprintf(output, "Object is an XSLT value tree :\n"); 1426 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth); 1427 break; 1428 case XPATH_BOOLEAN: 1429 fprintf(output, "Object is a Boolean : "); 1430 if (cur->boolval) fprintf(output, "true\n"); 1431 else fprintf(output, "false\n"); 1432 break; 1433 case XPATH_NUMBER: 1434 switch (xmlXPathIsInf(cur->floatval)) { 1435 case 1: 1436 fprintf(output, "Object is a number : Infinity\n"); 1437 break; 1438 case -1: 1439 fprintf(output, "Object is a number : -Infinity\n"); 1440 break; 1441 default: 1442 if (xmlXPathIsNaN(cur->floatval)) { 1443 fprintf(output, "Object is a number : NaN\n"); 1444 } else if (cur->floatval == 0) { 1445 /* Omit sign for negative zero. */ 1446 fprintf(output, "Object is a number : 0\n"); 1447 } else { 1448 fprintf(output, "Object is a number : %0g\n", cur->floatval); 1449 } 1450 } 1451 break; 1452 case XPATH_STRING: 1453 fprintf(output, "Object is a string : "); 1454 xmlDebugDumpString(output, cur->stringval); 1455 fprintf(output, "\n"); 1456 break; 1457 case XPATH_POINT: 1458 fprintf(output, "Object is a point : index %d in node", cur->index); 1459 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1); 1460 fprintf(output, "\n"); 1461 break; 1462 case XPATH_RANGE: 1463 if ((cur->user2 == NULL) || 1464 ((cur->user2 == cur->user) && (cur->index == cur->index2))) { 1465 fprintf(output, "Object is a collapsed range :\n"); 1466 fprintf(output, "%s", shift); 1467 if (cur->index >= 0) 1468 fprintf(output, "index %d in ", cur->index); 1469 fprintf(output, "node\n"); 1470 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, 1471 depth + 1); 1472 } else { 1473 fprintf(output, "Object is a range :\n"); 1474 fprintf(output, "%s", shift); 1475 fprintf(output, "From "); 1476 if (cur->index >= 0) 1477 fprintf(output, "index %d in ", cur->index); 1478 fprintf(output, "node\n"); 1479 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, 1480 depth + 1); 1481 fprintf(output, "%s", shift); 1482 fprintf(output, "To "); 1483 if (cur->index2 >= 0) 1484 fprintf(output, "index %d in ", cur->index2); 1485 fprintf(output, "node\n"); 1486 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2, 1487 depth + 1); 1488 fprintf(output, "\n"); 1489 } 1490 break; 1491 case XPATH_LOCATIONSET: 1492 #if defined(LIBXML_XPTR_ENABLED) 1493 fprintf(output, "Object is a Location Set:\n"); 1494 xmlXPathDebugDumpLocationSet(output, 1495 (xmlLocationSetPtr) cur->user, depth); 1496 #endif 1497 break; 1498 case XPATH_USERS: 1499 fprintf(output, "Object is user defined\n"); 1500 break; 1501 } 1502 } 1503 1504 static void 1505 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp, 1506 xmlXPathStepOpPtr op, int depth) { 1507 int i; 1508 char shift[100]; 1509 1510 for (i = 0;((i < depth) && (i < 25));i++) 1511 shift[2 * i] = shift[2 * i + 1] = ' '; 1512 shift[2 * i] = shift[2 * i + 1] = 0; 1513 1514 fprintf(output, "%s", shift); 1515 if (op == NULL) { 1516 fprintf(output, "Step is NULL\n"); 1517 return; 1518 } 1519 switch (op->op) { 1520 case XPATH_OP_END: 1521 fprintf(output, "END"); break; 1522 case XPATH_OP_AND: 1523 fprintf(output, "AND"); break; 1524 case XPATH_OP_OR: 1525 fprintf(output, "OR"); break; 1526 case XPATH_OP_EQUAL: 1527 if (op->value) 1528 fprintf(output, "EQUAL ="); 1529 else 1530 fprintf(output, "EQUAL !="); 1531 break; 1532 case XPATH_OP_CMP: 1533 if (op->value) 1534 fprintf(output, "CMP <"); 1535 else 1536 fprintf(output, "CMP >"); 1537 if (!op->value2) 1538 fprintf(output, "="); 1539 break; 1540 case XPATH_OP_PLUS: 1541 if (op->value == 0) 1542 fprintf(output, "PLUS -"); 1543 else if (op->value == 1) 1544 fprintf(output, "PLUS +"); 1545 else if (op->value == 2) 1546 fprintf(output, "PLUS unary -"); 1547 else if (op->value == 3) 1548 fprintf(output, "PLUS unary - -"); 1549 break; 1550 case XPATH_OP_MULT: 1551 if (op->value == 0) 1552 fprintf(output, "MULT *"); 1553 else if (op->value == 1) 1554 fprintf(output, "MULT div"); 1555 else 1556 fprintf(output, "MULT mod"); 1557 break; 1558 case XPATH_OP_UNION: 1559 fprintf(output, "UNION"); break; 1560 case XPATH_OP_ROOT: 1561 fprintf(output, "ROOT"); break; 1562 case XPATH_OP_NODE: 1563 fprintf(output, "NODE"); break; 1564 case XPATH_OP_SORT: 1565 fprintf(output, "SORT"); break; 1566 case XPATH_OP_COLLECT: { 1567 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value; 1568 xmlXPathTestVal test = (xmlXPathTestVal)op->value2; 1569 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3; 1570 const xmlChar *prefix = op->value4; 1571 const xmlChar *name = op->value5; 1572 1573 fprintf(output, "COLLECT "); 1574 switch (axis) { 1575 case AXIS_ANCESTOR: 1576 fprintf(output, " 'ancestors' "); break; 1577 case AXIS_ANCESTOR_OR_SELF: 1578 fprintf(output, " 'ancestors-or-self' "); break; 1579 case AXIS_ATTRIBUTE: 1580 fprintf(output, " 'attributes' "); break; 1581 case AXIS_CHILD: 1582 fprintf(output, " 'child' "); break; 1583 case AXIS_DESCENDANT: 1584 fprintf(output, " 'descendant' "); break; 1585 case AXIS_DESCENDANT_OR_SELF: 1586 fprintf(output, " 'descendant-or-self' "); break; 1587 case AXIS_FOLLOWING: 1588 fprintf(output, " 'following' "); break; 1589 case AXIS_FOLLOWING_SIBLING: 1590 fprintf(output, " 'following-siblings' "); break; 1591 case AXIS_NAMESPACE: 1592 fprintf(output, " 'namespace' "); break; 1593 case AXIS_PARENT: 1594 fprintf(output, " 'parent' "); break; 1595 case AXIS_PRECEDING: 1596 fprintf(output, " 'preceding' "); break; 1597 case AXIS_PRECEDING_SIBLING: 1598 fprintf(output, " 'preceding-sibling' "); break; 1599 case AXIS_SELF: 1600 fprintf(output, " 'self' "); break; 1601 } 1602 switch (test) { 1603 case NODE_TEST_NONE: 1604 fprintf(output, "'none' "); break; 1605 case NODE_TEST_TYPE: 1606 fprintf(output, "'type' "); break; 1607 case NODE_TEST_PI: 1608 fprintf(output, "'PI' "); break; 1609 case NODE_TEST_ALL: 1610 fprintf(output, "'all' "); break; 1611 case NODE_TEST_NS: 1612 fprintf(output, "'namespace' "); break; 1613 case NODE_TEST_NAME: 1614 fprintf(output, "'name' "); break; 1615 } 1616 switch (type) { 1617 case NODE_TYPE_NODE: 1618 fprintf(output, "'node' "); break; 1619 case NODE_TYPE_COMMENT: 1620 fprintf(output, "'comment' "); break; 1621 case NODE_TYPE_TEXT: 1622 fprintf(output, "'text' "); break; 1623 case NODE_TYPE_PI: 1624 fprintf(output, "'PI' "); break; 1625 } 1626 if (prefix != NULL) 1627 fprintf(output, "%s:", prefix); 1628 if (name != NULL) 1629 fprintf(output, "%s", (const char *) name); 1630 break; 1631 1632 } 1633 case XPATH_OP_VALUE: { 1634 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4; 1635 1636 fprintf(output, "ELEM "); 1637 xmlXPathDebugDumpObject(output, object, 0); 1638 goto finish; 1639 } 1640 case XPATH_OP_VARIABLE: { 1641 const xmlChar *prefix = op->value5; 1642 const xmlChar *name = op->value4; 1643 1644 if (prefix != NULL) 1645 fprintf(output, "VARIABLE %s:%s", prefix, name); 1646 else 1647 fprintf(output, "VARIABLE %s", name); 1648 break; 1649 } 1650 case XPATH_OP_FUNCTION: { 1651 int nbargs = op->value; 1652 const xmlChar *prefix = op->value5; 1653 const xmlChar *name = op->value4; 1654 1655 if (prefix != NULL) 1656 fprintf(output, "FUNCTION %s:%s(%d args)", 1657 prefix, name, nbargs); 1658 else 1659 fprintf(output, "FUNCTION %s(%d args)", name, nbargs); 1660 break; 1661 } 1662 case XPATH_OP_ARG: fprintf(output, "ARG"); break; 1663 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break; 1664 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break; 1665 #ifdef LIBXML_XPTR_ENABLED 1666 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break; 1667 #endif 1668 default: 1669 fprintf(output, "UNKNOWN %d\n", op->op); return; 1670 } 1671 fprintf(output, "\n"); 1672 finish: 1673 if (op->ch1 >= 0) 1674 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1); 1675 if (op->ch2 >= 0) 1676 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1); 1677 } 1678 1679 /** 1680 * xmlXPathDebugDumpCompExpr: 1681 * @output: the FILE * for the output 1682 * @comp: the precompiled XPath expression 1683 * @depth: the indentation level. 1684 * 1685 * Dumps the tree of the compiled XPath expression. 1686 */ 1687 void 1688 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp, 1689 int depth) { 1690 int i; 1691 char shift[100]; 1692 1693 if ((output == NULL) || (comp == NULL)) return; 1694 1695 for (i = 0;((i < depth) && (i < 25));i++) 1696 shift[2 * i] = shift[2 * i + 1] = ' '; 1697 shift[2 * i] = shift[2 * i + 1] = 0; 1698 1699 fprintf(output, "%s", shift); 1700 1701 #ifdef XPATH_STREAMING 1702 if (comp->stream) { 1703 fprintf(output, "Streaming Expression\n"); 1704 } else 1705 #endif 1706 { 1707 fprintf(output, "Compiled Expression : %d elements\n", 1708 comp->nbStep); 1709 i = comp->last; 1710 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1); 1711 } 1712 } 1713 1714 #ifdef XP_DEBUG_OBJ_USAGE 1715 1716 /* 1717 * XPath object usage related debugging variables. 1718 */ 1719 static int xmlXPathDebugObjCounterUndefined = 0; 1720 static int xmlXPathDebugObjCounterNodeset = 0; 1721 static int xmlXPathDebugObjCounterBool = 0; 1722 static int xmlXPathDebugObjCounterNumber = 0; 1723 static int xmlXPathDebugObjCounterString = 0; 1724 static int xmlXPathDebugObjCounterPoint = 0; 1725 static int xmlXPathDebugObjCounterRange = 0; 1726 static int xmlXPathDebugObjCounterLocset = 0; 1727 static int xmlXPathDebugObjCounterUsers = 0; 1728 static int xmlXPathDebugObjCounterXSLTTree = 0; 1729 static int xmlXPathDebugObjCounterAll = 0; 1730 1731 static int xmlXPathDebugObjTotalUndefined = 0; 1732 static int xmlXPathDebugObjTotalNodeset = 0; 1733 static int xmlXPathDebugObjTotalBool = 0; 1734 static int xmlXPathDebugObjTotalNumber = 0; 1735 static int xmlXPathDebugObjTotalString = 0; 1736 static int xmlXPathDebugObjTotalPoint = 0; 1737 static int xmlXPathDebugObjTotalRange = 0; 1738 static int xmlXPathDebugObjTotalLocset = 0; 1739 static int xmlXPathDebugObjTotalUsers = 0; 1740 static int xmlXPathDebugObjTotalXSLTTree = 0; 1741 static int xmlXPathDebugObjTotalAll = 0; 1742 1743 static int xmlXPathDebugObjMaxUndefined = 0; 1744 static int xmlXPathDebugObjMaxNodeset = 0; 1745 static int xmlXPathDebugObjMaxBool = 0; 1746 static int xmlXPathDebugObjMaxNumber = 0; 1747 static int xmlXPathDebugObjMaxString = 0; 1748 static int xmlXPathDebugObjMaxPoint = 0; 1749 static int xmlXPathDebugObjMaxRange = 0; 1750 static int xmlXPathDebugObjMaxLocset = 0; 1751 static int xmlXPathDebugObjMaxUsers = 0; 1752 static int xmlXPathDebugObjMaxXSLTTree = 0; 1753 static int xmlXPathDebugObjMaxAll = 0; 1754 1755 static void 1756 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt) 1757 { 1758 if (ctxt != NULL) { 1759 if (ctxt->cache != NULL) { 1760 xmlXPathContextCachePtr cache = 1761 (xmlXPathContextCachePtr) ctxt->cache; 1762 1763 cache->dbgCachedAll = 0; 1764 cache->dbgCachedNodeset = 0; 1765 cache->dbgCachedString = 0; 1766 cache->dbgCachedBool = 0; 1767 cache->dbgCachedNumber = 0; 1768 cache->dbgCachedPoint = 0; 1769 cache->dbgCachedRange = 0; 1770 cache->dbgCachedLocset = 0; 1771 cache->dbgCachedUsers = 0; 1772 cache->dbgCachedXSLTTree = 0; 1773 cache->dbgCachedUndefined = 0; 1774 1775 cache->dbgReusedAll = 0; 1776 cache->dbgReusedNodeset = 0; 1777 cache->dbgReusedString = 0; 1778 cache->dbgReusedBool = 0; 1779 cache->dbgReusedNumber = 0; 1780 cache->dbgReusedPoint = 0; 1781 cache->dbgReusedRange = 0; 1782 cache->dbgReusedLocset = 0; 1783 cache->dbgReusedUsers = 0; 1784 cache->dbgReusedXSLTTree = 0; 1785 cache->dbgReusedUndefined = 0; 1786 } 1787 } 1788 1789 xmlXPathDebugObjCounterUndefined = 0; 1790 xmlXPathDebugObjCounterNodeset = 0; 1791 xmlXPathDebugObjCounterBool = 0; 1792 xmlXPathDebugObjCounterNumber = 0; 1793 xmlXPathDebugObjCounterString = 0; 1794 xmlXPathDebugObjCounterPoint = 0; 1795 xmlXPathDebugObjCounterRange = 0; 1796 xmlXPathDebugObjCounterLocset = 0; 1797 xmlXPathDebugObjCounterUsers = 0; 1798 xmlXPathDebugObjCounterXSLTTree = 0; 1799 xmlXPathDebugObjCounterAll = 0; 1800 1801 xmlXPathDebugObjTotalUndefined = 0; 1802 xmlXPathDebugObjTotalNodeset = 0; 1803 xmlXPathDebugObjTotalBool = 0; 1804 xmlXPathDebugObjTotalNumber = 0; 1805 xmlXPathDebugObjTotalString = 0; 1806 xmlXPathDebugObjTotalPoint = 0; 1807 xmlXPathDebugObjTotalRange = 0; 1808 xmlXPathDebugObjTotalLocset = 0; 1809 xmlXPathDebugObjTotalUsers = 0; 1810 xmlXPathDebugObjTotalXSLTTree = 0; 1811 xmlXPathDebugObjTotalAll = 0; 1812 1813 xmlXPathDebugObjMaxUndefined = 0; 1814 xmlXPathDebugObjMaxNodeset = 0; 1815 xmlXPathDebugObjMaxBool = 0; 1816 xmlXPathDebugObjMaxNumber = 0; 1817 xmlXPathDebugObjMaxString = 0; 1818 xmlXPathDebugObjMaxPoint = 0; 1819 xmlXPathDebugObjMaxRange = 0; 1820 xmlXPathDebugObjMaxLocset = 0; 1821 xmlXPathDebugObjMaxUsers = 0; 1822 xmlXPathDebugObjMaxXSLTTree = 0; 1823 xmlXPathDebugObjMaxAll = 0; 1824 1825 } 1826 1827 static void 1828 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt, 1829 xmlXPathObjectType objType) 1830 { 1831 int isCached = 0; 1832 1833 if (ctxt != NULL) { 1834 if (ctxt->cache != NULL) { 1835 xmlXPathContextCachePtr cache = 1836 (xmlXPathContextCachePtr) ctxt->cache; 1837 1838 isCached = 1; 1839 1840 cache->dbgReusedAll++; 1841 switch (objType) { 1842 case XPATH_UNDEFINED: 1843 cache->dbgReusedUndefined++; 1844 break; 1845 case XPATH_NODESET: 1846 cache->dbgReusedNodeset++; 1847 break; 1848 case XPATH_BOOLEAN: 1849 cache->dbgReusedBool++; 1850 break; 1851 case XPATH_NUMBER: 1852 cache->dbgReusedNumber++; 1853 break; 1854 case XPATH_STRING: 1855 cache->dbgReusedString++; 1856 break; 1857 case XPATH_POINT: 1858 cache->dbgReusedPoint++; 1859 break; 1860 case XPATH_RANGE: 1861 cache->dbgReusedRange++; 1862 break; 1863 case XPATH_LOCATIONSET: 1864 cache->dbgReusedLocset++; 1865 break; 1866 case XPATH_USERS: 1867 cache->dbgReusedUsers++; 1868 break; 1869 case XPATH_XSLT_TREE: 1870 cache->dbgReusedXSLTTree++; 1871 break; 1872 default: 1873 break; 1874 } 1875 } 1876 } 1877 1878 switch (objType) { 1879 case XPATH_UNDEFINED: 1880 if (! isCached) 1881 xmlXPathDebugObjTotalUndefined++; 1882 xmlXPathDebugObjCounterUndefined++; 1883 if (xmlXPathDebugObjCounterUndefined > 1884 xmlXPathDebugObjMaxUndefined) 1885 xmlXPathDebugObjMaxUndefined = 1886 xmlXPathDebugObjCounterUndefined; 1887 break; 1888 case XPATH_NODESET: 1889 if (! isCached) 1890 xmlXPathDebugObjTotalNodeset++; 1891 xmlXPathDebugObjCounterNodeset++; 1892 if (xmlXPathDebugObjCounterNodeset > 1893 xmlXPathDebugObjMaxNodeset) 1894 xmlXPathDebugObjMaxNodeset = 1895 xmlXPathDebugObjCounterNodeset; 1896 break; 1897 case XPATH_BOOLEAN: 1898 if (! isCached) 1899 xmlXPathDebugObjTotalBool++; 1900 xmlXPathDebugObjCounterBool++; 1901 if (xmlXPathDebugObjCounterBool > 1902 xmlXPathDebugObjMaxBool) 1903 xmlXPathDebugObjMaxBool = 1904 xmlXPathDebugObjCounterBool; 1905 break; 1906 case XPATH_NUMBER: 1907 if (! isCached) 1908 xmlXPathDebugObjTotalNumber++; 1909 xmlXPathDebugObjCounterNumber++; 1910 if (xmlXPathDebugObjCounterNumber > 1911 xmlXPathDebugObjMaxNumber) 1912 xmlXPathDebugObjMaxNumber = 1913 xmlXPathDebugObjCounterNumber; 1914 break; 1915 case XPATH_STRING: 1916 if (! isCached) 1917 xmlXPathDebugObjTotalString++; 1918 xmlXPathDebugObjCounterString++; 1919 if (xmlXPathDebugObjCounterString > 1920 xmlXPathDebugObjMaxString) 1921 xmlXPathDebugObjMaxString = 1922 xmlXPathDebugObjCounterString; 1923 break; 1924 case XPATH_POINT: 1925 if (! isCached) 1926 xmlXPathDebugObjTotalPoint++; 1927 xmlXPathDebugObjCounterPoint++; 1928 if (xmlXPathDebugObjCounterPoint > 1929 xmlXPathDebugObjMaxPoint) 1930 xmlXPathDebugObjMaxPoint = 1931 xmlXPathDebugObjCounterPoint; 1932 break; 1933 case XPATH_RANGE: 1934 if (! isCached) 1935 xmlXPathDebugObjTotalRange++; 1936 xmlXPathDebugObjCounterRange++; 1937 if (xmlXPathDebugObjCounterRange > 1938 xmlXPathDebugObjMaxRange) 1939 xmlXPathDebugObjMaxRange = 1940 xmlXPathDebugObjCounterRange; 1941 break; 1942 case XPATH_LOCATIONSET: 1943 if (! isCached) 1944 xmlXPathDebugObjTotalLocset++; 1945 xmlXPathDebugObjCounterLocset++; 1946 if (xmlXPathDebugObjCounterLocset > 1947 xmlXPathDebugObjMaxLocset) 1948 xmlXPathDebugObjMaxLocset = 1949 xmlXPathDebugObjCounterLocset; 1950 break; 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 case XPATH_POINT: 2012 cache->dbgCachedPoint++; 2013 break; 2014 case XPATH_RANGE: 2015 cache->dbgCachedRange++; 2016 break; 2017 case XPATH_LOCATIONSET: 2018 cache->dbgCachedLocset++; 2019 break; 2020 case XPATH_USERS: 2021 cache->dbgCachedUsers++; 2022 break; 2023 case XPATH_XSLT_TREE: 2024 cache->dbgCachedXSLTTree++; 2025 break; 2026 default: 2027 break; 2028 } 2029 2030 } 2031 } 2032 switch (objType) { 2033 case XPATH_UNDEFINED: 2034 xmlXPathDebugObjCounterUndefined--; 2035 break; 2036 case XPATH_NODESET: 2037 xmlXPathDebugObjCounterNodeset--; 2038 break; 2039 case XPATH_BOOLEAN: 2040 xmlXPathDebugObjCounterBool--; 2041 break; 2042 case XPATH_NUMBER: 2043 xmlXPathDebugObjCounterNumber--; 2044 break; 2045 case XPATH_STRING: 2046 xmlXPathDebugObjCounterString--; 2047 break; 2048 case XPATH_POINT: 2049 xmlXPathDebugObjCounterPoint--; 2050 break; 2051 case XPATH_RANGE: 2052 xmlXPathDebugObjCounterRange--; 2053 break; 2054 case XPATH_LOCATIONSET: 2055 xmlXPathDebugObjCounterLocset--; 2056 break; 2057 case XPATH_USERS: 2058 xmlXPathDebugObjCounterUsers--; 2059 break; 2060 case XPATH_XSLT_TREE: 2061 xmlXPathDebugObjCounterXSLTTree--; 2062 break; 2063 default: 2064 break; 2065 } 2066 xmlXPathDebugObjCounterAll--; 2067 } 2068 2069 static void 2070 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt) 2071 { 2072 int reqAll, reqNodeset, reqString, reqBool, reqNumber, 2073 reqXSLTTree, reqUndefined; 2074 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0, 2075 caNumber = 0, caXSLTTree = 0, caUndefined = 0; 2076 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0, 2077 reNumber = 0, reXSLTTree = 0, reUndefined = 0; 2078 int leftObjs = xmlXPathDebugObjCounterAll; 2079 2080 reqAll = xmlXPathDebugObjTotalAll; 2081 reqNodeset = xmlXPathDebugObjTotalNodeset; 2082 reqString = xmlXPathDebugObjTotalString; 2083 reqBool = xmlXPathDebugObjTotalBool; 2084 reqNumber = xmlXPathDebugObjTotalNumber; 2085 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree; 2086 reqUndefined = xmlXPathDebugObjTotalUndefined; 2087 2088 printf("# XPath object usage:\n"); 2089 2090 if (ctxt != NULL) { 2091 if (ctxt->cache != NULL) { 2092 xmlXPathContextCachePtr cache = 2093 (xmlXPathContextCachePtr) ctxt->cache; 2094 2095 reAll = cache->dbgReusedAll; 2096 reqAll += reAll; 2097 reNodeset = cache->dbgReusedNodeset; 2098 reqNodeset += reNodeset; 2099 reString = cache->dbgReusedString; 2100 reqString += reString; 2101 reBool = cache->dbgReusedBool; 2102 reqBool += reBool; 2103 reNumber = cache->dbgReusedNumber; 2104 reqNumber += reNumber; 2105 reXSLTTree = cache->dbgReusedXSLTTree; 2106 reqXSLTTree += reXSLTTree; 2107 reUndefined = cache->dbgReusedUndefined; 2108 reqUndefined += reUndefined; 2109 2110 caAll = cache->dbgCachedAll; 2111 caBool = cache->dbgCachedBool; 2112 caNodeset = cache->dbgCachedNodeset; 2113 caString = cache->dbgCachedString; 2114 caNumber = cache->dbgCachedNumber; 2115 caXSLTTree = cache->dbgCachedXSLTTree; 2116 caUndefined = cache->dbgCachedUndefined; 2117 2118 if (cache->nodesetObjs) 2119 leftObjs -= cache->nodesetObjs->number; 2120 if (cache->stringObjs) 2121 leftObjs -= cache->stringObjs->number; 2122 if (cache->booleanObjs) 2123 leftObjs -= cache->booleanObjs->number; 2124 if (cache->numberObjs) 2125 leftObjs -= cache->numberObjs->number; 2126 if (cache->miscObjs) 2127 leftObjs -= cache->miscObjs->number; 2128 } 2129 } 2130 2131 printf("# all\n"); 2132 printf("# total : %d\n", reqAll); 2133 printf("# left : %d\n", leftObjs); 2134 printf("# created: %d\n", xmlXPathDebugObjTotalAll); 2135 printf("# reused : %d\n", reAll); 2136 printf("# max : %d\n", xmlXPathDebugObjMaxAll); 2137 2138 printf("# node-sets\n"); 2139 printf("# total : %d\n", reqNodeset); 2140 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset); 2141 printf("# reused : %d\n", reNodeset); 2142 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset); 2143 2144 printf("# strings\n"); 2145 printf("# total : %d\n", reqString); 2146 printf("# created: %d\n", xmlXPathDebugObjTotalString); 2147 printf("# reused : %d\n", reString); 2148 printf("# max : %d\n", xmlXPathDebugObjMaxString); 2149 2150 printf("# booleans\n"); 2151 printf("# total : %d\n", reqBool); 2152 printf("# created: %d\n", xmlXPathDebugObjTotalBool); 2153 printf("# reused : %d\n", reBool); 2154 printf("# max : %d\n", xmlXPathDebugObjMaxBool); 2155 2156 printf("# numbers\n"); 2157 printf("# total : %d\n", reqNumber); 2158 printf("# created: %d\n", xmlXPathDebugObjTotalNumber); 2159 printf("# reused : %d\n", reNumber); 2160 printf("# max : %d\n", xmlXPathDebugObjMaxNumber); 2161 2162 printf("# XSLT result tree fragments\n"); 2163 printf("# total : %d\n", reqXSLTTree); 2164 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree); 2165 printf("# reused : %d\n", reXSLTTree); 2166 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree); 2167 2168 printf("# undefined\n"); 2169 printf("# total : %d\n", reqUndefined); 2170 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined); 2171 printf("# reused : %d\n", reUndefined); 2172 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined); 2173 2174 } 2175 2176 #endif /* XP_DEBUG_OBJ_USAGE */ 2177 2178 #endif /* LIBXML_DEBUG_ENABLED */ 2179 2180 /************************************************************************ 2181 * * 2182 * XPath object caching * 2183 * * 2184 ************************************************************************/ 2185 2186 /** 2187 * xmlXPathNewCache: 2188 * 2189 * Create a new object cache 2190 * 2191 * Returns the xmlXPathCache just allocated. 2192 */ 2193 static xmlXPathContextCachePtr 2194 xmlXPathNewCache(void) 2195 { 2196 xmlXPathContextCachePtr ret; 2197 2198 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache)); 2199 if (ret == NULL) { 2200 xmlXPathErrMemory(NULL, "creating object cache\n"); 2201 return(NULL); 2202 } 2203 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache)); 2204 ret->maxNodeset = 100; 2205 ret->maxString = 100; 2206 ret->maxBoolean = 100; 2207 ret->maxNumber = 100; 2208 ret->maxMisc = 100; 2209 return(ret); 2210 } 2211 2212 static void 2213 xmlXPathCacheFreeObjectList(xmlPointerListPtr list) 2214 { 2215 int i; 2216 xmlXPathObjectPtr obj; 2217 2218 if (list == NULL) 2219 return; 2220 2221 for (i = 0; i < list->number; i++) { 2222 obj = list->items[i]; 2223 /* 2224 * Note that it is already assured that we don't need to 2225 * look out for namespace nodes in the node-set. 2226 */ 2227 if (obj->nodesetval != NULL) { 2228 if (obj->nodesetval->nodeTab != NULL) 2229 xmlFree(obj->nodesetval->nodeTab); 2230 xmlFree(obj->nodesetval); 2231 } 2232 xmlFree(obj); 2233 #ifdef XP_DEBUG_OBJ_USAGE 2234 xmlXPathDebugObjCounterAll--; 2235 #endif 2236 } 2237 xmlPointerListFree(list); 2238 } 2239 2240 static void 2241 xmlXPathFreeCache(xmlXPathContextCachePtr cache) 2242 { 2243 if (cache == NULL) 2244 return; 2245 if (cache->nodesetObjs) 2246 xmlXPathCacheFreeObjectList(cache->nodesetObjs); 2247 if (cache->stringObjs) 2248 xmlXPathCacheFreeObjectList(cache->stringObjs); 2249 if (cache->booleanObjs) 2250 xmlXPathCacheFreeObjectList(cache->booleanObjs); 2251 if (cache->numberObjs) 2252 xmlXPathCacheFreeObjectList(cache->numberObjs); 2253 if (cache->miscObjs) 2254 xmlXPathCacheFreeObjectList(cache->miscObjs); 2255 xmlFree(cache); 2256 } 2257 2258 /** 2259 * xmlXPathContextSetCache: 2260 * 2261 * @ctxt: the XPath context 2262 * @active: enables/disables (creates/frees) the cache 2263 * @value: a value with semantics dependent on @options 2264 * @options: options (currently only the value 0 is used) 2265 * 2266 * Creates/frees an object cache on the XPath context. 2267 * If activates XPath objects (xmlXPathObject) will be cached internally 2268 * to be reused. 2269 * @options: 2270 * 0: This will set the XPath object caching: 2271 * @value: 2272 * This will set the maximum number of XPath objects 2273 * to be cached per slot 2274 * There are 5 slots for: node-set, string, number, boolean, and 2275 * misc objects. Use <0 for the default number (100). 2276 * Other values for @options have currently no effect. 2277 * 2278 * Returns 0 if the setting succeeded, and -1 on API or internal errors. 2279 */ 2280 int 2281 xmlXPathContextSetCache(xmlXPathContextPtr ctxt, 2282 int active, 2283 int value, 2284 int options) 2285 { 2286 if (ctxt == NULL) 2287 return(-1); 2288 if (active) { 2289 xmlXPathContextCachePtr cache; 2290 2291 if (ctxt->cache == NULL) { 2292 ctxt->cache = xmlXPathNewCache(); 2293 if (ctxt->cache == NULL) 2294 return(-1); 2295 } 2296 cache = (xmlXPathContextCachePtr) ctxt->cache; 2297 if (options == 0) { 2298 if (value < 0) 2299 value = 100; 2300 cache->maxNodeset = value; 2301 cache->maxString = value; 2302 cache->maxNumber = value; 2303 cache->maxBoolean = value; 2304 cache->maxMisc = value; 2305 } 2306 } else if (ctxt->cache != NULL) { 2307 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache); 2308 ctxt->cache = NULL; 2309 } 2310 return(0); 2311 } 2312 2313 /** 2314 * xmlXPathCacheWrapNodeSet: 2315 * @ctxt: the XPath context 2316 * @val: the NodePtr value 2317 * 2318 * This is the cached version of xmlXPathWrapNodeSet(). 2319 * Wrap the Nodeset @val in a new xmlXPathObjectPtr 2320 * 2321 * Returns the created or reused object. 2322 */ 2323 static xmlXPathObjectPtr 2324 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val) 2325 { 2326 if ((ctxt != NULL) && (ctxt->cache != NULL)) { 2327 xmlXPathContextCachePtr cache = 2328 (xmlXPathContextCachePtr) ctxt->cache; 2329 2330 if ((cache->miscObjs != NULL) && 2331 (cache->miscObjs->number != 0)) 2332 { 2333 xmlXPathObjectPtr ret; 2334 2335 ret = (xmlXPathObjectPtr) 2336 cache->miscObjs->items[--cache->miscObjs->number]; 2337 ret->type = XPATH_NODESET; 2338 ret->nodesetval = val; 2339 #ifdef XP_DEBUG_OBJ_USAGE 2340 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 2341 #endif 2342 return(ret); 2343 } 2344 } 2345 2346 return(xmlXPathWrapNodeSet(val)); 2347 2348 } 2349 2350 /** 2351 * xmlXPathCacheWrapString: 2352 * @ctxt: the XPath context 2353 * @val: the xmlChar * value 2354 * 2355 * This is the cached version of xmlXPathWrapString(). 2356 * Wraps the @val string into an XPath object. 2357 * 2358 * Returns the created or reused object. 2359 */ 2360 static xmlXPathObjectPtr 2361 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val) 2362 { 2363 if ((ctxt != NULL) && (ctxt->cache != NULL)) { 2364 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2365 2366 if ((cache->stringObjs != NULL) && 2367 (cache->stringObjs->number != 0)) 2368 { 2369 2370 xmlXPathObjectPtr ret; 2371 2372 ret = (xmlXPathObjectPtr) 2373 cache->stringObjs->items[--cache->stringObjs->number]; 2374 ret->type = XPATH_STRING; 2375 ret->stringval = val; 2376 #ifdef XP_DEBUG_OBJ_USAGE 2377 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2378 #endif 2379 return(ret); 2380 } else if ((cache->miscObjs != NULL) && 2381 (cache->miscObjs->number != 0)) 2382 { 2383 xmlXPathObjectPtr ret; 2384 /* 2385 * Fallback to misc-cache. 2386 */ 2387 ret = (xmlXPathObjectPtr) 2388 cache->miscObjs->items[--cache->miscObjs->number]; 2389 2390 ret->type = XPATH_STRING; 2391 ret->stringval = val; 2392 #ifdef XP_DEBUG_OBJ_USAGE 2393 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2394 #endif 2395 return(ret); 2396 } 2397 } 2398 return(xmlXPathWrapString(val)); 2399 } 2400 2401 /** 2402 * xmlXPathCacheNewNodeSet: 2403 * @ctxt: the XPath context 2404 * @val: the NodePtr value 2405 * 2406 * This is the cached version of xmlXPathNewNodeSet(). 2407 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize 2408 * it with the single Node @val 2409 * 2410 * Returns the created or reused object. 2411 */ 2412 static xmlXPathObjectPtr 2413 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val) 2414 { 2415 if ((ctxt != NULL) && (ctxt->cache)) { 2416 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2417 2418 if ((cache->nodesetObjs != NULL) && 2419 (cache->nodesetObjs->number != 0)) 2420 { 2421 xmlXPathObjectPtr ret; 2422 /* 2423 * Use the nodeset-cache. 2424 */ 2425 ret = (xmlXPathObjectPtr) 2426 cache->nodesetObjs->items[--cache->nodesetObjs->number]; 2427 ret->type = XPATH_NODESET; 2428 ret->boolval = 0; 2429 if (val) { 2430 if ((ret->nodesetval->nodeMax == 0) || 2431 (val->type == XML_NAMESPACE_DECL)) 2432 { 2433 /* TODO: Check memory error. */ 2434 xmlXPathNodeSetAddUnique(ret->nodesetval, val); 2435 } else { 2436 ret->nodesetval->nodeTab[0] = val; 2437 ret->nodesetval->nodeNr = 1; 2438 } 2439 } 2440 #ifdef XP_DEBUG_OBJ_USAGE 2441 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 2442 #endif 2443 return(ret); 2444 } else if ((cache->miscObjs != NULL) && 2445 (cache->miscObjs->number != 0)) 2446 { 2447 xmlXPathObjectPtr ret; 2448 /* 2449 * Fallback to misc-cache. 2450 */ 2451 2452 ret = (xmlXPathObjectPtr) 2453 cache->miscObjs->items[--cache->miscObjs->number]; 2454 2455 ret->type = XPATH_NODESET; 2456 ret->boolval = 0; 2457 ret->nodesetval = xmlXPathNodeSetCreate(val); 2458 if (ret->nodesetval == NULL) { 2459 ctxt->lastError.domain = XML_FROM_XPATH; 2460 ctxt->lastError.code = XML_ERR_NO_MEMORY; 2461 return(NULL); 2462 } 2463 #ifdef XP_DEBUG_OBJ_USAGE 2464 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 2465 #endif 2466 return(ret); 2467 } 2468 } 2469 return(xmlXPathNewNodeSet(val)); 2470 } 2471 2472 /** 2473 * xmlXPathCacheNewCString: 2474 * @ctxt: the XPath context 2475 * @val: the char * value 2476 * 2477 * This is the cached version of xmlXPathNewCString(). 2478 * Acquire an xmlXPathObjectPtr of type string and of value @val 2479 * 2480 * Returns the created or reused object. 2481 */ 2482 static xmlXPathObjectPtr 2483 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val) 2484 { 2485 if ((ctxt != NULL) && (ctxt->cache)) { 2486 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2487 2488 if ((cache->stringObjs != NULL) && 2489 (cache->stringObjs->number != 0)) 2490 { 2491 xmlXPathObjectPtr ret; 2492 2493 ret = (xmlXPathObjectPtr) 2494 cache->stringObjs->items[--cache->stringObjs->number]; 2495 2496 ret->type = XPATH_STRING; 2497 ret->stringval = xmlStrdup(BAD_CAST val); 2498 #ifdef XP_DEBUG_OBJ_USAGE 2499 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2500 #endif 2501 return(ret); 2502 } else if ((cache->miscObjs != NULL) && 2503 (cache->miscObjs->number != 0)) 2504 { 2505 xmlXPathObjectPtr ret; 2506 2507 ret = (xmlXPathObjectPtr) 2508 cache->miscObjs->items[--cache->miscObjs->number]; 2509 2510 ret->type = XPATH_STRING; 2511 ret->stringval = xmlStrdup(BAD_CAST val); 2512 #ifdef XP_DEBUG_OBJ_USAGE 2513 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2514 #endif 2515 return(ret); 2516 } 2517 } 2518 return(xmlXPathNewCString(val)); 2519 } 2520 2521 /** 2522 * xmlXPathCacheNewString: 2523 * @ctxt: the XPath context 2524 * @val: the xmlChar * value 2525 * 2526 * This is the cached version of xmlXPathNewString(). 2527 * Acquire an xmlXPathObjectPtr of type string and of value @val 2528 * 2529 * Returns the created or reused object. 2530 */ 2531 static xmlXPathObjectPtr 2532 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val) 2533 { 2534 if ((ctxt != NULL) && (ctxt->cache)) { 2535 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2536 2537 if ((cache->stringObjs != NULL) && 2538 (cache->stringObjs->number != 0)) 2539 { 2540 xmlXPathObjectPtr ret; 2541 2542 ret = (xmlXPathObjectPtr) 2543 cache->stringObjs->items[--cache->stringObjs->number]; 2544 ret->type = XPATH_STRING; 2545 if (val != NULL) 2546 ret->stringval = xmlStrdup(val); 2547 else 2548 ret->stringval = xmlStrdup((const xmlChar *)""); 2549 #ifdef XP_DEBUG_OBJ_USAGE 2550 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2551 #endif 2552 return(ret); 2553 } else if ((cache->miscObjs != NULL) && 2554 (cache->miscObjs->number != 0)) 2555 { 2556 xmlXPathObjectPtr ret; 2557 2558 ret = (xmlXPathObjectPtr) 2559 cache->miscObjs->items[--cache->miscObjs->number]; 2560 2561 ret->type = XPATH_STRING; 2562 if (val != NULL) 2563 ret->stringval = xmlStrdup(val); 2564 else 2565 ret->stringval = xmlStrdup((const xmlChar *)""); 2566 #ifdef XP_DEBUG_OBJ_USAGE 2567 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2568 #endif 2569 return(ret); 2570 } 2571 } 2572 return(xmlXPathNewString(val)); 2573 } 2574 2575 /** 2576 * xmlXPathCacheNewBoolean: 2577 * @ctxt: the XPath context 2578 * @val: the boolean value 2579 * 2580 * This is the cached version of xmlXPathNewBoolean(). 2581 * Acquires an xmlXPathObjectPtr of type boolean and of value @val 2582 * 2583 * Returns the created or reused object. 2584 */ 2585 static xmlXPathObjectPtr 2586 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val) 2587 { 2588 if ((ctxt != NULL) && (ctxt->cache)) { 2589 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2590 2591 if ((cache->booleanObjs != NULL) && 2592 (cache->booleanObjs->number != 0)) 2593 { 2594 xmlXPathObjectPtr ret; 2595 2596 ret = (xmlXPathObjectPtr) 2597 cache->booleanObjs->items[--cache->booleanObjs->number]; 2598 ret->type = XPATH_BOOLEAN; 2599 ret->boolval = (val != 0); 2600 #ifdef XP_DEBUG_OBJ_USAGE 2601 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN); 2602 #endif 2603 return(ret); 2604 } else if ((cache->miscObjs != NULL) && 2605 (cache->miscObjs->number != 0)) 2606 { 2607 xmlXPathObjectPtr ret; 2608 2609 ret = (xmlXPathObjectPtr) 2610 cache->miscObjs->items[--cache->miscObjs->number]; 2611 2612 ret->type = XPATH_BOOLEAN; 2613 ret->boolval = (val != 0); 2614 #ifdef XP_DEBUG_OBJ_USAGE 2615 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN); 2616 #endif 2617 return(ret); 2618 } 2619 } 2620 return(xmlXPathNewBoolean(val)); 2621 } 2622 2623 /** 2624 * xmlXPathCacheNewFloat: 2625 * @ctxt: the XPath context 2626 * @val: the double value 2627 * 2628 * This is the cached version of xmlXPathNewFloat(). 2629 * Acquires an xmlXPathObjectPtr of type double and of value @val 2630 * 2631 * Returns the created or reused object. 2632 */ 2633 static xmlXPathObjectPtr 2634 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val) 2635 { 2636 if ((ctxt != NULL) && (ctxt->cache)) { 2637 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2638 2639 if ((cache->numberObjs != NULL) && 2640 (cache->numberObjs->number != 0)) 2641 { 2642 xmlXPathObjectPtr ret; 2643 2644 ret = (xmlXPathObjectPtr) 2645 cache->numberObjs->items[--cache->numberObjs->number]; 2646 ret->type = XPATH_NUMBER; 2647 ret->floatval = val; 2648 #ifdef XP_DEBUG_OBJ_USAGE 2649 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER); 2650 #endif 2651 return(ret); 2652 } else if ((cache->miscObjs != NULL) && 2653 (cache->miscObjs->number != 0)) 2654 { 2655 xmlXPathObjectPtr ret; 2656 2657 ret = (xmlXPathObjectPtr) 2658 cache->miscObjs->items[--cache->miscObjs->number]; 2659 2660 ret->type = XPATH_NUMBER; 2661 ret->floatval = val; 2662 #ifdef XP_DEBUG_OBJ_USAGE 2663 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER); 2664 #endif 2665 return(ret); 2666 } 2667 } 2668 return(xmlXPathNewFloat(val)); 2669 } 2670 2671 /** 2672 * xmlXPathCacheConvertString: 2673 * @ctxt: the XPath context 2674 * @val: an XPath object 2675 * 2676 * This is the cached version of xmlXPathConvertString(). 2677 * Converts an existing object to its string() equivalent 2678 * 2679 * Returns a created or reused object, the old one is freed (cached) 2680 * (or the operation is done directly on @val) 2681 */ 2682 2683 static xmlXPathObjectPtr 2684 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 2685 xmlChar *res = NULL; 2686 2687 if (val == NULL) 2688 return(xmlXPathCacheNewCString(ctxt, "")); 2689 2690 switch (val->type) { 2691 case XPATH_UNDEFINED: 2692 #ifdef DEBUG_EXPR 2693 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n"); 2694 #endif 2695 break; 2696 case XPATH_NODESET: 2697 case XPATH_XSLT_TREE: 2698 res = xmlXPathCastNodeSetToString(val->nodesetval); 2699 break; 2700 case XPATH_STRING: 2701 return(val); 2702 case XPATH_BOOLEAN: 2703 res = xmlXPathCastBooleanToString(val->boolval); 2704 break; 2705 case XPATH_NUMBER: 2706 res = xmlXPathCastNumberToString(val->floatval); 2707 break; 2708 case XPATH_USERS: 2709 case XPATH_POINT: 2710 case XPATH_RANGE: 2711 case XPATH_LOCATIONSET: 2712 TODO; 2713 break; 2714 } 2715 xmlXPathReleaseObject(ctxt, val); 2716 if (res == NULL) 2717 return(xmlXPathCacheNewCString(ctxt, "")); 2718 return(xmlXPathCacheWrapString(ctxt, res)); 2719 } 2720 2721 /** 2722 * xmlXPathCacheObjectCopy: 2723 * @ctxt: the XPath context 2724 * @val: the original object 2725 * 2726 * This is the cached version of xmlXPathObjectCopy(). 2727 * Acquire a copy of a given object 2728 * 2729 * Returns a created or reused created object. 2730 */ 2731 static xmlXPathObjectPtr 2732 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) 2733 { 2734 if (val == NULL) 2735 return(NULL); 2736 2737 if (XP_HAS_CACHE(ctxt)) { 2738 switch (val->type) { 2739 case XPATH_NODESET: 2740 return(xmlXPathCacheWrapNodeSet(ctxt, 2741 xmlXPathNodeSetMerge(NULL, val->nodesetval))); 2742 case XPATH_STRING: 2743 return(xmlXPathCacheNewString(ctxt, val->stringval)); 2744 case XPATH_BOOLEAN: 2745 return(xmlXPathCacheNewBoolean(ctxt, val->boolval)); 2746 case XPATH_NUMBER: 2747 return(xmlXPathCacheNewFloat(ctxt, val->floatval)); 2748 default: 2749 break; 2750 } 2751 } 2752 return(xmlXPathObjectCopy(val)); 2753 } 2754 2755 /** 2756 * xmlXPathCacheConvertBoolean: 2757 * @ctxt: the XPath context 2758 * @val: an XPath object 2759 * 2760 * This is the cached version of xmlXPathConvertBoolean(). 2761 * Converts an existing object to its boolean() equivalent 2762 * 2763 * Returns a created or reused object, the old one is freed (or the operation 2764 * is done directly on @val) 2765 */ 2766 static xmlXPathObjectPtr 2767 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 2768 xmlXPathObjectPtr ret; 2769 2770 if (val == NULL) 2771 return(xmlXPathCacheNewBoolean(ctxt, 0)); 2772 if (val->type == XPATH_BOOLEAN) 2773 return(val); 2774 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val)); 2775 xmlXPathReleaseObject(ctxt, val); 2776 return(ret); 2777 } 2778 2779 /** 2780 * xmlXPathCacheConvertNumber: 2781 * @ctxt: the XPath context 2782 * @val: an XPath object 2783 * 2784 * This is the cached version of xmlXPathConvertNumber(). 2785 * Converts an existing object to its number() equivalent 2786 * 2787 * Returns a created or reused object, the old one is freed (or the operation 2788 * is done directly on @val) 2789 */ 2790 static xmlXPathObjectPtr 2791 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 2792 xmlXPathObjectPtr ret; 2793 2794 if (val == NULL) 2795 return(xmlXPathCacheNewFloat(ctxt, 0.0)); 2796 if (val->type == XPATH_NUMBER) 2797 return(val); 2798 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val)); 2799 xmlXPathReleaseObject(ctxt, val); 2800 return(ret); 2801 } 2802 2803 /************************************************************************ 2804 * * 2805 * Parser stacks related functions and macros * 2806 * * 2807 ************************************************************************/ 2808 2809 /** 2810 * xmlXPathSetFrame: 2811 * @ctxt: an XPath parser context 2812 * 2813 * Set the callee evaluation frame 2814 * 2815 * Returns the previous frame value to be restored once done 2816 */ 2817 static int 2818 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) { 2819 int ret; 2820 2821 if (ctxt == NULL) 2822 return(0); 2823 ret = ctxt->valueFrame; 2824 ctxt->valueFrame = ctxt->valueNr; 2825 return(ret); 2826 } 2827 2828 /** 2829 * xmlXPathPopFrame: 2830 * @ctxt: an XPath parser context 2831 * @frame: the previous frame value 2832 * 2833 * Remove the callee evaluation frame 2834 */ 2835 static void 2836 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) { 2837 if (ctxt == NULL) 2838 return; 2839 if (ctxt->valueNr < ctxt->valueFrame) { 2840 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR); 2841 } 2842 ctxt->valueFrame = frame; 2843 } 2844 2845 /** 2846 * valuePop: 2847 * @ctxt: an XPath evaluation context 2848 * 2849 * Pops the top XPath object from the value stack 2850 * 2851 * Returns the XPath object just removed 2852 */ 2853 xmlXPathObjectPtr 2854 valuePop(xmlXPathParserContextPtr ctxt) 2855 { 2856 xmlXPathObjectPtr ret; 2857 2858 if ((ctxt == NULL) || (ctxt->valueNr <= 0)) 2859 return (NULL); 2860 2861 if (ctxt->valueNr <= ctxt->valueFrame) { 2862 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR); 2863 return (NULL); 2864 } 2865 2866 ctxt->valueNr--; 2867 if (ctxt->valueNr > 0) 2868 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1]; 2869 else 2870 ctxt->value = NULL; 2871 ret = ctxt->valueTab[ctxt->valueNr]; 2872 ctxt->valueTab[ctxt->valueNr] = NULL; 2873 return (ret); 2874 } 2875 /** 2876 * valuePush: 2877 * @ctxt: an XPath evaluation context 2878 * @value: the XPath object 2879 * 2880 * Pushes a new XPath object on top of the value stack. If value is NULL, 2881 * a memory error is recorded in the parser context. 2882 * 2883 * Returns the number of items on the value stack, or -1 in case of error. 2884 */ 2885 int 2886 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value) 2887 { 2888 if (ctxt == NULL) return(-1); 2889 if (value == NULL) { 2890 /* 2891 * A NULL value typically indicates that a memory allocation failed, 2892 * so we set ctxt->error here to propagate the error. 2893 */ 2894 ctxt->error = XPATH_MEMORY_ERROR; 2895 return(-1); 2896 } 2897 if (ctxt->valueNr >= ctxt->valueMax) { 2898 xmlXPathObjectPtr *tmp; 2899 2900 if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) { 2901 xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n"); 2902 return (-1); 2903 } 2904 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab, 2905 2 * ctxt->valueMax * 2906 sizeof(ctxt->valueTab[0])); 2907 if (tmp == NULL) { 2908 xmlXPathPErrMemory(ctxt, "pushing value\n"); 2909 return (-1); 2910 } 2911 ctxt->valueMax *= 2; 2912 ctxt->valueTab = tmp; 2913 } 2914 ctxt->valueTab[ctxt->valueNr] = value; 2915 ctxt->value = value; 2916 return (ctxt->valueNr++); 2917 } 2918 2919 /** 2920 * xmlXPathPopBoolean: 2921 * @ctxt: an XPath parser context 2922 * 2923 * Pops a boolean from the stack, handling conversion if needed. 2924 * Check error with #xmlXPathCheckError. 2925 * 2926 * Returns the boolean 2927 */ 2928 int 2929 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) { 2930 xmlXPathObjectPtr obj; 2931 int ret; 2932 2933 obj = valuePop(ctxt); 2934 if (obj == NULL) { 2935 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2936 return(0); 2937 } 2938 if (obj->type != XPATH_BOOLEAN) 2939 ret = xmlXPathCastToBoolean(obj); 2940 else 2941 ret = obj->boolval; 2942 xmlXPathReleaseObject(ctxt->context, obj); 2943 return(ret); 2944 } 2945 2946 /** 2947 * xmlXPathPopNumber: 2948 * @ctxt: an XPath parser context 2949 * 2950 * Pops a number from the stack, handling conversion if needed. 2951 * Check error with #xmlXPathCheckError. 2952 * 2953 * Returns the number 2954 */ 2955 double 2956 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) { 2957 xmlXPathObjectPtr obj; 2958 double ret; 2959 2960 obj = valuePop(ctxt); 2961 if (obj == NULL) { 2962 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2963 return(0); 2964 } 2965 if (obj->type != XPATH_NUMBER) 2966 ret = xmlXPathCastToNumber(obj); 2967 else 2968 ret = obj->floatval; 2969 xmlXPathReleaseObject(ctxt->context, obj); 2970 return(ret); 2971 } 2972 2973 /** 2974 * xmlXPathPopString: 2975 * @ctxt: an XPath parser context 2976 * 2977 * Pops a string from the stack, handling conversion if needed. 2978 * Check error with #xmlXPathCheckError. 2979 * 2980 * Returns the string 2981 */ 2982 xmlChar * 2983 xmlXPathPopString (xmlXPathParserContextPtr ctxt) { 2984 xmlXPathObjectPtr obj; 2985 xmlChar * ret; 2986 2987 obj = valuePop(ctxt); 2988 if (obj == NULL) { 2989 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2990 return(NULL); 2991 } 2992 ret = xmlXPathCastToString(obj); /* this does required strdup */ 2993 /* TODO: needs refactoring somewhere else */ 2994 if (obj->stringval == ret) 2995 obj->stringval = NULL; 2996 xmlXPathReleaseObject(ctxt->context, obj); 2997 return(ret); 2998 } 2999 3000 /** 3001 * xmlXPathPopNodeSet: 3002 * @ctxt: an XPath parser context 3003 * 3004 * Pops a node-set from the stack, handling conversion if needed. 3005 * Check error with #xmlXPathCheckError. 3006 * 3007 * Returns the node-set 3008 */ 3009 xmlNodeSetPtr 3010 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) { 3011 xmlXPathObjectPtr obj; 3012 xmlNodeSetPtr ret; 3013 3014 if (ctxt == NULL) return(NULL); 3015 if (ctxt->value == NULL) { 3016 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 3017 return(NULL); 3018 } 3019 if (!xmlXPathStackIsNodeSet(ctxt)) { 3020 xmlXPathSetTypeError(ctxt); 3021 return(NULL); 3022 } 3023 obj = valuePop(ctxt); 3024 ret = obj->nodesetval; 3025 #if 0 3026 /* to fix memory leak of not clearing obj->user */ 3027 if (obj->boolval && obj->user != NULL) 3028 xmlFreeNodeList((xmlNodePtr) obj->user); 3029 #endif 3030 obj->nodesetval = NULL; 3031 xmlXPathReleaseObject(ctxt->context, obj); 3032 return(ret); 3033 } 3034 3035 /** 3036 * xmlXPathPopExternal: 3037 * @ctxt: an XPath parser context 3038 * 3039 * Pops an external object from the stack, handling conversion if needed. 3040 * Check error with #xmlXPathCheckError. 3041 * 3042 * Returns the object 3043 */ 3044 void * 3045 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) { 3046 xmlXPathObjectPtr obj; 3047 void * ret; 3048 3049 if ((ctxt == NULL) || (ctxt->value == NULL)) { 3050 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 3051 return(NULL); 3052 } 3053 if (ctxt->value->type != XPATH_USERS) { 3054 xmlXPathSetTypeError(ctxt); 3055 return(NULL); 3056 } 3057 obj = valuePop(ctxt); 3058 ret = obj->user; 3059 obj->user = NULL; 3060 xmlXPathReleaseObject(ctxt->context, obj); 3061 return(ret); 3062 } 3063 3064 /* 3065 * Macros for accessing the content. Those should be used only by the parser, 3066 * and not exported. 3067 * 3068 * Dirty macros, i.e. one need to make assumption on the context to use them 3069 * 3070 * CUR_PTR return the current pointer to the xmlChar to be parsed. 3071 * CUR returns the current xmlChar value, i.e. a 8 bit value 3072 * in ISO-Latin or UTF-8. 3073 * This should be used internally by the parser 3074 * only to compare to ASCII values otherwise it would break when 3075 * running with UTF-8 encoding. 3076 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only 3077 * to compare on ASCII based substring. 3078 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined 3079 * strings within the parser. 3080 * CURRENT Returns the current char value, with the full decoding of 3081 * UTF-8 if we are using this mode. It returns an int. 3082 * NEXT Skip to the next character, this does the proper decoding 3083 * in UTF-8 mode. It also pop-up unfinished entities on the fly. 3084 * It returns the pointer to the current xmlChar. 3085 */ 3086 3087 #define CUR (*ctxt->cur) 3088 #define SKIP(val) ctxt->cur += (val) 3089 #define NXT(val) ctxt->cur[(val)] 3090 #define CUR_PTR ctxt->cur 3091 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l) 3092 3093 #define COPY_BUF(l,b,i,v) \ 3094 if (l == 1) b[i++] = (xmlChar) v; \ 3095 else i += xmlCopyChar(l,&b[i],v) 3096 3097 #define NEXTL(l) ctxt->cur += l 3098 3099 #define SKIP_BLANKS \ 3100 while (IS_BLANK_CH(*(ctxt->cur))) NEXT 3101 3102 #define CURRENT (*ctxt->cur) 3103 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur) 3104 3105 3106 #ifndef DBL_DIG 3107 #define DBL_DIG 16 3108 #endif 3109 #ifndef DBL_EPSILON 3110 #define DBL_EPSILON 1E-9 3111 #endif 3112 3113 #define UPPER_DOUBLE 1E9 3114 #define LOWER_DOUBLE 1E-5 3115 #define LOWER_DOUBLE_EXP 5 3116 3117 #define INTEGER_DIGITS DBL_DIG 3118 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP)) 3119 #define EXPONENT_DIGITS (3 + 2) 3120 3121 /** 3122 * xmlXPathFormatNumber: 3123 * @number: number to format 3124 * @buffer: output buffer 3125 * @buffersize: size of output buffer 3126 * 3127 * Convert the number into a string representation. 3128 */ 3129 static void 3130 xmlXPathFormatNumber(double number, char buffer[], int buffersize) 3131 { 3132 switch (xmlXPathIsInf(number)) { 3133 case 1: 3134 if (buffersize > (int)sizeof("Infinity")) 3135 snprintf(buffer, buffersize, "Infinity"); 3136 break; 3137 case -1: 3138 if (buffersize > (int)sizeof("-Infinity")) 3139 snprintf(buffer, buffersize, "-Infinity"); 3140 break; 3141 default: 3142 if (xmlXPathIsNaN(number)) { 3143 if (buffersize > (int)sizeof("NaN")) 3144 snprintf(buffer, buffersize, "NaN"); 3145 } else if (number == 0) { 3146 /* Omit sign for negative zero. */ 3147 snprintf(buffer, buffersize, "0"); 3148 } else if ((number > INT_MIN) && (number < INT_MAX) && 3149 (number == (int) number)) { 3150 char work[30]; 3151 char *ptr, *cur; 3152 int value = (int) number; 3153 3154 ptr = &buffer[0]; 3155 if (value == 0) { 3156 *ptr++ = '0'; 3157 } else { 3158 snprintf(work, 29, "%d", value); 3159 cur = &work[0]; 3160 while ((*cur) && (ptr - buffer < buffersize)) { 3161 *ptr++ = *cur++; 3162 } 3163 } 3164 if (ptr - buffer < buffersize) { 3165 *ptr = 0; 3166 } else if (buffersize > 0) { 3167 ptr--; 3168 *ptr = 0; 3169 } 3170 } else { 3171 /* 3172 For the dimension of work, 3173 DBL_DIG is number of significant digits 3174 EXPONENT is only needed for "scientific notation" 3175 3 is sign, decimal point, and terminating zero 3176 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction 3177 Note that this dimension is slightly (a few characters) 3178 larger than actually necessary. 3179 */ 3180 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP]; 3181 int integer_place, fraction_place; 3182 char *ptr; 3183 char *after_fraction; 3184 double absolute_value; 3185 int size; 3186 3187 absolute_value = fabs(number); 3188 3189 /* 3190 * First choose format - scientific or regular floating point. 3191 * In either case, result is in work, and after_fraction points 3192 * just past the fractional part. 3193 */ 3194 if ( ((absolute_value > UPPER_DOUBLE) || 3195 (absolute_value < LOWER_DOUBLE)) && 3196 (absolute_value != 0.0) ) { 3197 /* Use scientific notation */ 3198 integer_place = DBL_DIG + EXPONENT_DIGITS + 1; 3199 fraction_place = DBL_DIG - 1; 3200 size = snprintf(work, sizeof(work),"%*.*e", 3201 integer_place, fraction_place, number); 3202 while ((size > 0) && (work[size] != 'e')) size--; 3203 3204 } 3205 else { 3206 /* Use regular notation */ 3207 if (absolute_value > 0.0) { 3208 integer_place = (int)log10(absolute_value); 3209 if (integer_place > 0) 3210 fraction_place = DBL_DIG - integer_place - 1; 3211 else 3212 fraction_place = DBL_DIG - integer_place; 3213 } else { 3214 fraction_place = 1; 3215 } 3216 size = snprintf(work, sizeof(work), "%0.*f", 3217 fraction_place, number); 3218 } 3219 3220 /* Remove leading spaces sometimes inserted by snprintf */ 3221 while (work[0] == ' ') { 3222 for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++); 3223 size--; 3224 } 3225 3226 /* Remove fractional trailing zeroes */ 3227 after_fraction = work + size; 3228 ptr = after_fraction; 3229 while (*(--ptr) == '0') 3230 ; 3231 if (*ptr != '.') 3232 ptr++; 3233 while ((*ptr++ = *after_fraction++) != 0); 3234 3235 /* Finally copy result back to caller */ 3236 size = strlen(work) + 1; 3237 if (size > buffersize) { 3238 work[buffersize - 1] = 0; 3239 size = buffersize; 3240 } 3241 memmove(buffer, work, size); 3242 } 3243 break; 3244 } 3245 } 3246 3247 3248 /************************************************************************ 3249 * * 3250 * Routines to handle NodeSets * 3251 * * 3252 ************************************************************************/ 3253 3254 /** 3255 * xmlXPathOrderDocElems: 3256 * @doc: an input document 3257 * 3258 * Call this routine to speed up XPath computation on static documents. 3259 * This stamps all the element nodes with the document order 3260 * Like for line information, the order is kept in the element->content 3261 * field, the value stored is actually - the node number (starting at -1) 3262 * to be able to differentiate from line numbers. 3263 * 3264 * Returns the number of elements found in the document or -1 in case 3265 * of error. 3266 */ 3267 long 3268 xmlXPathOrderDocElems(xmlDocPtr doc) { 3269 ptrdiff_t count = 0; 3270 xmlNodePtr cur; 3271 3272 if (doc == NULL) 3273 return(-1); 3274 cur = doc->children; 3275 while (cur != NULL) { 3276 if (cur->type == XML_ELEMENT_NODE) { 3277 cur->content = (void *) (-(++count)); 3278 if (cur->children != NULL) { 3279 cur = cur->children; 3280 continue; 3281 } 3282 } 3283 if (cur->next != NULL) { 3284 cur = cur->next; 3285 continue; 3286 } 3287 do { 3288 cur = cur->parent; 3289 if (cur == NULL) 3290 break; 3291 if (cur == (xmlNodePtr) doc) { 3292 cur = NULL; 3293 break; 3294 } 3295 if (cur->next != NULL) { 3296 cur = cur->next; 3297 break; 3298 } 3299 } while (cur != NULL); 3300 } 3301 return((long) count); 3302 } 3303 3304 /** 3305 * xmlXPathCmpNodes: 3306 * @node1: the first node 3307 * @node2: the second node 3308 * 3309 * Compare two nodes w.r.t document order 3310 * 3311 * Returns -2 in case of error 1 if first point < second point, 0 if 3312 * it's the same node, -1 otherwise 3313 */ 3314 int 3315 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) { 3316 int depth1, depth2; 3317 int attr1 = 0, attr2 = 0; 3318 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL; 3319 xmlNodePtr cur, root; 3320 3321 if ((node1 == NULL) || (node2 == NULL)) 3322 return(-2); 3323 /* 3324 * a couple of optimizations which will avoid computations in most cases 3325 */ 3326 if (node1 == node2) /* trivial case */ 3327 return(0); 3328 if (node1->type == XML_ATTRIBUTE_NODE) { 3329 attr1 = 1; 3330 attrNode1 = node1; 3331 node1 = node1->parent; 3332 } 3333 if (node2->type == XML_ATTRIBUTE_NODE) { 3334 attr2 = 1; 3335 attrNode2 = node2; 3336 node2 = node2->parent; 3337 } 3338 if (node1 == node2) { 3339 if (attr1 == attr2) { 3340 /* not required, but we keep attributes in order */ 3341 if (attr1 != 0) { 3342 cur = attrNode2->prev; 3343 while (cur != NULL) { 3344 if (cur == attrNode1) 3345 return (1); 3346 cur = cur->prev; 3347 } 3348 return (-1); 3349 } 3350 return(0); 3351 } 3352 if (attr2 == 1) 3353 return(1); 3354 return(-1); 3355 } 3356 if ((node1->type == XML_NAMESPACE_DECL) || 3357 (node2->type == XML_NAMESPACE_DECL)) 3358 return(1); 3359 if (node1 == node2->prev) 3360 return(1); 3361 if (node1 == node2->next) 3362 return(-1); 3363 3364 /* 3365 * Speedup using document order if available. 3366 */ 3367 if ((node1->type == XML_ELEMENT_NODE) && 3368 (node2->type == XML_ELEMENT_NODE) && 3369 (0 > (ptrdiff_t) node1->content) && 3370 (0 > (ptrdiff_t) node2->content) && 3371 (node1->doc == node2->doc)) { 3372 ptrdiff_t l1, l2; 3373 3374 l1 = -((ptrdiff_t) node1->content); 3375 l2 = -((ptrdiff_t) node2->content); 3376 if (l1 < l2) 3377 return(1); 3378 if (l1 > l2) 3379 return(-1); 3380 } 3381 3382 /* 3383 * compute depth to root 3384 */ 3385 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) { 3386 if (cur->parent == node1) 3387 return(1); 3388 depth2++; 3389 } 3390 root = cur; 3391 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) { 3392 if (cur->parent == node2) 3393 return(-1); 3394 depth1++; 3395 } 3396 /* 3397 * Distinct document (or distinct entities :-( ) case. 3398 */ 3399 if (root != cur) { 3400 return(-2); 3401 } 3402 /* 3403 * get the nearest common ancestor. 3404 */ 3405 while (depth1 > depth2) { 3406 depth1--; 3407 node1 = node1->parent; 3408 } 3409 while (depth2 > depth1) { 3410 depth2--; 3411 node2 = node2->parent; 3412 } 3413 while (node1->parent != node2->parent) { 3414 node1 = node1->parent; 3415 node2 = node2->parent; 3416 /* should not happen but just in case ... */ 3417 if ((node1 == NULL) || (node2 == NULL)) 3418 return(-2); 3419 } 3420 /* 3421 * Find who's first. 3422 */ 3423 if (node1 == node2->prev) 3424 return(1); 3425 if (node1 == node2->next) 3426 return(-1); 3427 /* 3428 * Speedup using document order if available. 3429 */ 3430 if ((node1->type == XML_ELEMENT_NODE) && 3431 (node2->type == XML_ELEMENT_NODE) && 3432 (0 > (ptrdiff_t) node1->content) && 3433 (0 > (ptrdiff_t) node2->content) && 3434 (node1->doc == node2->doc)) { 3435 ptrdiff_t l1, l2; 3436 3437 l1 = -((ptrdiff_t) node1->content); 3438 l2 = -((ptrdiff_t) node2->content); 3439 if (l1 < l2) 3440 return(1); 3441 if (l1 > l2) 3442 return(-1); 3443 } 3444 3445 for (cur = node1->next;cur != NULL;cur = cur->next) 3446 if (cur == node2) 3447 return(1); 3448 return(-1); /* assume there is no sibling list corruption */ 3449 } 3450 3451 /** 3452 * xmlXPathNodeSetSort: 3453 * @set: the node set 3454 * 3455 * Sort the node set in document order 3456 */ 3457 void 3458 xmlXPathNodeSetSort(xmlNodeSetPtr set) { 3459 #ifndef WITH_TIM_SORT 3460 int i, j, incr, len; 3461 xmlNodePtr tmp; 3462 #endif 3463 3464 if (set == NULL) 3465 return; 3466 3467 #ifndef WITH_TIM_SORT 3468 /* 3469 * Use the old Shell's sort implementation to sort the node-set 3470 * Timsort ought to be quite faster 3471 */ 3472 len = set->nodeNr; 3473 for (incr = len / 2; incr > 0; incr /= 2) { 3474 for (i = incr; i < len; i++) { 3475 j = i - incr; 3476 while (j >= 0) { 3477 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 3478 if (xmlXPathCmpNodesExt(set->nodeTab[j], 3479 set->nodeTab[j + incr]) == -1) 3480 #else 3481 if (xmlXPathCmpNodes(set->nodeTab[j], 3482 set->nodeTab[j + incr]) == -1) 3483 #endif 3484 { 3485 tmp = set->nodeTab[j]; 3486 set->nodeTab[j] = set->nodeTab[j + incr]; 3487 set->nodeTab[j + incr] = tmp; 3488 j -= incr; 3489 } else 3490 break; 3491 } 3492 } 3493 } 3494 #else /* WITH_TIM_SORT */ 3495 libxml_domnode_tim_sort(set->nodeTab, set->nodeNr); 3496 #endif /* WITH_TIM_SORT */ 3497 } 3498 3499 #define XML_NODESET_DEFAULT 10 3500 /** 3501 * xmlXPathNodeSetDupNs: 3502 * @node: the parent node of the namespace XPath node 3503 * @ns: the libxml namespace declaration node. 3504 * 3505 * Namespace node in libxml don't match the XPath semantic. In a node set 3506 * the namespace nodes are duplicated and the next pointer is set to the 3507 * parent node in the XPath semantic. 3508 * 3509 * Returns the newly created object. 3510 */ 3511 static xmlNodePtr 3512 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) { 3513 xmlNsPtr cur; 3514 3515 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) 3516 return(NULL); 3517 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) 3518 return((xmlNodePtr) ns); 3519 3520 /* 3521 * Allocate a new Namespace and fill the fields. 3522 */ 3523 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); 3524 if (cur == NULL) { 3525 xmlXPathErrMemory(NULL, "duplicating namespace\n"); 3526 return(NULL); 3527 } 3528 memset(cur, 0, sizeof(xmlNs)); 3529 cur->type = XML_NAMESPACE_DECL; 3530 if (ns->href != NULL) 3531 cur->href = xmlStrdup(ns->href); 3532 if (ns->prefix != NULL) 3533 cur->prefix = xmlStrdup(ns->prefix); 3534 cur->next = (xmlNsPtr) node; 3535 return((xmlNodePtr) cur); 3536 } 3537 3538 /** 3539 * xmlXPathNodeSetFreeNs: 3540 * @ns: the XPath namespace node found in a nodeset. 3541 * 3542 * Namespace nodes in libxml don't match the XPath semantic. In a node set 3543 * the namespace nodes are duplicated and the next pointer is set to the 3544 * parent node in the XPath semantic. Check if such a node needs to be freed 3545 */ 3546 void 3547 xmlXPathNodeSetFreeNs(xmlNsPtr ns) { 3548 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) 3549 return; 3550 3551 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) { 3552 if (ns->href != NULL) 3553 xmlFree((xmlChar *)ns->href); 3554 if (ns->prefix != NULL) 3555 xmlFree((xmlChar *)ns->prefix); 3556 xmlFree(ns); 3557 } 3558 } 3559 3560 /** 3561 * xmlXPathNodeSetCreate: 3562 * @val: an initial xmlNodePtr, or NULL 3563 * 3564 * Create a new xmlNodeSetPtr of type double and of value @val 3565 * 3566 * Returns the newly created object. 3567 */ 3568 xmlNodeSetPtr 3569 xmlXPathNodeSetCreate(xmlNodePtr val) { 3570 xmlNodeSetPtr ret; 3571 3572 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet)); 3573 if (ret == NULL) { 3574 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3575 return(NULL); 3576 } 3577 memset(ret, 0 , (size_t) sizeof(xmlNodeSet)); 3578 if (val != NULL) { 3579 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3580 sizeof(xmlNodePtr)); 3581 if (ret->nodeTab == NULL) { 3582 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3583 xmlFree(ret); 3584 return(NULL); 3585 } 3586 memset(ret->nodeTab, 0 , 3587 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3588 ret->nodeMax = XML_NODESET_DEFAULT; 3589 if (val->type == XML_NAMESPACE_DECL) { 3590 xmlNsPtr ns = (xmlNsPtr) val; 3591 3592 /* TODO: Check memory error. */ 3593 ret->nodeTab[ret->nodeNr++] = 3594 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3595 } else 3596 ret->nodeTab[ret->nodeNr++] = val; 3597 } 3598 return(ret); 3599 } 3600 3601 /** 3602 * xmlXPathNodeSetContains: 3603 * @cur: the node-set 3604 * @val: the node 3605 * 3606 * checks whether @cur contains @val 3607 * 3608 * Returns true (1) if @cur contains @val, false (0) otherwise 3609 */ 3610 int 3611 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) { 3612 int i; 3613 3614 if ((cur == NULL) || (val == NULL)) return(0); 3615 if (val->type == XML_NAMESPACE_DECL) { 3616 for (i = 0; i < cur->nodeNr; i++) { 3617 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) { 3618 xmlNsPtr ns1, ns2; 3619 3620 ns1 = (xmlNsPtr) val; 3621 ns2 = (xmlNsPtr) cur->nodeTab[i]; 3622 if (ns1 == ns2) 3623 return(1); 3624 if ((ns1->next != NULL) && (ns2->next == ns1->next) && 3625 (xmlStrEqual(ns1->prefix, ns2->prefix))) 3626 return(1); 3627 } 3628 } 3629 } else { 3630 for (i = 0; i < cur->nodeNr; i++) { 3631 if (cur->nodeTab[i] == val) 3632 return(1); 3633 } 3634 } 3635 return(0); 3636 } 3637 3638 /** 3639 * xmlXPathNodeSetAddNs: 3640 * @cur: the initial node set 3641 * @node: the hosting node 3642 * @ns: a the namespace node 3643 * 3644 * add a new namespace node to an existing NodeSet 3645 * 3646 * Returns 0 in case of success and -1 in case of error 3647 */ 3648 int 3649 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) { 3650 int i; 3651 3652 3653 if ((cur == NULL) || (ns == NULL) || (node == NULL) || 3654 (ns->type != XML_NAMESPACE_DECL) || 3655 (node->type != XML_ELEMENT_NODE)) 3656 return(-1); 3657 3658 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3659 /* 3660 * prevent duplicates 3661 */ 3662 for (i = 0;i < cur->nodeNr;i++) { 3663 if ((cur->nodeTab[i] != NULL) && 3664 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) && 3665 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) && 3666 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix))) 3667 return(0); 3668 } 3669 3670 /* 3671 * grow the nodeTab if needed 3672 */ 3673 if (cur->nodeMax == 0) { 3674 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3675 sizeof(xmlNodePtr)); 3676 if (cur->nodeTab == NULL) { 3677 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3678 return(-1); 3679 } 3680 memset(cur->nodeTab, 0 , 3681 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3682 cur->nodeMax = XML_NODESET_DEFAULT; 3683 } else if (cur->nodeNr == cur->nodeMax) { 3684 xmlNodePtr *temp; 3685 3686 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 3687 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n"); 3688 return(-1); 3689 } 3690 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 * 3691 sizeof(xmlNodePtr)); 3692 if (temp == NULL) { 3693 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3694 return(-1); 3695 } 3696 cur->nodeMax *= 2; 3697 cur->nodeTab = temp; 3698 } 3699 /* TODO: Check memory error. */ 3700 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns); 3701 return(0); 3702 } 3703 3704 /** 3705 * xmlXPathNodeSetAdd: 3706 * @cur: the initial node set 3707 * @val: a new xmlNodePtr 3708 * 3709 * add a new xmlNodePtr to an existing NodeSet 3710 * 3711 * Returns 0 in case of success, and -1 in case of error 3712 */ 3713 int 3714 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) { 3715 int i; 3716 3717 if ((cur == NULL) || (val == NULL)) return(-1); 3718 3719 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3720 /* 3721 * prevent duplicates 3722 */ 3723 for (i = 0;i < cur->nodeNr;i++) 3724 if (cur->nodeTab[i] == val) return(0); 3725 3726 /* 3727 * grow the nodeTab if needed 3728 */ 3729 if (cur->nodeMax == 0) { 3730 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3731 sizeof(xmlNodePtr)); 3732 if (cur->nodeTab == NULL) { 3733 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3734 return(-1); 3735 } 3736 memset(cur->nodeTab, 0 , 3737 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3738 cur->nodeMax = XML_NODESET_DEFAULT; 3739 } else if (cur->nodeNr == cur->nodeMax) { 3740 xmlNodePtr *temp; 3741 3742 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 3743 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n"); 3744 return(-1); 3745 } 3746 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 * 3747 sizeof(xmlNodePtr)); 3748 if (temp == NULL) { 3749 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3750 return(-1); 3751 } 3752 cur->nodeMax *= 2; 3753 cur->nodeTab = temp; 3754 } 3755 if (val->type == XML_NAMESPACE_DECL) { 3756 xmlNsPtr ns = (xmlNsPtr) val; 3757 3758 /* TODO: Check memory error. */ 3759 cur->nodeTab[cur->nodeNr++] = 3760 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3761 } else 3762 cur->nodeTab[cur->nodeNr++] = val; 3763 return(0); 3764 } 3765 3766 /** 3767 * xmlXPathNodeSetAddUnique: 3768 * @cur: the initial node set 3769 * @val: a new xmlNodePtr 3770 * 3771 * add a new xmlNodePtr to an existing NodeSet, optimized version 3772 * when we are sure the node is not already in the set. 3773 * 3774 * Returns 0 in case of success and -1 in case of failure 3775 */ 3776 int 3777 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) { 3778 if ((cur == NULL) || (val == NULL)) return(-1); 3779 3780 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3781 /* 3782 * grow the nodeTab if needed 3783 */ 3784 if (cur->nodeMax == 0) { 3785 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3786 sizeof(xmlNodePtr)); 3787 if (cur->nodeTab == NULL) { 3788 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3789 return(-1); 3790 } 3791 memset(cur->nodeTab, 0 , 3792 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3793 cur->nodeMax = XML_NODESET_DEFAULT; 3794 } else if (cur->nodeNr == cur->nodeMax) { 3795 xmlNodePtr *temp; 3796 3797 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 3798 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n"); 3799 return(-1); 3800 } 3801 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 * 3802 sizeof(xmlNodePtr)); 3803 if (temp == NULL) { 3804 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3805 return(-1); 3806 } 3807 cur->nodeTab = temp; 3808 cur->nodeMax *= 2; 3809 } 3810 if (val->type == XML_NAMESPACE_DECL) { 3811 xmlNsPtr ns = (xmlNsPtr) val; 3812 3813 /* TODO: Check memory error. */ 3814 cur->nodeTab[cur->nodeNr++] = 3815 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3816 } else 3817 cur->nodeTab[cur->nodeNr++] = val; 3818 return(0); 3819 } 3820 3821 /** 3822 * xmlXPathNodeSetMerge: 3823 * @val1: the first NodeSet or NULL 3824 * @val2: the second NodeSet 3825 * 3826 * Merges two nodesets, all nodes from @val2 are added to @val1 3827 * if @val1 is NULL, a new set is created and copied from @val2 3828 * 3829 * Returns @val1 once extended or NULL in case of error. 3830 */ 3831 xmlNodeSetPtr 3832 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) { 3833 int i, j, initNr, skip; 3834 xmlNodePtr n1, n2; 3835 3836 if (val2 == NULL) return(val1); 3837 if (val1 == NULL) { 3838 val1 = xmlXPathNodeSetCreate(NULL); 3839 if (val1 == NULL) 3840 return (NULL); 3841 #if 0 3842 /* 3843 * TODO: The optimization won't work in every case, since 3844 * those nasty namespace nodes need to be added with 3845 * xmlXPathNodeSetDupNs() to the set; thus a pure 3846 * memcpy is not possible. 3847 * If there was a flag on the nodesetval, indicating that 3848 * some temporary nodes are in, that would be helpful. 3849 */ 3850 /* 3851 * Optimization: Create an equally sized node-set 3852 * and memcpy the content. 3853 */ 3854 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr); 3855 if (val1 == NULL) 3856 return(NULL); 3857 if (val2->nodeNr != 0) { 3858 if (val2->nodeNr == 1) 3859 *(val1->nodeTab) = *(val2->nodeTab); 3860 else { 3861 memcpy(val1->nodeTab, val2->nodeTab, 3862 val2->nodeNr * sizeof(xmlNodePtr)); 3863 } 3864 val1->nodeNr = val2->nodeNr; 3865 } 3866 return(val1); 3867 #endif 3868 } 3869 3870 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3871 initNr = val1->nodeNr; 3872 3873 for (i = 0;i < val2->nodeNr;i++) { 3874 n2 = val2->nodeTab[i]; 3875 /* 3876 * check against duplicates 3877 */ 3878 skip = 0; 3879 for (j = 0; j < initNr; j++) { 3880 n1 = val1->nodeTab[j]; 3881 if (n1 == n2) { 3882 skip = 1; 3883 break; 3884 } else if ((n1->type == XML_NAMESPACE_DECL) && 3885 (n2->type == XML_NAMESPACE_DECL)) { 3886 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) && 3887 (xmlStrEqual(((xmlNsPtr) n1)->prefix, 3888 ((xmlNsPtr) n2)->prefix))) 3889 { 3890 skip = 1; 3891 break; 3892 } 3893 } 3894 } 3895 if (skip) 3896 continue; 3897 3898 /* 3899 * grow the nodeTab if needed 3900 */ 3901 if (val1->nodeMax == 0) { 3902 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3903 sizeof(xmlNodePtr)); 3904 if (val1->nodeTab == NULL) { 3905 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3906 return(NULL); 3907 } 3908 memset(val1->nodeTab, 0 , 3909 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3910 val1->nodeMax = XML_NODESET_DEFAULT; 3911 } else if (val1->nodeNr == val1->nodeMax) { 3912 xmlNodePtr *temp; 3913 3914 if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 3915 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n"); 3916 return(NULL); 3917 } 3918 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 * 3919 sizeof(xmlNodePtr)); 3920 if (temp == NULL) { 3921 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3922 return(NULL); 3923 } 3924 val1->nodeTab = temp; 3925 val1->nodeMax *= 2; 3926 } 3927 if (n2->type == XML_NAMESPACE_DECL) { 3928 xmlNsPtr ns = (xmlNsPtr) n2; 3929 3930 /* TODO: Check memory error. */ 3931 val1->nodeTab[val1->nodeNr++] = 3932 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3933 } else 3934 val1->nodeTab[val1->nodeNr++] = n2; 3935 } 3936 3937 return(val1); 3938 } 3939 3940 3941 /** 3942 * xmlXPathNodeSetMergeAndClear: 3943 * @set1: the first NodeSet or NULL 3944 * @set2: the second NodeSet 3945 * 3946 * Merges two nodesets, all nodes from @set2 are added to @set1. 3947 * Checks for duplicate nodes. Clears set2. 3948 * 3949 * Returns @set1 once extended or NULL in case of error. 3950 */ 3951 static xmlNodeSetPtr 3952 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2) 3953 { 3954 { 3955 int i, j, initNbSet1; 3956 xmlNodePtr n1, n2; 3957 3958 initNbSet1 = set1->nodeNr; 3959 for (i = 0;i < set2->nodeNr;i++) { 3960 n2 = set2->nodeTab[i]; 3961 /* 3962 * Skip duplicates. 3963 */ 3964 for (j = 0; j < initNbSet1; j++) { 3965 n1 = set1->nodeTab[j]; 3966 if (n1 == n2) { 3967 goto skip_node; 3968 } else if ((n1->type == XML_NAMESPACE_DECL) && 3969 (n2->type == XML_NAMESPACE_DECL)) 3970 { 3971 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) && 3972 (xmlStrEqual(((xmlNsPtr) n1)->prefix, 3973 ((xmlNsPtr) n2)->prefix))) 3974 { 3975 /* 3976 * Free the namespace node. 3977 */ 3978 set2->nodeTab[i] = NULL; 3979 xmlXPathNodeSetFreeNs((xmlNsPtr) n2); 3980 goto skip_node; 3981 } 3982 } 3983 } 3984 /* 3985 * grow the nodeTab if needed 3986 */ 3987 if (set1->nodeMax == 0) { 3988 set1->nodeTab = (xmlNodePtr *) xmlMalloc( 3989 XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); 3990 if (set1->nodeTab == NULL) { 3991 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3992 return(NULL); 3993 } 3994 memset(set1->nodeTab, 0, 3995 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3996 set1->nodeMax = XML_NODESET_DEFAULT; 3997 } else if (set1->nodeNr >= set1->nodeMax) { 3998 xmlNodePtr *temp; 3999 4000 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 4001 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n"); 4002 return(NULL); 4003 } 4004 temp = (xmlNodePtr *) xmlRealloc( 4005 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr)); 4006 if (temp == NULL) { 4007 xmlXPathErrMemory(NULL, "merging nodeset\n"); 4008 return(NULL); 4009 } 4010 set1->nodeTab = temp; 4011 set1->nodeMax *= 2; 4012 } 4013 set1->nodeTab[set1->nodeNr++] = n2; 4014 skip_node: 4015 {} 4016 } 4017 } 4018 set2->nodeNr = 0; 4019 return(set1); 4020 } 4021 4022 /** 4023 * xmlXPathNodeSetMergeAndClearNoDupls: 4024 * @set1: the first NodeSet or NULL 4025 * @set2: the second NodeSet 4026 * 4027 * Merges two nodesets, all nodes from @set2 are added to @set1. 4028 * Doesn't check for duplicate nodes. Clears set2. 4029 * 4030 * Returns @set1 once extended or NULL in case of error. 4031 */ 4032 static xmlNodeSetPtr 4033 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2) 4034 { 4035 { 4036 int i; 4037 xmlNodePtr n2; 4038 4039 for (i = 0;i < set2->nodeNr;i++) { 4040 n2 = set2->nodeTab[i]; 4041 if (set1->nodeMax == 0) { 4042 set1->nodeTab = (xmlNodePtr *) xmlMalloc( 4043 XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); 4044 if (set1->nodeTab == NULL) { 4045 xmlXPathErrMemory(NULL, "merging nodeset\n"); 4046 return(NULL); 4047 } 4048 memset(set1->nodeTab, 0, 4049 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 4050 set1->nodeMax = XML_NODESET_DEFAULT; 4051 } else if (set1->nodeNr >= set1->nodeMax) { 4052 xmlNodePtr *temp; 4053 4054 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 4055 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n"); 4056 return(NULL); 4057 } 4058 temp = (xmlNodePtr *) xmlRealloc( 4059 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr)); 4060 if (temp == NULL) { 4061 xmlXPathErrMemory(NULL, "merging nodeset\n"); 4062 return(NULL); 4063 } 4064 set1->nodeTab = temp; 4065 set1->nodeMax *= 2; 4066 } 4067 set1->nodeTab[set1->nodeNr++] = n2; 4068 } 4069 } 4070 set2->nodeNr = 0; 4071 return(set1); 4072 } 4073 4074 /** 4075 * xmlXPathNodeSetDel: 4076 * @cur: the initial node set 4077 * @val: an xmlNodePtr 4078 * 4079 * Removes an xmlNodePtr from an existing NodeSet 4080 */ 4081 void 4082 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) { 4083 int i; 4084 4085 if (cur == NULL) return; 4086 if (val == NULL) return; 4087 4088 /* 4089 * find node in nodeTab 4090 */ 4091 for (i = 0;i < cur->nodeNr;i++) 4092 if (cur->nodeTab[i] == val) break; 4093 4094 if (i >= cur->nodeNr) { /* not found */ 4095 #ifdef DEBUG 4096 xmlGenericError(xmlGenericErrorContext, 4097 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n", 4098 val->name); 4099 #endif 4100 return; 4101 } 4102 if ((cur->nodeTab[i] != NULL) && 4103 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL)) 4104 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]); 4105 cur->nodeNr--; 4106 for (;i < cur->nodeNr;i++) 4107 cur->nodeTab[i] = cur->nodeTab[i + 1]; 4108 cur->nodeTab[cur->nodeNr] = NULL; 4109 } 4110 4111 /** 4112 * xmlXPathNodeSetRemove: 4113 * @cur: the initial node set 4114 * @val: the index to remove 4115 * 4116 * Removes an entry from an existing NodeSet list. 4117 */ 4118 void 4119 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) { 4120 if (cur == NULL) return; 4121 if (val >= cur->nodeNr) return; 4122 if ((cur->nodeTab[val] != NULL) && 4123 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL)) 4124 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]); 4125 cur->nodeNr--; 4126 for (;val < cur->nodeNr;val++) 4127 cur->nodeTab[val] = cur->nodeTab[val + 1]; 4128 cur->nodeTab[cur->nodeNr] = NULL; 4129 } 4130 4131 /** 4132 * xmlXPathFreeNodeSet: 4133 * @obj: the xmlNodeSetPtr to free 4134 * 4135 * Free the NodeSet compound (not the actual nodes !). 4136 */ 4137 void 4138 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) { 4139 if (obj == NULL) return; 4140 if (obj->nodeTab != NULL) { 4141 int i; 4142 4143 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 4144 for (i = 0;i < obj->nodeNr;i++) 4145 if ((obj->nodeTab[i] != NULL) && 4146 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL)) 4147 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]); 4148 xmlFree(obj->nodeTab); 4149 } 4150 xmlFree(obj); 4151 } 4152 4153 /** 4154 * xmlXPathNodeSetClearFromPos: 4155 * @set: the node set to be cleared 4156 * @pos: the start position to clear from 4157 * 4158 * Clears the list from temporary XPath objects (e.g. namespace nodes 4159 * are feed) starting with the entry at @pos, but does *not* free the list 4160 * itself. Sets the length of the list to @pos. 4161 */ 4162 static void 4163 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes) 4164 { 4165 if ((set == NULL) || (pos >= set->nodeNr)) 4166 return; 4167 else if ((hasNsNodes)) { 4168 int i; 4169 xmlNodePtr node; 4170 4171 for (i = pos; i < set->nodeNr; i++) { 4172 node = set->nodeTab[i]; 4173 if ((node != NULL) && 4174 (node->type == XML_NAMESPACE_DECL)) 4175 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 4176 } 4177 } 4178 set->nodeNr = pos; 4179 } 4180 4181 /** 4182 * xmlXPathNodeSetClear: 4183 * @set: the node set to clear 4184 * 4185 * Clears the list from all temporary XPath objects (e.g. namespace nodes 4186 * are feed), but does *not* free the list itself. Sets the length of the 4187 * list to 0. 4188 */ 4189 static void 4190 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes) 4191 { 4192 xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes); 4193 } 4194 4195 /** 4196 * xmlXPathNodeSetKeepLast: 4197 * @set: the node set to be cleared 4198 * 4199 * Move the last node to the first position and clear temporary XPath objects 4200 * (e.g. namespace nodes) from all other nodes. Sets the length of the list 4201 * to 1. 4202 */ 4203 static void 4204 xmlXPathNodeSetKeepLast(xmlNodeSetPtr set) 4205 { 4206 int i; 4207 xmlNodePtr node; 4208 4209 if ((set == NULL) || (set->nodeNr <= 1)) 4210 return; 4211 for (i = 0; i < set->nodeNr - 1; i++) { 4212 node = set->nodeTab[i]; 4213 if ((node != NULL) && 4214 (node->type == XML_NAMESPACE_DECL)) 4215 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 4216 } 4217 set->nodeTab[0] = set->nodeTab[set->nodeNr-1]; 4218 set->nodeNr = 1; 4219 } 4220 4221 /** 4222 * xmlXPathFreeValueTree: 4223 * @obj: the xmlNodeSetPtr to free 4224 * 4225 * Free the NodeSet compound and the actual tree, this is different 4226 * from xmlXPathFreeNodeSet() 4227 */ 4228 static void 4229 xmlXPathFreeValueTree(xmlNodeSetPtr obj) { 4230 int i; 4231 4232 if (obj == NULL) return; 4233 4234 if (obj->nodeTab != NULL) { 4235 for (i = 0;i < obj->nodeNr;i++) { 4236 if (obj->nodeTab[i] != NULL) { 4237 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) { 4238 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]); 4239 } else { 4240 xmlFreeNodeList(obj->nodeTab[i]); 4241 } 4242 } 4243 } 4244 xmlFree(obj->nodeTab); 4245 } 4246 xmlFree(obj); 4247 } 4248 4249 #if defined(DEBUG) || defined(DEBUG_STEP) 4250 /** 4251 * xmlGenericErrorContextNodeSet: 4252 * @output: a FILE * for the output 4253 * @obj: the xmlNodeSetPtr to display 4254 * 4255 * Quick display of a NodeSet 4256 */ 4257 void 4258 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) { 4259 int i; 4260 4261 if (output == NULL) output = xmlGenericErrorContext; 4262 if (obj == NULL) { 4263 fprintf(output, "NodeSet == NULL !\n"); 4264 return; 4265 } 4266 if (obj->nodeNr == 0) { 4267 fprintf(output, "NodeSet is empty\n"); 4268 return; 4269 } 4270 if (obj->nodeTab == NULL) { 4271 fprintf(output, " nodeTab == NULL !\n"); 4272 return; 4273 } 4274 for (i = 0; i < obj->nodeNr; i++) { 4275 if (obj->nodeTab[i] == NULL) { 4276 fprintf(output, " NULL !\n"); 4277 return; 4278 } 4279 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) || 4280 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE)) 4281 fprintf(output, " /"); 4282 else if (obj->nodeTab[i]->name == NULL) 4283 fprintf(output, " noname!"); 4284 else fprintf(output, " %s", obj->nodeTab[i]->name); 4285 } 4286 fprintf(output, "\n"); 4287 } 4288 #endif 4289 4290 /** 4291 * xmlXPathNewNodeSet: 4292 * @val: the NodePtr value 4293 * 4294 * Create a new xmlXPathObjectPtr of type NodeSet and initialize 4295 * it with the single Node @val 4296 * 4297 * Returns the newly created object. 4298 */ 4299 xmlXPathObjectPtr 4300 xmlXPathNewNodeSet(xmlNodePtr val) { 4301 xmlXPathObjectPtr ret; 4302 4303 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4304 if (ret == NULL) { 4305 xmlXPathErrMemory(NULL, "creating nodeset\n"); 4306 return(NULL); 4307 } 4308 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4309 ret->type = XPATH_NODESET; 4310 ret->boolval = 0; 4311 /* TODO: Check memory error. */ 4312 ret->nodesetval = xmlXPathNodeSetCreate(val); 4313 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 4314 #ifdef XP_DEBUG_OBJ_USAGE 4315 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET); 4316 #endif 4317 return(ret); 4318 } 4319 4320 /** 4321 * xmlXPathNewValueTree: 4322 * @val: the NodePtr value 4323 * 4324 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize 4325 * it with the tree root @val 4326 * 4327 * Returns the newly created object. 4328 */ 4329 xmlXPathObjectPtr 4330 xmlXPathNewValueTree(xmlNodePtr val) { 4331 xmlXPathObjectPtr ret; 4332 4333 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4334 if (ret == NULL) { 4335 xmlXPathErrMemory(NULL, "creating result value tree\n"); 4336 return(NULL); 4337 } 4338 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4339 ret->type = XPATH_XSLT_TREE; 4340 ret->boolval = 1; 4341 ret->user = (void *) val; 4342 ret->nodesetval = xmlXPathNodeSetCreate(val); 4343 #ifdef XP_DEBUG_OBJ_USAGE 4344 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE); 4345 #endif 4346 return(ret); 4347 } 4348 4349 /** 4350 * xmlXPathNewNodeSetList: 4351 * @val: an existing NodeSet 4352 * 4353 * Create a new xmlXPathObjectPtr of type NodeSet and initialize 4354 * it with the Nodeset @val 4355 * 4356 * Returns the newly created object. 4357 */ 4358 xmlXPathObjectPtr 4359 xmlXPathNewNodeSetList(xmlNodeSetPtr val) 4360 { 4361 xmlXPathObjectPtr ret; 4362 int i; 4363 4364 if (val == NULL) 4365 ret = NULL; 4366 else if (val->nodeTab == NULL) 4367 ret = xmlXPathNewNodeSet(NULL); 4368 else { 4369 ret = xmlXPathNewNodeSet(val->nodeTab[0]); 4370 if (ret) { 4371 for (i = 1; i < val->nodeNr; ++i) { 4372 /* TODO: Propagate memory error. */ 4373 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]) 4374 < 0) break; 4375 } 4376 } 4377 } 4378 4379 return (ret); 4380 } 4381 4382 /** 4383 * xmlXPathWrapNodeSet: 4384 * @val: the NodePtr value 4385 * 4386 * Wrap the Nodeset @val in a new xmlXPathObjectPtr 4387 * 4388 * Returns the newly created object. 4389 */ 4390 xmlXPathObjectPtr 4391 xmlXPathWrapNodeSet(xmlNodeSetPtr val) { 4392 xmlXPathObjectPtr ret; 4393 4394 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4395 if (ret == NULL) { 4396 xmlXPathErrMemory(NULL, "creating node set object\n"); 4397 return(NULL); 4398 } 4399 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4400 ret->type = XPATH_NODESET; 4401 ret->nodesetval = val; 4402 #ifdef XP_DEBUG_OBJ_USAGE 4403 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET); 4404 #endif 4405 return(ret); 4406 } 4407 4408 /** 4409 * xmlXPathFreeNodeSetList: 4410 * @obj: an existing NodeSetList object 4411 * 4412 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in 4413 * the list contrary to xmlXPathFreeObject(). 4414 */ 4415 void 4416 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) { 4417 if (obj == NULL) return; 4418 #ifdef XP_DEBUG_OBJ_USAGE 4419 xmlXPathDebugObjUsageReleased(NULL, obj->type); 4420 #endif 4421 xmlFree(obj); 4422 } 4423 4424 /** 4425 * xmlXPathDifference: 4426 * @nodes1: a node-set 4427 * @nodes2: a node-set 4428 * 4429 * Implements the EXSLT - Sets difference() function: 4430 * node-set set:difference (node-set, node-set) 4431 * 4432 * Returns the difference between the two node sets, or nodes1 if 4433 * nodes2 is empty 4434 */ 4435 xmlNodeSetPtr 4436 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4437 xmlNodeSetPtr ret; 4438 int i, l1; 4439 xmlNodePtr cur; 4440 4441 if (xmlXPathNodeSetIsEmpty(nodes2)) 4442 return(nodes1); 4443 4444 /* TODO: Check memory error. */ 4445 ret = xmlXPathNodeSetCreate(NULL); 4446 if (xmlXPathNodeSetIsEmpty(nodes1)) 4447 return(ret); 4448 4449 l1 = xmlXPathNodeSetGetLength(nodes1); 4450 4451 for (i = 0; i < l1; i++) { 4452 cur = xmlXPathNodeSetItem(nodes1, i); 4453 if (!xmlXPathNodeSetContains(nodes2, cur)) { 4454 /* TODO: Propagate memory error. */ 4455 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) 4456 break; 4457 } 4458 } 4459 return(ret); 4460 } 4461 4462 /** 4463 * xmlXPathIntersection: 4464 * @nodes1: a node-set 4465 * @nodes2: a node-set 4466 * 4467 * Implements the EXSLT - Sets intersection() function: 4468 * node-set set:intersection (node-set, node-set) 4469 * 4470 * Returns a node set comprising the nodes that are within both the 4471 * node sets passed as arguments 4472 */ 4473 xmlNodeSetPtr 4474 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4475 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL); 4476 int i, l1; 4477 xmlNodePtr cur; 4478 4479 if (ret == NULL) 4480 return(ret); 4481 if (xmlXPathNodeSetIsEmpty(nodes1)) 4482 return(ret); 4483 if (xmlXPathNodeSetIsEmpty(nodes2)) 4484 return(ret); 4485 4486 l1 = xmlXPathNodeSetGetLength(nodes1); 4487 4488 for (i = 0; i < l1; i++) { 4489 cur = xmlXPathNodeSetItem(nodes1, i); 4490 if (xmlXPathNodeSetContains(nodes2, cur)) { 4491 /* TODO: Propagate memory error. */ 4492 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) 4493 break; 4494 } 4495 } 4496 return(ret); 4497 } 4498 4499 /** 4500 * xmlXPathDistinctSorted: 4501 * @nodes: a node-set, sorted by document order 4502 * 4503 * Implements the EXSLT - Sets distinct() function: 4504 * node-set set:distinct (node-set) 4505 * 4506 * Returns a subset of the nodes contained in @nodes, or @nodes if 4507 * it is empty 4508 */ 4509 xmlNodeSetPtr 4510 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) { 4511 xmlNodeSetPtr ret; 4512 xmlHashTablePtr hash; 4513 int i, l; 4514 xmlChar * strval; 4515 xmlNodePtr cur; 4516 4517 if (xmlXPathNodeSetIsEmpty(nodes)) 4518 return(nodes); 4519 4520 ret = xmlXPathNodeSetCreate(NULL); 4521 if (ret == NULL) 4522 return(ret); 4523 l = xmlXPathNodeSetGetLength(nodes); 4524 hash = xmlHashCreate (l); 4525 for (i = 0; i < l; i++) { 4526 cur = xmlXPathNodeSetItem(nodes, i); 4527 strval = xmlXPathCastNodeToString(cur); 4528 if (xmlHashLookup(hash, strval) == NULL) { 4529 xmlHashAddEntry(hash, strval, strval); 4530 /* TODO: Propagate memory error. */ 4531 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) 4532 break; 4533 } else { 4534 xmlFree(strval); 4535 } 4536 } 4537 xmlHashFree(hash, xmlHashDefaultDeallocator); 4538 return(ret); 4539 } 4540 4541 /** 4542 * xmlXPathDistinct: 4543 * @nodes: a node-set 4544 * 4545 * Implements the EXSLT - Sets distinct() function: 4546 * node-set set:distinct (node-set) 4547 * @nodes is sorted by document order, then #exslSetsDistinctSorted 4548 * is called with the sorted node-set 4549 * 4550 * Returns a subset of the nodes contained in @nodes, or @nodes if 4551 * it is empty 4552 */ 4553 xmlNodeSetPtr 4554 xmlXPathDistinct (xmlNodeSetPtr nodes) { 4555 if (xmlXPathNodeSetIsEmpty(nodes)) 4556 return(nodes); 4557 4558 xmlXPathNodeSetSort(nodes); 4559 return(xmlXPathDistinctSorted(nodes)); 4560 } 4561 4562 /** 4563 * xmlXPathHasSameNodes: 4564 * @nodes1: a node-set 4565 * @nodes2: a node-set 4566 * 4567 * Implements the EXSLT - Sets has-same-nodes function: 4568 * boolean set:has-same-node(node-set, node-set) 4569 * 4570 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0) 4571 * otherwise 4572 */ 4573 int 4574 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4575 int i, l; 4576 xmlNodePtr cur; 4577 4578 if (xmlXPathNodeSetIsEmpty(nodes1) || 4579 xmlXPathNodeSetIsEmpty(nodes2)) 4580 return(0); 4581 4582 l = xmlXPathNodeSetGetLength(nodes1); 4583 for (i = 0; i < l; i++) { 4584 cur = xmlXPathNodeSetItem(nodes1, i); 4585 if (xmlXPathNodeSetContains(nodes2, cur)) 4586 return(1); 4587 } 4588 return(0); 4589 } 4590 4591 /** 4592 * xmlXPathNodeLeadingSorted: 4593 * @nodes: a node-set, sorted by document order 4594 * @node: a node 4595 * 4596 * Implements the EXSLT - Sets leading() function: 4597 * node-set set:leading (node-set, node-set) 4598 * 4599 * Returns the nodes in @nodes that precede @node in document order, 4600 * @nodes if @node is NULL or an empty node-set if @nodes 4601 * doesn't contain @node 4602 */ 4603 xmlNodeSetPtr 4604 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { 4605 int i, l; 4606 xmlNodePtr cur; 4607 xmlNodeSetPtr ret; 4608 4609 if (node == NULL) 4610 return(nodes); 4611 4612 ret = xmlXPathNodeSetCreate(NULL); 4613 if (ret == NULL) 4614 return(ret); 4615 if (xmlXPathNodeSetIsEmpty(nodes) || 4616 (!xmlXPathNodeSetContains(nodes, node))) 4617 return(ret); 4618 4619 l = xmlXPathNodeSetGetLength(nodes); 4620 for (i = 0; i < l; i++) { 4621 cur = xmlXPathNodeSetItem(nodes, i); 4622 if (cur == node) 4623 break; 4624 /* TODO: Propagate memory error. */ 4625 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) 4626 break; 4627 } 4628 return(ret); 4629 } 4630 4631 /** 4632 * xmlXPathNodeLeading: 4633 * @nodes: a node-set 4634 * @node: a node 4635 * 4636 * Implements the EXSLT - Sets leading() function: 4637 * node-set set:leading (node-set, node-set) 4638 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted 4639 * is called. 4640 * 4641 * Returns the nodes in @nodes that precede @node in document order, 4642 * @nodes if @node is NULL or an empty node-set if @nodes 4643 * doesn't contain @node 4644 */ 4645 xmlNodeSetPtr 4646 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) { 4647 xmlXPathNodeSetSort(nodes); 4648 return(xmlXPathNodeLeadingSorted(nodes, node)); 4649 } 4650 4651 /** 4652 * xmlXPathLeadingSorted: 4653 * @nodes1: a node-set, sorted by document order 4654 * @nodes2: a node-set, sorted by document order 4655 * 4656 * Implements the EXSLT - Sets leading() function: 4657 * node-set set:leading (node-set, node-set) 4658 * 4659 * Returns the nodes in @nodes1 that precede the first node in @nodes2 4660 * in document order, @nodes1 if @nodes2 is NULL or empty or 4661 * an empty node-set if @nodes1 doesn't contain @nodes2 4662 */ 4663 xmlNodeSetPtr 4664 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4665 if (xmlXPathNodeSetIsEmpty(nodes2)) 4666 return(nodes1); 4667 return(xmlXPathNodeLeadingSorted(nodes1, 4668 xmlXPathNodeSetItem(nodes2, 1))); 4669 } 4670 4671 /** 4672 * xmlXPathLeading: 4673 * @nodes1: a node-set 4674 * @nodes2: a node-set 4675 * 4676 * Implements the EXSLT - Sets leading() function: 4677 * node-set set:leading (node-set, node-set) 4678 * @nodes1 and @nodes2 are sorted by document order, then 4679 * #exslSetsLeadingSorted is called. 4680 * 4681 * Returns the nodes in @nodes1 that precede the first node in @nodes2 4682 * in document order, @nodes1 if @nodes2 is NULL or empty or 4683 * an empty node-set if @nodes1 doesn't contain @nodes2 4684 */ 4685 xmlNodeSetPtr 4686 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4687 if (xmlXPathNodeSetIsEmpty(nodes2)) 4688 return(nodes1); 4689 if (xmlXPathNodeSetIsEmpty(nodes1)) 4690 return(xmlXPathNodeSetCreate(NULL)); 4691 xmlXPathNodeSetSort(nodes1); 4692 xmlXPathNodeSetSort(nodes2); 4693 return(xmlXPathNodeLeadingSorted(nodes1, 4694 xmlXPathNodeSetItem(nodes2, 1))); 4695 } 4696 4697 /** 4698 * xmlXPathNodeTrailingSorted: 4699 * @nodes: a node-set, sorted by document order 4700 * @node: a node 4701 * 4702 * Implements the EXSLT - Sets trailing() function: 4703 * node-set set:trailing (node-set, node-set) 4704 * 4705 * Returns the nodes in @nodes that follow @node in document order, 4706 * @nodes if @node is NULL or an empty node-set if @nodes 4707 * doesn't contain @node 4708 */ 4709 xmlNodeSetPtr 4710 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { 4711 int i, l; 4712 xmlNodePtr cur; 4713 xmlNodeSetPtr ret; 4714 4715 if (node == NULL) 4716 return(nodes); 4717 4718 ret = xmlXPathNodeSetCreate(NULL); 4719 if (ret == NULL) 4720 return(ret); 4721 if (xmlXPathNodeSetIsEmpty(nodes) || 4722 (!xmlXPathNodeSetContains(nodes, node))) 4723 return(ret); 4724 4725 l = xmlXPathNodeSetGetLength(nodes); 4726 for (i = l - 1; i >= 0; i--) { 4727 cur = xmlXPathNodeSetItem(nodes, i); 4728 if (cur == node) 4729 break; 4730 /* TODO: Propagate memory error. */ 4731 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) 4732 break; 4733 } 4734 xmlXPathNodeSetSort(ret); /* bug 413451 */ 4735 return(ret); 4736 } 4737 4738 /** 4739 * xmlXPathNodeTrailing: 4740 * @nodes: a node-set 4741 * @node: a node 4742 * 4743 * Implements the EXSLT - Sets trailing() function: 4744 * node-set set:trailing (node-set, node-set) 4745 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted 4746 * is called. 4747 * 4748 * Returns the nodes in @nodes that follow @node in document order, 4749 * @nodes if @node is NULL or an empty node-set if @nodes 4750 * doesn't contain @node 4751 */ 4752 xmlNodeSetPtr 4753 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) { 4754 xmlXPathNodeSetSort(nodes); 4755 return(xmlXPathNodeTrailingSorted(nodes, node)); 4756 } 4757 4758 /** 4759 * xmlXPathTrailingSorted: 4760 * @nodes1: a node-set, sorted by document order 4761 * @nodes2: a node-set, sorted by document order 4762 * 4763 * Implements the EXSLT - Sets trailing() function: 4764 * node-set set:trailing (node-set, node-set) 4765 * 4766 * Returns the nodes in @nodes1 that follow the first node in @nodes2 4767 * in document order, @nodes1 if @nodes2 is NULL or empty or 4768 * an empty node-set if @nodes1 doesn't contain @nodes2 4769 */ 4770 xmlNodeSetPtr 4771 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4772 if (xmlXPathNodeSetIsEmpty(nodes2)) 4773 return(nodes1); 4774 return(xmlXPathNodeTrailingSorted(nodes1, 4775 xmlXPathNodeSetItem(nodes2, 0))); 4776 } 4777 4778 /** 4779 * xmlXPathTrailing: 4780 * @nodes1: a node-set 4781 * @nodes2: a node-set 4782 * 4783 * Implements the EXSLT - Sets trailing() function: 4784 * node-set set:trailing (node-set, node-set) 4785 * @nodes1 and @nodes2 are sorted by document order, then 4786 * #xmlXPathTrailingSorted is called. 4787 * 4788 * Returns the nodes in @nodes1 that follow the first node in @nodes2 4789 * in document order, @nodes1 if @nodes2 is NULL or empty or 4790 * an empty node-set if @nodes1 doesn't contain @nodes2 4791 */ 4792 xmlNodeSetPtr 4793 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4794 if (xmlXPathNodeSetIsEmpty(nodes2)) 4795 return(nodes1); 4796 if (xmlXPathNodeSetIsEmpty(nodes1)) 4797 return(xmlXPathNodeSetCreate(NULL)); 4798 xmlXPathNodeSetSort(nodes1); 4799 xmlXPathNodeSetSort(nodes2); 4800 return(xmlXPathNodeTrailingSorted(nodes1, 4801 xmlXPathNodeSetItem(nodes2, 0))); 4802 } 4803 4804 /************************************************************************ 4805 * * 4806 * Routines to handle extra functions * 4807 * * 4808 ************************************************************************/ 4809 4810 /** 4811 * xmlXPathRegisterFunc: 4812 * @ctxt: the XPath context 4813 * @name: the function name 4814 * @f: the function implementation or NULL 4815 * 4816 * Register a new function. If @f is NULL it unregisters the function 4817 * 4818 * Returns 0 in case of success, -1 in case of error 4819 */ 4820 int 4821 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name, 4822 xmlXPathFunction f) { 4823 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f)); 4824 } 4825 4826 /** 4827 * xmlXPathRegisterFuncNS: 4828 * @ctxt: the XPath context 4829 * @name: the function name 4830 * @ns_uri: the function namespace URI 4831 * @f: the function implementation or NULL 4832 * 4833 * Register a new function. If @f is NULL it unregisters the function 4834 * 4835 * Returns 0 in case of success, -1 in case of error 4836 */ 4837 int 4838 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name, 4839 const xmlChar *ns_uri, xmlXPathFunction f) { 4840 if (ctxt == NULL) 4841 return(-1); 4842 if (name == NULL) 4843 return(-1); 4844 4845 if (ctxt->funcHash == NULL) 4846 ctxt->funcHash = xmlHashCreate(0); 4847 if (ctxt->funcHash == NULL) 4848 return(-1); 4849 if (f == NULL) 4850 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL)); 4851 XML_IGNORE_PEDANTIC_WARNINGS 4852 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f)); 4853 XML_POP_WARNINGS 4854 } 4855 4856 /** 4857 * xmlXPathRegisterFuncLookup: 4858 * @ctxt: the XPath context 4859 * @f: the lookup function 4860 * @funcCtxt: the lookup data 4861 * 4862 * Registers an external mechanism to do function lookup. 4863 */ 4864 void 4865 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt, 4866 xmlXPathFuncLookupFunc f, 4867 void *funcCtxt) { 4868 if (ctxt == NULL) 4869 return; 4870 ctxt->funcLookupFunc = f; 4871 ctxt->funcLookupData = funcCtxt; 4872 } 4873 4874 /** 4875 * xmlXPathFunctionLookup: 4876 * @ctxt: the XPath context 4877 * @name: the function name 4878 * 4879 * Search in the Function array of the context for the given 4880 * function. 4881 * 4882 * Returns the xmlXPathFunction or NULL if not found 4883 */ 4884 xmlXPathFunction 4885 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { 4886 if (ctxt == NULL) 4887 return (NULL); 4888 4889 if (ctxt->funcLookupFunc != NULL) { 4890 xmlXPathFunction ret; 4891 xmlXPathFuncLookupFunc f; 4892 4893 f = ctxt->funcLookupFunc; 4894 ret = f(ctxt->funcLookupData, name, NULL); 4895 if (ret != NULL) 4896 return(ret); 4897 } 4898 return(xmlXPathFunctionLookupNS(ctxt, name, NULL)); 4899 } 4900 4901 /** 4902 * xmlXPathFunctionLookupNS: 4903 * @ctxt: the XPath context 4904 * @name: the function name 4905 * @ns_uri: the function namespace URI 4906 * 4907 * Search in the Function array of the context for the given 4908 * function. 4909 * 4910 * Returns the xmlXPathFunction or NULL if not found 4911 */ 4912 xmlXPathFunction 4913 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name, 4914 const xmlChar *ns_uri) { 4915 xmlXPathFunction ret; 4916 4917 if (ctxt == NULL) 4918 return(NULL); 4919 if (name == NULL) 4920 return(NULL); 4921 4922 if (ctxt->funcLookupFunc != NULL) { 4923 xmlXPathFuncLookupFunc f; 4924 4925 f = ctxt->funcLookupFunc; 4926 ret = f(ctxt->funcLookupData, name, ns_uri); 4927 if (ret != NULL) 4928 return(ret); 4929 } 4930 4931 if (ctxt->funcHash == NULL) 4932 return(NULL); 4933 4934 XML_IGNORE_PEDANTIC_WARNINGS 4935 ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri); 4936 XML_POP_WARNINGS 4937 return(ret); 4938 } 4939 4940 /** 4941 * xmlXPathRegisteredFuncsCleanup: 4942 * @ctxt: the XPath context 4943 * 4944 * Cleanup the XPath context data associated to registered functions 4945 */ 4946 void 4947 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) { 4948 if (ctxt == NULL) 4949 return; 4950 4951 xmlHashFree(ctxt->funcHash, NULL); 4952 ctxt->funcHash = NULL; 4953 } 4954 4955 /************************************************************************ 4956 * * 4957 * Routines to handle Variables * 4958 * * 4959 ************************************************************************/ 4960 4961 /** 4962 * xmlXPathRegisterVariable: 4963 * @ctxt: the XPath context 4964 * @name: the variable name 4965 * @value: the variable value or NULL 4966 * 4967 * Register a new variable value. If @value is NULL it unregisters 4968 * the variable 4969 * 4970 * Returns 0 in case of success, -1 in case of error 4971 */ 4972 int 4973 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name, 4974 xmlXPathObjectPtr value) { 4975 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value)); 4976 } 4977 4978 /** 4979 * xmlXPathRegisterVariableNS: 4980 * @ctxt: the XPath context 4981 * @name: the variable name 4982 * @ns_uri: the variable namespace URI 4983 * @value: the variable value or NULL 4984 * 4985 * Register a new variable value. If @value is NULL it unregisters 4986 * the variable 4987 * 4988 * Returns 0 in case of success, -1 in case of error 4989 */ 4990 int 4991 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name, 4992 const xmlChar *ns_uri, 4993 xmlXPathObjectPtr value) { 4994 if (ctxt == NULL) 4995 return(-1); 4996 if (name == NULL) 4997 return(-1); 4998 4999 if (ctxt->varHash == NULL) 5000 ctxt->varHash = xmlHashCreate(0); 5001 if (ctxt->varHash == NULL) 5002 return(-1); 5003 if (value == NULL) 5004 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri, 5005 xmlXPathFreeObjectEntry)); 5006 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri, 5007 (void *) value, xmlXPathFreeObjectEntry)); 5008 } 5009 5010 /** 5011 * xmlXPathRegisterVariableLookup: 5012 * @ctxt: the XPath context 5013 * @f: the lookup function 5014 * @data: the lookup data 5015 * 5016 * register an external mechanism to do variable lookup 5017 */ 5018 void 5019 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt, 5020 xmlXPathVariableLookupFunc f, void *data) { 5021 if (ctxt == NULL) 5022 return; 5023 ctxt->varLookupFunc = f; 5024 ctxt->varLookupData = data; 5025 } 5026 5027 /** 5028 * xmlXPathVariableLookup: 5029 * @ctxt: the XPath context 5030 * @name: the variable name 5031 * 5032 * Search in the Variable array of the context for the given 5033 * variable value. 5034 * 5035 * Returns a copy of the value or NULL if not found 5036 */ 5037 xmlXPathObjectPtr 5038 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { 5039 if (ctxt == NULL) 5040 return(NULL); 5041 5042 if (ctxt->varLookupFunc != NULL) { 5043 xmlXPathObjectPtr ret; 5044 5045 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc) 5046 (ctxt->varLookupData, name, NULL); 5047 return(ret); 5048 } 5049 return(xmlXPathVariableLookupNS(ctxt, name, NULL)); 5050 } 5051 5052 /** 5053 * xmlXPathVariableLookupNS: 5054 * @ctxt: the XPath context 5055 * @name: the variable name 5056 * @ns_uri: the variable namespace URI 5057 * 5058 * Search in the Variable array of the context for the given 5059 * variable value. 5060 * 5061 * Returns the a copy of the value or NULL if not found 5062 */ 5063 xmlXPathObjectPtr 5064 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name, 5065 const xmlChar *ns_uri) { 5066 if (ctxt == NULL) 5067 return(NULL); 5068 5069 if (ctxt->varLookupFunc != NULL) { 5070 xmlXPathObjectPtr ret; 5071 5072 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc) 5073 (ctxt->varLookupData, name, ns_uri); 5074 if (ret != NULL) return(ret); 5075 } 5076 5077 if (ctxt->varHash == NULL) 5078 return(NULL); 5079 if (name == NULL) 5080 return(NULL); 5081 5082 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr) 5083 xmlHashLookup2(ctxt->varHash, name, ns_uri))); 5084 } 5085 5086 /** 5087 * xmlXPathRegisteredVariablesCleanup: 5088 * @ctxt: the XPath context 5089 * 5090 * Cleanup the XPath context data associated to registered variables 5091 */ 5092 void 5093 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) { 5094 if (ctxt == NULL) 5095 return; 5096 5097 xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry); 5098 ctxt->varHash = NULL; 5099 } 5100 5101 /** 5102 * xmlXPathRegisterNs: 5103 * @ctxt: the XPath context 5104 * @prefix: the namespace prefix cannot be NULL or empty string 5105 * @ns_uri: the namespace name 5106 * 5107 * Register a new namespace. If @ns_uri is NULL it unregisters 5108 * the namespace 5109 * 5110 * Returns 0 in case of success, -1 in case of error 5111 */ 5112 int 5113 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix, 5114 const xmlChar *ns_uri) { 5115 if (ctxt == NULL) 5116 return(-1); 5117 if (prefix == NULL) 5118 return(-1); 5119 if (prefix[0] == 0) 5120 return(-1); 5121 5122 if (ctxt->nsHash == NULL) 5123 ctxt->nsHash = xmlHashCreate(10); 5124 if (ctxt->nsHash == NULL) 5125 return(-1); 5126 if (ns_uri == NULL) 5127 return(xmlHashRemoveEntry(ctxt->nsHash, prefix, 5128 xmlHashDefaultDeallocator)); 5129 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri), 5130 xmlHashDefaultDeallocator)); 5131 } 5132 5133 /** 5134 * xmlXPathNsLookup: 5135 * @ctxt: the XPath context 5136 * @prefix: the namespace prefix value 5137 * 5138 * Search in the namespace declaration array of the context for the given 5139 * namespace name associated to the given prefix 5140 * 5141 * Returns the value or NULL if not found 5142 */ 5143 const xmlChar * 5144 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) { 5145 if (ctxt == NULL) 5146 return(NULL); 5147 if (prefix == NULL) 5148 return(NULL); 5149 5150 #ifdef XML_XML_NAMESPACE 5151 if (xmlStrEqual(prefix, (const xmlChar *) "xml")) 5152 return(XML_XML_NAMESPACE); 5153 #endif 5154 5155 if (ctxt->namespaces != NULL) { 5156 int i; 5157 5158 for (i = 0;i < ctxt->nsNr;i++) { 5159 if ((ctxt->namespaces[i] != NULL) && 5160 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix))) 5161 return(ctxt->namespaces[i]->href); 5162 } 5163 } 5164 5165 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix)); 5166 } 5167 5168 /** 5169 * xmlXPathRegisteredNsCleanup: 5170 * @ctxt: the XPath context 5171 * 5172 * Cleanup the XPath context data associated to registered variables 5173 */ 5174 void 5175 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) { 5176 if (ctxt == NULL) 5177 return; 5178 5179 xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator); 5180 ctxt->nsHash = NULL; 5181 } 5182 5183 /************************************************************************ 5184 * * 5185 * Routines to handle Values * 5186 * * 5187 ************************************************************************/ 5188 5189 /* Allocations are terrible, one needs to optimize all this !!! */ 5190 5191 /** 5192 * xmlXPathNewFloat: 5193 * @val: the double value 5194 * 5195 * Create a new xmlXPathObjectPtr of type double and of value @val 5196 * 5197 * Returns the newly created object. 5198 */ 5199 xmlXPathObjectPtr 5200 xmlXPathNewFloat(double val) { 5201 xmlXPathObjectPtr ret; 5202 5203 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5204 if (ret == NULL) { 5205 xmlXPathErrMemory(NULL, "creating float object\n"); 5206 return(NULL); 5207 } 5208 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5209 ret->type = XPATH_NUMBER; 5210 ret->floatval = val; 5211 #ifdef XP_DEBUG_OBJ_USAGE 5212 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER); 5213 #endif 5214 return(ret); 5215 } 5216 5217 /** 5218 * xmlXPathNewBoolean: 5219 * @val: the boolean value 5220 * 5221 * Create a new xmlXPathObjectPtr of type boolean and of value @val 5222 * 5223 * Returns the newly created object. 5224 */ 5225 xmlXPathObjectPtr 5226 xmlXPathNewBoolean(int val) { 5227 xmlXPathObjectPtr ret; 5228 5229 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5230 if (ret == NULL) { 5231 xmlXPathErrMemory(NULL, "creating boolean object\n"); 5232 return(NULL); 5233 } 5234 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5235 ret->type = XPATH_BOOLEAN; 5236 ret->boolval = (val != 0); 5237 #ifdef XP_DEBUG_OBJ_USAGE 5238 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN); 5239 #endif 5240 return(ret); 5241 } 5242 5243 /** 5244 * xmlXPathNewString: 5245 * @val: the xmlChar * value 5246 * 5247 * Create a new xmlXPathObjectPtr of type string and of value @val 5248 * 5249 * Returns the newly created object. 5250 */ 5251 xmlXPathObjectPtr 5252 xmlXPathNewString(const xmlChar *val) { 5253 xmlXPathObjectPtr ret; 5254 5255 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5256 if (ret == NULL) { 5257 xmlXPathErrMemory(NULL, "creating string object\n"); 5258 return(NULL); 5259 } 5260 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5261 ret->type = XPATH_STRING; 5262 if (val != NULL) 5263 ret->stringval = xmlStrdup(val); 5264 else 5265 ret->stringval = xmlStrdup((const xmlChar *)""); 5266 #ifdef XP_DEBUG_OBJ_USAGE 5267 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); 5268 #endif 5269 return(ret); 5270 } 5271 5272 /** 5273 * xmlXPathWrapString: 5274 * @val: the xmlChar * value 5275 * 5276 * Wraps the @val string into an XPath object. 5277 * 5278 * Returns the newly created object. 5279 */ 5280 xmlXPathObjectPtr 5281 xmlXPathWrapString (xmlChar *val) { 5282 xmlXPathObjectPtr ret; 5283 5284 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5285 if (ret == NULL) { 5286 xmlXPathErrMemory(NULL, "creating string object\n"); 5287 return(NULL); 5288 } 5289 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5290 ret->type = XPATH_STRING; 5291 ret->stringval = val; 5292 #ifdef XP_DEBUG_OBJ_USAGE 5293 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); 5294 #endif 5295 return(ret); 5296 } 5297 5298 /** 5299 * xmlXPathNewCString: 5300 * @val: the char * value 5301 * 5302 * Create a new xmlXPathObjectPtr of type string and of value @val 5303 * 5304 * Returns the newly created object. 5305 */ 5306 xmlXPathObjectPtr 5307 xmlXPathNewCString(const char *val) { 5308 xmlXPathObjectPtr ret; 5309 5310 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5311 if (ret == NULL) { 5312 xmlXPathErrMemory(NULL, "creating string object\n"); 5313 return(NULL); 5314 } 5315 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5316 ret->type = XPATH_STRING; 5317 ret->stringval = xmlStrdup(BAD_CAST val); 5318 #ifdef XP_DEBUG_OBJ_USAGE 5319 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); 5320 #endif 5321 return(ret); 5322 } 5323 5324 /** 5325 * xmlXPathWrapCString: 5326 * @val: the char * value 5327 * 5328 * Wraps a string into an XPath object. 5329 * 5330 * Returns the newly created object. 5331 */ 5332 xmlXPathObjectPtr 5333 xmlXPathWrapCString (char * val) { 5334 return(xmlXPathWrapString((xmlChar *)(val))); 5335 } 5336 5337 /** 5338 * xmlXPathWrapExternal: 5339 * @val: the user data 5340 * 5341 * Wraps the @val data into an XPath object. 5342 * 5343 * Returns the newly created object. 5344 */ 5345 xmlXPathObjectPtr 5346 xmlXPathWrapExternal (void *val) { 5347 xmlXPathObjectPtr ret; 5348 5349 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5350 if (ret == NULL) { 5351 xmlXPathErrMemory(NULL, "creating user object\n"); 5352 return(NULL); 5353 } 5354 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5355 ret->type = XPATH_USERS; 5356 ret->user = val; 5357 #ifdef XP_DEBUG_OBJ_USAGE 5358 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS); 5359 #endif 5360 return(ret); 5361 } 5362 5363 /** 5364 * xmlXPathObjectCopy: 5365 * @val: the original object 5366 * 5367 * allocate a new copy of a given object 5368 * 5369 * Returns the newly created object. 5370 */ 5371 xmlXPathObjectPtr 5372 xmlXPathObjectCopy(xmlXPathObjectPtr val) { 5373 xmlXPathObjectPtr ret; 5374 5375 if (val == NULL) 5376 return(NULL); 5377 5378 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5379 if (ret == NULL) { 5380 xmlXPathErrMemory(NULL, "copying object\n"); 5381 return(NULL); 5382 } 5383 memcpy(ret, val , (size_t) sizeof(xmlXPathObject)); 5384 #ifdef XP_DEBUG_OBJ_USAGE 5385 xmlXPathDebugObjUsageRequested(NULL, val->type); 5386 #endif 5387 switch (val->type) { 5388 case XPATH_BOOLEAN: 5389 case XPATH_NUMBER: 5390 case XPATH_POINT: 5391 case XPATH_RANGE: 5392 break; 5393 case XPATH_STRING: 5394 ret->stringval = xmlStrdup(val->stringval); 5395 break; 5396 case XPATH_XSLT_TREE: 5397 #if 0 5398 /* 5399 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that 5400 this previous handling is no longer correct, and can cause some serious 5401 problems (ref. bug 145547) 5402 */ 5403 if ((val->nodesetval != NULL) && 5404 (val->nodesetval->nodeTab != NULL)) { 5405 xmlNodePtr cur, tmp; 5406 xmlDocPtr top; 5407 5408 ret->boolval = 1; 5409 top = xmlNewDoc(NULL); 5410 top->name = (char *) 5411 xmlStrdup(val->nodesetval->nodeTab[0]->name); 5412 ret->user = top; 5413 if (top != NULL) { 5414 top->doc = top; 5415 cur = val->nodesetval->nodeTab[0]->children; 5416 while (cur != NULL) { 5417 tmp = xmlDocCopyNode(cur, top, 1); 5418 xmlAddChild((xmlNodePtr) top, tmp); 5419 cur = cur->next; 5420 } 5421 } 5422 5423 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top); 5424 } else 5425 ret->nodesetval = xmlXPathNodeSetCreate(NULL); 5426 /* Deallocate the copied tree value */ 5427 break; 5428 #endif 5429 case XPATH_NODESET: 5430 /* TODO: Check memory error. */ 5431 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval); 5432 /* Do not deallocate the copied tree value */ 5433 ret->boolval = 0; 5434 break; 5435 case XPATH_LOCATIONSET: 5436 #ifdef LIBXML_XPTR_ENABLED 5437 { 5438 xmlLocationSetPtr loc = val->user; 5439 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc); 5440 break; 5441 } 5442 #endif 5443 case XPATH_USERS: 5444 ret->user = val->user; 5445 break; 5446 case XPATH_UNDEFINED: 5447 xmlGenericError(xmlGenericErrorContext, 5448 "xmlXPathObjectCopy: unsupported type %d\n", 5449 val->type); 5450 break; 5451 } 5452 return(ret); 5453 } 5454 5455 /** 5456 * xmlXPathFreeObject: 5457 * @obj: the object to free 5458 * 5459 * Free up an xmlXPathObjectPtr object. 5460 */ 5461 void 5462 xmlXPathFreeObject(xmlXPathObjectPtr obj) { 5463 if (obj == NULL) return; 5464 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) { 5465 if (obj->boolval) { 5466 #if 0 5467 if (obj->user != NULL) { 5468 xmlXPathFreeNodeSet(obj->nodesetval); 5469 xmlFreeNodeList((xmlNodePtr) obj->user); 5470 } else 5471 #endif 5472 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */ 5473 if (obj->nodesetval != NULL) 5474 xmlXPathFreeValueTree(obj->nodesetval); 5475 } else { 5476 if (obj->nodesetval != NULL) 5477 xmlXPathFreeNodeSet(obj->nodesetval); 5478 } 5479 #ifdef LIBXML_XPTR_ENABLED 5480 } else if (obj->type == XPATH_LOCATIONSET) { 5481 if (obj->user != NULL) 5482 xmlXPtrFreeLocationSet(obj->user); 5483 #endif 5484 } else if (obj->type == XPATH_STRING) { 5485 if (obj->stringval != NULL) 5486 xmlFree(obj->stringval); 5487 } 5488 #ifdef XP_DEBUG_OBJ_USAGE 5489 xmlXPathDebugObjUsageReleased(NULL, obj->type); 5490 #endif 5491 xmlFree(obj); 5492 } 5493 5494 static void 5495 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) { 5496 xmlXPathFreeObject((xmlXPathObjectPtr) obj); 5497 } 5498 5499 /** 5500 * xmlXPathReleaseObject: 5501 * @obj: the xmlXPathObjectPtr to free or to cache 5502 * 5503 * Depending on the state of the cache this frees the given 5504 * XPath object or stores it in the cache. 5505 */ 5506 static void 5507 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj) 5508 { 5509 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \ 5510 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \ 5511 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj; 5512 5513 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n)) 5514 5515 if (obj == NULL) 5516 return; 5517 if ((ctxt == NULL) || (ctxt->cache == NULL)) { 5518 xmlXPathFreeObject(obj); 5519 } else { 5520 xmlXPathContextCachePtr cache = 5521 (xmlXPathContextCachePtr) ctxt->cache; 5522 5523 switch (obj->type) { 5524 case XPATH_NODESET: 5525 case XPATH_XSLT_TREE: 5526 if (obj->nodesetval != NULL) { 5527 if (obj->boolval) { 5528 /* 5529 * It looks like the @boolval is used for 5530 * evaluation if this an XSLT Result Tree Fragment. 5531 * TODO: Check if this assumption is correct. 5532 */ 5533 obj->type = XPATH_XSLT_TREE; /* just for debugging */ 5534 xmlXPathFreeValueTree(obj->nodesetval); 5535 obj->nodesetval = NULL; 5536 } else if ((obj->nodesetval->nodeMax <= 40) && 5537 (XP_CACHE_WANTS(cache->nodesetObjs, 5538 cache->maxNodeset))) 5539 { 5540 XP_CACHE_ADD(cache->nodesetObjs, obj); 5541 goto obj_cached; 5542 } else { 5543 xmlXPathFreeNodeSet(obj->nodesetval); 5544 obj->nodesetval = NULL; 5545 } 5546 } 5547 break; 5548 case XPATH_STRING: 5549 if (obj->stringval != NULL) 5550 xmlFree(obj->stringval); 5551 5552 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) { 5553 XP_CACHE_ADD(cache->stringObjs, obj); 5554 goto obj_cached; 5555 } 5556 break; 5557 case XPATH_BOOLEAN: 5558 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) { 5559 XP_CACHE_ADD(cache->booleanObjs, obj); 5560 goto obj_cached; 5561 } 5562 break; 5563 case XPATH_NUMBER: 5564 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) { 5565 XP_CACHE_ADD(cache->numberObjs, obj); 5566 goto obj_cached; 5567 } 5568 break; 5569 #ifdef LIBXML_XPTR_ENABLED 5570 case XPATH_LOCATIONSET: 5571 if (obj->user != NULL) { 5572 xmlXPtrFreeLocationSet(obj->user); 5573 } 5574 goto free_obj; 5575 #endif 5576 default: 5577 goto free_obj; 5578 } 5579 5580 /* 5581 * Fallback to adding to the misc-objects slot. 5582 */ 5583 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) { 5584 XP_CACHE_ADD(cache->miscObjs, obj); 5585 } else 5586 goto free_obj; 5587 5588 obj_cached: 5589 5590 #ifdef XP_DEBUG_OBJ_USAGE 5591 xmlXPathDebugObjUsageReleased(ctxt, obj->type); 5592 #endif 5593 5594 if (obj->nodesetval != NULL) { 5595 xmlNodeSetPtr tmpset = obj->nodesetval; 5596 5597 /* 5598 * TODO: Due to those nasty ns-nodes, we need to traverse 5599 * the list and free the ns-nodes. 5600 * URGENT TODO: Check if it's actually slowing things down. 5601 * Maybe we shouldn't try to preserve the list. 5602 */ 5603 if (tmpset->nodeNr > 1) { 5604 int i; 5605 xmlNodePtr node; 5606 5607 for (i = 0; i < tmpset->nodeNr; i++) { 5608 node = tmpset->nodeTab[i]; 5609 if ((node != NULL) && 5610 (node->type == XML_NAMESPACE_DECL)) 5611 { 5612 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 5613 } 5614 } 5615 } else if (tmpset->nodeNr == 1) { 5616 if ((tmpset->nodeTab[0] != NULL) && 5617 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL)) 5618 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]); 5619 } 5620 tmpset->nodeNr = 0; 5621 memset(obj, 0, sizeof(xmlXPathObject)); 5622 obj->nodesetval = tmpset; 5623 } else 5624 memset(obj, 0, sizeof(xmlXPathObject)); 5625 5626 return; 5627 5628 free_obj: 5629 /* 5630 * Cache is full; free the object. 5631 */ 5632 if (obj->nodesetval != NULL) 5633 xmlXPathFreeNodeSet(obj->nodesetval); 5634 #ifdef XP_DEBUG_OBJ_USAGE 5635 xmlXPathDebugObjUsageReleased(NULL, obj->type); 5636 #endif 5637 xmlFree(obj); 5638 } 5639 return; 5640 } 5641 5642 5643 /************************************************************************ 5644 * * 5645 * Type Casting Routines * 5646 * * 5647 ************************************************************************/ 5648 5649 /** 5650 * xmlXPathCastBooleanToString: 5651 * @val: a boolean 5652 * 5653 * Converts a boolean to its string value. 5654 * 5655 * Returns a newly allocated string. 5656 */ 5657 xmlChar * 5658 xmlXPathCastBooleanToString (int val) { 5659 xmlChar *ret; 5660 if (val) 5661 ret = xmlStrdup((const xmlChar *) "true"); 5662 else 5663 ret = xmlStrdup((const xmlChar *) "false"); 5664 return(ret); 5665 } 5666 5667 /** 5668 * xmlXPathCastNumberToString: 5669 * @val: a number 5670 * 5671 * Converts a number to its string value. 5672 * 5673 * Returns a newly allocated string. 5674 */ 5675 xmlChar * 5676 xmlXPathCastNumberToString (double val) { 5677 xmlChar *ret; 5678 switch (xmlXPathIsInf(val)) { 5679 case 1: 5680 ret = xmlStrdup((const xmlChar *) "Infinity"); 5681 break; 5682 case -1: 5683 ret = xmlStrdup((const xmlChar *) "-Infinity"); 5684 break; 5685 default: 5686 if (xmlXPathIsNaN(val)) { 5687 ret = xmlStrdup((const xmlChar *) "NaN"); 5688 } else if (val == 0) { 5689 /* Omit sign for negative zero. */ 5690 ret = xmlStrdup((const xmlChar *) "0"); 5691 } else { 5692 /* could be improved */ 5693 char buf[100]; 5694 xmlXPathFormatNumber(val, buf, 99); 5695 buf[99] = 0; 5696 ret = xmlStrdup((const xmlChar *) buf); 5697 } 5698 } 5699 return(ret); 5700 } 5701 5702 /** 5703 * xmlXPathCastNodeToString: 5704 * @node: a node 5705 * 5706 * Converts a node to its string value. 5707 * 5708 * Returns a newly allocated string. 5709 */ 5710 xmlChar * 5711 xmlXPathCastNodeToString (xmlNodePtr node) { 5712 xmlChar *ret; 5713 if ((ret = xmlNodeGetContent(node)) == NULL) 5714 ret = xmlStrdup((const xmlChar *) ""); 5715 return(ret); 5716 } 5717 5718 /** 5719 * xmlXPathCastNodeSetToString: 5720 * @ns: a node-set 5721 * 5722 * Converts a node-set to its string value. 5723 * 5724 * Returns a newly allocated string. 5725 */ 5726 xmlChar * 5727 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) { 5728 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL)) 5729 return(xmlStrdup((const xmlChar *) "")); 5730 5731 if (ns->nodeNr > 1) 5732 xmlXPathNodeSetSort(ns); 5733 return(xmlXPathCastNodeToString(ns->nodeTab[0])); 5734 } 5735 5736 /** 5737 * xmlXPathCastToString: 5738 * @val: an XPath object 5739 * 5740 * Converts an existing object to its string() equivalent 5741 * 5742 * Returns the allocated string value of the object, NULL in case of error. 5743 * It's up to the caller to free the string memory with xmlFree(). 5744 */ 5745 xmlChar * 5746 xmlXPathCastToString(xmlXPathObjectPtr val) { 5747 xmlChar *ret = NULL; 5748 5749 if (val == NULL) 5750 return(xmlStrdup((const xmlChar *) "")); 5751 switch (val->type) { 5752 case XPATH_UNDEFINED: 5753 #ifdef DEBUG_EXPR 5754 xmlGenericError(xmlGenericErrorContext, "String: undefined\n"); 5755 #endif 5756 ret = xmlStrdup((const xmlChar *) ""); 5757 break; 5758 case XPATH_NODESET: 5759 case XPATH_XSLT_TREE: 5760 ret = xmlXPathCastNodeSetToString(val->nodesetval); 5761 break; 5762 case XPATH_STRING: 5763 return(xmlStrdup(val->stringval)); 5764 case XPATH_BOOLEAN: 5765 ret = xmlXPathCastBooleanToString(val->boolval); 5766 break; 5767 case XPATH_NUMBER: { 5768 ret = xmlXPathCastNumberToString(val->floatval); 5769 break; 5770 } 5771 case XPATH_USERS: 5772 case XPATH_POINT: 5773 case XPATH_RANGE: 5774 case XPATH_LOCATIONSET: 5775 TODO 5776 ret = xmlStrdup((const xmlChar *) ""); 5777 break; 5778 } 5779 return(ret); 5780 } 5781 5782 /** 5783 * xmlXPathConvertString: 5784 * @val: an XPath object 5785 * 5786 * Converts an existing object to its string() equivalent 5787 * 5788 * Returns the new object, the old one is freed (or the operation 5789 * is done directly on @val) 5790 */ 5791 xmlXPathObjectPtr 5792 xmlXPathConvertString(xmlXPathObjectPtr val) { 5793 xmlChar *res = NULL; 5794 5795 if (val == NULL) 5796 return(xmlXPathNewCString("")); 5797 5798 switch (val->type) { 5799 case XPATH_UNDEFINED: 5800 #ifdef DEBUG_EXPR 5801 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n"); 5802 #endif 5803 break; 5804 case XPATH_NODESET: 5805 case XPATH_XSLT_TREE: 5806 res = xmlXPathCastNodeSetToString(val->nodesetval); 5807 break; 5808 case XPATH_STRING: 5809 return(val); 5810 case XPATH_BOOLEAN: 5811 res = xmlXPathCastBooleanToString(val->boolval); 5812 break; 5813 case XPATH_NUMBER: 5814 res = xmlXPathCastNumberToString(val->floatval); 5815 break; 5816 case XPATH_USERS: 5817 case XPATH_POINT: 5818 case XPATH_RANGE: 5819 case XPATH_LOCATIONSET: 5820 TODO; 5821 break; 5822 } 5823 xmlXPathFreeObject(val); 5824 if (res == NULL) 5825 return(xmlXPathNewCString("")); 5826 return(xmlXPathWrapString(res)); 5827 } 5828 5829 /** 5830 * xmlXPathCastBooleanToNumber: 5831 * @val: a boolean 5832 * 5833 * Converts a boolean to its number value 5834 * 5835 * Returns the number value 5836 */ 5837 double 5838 xmlXPathCastBooleanToNumber(int val) { 5839 if (val) 5840 return(1.0); 5841 return(0.0); 5842 } 5843 5844 /** 5845 * xmlXPathCastStringToNumber: 5846 * @val: a string 5847 * 5848 * Converts a string to its number value 5849 * 5850 * Returns the number value 5851 */ 5852 double 5853 xmlXPathCastStringToNumber(const xmlChar * val) { 5854 return(xmlXPathStringEvalNumber(val)); 5855 } 5856 5857 /** 5858 * xmlXPathCastNodeToNumber: 5859 * @node: a node 5860 * 5861 * Converts a node to its number value 5862 * 5863 * Returns the number value 5864 */ 5865 double 5866 xmlXPathCastNodeToNumber (xmlNodePtr node) { 5867 xmlChar *strval; 5868 double ret; 5869 5870 if (node == NULL) 5871 return(xmlXPathNAN); 5872 strval = xmlXPathCastNodeToString(node); 5873 if (strval == NULL) 5874 return(xmlXPathNAN); 5875 ret = xmlXPathCastStringToNumber(strval); 5876 xmlFree(strval); 5877 5878 return(ret); 5879 } 5880 5881 /** 5882 * xmlXPathCastNodeSetToNumber: 5883 * @ns: a node-set 5884 * 5885 * Converts a node-set to its number value 5886 * 5887 * Returns the number value 5888 */ 5889 double 5890 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) { 5891 xmlChar *str; 5892 double ret; 5893 5894 if (ns == NULL) 5895 return(xmlXPathNAN); 5896 str = xmlXPathCastNodeSetToString(ns); 5897 ret = xmlXPathCastStringToNumber(str); 5898 xmlFree(str); 5899 return(ret); 5900 } 5901 5902 /** 5903 * xmlXPathCastToNumber: 5904 * @val: an XPath object 5905 * 5906 * Converts an XPath object to its number value 5907 * 5908 * Returns the number value 5909 */ 5910 double 5911 xmlXPathCastToNumber(xmlXPathObjectPtr val) { 5912 double ret = 0.0; 5913 5914 if (val == NULL) 5915 return(xmlXPathNAN); 5916 switch (val->type) { 5917 case XPATH_UNDEFINED: 5918 #ifdef DEBUG_EXPR 5919 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n"); 5920 #endif 5921 ret = xmlXPathNAN; 5922 break; 5923 case XPATH_NODESET: 5924 case XPATH_XSLT_TREE: 5925 ret = xmlXPathCastNodeSetToNumber(val->nodesetval); 5926 break; 5927 case XPATH_STRING: 5928 ret = xmlXPathCastStringToNumber(val->stringval); 5929 break; 5930 case XPATH_NUMBER: 5931 ret = val->floatval; 5932 break; 5933 case XPATH_BOOLEAN: 5934 ret = xmlXPathCastBooleanToNumber(val->boolval); 5935 break; 5936 case XPATH_USERS: 5937 case XPATH_POINT: 5938 case XPATH_RANGE: 5939 case XPATH_LOCATIONSET: 5940 TODO; 5941 ret = xmlXPathNAN; 5942 break; 5943 } 5944 return(ret); 5945 } 5946 5947 /** 5948 * xmlXPathConvertNumber: 5949 * @val: an XPath object 5950 * 5951 * Converts an existing object to its number() equivalent 5952 * 5953 * Returns the new object, the old one is freed (or the operation 5954 * is done directly on @val) 5955 */ 5956 xmlXPathObjectPtr 5957 xmlXPathConvertNumber(xmlXPathObjectPtr val) { 5958 xmlXPathObjectPtr ret; 5959 5960 if (val == NULL) 5961 return(xmlXPathNewFloat(0.0)); 5962 if (val->type == XPATH_NUMBER) 5963 return(val); 5964 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val)); 5965 xmlXPathFreeObject(val); 5966 return(ret); 5967 } 5968 5969 /** 5970 * xmlXPathCastNumberToBoolean: 5971 * @val: a number 5972 * 5973 * Converts a number to its boolean value 5974 * 5975 * Returns the boolean value 5976 */ 5977 int 5978 xmlXPathCastNumberToBoolean (double val) { 5979 if (xmlXPathIsNaN(val) || (val == 0.0)) 5980 return(0); 5981 return(1); 5982 } 5983 5984 /** 5985 * xmlXPathCastStringToBoolean: 5986 * @val: a string 5987 * 5988 * Converts a string to its boolean value 5989 * 5990 * Returns the boolean value 5991 */ 5992 int 5993 xmlXPathCastStringToBoolean (const xmlChar *val) { 5994 if ((val == NULL) || (xmlStrlen(val) == 0)) 5995 return(0); 5996 return(1); 5997 } 5998 5999 /** 6000 * xmlXPathCastNodeSetToBoolean: 6001 * @ns: a node-set 6002 * 6003 * Converts a node-set to its boolean value 6004 * 6005 * Returns the boolean value 6006 */ 6007 int 6008 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) { 6009 if ((ns == NULL) || (ns->nodeNr == 0)) 6010 return(0); 6011 return(1); 6012 } 6013 6014 /** 6015 * xmlXPathCastToBoolean: 6016 * @val: an XPath object 6017 * 6018 * Converts an XPath object to its boolean value 6019 * 6020 * Returns the boolean value 6021 */ 6022 int 6023 xmlXPathCastToBoolean (xmlXPathObjectPtr val) { 6024 int ret = 0; 6025 6026 if (val == NULL) 6027 return(0); 6028 switch (val->type) { 6029 case XPATH_UNDEFINED: 6030 #ifdef DEBUG_EXPR 6031 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n"); 6032 #endif 6033 ret = 0; 6034 break; 6035 case XPATH_NODESET: 6036 case XPATH_XSLT_TREE: 6037 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval); 6038 break; 6039 case XPATH_STRING: 6040 ret = xmlXPathCastStringToBoolean(val->stringval); 6041 break; 6042 case XPATH_NUMBER: 6043 ret = xmlXPathCastNumberToBoolean(val->floatval); 6044 break; 6045 case XPATH_BOOLEAN: 6046 ret = val->boolval; 6047 break; 6048 case XPATH_USERS: 6049 case XPATH_POINT: 6050 case XPATH_RANGE: 6051 case XPATH_LOCATIONSET: 6052 TODO; 6053 ret = 0; 6054 break; 6055 } 6056 return(ret); 6057 } 6058 6059 6060 /** 6061 * xmlXPathConvertBoolean: 6062 * @val: an XPath object 6063 * 6064 * Converts an existing object to its boolean() equivalent 6065 * 6066 * Returns the new object, the old one is freed (or the operation 6067 * is done directly on @val) 6068 */ 6069 xmlXPathObjectPtr 6070 xmlXPathConvertBoolean(xmlXPathObjectPtr val) { 6071 xmlXPathObjectPtr ret; 6072 6073 if (val == NULL) 6074 return(xmlXPathNewBoolean(0)); 6075 if (val->type == XPATH_BOOLEAN) 6076 return(val); 6077 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val)); 6078 xmlXPathFreeObject(val); 6079 return(ret); 6080 } 6081 6082 /************************************************************************ 6083 * * 6084 * Routines to handle XPath contexts * 6085 * * 6086 ************************************************************************/ 6087 6088 /** 6089 * xmlXPathNewContext: 6090 * @doc: the XML document 6091 * 6092 * Create a new xmlXPathContext 6093 * 6094 * Returns the xmlXPathContext just allocated. The caller will need to free it. 6095 */ 6096 xmlXPathContextPtr 6097 xmlXPathNewContext(xmlDocPtr doc) { 6098 xmlXPathContextPtr ret; 6099 6100 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext)); 6101 if (ret == NULL) { 6102 xmlXPathErrMemory(NULL, "creating context\n"); 6103 return(NULL); 6104 } 6105 memset(ret, 0 , (size_t) sizeof(xmlXPathContext)); 6106 ret->doc = doc; 6107 ret->node = NULL; 6108 6109 ret->varHash = NULL; 6110 6111 ret->nb_types = 0; 6112 ret->max_types = 0; 6113 ret->types = NULL; 6114 6115 ret->funcHash = xmlHashCreate(0); 6116 6117 ret->nb_axis = 0; 6118 ret->max_axis = 0; 6119 ret->axis = NULL; 6120 6121 ret->nsHash = NULL; 6122 ret->user = NULL; 6123 6124 ret->contextSize = -1; 6125 ret->proximityPosition = -1; 6126 6127 #ifdef XP_DEFAULT_CACHE_ON 6128 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) { 6129 xmlXPathFreeContext(ret); 6130 return(NULL); 6131 } 6132 #endif 6133 6134 xmlXPathRegisterAllFunctions(ret); 6135 6136 return(ret); 6137 } 6138 6139 /** 6140 * xmlXPathFreeContext: 6141 * @ctxt: the context to free 6142 * 6143 * Free up an xmlXPathContext 6144 */ 6145 void 6146 xmlXPathFreeContext(xmlXPathContextPtr ctxt) { 6147 if (ctxt == NULL) return; 6148 6149 if (ctxt->cache != NULL) 6150 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache); 6151 xmlXPathRegisteredNsCleanup(ctxt); 6152 xmlXPathRegisteredFuncsCleanup(ctxt); 6153 xmlXPathRegisteredVariablesCleanup(ctxt); 6154 xmlResetError(&ctxt->lastError); 6155 xmlFree(ctxt); 6156 } 6157 6158 /************************************************************************ 6159 * * 6160 * Routines to handle XPath parser contexts * 6161 * * 6162 ************************************************************************/ 6163 6164 #define CHECK_CTXT(ctxt) \ 6165 if (ctxt == NULL) { \ 6166 __xmlRaiseError(NULL, NULL, NULL, \ 6167 NULL, NULL, XML_FROM_XPATH, \ 6168 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \ 6169 __FILE__, __LINE__, \ 6170 NULL, NULL, NULL, 0, 0, \ 6171 "NULL context pointer\n"); \ 6172 return(NULL); \ 6173 } \ 6174 6175 #define CHECK_CTXT_NEG(ctxt) \ 6176 if (ctxt == NULL) { \ 6177 __xmlRaiseError(NULL, NULL, NULL, \ 6178 NULL, NULL, XML_FROM_XPATH, \ 6179 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \ 6180 __FILE__, __LINE__, \ 6181 NULL, NULL, NULL, 0, 0, \ 6182 "NULL context pointer\n"); \ 6183 return(-1); \ 6184 } \ 6185 6186 6187 #define CHECK_CONTEXT(ctxt) \ 6188 if ((ctxt == NULL) || (ctxt->doc == NULL) || \ 6189 (ctxt->doc->children == NULL)) { \ 6190 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \ 6191 return(NULL); \ 6192 } 6193 6194 6195 /** 6196 * xmlXPathNewParserContext: 6197 * @str: the XPath expression 6198 * @ctxt: the XPath context 6199 * 6200 * Create a new xmlXPathParserContext 6201 * 6202 * Returns the xmlXPathParserContext just allocated. 6203 */ 6204 xmlXPathParserContextPtr 6205 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) { 6206 xmlXPathParserContextPtr ret; 6207 6208 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext)); 6209 if (ret == NULL) { 6210 xmlXPathErrMemory(ctxt, "creating parser context\n"); 6211 return(NULL); 6212 } 6213 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext)); 6214 ret->cur = ret->base = str; 6215 ret->context = ctxt; 6216 6217 ret->comp = xmlXPathNewCompExpr(); 6218 if (ret->comp == NULL) { 6219 xmlFree(ret->valueTab); 6220 xmlFree(ret); 6221 return(NULL); 6222 } 6223 if ((ctxt != NULL) && (ctxt->dict != NULL)) { 6224 ret->comp->dict = ctxt->dict; 6225 xmlDictReference(ret->comp->dict); 6226 } 6227 6228 return(ret); 6229 } 6230 6231 /** 6232 * xmlXPathCompParserContext: 6233 * @comp: the XPath compiled expression 6234 * @ctxt: the XPath context 6235 * 6236 * Create a new xmlXPathParserContext when processing a compiled expression 6237 * 6238 * Returns the xmlXPathParserContext just allocated. 6239 */ 6240 static xmlXPathParserContextPtr 6241 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) { 6242 xmlXPathParserContextPtr ret; 6243 6244 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext)); 6245 if (ret == NULL) { 6246 xmlXPathErrMemory(ctxt, "creating evaluation context\n"); 6247 return(NULL); 6248 } 6249 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext)); 6250 6251 /* Allocate the value stack */ 6252 ret->valueTab = (xmlXPathObjectPtr *) 6253 xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); 6254 if (ret->valueTab == NULL) { 6255 xmlFree(ret); 6256 xmlXPathErrMemory(ctxt, "creating evaluation context\n"); 6257 return(NULL); 6258 } 6259 ret->valueNr = 0; 6260 ret->valueMax = 10; 6261 ret->value = NULL; 6262 ret->valueFrame = 0; 6263 6264 ret->context = ctxt; 6265 ret->comp = comp; 6266 6267 return(ret); 6268 } 6269 6270 /** 6271 * xmlXPathFreeParserContext: 6272 * @ctxt: the context to free 6273 * 6274 * Free up an xmlXPathParserContext 6275 */ 6276 void 6277 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) { 6278 int i; 6279 6280 if (ctxt->valueTab != NULL) { 6281 for (i = 0; i < ctxt->valueNr; i++) { 6282 if (ctxt->context) 6283 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]); 6284 else 6285 xmlXPathFreeObject(ctxt->valueTab[i]); 6286 } 6287 xmlFree(ctxt->valueTab); 6288 } 6289 if (ctxt->comp != NULL) { 6290 #ifdef XPATH_STREAMING 6291 if (ctxt->comp->stream != NULL) { 6292 xmlFreePatternList(ctxt->comp->stream); 6293 ctxt->comp->stream = NULL; 6294 } 6295 #endif 6296 xmlXPathFreeCompExpr(ctxt->comp); 6297 } 6298 xmlFree(ctxt); 6299 } 6300 6301 /************************************************************************ 6302 * * 6303 * The implicit core function library * 6304 * * 6305 ************************************************************************/ 6306 6307 /** 6308 * xmlXPathNodeValHash: 6309 * @node: a node pointer 6310 * 6311 * Function computing the beginning of the string value of the node, 6312 * used to speed up comparisons 6313 * 6314 * Returns an int usable as a hash 6315 */ 6316 static unsigned int 6317 xmlXPathNodeValHash(xmlNodePtr node) { 6318 int len = 2; 6319 const xmlChar * string = NULL; 6320 xmlNodePtr tmp = NULL; 6321 unsigned int ret = 0; 6322 6323 if (node == NULL) 6324 return(0); 6325 6326 if (node->type == XML_DOCUMENT_NODE) { 6327 tmp = xmlDocGetRootElement((xmlDocPtr) node); 6328 if (tmp == NULL) 6329 node = node->children; 6330 else 6331 node = tmp; 6332 6333 if (node == NULL) 6334 return(0); 6335 } 6336 6337 switch (node->type) { 6338 case XML_COMMENT_NODE: 6339 case XML_PI_NODE: 6340 case XML_CDATA_SECTION_NODE: 6341 case XML_TEXT_NODE: 6342 string = node->content; 6343 if (string == NULL) 6344 return(0); 6345 if (string[0] == 0) 6346 return(0); 6347 return(((unsigned int) string[0]) + 6348 (((unsigned int) string[1]) << 8)); 6349 case XML_NAMESPACE_DECL: 6350 string = ((xmlNsPtr)node)->href; 6351 if (string == NULL) 6352 return(0); 6353 if (string[0] == 0) 6354 return(0); 6355 return(((unsigned int) string[0]) + 6356 (((unsigned int) string[1]) << 8)); 6357 case XML_ATTRIBUTE_NODE: 6358 tmp = ((xmlAttrPtr) node)->children; 6359 break; 6360 case XML_ELEMENT_NODE: 6361 tmp = node->children; 6362 break; 6363 default: 6364 return(0); 6365 } 6366 while (tmp != NULL) { 6367 switch (tmp->type) { 6368 case XML_CDATA_SECTION_NODE: 6369 case XML_TEXT_NODE: 6370 string = tmp->content; 6371 break; 6372 default: 6373 string = NULL; 6374 break; 6375 } 6376 if ((string != NULL) && (string[0] != 0)) { 6377 if (len == 1) { 6378 return(ret + (((unsigned int) string[0]) << 8)); 6379 } 6380 if (string[1] == 0) { 6381 len = 1; 6382 ret = (unsigned int) string[0]; 6383 } else { 6384 return(((unsigned int) string[0]) + 6385 (((unsigned int) string[1]) << 8)); 6386 } 6387 } 6388 /* 6389 * Skip to next node 6390 */ 6391 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) { 6392 if (tmp->children->type != XML_ENTITY_DECL) { 6393 tmp = tmp->children; 6394 continue; 6395 } 6396 } 6397 if (tmp == node) 6398 break; 6399 6400 if (tmp->next != NULL) { 6401 tmp = tmp->next; 6402 continue; 6403 } 6404 6405 do { 6406 tmp = tmp->parent; 6407 if (tmp == NULL) 6408 break; 6409 if (tmp == node) { 6410 tmp = NULL; 6411 break; 6412 } 6413 if (tmp->next != NULL) { 6414 tmp = tmp->next; 6415 break; 6416 } 6417 } while (tmp != NULL); 6418 } 6419 return(ret); 6420 } 6421 6422 /** 6423 * xmlXPathStringHash: 6424 * @string: a string 6425 * 6426 * Function computing the beginning of the string value of the node, 6427 * used to speed up comparisons 6428 * 6429 * Returns an int usable as a hash 6430 */ 6431 static unsigned int 6432 xmlXPathStringHash(const xmlChar * string) { 6433 if (string == NULL) 6434 return((unsigned int) 0); 6435 if (string[0] == 0) 6436 return(0); 6437 return(((unsigned int) string[0]) + 6438 (((unsigned int) string[1]) << 8)); 6439 } 6440 6441 /** 6442 * xmlXPathCompareNodeSetFloat: 6443 * @ctxt: the XPath Parser context 6444 * @inf: less than (1) or greater than (0) 6445 * @strict: is the comparison strict 6446 * @arg: the node set 6447 * @f: the value 6448 * 6449 * Implement the compare operation between a nodeset and a number 6450 * @ns < @val (1, 1, ... 6451 * @ns <= @val (1, 0, ... 6452 * @ns > @val (0, 1, ... 6453 * @ns >= @val (0, 0, ... 6454 * 6455 * If one object to be compared is a node-set and the other is a number, 6456 * then the comparison will be true if and only if there is a node in the 6457 * node-set such that the result of performing the comparison on the number 6458 * to be compared and on the result of converting the string-value of that 6459 * node to a number using the number function is true. 6460 * 6461 * Returns 0 or 1 depending on the results of the test. 6462 */ 6463 static int 6464 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict, 6465 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) { 6466 int i, ret = 0; 6467 xmlNodeSetPtr ns; 6468 xmlChar *str2; 6469 6470 if ((f == NULL) || (arg == NULL) || 6471 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) { 6472 xmlXPathReleaseObject(ctxt->context, arg); 6473 xmlXPathReleaseObject(ctxt->context, f); 6474 return(0); 6475 } 6476 ns = arg->nodesetval; 6477 if (ns != NULL) { 6478 for (i = 0;i < ns->nodeNr;i++) { 6479 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 6480 if (str2 != NULL) { 6481 valuePush(ctxt, 6482 xmlXPathCacheNewString(ctxt->context, str2)); 6483 xmlFree(str2); 6484 xmlXPathNumberFunction(ctxt, 1); 6485 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f)); 6486 ret = xmlXPathCompareValues(ctxt, inf, strict); 6487 if (ret) 6488 break; 6489 } 6490 } 6491 } 6492 xmlXPathReleaseObject(ctxt->context, arg); 6493 xmlXPathReleaseObject(ctxt->context, f); 6494 return(ret); 6495 } 6496 6497 /** 6498 * xmlXPathCompareNodeSetString: 6499 * @ctxt: the XPath Parser context 6500 * @inf: less than (1) or greater than (0) 6501 * @strict: is the comparison strict 6502 * @arg: the node set 6503 * @s: the value 6504 * 6505 * Implement the compare operation between a nodeset and a string 6506 * @ns < @val (1, 1, ... 6507 * @ns <= @val (1, 0, ... 6508 * @ns > @val (0, 1, ... 6509 * @ns >= @val (0, 0, ... 6510 * 6511 * If one object to be compared is a node-set and the other is a string, 6512 * then the comparison will be true if and only if there is a node in 6513 * the node-set such that the result of performing the comparison on the 6514 * string-value of the node and the other string is true. 6515 * 6516 * Returns 0 or 1 depending on the results of the test. 6517 */ 6518 static int 6519 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict, 6520 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) { 6521 int i, ret = 0; 6522 xmlNodeSetPtr ns; 6523 xmlChar *str2; 6524 6525 if ((s == NULL) || (arg == NULL) || 6526 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) { 6527 xmlXPathReleaseObject(ctxt->context, arg); 6528 xmlXPathReleaseObject(ctxt->context, s); 6529 return(0); 6530 } 6531 ns = arg->nodesetval; 6532 if (ns != NULL) { 6533 for (i = 0;i < ns->nodeNr;i++) { 6534 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 6535 if (str2 != NULL) { 6536 valuePush(ctxt, 6537 xmlXPathCacheNewString(ctxt->context, str2)); 6538 xmlFree(str2); 6539 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s)); 6540 ret = xmlXPathCompareValues(ctxt, inf, strict); 6541 if (ret) 6542 break; 6543 } 6544 } 6545 } 6546 xmlXPathReleaseObject(ctxt->context, arg); 6547 xmlXPathReleaseObject(ctxt->context, s); 6548 return(ret); 6549 } 6550 6551 /** 6552 * xmlXPathCompareNodeSets: 6553 * @inf: less than (1) or greater than (0) 6554 * @strict: is the comparison strict 6555 * @arg1: the first node set object 6556 * @arg2: the second node set object 6557 * 6558 * Implement the compare operation on nodesets: 6559 * 6560 * If both objects to be compared are node-sets, then the comparison 6561 * will be true if and only if there is a node in the first node-set 6562 * and a node in the second node-set such that the result of performing 6563 * the comparison on the string-values of the two nodes is true. 6564 * .... 6565 * When neither object to be compared is a node-set and the operator 6566 * is <=, <, >= or >, then the objects are compared by converting both 6567 * objects to numbers and comparing the numbers according to IEEE 754. 6568 * .... 6569 * The number function converts its argument to a number as follows: 6570 * - a string that consists of optional whitespace followed by an 6571 * optional minus sign followed by a Number followed by whitespace 6572 * is converted to the IEEE 754 number that is nearest (according 6573 * to the IEEE 754 round-to-nearest rule) to the mathematical value 6574 * represented by the string; any other string is converted to NaN 6575 * 6576 * Conclusion all nodes need to be converted first to their string value 6577 * and then the comparison must be done when possible 6578 */ 6579 static int 6580 xmlXPathCompareNodeSets(int inf, int strict, 6581 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) { 6582 int i, j, init = 0; 6583 double val1; 6584 double *values2; 6585 int ret = 0; 6586 xmlNodeSetPtr ns1; 6587 xmlNodeSetPtr ns2; 6588 6589 if ((arg1 == NULL) || 6590 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) { 6591 xmlXPathFreeObject(arg2); 6592 return(0); 6593 } 6594 if ((arg2 == NULL) || 6595 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) { 6596 xmlXPathFreeObject(arg1); 6597 xmlXPathFreeObject(arg2); 6598 return(0); 6599 } 6600 6601 ns1 = arg1->nodesetval; 6602 ns2 = arg2->nodesetval; 6603 6604 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) { 6605 xmlXPathFreeObject(arg1); 6606 xmlXPathFreeObject(arg2); 6607 return(0); 6608 } 6609 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) { 6610 xmlXPathFreeObject(arg1); 6611 xmlXPathFreeObject(arg2); 6612 return(0); 6613 } 6614 6615 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double)); 6616 if (values2 == NULL) { 6617 /* TODO: Propagate memory error. */ 6618 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6619 xmlXPathFreeObject(arg1); 6620 xmlXPathFreeObject(arg2); 6621 return(0); 6622 } 6623 for (i = 0;i < ns1->nodeNr;i++) { 6624 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]); 6625 if (xmlXPathIsNaN(val1)) 6626 continue; 6627 for (j = 0;j < ns2->nodeNr;j++) { 6628 if (init == 0) { 6629 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]); 6630 } 6631 if (xmlXPathIsNaN(values2[j])) 6632 continue; 6633 if (inf && strict) 6634 ret = (val1 < values2[j]); 6635 else if (inf && !strict) 6636 ret = (val1 <= values2[j]); 6637 else if (!inf && strict) 6638 ret = (val1 > values2[j]); 6639 else if (!inf && !strict) 6640 ret = (val1 >= values2[j]); 6641 if (ret) 6642 break; 6643 } 6644 if (ret) 6645 break; 6646 init = 1; 6647 } 6648 xmlFree(values2); 6649 xmlXPathFreeObject(arg1); 6650 xmlXPathFreeObject(arg2); 6651 return(ret); 6652 } 6653 6654 /** 6655 * xmlXPathCompareNodeSetValue: 6656 * @ctxt: the XPath Parser context 6657 * @inf: less than (1) or greater than (0) 6658 * @strict: is the comparison strict 6659 * @arg: the node set 6660 * @val: the value 6661 * 6662 * Implement the compare operation between a nodeset and a value 6663 * @ns < @val (1, 1, ... 6664 * @ns <= @val (1, 0, ... 6665 * @ns > @val (0, 1, ... 6666 * @ns >= @val (0, 0, ... 6667 * 6668 * If one object to be compared is a node-set and the other is a boolean, 6669 * then the comparison will be true if and only if the result of performing 6670 * the comparison on the boolean and on the result of converting 6671 * the node-set to a boolean using the boolean function is true. 6672 * 6673 * Returns 0 or 1 depending on the results of the test. 6674 */ 6675 static int 6676 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict, 6677 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) { 6678 if ((val == NULL) || (arg == NULL) || 6679 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 6680 return(0); 6681 6682 switch(val->type) { 6683 case XPATH_NUMBER: 6684 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val)); 6685 case XPATH_NODESET: 6686 case XPATH_XSLT_TREE: 6687 return(xmlXPathCompareNodeSets(inf, strict, arg, val)); 6688 case XPATH_STRING: 6689 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val)); 6690 case XPATH_BOOLEAN: 6691 valuePush(ctxt, arg); 6692 xmlXPathBooleanFunction(ctxt, 1); 6693 valuePush(ctxt, val); 6694 return(xmlXPathCompareValues(ctxt, inf, strict)); 6695 default: 6696 xmlGenericError(xmlGenericErrorContext, 6697 "xmlXPathCompareNodeSetValue: Can't compare node set " 6698 "and object of type %d\n", 6699 val->type); 6700 xmlXPathReleaseObject(ctxt->context, arg); 6701 xmlXPathReleaseObject(ctxt->context, val); 6702 XP_ERROR0(XPATH_INVALID_TYPE); 6703 } 6704 return(0); 6705 } 6706 6707 /** 6708 * xmlXPathEqualNodeSetString: 6709 * @arg: the nodeset object argument 6710 * @str: the string to compare to. 6711 * @neq: flag to show whether for '=' (0) or '!=' (1) 6712 * 6713 * Implement the equal operation on XPath objects content: @arg1 == @arg2 6714 * If one object to be compared is a node-set and the other is a string, 6715 * then the comparison will be true if and only if there is a node in 6716 * the node-set such that the result of performing the comparison on the 6717 * string-value of the node and the other string is true. 6718 * 6719 * Returns 0 or 1 depending on the results of the test. 6720 */ 6721 static int 6722 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq) 6723 { 6724 int i; 6725 xmlNodeSetPtr ns; 6726 xmlChar *str2; 6727 unsigned int hash; 6728 6729 if ((str == NULL) || (arg == NULL) || 6730 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 6731 return (0); 6732 ns = arg->nodesetval; 6733 /* 6734 * A NULL nodeset compared with a string is always false 6735 * (since there is no node equal, and no node not equal) 6736 */ 6737 if ((ns == NULL) || (ns->nodeNr <= 0) ) 6738 return (0); 6739 hash = xmlXPathStringHash(str); 6740 for (i = 0; i < ns->nodeNr; i++) { 6741 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) { 6742 str2 = xmlNodeGetContent(ns->nodeTab[i]); 6743 if ((str2 != NULL) && (xmlStrEqual(str, str2))) { 6744 xmlFree(str2); 6745 if (neq) 6746 continue; 6747 return (1); 6748 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) { 6749 if (neq) 6750 continue; 6751 return (1); 6752 } else if (neq) { 6753 if (str2 != NULL) 6754 xmlFree(str2); 6755 return (1); 6756 } 6757 if (str2 != NULL) 6758 xmlFree(str2); 6759 } else if (neq) 6760 return (1); 6761 } 6762 return (0); 6763 } 6764 6765 /** 6766 * xmlXPathEqualNodeSetFloat: 6767 * @arg: the nodeset object argument 6768 * @f: the float to compare to 6769 * @neq: flag to show whether to compare '=' (0) or '!=' (1) 6770 * 6771 * Implement the equal operation on XPath objects content: @arg1 == @arg2 6772 * If one object to be compared is a node-set and the other is a number, 6773 * then the comparison will be true if and only if there is a node in 6774 * the node-set such that the result of performing the comparison on the 6775 * number to be compared and on the result of converting the string-value 6776 * of that node to a number using the number function is true. 6777 * 6778 * Returns 0 or 1 depending on the results of the test. 6779 */ 6780 static int 6781 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt, 6782 xmlXPathObjectPtr arg, double f, int neq) { 6783 int i, ret=0; 6784 xmlNodeSetPtr ns; 6785 xmlChar *str2; 6786 xmlXPathObjectPtr val; 6787 double v; 6788 6789 if ((arg == NULL) || 6790 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 6791 return(0); 6792 6793 ns = arg->nodesetval; 6794 if (ns != NULL) { 6795 for (i=0;i<ns->nodeNr;i++) { 6796 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 6797 if (str2 != NULL) { 6798 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2)); 6799 xmlFree(str2); 6800 xmlXPathNumberFunction(ctxt, 1); 6801 val = valuePop(ctxt); 6802 v = val->floatval; 6803 xmlXPathReleaseObject(ctxt->context, val); 6804 if (!xmlXPathIsNaN(v)) { 6805 if ((!neq) && (v==f)) { 6806 ret = 1; 6807 break; 6808 } else if ((neq) && (v!=f)) { 6809 ret = 1; 6810 break; 6811 } 6812 } else { /* NaN is unequal to any value */ 6813 if (neq) 6814 ret = 1; 6815 } 6816 } 6817 } 6818 } 6819 6820 return(ret); 6821 } 6822 6823 6824 /** 6825 * xmlXPathEqualNodeSets: 6826 * @arg1: first nodeset object argument 6827 * @arg2: second nodeset object argument 6828 * @neq: flag to show whether to test '=' (0) or '!=' (1) 6829 * 6830 * Implement the equal / not equal operation on XPath nodesets: 6831 * @arg1 == @arg2 or @arg1 != @arg2 6832 * If both objects to be compared are node-sets, then the comparison 6833 * will be true if and only if there is a node in the first node-set and 6834 * a node in the second node-set such that the result of performing the 6835 * comparison on the string-values of the two nodes is true. 6836 * 6837 * (needless to say, this is a costly operation) 6838 * 6839 * Returns 0 or 1 depending on the results of the test. 6840 */ 6841 static int 6842 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) { 6843 int i, j; 6844 unsigned int *hashs1; 6845 unsigned int *hashs2; 6846 xmlChar **values1; 6847 xmlChar **values2; 6848 int ret = 0; 6849 xmlNodeSetPtr ns1; 6850 xmlNodeSetPtr ns2; 6851 6852 if ((arg1 == NULL) || 6853 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) 6854 return(0); 6855 if ((arg2 == NULL) || 6856 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) 6857 return(0); 6858 6859 ns1 = arg1->nodesetval; 6860 ns2 = arg2->nodesetval; 6861 6862 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) 6863 return(0); 6864 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) 6865 return(0); 6866 6867 /* 6868 * for equal, check if there is a node pertaining to both sets 6869 */ 6870 if (neq == 0) 6871 for (i = 0;i < ns1->nodeNr;i++) 6872 for (j = 0;j < ns2->nodeNr;j++) 6873 if (ns1->nodeTab[i] == ns2->nodeTab[j]) 6874 return(1); 6875 6876 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *)); 6877 if (values1 == NULL) { 6878 /* TODO: Propagate memory error. */ 6879 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6880 return(0); 6881 } 6882 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int)); 6883 if (hashs1 == NULL) { 6884 /* TODO: Propagate memory error. */ 6885 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6886 xmlFree(values1); 6887 return(0); 6888 } 6889 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *)); 6890 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *)); 6891 if (values2 == NULL) { 6892 /* TODO: Propagate memory error. */ 6893 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6894 xmlFree(hashs1); 6895 xmlFree(values1); 6896 return(0); 6897 } 6898 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int)); 6899 if (hashs2 == NULL) { 6900 /* TODO: Propagate memory error. */ 6901 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6902 xmlFree(hashs1); 6903 xmlFree(values1); 6904 xmlFree(values2); 6905 return(0); 6906 } 6907 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *)); 6908 for (i = 0;i < ns1->nodeNr;i++) { 6909 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]); 6910 for (j = 0;j < ns2->nodeNr;j++) { 6911 if (i == 0) 6912 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]); 6913 if (hashs1[i] != hashs2[j]) { 6914 if (neq) { 6915 ret = 1; 6916 break; 6917 } 6918 } 6919 else { 6920 if (values1[i] == NULL) 6921 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]); 6922 if (values2[j] == NULL) 6923 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]); 6924 ret = xmlStrEqual(values1[i], values2[j]) ^ neq; 6925 if (ret) 6926 break; 6927 } 6928 } 6929 if (ret) 6930 break; 6931 } 6932 for (i = 0;i < ns1->nodeNr;i++) 6933 if (values1[i] != NULL) 6934 xmlFree(values1[i]); 6935 for (j = 0;j < ns2->nodeNr;j++) 6936 if (values2[j] != NULL) 6937 xmlFree(values2[j]); 6938 xmlFree(values1); 6939 xmlFree(values2); 6940 xmlFree(hashs1); 6941 xmlFree(hashs2); 6942 return(ret); 6943 } 6944 6945 static int 6946 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt, 6947 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) { 6948 int ret = 0; 6949 /* 6950 *At this point we are assured neither arg1 nor arg2 6951 *is a nodeset, so we can just pick the appropriate routine. 6952 */ 6953 switch (arg1->type) { 6954 case XPATH_UNDEFINED: 6955 #ifdef DEBUG_EXPR 6956 xmlGenericError(xmlGenericErrorContext, 6957 "Equal: undefined\n"); 6958 #endif 6959 break; 6960 case XPATH_BOOLEAN: 6961 switch (arg2->type) { 6962 case XPATH_UNDEFINED: 6963 #ifdef DEBUG_EXPR 6964 xmlGenericError(xmlGenericErrorContext, 6965 "Equal: undefined\n"); 6966 #endif 6967 break; 6968 case XPATH_BOOLEAN: 6969 #ifdef DEBUG_EXPR 6970 xmlGenericError(xmlGenericErrorContext, 6971 "Equal: %d boolean %d \n", 6972 arg1->boolval, arg2->boolval); 6973 #endif 6974 ret = (arg1->boolval == arg2->boolval); 6975 break; 6976 case XPATH_NUMBER: 6977 ret = (arg1->boolval == 6978 xmlXPathCastNumberToBoolean(arg2->floatval)); 6979 break; 6980 case XPATH_STRING: 6981 if ((arg2->stringval == NULL) || 6982 (arg2->stringval[0] == 0)) ret = 0; 6983 else 6984 ret = 1; 6985 ret = (arg1->boolval == ret); 6986 break; 6987 case XPATH_USERS: 6988 case XPATH_POINT: 6989 case XPATH_RANGE: 6990 case XPATH_LOCATIONSET: 6991 TODO 6992 break; 6993 case XPATH_NODESET: 6994 case XPATH_XSLT_TREE: 6995 break; 6996 } 6997 break; 6998 case XPATH_NUMBER: 6999 switch (arg2->type) { 7000 case XPATH_UNDEFINED: 7001 #ifdef DEBUG_EXPR 7002 xmlGenericError(xmlGenericErrorContext, 7003 "Equal: undefined\n"); 7004 #endif 7005 break; 7006 case XPATH_BOOLEAN: 7007 ret = (arg2->boolval== 7008 xmlXPathCastNumberToBoolean(arg1->floatval)); 7009 break; 7010 case XPATH_STRING: 7011 valuePush(ctxt, arg2); 7012 xmlXPathNumberFunction(ctxt, 1); 7013 arg2 = valuePop(ctxt); 7014 /* Falls through. */ 7015 case XPATH_NUMBER: 7016 /* Hand check NaN and Infinity equalities */ 7017 if (xmlXPathIsNaN(arg1->floatval) || 7018 xmlXPathIsNaN(arg2->floatval)) { 7019 ret = 0; 7020 } else if (xmlXPathIsInf(arg1->floatval) == 1) { 7021 if (xmlXPathIsInf(arg2->floatval) == 1) 7022 ret = 1; 7023 else 7024 ret = 0; 7025 } else if (xmlXPathIsInf(arg1->floatval) == -1) { 7026 if (xmlXPathIsInf(arg2->floatval) == -1) 7027 ret = 1; 7028 else 7029 ret = 0; 7030 } else if (xmlXPathIsInf(arg2->floatval) == 1) { 7031 if (xmlXPathIsInf(arg1->floatval) == 1) 7032 ret = 1; 7033 else 7034 ret = 0; 7035 } else if (xmlXPathIsInf(arg2->floatval) == -1) { 7036 if (xmlXPathIsInf(arg1->floatval) == -1) 7037 ret = 1; 7038 else 7039 ret = 0; 7040 } else { 7041 ret = (arg1->floatval == arg2->floatval); 7042 } 7043 break; 7044 case XPATH_USERS: 7045 case XPATH_POINT: 7046 case XPATH_RANGE: 7047 case XPATH_LOCATIONSET: 7048 TODO 7049 break; 7050 case XPATH_NODESET: 7051 case XPATH_XSLT_TREE: 7052 break; 7053 } 7054 break; 7055 case XPATH_STRING: 7056 switch (arg2->type) { 7057 case XPATH_UNDEFINED: 7058 #ifdef DEBUG_EXPR 7059 xmlGenericError(xmlGenericErrorContext, 7060 "Equal: undefined\n"); 7061 #endif 7062 break; 7063 case XPATH_BOOLEAN: 7064 if ((arg1->stringval == NULL) || 7065 (arg1->stringval[0] == 0)) ret = 0; 7066 else 7067 ret = 1; 7068 ret = (arg2->boolval == ret); 7069 break; 7070 case XPATH_STRING: 7071 ret = xmlStrEqual(arg1->stringval, arg2->stringval); 7072 break; 7073 case XPATH_NUMBER: 7074 valuePush(ctxt, arg1); 7075 xmlXPathNumberFunction(ctxt, 1); 7076 arg1 = valuePop(ctxt); 7077 /* Hand check NaN and Infinity equalities */ 7078 if (xmlXPathIsNaN(arg1->floatval) || 7079 xmlXPathIsNaN(arg2->floatval)) { 7080 ret = 0; 7081 } else if (xmlXPathIsInf(arg1->floatval) == 1) { 7082 if (xmlXPathIsInf(arg2->floatval) == 1) 7083 ret = 1; 7084 else 7085 ret = 0; 7086 } else if (xmlXPathIsInf(arg1->floatval) == -1) { 7087 if (xmlXPathIsInf(arg2->floatval) == -1) 7088 ret = 1; 7089 else 7090 ret = 0; 7091 } else if (xmlXPathIsInf(arg2->floatval) == 1) { 7092 if (xmlXPathIsInf(arg1->floatval) == 1) 7093 ret = 1; 7094 else 7095 ret = 0; 7096 } else if (xmlXPathIsInf(arg2->floatval) == -1) { 7097 if (xmlXPathIsInf(arg1->floatval) == -1) 7098 ret = 1; 7099 else 7100 ret = 0; 7101 } else { 7102 ret = (arg1->floatval == arg2->floatval); 7103 } 7104 break; 7105 case XPATH_USERS: 7106 case XPATH_POINT: 7107 case XPATH_RANGE: 7108 case XPATH_LOCATIONSET: 7109 TODO 7110 break; 7111 case XPATH_NODESET: 7112 case XPATH_XSLT_TREE: 7113 break; 7114 } 7115 break; 7116 case XPATH_USERS: 7117 case XPATH_POINT: 7118 case XPATH_RANGE: 7119 case XPATH_LOCATIONSET: 7120 TODO 7121 break; 7122 case XPATH_NODESET: 7123 case XPATH_XSLT_TREE: 7124 break; 7125 } 7126 xmlXPathReleaseObject(ctxt->context, arg1); 7127 xmlXPathReleaseObject(ctxt->context, arg2); 7128 return(ret); 7129 } 7130 7131 /** 7132 * xmlXPathEqualValues: 7133 * @ctxt: the XPath Parser context 7134 * 7135 * Implement the equal operation on XPath objects content: @arg1 == @arg2 7136 * 7137 * Returns 0 or 1 depending on the results of the test. 7138 */ 7139 int 7140 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) { 7141 xmlXPathObjectPtr arg1, arg2, argtmp; 7142 int ret = 0; 7143 7144 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); 7145 arg2 = valuePop(ctxt); 7146 arg1 = valuePop(ctxt); 7147 if ((arg1 == NULL) || (arg2 == NULL)) { 7148 if (arg1 != NULL) 7149 xmlXPathReleaseObject(ctxt->context, arg1); 7150 else 7151 xmlXPathReleaseObject(ctxt->context, arg2); 7152 XP_ERROR0(XPATH_INVALID_OPERAND); 7153 } 7154 7155 if (arg1 == arg2) { 7156 #ifdef DEBUG_EXPR 7157 xmlGenericError(xmlGenericErrorContext, 7158 "Equal: by pointer\n"); 7159 #endif 7160 xmlXPathFreeObject(arg1); 7161 return(1); 7162 } 7163 7164 /* 7165 *If either argument is a nodeset, it's a 'special case' 7166 */ 7167 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 7168 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7169 /* 7170 *Hack it to assure arg1 is the nodeset 7171 */ 7172 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) { 7173 argtmp = arg2; 7174 arg2 = arg1; 7175 arg1 = argtmp; 7176 } 7177 switch (arg2->type) { 7178 case XPATH_UNDEFINED: 7179 #ifdef DEBUG_EXPR 7180 xmlGenericError(xmlGenericErrorContext, 7181 "Equal: undefined\n"); 7182 #endif 7183 break; 7184 case XPATH_NODESET: 7185 case XPATH_XSLT_TREE: 7186 ret = xmlXPathEqualNodeSets(arg1, arg2, 0); 7187 break; 7188 case XPATH_BOOLEAN: 7189 if ((arg1->nodesetval == NULL) || 7190 (arg1->nodesetval->nodeNr == 0)) ret = 0; 7191 else 7192 ret = 1; 7193 ret = (ret == arg2->boolval); 7194 break; 7195 case XPATH_NUMBER: 7196 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0); 7197 break; 7198 case XPATH_STRING: 7199 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0); 7200 break; 7201 case XPATH_USERS: 7202 case XPATH_POINT: 7203 case XPATH_RANGE: 7204 case XPATH_LOCATIONSET: 7205 TODO 7206 break; 7207 } 7208 xmlXPathReleaseObject(ctxt->context, arg1); 7209 xmlXPathReleaseObject(ctxt->context, arg2); 7210 return(ret); 7211 } 7212 7213 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2)); 7214 } 7215 7216 /** 7217 * xmlXPathNotEqualValues: 7218 * @ctxt: the XPath Parser context 7219 * 7220 * Implement the equal operation on XPath objects content: @arg1 == @arg2 7221 * 7222 * Returns 0 or 1 depending on the results of the test. 7223 */ 7224 int 7225 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) { 7226 xmlXPathObjectPtr arg1, arg2, argtmp; 7227 int ret = 0; 7228 7229 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); 7230 arg2 = valuePop(ctxt); 7231 arg1 = valuePop(ctxt); 7232 if ((arg1 == NULL) || (arg2 == NULL)) { 7233 if (arg1 != NULL) 7234 xmlXPathReleaseObject(ctxt->context, arg1); 7235 else 7236 xmlXPathReleaseObject(ctxt->context, arg2); 7237 XP_ERROR0(XPATH_INVALID_OPERAND); 7238 } 7239 7240 if (arg1 == arg2) { 7241 #ifdef DEBUG_EXPR 7242 xmlGenericError(xmlGenericErrorContext, 7243 "NotEqual: by pointer\n"); 7244 #endif 7245 xmlXPathReleaseObject(ctxt->context, arg1); 7246 return(0); 7247 } 7248 7249 /* 7250 *If either argument is a nodeset, it's a 'special case' 7251 */ 7252 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 7253 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7254 /* 7255 *Hack it to assure arg1 is the nodeset 7256 */ 7257 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) { 7258 argtmp = arg2; 7259 arg2 = arg1; 7260 arg1 = argtmp; 7261 } 7262 switch (arg2->type) { 7263 case XPATH_UNDEFINED: 7264 #ifdef DEBUG_EXPR 7265 xmlGenericError(xmlGenericErrorContext, 7266 "NotEqual: undefined\n"); 7267 #endif 7268 break; 7269 case XPATH_NODESET: 7270 case XPATH_XSLT_TREE: 7271 ret = xmlXPathEqualNodeSets(arg1, arg2, 1); 7272 break; 7273 case XPATH_BOOLEAN: 7274 if ((arg1->nodesetval == NULL) || 7275 (arg1->nodesetval->nodeNr == 0)) ret = 0; 7276 else 7277 ret = 1; 7278 ret = (ret != arg2->boolval); 7279 break; 7280 case XPATH_NUMBER: 7281 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1); 7282 break; 7283 case XPATH_STRING: 7284 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1); 7285 break; 7286 case XPATH_USERS: 7287 case XPATH_POINT: 7288 case XPATH_RANGE: 7289 case XPATH_LOCATIONSET: 7290 TODO 7291 break; 7292 } 7293 xmlXPathReleaseObject(ctxt->context, arg1); 7294 xmlXPathReleaseObject(ctxt->context, arg2); 7295 return(ret); 7296 } 7297 7298 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2)); 7299 } 7300 7301 /** 7302 * xmlXPathCompareValues: 7303 * @ctxt: the XPath Parser context 7304 * @inf: less than (1) or greater than (0) 7305 * @strict: is the comparison strict 7306 * 7307 * Implement the compare operation on XPath objects: 7308 * @arg1 < @arg2 (1, 1, ... 7309 * @arg1 <= @arg2 (1, 0, ... 7310 * @arg1 > @arg2 (0, 1, ... 7311 * @arg1 >= @arg2 (0, 0, ... 7312 * 7313 * When neither object to be compared is a node-set and the operator is 7314 * <=, <, >=, >, then the objects are compared by converted both objects 7315 * to numbers and comparing the numbers according to IEEE 754. The < 7316 * comparison will be true if and only if the first number is less than the 7317 * second number. The <= comparison will be true if and only if the first 7318 * number is less than or equal to the second number. The > comparison 7319 * will be true if and only if the first number is greater than the second 7320 * number. The >= comparison will be true if and only if the first number 7321 * is greater than or equal to the second number. 7322 * 7323 * Returns 1 if the comparison succeeded, 0 if it failed 7324 */ 7325 int 7326 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) { 7327 int ret = 0, arg1i = 0, arg2i = 0; 7328 xmlXPathObjectPtr arg1, arg2; 7329 7330 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); 7331 arg2 = valuePop(ctxt); 7332 arg1 = valuePop(ctxt); 7333 if ((arg1 == NULL) || (arg2 == NULL)) { 7334 if (arg1 != NULL) 7335 xmlXPathReleaseObject(ctxt->context, arg1); 7336 else 7337 xmlXPathReleaseObject(ctxt->context, arg2); 7338 XP_ERROR0(XPATH_INVALID_OPERAND); 7339 } 7340 7341 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 7342 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7343 /* 7344 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments 7345 * are not freed from within this routine; they will be freed from the 7346 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue 7347 */ 7348 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) && 7349 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){ 7350 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2); 7351 } else { 7352 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7353 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict, 7354 arg1, arg2); 7355 } else { 7356 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict, 7357 arg2, arg1); 7358 } 7359 } 7360 return(ret); 7361 } 7362 7363 if (arg1->type != XPATH_NUMBER) { 7364 valuePush(ctxt, arg1); 7365 xmlXPathNumberFunction(ctxt, 1); 7366 arg1 = valuePop(ctxt); 7367 } 7368 if (arg1->type != XPATH_NUMBER) { 7369 xmlXPathFreeObject(arg1); 7370 xmlXPathFreeObject(arg2); 7371 XP_ERROR0(XPATH_INVALID_OPERAND); 7372 } 7373 if (arg2->type != XPATH_NUMBER) { 7374 valuePush(ctxt, arg2); 7375 xmlXPathNumberFunction(ctxt, 1); 7376 arg2 = valuePop(ctxt); 7377 } 7378 if (arg2->type != XPATH_NUMBER) { 7379 xmlXPathReleaseObject(ctxt->context, arg1); 7380 xmlXPathReleaseObject(ctxt->context, arg2); 7381 XP_ERROR0(XPATH_INVALID_OPERAND); 7382 } 7383 /* 7384 * Add tests for infinity and nan 7385 * => feedback on 3.4 for Inf and NaN 7386 */ 7387 /* Hand check NaN and Infinity comparisons */ 7388 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) { 7389 ret=0; 7390 } else { 7391 arg1i=xmlXPathIsInf(arg1->floatval); 7392 arg2i=xmlXPathIsInf(arg2->floatval); 7393 if (inf && strict) { 7394 if ((arg1i == -1 && arg2i != -1) || 7395 (arg2i == 1 && arg1i != 1)) { 7396 ret = 1; 7397 } else if (arg1i == 0 && arg2i == 0) { 7398 ret = (arg1->floatval < arg2->floatval); 7399 } else { 7400 ret = 0; 7401 } 7402 } 7403 else if (inf && !strict) { 7404 if (arg1i == -1 || arg2i == 1) { 7405 ret = 1; 7406 } else if (arg1i == 0 && arg2i == 0) { 7407 ret = (arg1->floatval <= arg2->floatval); 7408 } else { 7409 ret = 0; 7410 } 7411 } 7412 else if (!inf && strict) { 7413 if ((arg1i == 1 && arg2i != 1) || 7414 (arg2i == -1 && arg1i != -1)) { 7415 ret = 1; 7416 } else if (arg1i == 0 && arg2i == 0) { 7417 ret = (arg1->floatval > arg2->floatval); 7418 } else { 7419 ret = 0; 7420 } 7421 } 7422 else if (!inf && !strict) { 7423 if (arg1i == 1 || arg2i == -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 } 7432 xmlXPathReleaseObject(ctxt->context, arg1); 7433 xmlXPathReleaseObject(ctxt->context, arg2); 7434 return(ret); 7435 } 7436 7437 /** 7438 * xmlXPathValueFlipSign: 7439 * @ctxt: the XPath Parser context 7440 * 7441 * Implement the unary - operation on an XPath object 7442 * The numeric operators convert their operands to numbers as if 7443 * by calling the number function. 7444 */ 7445 void 7446 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) { 7447 if ((ctxt == NULL) || (ctxt->context == NULL)) return; 7448 CAST_TO_NUMBER; 7449 CHECK_TYPE(XPATH_NUMBER); 7450 ctxt->value->floatval = -ctxt->value->floatval; 7451 } 7452 7453 /** 7454 * xmlXPathAddValues: 7455 * @ctxt: the XPath Parser context 7456 * 7457 * Implement the add operation on XPath objects: 7458 * The numeric operators convert their operands to numbers as if 7459 * by calling the number function. 7460 */ 7461 void 7462 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) { 7463 xmlXPathObjectPtr arg; 7464 double val; 7465 7466 arg = valuePop(ctxt); 7467 if (arg == NULL) 7468 XP_ERROR(XPATH_INVALID_OPERAND); 7469 val = xmlXPathCastToNumber(arg); 7470 xmlXPathReleaseObject(ctxt->context, arg); 7471 CAST_TO_NUMBER; 7472 CHECK_TYPE(XPATH_NUMBER); 7473 ctxt->value->floatval += val; 7474 } 7475 7476 /** 7477 * xmlXPathSubValues: 7478 * @ctxt: the XPath Parser context 7479 * 7480 * Implement the subtraction operation on XPath objects: 7481 * The numeric operators convert their operands to numbers as if 7482 * by calling the number function. 7483 */ 7484 void 7485 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) { 7486 xmlXPathObjectPtr arg; 7487 double val; 7488 7489 arg = valuePop(ctxt); 7490 if (arg == NULL) 7491 XP_ERROR(XPATH_INVALID_OPERAND); 7492 val = xmlXPathCastToNumber(arg); 7493 xmlXPathReleaseObject(ctxt->context, arg); 7494 CAST_TO_NUMBER; 7495 CHECK_TYPE(XPATH_NUMBER); 7496 ctxt->value->floatval -= val; 7497 } 7498 7499 /** 7500 * xmlXPathMultValues: 7501 * @ctxt: the XPath Parser context 7502 * 7503 * Implement the multiply operation on XPath objects: 7504 * The numeric operators convert their operands to numbers as if 7505 * by calling the number function. 7506 */ 7507 void 7508 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) { 7509 xmlXPathObjectPtr arg; 7510 double val; 7511 7512 arg = valuePop(ctxt); 7513 if (arg == NULL) 7514 XP_ERROR(XPATH_INVALID_OPERAND); 7515 val = xmlXPathCastToNumber(arg); 7516 xmlXPathReleaseObject(ctxt->context, arg); 7517 CAST_TO_NUMBER; 7518 CHECK_TYPE(XPATH_NUMBER); 7519 ctxt->value->floatval *= val; 7520 } 7521 7522 /** 7523 * xmlXPathDivValues: 7524 * @ctxt: the XPath Parser context 7525 * 7526 * Implement the div operation on XPath objects @arg1 / @arg2: 7527 * The numeric operators convert their operands to numbers as if 7528 * by calling the number function. 7529 */ 7530 ATTRIBUTE_NO_SANITIZE("float-divide-by-zero") 7531 void 7532 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) { 7533 xmlXPathObjectPtr arg; 7534 double val; 7535 7536 arg = valuePop(ctxt); 7537 if (arg == NULL) 7538 XP_ERROR(XPATH_INVALID_OPERAND); 7539 val = xmlXPathCastToNumber(arg); 7540 xmlXPathReleaseObject(ctxt->context, arg); 7541 CAST_TO_NUMBER; 7542 CHECK_TYPE(XPATH_NUMBER); 7543 ctxt->value->floatval /= val; 7544 } 7545 7546 /** 7547 * xmlXPathModValues: 7548 * @ctxt: the XPath Parser context 7549 * 7550 * Implement the mod operation on XPath objects: @arg1 / @arg2 7551 * The numeric operators convert their operands to numbers as if 7552 * by calling the number function. 7553 */ 7554 void 7555 xmlXPathModValues(xmlXPathParserContextPtr ctxt) { 7556 xmlXPathObjectPtr arg; 7557 double arg1, arg2; 7558 7559 arg = valuePop(ctxt); 7560 if (arg == NULL) 7561 XP_ERROR(XPATH_INVALID_OPERAND); 7562 arg2 = xmlXPathCastToNumber(arg); 7563 xmlXPathReleaseObject(ctxt->context, arg); 7564 CAST_TO_NUMBER; 7565 CHECK_TYPE(XPATH_NUMBER); 7566 arg1 = ctxt->value->floatval; 7567 if (arg2 == 0) 7568 ctxt->value->floatval = xmlXPathNAN; 7569 else { 7570 ctxt->value->floatval = fmod(arg1, arg2); 7571 } 7572 } 7573 7574 /************************************************************************ 7575 * * 7576 * The traversal functions * 7577 * * 7578 ************************************************************************/ 7579 7580 /* 7581 * A traversal function enumerates nodes along an axis. 7582 * Initially it must be called with NULL, and it indicates 7583 * termination on the axis by returning NULL. 7584 */ 7585 typedef xmlNodePtr (*xmlXPathTraversalFunction) 7586 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur); 7587 7588 /* 7589 * xmlXPathTraversalFunctionExt: 7590 * A traversal function enumerates nodes along an axis. 7591 * Initially it must be called with NULL, and it indicates 7592 * termination on the axis by returning NULL. 7593 * The context node of the traversal is specified via @contextNode. 7594 */ 7595 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt) 7596 (xmlNodePtr cur, xmlNodePtr contextNode); 7597 7598 /* 7599 * xmlXPathNodeSetMergeFunction: 7600 * Used for merging node sets in xmlXPathCollectAndTest(). 7601 */ 7602 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction) 7603 (xmlNodeSetPtr, xmlNodeSetPtr); 7604 7605 7606 /** 7607 * xmlXPathNextSelf: 7608 * @ctxt: the XPath Parser context 7609 * @cur: the current node in the traversal 7610 * 7611 * Traversal function for the "self" direction 7612 * The self axis contains just the context node itself 7613 * 7614 * Returns the next element following that axis 7615 */ 7616 xmlNodePtr 7617 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7618 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7619 if (cur == NULL) 7620 return(ctxt->context->node); 7621 return(NULL); 7622 } 7623 7624 /** 7625 * xmlXPathNextChild: 7626 * @ctxt: the XPath Parser context 7627 * @cur: the current node in the traversal 7628 * 7629 * Traversal function for the "child" direction 7630 * The child axis contains the children of the context node in document order. 7631 * 7632 * Returns the next element following that axis 7633 */ 7634 xmlNodePtr 7635 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7636 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7637 if (cur == NULL) { 7638 if (ctxt->context->node == NULL) return(NULL); 7639 switch (ctxt->context->node->type) { 7640 case XML_ELEMENT_NODE: 7641 case XML_TEXT_NODE: 7642 case XML_CDATA_SECTION_NODE: 7643 case XML_ENTITY_REF_NODE: 7644 case XML_ENTITY_NODE: 7645 case XML_PI_NODE: 7646 case XML_COMMENT_NODE: 7647 case XML_NOTATION_NODE: 7648 case XML_DTD_NODE: 7649 return(ctxt->context->node->children); 7650 case XML_DOCUMENT_NODE: 7651 case XML_DOCUMENT_TYPE_NODE: 7652 case XML_DOCUMENT_FRAG_NODE: 7653 case XML_HTML_DOCUMENT_NODE: 7654 #ifdef LIBXML_DOCB_ENABLED 7655 case XML_DOCB_DOCUMENT_NODE: 7656 #endif 7657 return(((xmlDocPtr) ctxt->context->node)->children); 7658 case XML_ELEMENT_DECL: 7659 case XML_ATTRIBUTE_DECL: 7660 case XML_ENTITY_DECL: 7661 case XML_ATTRIBUTE_NODE: 7662 case XML_NAMESPACE_DECL: 7663 case XML_XINCLUDE_START: 7664 case XML_XINCLUDE_END: 7665 return(NULL); 7666 } 7667 return(NULL); 7668 } 7669 if ((cur->type == XML_DOCUMENT_NODE) || 7670 (cur->type == XML_HTML_DOCUMENT_NODE)) 7671 return(NULL); 7672 return(cur->next); 7673 } 7674 7675 /** 7676 * xmlXPathNextChildElement: 7677 * @ctxt: the XPath Parser context 7678 * @cur: the current node in the traversal 7679 * 7680 * Traversal function for the "child" direction and nodes of type element. 7681 * The child axis contains the children of the context node in document order. 7682 * 7683 * Returns the next element following that axis 7684 */ 7685 static xmlNodePtr 7686 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7687 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7688 if (cur == NULL) { 7689 cur = ctxt->context->node; 7690 if (cur == NULL) return(NULL); 7691 /* 7692 * Get the first element child. 7693 */ 7694 switch (cur->type) { 7695 case XML_ELEMENT_NODE: 7696 case XML_DOCUMENT_FRAG_NODE: 7697 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */ 7698 case XML_ENTITY_NODE: 7699 cur = cur->children; 7700 if (cur != NULL) { 7701 if (cur->type == XML_ELEMENT_NODE) 7702 return(cur); 7703 do { 7704 cur = cur->next; 7705 } while ((cur != NULL) && 7706 (cur->type != XML_ELEMENT_NODE)); 7707 return(cur); 7708 } 7709 return(NULL); 7710 case XML_DOCUMENT_NODE: 7711 case XML_HTML_DOCUMENT_NODE: 7712 #ifdef LIBXML_DOCB_ENABLED 7713 case XML_DOCB_DOCUMENT_NODE: 7714 #endif 7715 return(xmlDocGetRootElement((xmlDocPtr) cur)); 7716 default: 7717 return(NULL); 7718 } 7719 return(NULL); 7720 } 7721 /* 7722 * Get the next sibling element node. 7723 */ 7724 switch (cur->type) { 7725 case XML_ELEMENT_NODE: 7726 case XML_TEXT_NODE: 7727 case XML_ENTITY_REF_NODE: 7728 case XML_ENTITY_NODE: 7729 case XML_CDATA_SECTION_NODE: 7730 case XML_PI_NODE: 7731 case XML_COMMENT_NODE: 7732 case XML_XINCLUDE_END: 7733 break; 7734 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */ 7735 default: 7736 return(NULL); 7737 } 7738 if (cur->next != NULL) { 7739 if (cur->next->type == XML_ELEMENT_NODE) 7740 return(cur->next); 7741 cur = cur->next; 7742 do { 7743 cur = cur->next; 7744 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE)); 7745 return(cur); 7746 } 7747 return(NULL); 7748 } 7749 7750 #if 0 7751 /** 7752 * xmlXPathNextDescendantOrSelfElemParent: 7753 * @ctxt: the XPath Parser context 7754 * @cur: the current node in the traversal 7755 * 7756 * Traversal function for the "descendant-or-self" axis. 7757 * Additionally it returns only nodes which can be parents of 7758 * element nodes. 7759 * 7760 * 7761 * Returns the next element following that axis 7762 */ 7763 static xmlNodePtr 7764 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur, 7765 xmlNodePtr contextNode) 7766 { 7767 if (cur == NULL) { 7768 if (contextNode == NULL) 7769 return(NULL); 7770 switch (contextNode->type) { 7771 case XML_ELEMENT_NODE: 7772 case XML_XINCLUDE_START: 7773 case XML_DOCUMENT_FRAG_NODE: 7774 case XML_DOCUMENT_NODE: 7775 #ifdef LIBXML_DOCB_ENABLED 7776 case XML_DOCB_DOCUMENT_NODE: 7777 #endif 7778 case XML_HTML_DOCUMENT_NODE: 7779 return(contextNode); 7780 default: 7781 return(NULL); 7782 } 7783 return(NULL); 7784 } else { 7785 xmlNodePtr start = cur; 7786 7787 while (cur != NULL) { 7788 switch (cur->type) { 7789 case XML_ELEMENT_NODE: 7790 /* TODO: OK to have XInclude here? */ 7791 case XML_XINCLUDE_START: 7792 case XML_DOCUMENT_FRAG_NODE: 7793 if (cur != start) 7794 return(cur); 7795 if (cur->children != NULL) { 7796 cur = cur->children; 7797 continue; 7798 } 7799 break; 7800 /* Not sure if we need those here. */ 7801 case XML_DOCUMENT_NODE: 7802 #ifdef LIBXML_DOCB_ENABLED 7803 case XML_DOCB_DOCUMENT_NODE: 7804 #endif 7805 case XML_HTML_DOCUMENT_NODE: 7806 if (cur != start) 7807 return(cur); 7808 return(xmlDocGetRootElement((xmlDocPtr) cur)); 7809 default: 7810 break; 7811 } 7812 7813 next_sibling: 7814 if ((cur == NULL) || (cur == contextNode)) 7815 return(NULL); 7816 if (cur->next != NULL) { 7817 cur = cur->next; 7818 } else { 7819 cur = cur->parent; 7820 goto next_sibling; 7821 } 7822 } 7823 } 7824 return(NULL); 7825 } 7826 #endif 7827 7828 /** 7829 * xmlXPathNextDescendant: 7830 * @ctxt: the XPath Parser context 7831 * @cur: the current node in the traversal 7832 * 7833 * Traversal function for the "descendant" direction 7834 * the descendant axis contains the descendants of the context node in document 7835 * order; a descendant is a child or a child of a child and so on. 7836 * 7837 * Returns the next element following that axis 7838 */ 7839 xmlNodePtr 7840 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7841 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7842 if (cur == NULL) { 7843 if (ctxt->context->node == NULL) 7844 return(NULL); 7845 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 7846 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 7847 return(NULL); 7848 7849 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc) 7850 return(ctxt->context->doc->children); 7851 return(ctxt->context->node->children); 7852 } 7853 7854 if (cur->type == XML_NAMESPACE_DECL) 7855 return(NULL); 7856 if (cur->children != NULL) { 7857 /* 7858 * Do not descend on entities declarations 7859 */ 7860 if (cur->children->type != XML_ENTITY_DECL) { 7861 cur = cur->children; 7862 /* 7863 * Skip DTDs 7864 */ 7865 if (cur->type != XML_DTD_NODE) 7866 return(cur); 7867 } 7868 } 7869 7870 if (cur == ctxt->context->node) return(NULL); 7871 7872 while (cur->next != NULL) { 7873 cur = cur->next; 7874 if ((cur->type != XML_ENTITY_DECL) && 7875 (cur->type != XML_DTD_NODE)) 7876 return(cur); 7877 } 7878 7879 do { 7880 cur = cur->parent; 7881 if (cur == NULL) break; 7882 if (cur == ctxt->context->node) return(NULL); 7883 if (cur->next != NULL) { 7884 cur = cur->next; 7885 return(cur); 7886 } 7887 } while (cur != NULL); 7888 return(cur); 7889 } 7890 7891 /** 7892 * xmlXPathNextDescendantOrSelf: 7893 * @ctxt: the XPath Parser context 7894 * @cur: the current node in the traversal 7895 * 7896 * Traversal function for the "descendant-or-self" direction 7897 * the descendant-or-self axis contains the context node and the descendants 7898 * of the context node in document order; thus the context node is the first 7899 * node on the axis, and the first child of the context node is the second node 7900 * on the axis 7901 * 7902 * Returns the next element following that axis 7903 */ 7904 xmlNodePtr 7905 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7906 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7907 if (cur == NULL) 7908 return(ctxt->context->node); 7909 7910 if (ctxt->context->node == NULL) 7911 return(NULL); 7912 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 7913 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 7914 return(NULL); 7915 7916 return(xmlXPathNextDescendant(ctxt, cur)); 7917 } 7918 7919 /** 7920 * xmlXPathNextParent: 7921 * @ctxt: the XPath Parser context 7922 * @cur: the current node in the traversal 7923 * 7924 * Traversal function for the "parent" direction 7925 * The parent axis contains the parent of the context node, if there is one. 7926 * 7927 * Returns the next element following that axis 7928 */ 7929 xmlNodePtr 7930 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7931 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7932 /* 7933 * the parent of an attribute or namespace node is the element 7934 * to which the attribute or namespace node is attached 7935 * Namespace handling !!! 7936 */ 7937 if (cur == NULL) { 7938 if (ctxt->context->node == NULL) return(NULL); 7939 switch (ctxt->context->node->type) { 7940 case XML_ELEMENT_NODE: 7941 case XML_TEXT_NODE: 7942 case XML_CDATA_SECTION_NODE: 7943 case XML_ENTITY_REF_NODE: 7944 case XML_ENTITY_NODE: 7945 case XML_PI_NODE: 7946 case XML_COMMENT_NODE: 7947 case XML_NOTATION_NODE: 7948 case XML_DTD_NODE: 7949 case XML_ELEMENT_DECL: 7950 case XML_ATTRIBUTE_DECL: 7951 case XML_XINCLUDE_START: 7952 case XML_XINCLUDE_END: 7953 case XML_ENTITY_DECL: 7954 if (ctxt->context->node->parent == NULL) 7955 return((xmlNodePtr) ctxt->context->doc); 7956 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) && 7957 ((ctxt->context->node->parent->name[0] == ' ') || 7958 (xmlStrEqual(ctxt->context->node->parent->name, 7959 BAD_CAST "fake node libxslt")))) 7960 return(NULL); 7961 return(ctxt->context->node->parent); 7962 case XML_ATTRIBUTE_NODE: { 7963 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node; 7964 7965 return(att->parent); 7966 } 7967 case XML_DOCUMENT_NODE: 7968 case XML_DOCUMENT_TYPE_NODE: 7969 case XML_DOCUMENT_FRAG_NODE: 7970 case XML_HTML_DOCUMENT_NODE: 7971 #ifdef LIBXML_DOCB_ENABLED 7972 case XML_DOCB_DOCUMENT_NODE: 7973 #endif 7974 return(NULL); 7975 case XML_NAMESPACE_DECL: { 7976 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; 7977 7978 if ((ns->next != NULL) && 7979 (ns->next->type != XML_NAMESPACE_DECL)) 7980 return((xmlNodePtr) ns->next); 7981 return(NULL); 7982 } 7983 } 7984 } 7985 return(NULL); 7986 } 7987 7988 /** 7989 * xmlXPathNextAncestor: 7990 * @ctxt: the XPath Parser context 7991 * @cur: the current node in the traversal 7992 * 7993 * Traversal function for the "ancestor" direction 7994 * the ancestor axis contains the ancestors of the context node; the ancestors 7995 * of the context node consist of the parent of context node and the parent's 7996 * parent and so on; the nodes are ordered in reverse document order; thus the 7997 * parent is the first node on the axis, and the parent's parent is the second 7998 * node on the axis 7999 * 8000 * Returns the next element following that axis 8001 */ 8002 xmlNodePtr 8003 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8004 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8005 /* 8006 * the parent of an attribute or namespace node is the element 8007 * to which the attribute or namespace node is attached 8008 * !!!!!!!!!!!!! 8009 */ 8010 if (cur == NULL) { 8011 if (ctxt->context->node == NULL) return(NULL); 8012 switch (ctxt->context->node->type) { 8013 case XML_ELEMENT_NODE: 8014 case XML_TEXT_NODE: 8015 case XML_CDATA_SECTION_NODE: 8016 case XML_ENTITY_REF_NODE: 8017 case XML_ENTITY_NODE: 8018 case XML_PI_NODE: 8019 case XML_COMMENT_NODE: 8020 case XML_DTD_NODE: 8021 case XML_ELEMENT_DECL: 8022 case XML_ATTRIBUTE_DECL: 8023 case XML_ENTITY_DECL: 8024 case XML_NOTATION_NODE: 8025 case XML_XINCLUDE_START: 8026 case XML_XINCLUDE_END: 8027 if (ctxt->context->node->parent == NULL) 8028 return((xmlNodePtr) ctxt->context->doc); 8029 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) && 8030 ((ctxt->context->node->parent->name[0] == ' ') || 8031 (xmlStrEqual(ctxt->context->node->parent->name, 8032 BAD_CAST "fake node libxslt")))) 8033 return(NULL); 8034 return(ctxt->context->node->parent); 8035 case XML_ATTRIBUTE_NODE: { 8036 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node; 8037 8038 return(tmp->parent); 8039 } 8040 case XML_DOCUMENT_NODE: 8041 case XML_DOCUMENT_TYPE_NODE: 8042 case XML_DOCUMENT_FRAG_NODE: 8043 case XML_HTML_DOCUMENT_NODE: 8044 #ifdef LIBXML_DOCB_ENABLED 8045 case XML_DOCB_DOCUMENT_NODE: 8046 #endif 8047 return(NULL); 8048 case XML_NAMESPACE_DECL: { 8049 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; 8050 8051 if ((ns->next != NULL) && 8052 (ns->next->type != XML_NAMESPACE_DECL)) 8053 return((xmlNodePtr) ns->next); 8054 /* Bad, how did that namespace end up here ? */ 8055 return(NULL); 8056 } 8057 } 8058 return(NULL); 8059 } 8060 if (cur == ctxt->context->doc->children) 8061 return((xmlNodePtr) ctxt->context->doc); 8062 if (cur == (xmlNodePtr) ctxt->context->doc) 8063 return(NULL); 8064 switch (cur->type) { 8065 case XML_ELEMENT_NODE: 8066 case XML_TEXT_NODE: 8067 case XML_CDATA_SECTION_NODE: 8068 case XML_ENTITY_REF_NODE: 8069 case XML_ENTITY_NODE: 8070 case XML_PI_NODE: 8071 case XML_COMMENT_NODE: 8072 case XML_NOTATION_NODE: 8073 case XML_DTD_NODE: 8074 case XML_ELEMENT_DECL: 8075 case XML_ATTRIBUTE_DECL: 8076 case XML_ENTITY_DECL: 8077 case XML_XINCLUDE_START: 8078 case XML_XINCLUDE_END: 8079 if (cur->parent == NULL) 8080 return(NULL); 8081 if ((cur->parent->type == XML_ELEMENT_NODE) && 8082 ((cur->parent->name[0] == ' ') || 8083 (xmlStrEqual(cur->parent->name, 8084 BAD_CAST "fake node libxslt")))) 8085 return(NULL); 8086 return(cur->parent); 8087 case XML_ATTRIBUTE_NODE: { 8088 xmlAttrPtr att = (xmlAttrPtr) cur; 8089 8090 return(att->parent); 8091 } 8092 case XML_NAMESPACE_DECL: { 8093 xmlNsPtr ns = (xmlNsPtr) cur; 8094 8095 if ((ns->next != NULL) && 8096 (ns->next->type != XML_NAMESPACE_DECL)) 8097 return((xmlNodePtr) ns->next); 8098 /* Bad, how did that namespace end up here ? */ 8099 return(NULL); 8100 } 8101 case XML_DOCUMENT_NODE: 8102 case XML_DOCUMENT_TYPE_NODE: 8103 case XML_DOCUMENT_FRAG_NODE: 8104 case XML_HTML_DOCUMENT_NODE: 8105 #ifdef LIBXML_DOCB_ENABLED 8106 case XML_DOCB_DOCUMENT_NODE: 8107 #endif 8108 return(NULL); 8109 } 8110 return(NULL); 8111 } 8112 8113 /** 8114 * xmlXPathNextAncestorOrSelf: 8115 * @ctxt: the XPath Parser context 8116 * @cur: the current node in the traversal 8117 * 8118 * Traversal function for the "ancestor-or-self" direction 8119 * he ancestor-or-self axis contains the context node and ancestors of 8120 * the context node in reverse document order; thus the context node is 8121 * the first node on the axis, and the context node's parent the second; 8122 * parent here is defined the same as with the parent axis. 8123 * 8124 * Returns the next element following that axis 8125 */ 8126 xmlNodePtr 8127 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8128 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8129 if (cur == NULL) 8130 return(ctxt->context->node); 8131 return(xmlXPathNextAncestor(ctxt, cur)); 8132 } 8133 8134 /** 8135 * xmlXPathNextFollowingSibling: 8136 * @ctxt: the XPath Parser context 8137 * @cur: the current node in the traversal 8138 * 8139 * Traversal function for the "following-sibling" direction 8140 * The following-sibling axis contains the following siblings of the context 8141 * node in document order. 8142 * 8143 * Returns the next element following that axis 8144 */ 8145 xmlNodePtr 8146 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8147 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8148 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 8149 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 8150 return(NULL); 8151 if (cur == (xmlNodePtr) ctxt->context->doc) 8152 return(NULL); 8153 if (cur == NULL) 8154 return(ctxt->context->node->next); 8155 return(cur->next); 8156 } 8157 8158 /** 8159 * xmlXPathNextPrecedingSibling: 8160 * @ctxt: the XPath Parser context 8161 * @cur: the current node in the traversal 8162 * 8163 * Traversal function for the "preceding-sibling" direction 8164 * The preceding-sibling axis contains the preceding siblings of the context 8165 * node in reverse document order; the first preceding sibling is first on the 8166 * axis; the sibling preceding that node is the second on the axis and so on. 8167 * 8168 * Returns the next element following that axis 8169 */ 8170 xmlNodePtr 8171 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8172 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8173 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 8174 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 8175 return(NULL); 8176 if (cur == (xmlNodePtr) ctxt->context->doc) 8177 return(NULL); 8178 if (cur == NULL) 8179 return(ctxt->context->node->prev); 8180 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) { 8181 cur = cur->prev; 8182 if (cur == NULL) 8183 return(ctxt->context->node->prev); 8184 } 8185 return(cur->prev); 8186 } 8187 8188 /** 8189 * xmlXPathNextFollowing: 8190 * @ctxt: the XPath Parser context 8191 * @cur: the current node in the traversal 8192 * 8193 * Traversal function for the "following" direction 8194 * The following axis contains all nodes in the same document as the context 8195 * node that are after the context node in document order, excluding any 8196 * descendants and excluding attribute nodes and namespace nodes; the nodes 8197 * are ordered in document order 8198 * 8199 * Returns the next element following that axis 8200 */ 8201 xmlNodePtr 8202 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8203 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8204 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) && 8205 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL)) 8206 return(cur->children); 8207 8208 if (cur == NULL) { 8209 cur = ctxt->context->node; 8210 if (cur->type == XML_ATTRIBUTE_NODE) { 8211 cur = cur->parent; 8212 } else if (cur->type == XML_NAMESPACE_DECL) { 8213 xmlNsPtr ns = (xmlNsPtr) cur; 8214 8215 if ((ns->next == NULL) || 8216 (ns->next->type == XML_NAMESPACE_DECL)) 8217 return (NULL); 8218 cur = (xmlNodePtr) ns->next; 8219 } 8220 } 8221 if (cur == NULL) return(NULL) ; /* ERROR */ 8222 if (cur->next != NULL) return(cur->next) ; 8223 do { 8224 cur = cur->parent; 8225 if (cur == NULL) break; 8226 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL); 8227 if (cur->next != NULL) return(cur->next); 8228 } while (cur != NULL); 8229 return(cur); 8230 } 8231 8232 /* 8233 * xmlXPathIsAncestor: 8234 * @ancestor: the ancestor node 8235 * @node: the current node 8236 * 8237 * Check that @ancestor is a @node's ancestor 8238 * 8239 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise. 8240 */ 8241 static int 8242 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) { 8243 if ((ancestor == NULL) || (node == NULL)) return(0); 8244 if (node->type == XML_NAMESPACE_DECL) 8245 return(0); 8246 if (ancestor->type == XML_NAMESPACE_DECL) 8247 return(0); 8248 /* nodes need to be in the same document */ 8249 if (ancestor->doc != node->doc) return(0); 8250 /* avoid searching if ancestor or node is the root node */ 8251 if (ancestor == (xmlNodePtr) node->doc) return(1); 8252 if (node == (xmlNodePtr) ancestor->doc) return(0); 8253 while (node->parent != NULL) { 8254 if (node->parent == ancestor) 8255 return(1); 8256 node = node->parent; 8257 } 8258 return(0); 8259 } 8260 8261 /** 8262 * xmlXPathNextPreceding: 8263 * @ctxt: the XPath Parser context 8264 * @cur: the current node in the traversal 8265 * 8266 * Traversal function for the "preceding" direction 8267 * the preceding axis contains all nodes in the same document as the context 8268 * node that are before the context node in document order, excluding any 8269 * ancestors and excluding attribute nodes and namespace nodes; the nodes are 8270 * ordered in reverse document order 8271 * 8272 * Returns the next element following that axis 8273 */ 8274 xmlNodePtr 8275 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) 8276 { 8277 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8278 if (cur == NULL) { 8279 cur = ctxt->context->node; 8280 if (cur->type == XML_ATTRIBUTE_NODE) { 8281 cur = cur->parent; 8282 } else if (cur->type == XML_NAMESPACE_DECL) { 8283 xmlNsPtr ns = (xmlNsPtr) cur; 8284 8285 if ((ns->next == NULL) || 8286 (ns->next->type == XML_NAMESPACE_DECL)) 8287 return (NULL); 8288 cur = (xmlNodePtr) ns->next; 8289 } 8290 } 8291 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) 8292 return (NULL); 8293 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) 8294 cur = cur->prev; 8295 do { 8296 if (cur->prev != NULL) { 8297 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ; 8298 return (cur); 8299 } 8300 8301 cur = cur->parent; 8302 if (cur == NULL) 8303 return (NULL); 8304 if (cur == ctxt->context->doc->children) 8305 return (NULL); 8306 } while (xmlXPathIsAncestor(cur, ctxt->context->node)); 8307 return (cur); 8308 } 8309 8310 /** 8311 * xmlXPathNextPrecedingInternal: 8312 * @ctxt: the XPath Parser context 8313 * @cur: the current node in the traversal 8314 * 8315 * Traversal function for the "preceding" direction 8316 * the preceding axis contains all nodes in the same document as the context 8317 * node that are before the context node in document order, excluding any 8318 * ancestors and excluding attribute nodes and namespace nodes; the nodes are 8319 * ordered in reverse document order 8320 * This is a faster implementation but internal only since it requires a 8321 * state kept in the parser context: ctxt->ancestor. 8322 * 8323 * Returns the next element following that axis 8324 */ 8325 static xmlNodePtr 8326 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt, 8327 xmlNodePtr cur) 8328 { 8329 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8330 if (cur == NULL) { 8331 cur = ctxt->context->node; 8332 if (cur == NULL) 8333 return (NULL); 8334 if (cur->type == XML_ATTRIBUTE_NODE) { 8335 cur = cur->parent; 8336 } else if (cur->type == XML_NAMESPACE_DECL) { 8337 xmlNsPtr ns = (xmlNsPtr) cur; 8338 8339 if ((ns->next == NULL) || 8340 (ns->next->type == XML_NAMESPACE_DECL)) 8341 return (NULL); 8342 cur = (xmlNodePtr) ns->next; 8343 } 8344 ctxt->ancestor = cur->parent; 8345 } 8346 if (cur->type == XML_NAMESPACE_DECL) 8347 return(NULL); 8348 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) 8349 cur = cur->prev; 8350 while (cur->prev == NULL) { 8351 cur = cur->parent; 8352 if (cur == NULL) 8353 return (NULL); 8354 if (cur == ctxt->context->doc->children) 8355 return (NULL); 8356 if (cur != ctxt->ancestor) 8357 return (cur); 8358 ctxt->ancestor = cur->parent; 8359 } 8360 cur = cur->prev; 8361 while (cur->last != NULL) 8362 cur = cur->last; 8363 return (cur); 8364 } 8365 8366 /** 8367 * xmlXPathNextNamespace: 8368 * @ctxt: the XPath Parser context 8369 * @cur: the current attribute in the traversal 8370 * 8371 * Traversal function for the "namespace" direction 8372 * the namespace axis contains the namespace nodes of the context node; 8373 * the order of nodes on this axis is implementation-defined; the axis will 8374 * be empty unless the context node is an element 8375 * 8376 * We keep the XML namespace node at the end of the list. 8377 * 8378 * Returns the next element following that axis 8379 */ 8380 xmlNodePtr 8381 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8382 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8383 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL); 8384 if (cur == NULL) { 8385 if (ctxt->context->tmpNsList != NULL) 8386 xmlFree(ctxt->context->tmpNsList); 8387 ctxt->context->tmpNsList = 8388 xmlGetNsList(ctxt->context->doc, ctxt->context->node); 8389 ctxt->context->tmpNsNr = 0; 8390 if (ctxt->context->tmpNsList != NULL) { 8391 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) { 8392 ctxt->context->tmpNsNr++; 8393 } 8394 } 8395 return((xmlNodePtr) xmlXPathXMLNamespace); 8396 } 8397 if (ctxt->context->tmpNsNr > 0) { 8398 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr]; 8399 } else { 8400 if (ctxt->context->tmpNsList != NULL) 8401 xmlFree(ctxt->context->tmpNsList); 8402 ctxt->context->tmpNsList = NULL; 8403 return(NULL); 8404 } 8405 } 8406 8407 /** 8408 * xmlXPathNextAttribute: 8409 * @ctxt: the XPath Parser context 8410 * @cur: the current attribute in the traversal 8411 * 8412 * Traversal function for the "attribute" direction 8413 * TODO: support DTD inherited default attributes 8414 * 8415 * Returns the next element following that axis 8416 */ 8417 xmlNodePtr 8418 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8419 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8420 if (ctxt->context->node == NULL) 8421 return(NULL); 8422 if (ctxt->context->node->type != XML_ELEMENT_NODE) 8423 return(NULL); 8424 if (cur == NULL) { 8425 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc) 8426 return(NULL); 8427 return((xmlNodePtr)ctxt->context->node->properties); 8428 } 8429 return((xmlNodePtr)cur->next); 8430 } 8431 8432 /************************************************************************ 8433 * * 8434 * NodeTest Functions * 8435 * * 8436 ************************************************************************/ 8437 8438 #define IS_FUNCTION 200 8439 8440 8441 /************************************************************************ 8442 * * 8443 * Implicit tree core function library * 8444 * * 8445 ************************************************************************/ 8446 8447 /** 8448 * xmlXPathRoot: 8449 * @ctxt: the XPath Parser context 8450 * 8451 * Initialize the context to the root of the document 8452 */ 8453 void 8454 xmlXPathRoot(xmlXPathParserContextPtr ctxt) { 8455 if ((ctxt == NULL) || (ctxt->context == NULL)) 8456 return; 8457 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8458 (xmlNodePtr) ctxt->context->doc)); 8459 } 8460 8461 /************************************************************************ 8462 * * 8463 * The explicit core function library * 8464 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib * 8465 * * 8466 ************************************************************************/ 8467 8468 8469 /** 8470 * xmlXPathLastFunction: 8471 * @ctxt: the XPath Parser context 8472 * @nargs: the number of arguments 8473 * 8474 * Implement the last() XPath function 8475 * number last() 8476 * The last function returns the number of nodes in the context node list. 8477 */ 8478 void 8479 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8480 CHECK_ARITY(0); 8481 if (ctxt->context->contextSize >= 0) { 8482 valuePush(ctxt, 8483 xmlXPathCacheNewFloat(ctxt->context, 8484 (double) ctxt->context->contextSize)); 8485 #ifdef DEBUG_EXPR 8486 xmlGenericError(xmlGenericErrorContext, 8487 "last() : %d\n", ctxt->context->contextSize); 8488 #endif 8489 } else { 8490 XP_ERROR(XPATH_INVALID_CTXT_SIZE); 8491 } 8492 } 8493 8494 /** 8495 * xmlXPathPositionFunction: 8496 * @ctxt: the XPath Parser context 8497 * @nargs: the number of arguments 8498 * 8499 * Implement the position() XPath function 8500 * number position() 8501 * The position function returns the position of the context node in the 8502 * context node list. The first position is 1, and so the last position 8503 * will be equal to last(). 8504 */ 8505 void 8506 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8507 CHECK_ARITY(0); 8508 if (ctxt->context->proximityPosition >= 0) { 8509 valuePush(ctxt, 8510 xmlXPathCacheNewFloat(ctxt->context, 8511 (double) ctxt->context->proximityPosition)); 8512 #ifdef DEBUG_EXPR 8513 xmlGenericError(xmlGenericErrorContext, "position() : %d\n", 8514 ctxt->context->proximityPosition); 8515 #endif 8516 } else { 8517 XP_ERROR(XPATH_INVALID_CTXT_POSITION); 8518 } 8519 } 8520 8521 /** 8522 * xmlXPathCountFunction: 8523 * @ctxt: the XPath Parser context 8524 * @nargs: the number of arguments 8525 * 8526 * Implement the count() XPath function 8527 * number count(node-set) 8528 */ 8529 void 8530 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8531 xmlXPathObjectPtr cur; 8532 8533 CHECK_ARITY(1); 8534 if ((ctxt->value == NULL) || 8535 ((ctxt->value->type != XPATH_NODESET) && 8536 (ctxt->value->type != XPATH_XSLT_TREE))) 8537 XP_ERROR(XPATH_INVALID_TYPE); 8538 cur = valuePop(ctxt); 8539 8540 if ((cur == NULL) || (cur->nodesetval == NULL)) 8541 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0)); 8542 else 8543 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 8544 (double) cur->nodesetval->nodeNr)); 8545 xmlXPathReleaseObject(ctxt->context, cur); 8546 } 8547 8548 /** 8549 * xmlXPathGetElementsByIds: 8550 * @doc: the document 8551 * @ids: a whitespace separated list of IDs 8552 * 8553 * Selects elements by their unique ID. 8554 * 8555 * Returns a node-set of selected elements. 8556 */ 8557 static xmlNodeSetPtr 8558 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) { 8559 xmlNodeSetPtr ret; 8560 const xmlChar *cur = ids; 8561 xmlChar *ID; 8562 xmlAttrPtr attr; 8563 xmlNodePtr elem = NULL; 8564 8565 if (ids == NULL) return(NULL); 8566 8567 ret = xmlXPathNodeSetCreate(NULL); 8568 if (ret == NULL) 8569 return(ret); 8570 8571 while (IS_BLANK_CH(*cur)) cur++; 8572 while (*cur != 0) { 8573 while ((!IS_BLANK_CH(*cur)) && (*cur != 0)) 8574 cur++; 8575 8576 ID = xmlStrndup(ids, cur - ids); 8577 if (ID != NULL) { 8578 /* 8579 * We used to check the fact that the value passed 8580 * was an NCName, but this generated much troubles for 8581 * me and Aleksey Sanin, people blatantly violated that 8582 * constraint, like Visa3D spec. 8583 * if (xmlValidateNCName(ID, 1) == 0) 8584 */ 8585 attr = xmlGetID(doc, ID); 8586 if (attr != NULL) { 8587 if (attr->type == XML_ATTRIBUTE_NODE) 8588 elem = attr->parent; 8589 else if (attr->type == XML_ELEMENT_NODE) 8590 elem = (xmlNodePtr) attr; 8591 else 8592 elem = NULL; 8593 /* TODO: Check memory error. */ 8594 if (elem != NULL) 8595 xmlXPathNodeSetAdd(ret, elem); 8596 } 8597 xmlFree(ID); 8598 } 8599 8600 while (IS_BLANK_CH(*cur)) cur++; 8601 ids = cur; 8602 } 8603 return(ret); 8604 } 8605 8606 /** 8607 * xmlXPathIdFunction: 8608 * @ctxt: the XPath Parser context 8609 * @nargs: the number of arguments 8610 * 8611 * Implement the id() XPath function 8612 * node-set id(object) 8613 * The id function selects elements by their unique ID 8614 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set, 8615 * then the result is the union of the result of applying id to the 8616 * string value of each of the nodes in the argument node-set. When the 8617 * argument to id is of any other type, the argument is converted to a 8618 * string as if by a call to the string function; the string is split 8619 * into a whitespace-separated list of tokens (whitespace is any sequence 8620 * of characters matching the production S); the result is a node-set 8621 * containing the elements in the same document as the context node that 8622 * have a unique ID equal to any of the tokens in the list. 8623 */ 8624 void 8625 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8626 xmlChar *tokens; 8627 xmlNodeSetPtr ret; 8628 xmlXPathObjectPtr obj; 8629 8630 CHECK_ARITY(1); 8631 obj = valuePop(ctxt); 8632 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 8633 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) { 8634 xmlNodeSetPtr ns; 8635 int i; 8636 8637 /* TODO: Check memory error. */ 8638 ret = xmlXPathNodeSetCreate(NULL); 8639 8640 if (obj->nodesetval != NULL) { 8641 for (i = 0; i < obj->nodesetval->nodeNr; i++) { 8642 tokens = 8643 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]); 8644 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens); 8645 /* TODO: Check memory error. */ 8646 ret = xmlXPathNodeSetMerge(ret, ns); 8647 xmlXPathFreeNodeSet(ns); 8648 if (tokens != NULL) 8649 xmlFree(tokens); 8650 } 8651 } 8652 xmlXPathReleaseObject(ctxt->context, obj); 8653 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret)); 8654 return; 8655 } 8656 obj = xmlXPathCacheConvertString(ctxt->context, obj); 8657 if (obj == NULL) return; 8658 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval); 8659 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret)); 8660 xmlXPathReleaseObject(ctxt->context, obj); 8661 return; 8662 } 8663 8664 /** 8665 * xmlXPathLocalNameFunction: 8666 * @ctxt: the XPath Parser context 8667 * @nargs: the number of arguments 8668 * 8669 * Implement the local-name() XPath function 8670 * string local-name(node-set?) 8671 * The local-name function returns a string containing the local part 8672 * of the name of the node in the argument node-set that is first in 8673 * document order. If the node-set is empty or the first node has no 8674 * name, an empty string is returned. If the argument is omitted it 8675 * defaults to the context node. 8676 */ 8677 void 8678 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8679 xmlXPathObjectPtr cur; 8680 8681 if (ctxt == NULL) return; 8682 8683 if (nargs == 0) { 8684 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8685 ctxt->context->node)); 8686 nargs = 1; 8687 } 8688 8689 CHECK_ARITY(1); 8690 if ((ctxt->value == NULL) || 8691 ((ctxt->value->type != XPATH_NODESET) && 8692 (ctxt->value->type != XPATH_XSLT_TREE))) 8693 XP_ERROR(XPATH_INVALID_TYPE); 8694 cur = valuePop(ctxt); 8695 8696 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 8697 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8698 } else { 8699 int i = 0; /* Should be first in document order !!!!! */ 8700 switch (cur->nodesetval->nodeTab[i]->type) { 8701 case XML_ELEMENT_NODE: 8702 case XML_ATTRIBUTE_NODE: 8703 case XML_PI_NODE: 8704 if (cur->nodesetval->nodeTab[i]->name[0] == ' ') 8705 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8706 else 8707 valuePush(ctxt, 8708 xmlXPathCacheNewString(ctxt->context, 8709 cur->nodesetval->nodeTab[i]->name)); 8710 break; 8711 case XML_NAMESPACE_DECL: 8712 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 8713 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix)); 8714 break; 8715 default: 8716 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8717 } 8718 } 8719 xmlXPathReleaseObject(ctxt->context, cur); 8720 } 8721 8722 /** 8723 * xmlXPathNamespaceURIFunction: 8724 * @ctxt: the XPath Parser context 8725 * @nargs: the number of arguments 8726 * 8727 * Implement the namespace-uri() XPath function 8728 * string namespace-uri(node-set?) 8729 * The namespace-uri function returns a string containing the 8730 * namespace URI of the expanded name of the node in the argument 8731 * node-set that is first in document order. If the node-set is empty, 8732 * the first node has no name, or the expanded name has no namespace 8733 * URI, an empty string is returned. If the argument is omitted it 8734 * defaults to the context node. 8735 */ 8736 void 8737 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8738 xmlXPathObjectPtr cur; 8739 8740 if (ctxt == NULL) return; 8741 8742 if (nargs == 0) { 8743 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8744 ctxt->context->node)); 8745 nargs = 1; 8746 } 8747 CHECK_ARITY(1); 8748 if ((ctxt->value == NULL) || 8749 ((ctxt->value->type != XPATH_NODESET) && 8750 (ctxt->value->type != XPATH_XSLT_TREE))) 8751 XP_ERROR(XPATH_INVALID_TYPE); 8752 cur = valuePop(ctxt); 8753 8754 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 8755 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8756 } else { 8757 int i = 0; /* Should be first in document order !!!!! */ 8758 switch (cur->nodesetval->nodeTab[i]->type) { 8759 case XML_ELEMENT_NODE: 8760 case XML_ATTRIBUTE_NODE: 8761 if (cur->nodesetval->nodeTab[i]->ns == NULL) 8762 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8763 else 8764 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 8765 cur->nodesetval->nodeTab[i]->ns->href)); 8766 break; 8767 default: 8768 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8769 } 8770 } 8771 xmlXPathReleaseObject(ctxt->context, cur); 8772 } 8773 8774 /** 8775 * xmlXPathNameFunction: 8776 * @ctxt: the XPath Parser context 8777 * @nargs: the number of arguments 8778 * 8779 * Implement the name() XPath function 8780 * string name(node-set?) 8781 * The name function returns a string containing a QName representing 8782 * the name of the node in the argument node-set that is first in document 8783 * order. The QName must represent the name with respect to the namespace 8784 * declarations in effect on the node whose name is being represented. 8785 * Typically, this will be the form in which the name occurred in the XML 8786 * source. This need not be the case if there are namespace declarations 8787 * in effect on the node that associate multiple prefixes with the same 8788 * namespace. However, an implementation may include information about 8789 * the original prefix in its representation of nodes; in this case, an 8790 * implementation can ensure that the returned string is always the same 8791 * as the QName used in the XML source. If the argument it omitted it 8792 * defaults to the context node. 8793 * Libxml keep the original prefix so the "real qualified name" used is 8794 * returned. 8795 */ 8796 static void 8797 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) 8798 { 8799 xmlXPathObjectPtr cur; 8800 8801 if (nargs == 0) { 8802 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8803 ctxt->context->node)); 8804 nargs = 1; 8805 } 8806 8807 CHECK_ARITY(1); 8808 if ((ctxt->value == NULL) || 8809 ((ctxt->value->type != XPATH_NODESET) && 8810 (ctxt->value->type != XPATH_XSLT_TREE))) 8811 XP_ERROR(XPATH_INVALID_TYPE); 8812 cur = valuePop(ctxt); 8813 8814 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 8815 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8816 } else { 8817 int i = 0; /* Should be first in document order !!!!! */ 8818 8819 switch (cur->nodesetval->nodeTab[i]->type) { 8820 case XML_ELEMENT_NODE: 8821 case XML_ATTRIBUTE_NODE: 8822 if (cur->nodesetval->nodeTab[i]->name[0] == ' ') 8823 valuePush(ctxt, 8824 xmlXPathCacheNewCString(ctxt->context, "")); 8825 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) || 8826 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) { 8827 valuePush(ctxt, 8828 xmlXPathCacheNewString(ctxt->context, 8829 cur->nodesetval->nodeTab[i]->name)); 8830 } else { 8831 xmlChar *fullname; 8832 8833 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name, 8834 cur->nodesetval->nodeTab[i]->ns->prefix, 8835 NULL, 0); 8836 if (fullname == cur->nodesetval->nodeTab[i]->name) 8837 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name); 8838 if (fullname == NULL) { 8839 XP_ERROR(XPATH_MEMORY_ERROR); 8840 } 8841 valuePush(ctxt, xmlXPathCacheWrapString( 8842 ctxt->context, fullname)); 8843 } 8844 break; 8845 default: 8846 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8847 cur->nodesetval->nodeTab[i])); 8848 xmlXPathLocalNameFunction(ctxt, 1); 8849 } 8850 } 8851 xmlXPathReleaseObject(ctxt->context, cur); 8852 } 8853 8854 8855 /** 8856 * xmlXPathStringFunction: 8857 * @ctxt: the XPath Parser context 8858 * @nargs: the number of arguments 8859 * 8860 * Implement the string() XPath function 8861 * string string(object?) 8862 * The string function converts an object to a string as follows: 8863 * - A node-set is converted to a string by returning the value of 8864 * the node in the node-set that is first in document order. 8865 * If the node-set is empty, an empty string is returned. 8866 * - A number is converted to a string as follows 8867 * + NaN is converted to the string NaN 8868 * + positive zero is converted to the string 0 8869 * + negative zero is converted to the string 0 8870 * + positive infinity is converted to the string Infinity 8871 * + negative infinity is converted to the string -Infinity 8872 * + if the number is an integer, the number is represented in 8873 * decimal form as a Number with no decimal point and no leading 8874 * zeros, preceded by a minus sign (-) if the number is negative 8875 * + otherwise, the number is represented in decimal form as a 8876 * Number including a decimal point with at least one digit 8877 * before the decimal point and at least one digit after the 8878 * decimal point, preceded by a minus sign (-) if the number 8879 * is negative; there must be no leading zeros before the decimal 8880 * point apart possibly from the one required digit immediately 8881 * before the decimal point; beyond the one required digit 8882 * after the decimal point there must be as many, but only as 8883 * many, more digits as are needed to uniquely distinguish the 8884 * number from all other IEEE 754 numeric values. 8885 * - The boolean false value is converted to the string false. 8886 * The boolean true value is converted to the string true. 8887 * 8888 * If the argument is omitted, it defaults to a node-set with the 8889 * context node as its only member. 8890 */ 8891 void 8892 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8893 xmlXPathObjectPtr cur; 8894 8895 if (ctxt == NULL) return; 8896 if (nargs == 0) { 8897 valuePush(ctxt, 8898 xmlXPathCacheWrapString(ctxt->context, 8899 xmlXPathCastNodeToString(ctxt->context->node))); 8900 return; 8901 } 8902 8903 CHECK_ARITY(1); 8904 cur = valuePop(ctxt); 8905 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 8906 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur)); 8907 } 8908 8909 /** 8910 * xmlXPathStringLengthFunction: 8911 * @ctxt: the XPath Parser context 8912 * @nargs: the number of arguments 8913 * 8914 * Implement the string-length() XPath function 8915 * number string-length(string?) 8916 * The string-length returns the number of characters in the string 8917 * (see [3.6 Strings]). If the argument is omitted, it defaults to 8918 * the context node converted to a string, in other words the value 8919 * of the context node. 8920 */ 8921 void 8922 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8923 xmlXPathObjectPtr cur; 8924 8925 if (nargs == 0) { 8926 if ((ctxt == NULL) || (ctxt->context == NULL)) 8927 return; 8928 if (ctxt->context->node == NULL) { 8929 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0)); 8930 } else { 8931 xmlChar *content; 8932 8933 content = xmlXPathCastNodeToString(ctxt->context->node); 8934 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 8935 xmlUTF8Strlen(content))); 8936 xmlFree(content); 8937 } 8938 return; 8939 } 8940 CHECK_ARITY(1); 8941 CAST_TO_STRING; 8942 CHECK_TYPE(XPATH_STRING); 8943 cur = valuePop(ctxt); 8944 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 8945 xmlUTF8Strlen(cur->stringval))); 8946 xmlXPathReleaseObject(ctxt->context, cur); 8947 } 8948 8949 /** 8950 * xmlXPathConcatFunction: 8951 * @ctxt: the XPath Parser context 8952 * @nargs: the number of arguments 8953 * 8954 * Implement the concat() XPath function 8955 * string concat(string, string, string*) 8956 * The concat function returns the concatenation of its arguments. 8957 */ 8958 void 8959 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8960 xmlXPathObjectPtr cur, newobj; 8961 xmlChar *tmp; 8962 8963 if (ctxt == NULL) return; 8964 if (nargs < 2) { 8965 CHECK_ARITY(2); 8966 } 8967 8968 CAST_TO_STRING; 8969 cur = valuePop(ctxt); 8970 if ((cur == NULL) || (cur->type != XPATH_STRING)) { 8971 xmlXPathReleaseObject(ctxt->context, cur); 8972 return; 8973 } 8974 nargs--; 8975 8976 while (nargs > 0) { 8977 CAST_TO_STRING; 8978 newobj = valuePop(ctxt); 8979 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) { 8980 xmlXPathReleaseObject(ctxt->context, newobj); 8981 xmlXPathReleaseObject(ctxt->context, cur); 8982 XP_ERROR(XPATH_INVALID_TYPE); 8983 } 8984 tmp = xmlStrcat(newobj->stringval, cur->stringval); 8985 newobj->stringval = cur->stringval; 8986 cur->stringval = tmp; 8987 xmlXPathReleaseObject(ctxt->context, newobj); 8988 nargs--; 8989 } 8990 valuePush(ctxt, cur); 8991 } 8992 8993 /** 8994 * xmlXPathContainsFunction: 8995 * @ctxt: the XPath Parser context 8996 * @nargs: the number of arguments 8997 * 8998 * Implement the contains() XPath function 8999 * boolean contains(string, string) 9000 * The contains function returns true if the first argument string 9001 * contains the second argument string, and otherwise returns false. 9002 */ 9003 void 9004 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9005 xmlXPathObjectPtr hay, needle; 9006 9007 CHECK_ARITY(2); 9008 CAST_TO_STRING; 9009 CHECK_TYPE(XPATH_STRING); 9010 needle = valuePop(ctxt); 9011 CAST_TO_STRING; 9012 hay = valuePop(ctxt); 9013 9014 if ((hay == NULL) || (hay->type != XPATH_STRING)) { 9015 xmlXPathReleaseObject(ctxt->context, hay); 9016 xmlXPathReleaseObject(ctxt->context, needle); 9017 XP_ERROR(XPATH_INVALID_TYPE); 9018 } 9019 if (xmlStrstr(hay->stringval, needle->stringval)) 9020 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); 9021 else 9022 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); 9023 xmlXPathReleaseObject(ctxt->context, hay); 9024 xmlXPathReleaseObject(ctxt->context, needle); 9025 } 9026 9027 /** 9028 * xmlXPathStartsWithFunction: 9029 * @ctxt: the XPath Parser context 9030 * @nargs: the number of arguments 9031 * 9032 * Implement the starts-with() XPath function 9033 * boolean starts-with(string, string) 9034 * The starts-with function returns true if the first argument string 9035 * starts with the second argument string, and otherwise returns false. 9036 */ 9037 void 9038 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9039 xmlXPathObjectPtr hay, needle; 9040 int n; 9041 9042 CHECK_ARITY(2); 9043 CAST_TO_STRING; 9044 CHECK_TYPE(XPATH_STRING); 9045 needle = valuePop(ctxt); 9046 CAST_TO_STRING; 9047 hay = valuePop(ctxt); 9048 9049 if ((hay == NULL) || (hay->type != XPATH_STRING)) { 9050 xmlXPathReleaseObject(ctxt->context, hay); 9051 xmlXPathReleaseObject(ctxt->context, needle); 9052 XP_ERROR(XPATH_INVALID_TYPE); 9053 } 9054 n = xmlStrlen(needle->stringval); 9055 if (xmlStrncmp(hay->stringval, needle->stringval, n)) 9056 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); 9057 else 9058 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); 9059 xmlXPathReleaseObject(ctxt->context, hay); 9060 xmlXPathReleaseObject(ctxt->context, needle); 9061 } 9062 9063 /** 9064 * xmlXPathSubstringFunction: 9065 * @ctxt: the XPath Parser context 9066 * @nargs: the number of arguments 9067 * 9068 * Implement the substring() XPath function 9069 * string substring(string, number, number?) 9070 * The substring function returns the substring of the first argument 9071 * starting at the position specified in the second argument with 9072 * length specified in the third argument. For example, 9073 * substring("12345",2,3) returns "234". If the third argument is not 9074 * specified, it returns the substring starting at the position specified 9075 * in the second argument and continuing to the end of the string. For 9076 * example, substring("12345",2) returns "2345". More precisely, each 9077 * character in the string (see [3.6 Strings]) is considered to have a 9078 * numeric position: the position of the first character is 1, the position 9079 * of the second character is 2 and so on. The returned substring contains 9080 * those characters for which the position of the character is greater than 9081 * or equal to the second argument and, if the third argument is specified, 9082 * less than the sum of the second and third arguments; the comparisons 9083 * and addition used for the above follow the standard IEEE 754 rules. Thus: 9084 * - substring("12345", 1.5, 2.6) returns "234" 9085 * - substring("12345", 0, 3) returns "12" 9086 * - substring("12345", 0 div 0, 3) returns "" 9087 * - substring("12345", 1, 0 div 0) returns "" 9088 * - substring("12345", -42, 1 div 0) returns "12345" 9089 * - substring("12345", -1 div 0, 1 div 0) returns "" 9090 */ 9091 void 9092 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9093 xmlXPathObjectPtr str, start, len; 9094 double le=0, in; 9095 int i = 1, j = INT_MAX; 9096 9097 if (nargs < 2) { 9098 CHECK_ARITY(2); 9099 } 9100 if (nargs > 3) { 9101 CHECK_ARITY(3); 9102 } 9103 /* 9104 * take care of possible last (position) argument 9105 */ 9106 if (nargs == 3) { 9107 CAST_TO_NUMBER; 9108 CHECK_TYPE(XPATH_NUMBER); 9109 len = valuePop(ctxt); 9110 le = len->floatval; 9111 xmlXPathReleaseObject(ctxt->context, len); 9112 } 9113 9114 CAST_TO_NUMBER; 9115 CHECK_TYPE(XPATH_NUMBER); 9116 start = valuePop(ctxt); 9117 in = start->floatval; 9118 xmlXPathReleaseObject(ctxt->context, start); 9119 CAST_TO_STRING; 9120 CHECK_TYPE(XPATH_STRING); 9121 str = valuePop(ctxt); 9122 9123 if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */ 9124 i = INT_MAX; 9125 } else if (in >= 1.0) { 9126 i = (int)in; 9127 if (in - floor(in) >= 0.5) 9128 i += 1; 9129 } 9130 9131 if (nargs == 3) { 9132 double rin, rle, end; 9133 9134 rin = floor(in); 9135 if (in - rin >= 0.5) 9136 rin += 1.0; 9137 9138 rle = floor(le); 9139 if (le - rle >= 0.5) 9140 rle += 1.0; 9141 9142 end = rin + rle; 9143 if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */ 9144 j = 1; 9145 } else if (end < INT_MAX) { 9146 j = (int)end; 9147 } 9148 } 9149 9150 if (i < j) { 9151 xmlChar *ret = xmlUTF8Strsub(str->stringval, i - 1, j - i); 9152 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret)); 9153 xmlFree(ret); 9154 } else { 9155 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 9156 } 9157 9158 xmlXPathReleaseObject(ctxt->context, str); 9159 } 9160 9161 /** 9162 * xmlXPathSubstringBeforeFunction: 9163 * @ctxt: the XPath Parser context 9164 * @nargs: the number of arguments 9165 * 9166 * Implement the substring-before() XPath function 9167 * string substring-before(string, string) 9168 * The substring-before function returns the substring of the first 9169 * argument string that precedes the first occurrence of the second 9170 * argument string in the first argument string, or the empty string 9171 * if the first argument string does not contain the second argument 9172 * string. For example, substring-before("1999/04/01","/") returns 1999. 9173 */ 9174 void 9175 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9176 xmlXPathObjectPtr str; 9177 xmlXPathObjectPtr find; 9178 xmlBufPtr target; 9179 const xmlChar *point; 9180 int offset; 9181 9182 CHECK_ARITY(2); 9183 CAST_TO_STRING; 9184 find = valuePop(ctxt); 9185 CAST_TO_STRING; 9186 str = valuePop(ctxt); 9187 9188 target = xmlBufCreate(); 9189 if (target) { 9190 point = xmlStrstr(str->stringval, find->stringval); 9191 if (point) { 9192 offset = (int)(point - str->stringval); 9193 xmlBufAdd(target, str->stringval, offset); 9194 } 9195 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9196 xmlBufContent(target))); 9197 xmlBufFree(target); 9198 } 9199 xmlXPathReleaseObject(ctxt->context, str); 9200 xmlXPathReleaseObject(ctxt->context, find); 9201 } 9202 9203 /** 9204 * xmlXPathSubstringAfterFunction: 9205 * @ctxt: the XPath Parser context 9206 * @nargs: the number of arguments 9207 * 9208 * Implement the substring-after() XPath function 9209 * string substring-after(string, string) 9210 * The substring-after function returns the substring of the first 9211 * argument string that follows the first occurrence of the second 9212 * argument string in the first argument string, or the empty stringi 9213 * if the first argument string does not contain the second argument 9214 * string. For example, substring-after("1999/04/01","/") returns 04/01, 9215 * and substring-after("1999/04/01","19") returns 99/04/01. 9216 */ 9217 void 9218 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9219 xmlXPathObjectPtr str; 9220 xmlXPathObjectPtr find; 9221 xmlBufPtr target; 9222 const xmlChar *point; 9223 int offset; 9224 9225 CHECK_ARITY(2); 9226 CAST_TO_STRING; 9227 find = valuePop(ctxt); 9228 CAST_TO_STRING; 9229 str = valuePop(ctxt); 9230 9231 target = xmlBufCreate(); 9232 if (target) { 9233 point = xmlStrstr(str->stringval, find->stringval); 9234 if (point) { 9235 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval); 9236 xmlBufAdd(target, &str->stringval[offset], 9237 xmlStrlen(str->stringval) - offset); 9238 } 9239 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9240 xmlBufContent(target))); 9241 xmlBufFree(target); 9242 } 9243 xmlXPathReleaseObject(ctxt->context, str); 9244 xmlXPathReleaseObject(ctxt->context, find); 9245 } 9246 9247 /** 9248 * xmlXPathNormalizeFunction: 9249 * @ctxt: the XPath Parser context 9250 * @nargs: the number of arguments 9251 * 9252 * Implement the normalize-space() XPath function 9253 * string normalize-space(string?) 9254 * The normalize-space function returns the argument string with white 9255 * space normalized by stripping leading and trailing whitespace 9256 * and replacing sequences of whitespace characters by a single 9257 * space. Whitespace characters are the same allowed by the S production 9258 * in XML. If the argument is omitted, it defaults to the context 9259 * node converted to a string, in other words the value of the context node. 9260 */ 9261 void 9262 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9263 xmlXPathObjectPtr obj = NULL; 9264 xmlChar *source = NULL; 9265 xmlBufPtr target; 9266 xmlChar blank; 9267 9268 if (ctxt == NULL) return; 9269 if (nargs == 0) { 9270 /* Use current context node */ 9271 valuePush(ctxt, 9272 xmlXPathCacheWrapString(ctxt->context, 9273 xmlXPathCastNodeToString(ctxt->context->node))); 9274 nargs = 1; 9275 } 9276 9277 CHECK_ARITY(1); 9278 CAST_TO_STRING; 9279 CHECK_TYPE(XPATH_STRING); 9280 obj = valuePop(ctxt); 9281 source = obj->stringval; 9282 9283 target = xmlBufCreate(); 9284 if (target && source) { 9285 9286 /* Skip leading whitespaces */ 9287 while (IS_BLANK_CH(*source)) 9288 source++; 9289 9290 /* Collapse intermediate whitespaces, and skip trailing whitespaces */ 9291 blank = 0; 9292 while (*source) { 9293 if (IS_BLANK_CH(*source)) { 9294 blank = 0x20; 9295 } else { 9296 if (blank) { 9297 xmlBufAdd(target, &blank, 1); 9298 blank = 0; 9299 } 9300 xmlBufAdd(target, source, 1); 9301 } 9302 source++; 9303 } 9304 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9305 xmlBufContent(target))); 9306 xmlBufFree(target); 9307 } 9308 xmlXPathReleaseObject(ctxt->context, obj); 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 len = 0, 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 len += l; 10527 NEXTL(l); 10528 c = CUR_CHAR(l); 10529 } 10530 ret = xmlStrndup(cur, ctxt->cur - cur); 10531 ctxt->cur = cur; 10532 return(ret); 10533 } 10534 10535 /** 10536 * xmlXPathCompPathExpr: 10537 * @ctxt: the XPath Parser context 10538 * 10539 * [19] PathExpr ::= LocationPath 10540 * | FilterExpr 10541 * | FilterExpr '/' RelativeLocationPath 10542 * | FilterExpr '//' RelativeLocationPath 10543 * 10544 * Compile a path expression. 10545 * The / operator and // operators combine an arbitrary expression 10546 * and a relative location path. It is an error if the expression 10547 * does not evaluate to a node-set. 10548 * The / operator does composition in the same way as when / is 10549 * used in a location path. As in location paths, // is short for 10550 * /descendant-or-self::node()/. 10551 */ 10552 10553 static void 10554 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) { 10555 int lc = 1; /* Should we branch to LocationPath ? */ 10556 xmlChar *name = NULL; /* we may have to preparse a name to find out */ 10557 10558 SKIP_BLANKS; 10559 if ((CUR == '$') || (CUR == '(') || 10560 (IS_ASCII_DIGIT(CUR)) || 10561 (CUR == '\'') || (CUR == '"') || 10562 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) { 10563 lc = 0; 10564 } else if (CUR == '*') { 10565 /* relative or absolute location path */ 10566 lc = 1; 10567 } else if (CUR == '/') { 10568 /* relative or absolute location path */ 10569 lc = 1; 10570 } else if (CUR == '@') { 10571 /* relative abbreviated attribute location path */ 10572 lc = 1; 10573 } else if (CUR == '.') { 10574 /* relative abbreviated attribute location path */ 10575 lc = 1; 10576 } else { 10577 /* 10578 * Problem is finding if we have a name here whether it's: 10579 * - a nodetype 10580 * - a function call in which case it's followed by '(' 10581 * - an axis in which case it's followed by ':' 10582 * - a element name 10583 * We do an a priori analysis here rather than having to 10584 * maintain parsed token content through the recursive function 10585 * calls. This looks uglier but makes the code easier to 10586 * read/write/debug. 10587 */ 10588 SKIP_BLANKS; 10589 name = xmlXPathScanName(ctxt); 10590 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) { 10591 #ifdef DEBUG_STEP 10592 xmlGenericError(xmlGenericErrorContext, 10593 "PathExpr: Axis\n"); 10594 #endif 10595 lc = 1; 10596 xmlFree(name); 10597 } else if (name != NULL) { 10598 int len =xmlStrlen(name); 10599 10600 10601 while (NXT(len) != 0) { 10602 if (NXT(len) == '/') { 10603 /* element name */ 10604 #ifdef DEBUG_STEP 10605 xmlGenericError(xmlGenericErrorContext, 10606 "PathExpr: AbbrRelLocation\n"); 10607 #endif 10608 lc = 1; 10609 break; 10610 } else if (IS_BLANK_CH(NXT(len))) { 10611 /* ignore blanks */ 10612 ; 10613 } else if (NXT(len) == ':') { 10614 #ifdef DEBUG_STEP 10615 xmlGenericError(xmlGenericErrorContext, 10616 "PathExpr: AbbrRelLocation\n"); 10617 #endif 10618 lc = 1; 10619 break; 10620 } else if ((NXT(len) == '(')) { 10621 /* Node Type or Function */ 10622 if (xmlXPathIsNodeType(name)) { 10623 #ifdef DEBUG_STEP 10624 xmlGenericError(xmlGenericErrorContext, 10625 "PathExpr: Type search\n"); 10626 #endif 10627 lc = 1; 10628 #ifdef LIBXML_XPTR_ENABLED 10629 } else if (ctxt->xptr && 10630 xmlStrEqual(name, BAD_CAST "range-to")) { 10631 lc = 1; 10632 #endif 10633 } else { 10634 #ifdef DEBUG_STEP 10635 xmlGenericError(xmlGenericErrorContext, 10636 "PathExpr: function call\n"); 10637 #endif 10638 lc = 0; 10639 } 10640 break; 10641 } else if ((NXT(len) == '[')) { 10642 /* element name */ 10643 #ifdef DEBUG_STEP 10644 xmlGenericError(xmlGenericErrorContext, 10645 "PathExpr: AbbrRelLocation\n"); 10646 #endif 10647 lc = 1; 10648 break; 10649 } else if ((NXT(len) == '<') || (NXT(len) == '>') || 10650 (NXT(len) == '=')) { 10651 lc = 1; 10652 break; 10653 } else { 10654 lc = 1; 10655 break; 10656 } 10657 len++; 10658 } 10659 if (NXT(len) == 0) { 10660 #ifdef DEBUG_STEP 10661 xmlGenericError(xmlGenericErrorContext, 10662 "PathExpr: AbbrRelLocation\n"); 10663 #endif 10664 /* element name */ 10665 lc = 1; 10666 } 10667 xmlFree(name); 10668 } else { 10669 /* make sure all cases are covered explicitly */ 10670 XP_ERROR(XPATH_EXPR_ERROR); 10671 } 10672 } 10673 10674 if (lc) { 10675 if (CUR == '/') { 10676 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0); 10677 } else { 10678 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0); 10679 } 10680 xmlXPathCompLocationPath(ctxt); 10681 } else { 10682 xmlXPathCompFilterExpr(ctxt); 10683 CHECK_ERROR; 10684 if ((CUR == '/') && (NXT(1) == '/')) { 10685 SKIP(2); 10686 SKIP_BLANKS; 10687 10688 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 10689 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 10690 10691 xmlXPathCompRelativeLocationPath(ctxt); 10692 } else if (CUR == '/') { 10693 xmlXPathCompRelativeLocationPath(ctxt); 10694 } 10695 } 10696 SKIP_BLANKS; 10697 } 10698 10699 /** 10700 * xmlXPathCompUnionExpr: 10701 * @ctxt: the XPath Parser context 10702 * 10703 * [18] UnionExpr ::= PathExpr 10704 * | UnionExpr '|' PathExpr 10705 * 10706 * Compile an union expression. 10707 */ 10708 10709 static void 10710 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) { 10711 xmlXPathCompPathExpr(ctxt); 10712 CHECK_ERROR; 10713 SKIP_BLANKS; 10714 while (CUR == '|') { 10715 int op1 = ctxt->comp->last; 10716 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0); 10717 10718 NEXT; 10719 SKIP_BLANKS; 10720 xmlXPathCompPathExpr(ctxt); 10721 10722 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0); 10723 10724 SKIP_BLANKS; 10725 } 10726 } 10727 10728 /** 10729 * xmlXPathCompUnaryExpr: 10730 * @ctxt: the XPath Parser context 10731 * 10732 * [27] UnaryExpr ::= UnionExpr 10733 * | '-' UnaryExpr 10734 * 10735 * Compile an unary expression. 10736 */ 10737 10738 static void 10739 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) { 10740 int minus = 0; 10741 int found = 0; 10742 10743 SKIP_BLANKS; 10744 while (CUR == '-') { 10745 minus = 1 - minus; 10746 found = 1; 10747 NEXT; 10748 SKIP_BLANKS; 10749 } 10750 10751 xmlXPathCompUnionExpr(ctxt); 10752 CHECK_ERROR; 10753 if (found) { 10754 if (minus) 10755 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0); 10756 else 10757 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0); 10758 } 10759 } 10760 10761 /** 10762 * xmlXPathCompMultiplicativeExpr: 10763 * @ctxt: the XPath Parser context 10764 * 10765 * [26] MultiplicativeExpr ::= UnaryExpr 10766 * | MultiplicativeExpr MultiplyOperator UnaryExpr 10767 * | MultiplicativeExpr 'div' UnaryExpr 10768 * | MultiplicativeExpr 'mod' UnaryExpr 10769 * [34] MultiplyOperator ::= '*' 10770 * 10771 * Compile an Additive expression. 10772 */ 10773 10774 static void 10775 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) { 10776 xmlXPathCompUnaryExpr(ctxt); 10777 CHECK_ERROR; 10778 SKIP_BLANKS; 10779 while ((CUR == '*') || 10780 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) || 10781 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) { 10782 int op = -1; 10783 int op1 = ctxt->comp->last; 10784 10785 if (CUR == '*') { 10786 op = 0; 10787 NEXT; 10788 } else if (CUR == 'd') { 10789 op = 1; 10790 SKIP(3); 10791 } else if (CUR == 'm') { 10792 op = 2; 10793 SKIP(3); 10794 } 10795 SKIP_BLANKS; 10796 xmlXPathCompUnaryExpr(ctxt); 10797 CHECK_ERROR; 10798 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0); 10799 SKIP_BLANKS; 10800 } 10801 } 10802 10803 /** 10804 * xmlXPathCompAdditiveExpr: 10805 * @ctxt: the XPath Parser context 10806 * 10807 * [25] AdditiveExpr ::= MultiplicativeExpr 10808 * | AdditiveExpr '+' MultiplicativeExpr 10809 * | AdditiveExpr '-' MultiplicativeExpr 10810 * 10811 * Compile an Additive expression. 10812 */ 10813 10814 static void 10815 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) { 10816 10817 xmlXPathCompMultiplicativeExpr(ctxt); 10818 CHECK_ERROR; 10819 SKIP_BLANKS; 10820 while ((CUR == '+') || (CUR == '-')) { 10821 int plus; 10822 int op1 = ctxt->comp->last; 10823 10824 if (CUR == '+') plus = 1; 10825 else plus = 0; 10826 NEXT; 10827 SKIP_BLANKS; 10828 xmlXPathCompMultiplicativeExpr(ctxt); 10829 CHECK_ERROR; 10830 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0); 10831 SKIP_BLANKS; 10832 } 10833 } 10834 10835 /** 10836 * xmlXPathCompRelationalExpr: 10837 * @ctxt: the XPath Parser context 10838 * 10839 * [24] RelationalExpr ::= AdditiveExpr 10840 * | RelationalExpr '<' AdditiveExpr 10841 * | RelationalExpr '>' AdditiveExpr 10842 * | RelationalExpr '<=' AdditiveExpr 10843 * | RelationalExpr '>=' AdditiveExpr 10844 * 10845 * A <= B > C is allowed ? Answer from James, yes with 10846 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr 10847 * which is basically what got implemented. 10848 * 10849 * Compile a Relational expression, then push the result 10850 * on the stack 10851 */ 10852 10853 static void 10854 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) { 10855 xmlXPathCompAdditiveExpr(ctxt); 10856 CHECK_ERROR; 10857 SKIP_BLANKS; 10858 while ((CUR == '<') || (CUR == '>')) { 10859 int inf, strict; 10860 int op1 = ctxt->comp->last; 10861 10862 if (CUR == '<') inf = 1; 10863 else inf = 0; 10864 if (NXT(1) == '=') strict = 0; 10865 else strict = 1; 10866 NEXT; 10867 if (!strict) NEXT; 10868 SKIP_BLANKS; 10869 xmlXPathCompAdditiveExpr(ctxt); 10870 CHECK_ERROR; 10871 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict); 10872 SKIP_BLANKS; 10873 } 10874 } 10875 10876 /** 10877 * xmlXPathCompEqualityExpr: 10878 * @ctxt: the XPath Parser context 10879 * 10880 * [23] EqualityExpr ::= RelationalExpr 10881 * | EqualityExpr '=' RelationalExpr 10882 * | EqualityExpr '!=' RelationalExpr 10883 * 10884 * A != B != C is allowed ? Answer from James, yes with 10885 * (RelationalExpr = RelationalExpr) = RelationalExpr 10886 * (RelationalExpr != RelationalExpr) != RelationalExpr 10887 * which is basically what got implemented. 10888 * 10889 * Compile an Equality expression. 10890 * 10891 */ 10892 static void 10893 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) { 10894 xmlXPathCompRelationalExpr(ctxt); 10895 CHECK_ERROR; 10896 SKIP_BLANKS; 10897 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) { 10898 int eq; 10899 int op1 = ctxt->comp->last; 10900 10901 if (CUR == '=') eq = 1; 10902 else eq = 0; 10903 NEXT; 10904 if (!eq) NEXT; 10905 SKIP_BLANKS; 10906 xmlXPathCompRelationalExpr(ctxt); 10907 CHECK_ERROR; 10908 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0); 10909 SKIP_BLANKS; 10910 } 10911 } 10912 10913 /** 10914 * xmlXPathCompAndExpr: 10915 * @ctxt: the XPath Parser context 10916 * 10917 * [22] AndExpr ::= EqualityExpr 10918 * | AndExpr 'and' EqualityExpr 10919 * 10920 * Compile an AND expression. 10921 * 10922 */ 10923 static void 10924 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) { 10925 xmlXPathCompEqualityExpr(ctxt); 10926 CHECK_ERROR; 10927 SKIP_BLANKS; 10928 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) { 10929 int op1 = ctxt->comp->last; 10930 SKIP(3); 10931 SKIP_BLANKS; 10932 xmlXPathCompEqualityExpr(ctxt); 10933 CHECK_ERROR; 10934 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0); 10935 SKIP_BLANKS; 10936 } 10937 } 10938 10939 /** 10940 * xmlXPathCompileExpr: 10941 * @ctxt: the XPath Parser context 10942 * 10943 * [14] Expr ::= OrExpr 10944 * [21] OrExpr ::= AndExpr 10945 * | OrExpr 'or' AndExpr 10946 * 10947 * Parse and compile an expression 10948 */ 10949 static void 10950 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) { 10951 xmlXPathContextPtr xpctxt = ctxt->context; 10952 10953 if (xpctxt != NULL) { 10954 if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH) 10955 XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED); 10956 /* 10957 * Parsing a single '(' pushes about 10 functions on the call stack 10958 * before recursing! 10959 */ 10960 xpctxt->depth += 10; 10961 } 10962 10963 xmlXPathCompAndExpr(ctxt); 10964 CHECK_ERROR; 10965 SKIP_BLANKS; 10966 while ((CUR == 'o') && (NXT(1) == 'r')) { 10967 int op1 = ctxt->comp->last; 10968 SKIP(2); 10969 SKIP_BLANKS; 10970 xmlXPathCompAndExpr(ctxt); 10971 CHECK_ERROR; 10972 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0); 10973 SKIP_BLANKS; 10974 } 10975 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) { 10976 /* more ops could be optimized too */ 10977 /* 10978 * This is the main place to eliminate sorting for 10979 * operations which don't require a sorted node-set. 10980 * E.g. count(). 10981 */ 10982 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0); 10983 } 10984 10985 if (xpctxt != NULL) 10986 xpctxt->depth -= 1; 10987 } 10988 10989 /** 10990 * xmlXPathCompPredicate: 10991 * @ctxt: the XPath Parser context 10992 * @filter: act as a filter 10993 * 10994 * [8] Predicate ::= '[' PredicateExpr ']' 10995 * [9] PredicateExpr ::= Expr 10996 * 10997 * Compile a predicate expression 10998 */ 10999 static void 11000 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) { 11001 int op1 = ctxt->comp->last; 11002 11003 SKIP_BLANKS; 11004 if (CUR != '[') { 11005 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); 11006 } 11007 NEXT; 11008 SKIP_BLANKS; 11009 11010 ctxt->comp->last = -1; 11011 /* 11012 * This call to xmlXPathCompileExpr() will deactivate sorting 11013 * of the predicate result. 11014 * TODO: Sorting is still activated for filters, since I'm not 11015 * sure if needed. Normally sorting should not be needed, since 11016 * a filter can only diminish the number of items in a sequence, 11017 * but won't change its order; so if the initial sequence is sorted, 11018 * subsequent sorting is not needed. 11019 */ 11020 if (! filter) 11021 xmlXPathCompileExpr(ctxt, 0); 11022 else 11023 xmlXPathCompileExpr(ctxt, 1); 11024 CHECK_ERROR; 11025 11026 if (CUR != ']') { 11027 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); 11028 } 11029 11030 if (filter) 11031 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0); 11032 else 11033 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0); 11034 11035 NEXT; 11036 SKIP_BLANKS; 11037 } 11038 11039 /** 11040 * xmlXPathCompNodeTest: 11041 * @ctxt: the XPath Parser context 11042 * @test: pointer to a xmlXPathTestVal 11043 * @type: pointer to a xmlXPathTypeVal 11044 * @prefix: placeholder for a possible name prefix 11045 * 11046 * [7] NodeTest ::= NameTest 11047 * | NodeType '(' ')' 11048 * | 'processing-instruction' '(' Literal ')' 11049 * 11050 * [37] NameTest ::= '*' 11051 * | NCName ':' '*' 11052 * | QName 11053 * [38] NodeType ::= 'comment' 11054 * | 'text' 11055 * | 'processing-instruction' 11056 * | 'node' 11057 * 11058 * Returns the name found and updates @test, @type and @prefix appropriately 11059 */ 11060 static xmlChar * 11061 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test, 11062 xmlXPathTypeVal *type, xmlChar **prefix, 11063 xmlChar *name) { 11064 int blanks; 11065 11066 if ((test == NULL) || (type == NULL) || (prefix == NULL)) { 11067 STRANGE; 11068 return(NULL); 11069 } 11070 *type = (xmlXPathTypeVal) 0; 11071 *test = (xmlXPathTestVal) 0; 11072 *prefix = NULL; 11073 SKIP_BLANKS; 11074 11075 if ((name == NULL) && (CUR == '*')) { 11076 /* 11077 * All elements 11078 */ 11079 NEXT; 11080 *test = NODE_TEST_ALL; 11081 return(NULL); 11082 } 11083 11084 if (name == NULL) 11085 name = xmlXPathParseNCName(ctxt); 11086 if (name == NULL) { 11087 XP_ERRORNULL(XPATH_EXPR_ERROR); 11088 } 11089 11090 blanks = IS_BLANK_CH(CUR); 11091 SKIP_BLANKS; 11092 if (CUR == '(') { 11093 NEXT; 11094 /* 11095 * NodeType or PI search 11096 */ 11097 if (xmlStrEqual(name, BAD_CAST "comment")) 11098 *type = NODE_TYPE_COMMENT; 11099 else if (xmlStrEqual(name, BAD_CAST "node")) 11100 *type = NODE_TYPE_NODE; 11101 else if (xmlStrEqual(name, BAD_CAST "processing-instruction")) 11102 *type = NODE_TYPE_PI; 11103 else if (xmlStrEqual(name, BAD_CAST "text")) 11104 *type = NODE_TYPE_TEXT; 11105 else { 11106 if (name != NULL) 11107 xmlFree(name); 11108 XP_ERRORNULL(XPATH_EXPR_ERROR); 11109 } 11110 11111 *test = NODE_TEST_TYPE; 11112 11113 SKIP_BLANKS; 11114 if (*type == NODE_TYPE_PI) { 11115 /* 11116 * Specific case: search a PI by name. 11117 */ 11118 if (name != NULL) 11119 xmlFree(name); 11120 name = NULL; 11121 if (CUR != ')') { 11122 name = xmlXPathParseLiteral(ctxt); 11123 CHECK_ERROR NULL; 11124 *test = NODE_TEST_PI; 11125 SKIP_BLANKS; 11126 } 11127 } 11128 if (CUR != ')') { 11129 if (name != NULL) 11130 xmlFree(name); 11131 XP_ERRORNULL(XPATH_UNCLOSED_ERROR); 11132 } 11133 NEXT; 11134 return(name); 11135 } 11136 *test = NODE_TEST_NAME; 11137 if ((!blanks) && (CUR == ':')) { 11138 NEXT; 11139 11140 /* 11141 * Since currently the parser context don't have a 11142 * namespace list associated: 11143 * The namespace name for this prefix can be computed 11144 * only at evaluation time. The compilation is done 11145 * outside of any context. 11146 */ 11147 #if 0 11148 *prefix = xmlXPathNsLookup(ctxt->context, name); 11149 if (name != NULL) 11150 xmlFree(name); 11151 if (*prefix == NULL) { 11152 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); 11153 } 11154 #else 11155 *prefix = name; 11156 #endif 11157 11158 if (CUR == '*') { 11159 /* 11160 * All elements 11161 */ 11162 NEXT; 11163 *test = NODE_TEST_ALL; 11164 return(NULL); 11165 } 11166 11167 name = xmlXPathParseNCName(ctxt); 11168 if (name == NULL) { 11169 XP_ERRORNULL(XPATH_EXPR_ERROR); 11170 } 11171 } 11172 return(name); 11173 } 11174 11175 /** 11176 * xmlXPathIsAxisName: 11177 * @name: a preparsed name token 11178 * 11179 * [6] AxisName ::= 'ancestor' 11180 * | 'ancestor-or-self' 11181 * | 'attribute' 11182 * | 'child' 11183 * | 'descendant' 11184 * | 'descendant-or-self' 11185 * | 'following' 11186 * | 'following-sibling' 11187 * | 'namespace' 11188 * | 'parent' 11189 * | 'preceding' 11190 * | 'preceding-sibling' 11191 * | 'self' 11192 * 11193 * Returns the axis or 0 11194 */ 11195 static xmlXPathAxisVal 11196 xmlXPathIsAxisName(const xmlChar *name) { 11197 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0; 11198 switch (name[0]) { 11199 case 'a': 11200 if (xmlStrEqual(name, BAD_CAST "ancestor")) 11201 ret = AXIS_ANCESTOR; 11202 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self")) 11203 ret = AXIS_ANCESTOR_OR_SELF; 11204 if (xmlStrEqual(name, BAD_CAST "attribute")) 11205 ret = AXIS_ATTRIBUTE; 11206 break; 11207 case 'c': 11208 if (xmlStrEqual(name, BAD_CAST "child")) 11209 ret = AXIS_CHILD; 11210 break; 11211 case 'd': 11212 if (xmlStrEqual(name, BAD_CAST "descendant")) 11213 ret = AXIS_DESCENDANT; 11214 if (xmlStrEqual(name, BAD_CAST "descendant-or-self")) 11215 ret = AXIS_DESCENDANT_OR_SELF; 11216 break; 11217 case 'f': 11218 if (xmlStrEqual(name, BAD_CAST "following")) 11219 ret = AXIS_FOLLOWING; 11220 if (xmlStrEqual(name, BAD_CAST "following-sibling")) 11221 ret = AXIS_FOLLOWING_SIBLING; 11222 break; 11223 case 'n': 11224 if (xmlStrEqual(name, BAD_CAST "namespace")) 11225 ret = AXIS_NAMESPACE; 11226 break; 11227 case 'p': 11228 if (xmlStrEqual(name, BAD_CAST "parent")) 11229 ret = AXIS_PARENT; 11230 if (xmlStrEqual(name, BAD_CAST "preceding")) 11231 ret = AXIS_PRECEDING; 11232 if (xmlStrEqual(name, BAD_CAST "preceding-sibling")) 11233 ret = AXIS_PRECEDING_SIBLING; 11234 break; 11235 case 's': 11236 if (xmlStrEqual(name, BAD_CAST "self")) 11237 ret = AXIS_SELF; 11238 break; 11239 } 11240 return(ret); 11241 } 11242 11243 /** 11244 * xmlXPathCompStep: 11245 * @ctxt: the XPath Parser context 11246 * 11247 * [4] Step ::= AxisSpecifier NodeTest Predicate* 11248 * | AbbreviatedStep 11249 * 11250 * [12] AbbreviatedStep ::= '.' | '..' 11251 * 11252 * [5] AxisSpecifier ::= AxisName '::' 11253 * | AbbreviatedAxisSpecifier 11254 * 11255 * [13] AbbreviatedAxisSpecifier ::= '@'? 11256 * 11257 * Modified for XPtr range support as: 11258 * 11259 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate* 11260 * | AbbreviatedStep 11261 * | 'range-to' '(' Expr ')' Predicate* 11262 * 11263 * Compile one step in a Location Path 11264 * A location step of . is short for self::node(). This is 11265 * particularly useful in conjunction with //. For example, the 11266 * location path .//para is short for 11267 * self::node()/descendant-or-self::node()/child::para 11268 * and so will select all para descendant elements of the context 11269 * node. 11270 * Similarly, a location step of .. is short for parent::node(). 11271 * For example, ../title is short for parent::node()/child::title 11272 * and so will select the title children of the parent of the context 11273 * node. 11274 */ 11275 static void 11276 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) { 11277 #ifdef LIBXML_XPTR_ENABLED 11278 int rangeto = 0; 11279 int op2 = -1; 11280 #endif 11281 11282 SKIP_BLANKS; 11283 if ((CUR == '.') && (NXT(1) == '.')) { 11284 SKIP(2); 11285 SKIP_BLANKS; 11286 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT, 11287 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11288 } else if (CUR == '.') { 11289 NEXT; 11290 SKIP_BLANKS; 11291 } else { 11292 xmlChar *name = NULL; 11293 xmlChar *prefix = NULL; 11294 xmlXPathTestVal test = (xmlXPathTestVal) 0; 11295 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0; 11296 xmlXPathTypeVal type = (xmlXPathTypeVal) 0; 11297 int op1; 11298 11299 /* 11300 * The modification needed for XPointer change to the production 11301 */ 11302 #ifdef LIBXML_XPTR_ENABLED 11303 if (ctxt->xptr) { 11304 name = xmlXPathParseNCName(ctxt); 11305 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) { 11306 op2 = ctxt->comp->last; 11307 xmlFree(name); 11308 SKIP_BLANKS; 11309 if (CUR != '(') { 11310 XP_ERROR(XPATH_EXPR_ERROR); 11311 } 11312 NEXT; 11313 SKIP_BLANKS; 11314 11315 xmlXPathCompileExpr(ctxt, 1); 11316 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */ 11317 CHECK_ERROR; 11318 11319 SKIP_BLANKS; 11320 if (CUR != ')') { 11321 XP_ERROR(XPATH_EXPR_ERROR); 11322 } 11323 NEXT; 11324 rangeto = 1; 11325 goto eval_predicates; 11326 } 11327 } 11328 #endif 11329 if (CUR == '*') { 11330 axis = AXIS_CHILD; 11331 } else { 11332 if (name == NULL) 11333 name = xmlXPathParseNCName(ctxt); 11334 if (name != NULL) { 11335 axis = xmlXPathIsAxisName(name); 11336 if (axis != 0) { 11337 SKIP_BLANKS; 11338 if ((CUR == ':') && (NXT(1) == ':')) { 11339 SKIP(2); 11340 xmlFree(name); 11341 name = NULL; 11342 } else { 11343 /* an element name can conflict with an axis one :-\ */ 11344 axis = AXIS_CHILD; 11345 } 11346 } else { 11347 axis = AXIS_CHILD; 11348 } 11349 } else if (CUR == '@') { 11350 NEXT; 11351 axis = AXIS_ATTRIBUTE; 11352 } else { 11353 axis = AXIS_CHILD; 11354 } 11355 } 11356 11357 if (ctxt->error != XPATH_EXPRESSION_OK) { 11358 xmlFree(name); 11359 return; 11360 } 11361 11362 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name); 11363 if (test == 0) 11364 return; 11365 11366 if ((prefix != NULL) && (ctxt->context != NULL) && 11367 (ctxt->context->flags & XML_XPATH_CHECKNS)) { 11368 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) { 11369 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR); 11370 } 11371 } 11372 #ifdef DEBUG_STEP 11373 xmlGenericError(xmlGenericErrorContext, 11374 "Basis : computing new set\n"); 11375 #endif 11376 11377 #ifdef DEBUG_STEP 11378 xmlGenericError(xmlGenericErrorContext, "Basis : "); 11379 if (ctxt->value == NULL) 11380 xmlGenericError(xmlGenericErrorContext, "no value\n"); 11381 else if (ctxt->value->nodesetval == NULL) 11382 xmlGenericError(xmlGenericErrorContext, "Empty\n"); 11383 else 11384 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval); 11385 #endif 11386 11387 #ifdef LIBXML_XPTR_ENABLED 11388 eval_predicates: 11389 #endif 11390 op1 = ctxt->comp->last; 11391 ctxt->comp->last = -1; 11392 11393 SKIP_BLANKS; 11394 while (CUR == '[') { 11395 xmlXPathCompPredicate(ctxt, 0); 11396 } 11397 11398 #ifdef LIBXML_XPTR_ENABLED 11399 if (rangeto) { 11400 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0); 11401 } else 11402 #endif 11403 if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis, 11404 test, type, (void *)prefix, (void *)name) == -1) { 11405 xmlFree(prefix); 11406 xmlFree(name); 11407 } 11408 } 11409 #ifdef DEBUG_STEP 11410 xmlGenericError(xmlGenericErrorContext, "Step : "); 11411 if (ctxt->value == NULL) 11412 xmlGenericError(xmlGenericErrorContext, "no value\n"); 11413 else if (ctxt->value->nodesetval == NULL) 11414 xmlGenericError(xmlGenericErrorContext, "Empty\n"); 11415 else 11416 xmlGenericErrorContextNodeSet(xmlGenericErrorContext, 11417 ctxt->value->nodesetval); 11418 #endif 11419 } 11420 11421 /** 11422 * xmlXPathCompRelativeLocationPath: 11423 * @ctxt: the XPath Parser context 11424 * 11425 * [3] RelativeLocationPath ::= Step 11426 * | RelativeLocationPath '/' Step 11427 * | AbbreviatedRelativeLocationPath 11428 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step 11429 * 11430 * Compile a relative location path. 11431 */ 11432 static void 11433 xmlXPathCompRelativeLocationPath 11434 (xmlXPathParserContextPtr ctxt) { 11435 SKIP_BLANKS; 11436 if ((CUR == '/') && (NXT(1) == '/')) { 11437 SKIP(2); 11438 SKIP_BLANKS; 11439 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 11440 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11441 } else if (CUR == '/') { 11442 NEXT; 11443 SKIP_BLANKS; 11444 } 11445 xmlXPathCompStep(ctxt); 11446 CHECK_ERROR; 11447 SKIP_BLANKS; 11448 while (CUR == '/') { 11449 if ((CUR == '/') && (NXT(1) == '/')) { 11450 SKIP(2); 11451 SKIP_BLANKS; 11452 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 11453 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11454 xmlXPathCompStep(ctxt); 11455 } else if (CUR == '/') { 11456 NEXT; 11457 SKIP_BLANKS; 11458 xmlXPathCompStep(ctxt); 11459 } 11460 SKIP_BLANKS; 11461 } 11462 } 11463 11464 /** 11465 * xmlXPathCompLocationPath: 11466 * @ctxt: the XPath Parser context 11467 * 11468 * [1] LocationPath ::= RelativeLocationPath 11469 * | AbsoluteLocationPath 11470 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath? 11471 * | AbbreviatedAbsoluteLocationPath 11472 * [10] AbbreviatedAbsoluteLocationPath ::= 11473 * '//' RelativeLocationPath 11474 * 11475 * Compile a location path 11476 * 11477 * // is short for /descendant-or-self::node()/. For example, 11478 * //para is short for /descendant-or-self::node()/child::para and 11479 * so will select any para element in the document (even a para element 11480 * that is a document element will be selected by //para since the 11481 * document element node is a child of the root node); div//para is 11482 * short for div/descendant-or-self::node()/child::para and so will 11483 * select all para descendants of div children. 11484 */ 11485 static void 11486 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) { 11487 SKIP_BLANKS; 11488 if (CUR != '/') { 11489 xmlXPathCompRelativeLocationPath(ctxt); 11490 } else { 11491 while (CUR == '/') { 11492 if ((CUR == '/') && (NXT(1) == '/')) { 11493 SKIP(2); 11494 SKIP_BLANKS; 11495 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 11496 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11497 xmlXPathCompRelativeLocationPath(ctxt); 11498 } else if (CUR == '/') { 11499 NEXT; 11500 SKIP_BLANKS; 11501 if ((CUR != 0 ) && 11502 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') || 11503 (CUR == '@') || (CUR == '*'))) 11504 xmlXPathCompRelativeLocationPath(ctxt); 11505 } 11506 CHECK_ERROR; 11507 } 11508 } 11509 } 11510 11511 /************************************************************************ 11512 * * 11513 * XPath precompiled expression evaluation * 11514 * * 11515 ************************************************************************/ 11516 11517 static int 11518 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op); 11519 11520 #ifdef DEBUG_STEP 11521 static void 11522 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op, 11523 int nbNodes) 11524 { 11525 xmlGenericError(xmlGenericErrorContext, "new step : "); 11526 switch (op->value) { 11527 case AXIS_ANCESTOR: 11528 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' "); 11529 break; 11530 case AXIS_ANCESTOR_OR_SELF: 11531 xmlGenericError(xmlGenericErrorContext, 11532 "axis 'ancestors-or-self' "); 11533 break; 11534 case AXIS_ATTRIBUTE: 11535 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' "); 11536 break; 11537 case AXIS_CHILD: 11538 xmlGenericError(xmlGenericErrorContext, "axis 'child' "); 11539 break; 11540 case AXIS_DESCENDANT: 11541 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' "); 11542 break; 11543 case AXIS_DESCENDANT_OR_SELF: 11544 xmlGenericError(xmlGenericErrorContext, 11545 "axis 'descendant-or-self' "); 11546 break; 11547 case AXIS_FOLLOWING: 11548 xmlGenericError(xmlGenericErrorContext, "axis 'following' "); 11549 break; 11550 case AXIS_FOLLOWING_SIBLING: 11551 xmlGenericError(xmlGenericErrorContext, 11552 "axis 'following-siblings' "); 11553 break; 11554 case AXIS_NAMESPACE: 11555 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' "); 11556 break; 11557 case AXIS_PARENT: 11558 xmlGenericError(xmlGenericErrorContext, "axis 'parent' "); 11559 break; 11560 case AXIS_PRECEDING: 11561 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' "); 11562 break; 11563 case AXIS_PRECEDING_SIBLING: 11564 xmlGenericError(xmlGenericErrorContext, 11565 "axis 'preceding-sibling' "); 11566 break; 11567 case AXIS_SELF: 11568 xmlGenericError(xmlGenericErrorContext, "axis 'self' "); 11569 break; 11570 } 11571 xmlGenericError(xmlGenericErrorContext, 11572 " context contains %d nodes\n", nbNodes); 11573 switch (op->value2) { 11574 case NODE_TEST_NONE: 11575 xmlGenericError(xmlGenericErrorContext, 11576 " searching for none !!!\n"); 11577 break; 11578 case NODE_TEST_TYPE: 11579 xmlGenericError(xmlGenericErrorContext, 11580 " searching for type %d\n", op->value3); 11581 break; 11582 case NODE_TEST_PI: 11583 xmlGenericError(xmlGenericErrorContext, 11584 " searching for PI !!!\n"); 11585 break; 11586 case NODE_TEST_ALL: 11587 xmlGenericError(xmlGenericErrorContext, 11588 " searching for *\n"); 11589 break; 11590 case NODE_TEST_NS: 11591 xmlGenericError(xmlGenericErrorContext, 11592 " searching for namespace %s\n", 11593 op->value5); 11594 break; 11595 case NODE_TEST_NAME: 11596 xmlGenericError(xmlGenericErrorContext, 11597 " searching for name %s\n", op->value5); 11598 if (op->value4) 11599 xmlGenericError(xmlGenericErrorContext, 11600 " with namespace %s\n", op->value4); 11601 break; 11602 } 11603 xmlGenericError(xmlGenericErrorContext, "Testing : "); 11604 } 11605 #endif /* DEBUG_STEP */ 11606 11607 /** 11608 * xmlXPathNodeSetFilter: 11609 * @ctxt: the XPath Parser context 11610 * @set: the node set to filter 11611 * @filterOpIndex: the index of the predicate/filter op 11612 * @minPos: minimum position in the filtered set (1-based) 11613 * @maxPos: maximum position in the filtered set (1-based) 11614 * @hasNsNodes: true if the node set may contain namespace nodes 11615 * 11616 * Filter a node set, keeping only nodes for which the predicate expression 11617 * matches. Afterwards, keep only nodes between minPos and maxPos in the 11618 * filtered result. 11619 */ 11620 static void 11621 xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt, 11622 xmlNodeSetPtr set, 11623 int filterOpIndex, 11624 int minPos, int maxPos, 11625 int hasNsNodes) 11626 { 11627 xmlXPathContextPtr xpctxt; 11628 xmlNodePtr oldnode; 11629 xmlDocPtr olddoc; 11630 xmlXPathStepOpPtr filterOp; 11631 int oldcs, oldpp; 11632 int i, j, pos; 11633 11634 if ((set == NULL) || (set->nodeNr == 0)) 11635 return; 11636 11637 /* 11638 * Check if the node set contains a sufficient number of nodes for 11639 * the requested range. 11640 */ 11641 if (set->nodeNr < minPos) { 11642 xmlXPathNodeSetClear(set, hasNsNodes); 11643 return; 11644 } 11645 11646 xpctxt = ctxt->context; 11647 oldnode = xpctxt->node; 11648 olddoc = xpctxt->doc; 11649 oldcs = xpctxt->contextSize; 11650 oldpp = xpctxt->proximityPosition; 11651 filterOp = &ctxt->comp->steps[filterOpIndex]; 11652 11653 xpctxt->contextSize = set->nodeNr; 11654 11655 for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) { 11656 xmlNodePtr node = set->nodeTab[i]; 11657 int res; 11658 11659 xpctxt->node = node; 11660 xpctxt->proximityPosition = i + 1; 11661 11662 /* 11663 * Also set the xpath document in case things like 11664 * key() are evaluated in the predicate. 11665 * 11666 * TODO: Get real doc for namespace nodes. 11667 */ 11668 if ((node->type != XML_NAMESPACE_DECL) && 11669 (node->doc != NULL)) 11670 xpctxt->doc = node->doc; 11671 11672 res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1); 11673 11674 if (ctxt->error != XPATH_EXPRESSION_OK) 11675 break; 11676 if (res < 0) { 11677 /* Shouldn't happen */ 11678 xmlXPathErr(ctxt, XPATH_EXPR_ERROR); 11679 break; 11680 } 11681 11682 if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) { 11683 if (i != j) { 11684 set->nodeTab[j] = node; 11685 set->nodeTab[i] = NULL; 11686 } 11687 11688 j += 1; 11689 } else { 11690 /* Remove the entry from the initial node set. */ 11691 set->nodeTab[i] = NULL; 11692 if (node->type == XML_NAMESPACE_DECL) 11693 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 11694 } 11695 11696 if (res != 0) { 11697 if (pos == maxPos) { 11698 i += 1; 11699 break; 11700 } 11701 11702 pos += 1; 11703 } 11704 } 11705 11706 /* Free remaining nodes. */ 11707 if (hasNsNodes) { 11708 for (; i < set->nodeNr; i++) { 11709 xmlNodePtr node = set->nodeTab[i]; 11710 if ((node != NULL) && (node->type == XML_NAMESPACE_DECL)) 11711 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 11712 } 11713 } 11714 11715 set->nodeNr = j; 11716 11717 /* If too many elements were removed, shrink table to preserve memory. */ 11718 if ((set->nodeMax > XML_NODESET_DEFAULT) && 11719 (set->nodeNr < set->nodeMax / 2)) { 11720 xmlNodePtr *tmp; 11721 int nodeMax = set->nodeNr; 11722 11723 if (nodeMax < XML_NODESET_DEFAULT) 11724 nodeMax = XML_NODESET_DEFAULT; 11725 tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab, 11726 nodeMax * sizeof(xmlNodePtr)); 11727 if (tmp == NULL) { 11728 xmlXPathPErrMemory(ctxt, "shrinking nodeset\n"); 11729 } else { 11730 set->nodeTab = tmp; 11731 set->nodeMax = nodeMax; 11732 } 11733 } 11734 11735 xpctxt->node = oldnode; 11736 xpctxt->doc = olddoc; 11737 xpctxt->contextSize = oldcs; 11738 xpctxt->proximityPosition = oldpp; 11739 } 11740 11741 #ifdef LIBXML_XPTR_ENABLED 11742 /** 11743 * xmlXPathLocationSetFilter: 11744 * @ctxt: the XPath Parser context 11745 * @locset: the location set to filter 11746 * @filterOpIndex: the index of the predicate/filter op 11747 * @minPos: minimum position in the filtered set (1-based) 11748 * @maxPos: maximum position in the filtered set (1-based) 11749 * 11750 * Filter a location set, keeping only nodes for which the predicate 11751 * expression matches. Afterwards, keep only nodes between minPos and maxPos 11752 * in the filtered result. 11753 */ 11754 static void 11755 xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt, 11756 xmlLocationSetPtr locset, 11757 int filterOpIndex, 11758 int minPos, int maxPos) 11759 { 11760 xmlXPathContextPtr xpctxt; 11761 xmlNodePtr oldnode; 11762 xmlDocPtr olddoc; 11763 xmlXPathStepOpPtr filterOp; 11764 int oldcs, oldpp; 11765 int i, j, pos; 11766 11767 if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1)) 11768 return; 11769 11770 xpctxt = ctxt->context; 11771 oldnode = xpctxt->node; 11772 olddoc = xpctxt->doc; 11773 oldcs = xpctxt->contextSize; 11774 oldpp = xpctxt->proximityPosition; 11775 filterOp = &ctxt->comp->steps[filterOpIndex]; 11776 11777 xpctxt->contextSize = locset->locNr; 11778 11779 for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) { 11780 xmlNodePtr contextNode = locset->locTab[i]->user; 11781 int res; 11782 11783 xpctxt->node = contextNode; 11784 xpctxt->proximityPosition = i + 1; 11785 11786 /* 11787 * Also set the xpath document in case things like 11788 * key() are evaluated in the predicate. 11789 * 11790 * TODO: Get real doc for namespace nodes. 11791 */ 11792 if ((contextNode->type != XML_NAMESPACE_DECL) && 11793 (contextNode->doc != NULL)) 11794 xpctxt->doc = contextNode->doc; 11795 11796 res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1); 11797 11798 if (ctxt->error != XPATH_EXPRESSION_OK) 11799 break; 11800 if (res < 0) { 11801 /* Shouldn't happen */ 11802 xmlXPathErr(ctxt, XPATH_EXPR_ERROR); 11803 break; 11804 } 11805 11806 if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) { 11807 if (i != j) { 11808 locset->locTab[j] = locset->locTab[i]; 11809 locset->locTab[i] = NULL; 11810 } 11811 11812 j += 1; 11813 } else { 11814 /* Remove the entry from the initial location set. */ 11815 xmlXPathFreeObject(locset->locTab[i]); 11816 locset->locTab[i] = NULL; 11817 } 11818 11819 if (res != 0) { 11820 if (pos == maxPos) { 11821 i += 1; 11822 break; 11823 } 11824 11825 pos += 1; 11826 } 11827 } 11828 11829 /* Free remaining nodes. */ 11830 for (; i < locset->locNr; i++) 11831 xmlXPathFreeObject(locset->locTab[i]); 11832 11833 locset->locNr = j; 11834 11835 /* If too many elements were removed, shrink table to preserve memory. */ 11836 if ((locset->locMax > XML_NODESET_DEFAULT) && 11837 (locset->locNr < locset->locMax / 2)) { 11838 xmlXPathObjectPtr *tmp; 11839 int locMax = locset->locNr; 11840 11841 if (locMax < XML_NODESET_DEFAULT) 11842 locMax = XML_NODESET_DEFAULT; 11843 tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab, 11844 locMax * sizeof(xmlXPathObjectPtr)); 11845 if (tmp == NULL) { 11846 xmlXPathPErrMemory(ctxt, "shrinking locset\n"); 11847 } else { 11848 locset->locTab = tmp; 11849 locset->locMax = locMax; 11850 } 11851 } 11852 11853 xpctxt->node = oldnode; 11854 xpctxt->doc = olddoc; 11855 xpctxt->contextSize = oldcs; 11856 xpctxt->proximityPosition = oldpp; 11857 } 11858 #endif /* LIBXML_XPTR_ENABLED */ 11859 11860 /** 11861 * xmlXPathCompOpEvalPredicate: 11862 * @ctxt: the XPath Parser context 11863 * @op: the predicate op 11864 * @set: the node set to filter 11865 * @minPos: minimum position in the filtered set (1-based) 11866 * @maxPos: maximum position in the filtered set (1-based) 11867 * @hasNsNodes: true if the node set may contain namespace nodes 11868 * 11869 * Filter a node set, keeping only nodes for which the sequence of predicate 11870 * expressions matches. Afterwards, keep only nodes between minPos and maxPos 11871 * in the filtered result. 11872 */ 11873 static void 11874 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt, 11875 xmlXPathStepOpPtr op, 11876 xmlNodeSetPtr set, 11877 int minPos, int maxPos, 11878 int hasNsNodes) 11879 { 11880 if (op->ch1 != -1) { 11881 xmlXPathCompExprPtr comp = ctxt->comp; 11882 /* 11883 * Process inner predicates first. 11884 */ 11885 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) { 11886 xmlGenericError(xmlGenericErrorContext, 11887 "xmlXPathCompOpEvalPredicate: Expected a predicate\n"); 11888 XP_ERROR(XPATH_INVALID_OPERAND); 11889 } 11890 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH) 11891 XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED); 11892 ctxt->context->depth += 1; 11893 xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set, 11894 1, set->nodeNr, hasNsNodes); 11895 ctxt->context->depth -= 1; 11896 CHECK_ERROR; 11897 } 11898 11899 if (op->ch2 != -1) 11900 xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes); 11901 } 11902 11903 static int 11904 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt, 11905 xmlXPathStepOpPtr op, 11906 int *maxPos) 11907 { 11908 11909 xmlXPathStepOpPtr exprOp; 11910 11911 /* 11912 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet! 11913 */ 11914 11915 /* 11916 * If not -1, then ch1 will point to: 11917 * 1) For predicates (XPATH_OP_PREDICATE): 11918 * - an inner predicate operator 11919 * 2) For filters (XPATH_OP_FILTER): 11920 * - an inner filter operator OR 11921 * - an expression selecting the node set. 11922 * E.g. "key('a', 'b')" or "(//foo | //bar)". 11923 */ 11924 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER)) 11925 return(0); 11926 11927 if (op->ch2 != -1) { 11928 exprOp = &ctxt->comp->steps[op->ch2]; 11929 } else 11930 return(0); 11931 11932 if ((exprOp != NULL) && 11933 (exprOp->op == XPATH_OP_VALUE) && 11934 (exprOp->value4 != NULL) && 11935 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER)) 11936 { 11937 double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval; 11938 11939 /* 11940 * We have a "[n]" predicate here. 11941 * TODO: Unfortunately this simplistic test here is not 11942 * able to detect a position() predicate in compound 11943 * expressions like "[@attr = 'a" and position() = 1], 11944 * and even not the usage of position() in 11945 * "[position() = 1]"; thus - obviously - a position-range, 11946 * like it "[position() < 5]", is also not detected. 11947 * Maybe we could rewrite the AST to ease the optimization. 11948 */ 11949 11950 if ((floatval > INT_MIN) && (floatval < INT_MAX)) { 11951 *maxPos = (int) floatval; 11952 if (floatval == (double) *maxPos) 11953 return(1); 11954 } 11955 } 11956 return(0); 11957 } 11958 11959 static int 11960 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, 11961 xmlXPathStepOpPtr op, 11962 xmlNodePtr * first, xmlNodePtr * last, 11963 int toBool) 11964 { 11965 11966 #define XP_TEST_HIT \ 11967 if (hasAxisRange != 0) { \ 11968 if (++pos == maxPos) { \ 11969 if (addNode(seq, cur) < 0) \ 11970 ctxt->error = XPATH_MEMORY_ERROR; \ 11971 goto axis_range_end; } \ 11972 } else { \ 11973 if (addNode(seq, cur) < 0) \ 11974 ctxt->error = XPATH_MEMORY_ERROR; \ 11975 if (breakOnFirstHit) goto first_hit; } 11976 11977 #define XP_TEST_HIT_NS \ 11978 if (hasAxisRange != 0) { \ 11979 if (++pos == maxPos) { \ 11980 hasNsNodes = 1; \ 11981 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \ 11982 ctxt->error = XPATH_MEMORY_ERROR; \ 11983 goto axis_range_end; } \ 11984 } else { \ 11985 hasNsNodes = 1; \ 11986 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \ 11987 ctxt->error = XPATH_MEMORY_ERROR; \ 11988 if (breakOnFirstHit) goto first_hit; } 11989 11990 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value; 11991 xmlXPathTestVal test = (xmlXPathTestVal) op->value2; 11992 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3; 11993 const xmlChar *prefix = op->value4; 11994 const xmlChar *name = op->value5; 11995 const xmlChar *URI = NULL; 11996 11997 #ifdef DEBUG_STEP 11998 int nbMatches = 0, prevMatches = 0; 11999 #endif 12000 int total = 0, hasNsNodes = 0; 12001 /* The popped object holding the context nodes */ 12002 xmlXPathObjectPtr obj; 12003 /* The set of context nodes for the node tests */ 12004 xmlNodeSetPtr contextSeq; 12005 int contextIdx; 12006 xmlNodePtr contextNode; 12007 /* The final resulting node set wrt to all context nodes */ 12008 xmlNodeSetPtr outSeq; 12009 /* 12010 * The temporary resulting node set wrt 1 context node. 12011 * Used to feed predicate evaluation. 12012 */ 12013 xmlNodeSetPtr seq; 12014 xmlNodePtr cur; 12015 /* First predicate operator */ 12016 xmlXPathStepOpPtr predOp; 12017 int maxPos; /* The requested position() (when a "[n]" predicate) */ 12018 int hasPredicateRange, hasAxisRange, pos; 12019 int breakOnFirstHit; 12020 12021 xmlXPathTraversalFunction next = NULL; 12022 int (*addNode) (xmlNodeSetPtr, xmlNodePtr); 12023 xmlXPathNodeSetMergeFunction mergeAndClear; 12024 xmlNodePtr oldContextNode; 12025 xmlXPathContextPtr xpctxt = ctxt->context; 12026 12027 12028 CHECK_TYPE0(XPATH_NODESET); 12029 obj = valuePop(ctxt); 12030 /* 12031 * Setup namespaces. 12032 */ 12033 if (prefix != NULL) { 12034 URI = xmlXPathNsLookup(xpctxt, prefix); 12035 if (URI == NULL) { 12036 xmlXPathReleaseObject(xpctxt, obj); 12037 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); 12038 } 12039 } 12040 /* 12041 * Setup axis. 12042 * 12043 * MAYBE FUTURE TODO: merging optimizations: 12044 * - If the nodes to be traversed wrt to the initial nodes and 12045 * the current axis cannot overlap, then we could avoid searching 12046 * for duplicates during the merge. 12047 * But the question is how/when to evaluate if they cannot overlap. 12048 * Example: if we know that for two initial nodes, the one is 12049 * not in the ancestor-or-self axis of the other, then we could safely 12050 * avoid a duplicate-aware merge, if the axis to be traversed is e.g. 12051 * the descendant-or-self axis. 12052 */ 12053 mergeAndClear = xmlXPathNodeSetMergeAndClear; 12054 switch (axis) { 12055 case AXIS_ANCESTOR: 12056 first = NULL; 12057 next = xmlXPathNextAncestor; 12058 break; 12059 case AXIS_ANCESTOR_OR_SELF: 12060 first = NULL; 12061 next = xmlXPathNextAncestorOrSelf; 12062 break; 12063 case AXIS_ATTRIBUTE: 12064 first = NULL; 12065 last = NULL; 12066 next = xmlXPathNextAttribute; 12067 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12068 break; 12069 case AXIS_CHILD: 12070 last = NULL; 12071 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) && 12072 (type == NODE_TYPE_NODE)) 12073 { 12074 /* 12075 * Optimization if an element node type is 'element'. 12076 */ 12077 next = xmlXPathNextChildElement; 12078 } else 12079 next = xmlXPathNextChild; 12080 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12081 break; 12082 case AXIS_DESCENDANT: 12083 last = NULL; 12084 next = xmlXPathNextDescendant; 12085 break; 12086 case AXIS_DESCENDANT_OR_SELF: 12087 last = NULL; 12088 next = xmlXPathNextDescendantOrSelf; 12089 break; 12090 case AXIS_FOLLOWING: 12091 last = NULL; 12092 next = xmlXPathNextFollowing; 12093 break; 12094 case AXIS_FOLLOWING_SIBLING: 12095 last = NULL; 12096 next = xmlXPathNextFollowingSibling; 12097 break; 12098 case AXIS_NAMESPACE: 12099 first = NULL; 12100 last = NULL; 12101 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; 12102 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12103 break; 12104 case AXIS_PARENT: 12105 first = NULL; 12106 next = xmlXPathNextParent; 12107 break; 12108 case AXIS_PRECEDING: 12109 first = NULL; 12110 next = xmlXPathNextPrecedingInternal; 12111 break; 12112 case AXIS_PRECEDING_SIBLING: 12113 first = NULL; 12114 next = xmlXPathNextPrecedingSibling; 12115 break; 12116 case AXIS_SELF: 12117 first = NULL; 12118 last = NULL; 12119 next = xmlXPathNextSelf; 12120 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12121 break; 12122 } 12123 12124 #ifdef DEBUG_STEP 12125 xmlXPathDebugDumpStepAxis(op, 12126 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0); 12127 #endif 12128 12129 if (next == NULL) { 12130 xmlXPathReleaseObject(xpctxt, obj); 12131 return(0); 12132 } 12133 contextSeq = obj->nodesetval; 12134 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) { 12135 xmlXPathReleaseObject(xpctxt, obj); 12136 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL)); 12137 return(0); 12138 } 12139 /* 12140 * Predicate optimization --------------------------------------------- 12141 * If this step has a last predicate, which contains a position(), 12142 * then we'll optimize (although not exactly "position()", but only 12143 * the short-hand form, i.e., "[n]". 12144 * 12145 * Example - expression "/foo[parent::bar][1]": 12146 * 12147 * COLLECT 'child' 'name' 'node' foo -- op (we are here) 12148 * ROOT -- op->ch1 12149 * PREDICATE -- op->ch2 (predOp) 12150 * PREDICATE -- predOp->ch1 = [parent::bar] 12151 * SORT 12152 * COLLECT 'parent' 'name' 'node' bar 12153 * NODE 12154 * ELEM Object is a number : 1 -- predOp->ch2 = [1] 12155 * 12156 */ 12157 maxPos = 0; 12158 predOp = NULL; 12159 hasPredicateRange = 0; 12160 hasAxisRange = 0; 12161 if (op->ch2 != -1) { 12162 /* 12163 * There's at least one predicate. 16 == XPATH_OP_PREDICATE 12164 */ 12165 predOp = &ctxt->comp->steps[op->ch2]; 12166 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) { 12167 if (predOp->ch1 != -1) { 12168 /* 12169 * Use the next inner predicate operator. 12170 */ 12171 predOp = &ctxt->comp->steps[predOp->ch1]; 12172 hasPredicateRange = 1; 12173 } else { 12174 /* 12175 * There's no other predicate than the [n] predicate. 12176 */ 12177 predOp = NULL; 12178 hasAxisRange = 1; 12179 } 12180 } 12181 } 12182 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0; 12183 /* 12184 * Axis traversal ----------------------------------------------------- 12185 */ 12186 /* 12187 * 2.3 Node Tests 12188 * - For the attribute axis, the principal node type is attribute. 12189 * - For the namespace axis, the principal node type is namespace. 12190 * - For other axes, the principal node type is element. 12191 * 12192 * A node test * is true for any node of the 12193 * principal node type. For example, child::* will 12194 * select all element children of the context node 12195 */ 12196 oldContextNode = xpctxt->node; 12197 addNode = xmlXPathNodeSetAddUnique; 12198 outSeq = NULL; 12199 seq = NULL; 12200 contextNode = NULL; 12201 contextIdx = 0; 12202 12203 12204 while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) && 12205 (ctxt->error == XPATH_EXPRESSION_OK)) { 12206 xpctxt->node = contextSeq->nodeTab[contextIdx++]; 12207 12208 if (seq == NULL) { 12209 seq = xmlXPathNodeSetCreate(NULL); 12210 if (seq == NULL) { 12211 /* TODO: Propagate memory error. */ 12212 total = 0; 12213 goto error; 12214 } 12215 } 12216 /* 12217 * Traverse the axis and test the nodes. 12218 */ 12219 pos = 0; 12220 cur = NULL; 12221 hasNsNodes = 0; 12222 do { 12223 if (OP_LIMIT_EXCEEDED(ctxt, 1)) 12224 goto error; 12225 12226 cur = next(ctxt, cur); 12227 if (cur == NULL) 12228 break; 12229 12230 /* 12231 * QUESTION TODO: What does the "first" and "last" stuff do? 12232 */ 12233 if ((first != NULL) && (*first != NULL)) { 12234 if (*first == cur) 12235 break; 12236 if (((total % 256) == 0) && 12237 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 12238 (xmlXPathCmpNodesExt(*first, cur) >= 0)) 12239 #else 12240 (xmlXPathCmpNodes(*first, cur) >= 0)) 12241 #endif 12242 { 12243 break; 12244 } 12245 } 12246 if ((last != NULL) && (*last != NULL)) { 12247 if (*last == cur) 12248 break; 12249 if (((total % 256) == 0) && 12250 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 12251 (xmlXPathCmpNodesExt(cur, *last) >= 0)) 12252 #else 12253 (xmlXPathCmpNodes(cur, *last) >= 0)) 12254 #endif 12255 { 12256 break; 12257 } 12258 } 12259 12260 total++; 12261 12262 #ifdef DEBUG_STEP 12263 xmlGenericError(xmlGenericErrorContext, " %s", cur->name); 12264 #endif 12265 12266 switch (test) { 12267 case NODE_TEST_NONE: 12268 total = 0; 12269 STRANGE 12270 goto error; 12271 case NODE_TEST_TYPE: 12272 if (type == NODE_TYPE_NODE) { 12273 switch (cur->type) { 12274 case XML_DOCUMENT_NODE: 12275 case XML_HTML_DOCUMENT_NODE: 12276 #ifdef LIBXML_DOCB_ENABLED 12277 case XML_DOCB_DOCUMENT_NODE: 12278 #endif 12279 case XML_ELEMENT_NODE: 12280 case XML_ATTRIBUTE_NODE: 12281 case XML_PI_NODE: 12282 case XML_COMMENT_NODE: 12283 case XML_CDATA_SECTION_NODE: 12284 case XML_TEXT_NODE: 12285 XP_TEST_HIT 12286 break; 12287 case XML_NAMESPACE_DECL: { 12288 if (axis == AXIS_NAMESPACE) { 12289 XP_TEST_HIT_NS 12290 } else { 12291 hasNsNodes = 1; 12292 XP_TEST_HIT 12293 } 12294 break; 12295 } 12296 default: 12297 break; 12298 } 12299 } else if (cur->type == (xmlElementType) type) { 12300 if (cur->type == XML_NAMESPACE_DECL) 12301 XP_TEST_HIT_NS 12302 else 12303 XP_TEST_HIT 12304 } else if ((type == NODE_TYPE_TEXT) && 12305 (cur->type == XML_CDATA_SECTION_NODE)) 12306 { 12307 XP_TEST_HIT 12308 } 12309 break; 12310 case NODE_TEST_PI: 12311 if ((cur->type == XML_PI_NODE) && 12312 ((name == NULL) || xmlStrEqual(name, cur->name))) 12313 { 12314 XP_TEST_HIT 12315 } 12316 break; 12317 case NODE_TEST_ALL: 12318 if (axis == AXIS_ATTRIBUTE) { 12319 if (cur->type == XML_ATTRIBUTE_NODE) 12320 { 12321 if (prefix == NULL) 12322 { 12323 XP_TEST_HIT 12324 } else if ((cur->ns != NULL) && 12325 (xmlStrEqual(URI, cur->ns->href))) 12326 { 12327 XP_TEST_HIT 12328 } 12329 } 12330 } else if (axis == AXIS_NAMESPACE) { 12331 if (cur->type == XML_NAMESPACE_DECL) 12332 { 12333 XP_TEST_HIT_NS 12334 } 12335 } else { 12336 if (cur->type == XML_ELEMENT_NODE) { 12337 if (prefix == NULL) 12338 { 12339 XP_TEST_HIT 12340 12341 } else if ((cur->ns != NULL) && 12342 (xmlStrEqual(URI, cur->ns->href))) 12343 { 12344 XP_TEST_HIT 12345 } 12346 } 12347 } 12348 break; 12349 case NODE_TEST_NS:{ 12350 TODO; 12351 break; 12352 } 12353 case NODE_TEST_NAME: 12354 if (axis == AXIS_ATTRIBUTE) { 12355 if (cur->type != XML_ATTRIBUTE_NODE) 12356 break; 12357 } else if (axis == AXIS_NAMESPACE) { 12358 if (cur->type != XML_NAMESPACE_DECL) 12359 break; 12360 } else { 12361 if (cur->type != XML_ELEMENT_NODE) 12362 break; 12363 } 12364 switch (cur->type) { 12365 case XML_ELEMENT_NODE: 12366 if (xmlStrEqual(name, cur->name)) { 12367 if (prefix == NULL) { 12368 if (cur->ns == NULL) 12369 { 12370 XP_TEST_HIT 12371 } 12372 } else { 12373 if ((cur->ns != NULL) && 12374 (xmlStrEqual(URI, cur->ns->href))) 12375 { 12376 XP_TEST_HIT 12377 } 12378 } 12379 } 12380 break; 12381 case XML_ATTRIBUTE_NODE:{ 12382 xmlAttrPtr attr = (xmlAttrPtr) cur; 12383 12384 if (xmlStrEqual(name, attr->name)) { 12385 if (prefix == NULL) { 12386 if ((attr->ns == NULL) || 12387 (attr->ns->prefix == NULL)) 12388 { 12389 XP_TEST_HIT 12390 } 12391 } else { 12392 if ((attr->ns != NULL) && 12393 (xmlStrEqual(URI, 12394 attr->ns->href))) 12395 { 12396 XP_TEST_HIT 12397 } 12398 } 12399 } 12400 break; 12401 } 12402 case XML_NAMESPACE_DECL: 12403 if (cur->type == XML_NAMESPACE_DECL) { 12404 xmlNsPtr ns = (xmlNsPtr) cur; 12405 12406 if ((ns->prefix != NULL) && (name != NULL) 12407 && (xmlStrEqual(ns->prefix, name))) 12408 { 12409 XP_TEST_HIT_NS 12410 } 12411 } 12412 break; 12413 default: 12414 break; 12415 } 12416 break; 12417 } /* switch(test) */ 12418 } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK)); 12419 12420 goto apply_predicates; 12421 12422 axis_range_end: /* ----------------------------------------------------- */ 12423 /* 12424 * We have a "/foo[n]", and position() = n was reached. 12425 * Note that we can have as well "/foo/::parent::foo[1]", so 12426 * a duplicate-aware merge is still needed. 12427 * Merge with the result. 12428 */ 12429 if (outSeq == NULL) { 12430 outSeq = seq; 12431 seq = NULL; 12432 } else 12433 /* TODO: Check memory error. */ 12434 outSeq = mergeAndClear(outSeq, seq); 12435 /* 12436 * Break if only a true/false result was requested. 12437 */ 12438 if (toBool) 12439 break; 12440 continue; 12441 12442 first_hit: /* ---------------------------------------------------------- */ 12443 /* 12444 * Break if only a true/false result was requested and 12445 * no predicates existed and a node test succeeded. 12446 */ 12447 if (outSeq == NULL) { 12448 outSeq = seq; 12449 seq = NULL; 12450 } else 12451 /* TODO: Check memory error. */ 12452 outSeq = mergeAndClear(outSeq, seq); 12453 break; 12454 12455 #ifdef DEBUG_STEP 12456 if (seq != NULL) 12457 nbMatches += seq->nodeNr; 12458 #endif 12459 12460 apply_predicates: /* --------------------------------------------------- */ 12461 if (ctxt->error != XPATH_EXPRESSION_OK) 12462 goto error; 12463 12464 /* 12465 * Apply predicates. 12466 */ 12467 if ((predOp != NULL) && (seq->nodeNr > 0)) { 12468 /* 12469 * E.g. when we have a "/foo[some expression][n]". 12470 */ 12471 /* 12472 * QUESTION TODO: The old predicate evaluation took into 12473 * account location-sets. 12474 * (E.g. ctxt->value->type == XPATH_LOCATIONSET) 12475 * Do we expect such a set here? 12476 * All what I learned now from the evaluation semantics 12477 * does not indicate that a location-set will be processed 12478 * here, so this looks OK. 12479 */ 12480 /* 12481 * Iterate over all predicates, starting with the outermost 12482 * predicate. 12483 * TODO: Problem: we cannot execute the inner predicates first 12484 * since we cannot go back *up* the operator tree! 12485 * Options we have: 12486 * 1) Use of recursive functions (like is it currently done 12487 * via xmlXPathCompOpEval()) 12488 * 2) Add a predicate evaluation information stack to the 12489 * context struct 12490 * 3) Change the way the operators are linked; we need a 12491 * "parent" field on xmlXPathStepOp 12492 * 12493 * For the moment, I'll try to solve this with a recursive 12494 * function: xmlXPathCompOpEvalPredicate(). 12495 */ 12496 if (hasPredicateRange != 0) 12497 xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos, 12498 hasNsNodes); 12499 else 12500 xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr, 12501 hasNsNodes); 12502 12503 if (ctxt->error != XPATH_EXPRESSION_OK) { 12504 total = 0; 12505 goto error; 12506 } 12507 } 12508 12509 if (seq->nodeNr > 0) { 12510 /* 12511 * Add to result set. 12512 */ 12513 if (outSeq == NULL) { 12514 outSeq = seq; 12515 seq = NULL; 12516 } else { 12517 /* TODO: Check memory error. */ 12518 outSeq = mergeAndClear(outSeq, seq); 12519 } 12520 12521 if (toBool) 12522 break; 12523 } 12524 } 12525 12526 error: 12527 if ((obj->boolval) && (obj->user != NULL)) { 12528 /* 12529 * QUESTION TODO: What does this do and why? 12530 * TODO: Do we have to do this also for the "error" 12531 * cleanup further down? 12532 */ 12533 ctxt->value->boolval = 1; 12534 ctxt->value->user = obj->user; 12535 obj->user = NULL; 12536 obj->boolval = 0; 12537 } 12538 xmlXPathReleaseObject(xpctxt, obj); 12539 12540 /* 12541 * Ensure we return at least an empty set. 12542 */ 12543 if (outSeq == NULL) { 12544 if ((seq != NULL) && (seq->nodeNr == 0)) 12545 outSeq = seq; 12546 else 12547 /* TODO: Check memory error. */ 12548 outSeq = xmlXPathNodeSetCreate(NULL); 12549 } 12550 if ((seq != NULL) && (seq != outSeq)) { 12551 xmlXPathFreeNodeSet(seq); 12552 } 12553 /* 12554 * Hand over the result. Better to push the set also in 12555 * case of errors. 12556 */ 12557 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq)); 12558 /* 12559 * Reset the context node. 12560 */ 12561 xpctxt->node = oldContextNode; 12562 /* 12563 * When traversing the namespace axis in "toBool" mode, it's 12564 * possible that tmpNsList wasn't freed. 12565 */ 12566 if (xpctxt->tmpNsList != NULL) { 12567 xmlFree(xpctxt->tmpNsList); 12568 xpctxt->tmpNsList = NULL; 12569 } 12570 12571 #ifdef DEBUG_STEP 12572 xmlGenericError(xmlGenericErrorContext, 12573 "\nExamined %d nodes, found %d nodes at that step\n", 12574 total, nbMatches); 12575 #endif 12576 12577 return(total); 12578 } 12579 12580 static int 12581 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt, 12582 xmlXPathStepOpPtr op, xmlNodePtr * first); 12583 12584 /** 12585 * xmlXPathCompOpEvalFirst: 12586 * @ctxt: the XPath parser context with the compiled expression 12587 * @op: an XPath compiled operation 12588 * @first: the first elem found so far 12589 * 12590 * Evaluate the Precompiled XPath operation searching only the first 12591 * element in document order 12592 * 12593 * Returns the number of examined objects. 12594 */ 12595 static int 12596 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt, 12597 xmlXPathStepOpPtr op, xmlNodePtr * first) 12598 { 12599 int total = 0, cur; 12600 xmlXPathCompExprPtr comp; 12601 xmlXPathObjectPtr arg1, arg2; 12602 12603 CHECK_ERROR0; 12604 if (OP_LIMIT_EXCEEDED(ctxt, 1)) 12605 return(0); 12606 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH) 12607 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED); 12608 ctxt->context->depth += 1; 12609 comp = ctxt->comp; 12610 switch (op->op) { 12611 case XPATH_OP_END: 12612 break; 12613 case XPATH_OP_UNION: 12614 total = 12615 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1], 12616 first); 12617 CHECK_ERROR0; 12618 if ((ctxt->value != NULL) 12619 && (ctxt->value->type == XPATH_NODESET) 12620 && (ctxt->value->nodesetval != NULL) 12621 && (ctxt->value->nodesetval->nodeNr >= 1)) { 12622 /* 12623 * limit tree traversing to first node in the result 12624 */ 12625 /* 12626 * OPTIMIZE TODO: This implicitly sorts 12627 * the result, even if not needed. E.g. if the argument 12628 * of the count() function, no sorting is needed. 12629 * OPTIMIZE TODO: How do we know if the node-list wasn't 12630 * already sorted? 12631 */ 12632 if (ctxt->value->nodesetval->nodeNr > 1) 12633 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12634 *first = ctxt->value->nodesetval->nodeTab[0]; 12635 } 12636 cur = 12637 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2], 12638 first); 12639 CHECK_ERROR0; 12640 12641 arg2 = valuePop(ctxt); 12642 arg1 = valuePop(ctxt); 12643 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) || 12644 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) { 12645 xmlXPathReleaseObject(ctxt->context, arg1); 12646 xmlXPathReleaseObject(ctxt->context, arg2); 12647 XP_ERROR0(XPATH_INVALID_TYPE); 12648 } 12649 if ((ctxt->context->opLimit != 0) && 12650 (((arg1->nodesetval != NULL) && 12651 (xmlXPathCheckOpLimit(ctxt, 12652 arg1->nodesetval->nodeNr) < 0)) || 12653 ((arg2->nodesetval != NULL) && 12654 (xmlXPathCheckOpLimit(ctxt, 12655 arg2->nodesetval->nodeNr) < 0)))) { 12656 xmlXPathReleaseObject(ctxt->context, arg1); 12657 xmlXPathReleaseObject(ctxt->context, arg2); 12658 break; 12659 } 12660 12661 /* TODO: Check memory error. */ 12662 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 12663 arg2->nodesetval); 12664 valuePush(ctxt, arg1); 12665 xmlXPathReleaseObject(ctxt->context, arg2); 12666 /* optimizer */ 12667 if (total > cur) 12668 xmlXPathCompSwap(op); 12669 total += cur; 12670 break; 12671 case XPATH_OP_ROOT: 12672 xmlXPathRoot(ctxt); 12673 break; 12674 case XPATH_OP_NODE: 12675 if (op->ch1 != -1) 12676 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12677 CHECK_ERROR0; 12678 if (op->ch2 != -1) 12679 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12680 CHECK_ERROR0; 12681 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 12682 ctxt->context->node)); 12683 break; 12684 case XPATH_OP_COLLECT:{ 12685 if (op->ch1 == -1) 12686 break; 12687 12688 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12689 CHECK_ERROR0; 12690 12691 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0); 12692 break; 12693 } 12694 case XPATH_OP_VALUE: 12695 valuePush(ctxt, 12696 xmlXPathCacheObjectCopy(ctxt->context, 12697 (xmlXPathObjectPtr) op->value4)); 12698 break; 12699 case XPATH_OP_SORT: 12700 if (op->ch1 != -1) 12701 total += 12702 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1], 12703 first); 12704 CHECK_ERROR0; 12705 if ((ctxt->value != NULL) 12706 && (ctxt->value->type == XPATH_NODESET) 12707 && (ctxt->value->nodesetval != NULL) 12708 && (ctxt->value->nodesetval->nodeNr > 1)) 12709 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12710 break; 12711 #ifdef XP_OPTIMIZED_FILTER_FIRST 12712 case XPATH_OP_FILTER: 12713 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first); 12714 break; 12715 #endif 12716 default: 12717 total += xmlXPathCompOpEval(ctxt, op); 12718 break; 12719 } 12720 12721 ctxt->context->depth -= 1; 12722 return(total); 12723 } 12724 12725 /** 12726 * xmlXPathCompOpEvalLast: 12727 * @ctxt: the XPath parser context with the compiled expression 12728 * @op: an XPath compiled operation 12729 * @last: the last elem found so far 12730 * 12731 * Evaluate the Precompiled XPath operation searching only the last 12732 * element in document order 12733 * 12734 * Returns the number of nodes traversed 12735 */ 12736 static int 12737 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op, 12738 xmlNodePtr * last) 12739 { 12740 int total = 0, cur; 12741 xmlXPathCompExprPtr comp; 12742 xmlXPathObjectPtr arg1, arg2; 12743 12744 CHECK_ERROR0; 12745 if (OP_LIMIT_EXCEEDED(ctxt, 1)) 12746 return(0); 12747 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH) 12748 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED); 12749 ctxt->context->depth += 1; 12750 comp = ctxt->comp; 12751 switch (op->op) { 12752 case XPATH_OP_END: 12753 break; 12754 case XPATH_OP_UNION: 12755 total = 12756 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last); 12757 CHECK_ERROR0; 12758 if ((ctxt->value != NULL) 12759 && (ctxt->value->type == XPATH_NODESET) 12760 && (ctxt->value->nodesetval != NULL) 12761 && (ctxt->value->nodesetval->nodeNr >= 1)) { 12762 /* 12763 * limit tree traversing to first node in the result 12764 */ 12765 if (ctxt->value->nodesetval->nodeNr > 1) 12766 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12767 *last = 12768 ctxt->value->nodesetval->nodeTab[ctxt->value-> 12769 nodesetval->nodeNr - 12770 1]; 12771 } 12772 cur = 12773 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last); 12774 CHECK_ERROR0; 12775 if ((ctxt->value != NULL) 12776 && (ctxt->value->type == XPATH_NODESET) 12777 && (ctxt->value->nodesetval != NULL) 12778 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */ 12779 } 12780 12781 arg2 = valuePop(ctxt); 12782 arg1 = valuePop(ctxt); 12783 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) || 12784 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) { 12785 xmlXPathReleaseObject(ctxt->context, arg1); 12786 xmlXPathReleaseObject(ctxt->context, arg2); 12787 XP_ERROR0(XPATH_INVALID_TYPE); 12788 } 12789 if ((ctxt->context->opLimit != 0) && 12790 (((arg1->nodesetval != NULL) && 12791 (xmlXPathCheckOpLimit(ctxt, 12792 arg1->nodesetval->nodeNr) < 0)) || 12793 ((arg2->nodesetval != NULL) && 12794 (xmlXPathCheckOpLimit(ctxt, 12795 arg2->nodesetval->nodeNr) < 0)))) { 12796 xmlXPathReleaseObject(ctxt->context, arg1); 12797 xmlXPathReleaseObject(ctxt->context, arg2); 12798 break; 12799 } 12800 12801 /* TODO: Check memory error. */ 12802 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 12803 arg2->nodesetval); 12804 valuePush(ctxt, arg1); 12805 xmlXPathReleaseObject(ctxt->context, arg2); 12806 /* optimizer */ 12807 if (total > cur) 12808 xmlXPathCompSwap(op); 12809 total += cur; 12810 break; 12811 case XPATH_OP_ROOT: 12812 xmlXPathRoot(ctxt); 12813 break; 12814 case XPATH_OP_NODE: 12815 if (op->ch1 != -1) 12816 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12817 CHECK_ERROR0; 12818 if (op->ch2 != -1) 12819 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12820 CHECK_ERROR0; 12821 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 12822 ctxt->context->node)); 12823 break; 12824 case XPATH_OP_COLLECT:{ 12825 if (op->ch1 == -1) 12826 break; 12827 12828 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12829 CHECK_ERROR0; 12830 12831 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0); 12832 break; 12833 } 12834 case XPATH_OP_VALUE: 12835 valuePush(ctxt, 12836 xmlXPathCacheObjectCopy(ctxt->context, 12837 (xmlXPathObjectPtr) op->value4)); 12838 break; 12839 case XPATH_OP_SORT: 12840 if (op->ch1 != -1) 12841 total += 12842 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], 12843 last); 12844 CHECK_ERROR0; 12845 if ((ctxt->value != NULL) 12846 && (ctxt->value->type == XPATH_NODESET) 12847 && (ctxt->value->nodesetval != NULL) 12848 && (ctxt->value->nodesetval->nodeNr > 1)) 12849 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12850 break; 12851 default: 12852 total += xmlXPathCompOpEval(ctxt, op); 12853 break; 12854 } 12855 12856 ctxt->context->depth -= 1; 12857 return (total); 12858 } 12859 12860 #ifdef XP_OPTIMIZED_FILTER_FIRST 12861 static int 12862 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt, 12863 xmlXPathStepOpPtr op, xmlNodePtr * first) 12864 { 12865 int total = 0; 12866 xmlXPathCompExprPtr comp; 12867 xmlNodeSetPtr set; 12868 12869 CHECK_ERROR0; 12870 comp = ctxt->comp; 12871 /* 12872 * Optimization for ()[last()] selection i.e. the last elem 12873 */ 12874 if ((op->ch1 != -1) && (op->ch2 != -1) && 12875 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 12876 (comp->steps[op->ch2].op == XPATH_OP_SORT)) { 12877 int f = comp->steps[op->ch2].ch1; 12878 12879 if ((f != -1) && 12880 (comp->steps[f].op == XPATH_OP_FUNCTION) && 12881 (comp->steps[f].value5 == NULL) && 12882 (comp->steps[f].value == 0) && 12883 (comp->steps[f].value4 != NULL) && 12884 (xmlStrEqual 12885 (comp->steps[f].value4, BAD_CAST "last"))) { 12886 xmlNodePtr last = NULL; 12887 12888 total += 12889 xmlXPathCompOpEvalLast(ctxt, 12890 &comp->steps[op->ch1], 12891 &last); 12892 CHECK_ERROR0; 12893 /* 12894 * The nodeset should be in document order, 12895 * Keep only the last value 12896 */ 12897 if ((ctxt->value != NULL) && 12898 (ctxt->value->type == XPATH_NODESET) && 12899 (ctxt->value->nodesetval != NULL) && 12900 (ctxt->value->nodesetval->nodeTab != NULL) && 12901 (ctxt->value->nodesetval->nodeNr > 1)) { 12902 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval); 12903 *first = *(ctxt->value->nodesetval->nodeTab); 12904 } 12905 return (total); 12906 } 12907 } 12908 12909 if (op->ch1 != -1) 12910 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12911 CHECK_ERROR0; 12912 if (op->ch2 == -1) 12913 return (total); 12914 if (ctxt->value == NULL) 12915 return (total); 12916 12917 #ifdef LIBXML_XPTR_ENABLED 12918 /* 12919 * Hum are we filtering the result of an XPointer expression 12920 */ 12921 if (ctxt->value->type == XPATH_LOCATIONSET) { 12922 xmlLocationSetPtr locset = ctxt->value->user; 12923 12924 if (locset != NULL) { 12925 xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1); 12926 if (locset->locNr > 0) 12927 *first = (xmlNodePtr) locset->locTab[0]->user; 12928 } 12929 12930 return (total); 12931 } 12932 #endif /* LIBXML_XPTR_ENABLED */ 12933 12934 CHECK_TYPE0(XPATH_NODESET); 12935 set = ctxt->value->nodesetval; 12936 if (set != NULL) { 12937 xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1); 12938 if (set->nodeNr > 0) 12939 *first = set->nodeTab[0]; 12940 } 12941 12942 return (total); 12943 } 12944 #endif /* XP_OPTIMIZED_FILTER_FIRST */ 12945 12946 /** 12947 * xmlXPathCompOpEval: 12948 * @ctxt: the XPath parser context with the compiled expression 12949 * @op: an XPath compiled operation 12950 * 12951 * Evaluate the Precompiled XPath operation 12952 * Returns the number of nodes traversed 12953 */ 12954 static int 12955 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) 12956 { 12957 int total = 0; 12958 int equal, ret; 12959 xmlXPathCompExprPtr comp; 12960 xmlXPathObjectPtr arg1, arg2; 12961 12962 CHECK_ERROR0; 12963 if (OP_LIMIT_EXCEEDED(ctxt, 1)) 12964 return(0); 12965 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH) 12966 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED); 12967 ctxt->context->depth += 1; 12968 comp = ctxt->comp; 12969 switch (op->op) { 12970 case XPATH_OP_END: 12971 break; 12972 case XPATH_OP_AND: 12973 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12974 CHECK_ERROR0; 12975 xmlXPathBooleanFunction(ctxt, 1); 12976 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0)) 12977 break; 12978 arg2 = valuePop(ctxt); 12979 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12980 if (ctxt->error) { 12981 xmlXPathFreeObject(arg2); 12982 break; 12983 } 12984 xmlXPathBooleanFunction(ctxt, 1); 12985 if (ctxt->value != NULL) 12986 ctxt->value->boolval &= arg2->boolval; 12987 xmlXPathReleaseObject(ctxt->context, arg2); 12988 break; 12989 case XPATH_OP_OR: 12990 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12991 CHECK_ERROR0; 12992 xmlXPathBooleanFunction(ctxt, 1); 12993 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1)) 12994 break; 12995 arg2 = valuePop(ctxt); 12996 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12997 if (ctxt->error) { 12998 xmlXPathFreeObject(arg2); 12999 break; 13000 } 13001 xmlXPathBooleanFunction(ctxt, 1); 13002 if (ctxt->value != NULL) 13003 ctxt->value->boolval |= arg2->boolval; 13004 xmlXPathReleaseObject(ctxt->context, arg2); 13005 break; 13006 case XPATH_OP_EQUAL: 13007 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13008 CHECK_ERROR0; 13009 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13010 CHECK_ERROR0; 13011 if (op->value) 13012 equal = xmlXPathEqualValues(ctxt); 13013 else 13014 equal = xmlXPathNotEqualValues(ctxt); 13015 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal)); 13016 break; 13017 case XPATH_OP_CMP: 13018 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13019 CHECK_ERROR0; 13020 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13021 CHECK_ERROR0; 13022 ret = xmlXPathCompareValues(ctxt, op->value, op->value2); 13023 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret)); 13024 break; 13025 case XPATH_OP_PLUS: 13026 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13027 CHECK_ERROR0; 13028 if (op->ch2 != -1) { 13029 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13030 } 13031 CHECK_ERROR0; 13032 if (op->value == 0) 13033 xmlXPathSubValues(ctxt); 13034 else if (op->value == 1) 13035 xmlXPathAddValues(ctxt); 13036 else if (op->value == 2) 13037 xmlXPathValueFlipSign(ctxt); 13038 else if (op->value == 3) { 13039 CAST_TO_NUMBER; 13040 CHECK_TYPE0(XPATH_NUMBER); 13041 } 13042 break; 13043 case XPATH_OP_MULT: 13044 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13045 CHECK_ERROR0; 13046 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13047 CHECK_ERROR0; 13048 if (op->value == 0) 13049 xmlXPathMultValues(ctxt); 13050 else if (op->value == 1) 13051 xmlXPathDivValues(ctxt); 13052 else if (op->value == 2) 13053 xmlXPathModValues(ctxt); 13054 break; 13055 case XPATH_OP_UNION: 13056 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13057 CHECK_ERROR0; 13058 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13059 CHECK_ERROR0; 13060 13061 arg2 = valuePop(ctxt); 13062 arg1 = valuePop(ctxt); 13063 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) || 13064 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) { 13065 xmlXPathReleaseObject(ctxt->context, arg1); 13066 xmlXPathReleaseObject(ctxt->context, arg2); 13067 XP_ERROR0(XPATH_INVALID_TYPE); 13068 } 13069 if ((ctxt->context->opLimit != 0) && 13070 (((arg1->nodesetval != NULL) && 13071 (xmlXPathCheckOpLimit(ctxt, 13072 arg1->nodesetval->nodeNr) < 0)) || 13073 ((arg2->nodesetval != NULL) && 13074 (xmlXPathCheckOpLimit(ctxt, 13075 arg2->nodesetval->nodeNr) < 0)))) { 13076 xmlXPathReleaseObject(ctxt->context, arg1); 13077 xmlXPathReleaseObject(ctxt->context, arg2); 13078 break; 13079 } 13080 13081 if ((arg1->nodesetval == NULL) || 13082 ((arg2->nodesetval != NULL) && 13083 (arg2->nodesetval->nodeNr != 0))) 13084 { 13085 /* TODO: Check memory error. */ 13086 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 13087 arg2->nodesetval); 13088 } 13089 13090 valuePush(ctxt, arg1); 13091 xmlXPathReleaseObject(ctxt->context, arg2); 13092 break; 13093 case XPATH_OP_ROOT: 13094 xmlXPathRoot(ctxt); 13095 break; 13096 case XPATH_OP_NODE: 13097 if (op->ch1 != -1) 13098 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13099 CHECK_ERROR0; 13100 if (op->ch2 != -1) 13101 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13102 CHECK_ERROR0; 13103 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 13104 ctxt->context->node)); 13105 break; 13106 case XPATH_OP_COLLECT:{ 13107 if (op->ch1 == -1) 13108 break; 13109 13110 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13111 CHECK_ERROR0; 13112 13113 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0); 13114 break; 13115 } 13116 case XPATH_OP_VALUE: 13117 valuePush(ctxt, 13118 xmlXPathCacheObjectCopy(ctxt->context, 13119 (xmlXPathObjectPtr) op->value4)); 13120 break; 13121 case XPATH_OP_VARIABLE:{ 13122 xmlXPathObjectPtr val; 13123 13124 if (op->ch1 != -1) 13125 total += 13126 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13127 if (op->value5 == NULL) { 13128 val = xmlXPathVariableLookup(ctxt->context, op->value4); 13129 if (val == NULL) 13130 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR); 13131 valuePush(ctxt, val); 13132 } else { 13133 const xmlChar *URI; 13134 13135 URI = xmlXPathNsLookup(ctxt->context, op->value5); 13136 if (URI == NULL) { 13137 xmlGenericError(xmlGenericErrorContext, 13138 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n", 13139 (char *) op->value4, (char *)op->value5); 13140 ctxt->error = XPATH_UNDEF_PREFIX_ERROR; 13141 break; 13142 } 13143 val = xmlXPathVariableLookupNS(ctxt->context, 13144 op->value4, URI); 13145 if (val == NULL) 13146 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR); 13147 valuePush(ctxt, val); 13148 } 13149 break; 13150 } 13151 case XPATH_OP_FUNCTION:{ 13152 xmlXPathFunction func; 13153 const xmlChar *oldFunc, *oldFuncURI; 13154 int i; 13155 int frame; 13156 13157 frame = xmlXPathSetFrame(ctxt); 13158 if (op->ch1 != -1) { 13159 total += 13160 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13161 if (ctxt->error != XPATH_EXPRESSION_OK) { 13162 xmlXPathPopFrame(ctxt, frame); 13163 break; 13164 } 13165 } 13166 if (ctxt->valueNr < ctxt->valueFrame + op->value) { 13167 xmlGenericError(xmlGenericErrorContext, 13168 "xmlXPathCompOpEval: parameter error\n"); 13169 ctxt->error = XPATH_INVALID_OPERAND; 13170 xmlXPathPopFrame(ctxt, frame); 13171 break; 13172 } 13173 for (i = 0; i < op->value; i++) { 13174 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) { 13175 xmlGenericError(xmlGenericErrorContext, 13176 "xmlXPathCompOpEval: parameter error\n"); 13177 ctxt->error = XPATH_INVALID_OPERAND; 13178 xmlXPathPopFrame(ctxt, frame); 13179 break; 13180 } 13181 } 13182 if (op->cache != NULL) 13183 func = op->cache; 13184 else { 13185 const xmlChar *URI = NULL; 13186 13187 if (op->value5 == NULL) 13188 func = 13189 xmlXPathFunctionLookup(ctxt->context, 13190 op->value4); 13191 else { 13192 URI = xmlXPathNsLookup(ctxt->context, op->value5); 13193 if (URI == NULL) { 13194 xmlGenericError(xmlGenericErrorContext, 13195 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n", 13196 (char *)op->value4, (char *)op->value5); 13197 xmlXPathPopFrame(ctxt, frame); 13198 ctxt->error = XPATH_UNDEF_PREFIX_ERROR; 13199 break; 13200 } 13201 func = xmlXPathFunctionLookupNS(ctxt->context, 13202 op->value4, URI); 13203 } 13204 if (func == NULL) { 13205 xmlGenericError(xmlGenericErrorContext, 13206 "xmlXPathCompOpEval: function %s not found\n", 13207 (char *)op->value4); 13208 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR); 13209 } 13210 op->cache = func; 13211 op->cacheURI = (void *) URI; 13212 } 13213 oldFunc = ctxt->context->function; 13214 oldFuncURI = ctxt->context->functionURI; 13215 ctxt->context->function = op->value4; 13216 ctxt->context->functionURI = op->cacheURI; 13217 func(ctxt, op->value); 13218 ctxt->context->function = oldFunc; 13219 ctxt->context->functionURI = oldFuncURI; 13220 if ((ctxt->error == XPATH_EXPRESSION_OK) && 13221 (ctxt->valueNr != ctxt->valueFrame + 1)) 13222 XP_ERROR0(XPATH_STACK_ERROR); 13223 xmlXPathPopFrame(ctxt, frame); 13224 break; 13225 } 13226 case XPATH_OP_ARG: 13227 if (op->ch1 != -1) { 13228 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13229 CHECK_ERROR0; 13230 } 13231 if (op->ch2 != -1) { 13232 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13233 CHECK_ERROR0; 13234 } 13235 break; 13236 case XPATH_OP_PREDICATE: 13237 case XPATH_OP_FILTER:{ 13238 xmlNodeSetPtr set; 13239 13240 /* 13241 * Optimization for ()[1] selection i.e. the first elem 13242 */ 13243 if ((op->ch1 != -1) && (op->ch2 != -1) && 13244 #ifdef XP_OPTIMIZED_FILTER_FIRST 13245 /* 13246 * FILTER TODO: Can we assume that the inner processing 13247 * will result in an ordered list if we have an 13248 * XPATH_OP_FILTER? 13249 * What about an additional field or flag on 13250 * xmlXPathObject like @sorted ? This way we wouldn't need 13251 * to assume anything, so it would be more robust and 13252 * easier to optimize. 13253 */ 13254 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */ 13255 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */ 13256 #else 13257 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 13258 #endif 13259 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */ 13260 xmlXPathObjectPtr val; 13261 13262 val = comp->steps[op->ch2].value4; 13263 if ((val != NULL) && (val->type == XPATH_NUMBER) && 13264 (val->floatval == 1.0)) { 13265 xmlNodePtr first = NULL; 13266 13267 total += 13268 xmlXPathCompOpEvalFirst(ctxt, 13269 &comp->steps[op->ch1], 13270 &first); 13271 CHECK_ERROR0; 13272 /* 13273 * The nodeset should be in document order, 13274 * Keep only the first value 13275 */ 13276 if ((ctxt->value != NULL) && 13277 (ctxt->value->type == XPATH_NODESET) && 13278 (ctxt->value->nodesetval != NULL) && 13279 (ctxt->value->nodesetval->nodeNr > 1)) 13280 xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval, 13281 1, 1); 13282 break; 13283 } 13284 } 13285 /* 13286 * Optimization for ()[last()] selection i.e. the last elem 13287 */ 13288 if ((op->ch1 != -1) && (op->ch2 != -1) && 13289 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 13290 (comp->steps[op->ch2].op == XPATH_OP_SORT)) { 13291 int f = comp->steps[op->ch2].ch1; 13292 13293 if ((f != -1) && 13294 (comp->steps[f].op == XPATH_OP_FUNCTION) && 13295 (comp->steps[f].value5 == NULL) && 13296 (comp->steps[f].value == 0) && 13297 (comp->steps[f].value4 != NULL) && 13298 (xmlStrEqual 13299 (comp->steps[f].value4, BAD_CAST "last"))) { 13300 xmlNodePtr last = NULL; 13301 13302 total += 13303 xmlXPathCompOpEvalLast(ctxt, 13304 &comp->steps[op->ch1], 13305 &last); 13306 CHECK_ERROR0; 13307 /* 13308 * The nodeset should be in document order, 13309 * Keep only the last value 13310 */ 13311 if ((ctxt->value != NULL) && 13312 (ctxt->value->type == XPATH_NODESET) && 13313 (ctxt->value->nodesetval != NULL) && 13314 (ctxt->value->nodesetval->nodeTab != NULL) && 13315 (ctxt->value->nodesetval->nodeNr > 1)) 13316 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval); 13317 break; 13318 } 13319 } 13320 /* 13321 * Process inner predicates first. 13322 * Example "index[parent::book][1]": 13323 * ... 13324 * PREDICATE <-- we are here "[1]" 13325 * PREDICATE <-- process "[parent::book]" first 13326 * SORT 13327 * COLLECT 'parent' 'name' 'node' book 13328 * NODE 13329 * ELEM Object is a number : 1 13330 */ 13331 if (op->ch1 != -1) 13332 total += 13333 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13334 CHECK_ERROR0; 13335 if (op->ch2 == -1) 13336 break; 13337 if (ctxt->value == NULL) 13338 break; 13339 13340 #ifdef LIBXML_XPTR_ENABLED 13341 /* 13342 * Hum are we filtering the result of an XPointer expression 13343 */ 13344 if (ctxt->value->type == XPATH_LOCATIONSET) { 13345 xmlLocationSetPtr locset = ctxt->value->user; 13346 xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 13347 1, locset->locNr); 13348 break; 13349 } 13350 #endif /* LIBXML_XPTR_ENABLED */ 13351 13352 CHECK_TYPE0(XPATH_NODESET); 13353 set = ctxt->value->nodesetval; 13354 if (set != NULL) 13355 xmlXPathNodeSetFilter(ctxt, set, op->ch2, 13356 1, set->nodeNr, 1); 13357 break; 13358 } 13359 case XPATH_OP_SORT: 13360 if (op->ch1 != -1) 13361 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13362 CHECK_ERROR0; 13363 if ((ctxt->value != NULL) && 13364 (ctxt->value->type == XPATH_NODESET) && 13365 (ctxt->value->nodesetval != NULL) && 13366 (ctxt->value->nodesetval->nodeNr > 1)) 13367 { 13368 xmlXPathNodeSetSort(ctxt->value->nodesetval); 13369 } 13370 break; 13371 #ifdef LIBXML_XPTR_ENABLED 13372 case XPATH_OP_RANGETO:{ 13373 xmlXPathObjectPtr range; 13374 xmlXPathObjectPtr res, obj; 13375 xmlXPathObjectPtr tmp; 13376 xmlLocationSetPtr newlocset = NULL; 13377 xmlLocationSetPtr oldlocset; 13378 xmlNodeSetPtr oldset; 13379 xmlNodePtr oldnode = ctxt->context->node; 13380 int oldcs = ctxt->context->contextSize; 13381 int oldpp = ctxt->context->proximityPosition; 13382 int i, j; 13383 13384 if (op->ch1 != -1) { 13385 total += 13386 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13387 CHECK_ERROR0; 13388 } 13389 if (ctxt->value == NULL) { 13390 XP_ERROR0(XPATH_INVALID_OPERAND); 13391 } 13392 if (op->ch2 == -1) 13393 break; 13394 13395 if (ctxt->value->type == XPATH_LOCATIONSET) { 13396 /* 13397 * Extract the old locset, and then evaluate the result of the 13398 * expression for all the element in the locset. use it to grow 13399 * up a new locset. 13400 */ 13401 CHECK_TYPE0(XPATH_LOCATIONSET); 13402 13403 if ((ctxt->value->user == NULL) || 13404 (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0)) 13405 break; 13406 13407 obj = valuePop(ctxt); 13408 oldlocset = obj->user; 13409 13410 newlocset = xmlXPtrLocationSetCreate(NULL); 13411 13412 for (i = 0; i < oldlocset->locNr; i++) { 13413 /* 13414 * Run the evaluation with a node list made of a 13415 * single item in the nodelocset. 13416 */ 13417 ctxt->context->node = oldlocset->locTab[i]->user; 13418 ctxt->context->contextSize = oldlocset->locNr; 13419 ctxt->context->proximityPosition = i + 1; 13420 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13421 ctxt->context->node); 13422 valuePush(ctxt, tmp); 13423 13424 if (op->ch2 != -1) 13425 total += 13426 xmlXPathCompOpEval(ctxt, 13427 &comp->steps[op->ch2]); 13428 if (ctxt->error != XPATH_EXPRESSION_OK) { 13429 xmlXPtrFreeLocationSet(newlocset); 13430 goto rangeto_error; 13431 } 13432 13433 res = valuePop(ctxt); 13434 if (res->type == XPATH_LOCATIONSET) { 13435 xmlLocationSetPtr rloc = 13436 (xmlLocationSetPtr)res->user; 13437 for (j=0; j<rloc->locNr; j++) { 13438 range = xmlXPtrNewRange( 13439 oldlocset->locTab[i]->user, 13440 oldlocset->locTab[i]->index, 13441 rloc->locTab[j]->user2, 13442 rloc->locTab[j]->index2); 13443 if (range != NULL) { 13444 xmlXPtrLocationSetAdd(newlocset, range); 13445 } 13446 } 13447 } else { 13448 range = xmlXPtrNewRangeNodeObject( 13449 (xmlNodePtr)oldlocset->locTab[i]->user, res); 13450 if (range != NULL) { 13451 xmlXPtrLocationSetAdd(newlocset,range); 13452 } 13453 } 13454 13455 /* 13456 * Cleanup 13457 */ 13458 if (res != NULL) { 13459 xmlXPathReleaseObject(ctxt->context, res); 13460 } 13461 if (ctxt->value == tmp) { 13462 res = valuePop(ctxt); 13463 xmlXPathReleaseObject(ctxt->context, res); 13464 } 13465 } 13466 } else { /* Not a location set */ 13467 CHECK_TYPE0(XPATH_NODESET); 13468 obj = valuePop(ctxt); 13469 oldset = obj->nodesetval; 13470 13471 newlocset = xmlXPtrLocationSetCreate(NULL); 13472 13473 if (oldset != NULL) { 13474 for (i = 0; i < oldset->nodeNr; i++) { 13475 /* 13476 * Run the evaluation with a node list made of a single item 13477 * in the nodeset. 13478 */ 13479 ctxt->context->node = oldset->nodeTab[i]; 13480 /* 13481 * OPTIMIZE TODO: Avoid recreation for every iteration. 13482 */ 13483 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13484 ctxt->context->node); 13485 valuePush(ctxt, tmp); 13486 13487 if (op->ch2 != -1) 13488 total += 13489 xmlXPathCompOpEval(ctxt, 13490 &comp->steps[op->ch2]); 13491 if (ctxt->error != XPATH_EXPRESSION_OK) { 13492 xmlXPtrFreeLocationSet(newlocset); 13493 goto rangeto_error; 13494 } 13495 13496 res = valuePop(ctxt); 13497 range = 13498 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i], 13499 res); 13500 if (range != NULL) { 13501 xmlXPtrLocationSetAdd(newlocset, range); 13502 } 13503 13504 /* 13505 * Cleanup 13506 */ 13507 if (res != NULL) { 13508 xmlXPathReleaseObject(ctxt->context, res); 13509 } 13510 if (ctxt->value == tmp) { 13511 res = valuePop(ctxt); 13512 xmlXPathReleaseObject(ctxt->context, res); 13513 } 13514 } 13515 } 13516 } 13517 13518 /* 13519 * The result is used as the new evaluation set. 13520 */ 13521 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset)); 13522 rangeto_error: 13523 xmlXPathReleaseObject(ctxt->context, obj); 13524 ctxt->context->node = oldnode; 13525 ctxt->context->contextSize = oldcs; 13526 ctxt->context->proximityPosition = oldpp; 13527 break; 13528 } 13529 #endif /* LIBXML_XPTR_ENABLED */ 13530 default: 13531 xmlGenericError(xmlGenericErrorContext, 13532 "XPath: unknown precompiled operation %d\n", op->op); 13533 ctxt->error = XPATH_INVALID_OPERAND; 13534 break; 13535 } 13536 13537 ctxt->context->depth -= 1; 13538 return (total); 13539 } 13540 13541 /** 13542 * xmlXPathCompOpEvalToBoolean: 13543 * @ctxt: the XPath parser context 13544 * 13545 * Evaluates if the expression evaluates to true. 13546 * 13547 * Returns 1 if true, 0 if false and -1 on API or internal errors. 13548 */ 13549 static int 13550 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt, 13551 xmlXPathStepOpPtr op, 13552 int isPredicate) 13553 { 13554 xmlXPathObjectPtr resObj = NULL; 13555 13556 start: 13557 if (OP_LIMIT_EXCEEDED(ctxt, 1)) 13558 return(0); 13559 /* comp = ctxt->comp; */ 13560 switch (op->op) { 13561 case XPATH_OP_END: 13562 return (0); 13563 case XPATH_OP_VALUE: 13564 resObj = (xmlXPathObjectPtr) op->value4; 13565 if (isPredicate) 13566 return(xmlXPathEvaluatePredicateResult(ctxt, resObj)); 13567 return(xmlXPathCastToBoolean(resObj)); 13568 case XPATH_OP_SORT: 13569 /* 13570 * We don't need sorting for boolean results. Skip this one. 13571 */ 13572 if (op->ch1 != -1) { 13573 op = &ctxt->comp->steps[op->ch1]; 13574 goto start; 13575 } 13576 return(0); 13577 case XPATH_OP_COLLECT: 13578 if (op->ch1 == -1) 13579 return(0); 13580 13581 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]); 13582 if (ctxt->error != XPATH_EXPRESSION_OK) 13583 return(-1); 13584 13585 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1); 13586 if (ctxt->error != XPATH_EXPRESSION_OK) 13587 return(-1); 13588 13589 resObj = valuePop(ctxt); 13590 if (resObj == NULL) 13591 return(-1); 13592 break; 13593 default: 13594 /* 13595 * Fallback to call xmlXPathCompOpEval(). 13596 */ 13597 xmlXPathCompOpEval(ctxt, op); 13598 if (ctxt->error != XPATH_EXPRESSION_OK) 13599 return(-1); 13600 13601 resObj = valuePop(ctxt); 13602 if (resObj == NULL) 13603 return(-1); 13604 break; 13605 } 13606 13607 if (resObj) { 13608 int res; 13609 13610 if (resObj->type == XPATH_BOOLEAN) { 13611 res = resObj->boolval; 13612 } else if (isPredicate) { 13613 /* 13614 * For predicates a result of type "number" is handled 13615 * differently: 13616 * SPEC XPath 1.0: 13617 * "If the result is a number, the result will be converted 13618 * to true if the number is equal to the context position 13619 * and will be converted to false otherwise;" 13620 */ 13621 res = xmlXPathEvaluatePredicateResult(ctxt, resObj); 13622 } else { 13623 res = xmlXPathCastToBoolean(resObj); 13624 } 13625 xmlXPathReleaseObject(ctxt->context, resObj); 13626 return(res); 13627 } 13628 13629 return(0); 13630 } 13631 13632 #ifdef XPATH_STREAMING 13633 /** 13634 * xmlXPathRunStreamEval: 13635 * @ctxt: the XPath parser context with the compiled expression 13636 * 13637 * Evaluate the Precompiled Streamable XPath expression in the given context. 13638 */ 13639 static int 13640 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp, 13641 xmlXPathObjectPtr *resultSeq, int toBool) 13642 { 13643 int max_depth, min_depth; 13644 int from_root; 13645 int ret, depth; 13646 int eval_all_nodes; 13647 xmlNodePtr cur = NULL, limit = NULL; 13648 xmlStreamCtxtPtr patstream = NULL; 13649 13650 int nb_nodes = 0; 13651 13652 if ((ctxt == NULL) || (comp == NULL)) 13653 return(-1); 13654 max_depth = xmlPatternMaxDepth(comp); 13655 if (max_depth == -1) 13656 return(-1); 13657 if (max_depth == -2) 13658 max_depth = 10000; 13659 min_depth = xmlPatternMinDepth(comp); 13660 if (min_depth == -1) 13661 return(-1); 13662 from_root = xmlPatternFromRoot(comp); 13663 if (from_root < 0) 13664 return(-1); 13665 #if 0 13666 printf("stream eval: depth %d from root %d\n", max_depth, from_root); 13667 #endif 13668 13669 if (! toBool) { 13670 if (resultSeq == NULL) 13671 return(-1); 13672 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL); 13673 if (*resultSeq == NULL) 13674 return(-1); 13675 } 13676 13677 /* 13678 * handle the special cases of "/" amd "." being matched 13679 */ 13680 if (min_depth == 0) { 13681 if (from_root) { 13682 /* Select "/" */ 13683 if (toBool) 13684 return(1); 13685 /* TODO: Check memory error. */ 13686 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, 13687 (xmlNodePtr) ctxt->doc); 13688 } else { 13689 /* Select "self::node()" */ 13690 if (toBool) 13691 return(1); 13692 /* TODO: Check memory error. */ 13693 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node); 13694 } 13695 } 13696 if (max_depth == 0) { 13697 return(0); 13698 } 13699 13700 if (from_root) { 13701 cur = (xmlNodePtr)ctxt->doc; 13702 } else if (ctxt->node != NULL) { 13703 switch (ctxt->node->type) { 13704 case XML_ELEMENT_NODE: 13705 case XML_DOCUMENT_NODE: 13706 case XML_DOCUMENT_FRAG_NODE: 13707 case XML_HTML_DOCUMENT_NODE: 13708 #ifdef LIBXML_DOCB_ENABLED 13709 case XML_DOCB_DOCUMENT_NODE: 13710 #endif 13711 cur = ctxt->node; 13712 break; 13713 case XML_ATTRIBUTE_NODE: 13714 case XML_TEXT_NODE: 13715 case XML_CDATA_SECTION_NODE: 13716 case XML_ENTITY_REF_NODE: 13717 case XML_ENTITY_NODE: 13718 case XML_PI_NODE: 13719 case XML_COMMENT_NODE: 13720 case XML_NOTATION_NODE: 13721 case XML_DTD_NODE: 13722 case XML_DOCUMENT_TYPE_NODE: 13723 case XML_ELEMENT_DECL: 13724 case XML_ATTRIBUTE_DECL: 13725 case XML_ENTITY_DECL: 13726 case XML_NAMESPACE_DECL: 13727 case XML_XINCLUDE_START: 13728 case XML_XINCLUDE_END: 13729 break; 13730 } 13731 limit = cur; 13732 } 13733 if (cur == NULL) { 13734 return(0); 13735 } 13736 13737 patstream = xmlPatternGetStreamCtxt(comp); 13738 if (patstream == NULL) { 13739 /* 13740 * QUESTION TODO: Is this an error? 13741 */ 13742 return(0); 13743 } 13744 13745 eval_all_nodes = xmlStreamWantsAnyNode(patstream); 13746 13747 if (from_root) { 13748 ret = xmlStreamPush(patstream, NULL, NULL); 13749 if (ret < 0) { 13750 } else if (ret == 1) { 13751 if (toBool) 13752 goto return_1; 13753 /* TODO: Check memory error. */ 13754 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur); 13755 } 13756 } 13757 depth = 0; 13758 goto scan_children; 13759 next_node: 13760 do { 13761 if (ctxt->opLimit != 0) { 13762 if (ctxt->opCount >= ctxt->opLimit) { 13763 xmlGenericError(xmlGenericErrorContext, 13764 "XPath operation limit exceeded\n"); 13765 xmlFreeStreamCtxt(patstream); 13766 return(-1); 13767 } 13768 ctxt->opCount++; 13769 } 13770 13771 nb_nodes++; 13772 13773 switch (cur->type) { 13774 case XML_ELEMENT_NODE: 13775 case XML_TEXT_NODE: 13776 case XML_CDATA_SECTION_NODE: 13777 case XML_COMMENT_NODE: 13778 case XML_PI_NODE: 13779 if (cur->type == XML_ELEMENT_NODE) { 13780 ret = xmlStreamPush(patstream, cur->name, 13781 (cur->ns ? cur->ns->href : NULL)); 13782 } else if (eval_all_nodes) 13783 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type); 13784 else 13785 break; 13786 13787 if (ret < 0) { 13788 /* NOP. */ 13789 } else if (ret == 1) { 13790 if (toBool) 13791 goto return_1; 13792 if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur) 13793 < 0) { 13794 ctxt->lastError.domain = XML_FROM_XPATH; 13795 ctxt->lastError.code = XML_ERR_NO_MEMORY; 13796 } 13797 } 13798 if ((cur->children == NULL) || (depth >= max_depth)) { 13799 ret = xmlStreamPop(patstream); 13800 while (cur->next != NULL) { 13801 cur = cur->next; 13802 if ((cur->type != XML_ENTITY_DECL) && 13803 (cur->type != XML_DTD_NODE)) 13804 goto next_node; 13805 } 13806 } 13807 default: 13808 break; 13809 } 13810 13811 scan_children: 13812 if (cur->type == XML_NAMESPACE_DECL) break; 13813 if ((cur->children != NULL) && (depth < max_depth)) { 13814 /* 13815 * Do not descend on entities declarations 13816 */ 13817 if (cur->children->type != XML_ENTITY_DECL) { 13818 cur = cur->children; 13819 depth++; 13820 /* 13821 * Skip DTDs 13822 */ 13823 if (cur->type != XML_DTD_NODE) 13824 continue; 13825 } 13826 } 13827 13828 if (cur == limit) 13829 break; 13830 13831 while (cur->next != NULL) { 13832 cur = cur->next; 13833 if ((cur->type != XML_ENTITY_DECL) && 13834 (cur->type != XML_DTD_NODE)) 13835 goto next_node; 13836 } 13837 13838 do { 13839 cur = cur->parent; 13840 depth--; 13841 if ((cur == NULL) || (cur == limit) || 13842 (cur->type == XML_DOCUMENT_NODE)) 13843 goto done; 13844 if (cur->type == XML_ELEMENT_NODE) { 13845 ret = xmlStreamPop(patstream); 13846 } else if ((eval_all_nodes) && 13847 ((cur->type == XML_TEXT_NODE) || 13848 (cur->type == XML_CDATA_SECTION_NODE) || 13849 (cur->type == XML_COMMENT_NODE) || 13850 (cur->type == XML_PI_NODE))) 13851 { 13852 ret = xmlStreamPop(patstream); 13853 } 13854 if (cur->next != NULL) { 13855 cur = cur->next; 13856 break; 13857 } 13858 } while (cur != NULL); 13859 13860 } while ((cur != NULL) && (depth >= 0)); 13861 13862 done: 13863 13864 #if 0 13865 printf("stream eval: checked %d nodes selected %d\n", 13866 nb_nodes, retObj->nodesetval->nodeNr); 13867 #endif 13868 13869 if (patstream) 13870 xmlFreeStreamCtxt(patstream); 13871 return(0); 13872 13873 return_1: 13874 if (patstream) 13875 xmlFreeStreamCtxt(patstream); 13876 return(1); 13877 } 13878 #endif /* XPATH_STREAMING */ 13879 13880 /** 13881 * xmlXPathRunEval: 13882 * @ctxt: the XPath parser context with the compiled expression 13883 * @toBool: evaluate to a boolean result 13884 * 13885 * Evaluate the Precompiled XPath expression in the given context. 13886 */ 13887 static int 13888 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool) 13889 { 13890 xmlXPathCompExprPtr comp; 13891 13892 if ((ctxt == NULL) || (ctxt->comp == NULL)) 13893 return(-1); 13894 13895 ctxt->context->depth = 0; 13896 13897 if (ctxt->valueTab == NULL) { 13898 /* Allocate the value stack */ 13899 ctxt->valueTab = (xmlXPathObjectPtr *) 13900 xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); 13901 if (ctxt->valueTab == NULL) { 13902 xmlXPathPErrMemory(ctxt, "creating evaluation context\n"); 13903 xmlFree(ctxt); 13904 } 13905 ctxt->valueNr = 0; 13906 ctxt->valueMax = 10; 13907 ctxt->value = NULL; 13908 ctxt->valueFrame = 0; 13909 } 13910 #ifdef XPATH_STREAMING 13911 if (ctxt->comp->stream) { 13912 int res; 13913 13914 if (toBool) { 13915 /* 13916 * Evaluation to boolean result. 13917 */ 13918 res = xmlXPathRunStreamEval(ctxt->context, 13919 ctxt->comp->stream, NULL, 1); 13920 if (res != -1) 13921 return(res); 13922 } else { 13923 xmlXPathObjectPtr resObj = NULL; 13924 13925 /* 13926 * Evaluation to a sequence. 13927 */ 13928 res = xmlXPathRunStreamEval(ctxt->context, 13929 ctxt->comp->stream, &resObj, 0); 13930 13931 if ((res != -1) && (resObj != NULL)) { 13932 valuePush(ctxt, resObj); 13933 return(0); 13934 } 13935 if (resObj != NULL) 13936 xmlXPathReleaseObject(ctxt->context, resObj); 13937 } 13938 /* 13939 * QUESTION TODO: This falls back to normal XPath evaluation 13940 * if res == -1. Is this intended? 13941 */ 13942 } 13943 #endif 13944 comp = ctxt->comp; 13945 if (comp->last < 0) { 13946 xmlGenericError(xmlGenericErrorContext, 13947 "xmlXPathRunEval: last is less than zero\n"); 13948 return(-1); 13949 } 13950 if (toBool) 13951 return(xmlXPathCompOpEvalToBoolean(ctxt, 13952 &comp->steps[comp->last], 0)); 13953 else 13954 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]); 13955 13956 return(0); 13957 } 13958 13959 /************************************************************************ 13960 * * 13961 * Public interfaces * 13962 * * 13963 ************************************************************************/ 13964 13965 /** 13966 * xmlXPathEvalPredicate: 13967 * @ctxt: the XPath context 13968 * @res: the Predicate Expression evaluation result 13969 * 13970 * Evaluate a predicate result for the current node. 13971 * A PredicateExpr is evaluated by evaluating the Expr and converting 13972 * the result to a boolean. If the result is a number, the result will 13973 * be converted to true if the number is equal to the position of the 13974 * context node in the context node list (as returned by the position 13975 * function) and will be converted to false otherwise; if the result 13976 * is not a number, then the result will be converted as if by a call 13977 * to the boolean function. 13978 * 13979 * Returns 1 if predicate is true, 0 otherwise 13980 */ 13981 int 13982 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) { 13983 if ((ctxt == NULL) || (res == NULL)) return(0); 13984 switch (res->type) { 13985 case XPATH_BOOLEAN: 13986 return(res->boolval); 13987 case XPATH_NUMBER: 13988 return(res->floatval == ctxt->proximityPosition); 13989 case XPATH_NODESET: 13990 case XPATH_XSLT_TREE: 13991 if (res->nodesetval == NULL) 13992 return(0); 13993 return(res->nodesetval->nodeNr != 0); 13994 case XPATH_STRING: 13995 return((res->stringval != NULL) && 13996 (xmlStrlen(res->stringval) != 0)); 13997 default: 13998 STRANGE 13999 } 14000 return(0); 14001 } 14002 14003 /** 14004 * xmlXPathEvaluatePredicateResult: 14005 * @ctxt: the XPath Parser context 14006 * @res: the Predicate Expression evaluation result 14007 * 14008 * Evaluate a predicate result for the current node. 14009 * A PredicateExpr is evaluated by evaluating the Expr and converting 14010 * the result to a boolean. If the result is a number, the result will 14011 * be converted to true if the number is equal to the position of the 14012 * context node in the context node list (as returned by the position 14013 * function) and will be converted to false otherwise; if the result 14014 * is not a number, then the result will be converted as if by a call 14015 * to the boolean function. 14016 * 14017 * Returns 1 if predicate is true, 0 otherwise 14018 */ 14019 int 14020 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt, 14021 xmlXPathObjectPtr res) { 14022 if ((ctxt == NULL) || (res == NULL)) return(0); 14023 switch (res->type) { 14024 case XPATH_BOOLEAN: 14025 return(res->boolval); 14026 case XPATH_NUMBER: 14027 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200)) 14028 return((res->floatval == ctxt->context->proximityPosition) && 14029 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/ 14030 #else 14031 return(res->floatval == ctxt->context->proximityPosition); 14032 #endif 14033 case XPATH_NODESET: 14034 case XPATH_XSLT_TREE: 14035 if (res->nodesetval == NULL) 14036 return(0); 14037 return(res->nodesetval->nodeNr != 0); 14038 case XPATH_STRING: 14039 return((res->stringval != NULL) && (res->stringval[0] != 0)); 14040 #ifdef LIBXML_XPTR_ENABLED 14041 case XPATH_LOCATIONSET:{ 14042 xmlLocationSetPtr ptr = res->user; 14043 if (ptr == NULL) 14044 return(0); 14045 return (ptr->locNr != 0); 14046 } 14047 #endif 14048 default: 14049 STRANGE 14050 } 14051 return(0); 14052 } 14053 14054 #ifdef XPATH_STREAMING 14055 /** 14056 * xmlXPathTryStreamCompile: 14057 * @ctxt: an XPath context 14058 * @str: the XPath expression 14059 * 14060 * Try to compile the XPath expression as a streamable subset. 14061 * 14062 * Returns the compiled expression or NULL if failed to compile. 14063 */ 14064 static xmlXPathCompExprPtr 14065 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { 14066 /* 14067 * Optimization: use streaming patterns when the XPath expression can 14068 * be compiled to a stream lookup 14069 */ 14070 xmlPatternPtr stream; 14071 xmlXPathCompExprPtr comp; 14072 xmlDictPtr dict = NULL; 14073 const xmlChar **namespaces = NULL; 14074 xmlNsPtr ns; 14075 int i, j; 14076 14077 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) && 14078 (!xmlStrchr(str, '@'))) { 14079 const xmlChar *tmp; 14080 14081 /* 14082 * We don't try to handle expressions using the verbose axis 14083 * specifiers ("::"), just the simplified form at this point. 14084 * Additionally, if there is no list of namespaces available and 14085 * there's a ":" in the expression, indicating a prefixed QName, 14086 * then we won't try to compile either. xmlPatterncompile() needs 14087 * to have a list of namespaces at compilation time in order to 14088 * compile prefixed name tests. 14089 */ 14090 tmp = xmlStrchr(str, ':'); 14091 if ((tmp != NULL) && 14092 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':'))) 14093 return(NULL); 14094 14095 if (ctxt != NULL) { 14096 dict = ctxt->dict; 14097 if (ctxt->nsNr > 0) { 14098 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*)); 14099 if (namespaces == NULL) { 14100 xmlXPathErrMemory(ctxt, "allocating namespaces array\n"); 14101 return(NULL); 14102 } 14103 for (i = 0, j = 0; (j < ctxt->nsNr); j++) { 14104 ns = ctxt->namespaces[j]; 14105 namespaces[i++] = ns->href; 14106 namespaces[i++] = ns->prefix; 14107 } 14108 namespaces[i++] = NULL; 14109 namespaces[i] = NULL; 14110 } 14111 } 14112 14113 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces); 14114 if (namespaces != NULL) { 14115 xmlFree((xmlChar **)namespaces); 14116 } 14117 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) { 14118 comp = xmlXPathNewCompExpr(); 14119 if (comp == NULL) { 14120 xmlXPathErrMemory(ctxt, "allocating streamable expression\n"); 14121 return(NULL); 14122 } 14123 comp->stream = stream; 14124 comp->dict = dict; 14125 if (comp->dict) 14126 xmlDictReference(comp->dict); 14127 return(comp); 14128 } 14129 xmlFreePattern(stream); 14130 } 14131 return(NULL); 14132 } 14133 #endif /* XPATH_STREAMING */ 14134 14135 static void 14136 xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt, 14137 xmlXPathStepOpPtr op) 14138 { 14139 xmlXPathCompExprPtr comp = pctxt->comp; 14140 xmlXPathContextPtr ctxt; 14141 14142 /* 14143 * Try to rewrite "descendant-or-self::node()/foo" to an optimized 14144 * internal representation. 14145 */ 14146 14147 if ((op->op == XPATH_OP_COLLECT /* 11 */) && 14148 (op->ch1 != -1) && 14149 (op->ch2 == -1 /* no predicate */)) 14150 { 14151 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1]; 14152 14153 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) && 14154 ((xmlXPathAxisVal) prevop->value == 14155 AXIS_DESCENDANT_OR_SELF) && 14156 (prevop->ch2 == -1) && 14157 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) && 14158 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE)) 14159 { 14160 /* 14161 * This is a "descendant-or-self::node()" without predicates. 14162 * Try to eliminate it. 14163 */ 14164 14165 switch ((xmlXPathAxisVal) op->value) { 14166 case AXIS_CHILD: 14167 case AXIS_DESCENDANT: 14168 /* 14169 * Convert "descendant-or-self::node()/child::" or 14170 * "descendant-or-self::node()/descendant::" to 14171 * "descendant::" 14172 */ 14173 op->ch1 = prevop->ch1; 14174 op->value = AXIS_DESCENDANT; 14175 break; 14176 case AXIS_SELF: 14177 case AXIS_DESCENDANT_OR_SELF: 14178 /* 14179 * Convert "descendant-or-self::node()/self::" or 14180 * "descendant-or-self::node()/descendant-or-self::" to 14181 * to "descendant-or-self::" 14182 */ 14183 op->ch1 = prevop->ch1; 14184 op->value = AXIS_DESCENDANT_OR_SELF; 14185 break; 14186 default: 14187 break; 14188 } 14189 } 14190 } 14191 14192 /* OP_VALUE has invalid ch1. */ 14193 if (op->op == XPATH_OP_VALUE) 14194 return; 14195 14196 /* Recurse */ 14197 ctxt = pctxt->context; 14198 if (ctxt != NULL) { 14199 if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH) 14200 return; 14201 ctxt->depth += 1; 14202 } 14203 if (op->ch1 != -1) 14204 xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]); 14205 if (op->ch2 != -1) 14206 xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]); 14207 if (ctxt != NULL) 14208 ctxt->depth -= 1; 14209 } 14210 14211 /** 14212 * xmlXPathCtxtCompile: 14213 * @ctxt: an XPath context 14214 * @str: the XPath expression 14215 * 14216 * Compile an XPath expression 14217 * 14218 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL. 14219 * the caller has to free the object. 14220 */ 14221 xmlXPathCompExprPtr 14222 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { 14223 xmlXPathParserContextPtr pctxt; 14224 xmlXPathCompExprPtr comp; 14225 14226 #ifdef XPATH_STREAMING 14227 comp = xmlXPathTryStreamCompile(ctxt, str); 14228 if (comp != NULL) 14229 return(comp); 14230 #endif 14231 14232 xmlInitParser(); 14233 14234 pctxt = xmlXPathNewParserContext(str, ctxt); 14235 if (pctxt == NULL) 14236 return NULL; 14237 if (ctxt != NULL) 14238 ctxt->depth = 0; 14239 xmlXPathCompileExpr(pctxt, 1); 14240 14241 if( pctxt->error != XPATH_EXPRESSION_OK ) 14242 { 14243 xmlXPathFreeParserContext(pctxt); 14244 return(NULL); 14245 } 14246 14247 if (*pctxt->cur != 0) { 14248 /* 14249 * aleksey: in some cases this line prints *second* error message 14250 * (see bug #78858) and probably this should be fixed. 14251 * However, we are not sure that all error messages are printed 14252 * out in other places. It's not critical so we leave it as-is for now 14253 */ 14254 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR); 14255 comp = NULL; 14256 } else { 14257 comp = pctxt->comp; 14258 if ((comp->nbStep > 1) && (comp->last >= 0)) { 14259 if (ctxt != NULL) 14260 ctxt->depth = 0; 14261 xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]); 14262 } 14263 pctxt->comp = NULL; 14264 } 14265 xmlXPathFreeParserContext(pctxt); 14266 14267 if (comp != NULL) { 14268 comp->expr = xmlStrdup(str); 14269 #ifdef DEBUG_EVAL_COUNTS 14270 comp->string = xmlStrdup(str); 14271 comp->nb = 0; 14272 #endif 14273 } 14274 return(comp); 14275 } 14276 14277 /** 14278 * xmlXPathCompile: 14279 * @str: the XPath expression 14280 * 14281 * Compile an XPath expression 14282 * 14283 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL. 14284 * the caller has to free the object. 14285 */ 14286 xmlXPathCompExprPtr 14287 xmlXPathCompile(const xmlChar *str) { 14288 return(xmlXPathCtxtCompile(NULL, str)); 14289 } 14290 14291 /** 14292 * xmlXPathCompiledEvalInternal: 14293 * @comp: the compiled XPath expression 14294 * @ctxt: the XPath context 14295 * @resObj: the resulting XPath object or NULL 14296 * @toBool: 1 if only a boolean result is requested 14297 * 14298 * Evaluate the Precompiled XPath expression in the given context. 14299 * The caller has to free @resObj. 14300 * 14301 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14302 * the caller has to free the object. 14303 */ 14304 static int 14305 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp, 14306 xmlXPathContextPtr ctxt, 14307 xmlXPathObjectPtr *resObjPtr, 14308 int toBool) 14309 { 14310 xmlXPathParserContextPtr pctxt; 14311 xmlXPathObjectPtr resObj; 14312 #ifndef LIBXML_THREAD_ENABLED 14313 static int reentance = 0; 14314 #endif 14315 int res; 14316 14317 CHECK_CTXT_NEG(ctxt) 14318 14319 if (comp == NULL) 14320 return(-1); 14321 xmlInitParser(); 14322 14323 #ifndef LIBXML_THREAD_ENABLED 14324 reentance++; 14325 if (reentance > 1) 14326 xmlXPathDisableOptimizer = 1; 14327 #endif 14328 14329 #ifdef DEBUG_EVAL_COUNTS 14330 comp->nb++; 14331 if ((comp->string != NULL) && (comp->nb > 100)) { 14332 fprintf(stderr, "100 x %s\n", comp->string); 14333 comp->nb = 0; 14334 } 14335 #endif 14336 pctxt = xmlXPathCompParserContext(comp, ctxt); 14337 res = xmlXPathRunEval(pctxt, toBool); 14338 14339 if (pctxt->error != XPATH_EXPRESSION_OK) { 14340 resObj = NULL; 14341 } else { 14342 resObj = valuePop(pctxt); 14343 if (resObj == NULL) { 14344 if (!toBool) 14345 xmlGenericError(xmlGenericErrorContext, 14346 "xmlXPathCompiledEval: No result on the stack.\n"); 14347 } else if (pctxt->valueNr > 0) { 14348 xmlGenericError(xmlGenericErrorContext, 14349 "xmlXPathCompiledEval: %d object(s) left on the stack.\n", 14350 pctxt->valueNr); 14351 } 14352 } 14353 14354 if (resObjPtr) 14355 *resObjPtr = resObj; 14356 else 14357 xmlXPathReleaseObject(ctxt, resObj); 14358 14359 pctxt->comp = NULL; 14360 xmlXPathFreeParserContext(pctxt); 14361 #ifndef LIBXML_THREAD_ENABLED 14362 reentance--; 14363 #endif 14364 14365 return(res); 14366 } 14367 14368 /** 14369 * xmlXPathCompiledEval: 14370 * @comp: the compiled XPath expression 14371 * @ctx: the XPath context 14372 * 14373 * Evaluate the Precompiled XPath expression in the given context. 14374 * 14375 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14376 * the caller has to free the object. 14377 */ 14378 xmlXPathObjectPtr 14379 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) 14380 { 14381 xmlXPathObjectPtr res = NULL; 14382 14383 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0); 14384 return(res); 14385 } 14386 14387 /** 14388 * xmlXPathCompiledEvalToBoolean: 14389 * @comp: the compiled XPath expression 14390 * @ctxt: the XPath context 14391 * 14392 * Applies the XPath boolean() function on the result of the given 14393 * compiled expression. 14394 * 14395 * Returns 1 if the expression evaluated to true, 0 if to false and 14396 * -1 in API and internal errors. 14397 */ 14398 int 14399 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp, 14400 xmlXPathContextPtr ctxt) 14401 { 14402 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1)); 14403 } 14404 14405 /** 14406 * xmlXPathEvalExpr: 14407 * @ctxt: the XPath Parser context 14408 * 14409 * Parse and evaluate an XPath expression in the given context, 14410 * then push the result on the context stack 14411 */ 14412 void 14413 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) { 14414 #ifdef XPATH_STREAMING 14415 xmlXPathCompExprPtr comp; 14416 #endif 14417 14418 if (ctxt == NULL) return; 14419 14420 #ifdef XPATH_STREAMING 14421 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base); 14422 if (comp != NULL) { 14423 if (ctxt->comp != NULL) 14424 xmlXPathFreeCompExpr(ctxt->comp); 14425 ctxt->comp = comp; 14426 } else 14427 #endif 14428 { 14429 if (ctxt->context != NULL) 14430 ctxt->context->depth = 0; 14431 xmlXPathCompileExpr(ctxt, 1); 14432 CHECK_ERROR; 14433 14434 /* Check for trailing characters. */ 14435 if (*ctxt->cur != 0) 14436 XP_ERROR(XPATH_EXPR_ERROR); 14437 14438 if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) { 14439 if (ctxt->context != NULL) 14440 ctxt->context->depth = 0; 14441 xmlXPathOptimizeExpression(ctxt, 14442 &ctxt->comp->steps[ctxt->comp->last]); 14443 } 14444 } 14445 14446 xmlXPathRunEval(ctxt, 0); 14447 } 14448 14449 /** 14450 * xmlXPathEval: 14451 * @str: the XPath expression 14452 * @ctx: the XPath context 14453 * 14454 * Evaluate the XPath Location Path in the given context. 14455 * 14456 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14457 * the caller has to free the object. 14458 */ 14459 xmlXPathObjectPtr 14460 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) { 14461 xmlXPathParserContextPtr ctxt; 14462 xmlXPathObjectPtr res; 14463 14464 CHECK_CTXT(ctx) 14465 14466 xmlInitParser(); 14467 14468 ctxt = xmlXPathNewParserContext(str, ctx); 14469 if (ctxt == NULL) 14470 return NULL; 14471 xmlXPathEvalExpr(ctxt); 14472 14473 if (ctxt->error != XPATH_EXPRESSION_OK) { 14474 res = NULL; 14475 } else { 14476 res = valuePop(ctxt); 14477 if (res == NULL) { 14478 xmlGenericError(xmlGenericErrorContext, 14479 "xmlXPathCompiledEval: No result on the stack.\n"); 14480 } else if (ctxt->valueNr > 0) { 14481 xmlGenericError(xmlGenericErrorContext, 14482 "xmlXPathCompiledEval: %d object(s) left on the stack.\n", 14483 ctxt->valueNr); 14484 } 14485 } 14486 14487 xmlXPathFreeParserContext(ctxt); 14488 return(res); 14489 } 14490 14491 /** 14492 * xmlXPathSetContextNode: 14493 * @node: the node to to use as the context node 14494 * @ctx: the XPath context 14495 * 14496 * Sets 'node' as the context node. The node must be in the same 14497 * document as that associated with the context. 14498 * 14499 * Returns -1 in case of error or 0 if successful 14500 */ 14501 int 14502 xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) { 14503 if ((node == NULL) || (ctx == NULL)) 14504 return(-1); 14505 14506 if (node->doc == ctx->doc) { 14507 ctx->node = node; 14508 return(0); 14509 } 14510 return(-1); 14511 } 14512 14513 /** 14514 * xmlXPathNodeEval: 14515 * @node: the node to to use as the context node 14516 * @str: the XPath expression 14517 * @ctx: the XPath context 14518 * 14519 * Evaluate the XPath Location Path in the given context. The node 'node' 14520 * is set as the context node. The context node is not restored. 14521 * 14522 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14523 * the caller has to free the object. 14524 */ 14525 xmlXPathObjectPtr 14526 xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) { 14527 if (str == NULL) 14528 return(NULL); 14529 if (xmlXPathSetContextNode(node, ctx) < 0) 14530 return(NULL); 14531 return(xmlXPathEval(str, ctx)); 14532 } 14533 14534 /** 14535 * xmlXPathEvalExpression: 14536 * @str: the XPath expression 14537 * @ctxt: the XPath context 14538 * 14539 * Alias for xmlXPathEval(). 14540 * 14541 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14542 * the caller has to free the object. 14543 */ 14544 xmlXPathObjectPtr 14545 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) { 14546 return(xmlXPathEval(str, ctxt)); 14547 } 14548 14549 /************************************************************************ 14550 * * 14551 * Extra functions not pertaining to the XPath spec * 14552 * * 14553 ************************************************************************/ 14554 /** 14555 * xmlXPathEscapeUriFunction: 14556 * @ctxt: the XPath Parser context 14557 * @nargs: the number of arguments 14558 * 14559 * Implement the escape-uri() XPath function 14560 * string escape-uri(string $str, bool $escape-reserved) 14561 * 14562 * This function applies the URI escaping rules defined in section 2 of [RFC 14563 * 2396] to the string supplied as $uri-part, which typically represents all 14564 * or part of a URI. The effect of the function is to replace any special 14565 * character in the string by an escape sequence of the form %xx%yy..., 14566 * where xxyy... is the hexadecimal representation of the octets used to 14567 * represent the character in UTF-8. 14568 * 14569 * The set of characters that are escaped depends on the setting of the 14570 * boolean argument $escape-reserved. 14571 * 14572 * If $escape-reserved is true, all characters are escaped other than lower 14573 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters 14574 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!" 14575 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only 14576 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and 14577 * A-F). 14578 * 14579 * If $escape-reserved is false, the behavior differs in that characters 14580 * referred to in [RFC 2396] as reserved characters are not escaped. These 14581 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",". 14582 * 14583 * [RFC 2396] does not define whether escaped URIs should use lower case or 14584 * upper case for hexadecimal digits. To ensure that escaped URIs can be 14585 * compared using string comparison functions, this function must always use 14586 * the upper-case letters A-F. 14587 * 14588 * Generally, $escape-reserved should be set to true when escaping a string 14589 * that is to form a single part of a URI, and to false when escaping an 14590 * entire URI or URI reference. 14591 * 14592 * In the case of non-ascii characters, the string is encoded according to 14593 * utf-8 and then converted according to RFC 2396. 14594 * 14595 * Examples 14596 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true()) 14597 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean" 14598 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false()) 14599 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean" 14600 * 14601 */ 14602 static void 14603 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) { 14604 xmlXPathObjectPtr str; 14605 int escape_reserved; 14606 xmlBufPtr target; 14607 xmlChar *cptr; 14608 xmlChar escape[4]; 14609 14610 CHECK_ARITY(2); 14611 14612 escape_reserved = xmlXPathPopBoolean(ctxt); 14613 14614 CAST_TO_STRING; 14615 str = valuePop(ctxt); 14616 14617 target = xmlBufCreate(); 14618 14619 escape[0] = '%'; 14620 escape[3] = 0; 14621 14622 if (target) { 14623 for (cptr = str->stringval; *cptr; cptr++) { 14624 if ((*cptr >= 'A' && *cptr <= 'Z') || 14625 (*cptr >= 'a' && *cptr <= 'z') || 14626 (*cptr >= '0' && *cptr <= '9') || 14627 *cptr == '-' || *cptr == '_' || *cptr == '.' || 14628 *cptr == '!' || *cptr == '~' || *cptr == '*' || 14629 *cptr == '\''|| *cptr == '(' || *cptr == ')' || 14630 (*cptr == '%' && 14631 ((cptr[1] >= 'A' && cptr[1] <= 'F') || 14632 (cptr[1] >= 'a' && cptr[1] <= 'f') || 14633 (cptr[1] >= '0' && cptr[1] <= '9')) && 14634 ((cptr[2] >= 'A' && cptr[2] <= 'F') || 14635 (cptr[2] >= 'a' && cptr[2] <= 'f') || 14636 (cptr[2] >= '0' && cptr[2] <= '9'))) || 14637 (!escape_reserved && 14638 (*cptr == ';' || *cptr == '/' || *cptr == '?' || 14639 *cptr == ':' || *cptr == '@' || *cptr == '&' || 14640 *cptr == '=' || *cptr == '+' || *cptr == '$' || 14641 *cptr == ','))) { 14642 xmlBufAdd(target, cptr, 1); 14643 } else { 14644 if ((*cptr >> 4) < 10) 14645 escape[1] = '0' + (*cptr >> 4); 14646 else 14647 escape[1] = 'A' - 10 + (*cptr >> 4); 14648 if ((*cptr & 0xF) < 10) 14649 escape[2] = '0' + (*cptr & 0xF); 14650 else 14651 escape[2] = 'A' - 10 + (*cptr & 0xF); 14652 14653 xmlBufAdd(target, &escape[0], 3); 14654 } 14655 } 14656 } 14657 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 14658 xmlBufContent(target))); 14659 xmlBufFree(target); 14660 xmlXPathReleaseObject(ctxt->context, str); 14661 } 14662 14663 /** 14664 * xmlXPathRegisterAllFunctions: 14665 * @ctxt: the XPath context 14666 * 14667 * Registers all default XPath functions in this context 14668 */ 14669 void 14670 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt) 14671 { 14672 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean", 14673 xmlXPathBooleanFunction); 14674 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling", 14675 xmlXPathCeilingFunction); 14676 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count", 14677 xmlXPathCountFunction); 14678 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat", 14679 xmlXPathConcatFunction); 14680 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains", 14681 xmlXPathContainsFunction); 14682 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id", 14683 xmlXPathIdFunction); 14684 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false", 14685 xmlXPathFalseFunction); 14686 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor", 14687 xmlXPathFloorFunction); 14688 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last", 14689 xmlXPathLastFunction); 14690 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang", 14691 xmlXPathLangFunction); 14692 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name", 14693 xmlXPathLocalNameFunction); 14694 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not", 14695 xmlXPathNotFunction); 14696 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name", 14697 xmlXPathNameFunction); 14698 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri", 14699 xmlXPathNamespaceURIFunction); 14700 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space", 14701 xmlXPathNormalizeFunction); 14702 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number", 14703 xmlXPathNumberFunction); 14704 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position", 14705 xmlXPathPositionFunction); 14706 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round", 14707 xmlXPathRoundFunction); 14708 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string", 14709 xmlXPathStringFunction); 14710 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length", 14711 xmlXPathStringLengthFunction); 14712 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with", 14713 xmlXPathStartsWithFunction); 14714 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring", 14715 xmlXPathSubstringFunction); 14716 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before", 14717 xmlXPathSubstringBeforeFunction); 14718 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after", 14719 xmlXPathSubstringAfterFunction); 14720 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum", 14721 xmlXPathSumFunction); 14722 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true", 14723 xmlXPathTrueFunction); 14724 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate", 14725 xmlXPathTranslateFunction); 14726 14727 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri", 14728 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions", 14729 xmlXPathEscapeUriFunction); 14730 } 14731 14732 #endif /* LIBXML_XPATH_ENABLED */ 14733 #define bottom_xpath 14734 #include "elfgcchack.h" 14735