1 /* 2 * xpath.c: XML Path Language implementation 3 * XPath is a language for addressing parts of an XML document, 4 * designed to be used by both XSLT and XPointer 5 *f 6 * Reference: W3C Recommendation 16 November 1999 7 * http://www.w3.org/TR/1999/REC-xpath-19991116 8 * Public reference: 9 * http://www.w3.org/TR/xpath 10 * 11 * See Copyright for the status of this software 12 * 13 * Author: daniel (at) veillard.com 14 * 15 */ 16 17 /* To avoid EBCDIC trouble when parsing on zOS */ 18 #if defined(__MVS__) 19 #pragma convert("ISO8859-1") 20 #endif 21 22 #define IN_LIBXML 23 #include "libxml.h" 24 25 #include <limits.h> 26 #include <string.h> 27 #include <stddef.h> 28 29 #ifdef HAVE_SYS_TYPES_H 30 #include <sys/types.h> 31 #endif 32 #ifdef HAVE_MATH_H 33 #include <math.h> 34 #endif 35 #ifdef HAVE_FLOAT_H 36 #include <float.h> 37 #endif 38 #ifdef HAVE_CTYPE_H 39 #include <ctype.h> 40 #endif 41 #ifdef HAVE_SIGNAL_H 42 #include <signal.h> 43 #endif 44 45 #include <libxml/xmlmemory.h> 46 #include <libxml/tree.h> 47 #include <libxml/valid.h> 48 #include <libxml/xpath.h> 49 #include <libxml/xpathInternals.h> 50 #include <libxml/parserInternals.h> 51 #include <libxml/hash.h> 52 #ifdef LIBXML_XPTR_ENABLED 53 #include <libxml/xpointer.h> 54 #endif 55 #ifdef LIBXML_DEBUG_ENABLED 56 #include <libxml/debugXML.h> 57 #endif 58 #include <libxml/xmlerror.h> 59 #include <libxml/threads.h> 60 #include <libxml/globals.h> 61 #ifdef LIBXML_PATTERN_ENABLED 62 #include <libxml/pattern.h> 63 #endif 64 65 #include "buf.h" 66 67 #ifdef LIBXML_PATTERN_ENABLED 68 #define XPATH_STREAMING 69 #endif 70 71 #define TODO \ 72 xmlGenericError(xmlGenericErrorContext, \ 73 "Unimplemented block at %s:%d\n", \ 74 __FILE__, __LINE__); 75 76 /** 77 * WITH_TIM_SORT: 78 * 79 * Use the Timsort algorithm provided in timsort.h to sort 80 * nodeset as this is a great improvement over the old Shell sort 81 * used in xmlXPathNodeSetSort() 82 */ 83 #define WITH_TIM_SORT 84 85 /* 86 * XP_OPTIMIZED_NON_ELEM_COMPARISON: 87 * If defined, this will use xmlXPathCmpNodesExt() instead of 88 * xmlXPathCmpNodes(). The new function is optimized comparison of 89 * non-element nodes; actually it will speed up comparison only if 90 * xmlXPathOrderDocElems() was called in order to index the elements of 91 * a tree in document order; Libxslt does such an indexing, thus it will 92 * benefit from this optimization. 93 */ 94 #define XP_OPTIMIZED_NON_ELEM_COMPARISON 95 96 /* 97 * XP_OPTIMIZED_FILTER_FIRST: 98 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]" 99 * in a way, that it stop evaluation at the first node. 100 */ 101 #define XP_OPTIMIZED_FILTER_FIRST 102 103 /* 104 * XP_DEBUG_OBJ_USAGE: 105 * Internal flag to enable tracking of how much XPath objects have been 106 * created. 107 */ 108 /* #define XP_DEBUG_OBJ_USAGE */ 109 110 /* 111 * XPATH_MAX_STEPS: 112 * when compiling an XPath expression we arbitrary limit the maximum 113 * number of step operation in the compiled expression. 1000000 is 114 * an insanely large value which should never be reached under normal 115 * circumstances 116 */ 117 #define XPATH_MAX_STEPS 1000000 118 119 /* 120 * XPATH_MAX_STACK_DEPTH: 121 * when evaluating an XPath expression we arbitrary limit the maximum 122 * number of object allowed to be pushed on the stack. 1000000 is 123 * an insanely large value which should never be reached under normal 124 * circumstances 125 */ 126 #define XPATH_MAX_STACK_DEPTH 1000000 127 128 /* 129 * XPATH_MAX_NODESET_LENGTH: 130 * when evaluating an XPath expression nodesets are created and we 131 * arbitrary limit the maximum length of those node set. 10000000 is 132 * an insanely large value which should never be reached under normal 133 * circumstances, one would first need to construct an in memory tree 134 * with more than 10 millions nodes. 135 */ 136 #define XPATH_MAX_NODESET_LENGTH 10000000 137 138 /* 139 * TODO: 140 * There are a few spots where some tests are done which depend upon ascii 141 * data. These should be enhanced for full UTF8 support (see particularly 142 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT) 143 */ 144 145 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 146 /** 147 * xmlXPathCmpNodesExt: 148 * @node1: the first node 149 * @node2: the second node 150 * 151 * Compare two nodes w.r.t document order. 152 * This one is optimized for handling of non-element nodes. 153 * 154 * Returns -2 in case of error 1 if first point < second point, 0 if 155 * it's the same node, -1 otherwise 156 */ 157 static int 158 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) { 159 int depth1, depth2; 160 int misc = 0, precedence1 = 0, precedence2 = 0; 161 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL; 162 xmlNodePtr cur, root; 163 ptrdiff_t l1, l2; 164 165 if ((node1 == NULL) || (node2 == NULL)) 166 return(-2); 167 168 if (node1 == node2) 169 return(0); 170 171 /* 172 * a couple of optimizations which will avoid computations in most cases 173 */ 174 switch (node1->type) { 175 case XML_ELEMENT_NODE: 176 if (node2->type == XML_ELEMENT_NODE) { 177 if ((0 > (ptrdiff_t) node1->content) && 178 (0 > (ptrdiff_t) node2->content) && 179 (node1->doc == node2->doc)) 180 { 181 l1 = -((ptrdiff_t) node1->content); 182 l2 = -((ptrdiff_t) node2->content); 183 if (l1 < l2) 184 return(1); 185 if (l1 > l2) 186 return(-1); 187 } else 188 goto turtle_comparison; 189 } 190 break; 191 case XML_ATTRIBUTE_NODE: 192 precedence1 = 1; /* element is owner */ 193 miscNode1 = node1; 194 node1 = node1->parent; 195 misc = 1; 196 break; 197 case XML_TEXT_NODE: 198 case XML_CDATA_SECTION_NODE: 199 case XML_COMMENT_NODE: 200 case XML_PI_NODE: { 201 miscNode1 = node1; 202 /* 203 * Find nearest element node. 204 */ 205 if (node1->prev != NULL) { 206 do { 207 node1 = node1->prev; 208 if (node1->type == XML_ELEMENT_NODE) { 209 precedence1 = 3; /* element in prev-sibl axis */ 210 break; 211 } 212 if (node1->prev == NULL) { 213 precedence1 = 2; /* element is parent */ 214 /* 215 * URGENT TODO: Are there any cases, where the 216 * parent of such a node is not an element node? 217 */ 218 node1 = node1->parent; 219 break; 220 } 221 } while (1); 222 } else { 223 precedence1 = 2; /* element is parent */ 224 node1 = node1->parent; 225 } 226 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) || 227 (0 <= (ptrdiff_t) node1->content)) { 228 /* 229 * Fallback for whatever case. 230 */ 231 node1 = miscNode1; 232 precedence1 = 0; 233 } else 234 misc = 1; 235 } 236 break; 237 case XML_NAMESPACE_DECL: 238 /* 239 * TODO: why do we return 1 for namespace nodes? 240 */ 241 return(1); 242 default: 243 break; 244 } 245 switch (node2->type) { 246 case XML_ELEMENT_NODE: 247 break; 248 case XML_ATTRIBUTE_NODE: 249 precedence2 = 1; /* element is owner */ 250 miscNode2 = node2; 251 node2 = node2->parent; 252 misc = 1; 253 break; 254 case XML_TEXT_NODE: 255 case XML_CDATA_SECTION_NODE: 256 case XML_COMMENT_NODE: 257 case XML_PI_NODE: { 258 miscNode2 = node2; 259 if (node2->prev != NULL) { 260 do { 261 node2 = node2->prev; 262 if (node2->type == XML_ELEMENT_NODE) { 263 precedence2 = 3; /* element in prev-sibl axis */ 264 break; 265 } 266 if (node2->prev == NULL) { 267 precedence2 = 2; /* element is parent */ 268 node2 = node2->parent; 269 break; 270 } 271 } while (1); 272 } else { 273 precedence2 = 2; /* element is parent */ 274 node2 = node2->parent; 275 } 276 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) || 277 (0 <= (ptrdiff_t) node2->content)) 278 { 279 node2 = miscNode2; 280 precedence2 = 0; 281 } else 282 misc = 1; 283 } 284 break; 285 case XML_NAMESPACE_DECL: 286 return(1); 287 default: 288 break; 289 } 290 if (misc) { 291 if (node1 == node2) { 292 if (precedence1 == precedence2) { 293 /* 294 * The ugly case; but normally there aren't many 295 * adjacent non-element nodes around. 296 */ 297 cur = miscNode2->prev; 298 while (cur != NULL) { 299 if (cur == miscNode1) 300 return(1); 301 if (cur->type == XML_ELEMENT_NODE) 302 return(-1); 303 cur = cur->prev; 304 } 305 return (-1); 306 } else { 307 /* 308 * Evaluate based on higher precedence wrt to the element. 309 * TODO: This assumes attributes are sorted before content. 310 * Is this 100% correct? 311 */ 312 if (precedence1 < precedence2) 313 return(1); 314 else 315 return(-1); 316 } 317 } 318 /* 319 * Special case: One of the helper-elements is contained by the other. 320 * <foo> 321 * <node2> 322 * <node1>Text-1(precedence1 == 2)</node1> 323 * </node2> 324 * Text-6(precedence2 == 3) 325 * </foo> 326 */ 327 if ((precedence2 == 3) && (precedence1 > 1)) { 328 cur = node1->parent; 329 while (cur) { 330 if (cur == node2) 331 return(1); 332 cur = cur->parent; 333 } 334 } 335 if ((precedence1 == 3) && (precedence2 > 1)) { 336 cur = node2->parent; 337 while (cur) { 338 if (cur == node1) 339 return(-1); 340 cur = cur->parent; 341 } 342 } 343 } 344 345 /* 346 * Speedup using document order if availble. 347 */ 348 if ((node1->type == XML_ELEMENT_NODE) && 349 (node2->type == XML_ELEMENT_NODE) && 350 (0 > (ptrdiff_t) node1->content) && 351 (0 > (ptrdiff_t) node2->content) && 352 (node1->doc == node2->doc)) { 353 354 l1 = -((ptrdiff_t) node1->content); 355 l2 = -((ptrdiff_t) node2->content); 356 if (l1 < l2) 357 return(1); 358 if (l1 > l2) 359 return(-1); 360 } 361 362 turtle_comparison: 363 364 if (node1 == node2->prev) 365 return(1); 366 if (node1 == node2->next) 367 return(-1); 368 /* 369 * compute depth to root 370 */ 371 for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) { 372 if (cur->parent == node1) 373 return(1); 374 depth2++; 375 } 376 root = cur; 377 for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) { 378 if (cur->parent == node2) 379 return(-1); 380 depth1++; 381 } 382 /* 383 * Distinct document (or distinct entities :-( ) case. 384 */ 385 if (root != cur) { 386 return(-2); 387 } 388 /* 389 * get the nearest common ancestor. 390 */ 391 while (depth1 > depth2) { 392 depth1--; 393 node1 = node1->parent; 394 } 395 while (depth2 > depth1) { 396 depth2--; 397 node2 = node2->parent; 398 } 399 while (node1->parent != node2->parent) { 400 node1 = node1->parent; 401 node2 = node2->parent; 402 /* should not happen but just in case ... */ 403 if ((node1 == NULL) || (node2 == NULL)) 404 return(-2); 405 } 406 /* 407 * Find who's first. 408 */ 409 if (node1 == node2->prev) 410 return(1); 411 if (node1 == node2->next) 412 return(-1); 413 /* 414 * Speedup using document order if availble. 415 */ 416 if ((node1->type == XML_ELEMENT_NODE) && 417 (node2->type == XML_ELEMENT_NODE) && 418 (0 > (ptrdiff_t) node1->content) && 419 (0 > (ptrdiff_t) node2->content) && 420 (node1->doc == node2->doc)) { 421 422 l1 = -((ptrdiff_t) node1->content); 423 l2 = -((ptrdiff_t) node2->content); 424 if (l1 < l2) 425 return(1); 426 if (l1 > l2) 427 return(-1); 428 } 429 430 for (cur = node1->next;cur != NULL;cur = cur->next) 431 if (cur == node2) 432 return(1); 433 return(-1); /* assume there is no sibling list corruption */ 434 } 435 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */ 436 437 /* 438 * Wrapper for the Timsort argorithm from timsort.h 439 */ 440 #ifdef WITH_TIM_SORT 441 #define SORT_NAME libxml_domnode 442 #define SORT_TYPE xmlNodePtr 443 /** 444 * wrap_cmp: 445 * @x: a node 446 * @y: another node 447 * 448 * Comparison function for the Timsort implementation 449 * 450 * Returns -2 in case of error -1 if first point < second point, 0 if 451 * it's the same node, +1 otherwise 452 */ 453 static 454 int wrap_cmp( xmlNodePtr x, xmlNodePtr y ); 455 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 456 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y ) 457 { 458 int res = xmlXPathCmpNodesExt(x, y); 459 return res == -2 ? res : -res; 460 } 461 #else 462 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y ) 463 { 464 int res = xmlXPathCmpNodes(x, y); 465 return res == -2 ? res : -res; 466 } 467 #endif 468 #define SORT_CMP(x, y) (wrap_cmp(x, y)) 469 #include "timsort.h" 470 #endif /* WITH_TIM_SORT */ 471 472 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) 473 474 /************************************************************************ 475 * * 476 * Floating point stuff * 477 * * 478 ************************************************************************/ 479 480 #ifndef NAN 481 #define NAN (0.0 / 0.0) 482 #endif 483 484 #ifndef INFINITY 485 #define INFINITY HUGE_VAL 486 #endif 487 488 double xmlXPathNAN = NAN; 489 double xmlXPathPINF = INFINITY; 490 double xmlXPathNINF = -INFINITY; 491 492 /** 493 * xmlXPathInit: 494 * 495 * Initialize the XPath environment 496 * 497 * Does nothing but must be kept as public function. 498 */ 499 void 500 xmlXPathInit(void) { 501 } 502 503 /** 504 * xmlXPathIsNaN: 505 * @val: a double value 506 * 507 * Returns 1 if the value is a NaN, 0 otherwise 508 */ 509 int 510 xmlXPathIsNaN(double val) { 511 #ifdef isnan 512 return isnan(val); 513 #else 514 return !(val == val); 515 #endif 516 } 517 518 /** 519 * xmlXPathIsInf: 520 * @val: a double value 521 * 522 * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise 523 */ 524 int 525 xmlXPathIsInf(double val) { 526 #ifdef isinf 527 return isinf(val) ? (val > 0 ? 1 : -1) : 0; 528 #else 529 if (val >= HUGE_VAL) 530 return 1; 531 if (val <= -HUGE_VAL) 532 return -1; 533 return 0; 534 #endif 535 } 536 537 #endif /* SCHEMAS or XPATH */ 538 539 #ifdef LIBXML_XPATH_ENABLED 540 541 /* 542 * TODO: when compatibility allows remove all "fake node libxslt" strings 543 * the test should just be name[0] = ' ' 544 */ 545 #ifdef DEBUG_XPATH_EXPRESSION 546 #define DEBUG_STEP 547 #define DEBUG_EXPR 548 #define DEBUG_EVAL_COUNTS 549 #endif 550 551 static xmlNs xmlXPathXMLNamespaceStruct = { 552 NULL, 553 XML_NAMESPACE_DECL, 554 XML_XML_NAMESPACE, 555 BAD_CAST "xml", 556 NULL, 557 NULL 558 }; 559 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct; 560 #ifndef LIBXML_THREAD_ENABLED 561 /* 562 * Optimizer is disabled only when threaded apps are detected while 563 * the library ain't compiled for thread safety. 564 */ 565 static int xmlXPathDisableOptimizer = 0; 566 #endif 567 568 /************************************************************************ 569 * * 570 * Error handling routines * 571 * * 572 ************************************************************************/ 573 574 /** 575 * XP_ERRORNULL: 576 * @X: the error code 577 * 578 * Macro to raise an XPath error and return NULL. 579 */ 580 #define XP_ERRORNULL(X) \ 581 { xmlXPathErr(ctxt, X); return(NULL); } 582 583 /* 584 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError 585 */ 586 static const char *xmlXPathErrorMessages[] = { 587 "Ok\n", 588 "Number encoding\n", 589 "Unfinished literal\n", 590 "Start of literal\n", 591 "Expected $ for variable reference\n", 592 "Undefined variable\n", 593 "Invalid predicate\n", 594 "Invalid expression\n", 595 "Missing closing curly brace\n", 596 "Unregistered function\n", 597 "Invalid operand\n", 598 "Invalid type\n", 599 "Invalid number of arguments\n", 600 "Invalid context size\n", 601 "Invalid context position\n", 602 "Memory allocation error\n", 603 "Syntax error\n", 604 "Resource error\n", 605 "Sub resource error\n", 606 "Undefined namespace prefix\n", 607 "Encoding error\n", 608 "Char out of XML range\n", 609 "Invalid or incomplete context\n", 610 "Stack usage error\n", 611 "Forbidden variable\n", 612 "?? Unknown error ??\n" /* Must be last in the list! */ 613 }; 614 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \ 615 sizeof(xmlXPathErrorMessages[0])) - 1) 616 /** 617 * xmlXPathErrMemory: 618 * @ctxt: an XPath context 619 * @extra: extra informations 620 * 621 * Handle a redefinition of attribute error 622 */ 623 static void 624 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra) 625 { 626 if (ctxt != NULL) { 627 if (extra) { 628 xmlChar buf[200]; 629 630 xmlStrPrintf(buf, 200, 631 "Memory allocation failed : %s\n", 632 extra); 633 ctxt->lastError.message = (char *) xmlStrdup(buf); 634 } else { 635 ctxt->lastError.message = (char *) 636 xmlStrdup(BAD_CAST "Memory allocation failed\n"); 637 } 638 ctxt->lastError.domain = XML_FROM_XPATH; 639 ctxt->lastError.code = XML_ERR_NO_MEMORY; 640 if (ctxt->error != NULL) 641 ctxt->error(ctxt->userData, &ctxt->lastError); 642 } else { 643 if (extra) 644 __xmlRaiseError(NULL, NULL, NULL, 645 NULL, NULL, XML_FROM_XPATH, 646 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, 647 extra, NULL, NULL, 0, 0, 648 "Memory allocation failed : %s\n", extra); 649 else 650 __xmlRaiseError(NULL, NULL, NULL, 651 NULL, NULL, XML_FROM_XPATH, 652 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, 653 NULL, NULL, NULL, 0, 0, 654 "Memory allocation failed\n"); 655 } 656 } 657 658 /** 659 * xmlXPathPErrMemory: 660 * @ctxt: an XPath parser context 661 * @extra: extra informations 662 * 663 * Handle a redefinition of attribute error 664 */ 665 static void 666 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra) 667 { 668 if (ctxt == NULL) 669 xmlXPathErrMemory(NULL, extra); 670 else { 671 ctxt->error = XPATH_MEMORY_ERROR; 672 xmlXPathErrMemory(ctxt->context, extra); 673 } 674 } 675 676 /** 677 * xmlXPathErr: 678 * @ctxt: a XPath parser context 679 * @error: the error code 680 * 681 * Handle an XPath error 682 */ 683 void 684 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error) 685 { 686 if ((error < 0) || (error > MAXERRNO)) 687 error = MAXERRNO; 688 if (ctxt == NULL) { 689 __xmlRaiseError(NULL, NULL, NULL, 690 NULL, NULL, XML_FROM_XPATH, 691 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, 692 XML_ERR_ERROR, NULL, 0, 693 NULL, NULL, NULL, 0, 0, 694 "%s", xmlXPathErrorMessages[error]); 695 return; 696 } 697 ctxt->error = error; 698 if (ctxt->context == 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 (const char *) ctxt->base, NULL, NULL, 704 ctxt->cur - ctxt->base, 0, 705 "%s", xmlXPathErrorMessages[error]); 706 return; 707 } 708 709 /* cleanup current last error */ 710 xmlResetError(&ctxt->context->lastError); 711 712 ctxt->context->lastError.domain = XML_FROM_XPATH; 713 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK - 714 XPATH_EXPRESSION_OK; 715 ctxt->context->lastError.level = XML_ERR_ERROR; 716 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base); 717 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base; 718 ctxt->context->lastError.node = ctxt->context->debugNode; 719 if (ctxt->context->error != NULL) { 720 ctxt->context->error(ctxt->context->userData, 721 &ctxt->context->lastError); 722 } else { 723 __xmlRaiseError(NULL, NULL, NULL, 724 NULL, ctxt->context->debugNode, XML_FROM_XPATH, 725 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, 726 XML_ERR_ERROR, NULL, 0, 727 (const char *) ctxt->base, NULL, NULL, 728 ctxt->cur - ctxt->base, 0, 729 "%s", xmlXPathErrorMessages[error]); 730 } 731 732 } 733 734 /** 735 * xmlXPatherror: 736 * @ctxt: the XPath Parser context 737 * @file: the file name 738 * @line: the line number 739 * @no: the error number 740 * 741 * Formats an error message. 742 */ 743 void 744 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED, 745 int line ATTRIBUTE_UNUSED, int no) { 746 xmlXPathErr(ctxt, no); 747 } 748 749 /************************************************************************ 750 * * 751 * Utilities * 752 * * 753 ************************************************************************/ 754 755 /** 756 * xsltPointerList: 757 * 758 * Pointer-list for various purposes. 759 */ 760 typedef struct _xmlPointerList xmlPointerList; 761 typedef xmlPointerList *xmlPointerListPtr; 762 struct _xmlPointerList { 763 void **items; 764 int number; 765 int size; 766 }; 767 /* 768 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt 769 * and here, we should make the functions public. 770 */ 771 static int 772 xmlPointerListAddSize(xmlPointerListPtr list, 773 void *item, 774 int initialSize) 775 { 776 if (list->items == NULL) { 777 if (initialSize <= 0) 778 initialSize = 1; 779 list->items = (void **) xmlMalloc(initialSize * sizeof(void *)); 780 if (list->items == NULL) { 781 xmlXPathErrMemory(NULL, 782 "xmlPointerListCreate: allocating item\n"); 783 return(-1); 784 } 785 list->number = 0; 786 list->size = initialSize; 787 } else if (list->size <= list->number) { 788 if (list->size > 50000000) { 789 xmlXPathErrMemory(NULL, 790 "xmlPointerListAddSize: re-allocating item\n"); 791 return(-1); 792 } 793 list->size *= 2; 794 list->items = (void **) xmlRealloc(list->items, 795 list->size * sizeof(void *)); 796 if (list->items == NULL) { 797 xmlXPathErrMemory(NULL, 798 "xmlPointerListAddSize: re-allocating item\n"); 799 list->size = 0; 800 return(-1); 801 } 802 } 803 list->items[list->number++] = item; 804 return(0); 805 } 806 807 /** 808 * xsltPointerListCreate: 809 * 810 * Creates an xsltPointerList structure. 811 * 812 * Returns a xsltPointerList structure or NULL in case of an error. 813 */ 814 static xmlPointerListPtr 815 xmlPointerListCreate(int initialSize) 816 { 817 xmlPointerListPtr ret; 818 819 ret = xmlMalloc(sizeof(xmlPointerList)); 820 if (ret == NULL) { 821 xmlXPathErrMemory(NULL, 822 "xmlPointerListCreate: allocating item\n"); 823 return (NULL); 824 } 825 memset(ret, 0, sizeof(xmlPointerList)); 826 if (initialSize > 0) { 827 xmlPointerListAddSize(ret, NULL, initialSize); 828 ret->number = 0; 829 } 830 return (ret); 831 } 832 833 /** 834 * xsltPointerListFree: 835 * 836 * Frees the xsltPointerList structure. This does not free 837 * the content of the list. 838 */ 839 static void 840 xmlPointerListFree(xmlPointerListPtr list) 841 { 842 if (list == NULL) 843 return; 844 if (list->items != NULL) 845 xmlFree(list->items); 846 xmlFree(list); 847 } 848 849 /************************************************************************ 850 * * 851 * Parser Types * 852 * * 853 ************************************************************************/ 854 855 /* 856 * Types are private: 857 */ 858 859 typedef enum { 860 XPATH_OP_END=0, 861 XPATH_OP_AND, 862 XPATH_OP_OR, 863 XPATH_OP_EQUAL, 864 XPATH_OP_CMP, 865 XPATH_OP_PLUS, 866 XPATH_OP_MULT, 867 XPATH_OP_UNION, 868 XPATH_OP_ROOT, 869 XPATH_OP_NODE, 870 XPATH_OP_RESET, /* 10 */ 871 XPATH_OP_COLLECT, 872 XPATH_OP_VALUE, /* 12 */ 873 XPATH_OP_VARIABLE, 874 XPATH_OP_FUNCTION, 875 XPATH_OP_ARG, 876 XPATH_OP_PREDICATE, 877 XPATH_OP_FILTER, /* 17 */ 878 XPATH_OP_SORT /* 18 */ 879 #ifdef LIBXML_XPTR_ENABLED 880 ,XPATH_OP_RANGETO 881 #endif 882 } xmlXPathOp; 883 884 typedef enum { 885 AXIS_ANCESTOR = 1, 886 AXIS_ANCESTOR_OR_SELF, 887 AXIS_ATTRIBUTE, 888 AXIS_CHILD, 889 AXIS_DESCENDANT, 890 AXIS_DESCENDANT_OR_SELF, 891 AXIS_FOLLOWING, 892 AXIS_FOLLOWING_SIBLING, 893 AXIS_NAMESPACE, 894 AXIS_PARENT, 895 AXIS_PRECEDING, 896 AXIS_PRECEDING_SIBLING, 897 AXIS_SELF 898 } xmlXPathAxisVal; 899 900 typedef enum { 901 NODE_TEST_NONE = 0, 902 NODE_TEST_TYPE = 1, 903 NODE_TEST_PI = 2, 904 NODE_TEST_ALL = 3, 905 NODE_TEST_NS = 4, 906 NODE_TEST_NAME = 5 907 } xmlXPathTestVal; 908 909 typedef enum { 910 NODE_TYPE_NODE = 0, 911 NODE_TYPE_COMMENT = XML_COMMENT_NODE, 912 NODE_TYPE_TEXT = XML_TEXT_NODE, 913 NODE_TYPE_PI = XML_PI_NODE 914 } xmlXPathTypeVal; 915 916 typedef struct _xmlXPathStepOp xmlXPathStepOp; 917 typedef xmlXPathStepOp *xmlXPathStepOpPtr; 918 struct _xmlXPathStepOp { 919 xmlXPathOp op; /* The identifier of the operation */ 920 int ch1; /* First child */ 921 int ch2; /* Second child */ 922 int value; 923 int value2; 924 int value3; 925 void *value4; 926 void *value5; 927 xmlXPathFunction cache; 928 void *cacheURI; 929 }; 930 931 struct _xmlXPathCompExpr { 932 int nbStep; /* Number of steps in this expression */ 933 int maxStep; /* Maximum number of steps allocated */ 934 xmlXPathStepOp *steps; /* ops for computation of this expression */ 935 int last; /* index of last step in expression */ 936 xmlChar *expr; /* the expression being computed */ 937 xmlDictPtr dict; /* the dictionary to use if any */ 938 #ifdef DEBUG_EVAL_COUNTS 939 int nb; 940 xmlChar *string; 941 #endif 942 #ifdef XPATH_STREAMING 943 xmlPatternPtr stream; 944 #endif 945 }; 946 947 /************************************************************************ 948 * * 949 * Forward declarations * 950 * * 951 ************************************************************************/ 952 static void 953 xmlXPathFreeValueTree(xmlNodeSetPtr obj); 954 static void 955 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj); 956 static int 957 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt, 958 xmlXPathStepOpPtr op, xmlNodePtr *first); 959 static int 960 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt, 961 xmlXPathStepOpPtr op, 962 int isPredicate); 963 static void 964 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name); 965 966 /************************************************************************ 967 * * 968 * Parser Type functions * 969 * * 970 ************************************************************************/ 971 972 /** 973 * xmlXPathNewCompExpr: 974 * 975 * Create a new Xpath component 976 * 977 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error 978 */ 979 static xmlXPathCompExprPtr 980 xmlXPathNewCompExpr(void) { 981 xmlXPathCompExprPtr cur; 982 983 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr)); 984 if (cur == NULL) { 985 xmlXPathErrMemory(NULL, "allocating component\n"); 986 return(NULL); 987 } 988 memset(cur, 0, sizeof(xmlXPathCompExpr)); 989 cur->maxStep = 10; 990 cur->nbStep = 0; 991 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep * 992 sizeof(xmlXPathStepOp)); 993 if (cur->steps == NULL) { 994 xmlXPathErrMemory(NULL, "allocating steps\n"); 995 xmlFree(cur); 996 return(NULL); 997 } 998 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp)); 999 cur->last = -1; 1000 #ifdef DEBUG_EVAL_COUNTS 1001 cur->nb = 0; 1002 #endif 1003 return(cur); 1004 } 1005 1006 /** 1007 * xmlXPathFreeCompExpr: 1008 * @comp: an XPATH comp 1009 * 1010 * Free up the memory allocated by @comp 1011 */ 1012 void 1013 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp) 1014 { 1015 xmlXPathStepOpPtr op; 1016 int i; 1017 1018 if (comp == NULL) 1019 return; 1020 if (comp->dict == NULL) { 1021 for (i = 0; i < comp->nbStep; i++) { 1022 op = &comp->steps[i]; 1023 if (op->value4 != NULL) { 1024 if (op->op == XPATH_OP_VALUE) 1025 xmlXPathFreeObject(op->value4); 1026 else 1027 xmlFree(op->value4); 1028 } 1029 if (op->value5 != NULL) 1030 xmlFree(op->value5); 1031 } 1032 } else { 1033 for (i = 0; i < comp->nbStep; i++) { 1034 op = &comp->steps[i]; 1035 if (op->value4 != NULL) { 1036 if (op->op == XPATH_OP_VALUE) 1037 xmlXPathFreeObject(op->value4); 1038 } 1039 } 1040 xmlDictFree(comp->dict); 1041 } 1042 if (comp->steps != NULL) { 1043 xmlFree(comp->steps); 1044 } 1045 #ifdef DEBUG_EVAL_COUNTS 1046 if (comp->string != NULL) { 1047 xmlFree(comp->string); 1048 } 1049 #endif 1050 #ifdef XPATH_STREAMING 1051 if (comp->stream != NULL) { 1052 xmlFreePatternList(comp->stream); 1053 } 1054 #endif 1055 if (comp->expr != NULL) { 1056 xmlFree(comp->expr); 1057 } 1058 1059 xmlFree(comp); 1060 } 1061 1062 /** 1063 * xmlXPathCompExprAdd: 1064 * @comp: the compiled expression 1065 * @ch1: first child index 1066 * @ch2: second child index 1067 * @op: an op 1068 * @value: the first int value 1069 * @value2: the second int value 1070 * @value3: the third int value 1071 * @value4: the first string value 1072 * @value5: the second string value 1073 * 1074 * Add a step to an XPath Compiled Expression 1075 * 1076 * Returns -1 in case of failure, the index otherwise 1077 */ 1078 static int 1079 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2, 1080 xmlXPathOp op, int value, 1081 int value2, int value3, void *value4, void *value5) { 1082 if (comp->nbStep >= comp->maxStep) { 1083 xmlXPathStepOp *real; 1084 1085 if (comp->maxStep >= XPATH_MAX_STEPS) { 1086 xmlXPathErrMemory(NULL, "adding step\n"); 1087 return(-1); 1088 } 1089 comp->maxStep *= 2; 1090 real = (xmlXPathStepOp *) xmlRealloc(comp->steps, 1091 comp->maxStep * sizeof(xmlXPathStepOp)); 1092 if (real == NULL) { 1093 comp->maxStep /= 2; 1094 xmlXPathErrMemory(NULL, "adding step\n"); 1095 return(-1); 1096 } 1097 comp->steps = real; 1098 } 1099 comp->last = comp->nbStep; 1100 comp->steps[comp->nbStep].ch1 = ch1; 1101 comp->steps[comp->nbStep].ch2 = ch2; 1102 comp->steps[comp->nbStep].op = op; 1103 comp->steps[comp->nbStep].value = value; 1104 comp->steps[comp->nbStep].value2 = value2; 1105 comp->steps[comp->nbStep].value3 = value3; 1106 if ((comp->dict != NULL) && 1107 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) || 1108 (op == XPATH_OP_COLLECT))) { 1109 if (value4 != NULL) { 1110 comp->steps[comp->nbStep].value4 = (xmlChar *) 1111 (void *)xmlDictLookup(comp->dict, value4, -1); 1112 xmlFree(value4); 1113 } else 1114 comp->steps[comp->nbStep].value4 = NULL; 1115 if (value5 != NULL) { 1116 comp->steps[comp->nbStep].value5 = (xmlChar *) 1117 (void *)xmlDictLookup(comp->dict, value5, -1); 1118 xmlFree(value5); 1119 } else 1120 comp->steps[comp->nbStep].value5 = NULL; 1121 } else { 1122 comp->steps[comp->nbStep].value4 = value4; 1123 comp->steps[comp->nbStep].value5 = value5; 1124 } 1125 comp->steps[comp->nbStep].cache = NULL; 1126 return(comp->nbStep++); 1127 } 1128 1129 /** 1130 * xmlXPathCompSwap: 1131 * @comp: the compiled expression 1132 * @op: operation index 1133 * 1134 * Swaps 2 operations in the compiled expression 1135 */ 1136 static void 1137 xmlXPathCompSwap(xmlXPathStepOpPtr op) { 1138 int tmp; 1139 1140 #ifndef LIBXML_THREAD_ENABLED 1141 /* 1142 * Since this manipulates possibly shared variables, this is 1143 * disabled if one detects that the library is used in a multithreaded 1144 * application 1145 */ 1146 if (xmlXPathDisableOptimizer) 1147 return; 1148 #endif 1149 1150 tmp = op->ch1; 1151 op->ch1 = op->ch2; 1152 op->ch2 = tmp; 1153 } 1154 1155 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \ 1156 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \ 1157 (op), (val), (val2), (val3), (val4), (val5)) 1158 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \ 1159 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \ 1160 (op), (val), (val2), (val3), (val4), (val5)) 1161 1162 #define PUSH_LEAVE_EXPR(op, val, val2) \ 1163 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL) 1164 1165 #define PUSH_UNARY_EXPR(op, ch, val, val2) \ 1166 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL) 1167 1168 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \ 1169 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \ 1170 (val), (val2), 0 ,NULL ,NULL) 1171 1172 /************************************************************************ 1173 * * 1174 * XPath object cache structures * 1175 * * 1176 ************************************************************************/ 1177 1178 /* #define XP_DEFAULT_CACHE_ON */ 1179 1180 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL)) 1181 1182 typedef struct _xmlXPathContextCache xmlXPathContextCache; 1183 typedef xmlXPathContextCache *xmlXPathContextCachePtr; 1184 struct _xmlXPathContextCache { 1185 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */ 1186 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */ 1187 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */ 1188 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */ 1189 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */ 1190 int maxNodeset; 1191 int maxString; 1192 int maxBoolean; 1193 int maxNumber; 1194 int maxMisc; 1195 #ifdef XP_DEBUG_OBJ_USAGE 1196 int dbgCachedAll; 1197 int dbgCachedNodeset; 1198 int dbgCachedString; 1199 int dbgCachedBool; 1200 int dbgCachedNumber; 1201 int dbgCachedPoint; 1202 int dbgCachedRange; 1203 int dbgCachedLocset; 1204 int dbgCachedUsers; 1205 int dbgCachedXSLTTree; 1206 int dbgCachedUndefined; 1207 1208 1209 int dbgReusedAll; 1210 int dbgReusedNodeset; 1211 int dbgReusedString; 1212 int dbgReusedBool; 1213 int dbgReusedNumber; 1214 int dbgReusedPoint; 1215 int dbgReusedRange; 1216 int dbgReusedLocset; 1217 int dbgReusedUsers; 1218 int dbgReusedXSLTTree; 1219 int dbgReusedUndefined; 1220 1221 #endif 1222 }; 1223 1224 /************************************************************************ 1225 * * 1226 * Debugging related functions * 1227 * * 1228 ************************************************************************/ 1229 1230 #define STRANGE \ 1231 xmlGenericError(xmlGenericErrorContext, \ 1232 "Internal error at %s:%d\n", \ 1233 __FILE__, __LINE__); 1234 1235 #ifdef LIBXML_DEBUG_ENABLED 1236 static void 1237 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) { 1238 int i; 1239 char shift[100]; 1240 1241 for (i = 0;((i < depth) && (i < 25));i++) 1242 shift[2 * i] = shift[2 * i + 1] = ' '; 1243 shift[2 * i] = shift[2 * i + 1] = 0; 1244 if (cur == NULL) { 1245 fprintf(output, "%s", shift); 1246 fprintf(output, "Node is NULL !\n"); 1247 return; 1248 1249 } 1250 1251 if ((cur->type == XML_DOCUMENT_NODE) || 1252 (cur->type == XML_HTML_DOCUMENT_NODE)) { 1253 fprintf(output, "%s", shift); 1254 fprintf(output, " /\n"); 1255 } else if (cur->type == XML_ATTRIBUTE_NODE) 1256 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth); 1257 else 1258 xmlDebugDumpOneNode(output, cur, depth); 1259 } 1260 static void 1261 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) { 1262 xmlNodePtr tmp; 1263 int i; 1264 char shift[100]; 1265 1266 for (i = 0;((i < depth) && (i < 25));i++) 1267 shift[2 * i] = shift[2 * i + 1] = ' '; 1268 shift[2 * i] = shift[2 * i + 1] = 0; 1269 if (cur == NULL) { 1270 fprintf(output, "%s", shift); 1271 fprintf(output, "Node is NULL !\n"); 1272 return; 1273 1274 } 1275 1276 while (cur != NULL) { 1277 tmp = cur; 1278 cur = cur->next; 1279 xmlDebugDumpOneNode(output, tmp, depth); 1280 } 1281 } 1282 1283 static void 1284 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) { 1285 int i; 1286 char shift[100]; 1287 1288 for (i = 0;((i < depth) && (i < 25));i++) 1289 shift[2 * i] = shift[2 * i + 1] = ' '; 1290 shift[2 * i] = shift[2 * i + 1] = 0; 1291 1292 if (cur == NULL) { 1293 fprintf(output, "%s", shift); 1294 fprintf(output, "NodeSet is NULL !\n"); 1295 return; 1296 1297 } 1298 1299 if (cur != NULL) { 1300 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr); 1301 for (i = 0;i < cur->nodeNr;i++) { 1302 fprintf(output, "%s", shift); 1303 fprintf(output, "%d", i + 1); 1304 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1); 1305 } 1306 } 1307 } 1308 1309 static void 1310 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) { 1311 int i; 1312 char shift[100]; 1313 1314 for (i = 0;((i < depth) && (i < 25));i++) 1315 shift[2 * i] = shift[2 * i + 1] = ' '; 1316 shift[2 * i] = shift[2 * i + 1] = 0; 1317 1318 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) { 1319 fprintf(output, "%s", shift); 1320 fprintf(output, "Value Tree is NULL !\n"); 1321 return; 1322 1323 } 1324 1325 fprintf(output, "%s", shift); 1326 fprintf(output, "%d", i + 1); 1327 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1); 1328 } 1329 #if defined(LIBXML_XPTR_ENABLED) 1330 static void 1331 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) { 1332 int i; 1333 char shift[100]; 1334 1335 for (i = 0;((i < depth) && (i < 25));i++) 1336 shift[2 * i] = shift[2 * i + 1] = ' '; 1337 shift[2 * i] = shift[2 * i + 1] = 0; 1338 1339 if (cur == NULL) { 1340 fprintf(output, "%s", shift); 1341 fprintf(output, "LocationSet is NULL !\n"); 1342 return; 1343 1344 } 1345 1346 for (i = 0;i < cur->locNr;i++) { 1347 fprintf(output, "%s", shift); 1348 fprintf(output, "%d : ", i + 1); 1349 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1); 1350 } 1351 } 1352 #endif /* LIBXML_XPTR_ENABLED */ 1353 1354 /** 1355 * xmlXPathDebugDumpObject: 1356 * @output: the FILE * to dump the output 1357 * @cur: the object to inspect 1358 * @depth: indentation level 1359 * 1360 * Dump the content of the object for debugging purposes 1361 */ 1362 void 1363 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) { 1364 int i; 1365 char shift[100]; 1366 1367 if (output == NULL) return; 1368 1369 for (i = 0;((i < depth) && (i < 25));i++) 1370 shift[2 * i] = shift[2 * i + 1] = ' '; 1371 shift[2 * i] = shift[2 * i + 1] = 0; 1372 1373 1374 fprintf(output, "%s", shift); 1375 1376 if (cur == NULL) { 1377 fprintf(output, "Object is empty (NULL)\n"); 1378 return; 1379 } 1380 switch(cur->type) { 1381 case XPATH_UNDEFINED: 1382 fprintf(output, "Object is uninitialized\n"); 1383 break; 1384 case XPATH_NODESET: 1385 fprintf(output, "Object is a Node Set :\n"); 1386 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth); 1387 break; 1388 case XPATH_XSLT_TREE: 1389 fprintf(output, "Object is an XSLT value tree :\n"); 1390 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth); 1391 break; 1392 case XPATH_BOOLEAN: 1393 fprintf(output, "Object is a Boolean : "); 1394 if (cur->boolval) fprintf(output, "true\n"); 1395 else fprintf(output, "false\n"); 1396 break; 1397 case XPATH_NUMBER: 1398 switch (xmlXPathIsInf(cur->floatval)) { 1399 case 1: 1400 fprintf(output, "Object is a number : Infinity\n"); 1401 break; 1402 case -1: 1403 fprintf(output, "Object is a number : -Infinity\n"); 1404 break; 1405 default: 1406 if (xmlXPathIsNaN(cur->floatval)) { 1407 fprintf(output, "Object is a number : NaN\n"); 1408 } else if (cur->floatval == 0) { 1409 /* Omit sign for negative zero. */ 1410 fprintf(output, "Object is a number : 0\n"); 1411 } else { 1412 fprintf(output, "Object is a number : %0g\n", cur->floatval); 1413 } 1414 } 1415 break; 1416 case XPATH_STRING: 1417 fprintf(output, "Object is a string : "); 1418 xmlDebugDumpString(output, cur->stringval); 1419 fprintf(output, "\n"); 1420 break; 1421 case XPATH_POINT: 1422 fprintf(output, "Object is a point : index %d in node", cur->index); 1423 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1); 1424 fprintf(output, "\n"); 1425 break; 1426 case XPATH_RANGE: 1427 if ((cur->user2 == NULL) || 1428 ((cur->user2 == cur->user) && (cur->index == cur->index2))) { 1429 fprintf(output, "Object is a collapsed range :\n"); 1430 fprintf(output, "%s", shift); 1431 if (cur->index >= 0) 1432 fprintf(output, "index %d in ", cur->index); 1433 fprintf(output, "node\n"); 1434 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, 1435 depth + 1); 1436 } else { 1437 fprintf(output, "Object is a range :\n"); 1438 fprintf(output, "%s", shift); 1439 fprintf(output, "From "); 1440 if (cur->index >= 0) 1441 fprintf(output, "index %d in ", cur->index); 1442 fprintf(output, "node\n"); 1443 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, 1444 depth + 1); 1445 fprintf(output, "%s", shift); 1446 fprintf(output, "To "); 1447 if (cur->index2 >= 0) 1448 fprintf(output, "index %d in ", cur->index2); 1449 fprintf(output, "node\n"); 1450 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2, 1451 depth + 1); 1452 fprintf(output, "\n"); 1453 } 1454 break; 1455 case XPATH_LOCATIONSET: 1456 #if defined(LIBXML_XPTR_ENABLED) 1457 fprintf(output, "Object is a Location Set:\n"); 1458 xmlXPathDebugDumpLocationSet(output, 1459 (xmlLocationSetPtr) cur->user, depth); 1460 #endif 1461 break; 1462 case XPATH_USERS: 1463 fprintf(output, "Object is user defined\n"); 1464 break; 1465 } 1466 } 1467 1468 static void 1469 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp, 1470 xmlXPathStepOpPtr op, int depth) { 1471 int i; 1472 char shift[100]; 1473 1474 for (i = 0;((i < depth) && (i < 25));i++) 1475 shift[2 * i] = shift[2 * i + 1] = ' '; 1476 shift[2 * i] = shift[2 * i + 1] = 0; 1477 1478 fprintf(output, "%s", shift); 1479 if (op == NULL) { 1480 fprintf(output, "Step is NULL\n"); 1481 return; 1482 } 1483 switch (op->op) { 1484 case XPATH_OP_END: 1485 fprintf(output, "END"); break; 1486 case XPATH_OP_AND: 1487 fprintf(output, "AND"); break; 1488 case XPATH_OP_OR: 1489 fprintf(output, "OR"); break; 1490 case XPATH_OP_EQUAL: 1491 if (op->value) 1492 fprintf(output, "EQUAL ="); 1493 else 1494 fprintf(output, "EQUAL !="); 1495 break; 1496 case XPATH_OP_CMP: 1497 if (op->value) 1498 fprintf(output, "CMP <"); 1499 else 1500 fprintf(output, "CMP >"); 1501 if (!op->value2) 1502 fprintf(output, "="); 1503 break; 1504 case XPATH_OP_PLUS: 1505 if (op->value == 0) 1506 fprintf(output, "PLUS -"); 1507 else if (op->value == 1) 1508 fprintf(output, "PLUS +"); 1509 else if (op->value == 2) 1510 fprintf(output, "PLUS unary -"); 1511 else if (op->value == 3) 1512 fprintf(output, "PLUS unary - -"); 1513 break; 1514 case XPATH_OP_MULT: 1515 if (op->value == 0) 1516 fprintf(output, "MULT *"); 1517 else if (op->value == 1) 1518 fprintf(output, "MULT div"); 1519 else 1520 fprintf(output, "MULT mod"); 1521 break; 1522 case XPATH_OP_UNION: 1523 fprintf(output, "UNION"); break; 1524 case XPATH_OP_ROOT: 1525 fprintf(output, "ROOT"); break; 1526 case XPATH_OP_NODE: 1527 fprintf(output, "NODE"); break; 1528 case XPATH_OP_RESET: 1529 fprintf(output, "RESET"); break; 1530 case XPATH_OP_SORT: 1531 fprintf(output, "SORT"); break; 1532 case XPATH_OP_COLLECT: { 1533 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value; 1534 xmlXPathTestVal test = (xmlXPathTestVal)op->value2; 1535 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3; 1536 const xmlChar *prefix = op->value4; 1537 const xmlChar *name = op->value5; 1538 1539 fprintf(output, "COLLECT "); 1540 switch (axis) { 1541 case AXIS_ANCESTOR: 1542 fprintf(output, " 'ancestors' "); break; 1543 case AXIS_ANCESTOR_OR_SELF: 1544 fprintf(output, " 'ancestors-or-self' "); break; 1545 case AXIS_ATTRIBUTE: 1546 fprintf(output, " 'attributes' "); break; 1547 case AXIS_CHILD: 1548 fprintf(output, " 'child' "); break; 1549 case AXIS_DESCENDANT: 1550 fprintf(output, " 'descendant' "); break; 1551 case AXIS_DESCENDANT_OR_SELF: 1552 fprintf(output, " 'descendant-or-self' "); break; 1553 case AXIS_FOLLOWING: 1554 fprintf(output, " 'following' "); break; 1555 case AXIS_FOLLOWING_SIBLING: 1556 fprintf(output, " 'following-siblings' "); break; 1557 case AXIS_NAMESPACE: 1558 fprintf(output, " 'namespace' "); break; 1559 case AXIS_PARENT: 1560 fprintf(output, " 'parent' "); break; 1561 case AXIS_PRECEDING: 1562 fprintf(output, " 'preceding' "); break; 1563 case AXIS_PRECEDING_SIBLING: 1564 fprintf(output, " 'preceding-sibling' "); break; 1565 case AXIS_SELF: 1566 fprintf(output, " 'self' "); break; 1567 } 1568 switch (test) { 1569 case NODE_TEST_NONE: 1570 fprintf(output, "'none' "); break; 1571 case NODE_TEST_TYPE: 1572 fprintf(output, "'type' "); break; 1573 case NODE_TEST_PI: 1574 fprintf(output, "'PI' "); break; 1575 case NODE_TEST_ALL: 1576 fprintf(output, "'all' "); break; 1577 case NODE_TEST_NS: 1578 fprintf(output, "'namespace' "); break; 1579 case NODE_TEST_NAME: 1580 fprintf(output, "'name' "); break; 1581 } 1582 switch (type) { 1583 case NODE_TYPE_NODE: 1584 fprintf(output, "'node' "); break; 1585 case NODE_TYPE_COMMENT: 1586 fprintf(output, "'comment' "); break; 1587 case NODE_TYPE_TEXT: 1588 fprintf(output, "'text' "); break; 1589 case NODE_TYPE_PI: 1590 fprintf(output, "'PI' "); break; 1591 } 1592 if (prefix != NULL) 1593 fprintf(output, "%s:", prefix); 1594 if (name != NULL) 1595 fprintf(output, "%s", (const char *) name); 1596 break; 1597 1598 } 1599 case XPATH_OP_VALUE: { 1600 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4; 1601 1602 fprintf(output, "ELEM "); 1603 xmlXPathDebugDumpObject(output, object, 0); 1604 goto finish; 1605 } 1606 case XPATH_OP_VARIABLE: { 1607 const xmlChar *prefix = op->value5; 1608 const xmlChar *name = op->value4; 1609 1610 if (prefix != NULL) 1611 fprintf(output, "VARIABLE %s:%s", prefix, name); 1612 else 1613 fprintf(output, "VARIABLE %s", name); 1614 break; 1615 } 1616 case XPATH_OP_FUNCTION: { 1617 int nbargs = op->value; 1618 const xmlChar *prefix = op->value5; 1619 const xmlChar *name = op->value4; 1620 1621 if (prefix != NULL) 1622 fprintf(output, "FUNCTION %s:%s(%d args)", 1623 prefix, name, nbargs); 1624 else 1625 fprintf(output, "FUNCTION %s(%d args)", name, nbargs); 1626 break; 1627 } 1628 case XPATH_OP_ARG: fprintf(output, "ARG"); break; 1629 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break; 1630 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break; 1631 #ifdef LIBXML_XPTR_ENABLED 1632 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break; 1633 #endif 1634 default: 1635 fprintf(output, "UNKNOWN %d\n", op->op); return; 1636 } 1637 fprintf(output, "\n"); 1638 finish: 1639 if (op->ch1 >= 0) 1640 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1); 1641 if (op->ch2 >= 0) 1642 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1); 1643 } 1644 1645 /** 1646 * xmlXPathDebugDumpCompExpr: 1647 * @output: the FILE * for the output 1648 * @comp: the precompiled XPath expression 1649 * @depth: the indentation level. 1650 * 1651 * Dumps the tree of the compiled XPath expression. 1652 */ 1653 void 1654 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp, 1655 int depth) { 1656 int i; 1657 char shift[100]; 1658 1659 if ((output == NULL) || (comp == NULL)) return; 1660 1661 for (i = 0;((i < depth) && (i < 25));i++) 1662 shift[2 * i] = shift[2 * i + 1] = ' '; 1663 shift[2 * i] = shift[2 * i + 1] = 0; 1664 1665 fprintf(output, "%s", shift); 1666 1667 #ifdef XPATH_STREAMING 1668 if (comp->stream) { 1669 fprintf(output, "Streaming Expression\n"); 1670 } else 1671 #endif 1672 { 1673 fprintf(output, "Compiled Expression : %d elements\n", 1674 comp->nbStep); 1675 i = comp->last; 1676 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1); 1677 } 1678 } 1679 1680 #ifdef XP_DEBUG_OBJ_USAGE 1681 1682 /* 1683 * XPath object usage related debugging variables. 1684 */ 1685 static int xmlXPathDebugObjCounterUndefined = 0; 1686 static int xmlXPathDebugObjCounterNodeset = 0; 1687 static int xmlXPathDebugObjCounterBool = 0; 1688 static int xmlXPathDebugObjCounterNumber = 0; 1689 static int xmlXPathDebugObjCounterString = 0; 1690 static int xmlXPathDebugObjCounterPoint = 0; 1691 static int xmlXPathDebugObjCounterRange = 0; 1692 static int xmlXPathDebugObjCounterLocset = 0; 1693 static int xmlXPathDebugObjCounterUsers = 0; 1694 static int xmlXPathDebugObjCounterXSLTTree = 0; 1695 static int xmlXPathDebugObjCounterAll = 0; 1696 1697 static int xmlXPathDebugObjTotalUndefined = 0; 1698 static int xmlXPathDebugObjTotalNodeset = 0; 1699 static int xmlXPathDebugObjTotalBool = 0; 1700 static int xmlXPathDebugObjTotalNumber = 0; 1701 static int xmlXPathDebugObjTotalString = 0; 1702 static int xmlXPathDebugObjTotalPoint = 0; 1703 static int xmlXPathDebugObjTotalRange = 0; 1704 static int xmlXPathDebugObjTotalLocset = 0; 1705 static int xmlXPathDebugObjTotalUsers = 0; 1706 static int xmlXPathDebugObjTotalXSLTTree = 0; 1707 static int xmlXPathDebugObjTotalAll = 0; 1708 1709 static int xmlXPathDebugObjMaxUndefined = 0; 1710 static int xmlXPathDebugObjMaxNodeset = 0; 1711 static int xmlXPathDebugObjMaxBool = 0; 1712 static int xmlXPathDebugObjMaxNumber = 0; 1713 static int xmlXPathDebugObjMaxString = 0; 1714 static int xmlXPathDebugObjMaxPoint = 0; 1715 static int xmlXPathDebugObjMaxRange = 0; 1716 static int xmlXPathDebugObjMaxLocset = 0; 1717 static int xmlXPathDebugObjMaxUsers = 0; 1718 static int xmlXPathDebugObjMaxXSLTTree = 0; 1719 static int xmlXPathDebugObjMaxAll = 0; 1720 1721 /* REVISIT TODO: Make this static when committing */ 1722 static void 1723 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt) 1724 { 1725 if (ctxt != NULL) { 1726 if (ctxt->cache != NULL) { 1727 xmlXPathContextCachePtr cache = 1728 (xmlXPathContextCachePtr) ctxt->cache; 1729 1730 cache->dbgCachedAll = 0; 1731 cache->dbgCachedNodeset = 0; 1732 cache->dbgCachedString = 0; 1733 cache->dbgCachedBool = 0; 1734 cache->dbgCachedNumber = 0; 1735 cache->dbgCachedPoint = 0; 1736 cache->dbgCachedRange = 0; 1737 cache->dbgCachedLocset = 0; 1738 cache->dbgCachedUsers = 0; 1739 cache->dbgCachedXSLTTree = 0; 1740 cache->dbgCachedUndefined = 0; 1741 1742 cache->dbgReusedAll = 0; 1743 cache->dbgReusedNodeset = 0; 1744 cache->dbgReusedString = 0; 1745 cache->dbgReusedBool = 0; 1746 cache->dbgReusedNumber = 0; 1747 cache->dbgReusedPoint = 0; 1748 cache->dbgReusedRange = 0; 1749 cache->dbgReusedLocset = 0; 1750 cache->dbgReusedUsers = 0; 1751 cache->dbgReusedXSLTTree = 0; 1752 cache->dbgReusedUndefined = 0; 1753 } 1754 } 1755 1756 xmlXPathDebugObjCounterUndefined = 0; 1757 xmlXPathDebugObjCounterNodeset = 0; 1758 xmlXPathDebugObjCounterBool = 0; 1759 xmlXPathDebugObjCounterNumber = 0; 1760 xmlXPathDebugObjCounterString = 0; 1761 xmlXPathDebugObjCounterPoint = 0; 1762 xmlXPathDebugObjCounterRange = 0; 1763 xmlXPathDebugObjCounterLocset = 0; 1764 xmlXPathDebugObjCounterUsers = 0; 1765 xmlXPathDebugObjCounterXSLTTree = 0; 1766 xmlXPathDebugObjCounterAll = 0; 1767 1768 xmlXPathDebugObjTotalUndefined = 0; 1769 xmlXPathDebugObjTotalNodeset = 0; 1770 xmlXPathDebugObjTotalBool = 0; 1771 xmlXPathDebugObjTotalNumber = 0; 1772 xmlXPathDebugObjTotalString = 0; 1773 xmlXPathDebugObjTotalPoint = 0; 1774 xmlXPathDebugObjTotalRange = 0; 1775 xmlXPathDebugObjTotalLocset = 0; 1776 xmlXPathDebugObjTotalUsers = 0; 1777 xmlXPathDebugObjTotalXSLTTree = 0; 1778 xmlXPathDebugObjTotalAll = 0; 1779 1780 xmlXPathDebugObjMaxUndefined = 0; 1781 xmlXPathDebugObjMaxNodeset = 0; 1782 xmlXPathDebugObjMaxBool = 0; 1783 xmlXPathDebugObjMaxNumber = 0; 1784 xmlXPathDebugObjMaxString = 0; 1785 xmlXPathDebugObjMaxPoint = 0; 1786 xmlXPathDebugObjMaxRange = 0; 1787 xmlXPathDebugObjMaxLocset = 0; 1788 xmlXPathDebugObjMaxUsers = 0; 1789 xmlXPathDebugObjMaxXSLTTree = 0; 1790 xmlXPathDebugObjMaxAll = 0; 1791 1792 } 1793 1794 static void 1795 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt, 1796 xmlXPathObjectType objType) 1797 { 1798 int isCached = 0; 1799 1800 if (ctxt != NULL) { 1801 if (ctxt->cache != NULL) { 1802 xmlXPathContextCachePtr cache = 1803 (xmlXPathContextCachePtr) ctxt->cache; 1804 1805 isCached = 1; 1806 1807 cache->dbgReusedAll++; 1808 switch (objType) { 1809 case XPATH_UNDEFINED: 1810 cache->dbgReusedUndefined++; 1811 break; 1812 case XPATH_NODESET: 1813 cache->dbgReusedNodeset++; 1814 break; 1815 case XPATH_BOOLEAN: 1816 cache->dbgReusedBool++; 1817 break; 1818 case XPATH_NUMBER: 1819 cache->dbgReusedNumber++; 1820 break; 1821 case XPATH_STRING: 1822 cache->dbgReusedString++; 1823 break; 1824 case XPATH_POINT: 1825 cache->dbgReusedPoint++; 1826 break; 1827 case XPATH_RANGE: 1828 cache->dbgReusedRange++; 1829 break; 1830 case XPATH_LOCATIONSET: 1831 cache->dbgReusedLocset++; 1832 break; 1833 case XPATH_USERS: 1834 cache->dbgReusedUsers++; 1835 break; 1836 case XPATH_XSLT_TREE: 1837 cache->dbgReusedXSLTTree++; 1838 break; 1839 default: 1840 break; 1841 } 1842 } 1843 } 1844 1845 switch (objType) { 1846 case XPATH_UNDEFINED: 1847 if (! isCached) 1848 xmlXPathDebugObjTotalUndefined++; 1849 xmlXPathDebugObjCounterUndefined++; 1850 if (xmlXPathDebugObjCounterUndefined > 1851 xmlXPathDebugObjMaxUndefined) 1852 xmlXPathDebugObjMaxUndefined = 1853 xmlXPathDebugObjCounterUndefined; 1854 break; 1855 case XPATH_NODESET: 1856 if (! isCached) 1857 xmlXPathDebugObjTotalNodeset++; 1858 xmlXPathDebugObjCounterNodeset++; 1859 if (xmlXPathDebugObjCounterNodeset > 1860 xmlXPathDebugObjMaxNodeset) 1861 xmlXPathDebugObjMaxNodeset = 1862 xmlXPathDebugObjCounterNodeset; 1863 break; 1864 case XPATH_BOOLEAN: 1865 if (! isCached) 1866 xmlXPathDebugObjTotalBool++; 1867 xmlXPathDebugObjCounterBool++; 1868 if (xmlXPathDebugObjCounterBool > 1869 xmlXPathDebugObjMaxBool) 1870 xmlXPathDebugObjMaxBool = 1871 xmlXPathDebugObjCounterBool; 1872 break; 1873 case XPATH_NUMBER: 1874 if (! isCached) 1875 xmlXPathDebugObjTotalNumber++; 1876 xmlXPathDebugObjCounterNumber++; 1877 if (xmlXPathDebugObjCounterNumber > 1878 xmlXPathDebugObjMaxNumber) 1879 xmlXPathDebugObjMaxNumber = 1880 xmlXPathDebugObjCounterNumber; 1881 break; 1882 case XPATH_STRING: 1883 if (! isCached) 1884 xmlXPathDebugObjTotalString++; 1885 xmlXPathDebugObjCounterString++; 1886 if (xmlXPathDebugObjCounterString > 1887 xmlXPathDebugObjMaxString) 1888 xmlXPathDebugObjMaxString = 1889 xmlXPathDebugObjCounterString; 1890 break; 1891 case XPATH_POINT: 1892 if (! isCached) 1893 xmlXPathDebugObjTotalPoint++; 1894 xmlXPathDebugObjCounterPoint++; 1895 if (xmlXPathDebugObjCounterPoint > 1896 xmlXPathDebugObjMaxPoint) 1897 xmlXPathDebugObjMaxPoint = 1898 xmlXPathDebugObjCounterPoint; 1899 break; 1900 case XPATH_RANGE: 1901 if (! isCached) 1902 xmlXPathDebugObjTotalRange++; 1903 xmlXPathDebugObjCounterRange++; 1904 if (xmlXPathDebugObjCounterRange > 1905 xmlXPathDebugObjMaxRange) 1906 xmlXPathDebugObjMaxRange = 1907 xmlXPathDebugObjCounterRange; 1908 break; 1909 case XPATH_LOCATIONSET: 1910 if (! isCached) 1911 xmlXPathDebugObjTotalLocset++; 1912 xmlXPathDebugObjCounterLocset++; 1913 if (xmlXPathDebugObjCounterLocset > 1914 xmlXPathDebugObjMaxLocset) 1915 xmlXPathDebugObjMaxLocset = 1916 xmlXPathDebugObjCounterLocset; 1917 break; 1918 case XPATH_USERS: 1919 if (! isCached) 1920 xmlXPathDebugObjTotalUsers++; 1921 xmlXPathDebugObjCounterUsers++; 1922 if (xmlXPathDebugObjCounterUsers > 1923 xmlXPathDebugObjMaxUsers) 1924 xmlXPathDebugObjMaxUsers = 1925 xmlXPathDebugObjCounterUsers; 1926 break; 1927 case XPATH_XSLT_TREE: 1928 if (! isCached) 1929 xmlXPathDebugObjTotalXSLTTree++; 1930 xmlXPathDebugObjCounterXSLTTree++; 1931 if (xmlXPathDebugObjCounterXSLTTree > 1932 xmlXPathDebugObjMaxXSLTTree) 1933 xmlXPathDebugObjMaxXSLTTree = 1934 xmlXPathDebugObjCounterXSLTTree; 1935 break; 1936 default: 1937 break; 1938 } 1939 if (! isCached) 1940 xmlXPathDebugObjTotalAll++; 1941 xmlXPathDebugObjCounterAll++; 1942 if (xmlXPathDebugObjCounterAll > 1943 xmlXPathDebugObjMaxAll) 1944 xmlXPathDebugObjMaxAll = 1945 xmlXPathDebugObjCounterAll; 1946 } 1947 1948 static void 1949 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt, 1950 xmlXPathObjectType objType) 1951 { 1952 int isCached = 0; 1953 1954 if (ctxt != NULL) { 1955 if (ctxt->cache != NULL) { 1956 xmlXPathContextCachePtr cache = 1957 (xmlXPathContextCachePtr) ctxt->cache; 1958 1959 isCached = 1; 1960 1961 cache->dbgCachedAll++; 1962 switch (objType) { 1963 case XPATH_UNDEFINED: 1964 cache->dbgCachedUndefined++; 1965 break; 1966 case XPATH_NODESET: 1967 cache->dbgCachedNodeset++; 1968 break; 1969 case XPATH_BOOLEAN: 1970 cache->dbgCachedBool++; 1971 break; 1972 case XPATH_NUMBER: 1973 cache->dbgCachedNumber++; 1974 break; 1975 case XPATH_STRING: 1976 cache->dbgCachedString++; 1977 break; 1978 case XPATH_POINT: 1979 cache->dbgCachedPoint++; 1980 break; 1981 case XPATH_RANGE: 1982 cache->dbgCachedRange++; 1983 break; 1984 case XPATH_LOCATIONSET: 1985 cache->dbgCachedLocset++; 1986 break; 1987 case XPATH_USERS: 1988 cache->dbgCachedUsers++; 1989 break; 1990 case XPATH_XSLT_TREE: 1991 cache->dbgCachedXSLTTree++; 1992 break; 1993 default: 1994 break; 1995 } 1996 1997 } 1998 } 1999 switch (objType) { 2000 case XPATH_UNDEFINED: 2001 xmlXPathDebugObjCounterUndefined--; 2002 break; 2003 case XPATH_NODESET: 2004 xmlXPathDebugObjCounterNodeset--; 2005 break; 2006 case XPATH_BOOLEAN: 2007 xmlXPathDebugObjCounterBool--; 2008 break; 2009 case XPATH_NUMBER: 2010 xmlXPathDebugObjCounterNumber--; 2011 break; 2012 case XPATH_STRING: 2013 xmlXPathDebugObjCounterString--; 2014 break; 2015 case XPATH_POINT: 2016 xmlXPathDebugObjCounterPoint--; 2017 break; 2018 case XPATH_RANGE: 2019 xmlXPathDebugObjCounterRange--; 2020 break; 2021 case XPATH_LOCATIONSET: 2022 xmlXPathDebugObjCounterLocset--; 2023 break; 2024 case XPATH_USERS: 2025 xmlXPathDebugObjCounterUsers--; 2026 break; 2027 case XPATH_XSLT_TREE: 2028 xmlXPathDebugObjCounterXSLTTree--; 2029 break; 2030 default: 2031 break; 2032 } 2033 xmlXPathDebugObjCounterAll--; 2034 } 2035 2036 /* REVISIT TODO: Make this static when committing */ 2037 static void 2038 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt) 2039 { 2040 int reqAll, reqNodeset, reqString, reqBool, reqNumber, 2041 reqXSLTTree, reqUndefined; 2042 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0, 2043 caNumber = 0, caXSLTTree = 0, caUndefined = 0; 2044 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0, 2045 reNumber = 0, reXSLTTree = 0, reUndefined = 0; 2046 int leftObjs = xmlXPathDebugObjCounterAll; 2047 2048 reqAll = xmlXPathDebugObjTotalAll; 2049 reqNodeset = xmlXPathDebugObjTotalNodeset; 2050 reqString = xmlXPathDebugObjTotalString; 2051 reqBool = xmlXPathDebugObjTotalBool; 2052 reqNumber = xmlXPathDebugObjTotalNumber; 2053 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree; 2054 reqUndefined = xmlXPathDebugObjTotalUndefined; 2055 2056 printf("# XPath object usage:\n"); 2057 2058 if (ctxt != NULL) { 2059 if (ctxt->cache != NULL) { 2060 xmlXPathContextCachePtr cache = 2061 (xmlXPathContextCachePtr) ctxt->cache; 2062 2063 reAll = cache->dbgReusedAll; 2064 reqAll += reAll; 2065 reNodeset = cache->dbgReusedNodeset; 2066 reqNodeset += reNodeset; 2067 reString = cache->dbgReusedString; 2068 reqString += reString; 2069 reBool = cache->dbgReusedBool; 2070 reqBool += reBool; 2071 reNumber = cache->dbgReusedNumber; 2072 reqNumber += reNumber; 2073 reXSLTTree = cache->dbgReusedXSLTTree; 2074 reqXSLTTree += reXSLTTree; 2075 reUndefined = cache->dbgReusedUndefined; 2076 reqUndefined += reUndefined; 2077 2078 caAll = cache->dbgCachedAll; 2079 caBool = cache->dbgCachedBool; 2080 caNodeset = cache->dbgCachedNodeset; 2081 caString = cache->dbgCachedString; 2082 caNumber = cache->dbgCachedNumber; 2083 caXSLTTree = cache->dbgCachedXSLTTree; 2084 caUndefined = cache->dbgCachedUndefined; 2085 2086 if (cache->nodesetObjs) 2087 leftObjs -= cache->nodesetObjs->number; 2088 if (cache->stringObjs) 2089 leftObjs -= cache->stringObjs->number; 2090 if (cache->booleanObjs) 2091 leftObjs -= cache->booleanObjs->number; 2092 if (cache->numberObjs) 2093 leftObjs -= cache->numberObjs->number; 2094 if (cache->miscObjs) 2095 leftObjs -= cache->miscObjs->number; 2096 } 2097 } 2098 2099 printf("# all\n"); 2100 printf("# total : %d\n", reqAll); 2101 printf("# left : %d\n", leftObjs); 2102 printf("# created: %d\n", xmlXPathDebugObjTotalAll); 2103 printf("# reused : %d\n", reAll); 2104 printf("# max : %d\n", xmlXPathDebugObjMaxAll); 2105 2106 printf("# node-sets\n"); 2107 printf("# total : %d\n", reqNodeset); 2108 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset); 2109 printf("# reused : %d\n", reNodeset); 2110 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset); 2111 2112 printf("# strings\n"); 2113 printf("# total : %d\n", reqString); 2114 printf("# created: %d\n", xmlXPathDebugObjTotalString); 2115 printf("# reused : %d\n", reString); 2116 printf("# max : %d\n", xmlXPathDebugObjMaxString); 2117 2118 printf("# booleans\n"); 2119 printf("# total : %d\n", reqBool); 2120 printf("# created: %d\n", xmlXPathDebugObjTotalBool); 2121 printf("# reused : %d\n", reBool); 2122 printf("# max : %d\n", xmlXPathDebugObjMaxBool); 2123 2124 printf("# numbers\n"); 2125 printf("# total : %d\n", reqNumber); 2126 printf("# created: %d\n", xmlXPathDebugObjTotalNumber); 2127 printf("# reused : %d\n", reNumber); 2128 printf("# max : %d\n", xmlXPathDebugObjMaxNumber); 2129 2130 printf("# XSLT result tree fragments\n"); 2131 printf("# total : %d\n", reqXSLTTree); 2132 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree); 2133 printf("# reused : %d\n", reXSLTTree); 2134 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree); 2135 2136 printf("# undefined\n"); 2137 printf("# total : %d\n", reqUndefined); 2138 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined); 2139 printf("# reused : %d\n", reUndefined); 2140 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined); 2141 2142 } 2143 2144 #endif /* XP_DEBUG_OBJ_USAGE */ 2145 2146 #endif /* LIBXML_DEBUG_ENABLED */ 2147 2148 /************************************************************************ 2149 * * 2150 * XPath object caching * 2151 * * 2152 ************************************************************************/ 2153 2154 /** 2155 * xmlXPathNewCache: 2156 * 2157 * Create a new object cache 2158 * 2159 * Returns the xmlXPathCache just allocated. 2160 */ 2161 static xmlXPathContextCachePtr 2162 xmlXPathNewCache(void) 2163 { 2164 xmlXPathContextCachePtr ret; 2165 2166 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache)); 2167 if (ret == NULL) { 2168 xmlXPathErrMemory(NULL, "creating object cache\n"); 2169 return(NULL); 2170 } 2171 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache)); 2172 ret->maxNodeset = 100; 2173 ret->maxString = 100; 2174 ret->maxBoolean = 100; 2175 ret->maxNumber = 100; 2176 ret->maxMisc = 100; 2177 return(ret); 2178 } 2179 2180 static void 2181 xmlXPathCacheFreeObjectList(xmlPointerListPtr list) 2182 { 2183 int i; 2184 xmlXPathObjectPtr obj; 2185 2186 if (list == NULL) 2187 return; 2188 2189 for (i = 0; i < list->number; i++) { 2190 obj = list->items[i]; 2191 /* 2192 * Note that it is already assured that we don't need to 2193 * look out for namespace nodes in the node-set. 2194 */ 2195 if (obj->nodesetval != NULL) { 2196 if (obj->nodesetval->nodeTab != NULL) 2197 xmlFree(obj->nodesetval->nodeTab); 2198 xmlFree(obj->nodesetval); 2199 } 2200 xmlFree(obj); 2201 #ifdef XP_DEBUG_OBJ_USAGE 2202 xmlXPathDebugObjCounterAll--; 2203 #endif 2204 } 2205 xmlPointerListFree(list); 2206 } 2207 2208 static void 2209 xmlXPathFreeCache(xmlXPathContextCachePtr cache) 2210 { 2211 if (cache == NULL) 2212 return; 2213 if (cache->nodesetObjs) 2214 xmlXPathCacheFreeObjectList(cache->nodesetObjs); 2215 if (cache->stringObjs) 2216 xmlXPathCacheFreeObjectList(cache->stringObjs); 2217 if (cache->booleanObjs) 2218 xmlXPathCacheFreeObjectList(cache->booleanObjs); 2219 if (cache->numberObjs) 2220 xmlXPathCacheFreeObjectList(cache->numberObjs); 2221 if (cache->miscObjs) 2222 xmlXPathCacheFreeObjectList(cache->miscObjs); 2223 xmlFree(cache); 2224 } 2225 2226 /** 2227 * xmlXPathContextSetCache: 2228 * 2229 * @ctxt: the XPath context 2230 * @active: enables/disables (creates/frees) the cache 2231 * @value: a value with semantics dependant on @options 2232 * @options: options (currently only the value 0 is used) 2233 * 2234 * Creates/frees an object cache on the XPath context. 2235 * If activates XPath objects (xmlXPathObject) will be cached internally 2236 * to be reused. 2237 * @options: 2238 * 0: This will set the XPath object caching: 2239 * @value: 2240 * This will set the maximum number of XPath objects 2241 * to be cached per slot 2242 * There are 5 slots for: node-set, string, number, boolean, and 2243 * misc objects. Use <0 for the default number (100). 2244 * Other values for @options have currently no effect. 2245 * 2246 * Returns 0 if the setting succeeded, and -1 on API or internal errors. 2247 */ 2248 int 2249 xmlXPathContextSetCache(xmlXPathContextPtr ctxt, 2250 int active, 2251 int value, 2252 int options) 2253 { 2254 if (ctxt == NULL) 2255 return(-1); 2256 if (active) { 2257 xmlXPathContextCachePtr cache; 2258 2259 if (ctxt->cache == NULL) { 2260 ctxt->cache = xmlXPathNewCache(); 2261 if (ctxt->cache == NULL) 2262 return(-1); 2263 } 2264 cache = (xmlXPathContextCachePtr) ctxt->cache; 2265 if (options == 0) { 2266 if (value < 0) 2267 value = 100; 2268 cache->maxNodeset = value; 2269 cache->maxString = value; 2270 cache->maxNumber = value; 2271 cache->maxBoolean = value; 2272 cache->maxMisc = value; 2273 } 2274 } else if (ctxt->cache != NULL) { 2275 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache); 2276 ctxt->cache = NULL; 2277 } 2278 return(0); 2279 } 2280 2281 /** 2282 * xmlXPathCacheWrapNodeSet: 2283 * @ctxt: the XPath context 2284 * @val: the NodePtr value 2285 * 2286 * This is the cached version of xmlXPathWrapNodeSet(). 2287 * Wrap the Nodeset @val in a new xmlXPathObjectPtr 2288 * 2289 * Returns the created or reused object. 2290 */ 2291 static xmlXPathObjectPtr 2292 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val) 2293 { 2294 if ((ctxt != NULL) && (ctxt->cache != NULL)) { 2295 xmlXPathContextCachePtr cache = 2296 (xmlXPathContextCachePtr) ctxt->cache; 2297 2298 if ((cache->miscObjs != NULL) && 2299 (cache->miscObjs->number != 0)) 2300 { 2301 xmlXPathObjectPtr ret; 2302 2303 ret = (xmlXPathObjectPtr) 2304 cache->miscObjs->items[--cache->miscObjs->number]; 2305 ret->type = XPATH_NODESET; 2306 ret->nodesetval = val; 2307 #ifdef XP_DEBUG_OBJ_USAGE 2308 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 2309 #endif 2310 return(ret); 2311 } 2312 } 2313 2314 return(xmlXPathWrapNodeSet(val)); 2315 2316 } 2317 2318 /** 2319 * xmlXPathCacheWrapString: 2320 * @ctxt: the XPath context 2321 * @val: the xmlChar * value 2322 * 2323 * This is the cached version of xmlXPathWrapString(). 2324 * Wraps the @val string into an XPath object. 2325 * 2326 * Returns the created or reused object. 2327 */ 2328 static xmlXPathObjectPtr 2329 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val) 2330 { 2331 if ((ctxt != NULL) && (ctxt->cache != NULL)) { 2332 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2333 2334 if ((cache->stringObjs != NULL) && 2335 (cache->stringObjs->number != 0)) 2336 { 2337 2338 xmlXPathObjectPtr ret; 2339 2340 ret = (xmlXPathObjectPtr) 2341 cache->stringObjs->items[--cache->stringObjs->number]; 2342 ret->type = XPATH_STRING; 2343 ret->stringval = val; 2344 #ifdef XP_DEBUG_OBJ_USAGE 2345 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2346 #endif 2347 return(ret); 2348 } else if ((cache->miscObjs != NULL) && 2349 (cache->miscObjs->number != 0)) 2350 { 2351 xmlXPathObjectPtr ret; 2352 /* 2353 * Fallback to misc-cache. 2354 */ 2355 ret = (xmlXPathObjectPtr) 2356 cache->miscObjs->items[--cache->miscObjs->number]; 2357 2358 ret->type = XPATH_STRING; 2359 ret->stringval = val; 2360 #ifdef XP_DEBUG_OBJ_USAGE 2361 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2362 #endif 2363 return(ret); 2364 } 2365 } 2366 return(xmlXPathWrapString(val)); 2367 } 2368 2369 /** 2370 * xmlXPathCacheNewNodeSet: 2371 * @ctxt: the XPath context 2372 * @val: the NodePtr value 2373 * 2374 * This is the cached version of xmlXPathNewNodeSet(). 2375 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize 2376 * it with the single Node @val 2377 * 2378 * Returns the created or reused object. 2379 */ 2380 static xmlXPathObjectPtr 2381 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val) 2382 { 2383 if ((ctxt != NULL) && (ctxt->cache)) { 2384 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2385 2386 if ((cache->nodesetObjs != NULL) && 2387 (cache->nodesetObjs->number != 0)) 2388 { 2389 xmlXPathObjectPtr ret; 2390 /* 2391 * Use the nodset-cache. 2392 */ 2393 ret = (xmlXPathObjectPtr) 2394 cache->nodesetObjs->items[--cache->nodesetObjs->number]; 2395 ret->type = XPATH_NODESET; 2396 ret->boolval = 0; 2397 if (val) { 2398 if ((ret->nodesetval->nodeMax == 0) || 2399 (val->type == XML_NAMESPACE_DECL)) 2400 { 2401 xmlXPathNodeSetAddUnique(ret->nodesetval, val); 2402 } else { 2403 ret->nodesetval->nodeTab[0] = val; 2404 ret->nodesetval->nodeNr = 1; 2405 } 2406 } 2407 #ifdef XP_DEBUG_OBJ_USAGE 2408 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 2409 #endif 2410 return(ret); 2411 } else if ((cache->miscObjs != NULL) && 2412 (cache->miscObjs->number != 0)) 2413 { 2414 xmlXPathObjectPtr ret; 2415 /* 2416 * Fallback to misc-cache. 2417 */ 2418 2419 ret = (xmlXPathObjectPtr) 2420 cache->miscObjs->items[--cache->miscObjs->number]; 2421 2422 ret->type = XPATH_NODESET; 2423 ret->boolval = 0; 2424 ret->nodesetval = xmlXPathNodeSetCreate(val); 2425 if (ret->nodesetval == NULL) { 2426 ctxt->lastError.domain = XML_FROM_XPATH; 2427 ctxt->lastError.code = XML_ERR_NO_MEMORY; 2428 return(NULL); 2429 } 2430 #ifdef XP_DEBUG_OBJ_USAGE 2431 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 2432 #endif 2433 return(ret); 2434 } 2435 } 2436 return(xmlXPathNewNodeSet(val)); 2437 } 2438 2439 /** 2440 * xmlXPathCacheNewCString: 2441 * @ctxt: the XPath context 2442 * @val: the char * value 2443 * 2444 * This is the cached version of xmlXPathNewCString(). 2445 * Acquire an xmlXPathObjectPtr of type string and of value @val 2446 * 2447 * Returns the created or reused object. 2448 */ 2449 static xmlXPathObjectPtr 2450 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val) 2451 { 2452 if ((ctxt != NULL) && (ctxt->cache)) { 2453 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2454 2455 if ((cache->stringObjs != NULL) && 2456 (cache->stringObjs->number != 0)) 2457 { 2458 xmlXPathObjectPtr ret; 2459 2460 ret = (xmlXPathObjectPtr) 2461 cache->stringObjs->items[--cache->stringObjs->number]; 2462 2463 ret->type = XPATH_STRING; 2464 ret->stringval = xmlStrdup(BAD_CAST val); 2465 #ifdef XP_DEBUG_OBJ_USAGE 2466 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2467 #endif 2468 return(ret); 2469 } else if ((cache->miscObjs != NULL) && 2470 (cache->miscObjs->number != 0)) 2471 { 2472 xmlXPathObjectPtr ret; 2473 2474 ret = (xmlXPathObjectPtr) 2475 cache->miscObjs->items[--cache->miscObjs->number]; 2476 2477 ret->type = XPATH_STRING; 2478 ret->stringval = xmlStrdup(BAD_CAST val); 2479 #ifdef XP_DEBUG_OBJ_USAGE 2480 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2481 #endif 2482 return(ret); 2483 } 2484 } 2485 return(xmlXPathNewCString(val)); 2486 } 2487 2488 /** 2489 * xmlXPathCacheNewString: 2490 * @ctxt: the XPath context 2491 * @val: the xmlChar * value 2492 * 2493 * This is the cached version of xmlXPathNewString(). 2494 * Acquire an xmlXPathObjectPtr of type string and of value @val 2495 * 2496 * Returns the created or reused object. 2497 */ 2498 static xmlXPathObjectPtr 2499 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val) 2500 { 2501 if ((ctxt != NULL) && (ctxt->cache)) { 2502 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2503 2504 if ((cache->stringObjs != NULL) && 2505 (cache->stringObjs->number != 0)) 2506 { 2507 xmlXPathObjectPtr ret; 2508 2509 ret = (xmlXPathObjectPtr) 2510 cache->stringObjs->items[--cache->stringObjs->number]; 2511 ret->type = XPATH_STRING; 2512 if (val != NULL) 2513 ret->stringval = xmlStrdup(val); 2514 else 2515 ret->stringval = xmlStrdup((const xmlChar *)""); 2516 #ifdef XP_DEBUG_OBJ_USAGE 2517 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2518 #endif 2519 return(ret); 2520 } else if ((cache->miscObjs != NULL) && 2521 (cache->miscObjs->number != 0)) 2522 { 2523 xmlXPathObjectPtr ret; 2524 2525 ret = (xmlXPathObjectPtr) 2526 cache->miscObjs->items[--cache->miscObjs->number]; 2527 2528 ret->type = XPATH_STRING; 2529 if (val != NULL) 2530 ret->stringval = xmlStrdup(val); 2531 else 2532 ret->stringval = xmlStrdup((const xmlChar *)""); 2533 #ifdef XP_DEBUG_OBJ_USAGE 2534 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2535 #endif 2536 return(ret); 2537 } 2538 } 2539 return(xmlXPathNewString(val)); 2540 } 2541 2542 /** 2543 * xmlXPathCacheNewBoolean: 2544 * @ctxt: the XPath context 2545 * @val: the boolean value 2546 * 2547 * This is the cached version of xmlXPathNewBoolean(). 2548 * Acquires an xmlXPathObjectPtr of type boolean and of value @val 2549 * 2550 * Returns the created or reused object. 2551 */ 2552 static xmlXPathObjectPtr 2553 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val) 2554 { 2555 if ((ctxt != NULL) && (ctxt->cache)) { 2556 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2557 2558 if ((cache->booleanObjs != NULL) && 2559 (cache->booleanObjs->number != 0)) 2560 { 2561 xmlXPathObjectPtr ret; 2562 2563 ret = (xmlXPathObjectPtr) 2564 cache->booleanObjs->items[--cache->booleanObjs->number]; 2565 ret->type = XPATH_BOOLEAN; 2566 ret->boolval = (val != 0); 2567 #ifdef XP_DEBUG_OBJ_USAGE 2568 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN); 2569 #endif 2570 return(ret); 2571 } else if ((cache->miscObjs != NULL) && 2572 (cache->miscObjs->number != 0)) 2573 { 2574 xmlXPathObjectPtr ret; 2575 2576 ret = (xmlXPathObjectPtr) 2577 cache->miscObjs->items[--cache->miscObjs->number]; 2578 2579 ret->type = XPATH_BOOLEAN; 2580 ret->boolval = (val != 0); 2581 #ifdef XP_DEBUG_OBJ_USAGE 2582 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN); 2583 #endif 2584 return(ret); 2585 } 2586 } 2587 return(xmlXPathNewBoolean(val)); 2588 } 2589 2590 /** 2591 * xmlXPathCacheNewFloat: 2592 * @ctxt: the XPath context 2593 * @val: the double value 2594 * 2595 * This is the cached version of xmlXPathNewFloat(). 2596 * Acquires an xmlXPathObjectPtr of type double and of value @val 2597 * 2598 * Returns the created or reused object. 2599 */ 2600 static xmlXPathObjectPtr 2601 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val) 2602 { 2603 if ((ctxt != NULL) && (ctxt->cache)) { 2604 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2605 2606 if ((cache->numberObjs != NULL) && 2607 (cache->numberObjs->number != 0)) 2608 { 2609 xmlXPathObjectPtr ret; 2610 2611 ret = (xmlXPathObjectPtr) 2612 cache->numberObjs->items[--cache->numberObjs->number]; 2613 ret->type = XPATH_NUMBER; 2614 ret->floatval = val; 2615 #ifdef XP_DEBUG_OBJ_USAGE 2616 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER); 2617 #endif 2618 return(ret); 2619 } else if ((cache->miscObjs != NULL) && 2620 (cache->miscObjs->number != 0)) 2621 { 2622 xmlXPathObjectPtr ret; 2623 2624 ret = (xmlXPathObjectPtr) 2625 cache->miscObjs->items[--cache->miscObjs->number]; 2626 2627 ret->type = XPATH_NUMBER; 2628 ret->floatval = val; 2629 #ifdef XP_DEBUG_OBJ_USAGE 2630 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER); 2631 #endif 2632 return(ret); 2633 } 2634 } 2635 return(xmlXPathNewFloat(val)); 2636 } 2637 2638 /** 2639 * xmlXPathCacheConvertString: 2640 * @ctxt: the XPath context 2641 * @val: an XPath object 2642 * 2643 * This is the cached version of xmlXPathConvertString(). 2644 * Converts an existing object to its string() equivalent 2645 * 2646 * Returns a created or reused object, the old one is freed (cached) 2647 * (or the operation is done directly on @val) 2648 */ 2649 2650 static xmlXPathObjectPtr 2651 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 2652 xmlChar *res = NULL; 2653 2654 if (val == NULL) 2655 return(xmlXPathCacheNewCString(ctxt, "")); 2656 2657 switch (val->type) { 2658 case XPATH_UNDEFINED: 2659 #ifdef DEBUG_EXPR 2660 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n"); 2661 #endif 2662 break; 2663 case XPATH_NODESET: 2664 case XPATH_XSLT_TREE: 2665 res = xmlXPathCastNodeSetToString(val->nodesetval); 2666 break; 2667 case XPATH_STRING: 2668 return(val); 2669 case XPATH_BOOLEAN: 2670 res = xmlXPathCastBooleanToString(val->boolval); 2671 break; 2672 case XPATH_NUMBER: 2673 res = xmlXPathCastNumberToString(val->floatval); 2674 break; 2675 case XPATH_USERS: 2676 case XPATH_POINT: 2677 case XPATH_RANGE: 2678 case XPATH_LOCATIONSET: 2679 TODO; 2680 break; 2681 } 2682 xmlXPathReleaseObject(ctxt, val); 2683 if (res == NULL) 2684 return(xmlXPathCacheNewCString(ctxt, "")); 2685 return(xmlXPathCacheWrapString(ctxt, res)); 2686 } 2687 2688 /** 2689 * xmlXPathCacheObjectCopy: 2690 * @ctxt: the XPath context 2691 * @val: the original object 2692 * 2693 * This is the cached version of xmlXPathObjectCopy(). 2694 * Acquire a copy of a given object 2695 * 2696 * Returns a created or reused created object. 2697 */ 2698 static xmlXPathObjectPtr 2699 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) 2700 { 2701 if (val == NULL) 2702 return(NULL); 2703 2704 if (XP_HAS_CACHE(ctxt)) { 2705 switch (val->type) { 2706 case XPATH_NODESET: 2707 return(xmlXPathCacheWrapNodeSet(ctxt, 2708 xmlXPathNodeSetMerge(NULL, val->nodesetval))); 2709 case XPATH_STRING: 2710 return(xmlXPathCacheNewString(ctxt, val->stringval)); 2711 case XPATH_BOOLEAN: 2712 return(xmlXPathCacheNewBoolean(ctxt, val->boolval)); 2713 case XPATH_NUMBER: 2714 return(xmlXPathCacheNewFloat(ctxt, val->floatval)); 2715 default: 2716 break; 2717 } 2718 } 2719 return(xmlXPathObjectCopy(val)); 2720 } 2721 2722 /** 2723 * xmlXPathCacheConvertBoolean: 2724 * @ctxt: the XPath context 2725 * @val: an XPath object 2726 * 2727 * This is the cached version of xmlXPathConvertBoolean(). 2728 * Converts an existing object to its boolean() equivalent 2729 * 2730 * Returns a created or reused object, the old one is freed (or the operation 2731 * is done directly on @val) 2732 */ 2733 static xmlXPathObjectPtr 2734 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 2735 xmlXPathObjectPtr ret; 2736 2737 if (val == NULL) 2738 return(xmlXPathCacheNewBoolean(ctxt, 0)); 2739 if (val->type == XPATH_BOOLEAN) 2740 return(val); 2741 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val)); 2742 xmlXPathReleaseObject(ctxt, val); 2743 return(ret); 2744 } 2745 2746 /** 2747 * xmlXPathCacheConvertNumber: 2748 * @ctxt: the XPath context 2749 * @val: an XPath object 2750 * 2751 * This is the cached version of xmlXPathConvertNumber(). 2752 * Converts an existing object to its number() equivalent 2753 * 2754 * Returns a created or reused object, the old one is freed (or the operation 2755 * is done directly on @val) 2756 */ 2757 static xmlXPathObjectPtr 2758 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 2759 xmlXPathObjectPtr ret; 2760 2761 if (val == NULL) 2762 return(xmlXPathCacheNewFloat(ctxt, 0.0)); 2763 if (val->type == XPATH_NUMBER) 2764 return(val); 2765 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val)); 2766 xmlXPathReleaseObject(ctxt, val); 2767 return(ret); 2768 } 2769 2770 /************************************************************************ 2771 * * 2772 * Parser stacks related functions and macros * 2773 * * 2774 ************************************************************************/ 2775 2776 /** 2777 * xmlXPathSetFrame: 2778 * @ctxt: an XPath parser context 2779 * 2780 * Set the callee evaluation frame 2781 * 2782 * Returns the previous frame value to be restored once done 2783 */ 2784 static int 2785 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) { 2786 int ret; 2787 2788 if (ctxt == NULL) 2789 return(0); 2790 ret = ctxt->valueFrame; 2791 ctxt->valueFrame = ctxt->valueNr; 2792 return(ret); 2793 } 2794 2795 /** 2796 * xmlXPathPopFrame: 2797 * @ctxt: an XPath parser context 2798 * @frame: the previous frame value 2799 * 2800 * Remove the callee evaluation frame 2801 */ 2802 static void 2803 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) { 2804 if (ctxt == NULL) 2805 return; 2806 if (ctxt->valueNr < ctxt->valueFrame) { 2807 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR); 2808 } 2809 ctxt->valueFrame = frame; 2810 } 2811 2812 /** 2813 * valuePop: 2814 * @ctxt: an XPath evaluation context 2815 * 2816 * Pops the top XPath object from the value stack 2817 * 2818 * Returns the XPath object just removed 2819 */ 2820 xmlXPathObjectPtr 2821 valuePop(xmlXPathParserContextPtr ctxt) 2822 { 2823 xmlXPathObjectPtr ret; 2824 2825 if ((ctxt == NULL) || (ctxt->valueNr <= 0)) 2826 return (NULL); 2827 2828 if (ctxt->valueNr <= ctxt->valueFrame) { 2829 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR); 2830 return (NULL); 2831 } 2832 2833 ctxt->valueNr--; 2834 if (ctxt->valueNr > 0) 2835 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1]; 2836 else 2837 ctxt->value = NULL; 2838 ret = ctxt->valueTab[ctxt->valueNr]; 2839 ctxt->valueTab[ctxt->valueNr] = NULL; 2840 return (ret); 2841 } 2842 /** 2843 * valuePush: 2844 * @ctxt: an XPath evaluation context 2845 * @value: the XPath object 2846 * 2847 * Pushes a new XPath object on top of the value stack 2848 * 2849 * returns the number of items on the value stack 2850 */ 2851 int 2852 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value) 2853 { 2854 if ((ctxt == NULL) || (value == NULL)) return(-1); 2855 if (ctxt->valueNr >= ctxt->valueMax) { 2856 xmlXPathObjectPtr *tmp; 2857 2858 if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) { 2859 xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n"); 2860 ctxt->error = XPATH_MEMORY_ERROR; 2861 return (0); 2862 } 2863 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab, 2864 2 * ctxt->valueMax * 2865 sizeof(ctxt->valueTab[0])); 2866 if (tmp == NULL) { 2867 xmlXPathErrMemory(NULL, "pushing value\n"); 2868 ctxt->error = XPATH_MEMORY_ERROR; 2869 return (0); 2870 } 2871 ctxt->valueMax *= 2; 2872 ctxt->valueTab = tmp; 2873 } 2874 ctxt->valueTab[ctxt->valueNr] = value; 2875 ctxt->value = value; 2876 return (ctxt->valueNr++); 2877 } 2878 2879 /** 2880 * xmlXPathPopBoolean: 2881 * @ctxt: an XPath parser context 2882 * 2883 * Pops a boolean from the stack, handling conversion if needed. 2884 * Check error with #xmlXPathCheckError. 2885 * 2886 * Returns the boolean 2887 */ 2888 int 2889 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) { 2890 xmlXPathObjectPtr obj; 2891 int ret; 2892 2893 obj = valuePop(ctxt); 2894 if (obj == NULL) { 2895 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2896 return(0); 2897 } 2898 if (obj->type != XPATH_BOOLEAN) 2899 ret = xmlXPathCastToBoolean(obj); 2900 else 2901 ret = obj->boolval; 2902 xmlXPathReleaseObject(ctxt->context, obj); 2903 return(ret); 2904 } 2905 2906 /** 2907 * xmlXPathPopNumber: 2908 * @ctxt: an XPath parser context 2909 * 2910 * Pops a number from the stack, handling conversion if needed. 2911 * Check error with #xmlXPathCheckError. 2912 * 2913 * Returns the number 2914 */ 2915 double 2916 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) { 2917 xmlXPathObjectPtr obj; 2918 double ret; 2919 2920 obj = valuePop(ctxt); 2921 if (obj == NULL) { 2922 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2923 return(0); 2924 } 2925 if (obj->type != XPATH_NUMBER) 2926 ret = xmlXPathCastToNumber(obj); 2927 else 2928 ret = obj->floatval; 2929 xmlXPathReleaseObject(ctxt->context, obj); 2930 return(ret); 2931 } 2932 2933 /** 2934 * xmlXPathPopString: 2935 * @ctxt: an XPath parser context 2936 * 2937 * Pops a string from the stack, handling conversion if needed. 2938 * Check error with #xmlXPathCheckError. 2939 * 2940 * Returns the string 2941 */ 2942 xmlChar * 2943 xmlXPathPopString (xmlXPathParserContextPtr ctxt) { 2944 xmlXPathObjectPtr obj; 2945 xmlChar * ret; 2946 2947 obj = valuePop(ctxt); 2948 if (obj == NULL) { 2949 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2950 return(NULL); 2951 } 2952 ret = xmlXPathCastToString(obj); /* this does required strdup */ 2953 /* TODO: needs refactoring somewhere else */ 2954 if (obj->stringval == ret) 2955 obj->stringval = NULL; 2956 xmlXPathReleaseObject(ctxt->context, obj); 2957 return(ret); 2958 } 2959 2960 /** 2961 * xmlXPathPopNodeSet: 2962 * @ctxt: an XPath parser context 2963 * 2964 * Pops a node-set from the stack, handling conversion if needed. 2965 * Check error with #xmlXPathCheckError. 2966 * 2967 * Returns the node-set 2968 */ 2969 xmlNodeSetPtr 2970 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) { 2971 xmlXPathObjectPtr obj; 2972 xmlNodeSetPtr ret; 2973 2974 if (ctxt == NULL) return(NULL); 2975 if (ctxt->value == NULL) { 2976 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2977 return(NULL); 2978 } 2979 if (!xmlXPathStackIsNodeSet(ctxt)) { 2980 xmlXPathSetTypeError(ctxt); 2981 return(NULL); 2982 } 2983 obj = valuePop(ctxt); 2984 ret = obj->nodesetval; 2985 #if 0 2986 /* to fix memory leak of not clearing obj->user */ 2987 if (obj->boolval && obj->user != NULL) 2988 xmlFreeNodeList((xmlNodePtr) obj->user); 2989 #endif 2990 obj->nodesetval = NULL; 2991 xmlXPathReleaseObject(ctxt->context, obj); 2992 return(ret); 2993 } 2994 2995 /** 2996 * xmlXPathPopExternal: 2997 * @ctxt: an XPath parser context 2998 * 2999 * Pops an external object from the stack, handling conversion if needed. 3000 * Check error with #xmlXPathCheckError. 3001 * 3002 * Returns the object 3003 */ 3004 void * 3005 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) { 3006 xmlXPathObjectPtr obj; 3007 void * ret; 3008 3009 if ((ctxt == NULL) || (ctxt->value == NULL)) { 3010 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 3011 return(NULL); 3012 } 3013 if (ctxt->value->type != XPATH_USERS) { 3014 xmlXPathSetTypeError(ctxt); 3015 return(NULL); 3016 } 3017 obj = valuePop(ctxt); 3018 ret = obj->user; 3019 obj->user = NULL; 3020 xmlXPathReleaseObject(ctxt->context, obj); 3021 return(ret); 3022 } 3023 3024 /* 3025 * Macros for accessing the content. Those should be used only by the parser, 3026 * and not exported. 3027 * 3028 * Dirty macros, i.e. one need to make assumption on the context to use them 3029 * 3030 * CUR_PTR return the current pointer to the xmlChar to be parsed. 3031 * CUR returns the current xmlChar value, i.e. a 8 bit value 3032 * in ISO-Latin or UTF-8. 3033 * This should be used internally by the parser 3034 * only to compare to ASCII values otherwise it would break when 3035 * running with UTF-8 encoding. 3036 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only 3037 * to compare on ASCII based substring. 3038 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined 3039 * strings within the parser. 3040 * CURRENT Returns the current char value, with the full decoding of 3041 * UTF-8 if we are using this mode. It returns an int. 3042 * NEXT Skip to the next character, this does the proper decoding 3043 * in UTF-8 mode. It also pop-up unfinished entities on the fly. 3044 * It returns the pointer to the current xmlChar. 3045 */ 3046 3047 #define CUR (*ctxt->cur) 3048 #define SKIP(val) ctxt->cur += (val) 3049 #define NXT(val) ctxt->cur[(val)] 3050 #define CUR_PTR ctxt->cur 3051 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l) 3052 3053 #define COPY_BUF(l,b,i,v) \ 3054 if (l == 1) b[i++] = (xmlChar) v; \ 3055 else i += xmlCopyChar(l,&b[i],v) 3056 3057 #define NEXTL(l) ctxt->cur += l 3058 3059 #define SKIP_BLANKS \ 3060 while (IS_BLANK_CH(*(ctxt->cur))) NEXT 3061 3062 #define CURRENT (*ctxt->cur) 3063 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur) 3064 3065 3066 #ifndef DBL_DIG 3067 #define DBL_DIG 16 3068 #endif 3069 #ifndef DBL_EPSILON 3070 #define DBL_EPSILON 1E-9 3071 #endif 3072 3073 #define UPPER_DOUBLE 1E9 3074 #define LOWER_DOUBLE 1E-5 3075 #define LOWER_DOUBLE_EXP 5 3076 3077 #define INTEGER_DIGITS DBL_DIG 3078 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP)) 3079 #define EXPONENT_DIGITS (3 + 2) 3080 3081 /** 3082 * xmlXPathFormatNumber: 3083 * @number: number to format 3084 * @buffer: output buffer 3085 * @buffersize: size of output buffer 3086 * 3087 * Convert the number into a string representation. 3088 */ 3089 static void 3090 xmlXPathFormatNumber(double number, char buffer[], int buffersize) 3091 { 3092 switch (xmlXPathIsInf(number)) { 3093 case 1: 3094 if (buffersize > (int)sizeof("Infinity")) 3095 snprintf(buffer, buffersize, "Infinity"); 3096 break; 3097 case -1: 3098 if (buffersize > (int)sizeof("-Infinity")) 3099 snprintf(buffer, buffersize, "-Infinity"); 3100 break; 3101 default: 3102 if (xmlXPathIsNaN(number)) { 3103 if (buffersize > (int)sizeof("NaN")) 3104 snprintf(buffer, buffersize, "NaN"); 3105 } else if (number == 0) { 3106 /* Omit sign for negative zero. */ 3107 snprintf(buffer, buffersize, "0"); 3108 } else if ((number > INT_MIN) && (number < INT_MAX) && 3109 (number == (int) number)) { 3110 char work[30]; 3111 char *ptr, *cur; 3112 int value = (int) number; 3113 3114 ptr = &buffer[0]; 3115 if (value == 0) { 3116 *ptr++ = '0'; 3117 } else { 3118 snprintf(work, 29, "%d", value); 3119 cur = &work[0]; 3120 while ((*cur) && (ptr - buffer < buffersize)) { 3121 *ptr++ = *cur++; 3122 } 3123 } 3124 if (ptr - buffer < buffersize) { 3125 *ptr = 0; 3126 } else if (buffersize > 0) { 3127 ptr--; 3128 *ptr = 0; 3129 } 3130 } else { 3131 /* 3132 For the dimension of work, 3133 DBL_DIG is number of significant digits 3134 EXPONENT is only needed for "scientific notation" 3135 3 is sign, decimal point, and terminating zero 3136 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction 3137 Note that this dimension is slightly (a few characters) 3138 larger than actually necessary. 3139 */ 3140 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP]; 3141 int integer_place, fraction_place; 3142 char *ptr; 3143 char *after_fraction; 3144 double absolute_value; 3145 int size; 3146 3147 absolute_value = fabs(number); 3148 3149 /* 3150 * First choose format - scientific or regular floating point. 3151 * In either case, result is in work, and after_fraction points 3152 * just past the fractional part. 3153 */ 3154 if ( ((absolute_value > UPPER_DOUBLE) || 3155 (absolute_value < LOWER_DOUBLE)) && 3156 (absolute_value != 0.0) ) { 3157 /* Use scientific notation */ 3158 integer_place = DBL_DIG + EXPONENT_DIGITS + 1; 3159 fraction_place = DBL_DIG - 1; 3160 size = snprintf(work, sizeof(work),"%*.*e", 3161 integer_place, fraction_place, number); 3162 while ((size > 0) && (work[size] != 'e')) size--; 3163 3164 } 3165 else { 3166 /* Use regular notation */ 3167 if (absolute_value > 0.0) { 3168 integer_place = (int)log10(absolute_value); 3169 if (integer_place > 0) 3170 fraction_place = DBL_DIG - integer_place - 1; 3171 else 3172 fraction_place = DBL_DIG - integer_place; 3173 } else { 3174 fraction_place = 1; 3175 } 3176 size = snprintf(work, sizeof(work), "%0.*f", 3177 fraction_place, number); 3178 } 3179 3180 /* Remove leading spaces sometimes inserted by snprintf */ 3181 while (work[0] == ' ') { 3182 for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++); 3183 size--; 3184 } 3185 3186 /* Remove fractional trailing zeroes */ 3187 after_fraction = work + size; 3188 ptr = after_fraction; 3189 while (*(--ptr) == '0') 3190 ; 3191 if (*ptr != '.') 3192 ptr++; 3193 while ((*ptr++ = *after_fraction++) != 0); 3194 3195 /* Finally copy result back to caller */ 3196 size = strlen(work) + 1; 3197 if (size > buffersize) { 3198 work[buffersize - 1] = 0; 3199 size = buffersize; 3200 } 3201 memmove(buffer, work, size); 3202 } 3203 break; 3204 } 3205 } 3206 3207 3208 /************************************************************************ 3209 * * 3210 * Routines to handle NodeSets * 3211 * * 3212 ************************************************************************/ 3213 3214 /** 3215 * xmlXPathOrderDocElems: 3216 * @doc: an input document 3217 * 3218 * Call this routine to speed up XPath computation on static documents. 3219 * This stamps all the element nodes with the document order 3220 * Like for line information, the order is kept in the element->content 3221 * field, the value stored is actually - the node number (starting at -1) 3222 * to be able to differentiate from line numbers. 3223 * 3224 * Returns the number of elements found in the document or -1 in case 3225 * of error. 3226 */ 3227 long 3228 xmlXPathOrderDocElems(xmlDocPtr doc) { 3229 ptrdiff_t count = 0; 3230 xmlNodePtr cur; 3231 3232 if (doc == NULL) 3233 return(-1); 3234 cur = doc->children; 3235 while (cur != NULL) { 3236 if (cur->type == XML_ELEMENT_NODE) { 3237 cur->content = (void *) (-(++count)); 3238 if (cur->children != NULL) { 3239 cur = cur->children; 3240 continue; 3241 } 3242 } 3243 if (cur->next != NULL) { 3244 cur = cur->next; 3245 continue; 3246 } 3247 do { 3248 cur = cur->parent; 3249 if (cur == NULL) 3250 break; 3251 if (cur == (xmlNodePtr) doc) { 3252 cur = NULL; 3253 break; 3254 } 3255 if (cur->next != NULL) { 3256 cur = cur->next; 3257 break; 3258 } 3259 } while (cur != NULL); 3260 } 3261 return((long) count); 3262 } 3263 3264 /** 3265 * xmlXPathCmpNodes: 3266 * @node1: the first node 3267 * @node2: the second node 3268 * 3269 * Compare two nodes w.r.t document order 3270 * 3271 * Returns -2 in case of error 1 if first point < second point, 0 if 3272 * it's the same node, -1 otherwise 3273 */ 3274 int 3275 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) { 3276 int depth1, depth2; 3277 int attr1 = 0, attr2 = 0; 3278 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL; 3279 xmlNodePtr cur, root; 3280 3281 if ((node1 == NULL) || (node2 == NULL)) 3282 return(-2); 3283 /* 3284 * a couple of optimizations which will avoid computations in most cases 3285 */ 3286 if (node1 == node2) /* trivial case */ 3287 return(0); 3288 if (node1->type == XML_ATTRIBUTE_NODE) { 3289 attr1 = 1; 3290 attrNode1 = node1; 3291 node1 = node1->parent; 3292 } 3293 if (node2->type == XML_ATTRIBUTE_NODE) { 3294 attr2 = 1; 3295 attrNode2 = node2; 3296 node2 = node2->parent; 3297 } 3298 if (node1 == node2) { 3299 if (attr1 == attr2) { 3300 /* not required, but we keep attributes in order */ 3301 if (attr1 != 0) { 3302 cur = attrNode2->prev; 3303 while (cur != NULL) { 3304 if (cur == attrNode1) 3305 return (1); 3306 cur = cur->prev; 3307 } 3308 return (-1); 3309 } 3310 return(0); 3311 } 3312 if (attr2 == 1) 3313 return(1); 3314 return(-1); 3315 } 3316 if ((node1->type == XML_NAMESPACE_DECL) || 3317 (node2->type == XML_NAMESPACE_DECL)) 3318 return(1); 3319 if (node1 == node2->prev) 3320 return(1); 3321 if (node1 == node2->next) 3322 return(-1); 3323 3324 /* 3325 * Speedup using document order if availble. 3326 */ 3327 if ((node1->type == XML_ELEMENT_NODE) && 3328 (node2->type == XML_ELEMENT_NODE) && 3329 (0 > (ptrdiff_t) node1->content) && 3330 (0 > (ptrdiff_t) node2->content) && 3331 (node1->doc == node2->doc)) { 3332 ptrdiff_t l1, l2; 3333 3334 l1 = -((ptrdiff_t) node1->content); 3335 l2 = -((ptrdiff_t) node2->content); 3336 if (l1 < l2) 3337 return(1); 3338 if (l1 > l2) 3339 return(-1); 3340 } 3341 3342 /* 3343 * compute depth to root 3344 */ 3345 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) { 3346 if (cur->parent == node1) 3347 return(1); 3348 depth2++; 3349 } 3350 root = cur; 3351 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) { 3352 if (cur->parent == node2) 3353 return(-1); 3354 depth1++; 3355 } 3356 /* 3357 * Distinct document (or distinct entities :-( ) case. 3358 */ 3359 if (root != cur) { 3360 return(-2); 3361 } 3362 /* 3363 * get the nearest common ancestor. 3364 */ 3365 while (depth1 > depth2) { 3366 depth1--; 3367 node1 = node1->parent; 3368 } 3369 while (depth2 > depth1) { 3370 depth2--; 3371 node2 = node2->parent; 3372 } 3373 while (node1->parent != node2->parent) { 3374 node1 = node1->parent; 3375 node2 = node2->parent; 3376 /* should not happen but just in case ... */ 3377 if ((node1 == NULL) || (node2 == NULL)) 3378 return(-2); 3379 } 3380 /* 3381 * Find who's first. 3382 */ 3383 if (node1 == node2->prev) 3384 return(1); 3385 if (node1 == node2->next) 3386 return(-1); 3387 /* 3388 * Speedup using document order if availble. 3389 */ 3390 if ((node1->type == XML_ELEMENT_NODE) && 3391 (node2->type == XML_ELEMENT_NODE) && 3392 (0 > (ptrdiff_t) node1->content) && 3393 (0 > (ptrdiff_t) node2->content) && 3394 (node1->doc == node2->doc)) { 3395 ptrdiff_t l1, l2; 3396 3397 l1 = -((ptrdiff_t) node1->content); 3398 l2 = -((ptrdiff_t) node2->content); 3399 if (l1 < l2) 3400 return(1); 3401 if (l1 > l2) 3402 return(-1); 3403 } 3404 3405 for (cur = node1->next;cur != NULL;cur = cur->next) 3406 if (cur == node2) 3407 return(1); 3408 return(-1); /* assume there is no sibling list corruption */ 3409 } 3410 3411 /** 3412 * xmlXPathNodeSetSort: 3413 * @set: the node set 3414 * 3415 * Sort the node set in document order 3416 */ 3417 void 3418 xmlXPathNodeSetSort(xmlNodeSetPtr set) { 3419 #ifndef WITH_TIM_SORT 3420 int i, j, incr, len; 3421 xmlNodePtr tmp; 3422 #endif 3423 3424 if (set == NULL) 3425 return; 3426 3427 #ifndef WITH_TIM_SORT 3428 /* 3429 * Use the old Shell's sort implementation to sort the node-set 3430 * Timsort ought to be quite faster 3431 */ 3432 len = set->nodeNr; 3433 for (incr = len / 2; incr > 0; incr /= 2) { 3434 for (i = incr; i < len; i++) { 3435 j = i - incr; 3436 while (j >= 0) { 3437 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 3438 if (xmlXPathCmpNodesExt(set->nodeTab[j], 3439 set->nodeTab[j + incr]) == -1) 3440 #else 3441 if (xmlXPathCmpNodes(set->nodeTab[j], 3442 set->nodeTab[j + incr]) == -1) 3443 #endif 3444 { 3445 tmp = set->nodeTab[j]; 3446 set->nodeTab[j] = set->nodeTab[j + incr]; 3447 set->nodeTab[j + incr] = tmp; 3448 j -= incr; 3449 } else 3450 break; 3451 } 3452 } 3453 } 3454 #else /* WITH_TIM_SORT */ 3455 libxml_domnode_tim_sort(set->nodeTab, set->nodeNr); 3456 #endif /* WITH_TIM_SORT */ 3457 } 3458 3459 #define XML_NODESET_DEFAULT 10 3460 /** 3461 * xmlXPathNodeSetDupNs: 3462 * @node: the parent node of the namespace XPath node 3463 * @ns: the libxml namespace declaration node. 3464 * 3465 * Namespace node in libxml don't match the XPath semantic. In a node set 3466 * the namespace nodes are duplicated and the next pointer is set to the 3467 * parent node in the XPath semantic. 3468 * 3469 * Returns the newly created object. 3470 */ 3471 static xmlNodePtr 3472 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) { 3473 xmlNsPtr cur; 3474 3475 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) 3476 return(NULL); 3477 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) 3478 return((xmlNodePtr) ns); 3479 3480 /* 3481 * Allocate a new Namespace and fill the fields. 3482 */ 3483 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); 3484 if (cur == NULL) { 3485 xmlXPathErrMemory(NULL, "duplicating namespace\n"); 3486 return(NULL); 3487 } 3488 memset(cur, 0, sizeof(xmlNs)); 3489 cur->type = XML_NAMESPACE_DECL; 3490 if (ns->href != NULL) 3491 cur->href = xmlStrdup(ns->href); 3492 if (ns->prefix != NULL) 3493 cur->prefix = xmlStrdup(ns->prefix); 3494 cur->next = (xmlNsPtr) node; 3495 return((xmlNodePtr) cur); 3496 } 3497 3498 /** 3499 * xmlXPathNodeSetFreeNs: 3500 * @ns: the XPath namespace node found in a nodeset. 3501 * 3502 * Namespace nodes in libxml don't match the XPath semantic. In a node set 3503 * the namespace nodes are duplicated and the next pointer is set to the 3504 * parent node in the XPath semantic. Check if such a node needs to be freed 3505 */ 3506 void 3507 xmlXPathNodeSetFreeNs(xmlNsPtr ns) { 3508 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) 3509 return; 3510 3511 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) { 3512 if (ns->href != NULL) 3513 xmlFree((xmlChar *)ns->href); 3514 if (ns->prefix != NULL) 3515 xmlFree((xmlChar *)ns->prefix); 3516 xmlFree(ns); 3517 } 3518 } 3519 3520 /** 3521 * xmlXPathNodeSetCreate: 3522 * @val: an initial xmlNodePtr, or NULL 3523 * 3524 * Create a new xmlNodeSetPtr of type double and of value @val 3525 * 3526 * Returns the newly created object. 3527 */ 3528 xmlNodeSetPtr 3529 xmlXPathNodeSetCreate(xmlNodePtr val) { 3530 xmlNodeSetPtr ret; 3531 3532 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet)); 3533 if (ret == NULL) { 3534 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3535 return(NULL); 3536 } 3537 memset(ret, 0 , (size_t) sizeof(xmlNodeSet)); 3538 if (val != NULL) { 3539 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3540 sizeof(xmlNodePtr)); 3541 if (ret->nodeTab == NULL) { 3542 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3543 xmlFree(ret); 3544 return(NULL); 3545 } 3546 memset(ret->nodeTab, 0 , 3547 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3548 ret->nodeMax = XML_NODESET_DEFAULT; 3549 if (val->type == XML_NAMESPACE_DECL) { 3550 xmlNsPtr ns = (xmlNsPtr) val; 3551 3552 ret->nodeTab[ret->nodeNr++] = 3553 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3554 } else 3555 ret->nodeTab[ret->nodeNr++] = val; 3556 } 3557 return(ret); 3558 } 3559 3560 /** 3561 * xmlXPathNodeSetCreateSize: 3562 * @size: the initial size of the set 3563 * 3564 * Create a new xmlNodeSetPtr of type double and of value @val 3565 * 3566 * Returns the newly created object. 3567 */ 3568 static xmlNodeSetPtr 3569 xmlXPathNodeSetCreateSize(int size) { 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 (size < XML_NODESET_DEFAULT) 3579 size = XML_NODESET_DEFAULT; 3580 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * 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 , size * (size_t) sizeof(xmlNodePtr)); 3587 ret->nodeMax = size; 3588 return(ret); 3589 } 3590 3591 /** 3592 * xmlXPathNodeSetContains: 3593 * @cur: the node-set 3594 * @val: the node 3595 * 3596 * checks whether @cur contains @val 3597 * 3598 * Returns true (1) if @cur contains @val, false (0) otherwise 3599 */ 3600 int 3601 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) { 3602 int i; 3603 3604 if ((cur == NULL) || (val == NULL)) return(0); 3605 if (val->type == XML_NAMESPACE_DECL) { 3606 for (i = 0; i < cur->nodeNr; i++) { 3607 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) { 3608 xmlNsPtr ns1, ns2; 3609 3610 ns1 = (xmlNsPtr) val; 3611 ns2 = (xmlNsPtr) cur->nodeTab[i]; 3612 if (ns1 == ns2) 3613 return(1); 3614 if ((ns1->next != NULL) && (ns2->next == ns1->next) && 3615 (xmlStrEqual(ns1->prefix, ns2->prefix))) 3616 return(1); 3617 } 3618 } 3619 } else { 3620 for (i = 0; i < cur->nodeNr; i++) { 3621 if (cur->nodeTab[i] == val) 3622 return(1); 3623 } 3624 } 3625 return(0); 3626 } 3627 3628 /** 3629 * xmlXPathNodeSetAddNs: 3630 * @cur: the initial node set 3631 * @node: the hosting node 3632 * @ns: a the namespace node 3633 * 3634 * add a new namespace node to an existing NodeSet 3635 * 3636 * Returns 0 in case of success and -1 in case of error 3637 */ 3638 int 3639 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) { 3640 int i; 3641 3642 3643 if ((cur == NULL) || (ns == NULL) || (node == NULL) || 3644 (ns->type != XML_NAMESPACE_DECL) || 3645 (node->type != XML_ELEMENT_NODE)) 3646 return(-1); 3647 3648 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3649 /* 3650 * prevent duplicates 3651 */ 3652 for (i = 0;i < cur->nodeNr;i++) { 3653 if ((cur->nodeTab[i] != NULL) && 3654 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) && 3655 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) && 3656 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix))) 3657 return(0); 3658 } 3659 3660 /* 3661 * grow the nodeTab if needed 3662 */ 3663 if (cur->nodeMax == 0) { 3664 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3665 sizeof(xmlNodePtr)); 3666 if (cur->nodeTab == NULL) { 3667 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3668 return(-1); 3669 } 3670 memset(cur->nodeTab, 0 , 3671 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3672 cur->nodeMax = XML_NODESET_DEFAULT; 3673 } else if (cur->nodeNr == cur->nodeMax) { 3674 xmlNodePtr *temp; 3675 3676 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 3677 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n"); 3678 return(-1); 3679 } 3680 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 * 3681 sizeof(xmlNodePtr)); 3682 if (temp == NULL) { 3683 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3684 return(-1); 3685 } 3686 cur->nodeMax *= 2; 3687 cur->nodeTab = temp; 3688 } 3689 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns); 3690 return(0); 3691 } 3692 3693 /** 3694 * xmlXPathNodeSetAdd: 3695 * @cur: the initial node set 3696 * @val: a new xmlNodePtr 3697 * 3698 * add a new xmlNodePtr to an existing NodeSet 3699 * 3700 * Returns 0 in case of success, and -1 in case of error 3701 */ 3702 int 3703 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) { 3704 int i; 3705 3706 if ((cur == NULL) || (val == NULL)) return(-1); 3707 3708 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3709 /* 3710 * prevent duplicates 3711 */ 3712 for (i = 0;i < cur->nodeNr;i++) 3713 if (cur->nodeTab[i] == val) return(0); 3714 3715 /* 3716 * grow the nodeTab if needed 3717 */ 3718 if (cur->nodeMax == 0) { 3719 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3720 sizeof(xmlNodePtr)); 3721 if (cur->nodeTab == NULL) { 3722 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3723 return(-1); 3724 } 3725 memset(cur->nodeTab, 0 , 3726 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3727 cur->nodeMax = XML_NODESET_DEFAULT; 3728 } else if (cur->nodeNr == cur->nodeMax) { 3729 xmlNodePtr *temp; 3730 3731 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 3732 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n"); 3733 return(-1); 3734 } 3735 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 * 3736 sizeof(xmlNodePtr)); 3737 if (temp == NULL) { 3738 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3739 return(-1); 3740 } 3741 cur->nodeMax *= 2; 3742 cur->nodeTab = temp; 3743 } 3744 if (val->type == XML_NAMESPACE_DECL) { 3745 xmlNsPtr ns = (xmlNsPtr) val; 3746 3747 cur->nodeTab[cur->nodeNr++] = 3748 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3749 } else 3750 cur->nodeTab[cur->nodeNr++] = val; 3751 return(0); 3752 } 3753 3754 /** 3755 * xmlXPathNodeSetAddUnique: 3756 * @cur: the initial node set 3757 * @val: a new xmlNodePtr 3758 * 3759 * add a new xmlNodePtr to an existing NodeSet, optimized version 3760 * when we are sure the node is not already in the set. 3761 * 3762 * Returns 0 in case of success and -1 in case of failure 3763 */ 3764 int 3765 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) { 3766 if ((cur == NULL) || (val == NULL)) return(-1); 3767 3768 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3769 /* 3770 * grow the nodeTab if needed 3771 */ 3772 if (cur->nodeMax == 0) { 3773 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3774 sizeof(xmlNodePtr)); 3775 if (cur->nodeTab == NULL) { 3776 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3777 return(-1); 3778 } 3779 memset(cur->nodeTab, 0 , 3780 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3781 cur->nodeMax = XML_NODESET_DEFAULT; 3782 } else if (cur->nodeNr == cur->nodeMax) { 3783 xmlNodePtr *temp; 3784 3785 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 3786 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n"); 3787 return(-1); 3788 } 3789 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 * 3790 sizeof(xmlNodePtr)); 3791 if (temp == NULL) { 3792 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3793 return(-1); 3794 } 3795 cur->nodeTab = temp; 3796 cur->nodeMax *= 2; 3797 } 3798 if (val->type == XML_NAMESPACE_DECL) { 3799 xmlNsPtr ns = (xmlNsPtr) val; 3800 3801 cur->nodeTab[cur->nodeNr++] = 3802 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3803 } else 3804 cur->nodeTab[cur->nodeNr++] = val; 3805 return(0); 3806 } 3807 3808 /** 3809 * xmlXPathNodeSetMerge: 3810 * @val1: the first NodeSet or NULL 3811 * @val2: the second NodeSet 3812 * 3813 * Merges two nodesets, all nodes from @val2 are added to @val1 3814 * if @val1 is NULL, a new set is created and copied from @val2 3815 * 3816 * Returns @val1 once extended or NULL in case of error. 3817 */ 3818 xmlNodeSetPtr 3819 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) { 3820 int i, j, initNr, skip; 3821 xmlNodePtr n1, n2; 3822 3823 if (val2 == NULL) return(val1); 3824 if (val1 == NULL) { 3825 val1 = xmlXPathNodeSetCreate(NULL); 3826 if (val1 == NULL) 3827 return (NULL); 3828 #if 0 3829 /* 3830 * TODO: The optimization won't work in every case, since 3831 * those nasty namespace nodes need to be added with 3832 * xmlXPathNodeSetDupNs() to the set; thus a pure 3833 * memcpy is not possible. 3834 * If there was a flag on the nodesetval, indicating that 3835 * some temporary nodes are in, that would be helpfull. 3836 */ 3837 /* 3838 * Optimization: Create an equally sized node-set 3839 * and memcpy the content. 3840 */ 3841 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr); 3842 if (val1 == NULL) 3843 return(NULL); 3844 if (val2->nodeNr != 0) { 3845 if (val2->nodeNr == 1) 3846 *(val1->nodeTab) = *(val2->nodeTab); 3847 else { 3848 memcpy(val1->nodeTab, val2->nodeTab, 3849 val2->nodeNr * sizeof(xmlNodePtr)); 3850 } 3851 val1->nodeNr = val2->nodeNr; 3852 } 3853 return(val1); 3854 #endif 3855 } 3856 3857 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3858 initNr = val1->nodeNr; 3859 3860 for (i = 0;i < val2->nodeNr;i++) { 3861 n2 = val2->nodeTab[i]; 3862 /* 3863 * check against duplicates 3864 */ 3865 skip = 0; 3866 for (j = 0; j < initNr; j++) { 3867 n1 = val1->nodeTab[j]; 3868 if (n1 == n2) { 3869 skip = 1; 3870 break; 3871 } else if ((n1->type == XML_NAMESPACE_DECL) && 3872 (n2->type == XML_NAMESPACE_DECL)) { 3873 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) && 3874 (xmlStrEqual(((xmlNsPtr) n1)->prefix, 3875 ((xmlNsPtr) n2)->prefix))) 3876 { 3877 skip = 1; 3878 break; 3879 } 3880 } 3881 } 3882 if (skip) 3883 continue; 3884 3885 /* 3886 * grow the nodeTab if needed 3887 */ 3888 if (val1->nodeMax == 0) { 3889 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3890 sizeof(xmlNodePtr)); 3891 if (val1->nodeTab == NULL) { 3892 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3893 return(NULL); 3894 } 3895 memset(val1->nodeTab, 0 , 3896 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3897 val1->nodeMax = XML_NODESET_DEFAULT; 3898 } else if (val1->nodeNr == val1->nodeMax) { 3899 xmlNodePtr *temp; 3900 3901 if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 3902 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n"); 3903 return(NULL); 3904 } 3905 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 * 3906 sizeof(xmlNodePtr)); 3907 if (temp == NULL) { 3908 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3909 return(NULL); 3910 } 3911 val1->nodeTab = temp; 3912 val1->nodeMax *= 2; 3913 } 3914 if (n2->type == XML_NAMESPACE_DECL) { 3915 xmlNsPtr ns = (xmlNsPtr) n2; 3916 3917 val1->nodeTab[val1->nodeNr++] = 3918 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3919 } else 3920 val1->nodeTab[val1->nodeNr++] = n2; 3921 } 3922 3923 return(val1); 3924 } 3925 3926 3927 /** 3928 * xmlXPathNodeSetMergeAndClear: 3929 * @set1: the first NodeSet or NULL 3930 * @set2: the second NodeSet 3931 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes 3932 * 3933 * Merges two nodesets, all nodes from @set2 are added to @set1 3934 * if @set1 is NULL, a new set is created and copied from @set2. 3935 * Checks for duplicate nodes. Clears set2. 3936 * 3937 * Returns @set1 once extended or NULL in case of error. 3938 */ 3939 static xmlNodeSetPtr 3940 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2, 3941 int hasNullEntries) 3942 { 3943 if ((set1 == NULL) && (hasNullEntries == 0)) { 3944 /* 3945 * Note that doing a memcpy of the list, namespace nodes are 3946 * just assigned to set1, since set2 is cleared anyway. 3947 */ 3948 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr); 3949 if (set1 == NULL) 3950 return(NULL); 3951 if (set2->nodeNr != 0) { 3952 memcpy(set1->nodeTab, set2->nodeTab, 3953 set2->nodeNr * sizeof(xmlNodePtr)); 3954 set1->nodeNr = set2->nodeNr; 3955 } 3956 } else { 3957 int i, j, initNbSet1; 3958 xmlNodePtr n1, n2; 3959 3960 if (set1 == NULL) 3961 set1 = xmlXPathNodeSetCreate(NULL); 3962 if (set1 == NULL) 3963 return (NULL); 3964 3965 initNbSet1 = set1->nodeNr; 3966 for (i = 0;i < set2->nodeNr;i++) { 3967 n2 = set2->nodeTab[i]; 3968 /* 3969 * Skip NULLed entries. 3970 */ 3971 if (n2 == NULL) 3972 continue; 3973 /* 3974 * Skip duplicates. 3975 */ 3976 for (j = 0; j < initNbSet1; j++) { 3977 n1 = set1->nodeTab[j]; 3978 if (n1 == n2) { 3979 goto skip_node; 3980 } else if ((n1->type == XML_NAMESPACE_DECL) && 3981 (n2->type == XML_NAMESPACE_DECL)) 3982 { 3983 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) && 3984 (xmlStrEqual(((xmlNsPtr) n1)->prefix, 3985 ((xmlNsPtr) n2)->prefix))) 3986 { 3987 /* 3988 * Free the namespace node. 3989 */ 3990 set2->nodeTab[i] = NULL; 3991 xmlXPathNodeSetFreeNs((xmlNsPtr) n2); 3992 goto skip_node; 3993 } 3994 } 3995 } 3996 /* 3997 * grow the nodeTab if needed 3998 */ 3999 if (set1->nodeMax == 0) { 4000 set1->nodeTab = (xmlNodePtr *) xmlMalloc( 4001 XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); 4002 if (set1->nodeTab == NULL) { 4003 xmlXPathErrMemory(NULL, "merging nodeset\n"); 4004 return(NULL); 4005 } 4006 memset(set1->nodeTab, 0, 4007 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 4008 set1->nodeMax = XML_NODESET_DEFAULT; 4009 } else if (set1->nodeNr >= set1->nodeMax) { 4010 xmlNodePtr *temp; 4011 4012 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 4013 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n"); 4014 return(NULL); 4015 } 4016 temp = (xmlNodePtr *) xmlRealloc( 4017 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr)); 4018 if (temp == NULL) { 4019 xmlXPathErrMemory(NULL, "merging nodeset\n"); 4020 return(NULL); 4021 } 4022 set1->nodeTab = temp; 4023 set1->nodeMax *= 2; 4024 } 4025 set1->nodeTab[set1->nodeNr++] = n2; 4026 skip_node: 4027 {} 4028 } 4029 } 4030 set2->nodeNr = 0; 4031 return(set1); 4032 } 4033 4034 /** 4035 * xmlXPathNodeSetMergeAndClearNoDupls: 4036 * @set1: the first NodeSet or NULL 4037 * @set2: the second NodeSet 4038 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes 4039 * 4040 * Merges two nodesets, all nodes from @set2 are added to @set1 4041 * if @set1 is NULL, a new set is created and copied from @set2. 4042 * Doesn't chack for duplicate nodes. Clears set2. 4043 * 4044 * Returns @set1 once extended or NULL in case of error. 4045 */ 4046 static xmlNodeSetPtr 4047 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2, 4048 int hasNullEntries) 4049 { 4050 if (set2 == NULL) 4051 return(set1); 4052 if ((set1 == NULL) && (hasNullEntries == 0)) { 4053 /* 4054 * Note that doing a memcpy of the list, namespace nodes are 4055 * just assigned to set1, since set2 is cleared anyway. 4056 */ 4057 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr); 4058 if (set1 == NULL) 4059 return(NULL); 4060 if (set2->nodeNr != 0) { 4061 memcpy(set1->nodeTab, set2->nodeTab, 4062 set2->nodeNr * sizeof(xmlNodePtr)); 4063 set1->nodeNr = set2->nodeNr; 4064 } 4065 } else { 4066 int i; 4067 xmlNodePtr n2; 4068 4069 if (set1 == NULL) 4070 set1 = xmlXPathNodeSetCreate(NULL); 4071 if (set1 == NULL) 4072 return (NULL); 4073 4074 for (i = 0;i < set2->nodeNr;i++) { 4075 n2 = set2->nodeTab[i]; 4076 /* 4077 * Skip NULLed entries. 4078 */ 4079 if (n2 == NULL) 4080 continue; 4081 if (set1->nodeMax == 0) { 4082 set1->nodeTab = (xmlNodePtr *) xmlMalloc( 4083 XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); 4084 if (set1->nodeTab == NULL) { 4085 xmlXPathErrMemory(NULL, "merging nodeset\n"); 4086 return(NULL); 4087 } 4088 memset(set1->nodeTab, 0, 4089 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 4090 set1->nodeMax = XML_NODESET_DEFAULT; 4091 } else if (set1->nodeNr >= set1->nodeMax) { 4092 xmlNodePtr *temp; 4093 4094 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 4095 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n"); 4096 return(NULL); 4097 } 4098 temp = (xmlNodePtr *) xmlRealloc( 4099 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr)); 4100 if (temp == NULL) { 4101 xmlXPathErrMemory(NULL, "merging nodeset\n"); 4102 return(NULL); 4103 } 4104 set1->nodeTab = temp; 4105 set1->nodeMax *= 2; 4106 } 4107 set1->nodeTab[set1->nodeNr++] = n2; 4108 } 4109 } 4110 set2->nodeNr = 0; 4111 return(set1); 4112 } 4113 4114 /** 4115 * xmlXPathNodeSetDel: 4116 * @cur: the initial node set 4117 * @val: an xmlNodePtr 4118 * 4119 * Removes an xmlNodePtr from an existing NodeSet 4120 */ 4121 void 4122 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) { 4123 int i; 4124 4125 if (cur == NULL) return; 4126 if (val == NULL) return; 4127 4128 /* 4129 * find node in nodeTab 4130 */ 4131 for (i = 0;i < cur->nodeNr;i++) 4132 if (cur->nodeTab[i] == val) break; 4133 4134 if (i >= cur->nodeNr) { /* not found */ 4135 #ifdef DEBUG 4136 xmlGenericError(xmlGenericErrorContext, 4137 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n", 4138 val->name); 4139 #endif 4140 return; 4141 } 4142 if ((cur->nodeTab[i] != NULL) && 4143 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL)) 4144 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]); 4145 cur->nodeNr--; 4146 for (;i < cur->nodeNr;i++) 4147 cur->nodeTab[i] = cur->nodeTab[i + 1]; 4148 cur->nodeTab[cur->nodeNr] = NULL; 4149 } 4150 4151 /** 4152 * xmlXPathNodeSetRemove: 4153 * @cur: the initial node set 4154 * @val: the index to remove 4155 * 4156 * Removes an entry from an existing NodeSet list. 4157 */ 4158 void 4159 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) { 4160 if (cur == NULL) return; 4161 if (val >= cur->nodeNr) return; 4162 if ((cur->nodeTab[val] != NULL) && 4163 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL)) 4164 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]); 4165 cur->nodeNr--; 4166 for (;val < cur->nodeNr;val++) 4167 cur->nodeTab[val] = cur->nodeTab[val + 1]; 4168 cur->nodeTab[cur->nodeNr] = NULL; 4169 } 4170 4171 /** 4172 * xmlXPathFreeNodeSet: 4173 * @obj: the xmlNodeSetPtr to free 4174 * 4175 * Free the NodeSet compound (not the actual nodes !). 4176 */ 4177 void 4178 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) { 4179 if (obj == NULL) return; 4180 if (obj->nodeTab != NULL) { 4181 int i; 4182 4183 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 4184 for (i = 0;i < obj->nodeNr;i++) 4185 if ((obj->nodeTab[i] != NULL) && 4186 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL)) 4187 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]); 4188 xmlFree(obj->nodeTab); 4189 } 4190 xmlFree(obj); 4191 } 4192 4193 /** 4194 * xmlXPathNodeSetClearFromPos: 4195 * @set: the node set to be cleared 4196 * @pos: the start position to clear from 4197 * 4198 * Clears the list from temporary XPath objects (e.g. namespace nodes 4199 * are feed) starting with the entry at @pos, but does *not* free the list 4200 * itself. Sets the length of the list to @pos. 4201 */ 4202 static void 4203 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes) 4204 { 4205 if ((set == NULL) || (pos >= set->nodeNr)) 4206 return; 4207 else if ((hasNsNodes)) { 4208 int i; 4209 xmlNodePtr node; 4210 4211 for (i = pos; i < set->nodeNr; i++) { 4212 node = set->nodeTab[i]; 4213 if ((node != NULL) && 4214 (node->type == XML_NAMESPACE_DECL)) 4215 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 4216 } 4217 } 4218 set->nodeNr = pos; 4219 } 4220 4221 /** 4222 * xmlXPathNodeSetClear: 4223 * @set: the node set to clear 4224 * 4225 * Clears the list from all temporary XPath objects (e.g. namespace nodes 4226 * are feed), but does *not* free the list itself. Sets the length of the 4227 * list to 0. 4228 */ 4229 static void 4230 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes) 4231 { 4232 xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes); 4233 } 4234 4235 /** 4236 * xmlXPathNodeSetKeepLast: 4237 * @set: the node set to be cleared 4238 * 4239 * Move the last node to the first position and clear temporary XPath objects 4240 * (e.g. namespace nodes) from all other nodes. Sets the length of the list 4241 * to 1. 4242 */ 4243 static void 4244 xmlXPathNodeSetKeepLast(xmlNodeSetPtr set) 4245 { 4246 int i; 4247 xmlNodePtr node; 4248 4249 if ((set == NULL) || (set->nodeNr <= 1)) 4250 return; 4251 for (i = 0; i < set->nodeNr - 1; i++) { 4252 node = set->nodeTab[i]; 4253 if ((node != NULL) && 4254 (node->type == XML_NAMESPACE_DECL)) 4255 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 4256 } 4257 set->nodeTab[0] = set->nodeTab[set->nodeNr-1]; 4258 set->nodeNr = 1; 4259 } 4260 4261 /** 4262 * xmlXPathFreeValueTree: 4263 * @obj: the xmlNodeSetPtr to free 4264 * 4265 * Free the NodeSet compound and the actual tree, this is different 4266 * from xmlXPathFreeNodeSet() 4267 */ 4268 static void 4269 xmlXPathFreeValueTree(xmlNodeSetPtr obj) { 4270 int i; 4271 4272 if (obj == NULL) return; 4273 4274 if (obj->nodeTab != NULL) { 4275 for (i = 0;i < obj->nodeNr;i++) { 4276 if (obj->nodeTab[i] != NULL) { 4277 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) { 4278 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]); 4279 } else { 4280 xmlFreeNodeList(obj->nodeTab[i]); 4281 } 4282 } 4283 } 4284 xmlFree(obj->nodeTab); 4285 } 4286 xmlFree(obj); 4287 } 4288 4289 #if defined(DEBUG) || defined(DEBUG_STEP) 4290 /** 4291 * xmlGenericErrorContextNodeSet: 4292 * @output: a FILE * for the output 4293 * @obj: the xmlNodeSetPtr to display 4294 * 4295 * Quick display of a NodeSet 4296 */ 4297 void 4298 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) { 4299 int i; 4300 4301 if (output == NULL) output = xmlGenericErrorContext; 4302 if (obj == NULL) { 4303 fprintf(output, "NodeSet == NULL !\n"); 4304 return; 4305 } 4306 if (obj->nodeNr == 0) { 4307 fprintf(output, "NodeSet is empty\n"); 4308 return; 4309 } 4310 if (obj->nodeTab == NULL) { 4311 fprintf(output, " nodeTab == NULL !\n"); 4312 return; 4313 } 4314 for (i = 0; i < obj->nodeNr; i++) { 4315 if (obj->nodeTab[i] == NULL) { 4316 fprintf(output, " NULL !\n"); 4317 return; 4318 } 4319 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) || 4320 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE)) 4321 fprintf(output, " /"); 4322 else if (obj->nodeTab[i]->name == NULL) 4323 fprintf(output, " noname!"); 4324 else fprintf(output, " %s", obj->nodeTab[i]->name); 4325 } 4326 fprintf(output, "\n"); 4327 } 4328 #endif 4329 4330 /** 4331 * xmlXPathNewNodeSet: 4332 * @val: the NodePtr value 4333 * 4334 * Create a new xmlXPathObjectPtr of type NodeSet and initialize 4335 * it with the single Node @val 4336 * 4337 * Returns the newly created object. 4338 */ 4339 xmlXPathObjectPtr 4340 xmlXPathNewNodeSet(xmlNodePtr val) { 4341 xmlXPathObjectPtr ret; 4342 4343 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4344 if (ret == NULL) { 4345 xmlXPathErrMemory(NULL, "creating nodeset\n"); 4346 return(NULL); 4347 } 4348 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4349 ret->type = XPATH_NODESET; 4350 ret->boolval = 0; 4351 ret->nodesetval = xmlXPathNodeSetCreate(val); 4352 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 4353 #ifdef XP_DEBUG_OBJ_USAGE 4354 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET); 4355 #endif 4356 return(ret); 4357 } 4358 4359 /** 4360 * xmlXPathNewValueTree: 4361 * @val: the NodePtr value 4362 * 4363 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize 4364 * it with the tree root @val 4365 * 4366 * Returns the newly created object. 4367 */ 4368 xmlXPathObjectPtr 4369 xmlXPathNewValueTree(xmlNodePtr val) { 4370 xmlXPathObjectPtr ret; 4371 4372 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4373 if (ret == NULL) { 4374 xmlXPathErrMemory(NULL, "creating result value tree\n"); 4375 return(NULL); 4376 } 4377 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4378 ret->type = XPATH_XSLT_TREE; 4379 ret->boolval = 0; 4380 ret->user = (void *) val; 4381 ret->nodesetval = xmlXPathNodeSetCreate(val); 4382 #ifdef XP_DEBUG_OBJ_USAGE 4383 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE); 4384 #endif 4385 return(ret); 4386 } 4387 4388 /** 4389 * xmlXPathNewNodeSetList: 4390 * @val: an existing NodeSet 4391 * 4392 * Create a new xmlXPathObjectPtr of type NodeSet and initialize 4393 * it with the Nodeset @val 4394 * 4395 * Returns the newly created object. 4396 */ 4397 xmlXPathObjectPtr 4398 xmlXPathNewNodeSetList(xmlNodeSetPtr val) 4399 { 4400 xmlXPathObjectPtr ret; 4401 int i; 4402 4403 if (val == NULL) 4404 ret = NULL; 4405 else if (val->nodeTab == NULL) 4406 ret = xmlXPathNewNodeSet(NULL); 4407 else { 4408 ret = xmlXPathNewNodeSet(val->nodeTab[0]); 4409 if (ret) { 4410 for (i = 1; i < val->nodeNr; ++i) { 4411 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]) 4412 < 0) break; 4413 } 4414 } 4415 } 4416 4417 return (ret); 4418 } 4419 4420 /** 4421 * xmlXPathWrapNodeSet: 4422 * @val: the NodePtr value 4423 * 4424 * Wrap the Nodeset @val in a new xmlXPathObjectPtr 4425 * 4426 * Returns the newly created object. 4427 */ 4428 xmlXPathObjectPtr 4429 xmlXPathWrapNodeSet(xmlNodeSetPtr val) { 4430 xmlXPathObjectPtr ret; 4431 4432 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4433 if (ret == NULL) { 4434 xmlXPathErrMemory(NULL, "creating node set object\n"); 4435 return(NULL); 4436 } 4437 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4438 ret->type = XPATH_NODESET; 4439 ret->nodesetval = val; 4440 #ifdef XP_DEBUG_OBJ_USAGE 4441 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET); 4442 #endif 4443 return(ret); 4444 } 4445 4446 /** 4447 * xmlXPathFreeNodeSetList: 4448 * @obj: an existing NodeSetList object 4449 * 4450 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in 4451 * the list contrary to xmlXPathFreeObject(). 4452 */ 4453 void 4454 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) { 4455 if (obj == NULL) return; 4456 #ifdef XP_DEBUG_OBJ_USAGE 4457 xmlXPathDebugObjUsageReleased(NULL, obj->type); 4458 #endif 4459 xmlFree(obj); 4460 } 4461 4462 /** 4463 * xmlXPathDifference: 4464 * @nodes1: a node-set 4465 * @nodes2: a node-set 4466 * 4467 * Implements the EXSLT - Sets difference() function: 4468 * node-set set:difference (node-set, node-set) 4469 * 4470 * Returns the difference between the two node sets, or nodes1 if 4471 * nodes2 is empty 4472 */ 4473 xmlNodeSetPtr 4474 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4475 xmlNodeSetPtr ret; 4476 int i, l1; 4477 xmlNodePtr cur; 4478 4479 if (xmlXPathNodeSetIsEmpty(nodes2)) 4480 return(nodes1); 4481 4482 ret = xmlXPathNodeSetCreate(NULL); 4483 if (xmlXPathNodeSetIsEmpty(nodes1)) 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 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) 4492 break; 4493 } 4494 } 4495 return(ret); 4496 } 4497 4498 /** 4499 * xmlXPathIntersection: 4500 * @nodes1: a node-set 4501 * @nodes2: a node-set 4502 * 4503 * Implements the EXSLT - Sets intersection() function: 4504 * node-set set:intersection (node-set, node-set) 4505 * 4506 * Returns a node set comprising the nodes that are within both the 4507 * node sets passed as arguments 4508 */ 4509 xmlNodeSetPtr 4510 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4511 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL); 4512 int i, l1; 4513 xmlNodePtr cur; 4514 4515 if (ret == NULL) 4516 return(ret); 4517 if (xmlXPathNodeSetIsEmpty(nodes1)) 4518 return(ret); 4519 if (xmlXPathNodeSetIsEmpty(nodes2)) 4520 return(ret); 4521 4522 l1 = xmlXPathNodeSetGetLength(nodes1); 4523 4524 for (i = 0; i < l1; i++) { 4525 cur = xmlXPathNodeSetItem(nodes1, i); 4526 if (xmlXPathNodeSetContains(nodes2, cur)) { 4527 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) 4528 break; 4529 } 4530 } 4531 return(ret); 4532 } 4533 4534 /** 4535 * xmlXPathDistinctSorted: 4536 * @nodes: a node-set, sorted by document order 4537 * 4538 * Implements the EXSLT - Sets distinct() function: 4539 * node-set set:distinct (node-set) 4540 * 4541 * Returns a subset of the nodes contained in @nodes, or @nodes if 4542 * it is empty 4543 */ 4544 xmlNodeSetPtr 4545 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) { 4546 xmlNodeSetPtr ret; 4547 xmlHashTablePtr hash; 4548 int i, l; 4549 xmlChar * strval; 4550 xmlNodePtr cur; 4551 4552 if (xmlXPathNodeSetIsEmpty(nodes)) 4553 return(nodes); 4554 4555 ret = xmlXPathNodeSetCreate(NULL); 4556 if (ret == NULL) 4557 return(ret); 4558 l = xmlXPathNodeSetGetLength(nodes); 4559 hash = xmlHashCreate (l); 4560 for (i = 0; i < l; i++) { 4561 cur = xmlXPathNodeSetItem(nodes, i); 4562 strval = xmlXPathCastNodeToString(cur); 4563 if (xmlHashLookup(hash, strval) == NULL) { 4564 xmlHashAddEntry(hash, strval, strval); 4565 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) 4566 break; 4567 } else { 4568 xmlFree(strval); 4569 } 4570 } 4571 xmlHashFree(hash, xmlHashDefaultDeallocator); 4572 return(ret); 4573 } 4574 4575 /** 4576 * xmlXPathDistinct: 4577 * @nodes: a node-set 4578 * 4579 * Implements the EXSLT - Sets distinct() function: 4580 * node-set set:distinct (node-set) 4581 * @nodes is sorted by document order, then #exslSetsDistinctSorted 4582 * is called with the sorted node-set 4583 * 4584 * Returns a subset of the nodes contained in @nodes, or @nodes if 4585 * it is empty 4586 */ 4587 xmlNodeSetPtr 4588 xmlXPathDistinct (xmlNodeSetPtr nodes) { 4589 if (xmlXPathNodeSetIsEmpty(nodes)) 4590 return(nodes); 4591 4592 xmlXPathNodeSetSort(nodes); 4593 return(xmlXPathDistinctSorted(nodes)); 4594 } 4595 4596 /** 4597 * xmlXPathHasSameNodes: 4598 * @nodes1: a node-set 4599 * @nodes2: a node-set 4600 * 4601 * Implements the EXSLT - Sets has-same-nodes function: 4602 * boolean set:has-same-node(node-set, node-set) 4603 * 4604 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0) 4605 * otherwise 4606 */ 4607 int 4608 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4609 int i, l; 4610 xmlNodePtr cur; 4611 4612 if (xmlXPathNodeSetIsEmpty(nodes1) || 4613 xmlXPathNodeSetIsEmpty(nodes2)) 4614 return(0); 4615 4616 l = xmlXPathNodeSetGetLength(nodes1); 4617 for (i = 0; i < l; i++) { 4618 cur = xmlXPathNodeSetItem(nodes1, i); 4619 if (xmlXPathNodeSetContains(nodes2, cur)) 4620 return(1); 4621 } 4622 return(0); 4623 } 4624 4625 /** 4626 * xmlXPathNodeLeadingSorted: 4627 * @nodes: a node-set, sorted by document order 4628 * @node: a node 4629 * 4630 * Implements the EXSLT - Sets leading() function: 4631 * node-set set:leading (node-set, node-set) 4632 * 4633 * Returns the nodes in @nodes that precede @node in document order, 4634 * @nodes if @node is NULL or an empty node-set if @nodes 4635 * doesn't contain @node 4636 */ 4637 xmlNodeSetPtr 4638 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { 4639 int i, l; 4640 xmlNodePtr cur; 4641 xmlNodeSetPtr ret; 4642 4643 if (node == NULL) 4644 return(nodes); 4645 4646 ret = xmlXPathNodeSetCreate(NULL); 4647 if (ret == NULL) 4648 return(ret); 4649 if (xmlXPathNodeSetIsEmpty(nodes) || 4650 (!xmlXPathNodeSetContains(nodes, node))) 4651 return(ret); 4652 4653 l = xmlXPathNodeSetGetLength(nodes); 4654 for (i = 0; i < l; i++) { 4655 cur = xmlXPathNodeSetItem(nodes, i); 4656 if (cur == node) 4657 break; 4658 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) 4659 break; 4660 } 4661 return(ret); 4662 } 4663 4664 /** 4665 * xmlXPathNodeLeading: 4666 * @nodes: a node-set 4667 * @node: a node 4668 * 4669 * Implements the EXSLT - Sets leading() function: 4670 * node-set set:leading (node-set, node-set) 4671 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted 4672 * is called. 4673 * 4674 * Returns the nodes in @nodes that precede @node in document order, 4675 * @nodes if @node is NULL or an empty node-set if @nodes 4676 * doesn't contain @node 4677 */ 4678 xmlNodeSetPtr 4679 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) { 4680 xmlXPathNodeSetSort(nodes); 4681 return(xmlXPathNodeLeadingSorted(nodes, node)); 4682 } 4683 4684 /** 4685 * xmlXPathLeadingSorted: 4686 * @nodes1: a node-set, sorted by document order 4687 * @nodes2: a node-set, sorted by document order 4688 * 4689 * Implements the EXSLT - Sets leading() function: 4690 * node-set set:leading (node-set, node-set) 4691 * 4692 * Returns the nodes in @nodes1 that precede the first node in @nodes2 4693 * in document order, @nodes1 if @nodes2 is NULL or empty or 4694 * an empty node-set if @nodes1 doesn't contain @nodes2 4695 */ 4696 xmlNodeSetPtr 4697 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4698 if (xmlXPathNodeSetIsEmpty(nodes2)) 4699 return(nodes1); 4700 return(xmlXPathNodeLeadingSorted(nodes1, 4701 xmlXPathNodeSetItem(nodes2, 1))); 4702 } 4703 4704 /** 4705 * xmlXPathLeading: 4706 * @nodes1: a node-set 4707 * @nodes2: a node-set 4708 * 4709 * Implements the EXSLT - Sets leading() function: 4710 * node-set set:leading (node-set, node-set) 4711 * @nodes1 and @nodes2 are sorted by document order, then 4712 * #exslSetsLeadingSorted is called. 4713 * 4714 * Returns the nodes in @nodes1 that precede the first node in @nodes2 4715 * in document order, @nodes1 if @nodes2 is NULL or empty or 4716 * an empty node-set if @nodes1 doesn't contain @nodes2 4717 */ 4718 xmlNodeSetPtr 4719 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4720 if (xmlXPathNodeSetIsEmpty(nodes2)) 4721 return(nodes1); 4722 if (xmlXPathNodeSetIsEmpty(nodes1)) 4723 return(xmlXPathNodeSetCreate(NULL)); 4724 xmlXPathNodeSetSort(nodes1); 4725 xmlXPathNodeSetSort(nodes2); 4726 return(xmlXPathNodeLeadingSorted(nodes1, 4727 xmlXPathNodeSetItem(nodes2, 1))); 4728 } 4729 4730 /** 4731 * xmlXPathNodeTrailingSorted: 4732 * @nodes: a node-set, sorted by document order 4733 * @node: a node 4734 * 4735 * Implements the EXSLT - Sets trailing() function: 4736 * node-set set:trailing (node-set, node-set) 4737 * 4738 * Returns the nodes in @nodes that follow @node in document order, 4739 * @nodes if @node is NULL or an empty node-set if @nodes 4740 * doesn't contain @node 4741 */ 4742 xmlNodeSetPtr 4743 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { 4744 int i, l; 4745 xmlNodePtr cur; 4746 xmlNodeSetPtr ret; 4747 4748 if (node == NULL) 4749 return(nodes); 4750 4751 ret = xmlXPathNodeSetCreate(NULL); 4752 if (ret == NULL) 4753 return(ret); 4754 if (xmlXPathNodeSetIsEmpty(nodes) || 4755 (!xmlXPathNodeSetContains(nodes, node))) 4756 return(ret); 4757 4758 l = xmlXPathNodeSetGetLength(nodes); 4759 for (i = l - 1; i >= 0; i--) { 4760 cur = xmlXPathNodeSetItem(nodes, i); 4761 if (cur == node) 4762 break; 4763 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) 4764 break; 4765 } 4766 xmlXPathNodeSetSort(ret); /* bug 413451 */ 4767 return(ret); 4768 } 4769 4770 /** 4771 * xmlXPathNodeTrailing: 4772 * @nodes: a node-set 4773 * @node: a node 4774 * 4775 * Implements the EXSLT - Sets trailing() function: 4776 * node-set set:trailing (node-set, node-set) 4777 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted 4778 * is called. 4779 * 4780 * Returns the nodes in @nodes that follow @node in document order, 4781 * @nodes if @node is NULL or an empty node-set if @nodes 4782 * doesn't contain @node 4783 */ 4784 xmlNodeSetPtr 4785 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) { 4786 xmlXPathNodeSetSort(nodes); 4787 return(xmlXPathNodeTrailingSorted(nodes, node)); 4788 } 4789 4790 /** 4791 * xmlXPathTrailingSorted: 4792 * @nodes1: a node-set, sorted by document order 4793 * @nodes2: a node-set, sorted by document order 4794 * 4795 * Implements the EXSLT - Sets trailing() function: 4796 * node-set set:trailing (node-set, node-set) 4797 * 4798 * Returns the nodes in @nodes1 that follow the first node in @nodes2 4799 * in document order, @nodes1 if @nodes2 is NULL or empty or 4800 * an empty node-set if @nodes1 doesn't contain @nodes2 4801 */ 4802 xmlNodeSetPtr 4803 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4804 if (xmlXPathNodeSetIsEmpty(nodes2)) 4805 return(nodes1); 4806 return(xmlXPathNodeTrailingSorted(nodes1, 4807 xmlXPathNodeSetItem(nodes2, 0))); 4808 } 4809 4810 /** 4811 * xmlXPathTrailing: 4812 * @nodes1: a node-set 4813 * @nodes2: a node-set 4814 * 4815 * Implements the EXSLT - Sets trailing() function: 4816 * node-set set:trailing (node-set, node-set) 4817 * @nodes1 and @nodes2 are sorted by document order, then 4818 * #xmlXPathTrailingSorted is called. 4819 * 4820 * Returns the nodes in @nodes1 that follow the first node in @nodes2 4821 * in document order, @nodes1 if @nodes2 is NULL or empty or 4822 * an empty node-set if @nodes1 doesn't contain @nodes2 4823 */ 4824 xmlNodeSetPtr 4825 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4826 if (xmlXPathNodeSetIsEmpty(nodes2)) 4827 return(nodes1); 4828 if (xmlXPathNodeSetIsEmpty(nodes1)) 4829 return(xmlXPathNodeSetCreate(NULL)); 4830 xmlXPathNodeSetSort(nodes1); 4831 xmlXPathNodeSetSort(nodes2); 4832 return(xmlXPathNodeTrailingSorted(nodes1, 4833 xmlXPathNodeSetItem(nodes2, 0))); 4834 } 4835 4836 /************************************************************************ 4837 * * 4838 * Routines to handle extra functions * 4839 * * 4840 ************************************************************************/ 4841 4842 /** 4843 * xmlXPathRegisterFunc: 4844 * @ctxt: the XPath context 4845 * @name: the function name 4846 * @f: the function implementation or NULL 4847 * 4848 * Register a new function. If @f is NULL it unregisters the function 4849 * 4850 * Returns 0 in case of success, -1 in case of error 4851 */ 4852 int 4853 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name, 4854 xmlXPathFunction f) { 4855 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f)); 4856 } 4857 4858 /** 4859 * xmlXPathRegisterFuncNS: 4860 * @ctxt: the XPath context 4861 * @name: the function name 4862 * @ns_uri: the function namespace URI 4863 * @f: the function implementation or NULL 4864 * 4865 * Register a new function. If @f is NULL it unregisters the function 4866 * 4867 * Returns 0 in case of success, -1 in case of error 4868 */ 4869 int 4870 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name, 4871 const xmlChar *ns_uri, xmlXPathFunction f) { 4872 if (ctxt == NULL) 4873 return(-1); 4874 if (name == NULL) 4875 return(-1); 4876 4877 if (ctxt->funcHash == NULL) 4878 ctxt->funcHash = xmlHashCreate(0); 4879 if (ctxt->funcHash == NULL) 4880 return(-1); 4881 if (f == NULL) 4882 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL)); 4883 XML_IGNORE_PEDANTIC_WARNINGS 4884 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f)); 4885 XML_POP_WARNINGS 4886 } 4887 4888 /** 4889 * xmlXPathRegisterFuncLookup: 4890 * @ctxt: the XPath context 4891 * @f: the lookup function 4892 * @funcCtxt: the lookup data 4893 * 4894 * Registers an external mechanism to do function lookup. 4895 */ 4896 void 4897 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt, 4898 xmlXPathFuncLookupFunc f, 4899 void *funcCtxt) { 4900 if (ctxt == NULL) 4901 return; 4902 ctxt->funcLookupFunc = f; 4903 ctxt->funcLookupData = funcCtxt; 4904 } 4905 4906 /** 4907 * xmlXPathFunctionLookup: 4908 * @ctxt: the XPath context 4909 * @name: the function name 4910 * 4911 * Search in the Function array of the context for the given 4912 * function. 4913 * 4914 * Returns the xmlXPathFunction or NULL if not found 4915 */ 4916 xmlXPathFunction 4917 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { 4918 if (ctxt == NULL) 4919 return (NULL); 4920 4921 if (ctxt->funcLookupFunc != NULL) { 4922 xmlXPathFunction ret; 4923 xmlXPathFuncLookupFunc f; 4924 4925 f = ctxt->funcLookupFunc; 4926 ret = f(ctxt->funcLookupData, name, NULL); 4927 if (ret != NULL) 4928 return(ret); 4929 } 4930 return(xmlXPathFunctionLookupNS(ctxt, name, NULL)); 4931 } 4932 4933 /** 4934 * xmlXPathFunctionLookupNS: 4935 * @ctxt: the XPath context 4936 * @name: the function name 4937 * @ns_uri: the function namespace URI 4938 * 4939 * Search in the Function array of the context for the given 4940 * function. 4941 * 4942 * Returns the xmlXPathFunction or NULL if not found 4943 */ 4944 xmlXPathFunction 4945 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name, 4946 const xmlChar *ns_uri) { 4947 xmlXPathFunction ret; 4948 4949 if (ctxt == NULL) 4950 return(NULL); 4951 if (name == NULL) 4952 return(NULL); 4953 4954 if (ctxt->funcLookupFunc != NULL) { 4955 xmlXPathFuncLookupFunc f; 4956 4957 f = ctxt->funcLookupFunc; 4958 ret = f(ctxt->funcLookupData, name, ns_uri); 4959 if (ret != NULL) 4960 return(ret); 4961 } 4962 4963 if (ctxt->funcHash == NULL) 4964 return(NULL); 4965 4966 XML_IGNORE_PEDANTIC_WARNINGS 4967 ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri); 4968 XML_POP_WARNINGS 4969 return(ret); 4970 } 4971 4972 /** 4973 * xmlXPathRegisteredFuncsCleanup: 4974 * @ctxt: the XPath context 4975 * 4976 * Cleanup the XPath context data associated to registered functions 4977 */ 4978 void 4979 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) { 4980 if (ctxt == NULL) 4981 return; 4982 4983 xmlHashFree(ctxt->funcHash, NULL); 4984 ctxt->funcHash = NULL; 4985 } 4986 4987 /************************************************************************ 4988 * * 4989 * Routines to handle Variables * 4990 * * 4991 ************************************************************************/ 4992 4993 /** 4994 * xmlXPathRegisterVariable: 4995 * @ctxt: the XPath context 4996 * @name: the variable name 4997 * @value: the variable value or NULL 4998 * 4999 * Register a new variable value. If @value is NULL it unregisters 5000 * the variable 5001 * 5002 * Returns 0 in case of success, -1 in case of error 5003 */ 5004 int 5005 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name, 5006 xmlXPathObjectPtr value) { 5007 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value)); 5008 } 5009 5010 /** 5011 * xmlXPathRegisterVariableNS: 5012 * @ctxt: the XPath context 5013 * @name: the variable name 5014 * @ns_uri: the variable namespace URI 5015 * @value: the variable value or NULL 5016 * 5017 * Register a new variable value. If @value is NULL it unregisters 5018 * the variable 5019 * 5020 * Returns 0 in case of success, -1 in case of error 5021 */ 5022 int 5023 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name, 5024 const xmlChar *ns_uri, 5025 xmlXPathObjectPtr value) { 5026 if (ctxt == NULL) 5027 return(-1); 5028 if (name == NULL) 5029 return(-1); 5030 5031 if (ctxt->varHash == NULL) 5032 ctxt->varHash = xmlHashCreate(0); 5033 if (ctxt->varHash == NULL) 5034 return(-1); 5035 if (value == NULL) 5036 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri, 5037 xmlXPathFreeObjectEntry)); 5038 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri, 5039 (void *) value, xmlXPathFreeObjectEntry)); 5040 } 5041 5042 /** 5043 * xmlXPathRegisterVariableLookup: 5044 * @ctxt: the XPath context 5045 * @f: the lookup function 5046 * @data: the lookup data 5047 * 5048 * register an external mechanism to do variable lookup 5049 */ 5050 void 5051 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt, 5052 xmlXPathVariableLookupFunc f, void *data) { 5053 if (ctxt == NULL) 5054 return; 5055 ctxt->varLookupFunc = f; 5056 ctxt->varLookupData = data; 5057 } 5058 5059 /** 5060 * xmlXPathVariableLookup: 5061 * @ctxt: the XPath context 5062 * @name: the variable name 5063 * 5064 * Search in the Variable array of the context for the given 5065 * variable value. 5066 * 5067 * Returns a copy of the value or NULL if not found 5068 */ 5069 xmlXPathObjectPtr 5070 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { 5071 if (ctxt == NULL) 5072 return(NULL); 5073 5074 if (ctxt->varLookupFunc != NULL) { 5075 xmlXPathObjectPtr ret; 5076 5077 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc) 5078 (ctxt->varLookupData, name, NULL); 5079 return(ret); 5080 } 5081 return(xmlXPathVariableLookupNS(ctxt, name, NULL)); 5082 } 5083 5084 /** 5085 * xmlXPathVariableLookupNS: 5086 * @ctxt: the XPath context 5087 * @name: the variable name 5088 * @ns_uri: the variable namespace URI 5089 * 5090 * Search in the Variable array of the context for the given 5091 * variable value. 5092 * 5093 * Returns the a copy of the value or NULL if not found 5094 */ 5095 xmlXPathObjectPtr 5096 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name, 5097 const xmlChar *ns_uri) { 5098 if (ctxt == NULL) 5099 return(NULL); 5100 5101 if (ctxt->varLookupFunc != NULL) { 5102 xmlXPathObjectPtr ret; 5103 5104 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc) 5105 (ctxt->varLookupData, name, ns_uri); 5106 if (ret != NULL) return(ret); 5107 } 5108 5109 if (ctxt->varHash == NULL) 5110 return(NULL); 5111 if (name == NULL) 5112 return(NULL); 5113 5114 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr) 5115 xmlHashLookup2(ctxt->varHash, name, ns_uri))); 5116 } 5117 5118 /** 5119 * xmlXPathRegisteredVariablesCleanup: 5120 * @ctxt: the XPath context 5121 * 5122 * Cleanup the XPath context data associated to registered variables 5123 */ 5124 void 5125 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) { 5126 if (ctxt == NULL) 5127 return; 5128 5129 xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry); 5130 ctxt->varHash = NULL; 5131 } 5132 5133 /** 5134 * xmlXPathRegisterNs: 5135 * @ctxt: the XPath context 5136 * @prefix: the namespace prefix cannot be NULL or empty string 5137 * @ns_uri: the namespace name 5138 * 5139 * Register a new namespace. If @ns_uri is NULL it unregisters 5140 * the namespace 5141 * 5142 * Returns 0 in case of success, -1 in case of error 5143 */ 5144 int 5145 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix, 5146 const xmlChar *ns_uri) { 5147 if (ctxt == NULL) 5148 return(-1); 5149 if (prefix == NULL) 5150 return(-1); 5151 if (prefix[0] == 0) 5152 return(-1); 5153 5154 if (ctxt->nsHash == NULL) 5155 ctxt->nsHash = xmlHashCreate(10); 5156 if (ctxt->nsHash == NULL) 5157 return(-1); 5158 if (ns_uri == NULL) 5159 return(xmlHashRemoveEntry(ctxt->nsHash, prefix, 5160 xmlHashDefaultDeallocator)); 5161 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri), 5162 xmlHashDefaultDeallocator)); 5163 } 5164 5165 /** 5166 * xmlXPathNsLookup: 5167 * @ctxt: the XPath context 5168 * @prefix: the namespace prefix value 5169 * 5170 * Search in the namespace declaration array of the context for the given 5171 * namespace name associated to the given prefix 5172 * 5173 * Returns the value or NULL if not found 5174 */ 5175 const xmlChar * 5176 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) { 5177 if (ctxt == NULL) 5178 return(NULL); 5179 if (prefix == NULL) 5180 return(NULL); 5181 5182 #ifdef XML_XML_NAMESPACE 5183 if (xmlStrEqual(prefix, (const xmlChar *) "xml")) 5184 return(XML_XML_NAMESPACE); 5185 #endif 5186 5187 if (ctxt->namespaces != NULL) { 5188 int i; 5189 5190 for (i = 0;i < ctxt->nsNr;i++) { 5191 if ((ctxt->namespaces[i] != NULL) && 5192 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix))) 5193 return(ctxt->namespaces[i]->href); 5194 } 5195 } 5196 5197 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix)); 5198 } 5199 5200 /** 5201 * xmlXPathRegisteredNsCleanup: 5202 * @ctxt: the XPath context 5203 * 5204 * Cleanup the XPath context data associated to registered variables 5205 */ 5206 void 5207 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) { 5208 if (ctxt == NULL) 5209 return; 5210 5211 xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator); 5212 ctxt->nsHash = NULL; 5213 } 5214 5215 /************************************************************************ 5216 * * 5217 * Routines to handle Values * 5218 * * 5219 ************************************************************************/ 5220 5221 /* Allocations are terrible, one needs to optimize all this !!! */ 5222 5223 /** 5224 * xmlXPathNewFloat: 5225 * @val: the double value 5226 * 5227 * Create a new xmlXPathObjectPtr of type double and of value @val 5228 * 5229 * Returns the newly created object. 5230 */ 5231 xmlXPathObjectPtr 5232 xmlXPathNewFloat(double val) { 5233 xmlXPathObjectPtr ret; 5234 5235 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5236 if (ret == NULL) { 5237 xmlXPathErrMemory(NULL, "creating float object\n"); 5238 return(NULL); 5239 } 5240 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5241 ret->type = XPATH_NUMBER; 5242 ret->floatval = val; 5243 #ifdef XP_DEBUG_OBJ_USAGE 5244 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER); 5245 #endif 5246 return(ret); 5247 } 5248 5249 /** 5250 * xmlXPathNewBoolean: 5251 * @val: the boolean value 5252 * 5253 * Create a new xmlXPathObjectPtr of type boolean and of value @val 5254 * 5255 * Returns the newly created object. 5256 */ 5257 xmlXPathObjectPtr 5258 xmlXPathNewBoolean(int val) { 5259 xmlXPathObjectPtr ret; 5260 5261 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5262 if (ret == NULL) { 5263 xmlXPathErrMemory(NULL, "creating boolean object\n"); 5264 return(NULL); 5265 } 5266 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5267 ret->type = XPATH_BOOLEAN; 5268 ret->boolval = (val != 0); 5269 #ifdef XP_DEBUG_OBJ_USAGE 5270 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN); 5271 #endif 5272 return(ret); 5273 } 5274 5275 /** 5276 * xmlXPathNewString: 5277 * @val: the xmlChar * value 5278 * 5279 * Create a new xmlXPathObjectPtr of type string and of value @val 5280 * 5281 * Returns the newly created object. 5282 */ 5283 xmlXPathObjectPtr 5284 xmlXPathNewString(const xmlChar *val) { 5285 xmlXPathObjectPtr ret; 5286 5287 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5288 if (ret == NULL) { 5289 xmlXPathErrMemory(NULL, "creating string object\n"); 5290 return(NULL); 5291 } 5292 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5293 ret->type = XPATH_STRING; 5294 if (val != NULL) 5295 ret->stringval = xmlStrdup(val); 5296 else 5297 ret->stringval = xmlStrdup((const xmlChar *)""); 5298 #ifdef XP_DEBUG_OBJ_USAGE 5299 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); 5300 #endif 5301 return(ret); 5302 } 5303 5304 /** 5305 * xmlXPathWrapString: 5306 * @val: the xmlChar * value 5307 * 5308 * Wraps the @val string into an XPath object. 5309 * 5310 * Returns the newly created object. 5311 */ 5312 xmlXPathObjectPtr 5313 xmlXPathWrapString (xmlChar *val) { 5314 xmlXPathObjectPtr ret; 5315 5316 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5317 if (ret == NULL) { 5318 xmlXPathErrMemory(NULL, "creating string object\n"); 5319 return(NULL); 5320 } 5321 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5322 ret->type = XPATH_STRING; 5323 ret->stringval = val; 5324 #ifdef XP_DEBUG_OBJ_USAGE 5325 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); 5326 #endif 5327 return(ret); 5328 } 5329 5330 /** 5331 * xmlXPathNewCString: 5332 * @val: the char * value 5333 * 5334 * Create a new xmlXPathObjectPtr of type string and of value @val 5335 * 5336 * Returns the newly created object. 5337 */ 5338 xmlXPathObjectPtr 5339 xmlXPathNewCString(const char *val) { 5340 xmlXPathObjectPtr ret; 5341 5342 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5343 if (ret == NULL) { 5344 xmlXPathErrMemory(NULL, "creating string object\n"); 5345 return(NULL); 5346 } 5347 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5348 ret->type = XPATH_STRING; 5349 ret->stringval = xmlStrdup(BAD_CAST val); 5350 #ifdef XP_DEBUG_OBJ_USAGE 5351 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); 5352 #endif 5353 return(ret); 5354 } 5355 5356 /** 5357 * xmlXPathWrapCString: 5358 * @val: the char * value 5359 * 5360 * Wraps a string into an XPath object. 5361 * 5362 * Returns the newly created object. 5363 */ 5364 xmlXPathObjectPtr 5365 xmlXPathWrapCString (char * val) { 5366 return(xmlXPathWrapString((xmlChar *)(val))); 5367 } 5368 5369 /** 5370 * xmlXPathWrapExternal: 5371 * @val: the user data 5372 * 5373 * Wraps the @val data into an XPath object. 5374 * 5375 * Returns the newly created object. 5376 */ 5377 xmlXPathObjectPtr 5378 xmlXPathWrapExternal (void *val) { 5379 xmlXPathObjectPtr ret; 5380 5381 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5382 if (ret == NULL) { 5383 xmlXPathErrMemory(NULL, "creating user object\n"); 5384 return(NULL); 5385 } 5386 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5387 ret->type = XPATH_USERS; 5388 ret->user = val; 5389 #ifdef XP_DEBUG_OBJ_USAGE 5390 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS); 5391 #endif 5392 return(ret); 5393 } 5394 5395 /** 5396 * xmlXPathObjectCopy: 5397 * @val: the original object 5398 * 5399 * allocate a new copy of a given object 5400 * 5401 * Returns the newly created object. 5402 */ 5403 xmlXPathObjectPtr 5404 xmlXPathObjectCopy(xmlXPathObjectPtr val) { 5405 xmlXPathObjectPtr ret; 5406 5407 if (val == NULL) 5408 return(NULL); 5409 5410 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5411 if (ret == NULL) { 5412 xmlXPathErrMemory(NULL, "copying object\n"); 5413 return(NULL); 5414 } 5415 memcpy(ret, val , (size_t) sizeof(xmlXPathObject)); 5416 #ifdef XP_DEBUG_OBJ_USAGE 5417 xmlXPathDebugObjUsageRequested(NULL, val->type); 5418 #endif 5419 switch (val->type) { 5420 case XPATH_BOOLEAN: 5421 case XPATH_NUMBER: 5422 case XPATH_POINT: 5423 case XPATH_RANGE: 5424 break; 5425 case XPATH_STRING: 5426 ret->stringval = xmlStrdup(val->stringval); 5427 break; 5428 case XPATH_XSLT_TREE: 5429 #if 0 5430 /* 5431 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that 5432 this previous handling is no longer correct, and can cause some serious 5433 problems (ref. bug 145547) 5434 */ 5435 if ((val->nodesetval != NULL) && 5436 (val->nodesetval->nodeTab != NULL)) { 5437 xmlNodePtr cur, tmp; 5438 xmlDocPtr top; 5439 5440 ret->boolval = 1; 5441 top = xmlNewDoc(NULL); 5442 top->name = (char *) 5443 xmlStrdup(val->nodesetval->nodeTab[0]->name); 5444 ret->user = top; 5445 if (top != NULL) { 5446 top->doc = top; 5447 cur = val->nodesetval->nodeTab[0]->children; 5448 while (cur != NULL) { 5449 tmp = xmlDocCopyNode(cur, top, 1); 5450 xmlAddChild((xmlNodePtr) top, tmp); 5451 cur = cur->next; 5452 } 5453 } 5454 5455 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top); 5456 } else 5457 ret->nodesetval = xmlXPathNodeSetCreate(NULL); 5458 /* Deallocate the copied tree value */ 5459 break; 5460 #endif 5461 case XPATH_NODESET: 5462 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval); 5463 /* Do not deallocate the copied tree value */ 5464 ret->boolval = 0; 5465 break; 5466 case XPATH_LOCATIONSET: 5467 #ifdef LIBXML_XPTR_ENABLED 5468 { 5469 xmlLocationSetPtr loc = val->user; 5470 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc); 5471 break; 5472 } 5473 #endif 5474 case XPATH_USERS: 5475 ret->user = val->user; 5476 break; 5477 case XPATH_UNDEFINED: 5478 xmlGenericError(xmlGenericErrorContext, 5479 "xmlXPathObjectCopy: unsupported type %d\n", 5480 val->type); 5481 break; 5482 } 5483 return(ret); 5484 } 5485 5486 /** 5487 * xmlXPathFreeObject: 5488 * @obj: the object to free 5489 * 5490 * Free up an xmlXPathObjectPtr object. 5491 */ 5492 void 5493 xmlXPathFreeObject(xmlXPathObjectPtr obj) { 5494 if (obj == NULL) return; 5495 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) { 5496 if (obj->boolval) { 5497 #if 0 5498 if (obj->user != NULL) { 5499 xmlXPathFreeNodeSet(obj->nodesetval); 5500 xmlFreeNodeList((xmlNodePtr) obj->user); 5501 } else 5502 #endif 5503 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */ 5504 if (obj->nodesetval != NULL) 5505 xmlXPathFreeValueTree(obj->nodesetval); 5506 } else { 5507 if (obj->nodesetval != NULL) 5508 xmlXPathFreeNodeSet(obj->nodesetval); 5509 } 5510 #ifdef LIBXML_XPTR_ENABLED 5511 } else if (obj->type == XPATH_LOCATIONSET) { 5512 if (obj->user != NULL) 5513 xmlXPtrFreeLocationSet(obj->user); 5514 #endif 5515 } else if (obj->type == XPATH_STRING) { 5516 if (obj->stringval != NULL) 5517 xmlFree(obj->stringval); 5518 } 5519 #ifdef XP_DEBUG_OBJ_USAGE 5520 xmlXPathDebugObjUsageReleased(NULL, obj->type); 5521 #endif 5522 xmlFree(obj); 5523 } 5524 5525 static void 5526 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) { 5527 xmlXPathFreeObject((xmlXPathObjectPtr) obj); 5528 } 5529 5530 /** 5531 * xmlXPathReleaseObject: 5532 * @obj: the xmlXPathObjectPtr to free or to cache 5533 * 5534 * Depending on the state of the cache this frees the given 5535 * XPath object or stores it in the cache. 5536 */ 5537 static void 5538 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj) 5539 { 5540 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \ 5541 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \ 5542 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj; 5543 5544 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n)) 5545 5546 if (obj == NULL) 5547 return; 5548 if ((ctxt == NULL) || (ctxt->cache == NULL)) { 5549 xmlXPathFreeObject(obj); 5550 } else { 5551 xmlXPathContextCachePtr cache = 5552 (xmlXPathContextCachePtr) ctxt->cache; 5553 5554 switch (obj->type) { 5555 case XPATH_NODESET: 5556 case XPATH_XSLT_TREE: 5557 if (obj->nodesetval != NULL) { 5558 if (obj->boolval) { 5559 /* 5560 * It looks like the @boolval is used for 5561 * evaluation if this an XSLT Result Tree Fragment. 5562 * TODO: Check if this assumption is correct. 5563 */ 5564 obj->type = XPATH_XSLT_TREE; /* just for debugging */ 5565 xmlXPathFreeValueTree(obj->nodesetval); 5566 obj->nodesetval = NULL; 5567 } else if ((obj->nodesetval->nodeMax <= 40) && 5568 (XP_CACHE_WANTS(cache->nodesetObjs, 5569 cache->maxNodeset))) 5570 { 5571 XP_CACHE_ADD(cache->nodesetObjs, obj); 5572 goto obj_cached; 5573 } else { 5574 xmlXPathFreeNodeSet(obj->nodesetval); 5575 obj->nodesetval = NULL; 5576 } 5577 } 5578 break; 5579 case XPATH_STRING: 5580 if (obj->stringval != NULL) 5581 xmlFree(obj->stringval); 5582 5583 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) { 5584 XP_CACHE_ADD(cache->stringObjs, obj); 5585 goto obj_cached; 5586 } 5587 break; 5588 case XPATH_BOOLEAN: 5589 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) { 5590 XP_CACHE_ADD(cache->booleanObjs, obj); 5591 goto obj_cached; 5592 } 5593 break; 5594 case XPATH_NUMBER: 5595 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) { 5596 XP_CACHE_ADD(cache->numberObjs, obj); 5597 goto obj_cached; 5598 } 5599 break; 5600 #ifdef LIBXML_XPTR_ENABLED 5601 case XPATH_LOCATIONSET: 5602 if (obj->user != NULL) { 5603 xmlXPtrFreeLocationSet(obj->user); 5604 } 5605 goto free_obj; 5606 #endif 5607 default: 5608 goto free_obj; 5609 } 5610 5611 /* 5612 * Fallback to adding to the misc-objects slot. 5613 */ 5614 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) { 5615 XP_CACHE_ADD(cache->miscObjs, obj); 5616 } else 5617 goto free_obj; 5618 5619 obj_cached: 5620 5621 #ifdef XP_DEBUG_OBJ_USAGE 5622 xmlXPathDebugObjUsageReleased(ctxt, obj->type); 5623 #endif 5624 5625 if (obj->nodesetval != NULL) { 5626 xmlNodeSetPtr tmpset = obj->nodesetval; 5627 5628 /* 5629 * TODO: Due to those nasty ns-nodes, we need to traverse 5630 * the list and free the ns-nodes. 5631 * URGENT TODO: Check if it's actually slowing things down. 5632 * Maybe we shouldn't try to preserve the list. 5633 */ 5634 if (tmpset->nodeNr > 1) { 5635 int i; 5636 xmlNodePtr node; 5637 5638 for (i = 0; i < tmpset->nodeNr; i++) { 5639 node = tmpset->nodeTab[i]; 5640 if ((node != NULL) && 5641 (node->type == XML_NAMESPACE_DECL)) 5642 { 5643 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 5644 } 5645 } 5646 } else if (tmpset->nodeNr == 1) { 5647 if ((tmpset->nodeTab[0] != NULL) && 5648 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL)) 5649 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]); 5650 } 5651 tmpset->nodeNr = 0; 5652 memset(obj, 0, sizeof(xmlXPathObject)); 5653 obj->nodesetval = tmpset; 5654 } else 5655 memset(obj, 0, sizeof(xmlXPathObject)); 5656 5657 return; 5658 5659 free_obj: 5660 /* 5661 * Cache is full; free the object. 5662 */ 5663 if (obj->nodesetval != NULL) 5664 xmlXPathFreeNodeSet(obj->nodesetval); 5665 #ifdef XP_DEBUG_OBJ_USAGE 5666 xmlXPathDebugObjUsageReleased(NULL, obj->type); 5667 #endif 5668 xmlFree(obj); 5669 } 5670 return; 5671 } 5672 5673 5674 /************************************************************************ 5675 * * 5676 * Type Casting Routines * 5677 * * 5678 ************************************************************************/ 5679 5680 /** 5681 * xmlXPathCastBooleanToString: 5682 * @val: a boolean 5683 * 5684 * Converts a boolean to its string value. 5685 * 5686 * Returns a newly allocated string. 5687 */ 5688 xmlChar * 5689 xmlXPathCastBooleanToString (int val) { 5690 xmlChar *ret; 5691 if (val) 5692 ret = xmlStrdup((const xmlChar *) "true"); 5693 else 5694 ret = xmlStrdup((const xmlChar *) "false"); 5695 return(ret); 5696 } 5697 5698 /** 5699 * xmlXPathCastNumberToString: 5700 * @val: a number 5701 * 5702 * Converts a number to its string value. 5703 * 5704 * Returns a newly allocated string. 5705 */ 5706 xmlChar * 5707 xmlXPathCastNumberToString (double val) { 5708 xmlChar *ret; 5709 switch (xmlXPathIsInf(val)) { 5710 case 1: 5711 ret = xmlStrdup((const xmlChar *) "Infinity"); 5712 break; 5713 case -1: 5714 ret = xmlStrdup((const xmlChar *) "-Infinity"); 5715 break; 5716 default: 5717 if (xmlXPathIsNaN(val)) { 5718 ret = xmlStrdup((const xmlChar *) "NaN"); 5719 } else if (val == 0) { 5720 /* Omit sign for negative zero. */ 5721 ret = xmlStrdup((const xmlChar *) "0"); 5722 } else { 5723 /* could be improved */ 5724 char buf[100]; 5725 xmlXPathFormatNumber(val, buf, 99); 5726 buf[99] = 0; 5727 ret = xmlStrdup((const xmlChar *) buf); 5728 } 5729 } 5730 return(ret); 5731 } 5732 5733 /** 5734 * xmlXPathCastNodeToString: 5735 * @node: a node 5736 * 5737 * Converts a node to its string value. 5738 * 5739 * Returns a newly allocated string. 5740 */ 5741 xmlChar * 5742 xmlXPathCastNodeToString (xmlNodePtr node) { 5743 xmlChar *ret; 5744 if ((ret = xmlNodeGetContent(node)) == NULL) 5745 ret = xmlStrdup((const xmlChar *) ""); 5746 return(ret); 5747 } 5748 5749 /** 5750 * xmlXPathCastNodeSetToString: 5751 * @ns: a node-set 5752 * 5753 * Converts a node-set to its string value. 5754 * 5755 * Returns a newly allocated string. 5756 */ 5757 xmlChar * 5758 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) { 5759 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL)) 5760 return(xmlStrdup((const xmlChar *) "")); 5761 5762 if (ns->nodeNr > 1) 5763 xmlXPathNodeSetSort(ns); 5764 return(xmlXPathCastNodeToString(ns->nodeTab[0])); 5765 } 5766 5767 /** 5768 * xmlXPathCastToString: 5769 * @val: an XPath object 5770 * 5771 * Converts an existing object to its string() equivalent 5772 * 5773 * Returns the allocated string value of the object, NULL in case of error. 5774 * It's up to the caller to free the string memory with xmlFree(). 5775 */ 5776 xmlChar * 5777 xmlXPathCastToString(xmlXPathObjectPtr val) { 5778 xmlChar *ret = NULL; 5779 5780 if (val == NULL) 5781 return(xmlStrdup((const xmlChar *) "")); 5782 switch (val->type) { 5783 case XPATH_UNDEFINED: 5784 #ifdef DEBUG_EXPR 5785 xmlGenericError(xmlGenericErrorContext, "String: undefined\n"); 5786 #endif 5787 ret = xmlStrdup((const xmlChar *) ""); 5788 break; 5789 case XPATH_NODESET: 5790 case XPATH_XSLT_TREE: 5791 ret = xmlXPathCastNodeSetToString(val->nodesetval); 5792 break; 5793 case XPATH_STRING: 5794 return(xmlStrdup(val->stringval)); 5795 case XPATH_BOOLEAN: 5796 ret = xmlXPathCastBooleanToString(val->boolval); 5797 break; 5798 case XPATH_NUMBER: { 5799 ret = xmlXPathCastNumberToString(val->floatval); 5800 break; 5801 } 5802 case XPATH_USERS: 5803 case XPATH_POINT: 5804 case XPATH_RANGE: 5805 case XPATH_LOCATIONSET: 5806 TODO 5807 ret = xmlStrdup((const xmlChar *) ""); 5808 break; 5809 } 5810 return(ret); 5811 } 5812 5813 /** 5814 * xmlXPathConvertString: 5815 * @val: an XPath object 5816 * 5817 * Converts an existing object to its string() equivalent 5818 * 5819 * Returns the new object, the old one is freed (or the operation 5820 * is done directly on @val) 5821 */ 5822 xmlXPathObjectPtr 5823 xmlXPathConvertString(xmlXPathObjectPtr val) { 5824 xmlChar *res = NULL; 5825 5826 if (val == NULL) 5827 return(xmlXPathNewCString("")); 5828 5829 switch (val->type) { 5830 case XPATH_UNDEFINED: 5831 #ifdef DEBUG_EXPR 5832 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n"); 5833 #endif 5834 break; 5835 case XPATH_NODESET: 5836 case XPATH_XSLT_TREE: 5837 res = xmlXPathCastNodeSetToString(val->nodesetval); 5838 break; 5839 case XPATH_STRING: 5840 return(val); 5841 case XPATH_BOOLEAN: 5842 res = xmlXPathCastBooleanToString(val->boolval); 5843 break; 5844 case XPATH_NUMBER: 5845 res = xmlXPathCastNumberToString(val->floatval); 5846 break; 5847 case XPATH_USERS: 5848 case XPATH_POINT: 5849 case XPATH_RANGE: 5850 case XPATH_LOCATIONSET: 5851 TODO; 5852 break; 5853 } 5854 xmlXPathFreeObject(val); 5855 if (res == NULL) 5856 return(xmlXPathNewCString("")); 5857 return(xmlXPathWrapString(res)); 5858 } 5859 5860 /** 5861 * xmlXPathCastBooleanToNumber: 5862 * @val: a boolean 5863 * 5864 * Converts a boolean to its number value 5865 * 5866 * Returns the number value 5867 */ 5868 double 5869 xmlXPathCastBooleanToNumber(int val) { 5870 if (val) 5871 return(1.0); 5872 return(0.0); 5873 } 5874 5875 /** 5876 * xmlXPathCastStringToNumber: 5877 * @val: a string 5878 * 5879 * Converts a string to its number value 5880 * 5881 * Returns the number value 5882 */ 5883 double 5884 xmlXPathCastStringToNumber(const xmlChar * val) { 5885 return(xmlXPathStringEvalNumber(val)); 5886 } 5887 5888 /** 5889 * xmlXPathCastNodeToNumber: 5890 * @node: a node 5891 * 5892 * Converts a node to its number value 5893 * 5894 * Returns the number value 5895 */ 5896 double 5897 xmlXPathCastNodeToNumber (xmlNodePtr node) { 5898 xmlChar *strval; 5899 double ret; 5900 5901 if (node == NULL) 5902 return(NAN); 5903 strval = xmlXPathCastNodeToString(node); 5904 if (strval == NULL) 5905 return(NAN); 5906 ret = xmlXPathCastStringToNumber(strval); 5907 xmlFree(strval); 5908 5909 return(ret); 5910 } 5911 5912 /** 5913 * xmlXPathCastNodeSetToNumber: 5914 * @ns: a node-set 5915 * 5916 * Converts a node-set to its number value 5917 * 5918 * Returns the number value 5919 */ 5920 double 5921 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) { 5922 xmlChar *str; 5923 double ret; 5924 5925 if (ns == NULL) 5926 return(NAN); 5927 str = xmlXPathCastNodeSetToString(ns); 5928 ret = xmlXPathCastStringToNumber(str); 5929 xmlFree(str); 5930 return(ret); 5931 } 5932 5933 /** 5934 * xmlXPathCastToNumber: 5935 * @val: an XPath object 5936 * 5937 * Converts an XPath object to its number value 5938 * 5939 * Returns the number value 5940 */ 5941 double 5942 xmlXPathCastToNumber(xmlXPathObjectPtr val) { 5943 double ret = 0.0; 5944 5945 if (val == NULL) 5946 return(NAN); 5947 switch (val->type) { 5948 case XPATH_UNDEFINED: 5949 #ifdef DEGUB_EXPR 5950 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n"); 5951 #endif 5952 ret = NAN; 5953 break; 5954 case XPATH_NODESET: 5955 case XPATH_XSLT_TREE: 5956 ret = xmlXPathCastNodeSetToNumber(val->nodesetval); 5957 break; 5958 case XPATH_STRING: 5959 ret = xmlXPathCastStringToNumber(val->stringval); 5960 break; 5961 case XPATH_NUMBER: 5962 ret = val->floatval; 5963 break; 5964 case XPATH_BOOLEAN: 5965 ret = xmlXPathCastBooleanToNumber(val->boolval); 5966 break; 5967 case XPATH_USERS: 5968 case XPATH_POINT: 5969 case XPATH_RANGE: 5970 case XPATH_LOCATIONSET: 5971 TODO; 5972 ret = NAN; 5973 break; 5974 } 5975 return(ret); 5976 } 5977 5978 /** 5979 * xmlXPathConvertNumber: 5980 * @val: an XPath object 5981 * 5982 * Converts an existing object to its number() equivalent 5983 * 5984 * Returns the new object, the old one is freed (or the operation 5985 * is done directly on @val) 5986 */ 5987 xmlXPathObjectPtr 5988 xmlXPathConvertNumber(xmlXPathObjectPtr val) { 5989 xmlXPathObjectPtr ret; 5990 5991 if (val == NULL) 5992 return(xmlXPathNewFloat(0.0)); 5993 if (val->type == XPATH_NUMBER) 5994 return(val); 5995 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val)); 5996 xmlXPathFreeObject(val); 5997 return(ret); 5998 } 5999 6000 /** 6001 * xmlXPathCastNumberToBoolean: 6002 * @val: a number 6003 * 6004 * Converts a number to its boolean value 6005 * 6006 * Returns the boolean value 6007 */ 6008 int 6009 xmlXPathCastNumberToBoolean (double val) { 6010 if (xmlXPathIsNaN(val) || (val == 0.0)) 6011 return(0); 6012 return(1); 6013 } 6014 6015 /** 6016 * xmlXPathCastStringToBoolean: 6017 * @val: a string 6018 * 6019 * Converts a string to its boolean value 6020 * 6021 * Returns the boolean value 6022 */ 6023 int 6024 xmlXPathCastStringToBoolean (const xmlChar *val) { 6025 if ((val == NULL) || (xmlStrlen(val) == 0)) 6026 return(0); 6027 return(1); 6028 } 6029 6030 /** 6031 * xmlXPathCastNodeSetToBoolean: 6032 * @ns: a node-set 6033 * 6034 * Converts a node-set to its boolean value 6035 * 6036 * Returns the boolean value 6037 */ 6038 int 6039 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) { 6040 if ((ns == NULL) || (ns->nodeNr == 0)) 6041 return(0); 6042 return(1); 6043 } 6044 6045 /** 6046 * xmlXPathCastToBoolean: 6047 * @val: an XPath object 6048 * 6049 * Converts an XPath object to its boolean value 6050 * 6051 * Returns the boolean value 6052 */ 6053 int 6054 xmlXPathCastToBoolean (xmlXPathObjectPtr val) { 6055 int ret = 0; 6056 6057 if (val == NULL) 6058 return(0); 6059 switch (val->type) { 6060 case XPATH_UNDEFINED: 6061 #ifdef DEBUG_EXPR 6062 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n"); 6063 #endif 6064 ret = 0; 6065 break; 6066 case XPATH_NODESET: 6067 case XPATH_XSLT_TREE: 6068 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval); 6069 break; 6070 case XPATH_STRING: 6071 ret = xmlXPathCastStringToBoolean(val->stringval); 6072 break; 6073 case XPATH_NUMBER: 6074 ret = xmlXPathCastNumberToBoolean(val->floatval); 6075 break; 6076 case XPATH_BOOLEAN: 6077 ret = val->boolval; 6078 break; 6079 case XPATH_USERS: 6080 case XPATH_POINT: 6081 case XPATH_RANGE: 6082 case XPATH_LOCATIONSET: 6083 TODO; 6084 ret = 0; 6085 break; 6086 } 6087 return(ret); 6088 } 6089 6090 6091 /** 6092 * xmlXPathConvertBoolean: 6093 * @val: an XPath object 6094 * 6095 * Converts an existing object to its boolean() equivalent 6096 * 6097 * Returns the new object, the old one is freed (or the operation 6098 * is done directly on @val) 6099 */ 6100 xmlXPathObjectPtr 6101 xmlXPathConvertBoolean(xmlXPathObjectPtr val) { 6102 xmlXPathObjectPtr ret; 6103 6104 if (val == NULL) 6105 return(xmlXPathNewBoolean(0)); 6106 if (val->type == XPATH_BOOLEAN) 6107 return(val); 6108 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val)); 6109 xmlXPathFreeObject(val); 6110 return(ret); 6111 } 6112 6113 /************************************************************************ 6114 * * 6115 * Routines to handle XPath contexts * 6116 * * 6117 ************************************************************************/ 6118 6119 /** 6120 * xmlXPathNewContext: 6121 * @doc: the XML document 6122 * 6123 * Create a new xmlXPathContext 6124 * 6125 * Returns the xmlXPathContext just allocated. The caller will need to free it. 6126 */ 6127 xmlXPathContextPtr 6128 xmlXPathNewContext(xmlDocPtr doc) { 6129 xmlXPathContextPtr ret; 6130 6131 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext)); 6132 if (ret == NULL) { 6133 xmlXPathErrMemory(NULL, "creating context\n"); 6134 return(NULL); 6135 } 6136 memset(ret, 0 , (size_t) sizeof(xmlXPathContext)); 6137 ret->doc = doc; 6138 ret->node = NULL; 6139 6140 ret->varHash = NULL; 6141 6142 ret->nb_types = 0; 6143 ret->max_types = 0; 6144 ret->types = NULL; 6145 6146 ret->funcHash = xmlHashCreate(0); 6147 6148 ret->nb_axis = 0; 6149 ret->max_axis = 0; 6150 ret->axis = NULL; 6151 6152 ret->nsHash = NULL; 6153 ret->user = NULL; 6154 6155 ret->contextSize = -1; 6156 ret->proximityPosition = -1; 6157 6158 #ifdef XP_DEFAULT_CACHE_ON 6159 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) { 6160 xmlXPathFreeContext(ret); 6161 return(NULL); 6162 } 6163 #endif 6164 6165 xmlXPathRegisterAllFunctions(ret); 6166 6167 return(ret); 6168 } 6169 6170 /** 6171 * xmlXPathFreeContext: 6172 * @ctxt: the context to free 6173 * 6174 * Free up an xmlXPathContext 6175 */ 6176 void 6177 xmlXPathFreeContext(xmlXPathContextPtr ctxt) { 6178 if (ctxt == NULL) return; 6179 6180 if (ctxt->cache != NULL) 6181 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache); 6182 xmlXPathRegisteredNsCleanup(ctxt); 6183 xmlXPathRegisteredFuncsCleanup(ctxt); 6184 xmlXPathRegisteredVariablesCleanup(ctxt); 6185 xmlResetError(&ctxt->lastError); 6186 xmlFree(ctxt); 6187 } 6188 6189 /************************************************************************ 6190 * * 6191 * Routines to handle XPath parser contexts * 6192 * * 6193 ************************************************************************/ 6194 6195 #define CHECK_CTXT(ctxt) \ 6196 if (ctxt == NULL) { \ 6197 __xmlRaiseError(NULL, NULL, NULL, \ 6198 NULL, NULL, XML_FROM_XPATH, \ 6199 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \ 6200 __FILE__, __LINE__, \ 6201 NULL, NULL, NULL, 0, 0, \ 6202 "NULL context pointer\n"); \ 6203 return(NULL); \ 6204 } \ 6205 6206 #define CHECK_CTXT_NEG(ctxt) \ 6207 if (ctxt == NULL) { \ 6208 __xmlRaiseError(NULL, NULL, NULL, \ 6209 NULL, NULL, XML_FROM_XPATH, \ 6210 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \ 6211 __FILE__, __LINE__, \ 6212 NULL, NULL, NULL, 0, 0, \ 6213 "NULL context pointer\n"); \ 6214 return(-1); \ 6215 } \ 6216 6217 6218 #define CHECK_CONTEXT(ctxt) \ 6219 if ((ctxt == NULL) || (ctxt->doc == NULL) || \ 6220 (ctxt->doc->children == NULL)) { \ 6221 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \ 6222 return(NULL); \ 6223 } 6224 6225 6226 /** 6227 * xmlXPathNewParserContext: 6228 * @str: the XPath expression 6229 * @ctxt: the XPath context 6230 * 6231 * Create a new xmlXPathParserContext 6232 * 6233 * Returns the xmlXPathParserContext just allocated. 6234 */ 6235 xmlXPathParserContextPtr 6236 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) { 6237 xmlXPathParserContextPtr ret; 6238 6239 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext)); 6240 if (ret == NULL) { 6241 xmlXPathErrMemory(ctxt, "creating parser context\n"); 6242 return(NULL); 6243 } 6244 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext)); 6245 ret->cur = ret->base = str; 6246 ret->context = ctxt; 6247 6248 ret->comp = xmlXPathNewCompExpr(); 6249 if (ret->comp == NULL) { 6250 xmlFree(ret->valueTab); 6251 xmlFree(ret); 6252 return(NULL); 6253 } 6254 if ((ctxt != NULL) && (ctxt->dict != NULL)) { 6255 ret->comp->dict = ctxt->dict; 6256 xmlDictReference(ret->comp->dict); 6257 } 6258 6259 return(ret); 6260 } 6261 6262 /** 6263 * xmlXPathCompParserContext: 6264 * @comp: the XPath compiled expression 6265 * @ctxt: the XPath context 6266 * 6267 * Create a new xmlXPathParserContext when processing a compiled expression 6268 * 6269 * Returns the xmlXPathParserContext just allocated. 6270 */ 6271 static xmlXPathParserContextPtr 6272 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) { 6273 xmlXPathParserContextPtr ret; 6274 6275 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext)); 6276 if (ret == NULL) { 6277 xmlXPathErrMemory(ctxt, "creating evaluation context\n"); 6278 return(NULL); 6279 } 6280 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext)); 6281 6282 /* Allocate the value stack */ 6283 ret->valueTab = (xmlXPathObjectPtr *) 6284 xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); 6285 if (ret->valueTab == NULL) { 6286 xmlFree(ret); 6287 xmlXPathErrMemory(ctxt, "creating evaluation context\n"); 6288 return(NULL); 6289 } 6290 ret->valueNr = 0; 6291 ret->valueMax = 10; 6292 ret->value = NULL; 6293 ret->valueFrame = 0; 6294 6295 ret->context = ctxt; 6296 ret->comp = comp; 6297 6298 return(ret); 6299 } 6300 6301 /** 6302 * xmlXPathFreeParserContext: 6303 * @ctxt: the context to free 6304 * 6305 * Free up an xmlXPathParserContext 6306 */ 6307 void 6308 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) { 6309 int i; 6310 6311 if (ctxt->valueTab != NULL) { 6312 for (i = 0; i < ctxt->valueNr; i++) { 6313 if (ctxt->context) 6314 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]); 6315 else 6316 xmlXPathFreeObject(ctxt->valueTab[i]); 6317 } 6318 xmlFree(ctxt->valueTab); 6319 } 6320 if (ctxt->comp != NULL) { 6321 #ifdef XPATH_STREAMING 6322 if (ctxt->comp->stream != NULL) { 6323 xmlFreePatternList(ctxt->comp->stream); 6324 ctxt->comp->stream = NULL; 6325 } 6326 #endif 6327 xmlXPathFreeCompExpr(ctxt->comp); 6328 } 6329 xmlFree(ctxt); 6330 } 6331 6332 /************************************************************************ 6333 * * 6334 * The implicit core function library * 6335 * * 6336 ************************************************************************/ 6337 6338 /** 6339 * xmlXPathNodeValHash: 6340 * @node: a node pointer 6341 * 6342 * Function computing the beginning of the string value of the node, 6343 * used to speed up comparisons 6344 * 6345 * Returns an int usable as a hash 6346 */ 6347 static unsigned int 6348 xmlXPathNodeValHash(xmlNodePtr node) { 6349 int len = 2; 6350 const xmlChar * string = NULL; 6351 xmlNodePtr tmp = NULL; 6352 unsigned int ret = 0; 6353 6354 if (node == NULL) 6355 return(0); 6356 6357 if (node->type == XML_DOCUMENT_NODE) { 6358 tmp = xmlDocGetRootElement((xmlDocPtr) node); 6359 if (tmp == NULL) 6360 node = node->children; 6361 else 6362 node = tmp; 6363 6364 if (node == NULL) 6365 return(0); 6366 } 6367 6368 switch (node->type) { 6369 case XML_COMMENT_NODE: 6370 case XML_PI_NODE: 6371 case XML_CDATA_SECTION_NODE: 6372 case XML_TEXT_NODE: 6373 string = node->content; 6374 if (string == NULL) 6375 return(0); 6376 if (string[0] == 0) 6377 return(0); 6378 return(((unsigned int) string[0]) + 6379 (((unsigned int) string[1]) << 8)); 6380 case XML_NAMESPACE_DECL: 6381 string = ((xmlNsPtr)node)->href; 6382 if (string == NULL) 6383 return(0); 6384 if (string[0] == 0) 6385 return(0); 6386 return(((unsigned int) string[0]) + 6387 (((unsigned int) string[1]) << 8)); 6388 case XML_ATTRIBUTE_NODE: 6389 tmp = ((xmlAttrPtr) node)->children; 6390 break; 6391 case XML_ELEMENT_NODE: 6392 tmp = node->children; 6393 break; 6394 default: 6395 return(0); 6396 } 6397 while (tmp != NULL) { 6398 switch (tmp->type) { 6399 case XML_CDATA_SECTION_NODE: 6400 case XML_TEXT_NODE: 6401 string = tmp->content; 6402 break; 6403 default: 6404 string = NULL; 6405 break; 6406 } 6407 if ((string != NULL) && (string[0] != 0)) { 6408 if (len == 1) { 6409 return(ret + (((unsigned int) string[0]) << 8)); 6410 } 6411 if (string[1] == 0) { 6412 len = 1; 6413 ret = (unsigned int) string[0]; 6414 } else { 6415 return(((unsigned int) string[0]) + 6416 (((unsigned int) string[1]) << 8)); 6417 } 6418 } 6419 /* 6420 * Skip to next node 6421 */ 6422 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) { 6423 if (tmp->children->type != XML_ENTITY_DECL) { 6424 tmp = tmp->children; 6425 continue; 6426 } 6427 } 6428 if (tmp == node) 6429 break; 6430 6431 if (tmp->next != NULL) { 6432 tmp = tmp->next; 6433 continue; 6434 } 6435 6436 do { 6437 tmp = tmp->parent; 6438 if (tmp == NULL) 6439 break; 6440 if (tmp == node) { 6441 tmp = NULL; 6442 break; 6443 } 6444 if (tmp->next != NULL) { 6445 tmp = tmp->next; 6446 break; 6447 } 6448 } while (tmp != NULL); 6449 } 6450 return(ret); 6451 } 6452 6453 /** 6454 * xmlXPathStringHash: 6455 * @string: a string 6456 * 6457 * Function computing the beginning of the string value of the node, 6458 * used to speed up comparisons 6459 * 6460 * Returns an int usable as a hash 6461 */ 6462 static unsigned int 6463 xmlXPathStringHash(const xmlChar * string) { 6464 if (string == NULL) 6465 return((unsigned int) 0); 6466 if (string[0] == 0) 6467 return(0); 6468 return(((unsigned int) string[0]) + 6469 (((unsigned int) string[1]) << 8)); 6470 } 6471 6472 /** 6473 * xmlXPathCompareNodeSetFloat: 6474 * @ctxt: the XPath Parser context 6475 * @inf: less than (1) or greater than (0) 6476 * @strict: is the comparison strict 6477 * @arg: the node set 6478 * @f: the value 6479 * 6480 * Implement the compare operation between a nodeset and a number 6481 * @ns < @val (1, 1, ... 6482 * @ns <= @val (1, 0, ... 6483 * @ns > @val (0, 1, ... 6484 * @ns >= @val (0, 0, ... 6485 * 6486 * If one object to be compared is a node-set and the other is a number, 6487 * then the comparison will be true if and only if there is a node in the 6488 * node-set such that the result of performing the comparison on the number 6489 * to be compared and on the result of converting the string-value of that 6490 * node to a number using the number function is true. 6491 * 6492 * Returns 0 or 1 depending on the results of the test. 6493 */ 6494 static int 6495 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict, 6496 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) { 6497 int i, ret = 0; 6498 xmlNodeSetPtr ns; 6499 xmlChar *str2; 6500 6501 if ((f == NULL) || (arg == NULL) || 6502 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) { 6503 xmlXPathReleaseObject(ctxt->context, arg); 6504 xmlXPathReleaseObject(ctxt->context, f); 6505 return(0); 6506 } 6507 ns = arg->nodesetval; 6508 if (ns != NULL) { 6509 for (i = 0;i < ns->nodeNr;i++) { 6510 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 6511 if (str2 != NULL) { 6512 valuePush(ctxt, 6513 xmlXPathCacheNewString(ctxt->context, str2)); 6514 xmlFree(str2); 6515 xmlXPathNumberFunction(ctxt, 1); 6516 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f)); 6517 ret = xmlXPathCompareValues(ctxt, inf, strict); 6518 if (ret) 6519 break; 6520 } 6521 } 6522 } 6523 xmlXPathReleaseObject(ctxt->context, arg); 6524 xmlXPathReleaseObject(ctxt->context, f); 6525 return(ret); 6526 } 6527 6528 /** 6529 * xmlXPathCompareNodeSetString: 6530 * @ctxt: the XPath Parser context 6531 * @inf: less than (1) or greater than (0) 6532 * @strict: is the comparison strict 6533 * @arg: the node set 6534 * @s: the value 6535 * 6536 * Implement the compare operation between a nodeset and a string 6537 * @ns < @val (1, 1, ... 6538 * @ns <= @val (1, 0, ... 6539 * @ns > @val (0, 1, ... 6540 * @ns >= @val (0, 0, ... 6541 * 6542 * If one object to be compared is a node-set and the other is a string, 6543 * then the comparison will be true if and only if there is a node in 6544 * the node-set such that the result of performing the comparison on the 6545 * string-value of the node and the other string is true. 6546 * 6547 * Returns 0 or 1 depending on the results of the test. 6548 */ 6549 static int 6550 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict, 6551 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) { 6552 int i, ret = 0; 6553 xmlNodeSetPtr ns; 6554 xmlChar *str2; 6555 6556 if ((s == NULL) || (arg == NULL) || 6557 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) { 6558 xmlXPathReleaseObject(ctxt->context, arg); 6559 xmlXPathReleaseObject(ctxt->context, s); 6560 return(0); 6561 } 6562 ns = arg->nodesetval; 6563 if (ns != NULL) { 6564 for (i = 0;i < ns->nodeNr;i++) { 6565 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 6566 if (str2 != NULL) { 6567 valuePush(ctxt, 6568 xmlXPathCacheNewString(ctxt->context, str2)); 6569 xmlFree(str2); 6570 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s)); 6571 ret = xmlXPathCompareValues(ctxt, inf, strict); 6572 if (ret) 6573 break; 6574 } 6575 } 6576 } 6577 xmlXPathReleaseObject(ctxt->context, arg); 6578 xmlXPathReleaseObject(ctxt->context, s); 6579 return(ret); 6580 } 6581 6582 /** 6583 * xmlXPathCompareNodeSets: 6584 * @inf: less than (1) or greater than (0) 6585 * @strict: is the comparison strict 6586 * @arg1: the first node set object 6587 * @arg2: the second node set object 6588 * 6589 * Implement the compare operation on nodesets: 6590 * 6591 * If both objects to be compared are node-sets, then the comparison 6592 * will be true if and only if there is a node in the first node-set 6593 * and a node in the second node-set such that the result of performing 6594 * the comparison on the string-values of the two nodes is true. 6595 * .... 6596 * When neither object to be compared is a node-set and the operator 6597 * is <=, <, >= or >, then the objects are compared by converting both 6598 * objects to numbers and comparing the numbers according to IEEE 754. 6599 * .... 6600 * The number function converts its argument to a number as follows: 6601 * - a string that consists of optional whitespace followed by an 6602 * optional minus sign followed by a Number followed by whitespace 6603 * is converted to the IEEE 754 number that is nearest (according 6604 * to the IEEE 754 round-to-nearest rule) to the mathematical value 6605 * represented by the string; any other string is converted to NaN 6606 * 6607 * Conclusion all nodes need to be converted first to their string value 6608 * and then the comparison must be done when possible 6609 */ 6610 static int 6611 xmlXPathCompareNodeSets(int inf, int strict, 6612 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) { 6613 int i, j, init = 0; 6614 double val1; 6615 double *values2; 6616 int ret = 0; 6617 xmlNodeSetPtr ns1; 6618 xmlNodeSetPtr ns2; 6619 6620 if ((arg1 == NULL) || 6621 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) { 6622 xmlXPathFreeObject(arg2); 6623 return(0); 6624 } 6625 if ((arg2 == NULL) || 6626 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) { 6627 xmlXPathFreeObject(arg1); 6628 xmlXPathFreeObject(arg2); 6629 return(0); 6630 } 6631 6632 ns1 = arg1->nodesetval; 6633 ns2 = arg2->nodesetval; 6634 6635 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) { 6636 xmlXPathFreeObject(arg1); 6637 xmlXPathFreeObject(arg2); 6638 return(0); 6639 } 6640 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) { 6641 xmlXPathFreeObject(arg1); 6642 xmlXPathFreeObject(arg2); 6643 return(0); 6644 } 6645 6646 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double)); 6647 if (values2 == NULL) { 6648 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6649 xmlXPathFreeObject(arg1); 6650 xmlXPathFreeObject(arg2); 6651 return(0); 6652 } 6653 for (i = 0;i < ns1->nodeNr;i++) { 6654 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]); 6655 if (xmlXPathIsNaN(val1)) 6656 continue; 6657 for (j = 0;j < ns2->nodeNr;j++) { 6658 if (init == 0) { 6659 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]); 6660 } 6661 if (xmlXPathIsNaN(values2[j])) 6662 continue; 6663 if (inf && strict) 6664 ret = (val1 < values2[j]); 6665 else if (inf && !strict) 6666 ret = (val1 <= values2[j]); 6667 else if (!inf && strict) 6668 ret = (val1 > values2[j]); 6669 else if (!inf && !strict) 6670 ret = (val1 >= values2[j]); 6671 if (ret) 6672 break; 6673 } 6674 if (ret) 6675 break; 6676 init = 1; 6677 } 6678 xmlFree(values2); 6679 xmlXPathFreeObject(arg1); 6680 xmlXPathFreeObject(arg2); 6681 return(ret); 6682 } 6683 6684 /** 6685 * xmlXPathCompareNodeSetValue: 6686 * @ctxt: the XPath Parser context 6687 * @inf: less than (1) or greater than (0) 6688 * @strict: is the comparison strict 6689 * @arg: the node set 6690 * @val: the value 6691 * 6692 * Implement the compare operation between a nodeset and a value 6693 * @ns < @val (1, 1, ... 6694 * @ns <= @val (1, 0, ... 6695 * @ns > @val (0, 1, ... 6696 * @ns >= @val (0, 0, ... 6697 * 6698 * If one object to be compared is a node-set and the other is a boolean, 6699 * then the comparison will be true if and only if the result of performing 6700 * the comparison on the boolean and on the result of converting 6701 * the node-set to a boolean using the boolean function is true. 6702 * 6703 * Returns 0 or 1 depending on the results of the test. 6704 */ 6705 static int 6706 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict, 6707 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) { 6708 if ((val == NULL) || (arg == NULL) || 6709 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 6710 return(0); 6711 6712 switch(val->type) { 6713 case XPATH_NUMBER: 6714 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val)); 6715 case XPATH_NODESET: 6716 case XPATH_XSLT_TREE: 6717 return(xmlXPathCompareNodeSets(inf, strict, arg, val)); 6718 case XPATH_STRING: 6719 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val)); 6720 case XPATH_BOOLEAN: 6721 valuePush(ctxt, arg); 6722 xmlXPathBooleanFunction(ctxt, 1); 6723 valuePush(ctxt, val); 6724 return(xmlXPathCompareValues(ctxt, inf, strict)); 6725 default: 6726 xmlGenericError(xmlGenericErrorContext, 6727 "xmlXPathCompareNodeSetValue: Can't compare node set " 6728 "and object of type %d\n", 6729 val->type); 6730 xmlXPathReleaseObject(ctxt->context, arg); 6731 xmlXPathReleaseObject(ctxt->context, val); 6732 XP_ERROR0(XPATH_INVALID_TYPE); 6733 } 6734 return(0); 6735 } 6736 6737 /** 6738 * xmlXPathEqualNodeSetString: 6739 * @arg: the nodeset object argument 6740 * @str: the string to compare to. 6741 * @neq: flag to show whether for '=' (0) or '!=' (1) 6742 * 6743 * Implement the equal operation on XPath objects content: @arg1 == @arg2 6744 * If one object to be compared is a node-set and the other is a string, 6745 * then the comparison will be true if and only if there is a node in 6746 * the node-set such that the result of performing the comparison on the 6747 * string-value of the node and the other string is true. 6748 * 6749 * Returns 0 or 1 depending on the results of the test. 6750 */ 6751 static int 6752 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq) 6753 { 6754 int i; 6755 xmlNodeSetPtr ns; 6756 xmlChar *str2; 6757 unsigned int hash; 6758 6759 if ((str == NULL) || (arg == NULL) || 6760 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 6761 return (0); 6762 ns = arg->nodesetval; 6763 /* 6764 * A NULL nodeset compared with a string is always false 6765 * (since there is no node equal, and no node not equal) 6766 */ 6767 if ((ns == NULL) || (ns->nodeNr <= 0) ) 6768 return (0); 6769 hash = xmlXPathStringHash(str); 6770 for (i = 0; i < ns->nodeNr; i++) { 6771 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) { 6772 str2 = xmlNodeGetContent(ns->nodeTab[i]); 6773 if ((str2 != NULL) && (xmlStrEqual(str, str2))) { 6774 xmlFree(str2); 6775 if (neq) 6776 continue; 6777 return (1); 6778 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) { 6779 if (neq) 6780 continue; 6781 return (1); 6782 } else if (neq) { 6783 if (str2 != NULL) 6784 xmlFree(str2); 6785 return (1); 6786 } 6787 if (str2 != NULL) 6788 xmlFree(str2); 6789 } else if (neq) 6790 return (1); 6791 } 6792 return (0); 6793 } 6794 6795 /** 6796 * xmlXPathEqualNodeSetFloat: 6797 * @arg: the nodeset object argument 6798 * @f: the float to compare to 6799 * @neq: flag to show whether to compare '=' (0) or '!=' (1) 6800 * 6801 * Implement the equal operation on XPath objects content: @arg1 == @arg2 6802 * If one object to be compared is a node-set and the other is a number, 6803 * then the comparison will be true if and only if there is a node in 6804 * the node-set such that the result of performing the comparison on the 6805 * number to be compared and on the result of converting the string-value 6806 * of that node to a number using the number function is true. 6807 * 6808 * Returns 0 or 1 depending on the results of the test. 6809 */ 6810 static int 6811 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt, 6812 xmlXPathObjectPtr arg, double f, int neq) { 6813 int i, ret=0; 6814 xmlNodeSetPtr ns; 6815 xmlChar *str2; 6816 xmlXPathObjectPtr val; 6817 double v; 6818 6819 if ((arg == NULL) || 6820 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 6821 return(0); 6822 6823 ns = arg->nodesetval; 6824 if (ns != NULL) { 6825 for (i=0;i<ns->nodeNr;i++) { 6826 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 6827 if (str2 != NULL) { 6828 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2)); 6829 xmlFree(str2); 6830 xmlXPathNumberFunction(ctxt, 1); 6831 val = valuePop(ctxt); 6832 v = val->floatval; 6833 xmlXPathReleaseObject(ctxt->context, val); 6834 if (!xmlXPathIsNaN(v)) { 6835 if ((!neq) && (v==f)) { 6836 ret = 1; 6837 break; 6838 } else if ((neq) && (v!=f)) { 6839 ret = 1; 6840 break; 6841 } 6842 } else { /* NaN is unequal to any value */ 6843 if (neq) 6844 ret = 1; 6845 } 6846 } 6847 } 6848 } 6849 6850 return(ret); 6851 } 6852 6853 6854 /** 6855 * xmlXPathEqualNodeSets: 6856 * @arg1: first nodeset object argument 6857 * @arg2: second nodeset object argument 6858 * @neq: flag to show whether to test '=' (0) or '!=' (1) 6859 * 6860 * Implement the equal / not equal operation on XPath nodesets: 6861 * @arg1 == @arg2 or @arg1 != @arg2 6862 * If both objects to be compared are node-sets, then the comparison 6863 * will be true if and only if there is a node in the first node-set and 6864 * a node in the second node-set such that the result of performing the 6865 * comparison on the string-values of the two nodes is true. 6866 * 6867 * (needless to say, this is a costly operation) 6868 * 6869 * Returns 0 or 1 depending on the results of the test. 6870 */ 6871 static int 6872 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) { 6873 int i, j; 6874 unsigned int *hashs1; 6875 unsigned int *hashs2; 6876 xmlChar **values1; 6877 xmlChar **values2; 6878 int ret = 0; 6879 xmlNodeSetPtr ns1; 6880 xmlNodeSetPtr ns2; 6881 6882 if ((arg1 == NULL) || 6883 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) 6884 return(0); 6885 if ((arg2 == NULL) || 6886 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) 6887 return(0); 6888 6889 ns1 = arg1->nodesetval; 6890 ns2 = arg2->nodesetval; 6891 6892 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) 6893 return(0); 6894 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) 6895 return(0); 6896 6897 /* 6898 * for equal, check if there is a node pertaining to both sets 6899 */ 6900 if (neq == 0) 6901 for (i = 0;i < ns1->nodeNr;i++) 6902 for (j = 0;j < ns2->nodeNr;j++) 6903 if (ns1->nodeTab[i] == ns2->nodeTab[j]) 6904 return(1); 6905 6906 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *)); 6907 if (values1 == NULL) { 6908 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6909 return(0); 6910 } 6911 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int)); 6912 if (hashs1 == NULL) { 6913 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6914 xmlFree(values1); 6915 return(0); 6916 } 6917 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *)); 6918 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *)); 6919 if (values2 == NULL) { 6920 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6921 xmlFree(hashs1); 6922 xmlFree(values1); 6923 return(0); 6924 } 6925 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int)); 6926 if (hashs2 == NULL) { 6927 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6928 xmlFree(hashs1); 6929 xmlFree(values1); 6930 xmlFree(values2); 6931 return(0); 6932 } 6933 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *)); 6934 for (i = 0;i < ns1->nodeNr;i++) { 6935 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]); 6936 for (j = 0;j < ns2->nodeNr;j++) { 6937 if (i == 0) 6938 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]); 6939 if (hashs1[i] != hashs2[j]) { 6940 if (neq) { 6941 ret = 1; 6942 break; 6943 } 6944 } 6945 else { 6946 if (values1[i] == NULL) 6947 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]); 6948 if (values2[j] == NULL) 6949 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]); 6950 ret = xmlStrEqual(values1[i], values2[j]) ^ neq; 6951 if (ret) 6952 break; 6953 } 6954 } 6955 if (ret) 6956 break; 6957 } 6958 for (i = 0;i < ns1->nodeNr;i++) 6959 if (values1[i] != NULL) 6960 xmlFree(values1[i]); 6961 for (j = 0;j < ns2->nodeNr;j++) 6962 if (values2[j] != NULL) 6963 xmlFree(values2[j]); 6964 xmlFree(values1); 6965 xmlFree(values2); 6966 xmlFree(hashs1); 6967 xmlFree(hashs2); 6968 return(ret); 6969 } 6970 6971 static int 6972 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt, 6973 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) { 6974 int ret = 0; 6975 /* 6976 *At this point we are assured neither arg1 nor arg2 6977 *is a nodeset, so we can just pick the appropriate routine. 6978 */ 6979 switch (arg1->type) { 6980 case XPATH_UNDEFINED: 6981 #ifdef DEBUG_EXPR 6982 xmlGenericError(xmlGenericErrorContext, 6983 "Equal: undefined\n"); 6984 #endif 6985 break; 6986 case XPATH_BOOLEAN: 6987 switch (arg2->type) { 6988 case XPATH_UNDEFINED: 6989 #ifdef DEBUG_EXPR 6990 xmlGenericError(xmlGenericErrorContext, 6991 "Equal: undefined\n"); 6992 #endif 6993 break; 6994 case XPATH_BOOLEAN: 6995 #ifdef DEBUG_EXPR 6996 xmlGenericError(xmlGenericErrorContext, 6997 "Equal: %d boolean %d \n", 6998 arg1->boolval, arg2->boolval); 6999 #endif 7000 ret = (arg1->boolval == arg2->boolval); 7001 break; 7002 case XPATH_NUMBER: 7003 ret = (arg1->boolval == 7004 xmlXPathCastNumberToBoolean(arg2->floatval)); 7005 break; 7006 case XPATH_STRING: 7007 if ((arg2->stringval == NULL) || 7008 (arg2->stringval[0] == 0)) ret = 0; 7009 else 7010 ret = 1; 7011 ret = (arg1->boolval == ret); 7012 break; 7013 case XPATH_USERS: 7014 case XPATH_POINT: 7015 case XPATH_RANGE: 7016 case XPATH_LOCATIONSET: 7017 TODO 7018 break; 7019 case XPATH_NODESET: 7020 case XPATH_XSLT_TREE: 7021 break; 7022 } 7023 break; 7024 case XPATH_NUMBER: 7025 switch (arg2->type) { 7026 case XPATH_UNDEFINED: 7027 #ifdef DEBUG_EXPR 7028 xmlGenericError(xmlGenericErrorContext, 7029 "Equal: undefined\n"); 7030 #endif 7031 break; 7032 case XPATH_BOOLEAN: 7033 ret = (arg2->boolval== 7034 xmlXPathCastNumberToBoolean(arg1->floatval)); 7035 break; 7036 case XPATH_STRING: 7037 valuePush(ctxt, arg2); 7038 xmlXPathNumberFunction(ctxt, 1); 7039 arg2 = valuePop(ctxt); 7040 /* Falls through. */ 7041 case XPATH_NUMBER: 7042 /* Hand check NaN and Infinity equalities */ 7043 if (xmlXPathIsNaN(arg1->floatval) || 7044 xmlXPathIsNaN(arg2->floatval)) { 7045 ret = 0; 7046 } else if (xmlXPathIsInf(arg1->floatval) == 1) { 7047 if (xmlXPathIsInf(arg2->floatval) == 1) 7048 ret = 1; 7049 else 7050 ret = 0; 7051 } else if (xmlXPathIsInf(arg1->floatval) == -1) { 7052 if (xmlXPathIsInf(arg2->floatval) == -1) 7053 ret = 1; 7054 else 7055 ret = 0; 7056 } else if (xmlXPathIsInf(arg2->floatval) == 1) { 7057 if (xmlXPathIsInf(arg1->floatval) == 1) 7058 ret = 1; 7059 else 7060 ret = 0; 7061 } else if (xmlXPathIsInf(arg2->floatval) == -1) { 7062 if (xmlXPathIsInf(arg1->floatval) == -1) 7063 ret = 1; 7064 else 7065 ret = 0; 7066 } else { 7067 ret = (arg1->floatval == arg2->floatval); 7068 } 7069 break; 7070 case XPATH_USERS: 7071 case XPATH_POINT: 7072 case XPATH_RANGE: 7073 case XPATH_LOCATIONSET: 7074 TODO 7075 break; 7076 case XPATH_NODESET: 7077 case XPATH_XSLT_TREE: 7078 break; 7079 } 7080 break; 7081 case XPATH_STRING: 7082 switch (arg2->type) { 7083 case XPATH_UNDEFINED: 7084 #ifdef DEBUG_EXPR 7085 xmlGenericError(xmlGenericErrorContext, 7086 "Equal: undefined\n"); 7087 #endif 7088 break; 7089 case XPATH_BOOLEAN: 7090 if ((arg1->stringval == NULL) || 7091 (arg1->stringval[0] == 0)) ret = 0; 7092 else 7093 ret = 1; 7094 ret = (arg2->boolval == ret); 7095 break; 7096 case XPATH_STRING: 7097 ret = xmlStrEqual(arg1->stringval, arg2->stringval); 7098 break; 7099 case XPATH_NUMBER: 7100 valuePush(ctxt, arg1); 7101 xmlXPathNumberFunction(ctxt, 1); 7102 arg1 = valuePop(ctxt); 7103 /* Hand check NaN and Infinity equalities */ 7104 if (xmlXPathIsNaN(arg1->floatval) || 7105 xmlXPathIsNaN(arg2->floatval)) { 7106 ret = 0; 7107 } else if (xmlXPathIsInf(arg1->floatval) == 1) { 7108 if (xmlXPathIsInf(arg2->floatval) == 1) 7109 ret = 1; 7110 else 7111 ret = 0; 7112 } else if (xmlXPathIsInf(arg1->floatval) == -1) { 7113 if (xmlXPathIsInf(arg2->floatval) == -1) 7114 ret = 1; 7115 else 7116 ret = 0; 7117 } else if (xmlXPathIsInf(arg2->floatval) == 1) { 7118 if (xmlXPathIsInf(arg1->floatval) == 1) 7119 ret = 1; 7120 else 7121 ret = 0; 7122 } else if (xmlXPathIsInf(arg2->floatval) == -1) { 7123 if (xmlXPathIsInf(arg1->floatval) == -1) 7124 ret = 1; 7125 else 7126 ret = 0; 7127 } else { 7128 ret = (arg1->floatval == arg2->floatval); 7129 } 7130 break; 7131 case XPATH_USERS: 7132 case XPATH_POINT: 7133 case XPATH_RANGE: 7134 case XPATH_LOCATIONSET: 7135 TODO 7136 break; 7137 case XPATH_NODESET: 7138 case XPATH_XSLT_TREE: 7139 break; 7140 } 7141 break; 7142 case XPATH_USERS: 7143 case XPATH_POINT: 7144 case XPATH_RANGE: 7145 case XPATH_LOCATIONSET: 7146 TODO 7147 break; 7148 case XPATH_NODESET: 7149 case XPATH_XSLT_TREE: 7150 break; 7151 } 7152 xmlXPathReleaseObject(ctxt->context, arg1); 7153 xmlXPathReleaseObject(ctxt->context, arg2); 7154 return(ret); 7155 } 7156 7157 /** 7158 * xmlXPathEqualValues: 7159 * @ctxt: the XPath Parser context 7160 * 7161 * Implement the equal operation on XPath objects content: @arg1 == @arg2 7162 * 7163 * Returns 0 or 1 depending on the results of the test. 7164 */ 7165 int 7166 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) { 7167 xmlXPathObjectPtr arg1, arg2, argtmp; 7168 int ret = 0; 7169 7170 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); 7171 arg2 = valuePop(ctxt); 7172 arg1 = valuePop(ctxt); 7173 if ((arg1 == NULL) || (arg2 == NULL)) { 7174 if (arg1 != NULL) 7175 xmlXPathReleaseObject(ctxt->context, arg1); 7176 else 7177 xmlXPathReleaseObject(ctxt->context, arg2); 7178 XP_ERROR0(XPATH_INVALID_OPERAND); 7179 } 7180 7181 if (arg1 == arg2) { 7182 #ifdef DEBUG_EXPR 7183 xmlGenericError(xmlGenericErrorContext, 7184 "Equal: by pointer\n"); 7185 #endif 7186 xmlXPathFreeObject(arg1); 7187 return(1); 7188 } 7189 7190 /* 7191 *If either argument is a nodeset, it's a 'special case' 7192 */ 7193 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 7194 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7195 /* 7196 *Hack it to assure arg1 is the nodeset 7197 */ 7198 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) { 7199 argtmp = arg2; 7200 arg2 = arg1; 7201 arg1 = argtmp; 7202 } 7203 switch (arg2->type) { 7204 case XPATH_UNDEFINED: 7205 #ifdef DEBUG_EXPR 7206 xmlGenericError(xmlGenericErrorContext, 7207 "Equal: undefined\n"); 7208 #endif 7209 break; 7210 case XPATH_NODESET: 7211 case XPATH_XSLT_TREE: 7212 ret = xmlXPathEqualNodeSets(arg1, arg2, 0); 7213 break; 7214 case XPATH_BOOLEAN: 7215 if ((arg1->nodesetval == NULL) || 7216 (arg1->nodesetval->nodeNr == 0)) ret = 0; 7217 else 7218 ret = 1; 7219 ret = (ret == arg2->boolval); 7220 break; 7221 case XPATH_NUMBER: 7222 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0); 7223 break; 7224 case XPATH_STRING: 7225 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0); 7226 break; 7227 case XPATH_USERS: 7228 case XPATH_POINT: 7229 case XPATH_RANGE: 7230 case XPATH_LOCATIONSET: 7231 TODO 7232 break; 7233 } 7234 xmlXPathReleaseObject(ctxt->context, arg1); 7235 xmlXPathReleaseObject(ctxt->context, arg2); 7236 return(ret); 7237 } 7238 7239 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2)); 7240 } 7241 7242 /** 7243 * xmlXPathNotEqualValues: 7244 * @ctxt: the XPath Parser context 7245 * 7246 * Implement the equal operation on XPath objects content: @arg1 == @arg2 7247 * 7248 * Returns 0 or 1 depending on the results of the test. 7249 */ 7250 int 7251 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) { 7252 xmlXPathObjectPtr arg1, arg2, argtmp; 7253 int ret = 0; 7254 7255 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); 7256 arg2 = valuePop(ctxt); 7257 arg1 = valuePop(ctxt); 7258 if ((arg1 == NULL) || (arg2 == NULL)) { 7259 if (arg1 != NULL) 7260 xmlXPathReleaseObject(ctxt->context, arg1); 7261 else 7262 xmlXPathReleaseObject(ctxt->context, arg2); 7263 XP_ERROR0(XPATH_INVALID_OPERAND); 7264 } 7265 7266 if (arg1 == arg2) { 7267 #ifdef DEBUG_EXPR 7268 xmlGenericError(xmlGenericErrorContext, 7269 "NotEqual: by pointer\n"); 7270 #endif 7271 xmlXPathReleaseObject(ctxt->context, arg1); 7272 return(0); 7273 } 7274 7275 /* 7276 *If either argument is a nodeset, it's a 'special case' 7277 */ 7278 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 7279 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7280 /* 7281 *Hack it to assure arg1 is the nodeset 7282 */ 7283 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) { 7284 argtmp = arg2; 7285 arg2 = arg1; 7286 arg1 = argtmp; 7287 } 7288 switch (arg2->type) { 7289 case XPATH_UNDEFINED: 7290 #ifdef DEBUG_EXPR 7291 xmlGenericError(xmlGenericErrorContext, 7292 "NotEqual: undefined\n"); 7293 #endif 7294 break; 7295 case XPATH_NODESET: 7296 case XPATH_XSLT_TREE: 7297 ret = xmlXPathEqualNodeSets(arg1, arg2, 1); 7298 break; 7299 case XPATH_BOOLEAN: 7300 if ((arg1->nodesetval == NULL) || 7301 (arg1->nodesetval->nodeNr == 0)) ret = 0; 7302 else 7303 ret = 1; 7304 ret = (ret != arg2->boolval); 7305 break; 7306 case XPATH_NUMBER: 7307 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1); 7308 break; 7309 case XPATH_STRING: 7310 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1); 7311 break; 7312 case XPATH_USERS: 7313 case XPATH_POINT: 7314 case XPATH_RANGE: 7315 case XPATH_LOCATIONSET: 7316 TODO 7317 break; 7318 } 7319 xmlXPathReleaseObject(ctxt->context, arg1); 7320 xmlXPathReleaseObject(ctxt->context, arg2); 7321 return(ret); 7322 } 7323 7324 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2)); 7325 } 7326 7327 /** 7328 * xmlXPathCompareValues: 7329 * @ctxt: the XPath Parser context 7330 * @inf: less than (1) or greater than (0) 7331 * @strict: is the comparison strict 7332 * 7333 * Implement the compare operation on XPath objects: 7334 * @arg1 < @arg2 (1, 1, ... 7335 * @arg1 <= @arg2 (1, 0, ... 7336 * @arg1 > @arg2 (0, 1, ... 7337 * @arg1 >= @arg2 (0, 0, ... 7338 * 7339 * When neither object to be compared is a node-set and the operator is 7340 * <=, <, >=, >, then the objects are compared by converted both objects 7341 * to numbers and comparing the numbers according to IEEE 754. The < 7342 * comparison will be true if and only if the first number is less than the 7343 * second number. The <= comparison will be true if and only if the first 7344 * number is less than or equal to the second number. The > comparison 7345 * will be true if and only if the first number is greater than the second 7346 * number. The >= comparison will be true if and only if the first number 7347 * is greater than or equal to the second number. 7348 * 7349 * Returns 1 if the comparison succeeded, 0 if it failed 7350 */ 7351 int 7352 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) { 7353 int ret = 0, arg1i = 0, arg2i = 0; 7354 xmlXPathObjectPtr arg1, arg2; 7355 7356 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); 7357 arg2 = valuePop(ctxt); 7358 arg1 = valuePop(ctxt); 7359 if ((arg1 == NULL) || (arg2 == NULL)) { 7360 if (arg1 != NULL) 7361 xmlXPathReleaseObject(ctxt->context, arg1); 7362 else 7363 xmlXPathReleaseObject(ctxt->context, arg2); 7364 XP_ERROR0(XPATH_INVALID_OPERAND); 7365 } 7366 7367 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 7368 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7369 /* 7370 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments 7371 * are not freed from within this routine; they will be freed from the 7372 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue 7373 */ 7374 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) && 7375 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){ 7376 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2); 7377 } else { 7378 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7379 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict, 7380 arg1, arg2); 7381 } else { 7382 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict, 7383 arg2, arg1); 7384 } 7385 } 7386 return(ret); 7387 } 7388 7389 if (arg1->type != XPATH_NUMBER) { 7390 valuePush(ctxt, arg1); 7391 xmlXPathNumberFunction(ctxt, 1); 7392 arg1 = valuePop(ctxt); 7393 } 7394 if (arg1->type != XPATH_NUMBER) { 7395 xmlXPathFreeObject(arg1); 7396 xmlXPathFreeObject(arg2); 7397 XP_ERROR0(XPATH_INVALID_OPERAND); 7398 } 7399 if (arg2->type != XPATH_NUMBER) { 7400 valuePush(ctxt, arg2); 7401 xmlXPathNumberFunction(ctxt, 1); 7402 arg2 = valuePop(ctxt); 7403 } 7404 if (arg2->type != XPATH_NUMBER) { 7405 xmlXPathReleaseObject(ctxt->context, arg1); 7406 xmlXPathReleaseObject(ctxt->context, arg2); 7407 XP_ERROR0(XPATH_INVALID_OPERAND); 7408 } 7409 /* 7410 * Add tests for infinity and nan 7411 * => feedback on 3.4 for Inf and NaN 7412 */ 7413 /* Hand check NaN and Infinity comparisons */ 7414 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) { 7415 ret=0; 7416 } else { 7417 arg1i=xmlXPathIsInf(arg1->floatval); 7418 arg2i=xmlXPathIsInf(arg2->floatval); 7419 if (inf && strict) { 7420 if ((arg1i == -1 && arg2i != -1) || 7421 (arg2i == 1 && arg1i != 1)) { 7422 ret = 1; 7423 } else if (arg1i == 0 && arg2i == 0) { 7424 ret = (arg1->floatval < arg2->floatval); 7425 } else { 7426 ret = 0; 7427 } 7428 } 7429 else if (inf && !strict) { 7430 if (arg1i == -1 || arg2i == 1) { 7431 ret = 1; 7432 } else if (arg1i == 0 && arg2i == 0) { 7433 ret = (arg1->floatval <= arg2->floatval); 7434 } else { 7435 ret = 0; 7436 } 7437 } 7438 else if (!inf && strict) { 7439 if ((arg1i == 1 && arg2i != 1) || 7440 (arg2i == -1 && arg1i != -1)) { 7441 ret = 1; 7442 } else if (arg1i == 0 && arg2i == 0) { 7443 ret = (arg1->floatval > arg2->floatval); 7444 } else { 7445 ret = 0; 7446 } 7447 } 7448 else if (!inf && !strict) { 7449 if (arg1i == 1 || arg2i == -1) { 7450 ret = 1; 7451 } else if (arg1i == 0 && arg2i == 0) { 7452 ret = (arg1->floatval >= arg2->floatval); 7453 } else { 7454 ret = 0; 7455 } 7456 } 7457 } 7458 xmlXPathReleaseObject(ctxt->context, arg1); 7459 xmlXPathReleaseObject(ctxt->context, arg2); 7460 return(ret); 7461 } 7462 7463 /** 7464 * xmlXPathValueFlipSign: 7465 * @ctxt: the XPath Parser context 7466 * 7467 * Implement the unary - operation on an XPath object 7468 * The numeric operators convert their operands to numbers as if 7469 * by calling the number function. 7470 */ 7471 void 7472 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) { 7473 if ((ctxt == NULL) || (ctxt->context == NULL)) return; 7474 CAST_TO_NUMBER; 7475 CHECK_TYPE(XPATH_NUMBER); 7476 ctxt->value->floatval = -ctxt->value->floatval; 7477 } 7478 7479 /** 7480 * xmlXPathAddValues: 7481 * @ctxt: the XPath Parser context 7482 * 7483 * Implement the add operation on XPath objects: 7484 * The numeric operators convert their operands to numbers as if 7485 * by calling the number function. 7486 */ 7487 void 7488 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) { 7489 xmlXPathObjectPtr arg; 7490 double val; 7491 7492 arg = valuePop(ctxt); 7493 if (arg == NULL) 7494 XP_ERROR(XPATH_INVALID_OPERAND); 7495 val = xmlXPathCastToNumber(arg); 7496 xmlXPathReleaseObject(ctxt->context, arg); 7497 CAST_TO_NUMBER; 7498 CHECK_TYPE(XPATH_NUMBER); 7499 ctxt->value->floatval += val; 7500 } 7501 7502 /** 7503 * xmlXPathSubValues: 7504 * @ctxt: the XPath Parser context 7505 * 7506 * Implement the subtraction operation on XPath objects: 7507 * The numeric operators convert their operands to numbers as if 7508 * by calling the number function. 7509 */ 7510 void 7511 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) { 7512 xmlXPathObjectPtr arg; 7513 double val; 7514 7515 arg = valuePop(ctxt); 7516 if (arg == NULL) 7517 XP_ERROR(XPATH_INVALID_OPERAND); 7518 val = xmlXPathCastToNumber(arg); 7519 xmlXPathReleaseObject(ctxt->context, arg); 7520 CAST_TO_NUMBER; 7521 CHECK_TYPE(XPATH_NUMBER); 7522 ctxt->value->floatval -= val; 7523 } 7524 7525 /** 7526 * xmlXPathMultValues: 7527 * @ctxt: the XPath Parser context 7528 * 7529 * Implement the multiply operation on XPath objects: 7530 * The numeric operators convert their operands to numbers as if 7531 * by calling the number function. 7532 */ 7533 void 7534 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) { 7535 xmlXPathObjectPtr arg; 7536 double val; 7537 7538 arg = valuePop(ctxt); 7539 if (arg == NULL) 7540 XP_ERROR(XPATH_INVALID_OPERAND); 7541 val = xmlXPathCastToNumber(arg); 7542 xmlXPathReleaseObject(ctxt->context, arg); 7543 CAST_TO_NUMBER; 7544 CHECK_TYPE(XPATH_NUMBER); 7545 ctxt->value->floatval *= val; 7546 } 7547 7548 /** 7549 * xmlXPathDivValues: 7550 * @ctxt: the XPath Parser context 7551 * 7552 * Implement the div operation on XPath objects @arg1 / @arg2: 7553 * The numeric operators convert their operands to numbers as if 7554 * by calling the number function. 7555 */ 7556 void 7557 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) { 7558 xmlXPathObjectPtr arg; 7559 double val; 7560 7561 arg = valuePop(ctxt); 7562 if (arg == NULL) 7563 XP_ERROR(XPATH_INVALID_OPERAND); 7564 val = xmlXPathCastToNumber(arg); 7565 xmlXPathReleaseObject(ctxt->context, arg); 7566 CAST_TO_NUMBER; 7567 CHECK_TYPE(XPATH_NUMBER); 7568 ctxt->value->floatval /= val; 7569 } 7570 7571 /** 7572 * xmlXPathModValues: 7573 * @ctxt: the XPath Parser context 7574 * 7575 * Implement the mod operation on XPath objects: @arg1 / @arg2 7576 * The numeric operators convert their operands to numbers as if 7577 * by calling the number function. 7578 */ 7579 void 7580 xmlXPathModValues(xmlXPathParserContextPtr ctxt) { 7581 xmlXPathObjectPtr arg; 7582 double arg1, arg2; 7583 7584 arg = valuePop(ctxt); 7585 if (arg == NULL) 7586 XP_ERROR(XPATH_INVALID_OPERAND); 7587 arg2 = xmlXPathCastToNumber(arg); 7588 xmlXPathReleaseObject(ctxt->context, arg); 7589 CAST_TO_NUMBER; 7590 CHECK_TYPE(XPATH_NUMBER); 7591 arg1 = ctxt->value->floatval; 7592 if (arg2 == 0) 7593 ctxt->value->floatval = NAN; 7594 else { 7595 ctxt->value->floatval = fmod(arg1, arg2); 7596 } 7597 } 7598 7599 /************************************************************************ 7600 * * 7601 * The traversal functions * 7602 * * 7603 ************************************************************************/ 7604 7605 /* 7606 * A traversal function enumerates nodes along an axis. 7607 * Initially it must be called with NULL, and it indicates 7608 * termination on the axis by returning NULL. 7609 */ 7610 typedef xmlNodePtr (*xmlXPathTraversalFunction) 7611 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur); 7612 7613 /* 7614 * xmlXPathTraversalFunctionExt: 7615 * A traversal function enumerates nodes along an axis. 7616 * Initially it must be called with NULL, and it indicates 7617 * termination on the axis by returning NULL. 7618 * The context node of the traversal is specified via @contextNode. 7619 */ 7620 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt) 7621 (xmlNodePtr cur, xmlNodePtr contextNode); 7622 7623 /* 7624 * xmlXPathNodeSetMergeFunction: 7625 * Used for merging node sets in xmlXPathCollectAndTest(). 7626 */ 7627 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction) 7628 (xmlNodeSetPtr, xmlNodeSetPtr, int); 7629 7630 7631 /** 7632 * xmlXPathNextSelf: 7633 * @ctxt: the XPath Parser context 7634 * @cur: the current node in the traversal 7635 * 7636 * Traversal function for the "self" direction 7637 * The self axis contains just the context node itself 7638 * 7639 * Returns the next element following that axis 7640 */ 7641 xmlNodePtr 7642 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7643 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7644 if (cur == NULL) 7645 return(ctxt->context->node); 7646 return(NULL); 7647 } 7648 7649 /** 7650 * xmlXPathNextChild: 7651 * @ctxt: the XPath Parser context 7652 * @cur: the current node in the traversal 7653 * 7654 * Traversal function for the "child" direction 7655 * The child axis contains the children of the context node in document order. 7656 * 7657 * Returns the next element following that axis 7658 */ 7659 xmlNodePtr 7660 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7661 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7662 if (cur == NULL) { 7663 if (ctxt->context->node == NULL) return(NULL); 7664 switch (ctxt->context->node->type) { 7665 case XML_ELEMENT_NODE: 7666 case XML_TEXT_NODE: 7667 case XML_CDATA_SECTION_NODE: 7668 case XML_ENTITY_REF_NODE: 7669 case XML_ENTITY_NODE: 7670 case XML_PI_NODE: 7671 case XML_COMMENT_NODE: 7672 case XML_NOTATION_NODE: 7673 case XML_DTD_NODE: 7674 return(ctxt->context->node->children); 7675 case XML_DOCUMENT_NODE: 7676 case XML_DOCUMENT_TYPE_NODE: 7677 case XML_DOCUMENT_FRAG_NODE: 7678 case XML_HTML_DOCUMENT_NODE: 7679 #ifdef LIBXML_DOCB_ENABLED 7680 case XML_DOCB_DOCUMENT_NODE: 7681 #endif 7682 return(((xmlDocPtr) ctxt->context->node)->children); 7683 case XML_ELEMENT_DECL: 7684 case XML_ATTRIBUTE_DECL: 7685 case XML_ENTITY_DECL: 7686 case XML_ATTRIBUTE_NODE: 7687 case XML_NAMESPACE_DECL: 7688 case XML_XINCLUDE_START: 7689 case XML_XINCLUDE_END: 7690 return(NULL); 7691 } 7692 return(NULL); 7693 } 7694 if ((cur->type == XML_DOCUMENT_NODE) || 7695 (cur->type == XML_HTML_DOCUMENT_NODE)) 7696 return(NULL); 7697 return(cur->next); 7698 } 7699 7700 /** 7701 * xmlXPathNextChildElement: 7702 * @ctxt: the XPath Parser context 7703 * @cur: the current node in the traversal 7704 * 7705 * Traversal function for the "child" direction and nodes of type element. 7706 * The child axis contains the children of the context node in document order. 7707 * 7708 * Returns the next element following that axis 7709 */ 7710 static xmlNodePtr 7711 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7712 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7713 if (cur == NULL) { 7714 cur = ctxt->context->node; 7715 if (cur == NULL) return(NULL); 7716 /* 7717 * Get the first element child. 7718 */ 7719 switch (cur->type) { 7720 case XML_ELEMENT_NODE: 7721 case XML_DOCUMENT_FRAG_NODE: 7722 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */ 7723 case XML_ENTITY_NODE: 7724 cur = cur->children; 7725 if (cur != NULL) { 7726 if (cur->type == XML_ELEMENT_NODE) 7727 return(cur); 7728 do { 7729 cur = cur->next; 7730 } while ((cur != NULL) && 7731 (cur->type != XML_ELEMENT_NODE)); 7732 return(cur); 7733 } 7734 return(NULL); 7735 case XML_DOCUMENT_NODE: 7736 case XML_HTML_DOCUMENT_NODE: 7737 #ifdef LIBXML_DOCB_ENABLED 7738 case XML_DOCB_DOCUMENT_NODE: 7739 #endif 7740 return(xmlDocGetRootElement((xmlDocPtr) cur)); 7741 default: 7742 return(NULL); 7743 } 7744 return(NULL); 7745 } 7746 /* 7747 * Get the next sibling element node. 7748 */ 7749 switch (cur->type) { 7750 case XML_ELEMENT_NODE: 7751 case XML_TEXT_NODE: 7752 case XML_ENTITY_REF_NODE: 7753 case XML_ENTITY_NODE: 7754 case XML_CDATA_SECTION_NODE: 7755 case XML_PI_NODE: 7756 case XML_COMMENT_NODE: 7757 case XML_XINCLUDE_END: 7758 break; 7759 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */ 7760 default: 7761 return(NULL); 7762 } 7763 if (cur->next != NULL) { 7764 if (cur->next->type == XML_ELEMENT_NODE) 7765 return(cur->next); 7766 cur = cur->next; 7767 do { 7768 cur = cur->next; 7769 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE)); 7770 return(cur); 7771 } 7772 return(NULL); 7773 } 7774 7775 #if 0 7776 /** 7777 * xmlXPathNextDescendantOrSelfElemParent: 7778 * @ctxt: the XPath Parser context 7779 * @cur: the current node in the traversal 7780 * 7781 * Traversal function for the "descendant-or-self" axis. 7782 * Additionally it returns only nodes which can be parents of 7783 * element nodes. 7784 * 7785 * 7786 * Returns the next element following that axis 7787 */ 7788 static xmlNodePtr 7789 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur, 7790 xmlNodePtr contextNode) 7791 { 7792 if (cur == NULL) { 7793 if (contextNode == NULL) 7794 return(NULL); 7795 switch (contextNode->type) { 7796 case XML_ELEMENT_NODE: 7797 case XML_XINCLUDE_START: 7798 case XML_DOCUMENT_FRAG_NODE: 7799 case XML_DOCUMENT_NODE: 7800 #ifdef LIBXML_DOCB_ENABLED 7801 case XML_DOCB_DOCUMENT_NODE: 7802 #endif 7803 case XML_HTML_DOCUMENT_NODE: 7804 return(contextNode); 7805 default: 7806 return(NULL); 7807 } 7808 return(NULL); 7809 } else { 7810 xmlNodePtr start = cur; 7811 7812 while (cur != NULL) { 7813 switch (cur->type) { 7814 case XML_ELEMENT_NODE: 7815 /* TODO: OK to have XInclude here? */ 7816 case XML_XINCLUDE_START: 7817 case XML_DOCUMENT_FRAG_NODE: 7818 if (cur != start) 7819 return(cur); 7820 if (cur->children != NULL) { 7821 cur = cur->children; 7822 continue; 7823 } 7824 break; 7825 /* Not sure if we need those here. */ 7826 case XML_DOCUMENT_NODE: 7827 #ifdef LIBXML_DOCB_ENABLED 7828 case XML_DOCB_DOCUMENT_NODE: 7829 #endif 7830 case XML_HTML_DOCUMENT_NODE: 7831 if (cur != start) 7832 return(cur); 7833 return(xmlDocGetRootElement((xmlDocPtr) cur)); 7834 default: 7835 break; 7836 } 7837 7838 next_sibling: 7839 if ((cur == NULL) || (cur == contextNode)) 7840 return(NULL); 7841 if (cur->next != NULL) { 7842 cur = cur->next; 7843 } else { 7844 cur = cur->parent; 7845 goto next_sibling; 7846 } 7847 } 7848 } 7849 return(NULL); 7850 } 7851 #endif 7852 7853 /** 7854 * xmlXPathNextDescendant: 7855 * @ctxt: the XPath Parser context 7856 * @cur: the current node in the traversal 7857 * 7858 * Traversal function for the "descendant" direction 7859 * the descendant axis contains the descendants of the context node in document 7860 * order; a descendant is a child or a child of a child and so on. 7861 * 7862 * Returns the next element following that axis 7863 */ 7864 xmlNodePtr 7865 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7866 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7867 if (cur == NULL) { 7868 if (ctxt->context->node == NULL) 7869 return(NULL); 7870 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 7871 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 7872 return(NULL); 7873 7874 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc) 7875 return(ctxt->context->doc->children); 7876 return(ctxt->context->node->children); 7877 } 7878 7879 if (cur->type == XML_NAMESPACE_DECL) 7880 return(NULL); 7881 if (cur->children != NULL) { 7882 /* 7883 * Do not descend on entities declarations 7884 */ 7885 if (cur->children->type != XML_ENTITY_DECL) { 7886 cur = cur->children; 7887 /* 7888 * Skip DTDs 7889 */ 7890 if (cur->type != XML_DTD_NODE) 7891 return(cur); 7892 } 7893 } 7894 7895 if (cur == ctxt->context->node) return(NULL); 7896 7897 while (cur->next != NULL) { 7898 cur = cur->next; 7899 if ((cur->type != XML_ENTITY_DECL) && 7900 (cur->type != XML_DTD_NODE)) 7901 return(cur); 7902 } 7903 7904 do { 7905 cur = cur->parent; 7906 if (cur == NULL) break; 7907 if (cur == ctxt->context->node) return(NULL); 7908 if (cur->next != NULL) { 7909 cur = cur->next; 7910 return(cur); 7911 } 7912 } while (cur != NULL); 7913 return(cur); 7914 } 7915 7916 /** 7917 * xmlXPathNextDescendantOrSelf: 7918 * @ctxt: the XPath Parser context 7919 * @cur: the current node in the traversal 7920 * 7921 * Traversal function for the "descendant-or-self" direction 7922 * the descendant-or-self axis contains the context node and the descendants 7923 * of the context node in document order; thus the context node is the first 7924 * node on the axis, and the first child of the context node is the second node 7925 * on the axis 7926 * 7927 * Returns the next element following that axis 7928 */ 7929 xmlNodePtr 7930 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7931 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7932 if (cur == NULL) 7933 return(ctxt->context->node); 7934 7935 if (ctxt->context->node == NULL) 7936 return(NULL); 7937 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 7938 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 7939 return(NULL); 7940 7941 return(xmlXPathNextDescendant(ctxt, cur)); 7942 } 7943 7944 /** 7945 * xmlXPathNextParent: 7946 * @ctxt: the XPath Parser context 7947 * @cur: the current node in the traversal 7948 * 7949 * Traversal function for the "parent" direction 7950 * The parent axis contains the parent of the context node, if there is one. 7951 * 7952 * Returns the next element following that axis 7953 */ 7954 xmlNodePtr 7955 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7956 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7957 /* 7958 * the parent of an attribute or namespace node is the element 7959 * to which the attribute or namespace node is attached 7960 * Namespace handling !!! 7961 */ 7962 if (cur == NULL) { 7963 if (ctxt->context->node == NULL) return(NULL); 7964 switch (ctxt->context->node->type) { 7965 case XML_ELEMENT_NODE: 7966 case XML_TEXT_NODE: 7967 case XML_CDATA_SECTION_NODE: 7968 case XML_ENTITY_REF_NODE: 7969 case XML_ENTITY_NODE: 7970 case XML_PI_NODE: 7971 case XML_COMMENT_NODE: 7972 case XML_NOTATION_NODE: 7973 case XML_DTD_NODE: 7974 case XML_ELEMENT_DECL: 7975 case XML_ATTRIBUTE_DECL: 7976 case XML_XINCLUDE_START: 7977 case XML_XINCLUDE_END: 7978 case XML_ENTITY_DECL: 7979 if (ctxt->context->node->parent == NULL) 7980 return((xmlNodePtr) ctxt->context->doc); 7981 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) && 7982 ((ctxt->context->node->parent->name[0] == ' ') || 7983 (xmlStrEqual(ctxt->context->node->parent->name, 7984 BAD_CAST "fake node libxslt")))) 7985 return(NULL); 7986 return(ctxt->context->node->parent); 7987 case XML_ATTRIBUTE_NODE: { 7988 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node; 7989 7990 return(att->parent); 7991 } 7992 case XML_DOCUMENT_NODE: 7993 case XML_DOCUMENT_TYPE_NODE: 7994 case XML_DOCUMENT_FRAG_NODE: 7995 case XML_HTML_DOCUMENT_NODE: 7996 #ifdef LIBXML_DOCB_ENABLED 7997 case XML_DOCB_DOCUMENT_NODE: 7998 #endif 7999 return(NULL); 8000 case XML_NAMESPACE_DECL: { 8001 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; 8002 8003 if ((ns->next != NULL) && 8004 (ns->next->type != XML_NAMESPACE_DECL)) 8005 return((xmlNodePtr) ns->next); 8006 return(NULL); 8007 } 8008 } 8009 } 8010 return(NULL); 8011 } 8012 8013 /** 8014 * xmlXPathNextAncestor: 8015 * @ctxt: the XPath Parser context 8016 * @cur: the current node in the traversal 8017 * 8018 * Traversal function for the "ancestor" direction 8019 * the ancestor axis contains the ancestors of the context node; the ancestors 8020 * of the context node consist of the parent of context node and the parent's 8021 * parent and so on; the nodes are ordered in reverse document order; thus the 8022 * parent is the first node on the axis, and the parent's parent is the second 8023 * node on the axis 8024 * 8025 * Returns the next element following that axis 8026 */ 8027 xmlNodePtr 8028 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8029 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8030 /* 8031 * the parent of an attribute or namespace node is the element 8032 * to which the attribute or namespace node is attached 8033 * !!!!!!!!!!!!! 8034 */ 8035 if (cur == NULL) { 8036 if (ctxt->context->node == NULL) return(NULL); 8037 switch (ctxt->context->node->type) { 8038 case XML_ELEMENT_NODE: 8039 case XML_TEXT_NODE: 8040 case XML_CDATA_SECTION_NODE: 8041 case XML_ENTITY_REF_NODE: 8042 case XML_ENTITY_NODE: 8043 case XML_PI_NODE: 8044 case XML_COMMENT_NODE: 8045 case XML_DTD_NODE: 8046 case XML_ELEMENT_DECL: 8047 case XML_ATTRIBUTE_DECL: 8048 case XML_ENTITY_DECL: 8049 case XML_NOTATION_NODE: 8050 case XML_XINCLUDE_START: 8051 case XML_XINCLUDE_END: 8052 if (ctxt->context->node->parent == NULL) 8053 return((xmlNodePtr) ctxt->context->doc); 8054 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) && 8055 ((ctxt->context->node->parent->name[0] == ' ') || 8056 (xmlStrEqual(ctxt->context->node->parent->name, 8057 BAD_CAST "fake node libxslt")))) 8058 return(NULL); 8059 return(ctxt->context->node->parent); 8060 case XML_ATTRIBUTE_NODE: { 8061 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node; 8062 8063 return(tmp->parent); 8064 } 8065 case XML_DOCUMENT_NODE: 8066 case XML_DOCUMENT_TYPE_NODE: 8067 case XML_DOCUMENT_FRAG_NODE: 8068 case XML_HTML_DOCUMENT_NODE: 8069 #ifdef LIBXML_DOCB_ENABLED 8070 case XML_DOCB_DOCUMENT_NODE: 8071 #endif 8072 return(NULL); 8073 case XML_NAMESPACE_DECL: { 8074 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; 8075 8076 if ((ns->next != NULL) && 8077 (ns->next->type != XML_NAMESPACE_DECL)) 8078 return((xmlNodePtr) ns->next); 8079 /* Bad, how did that namespace end up here ? */ 8080 return(NULL); 8081 } 8082 } 8083 return(NULL); 8084 } 8085 if (cur == ctxt->context->doc->children) 8086 return((xmlNodePtr) ctxt->context->doc); 8087 if (cur == (xmlNodePtr) ctxt->context->doc) 8088 return(NULL); 8089 switch (cur->type) { 8090 case XML_ELEMENT_NODE: 8091 case XML_TEXT_NODE: 8092 case XML_CDATA_SECTION_NODE: 8093 case XML_ENTITY_REF_NODE: 8094 case XML_ENTITY_NODE: 8095 case XML_PI_NODE: 8096 case XML_COMMENT_NODE: 8097 case XML_NOTATION_NODE: 8098 case XML_DTD_NODE: 8099 case XML_ELEMENT_DECL: 8100 case XML_ATTRIBUTE_DECL: 8101 case XML_ENTITY_DECL: 8102 case XML_XINCLUDE_START: 8103 case XML_XINCLUDE_END: 8104 if (cur->parent == NULL) 8105 return(NULL); 8106 if ((cur->parent->type == XML_ELEMENT_NODE) && 8107 ((cur->parent->name[0] == ' ') || 8108 (xmlStrEqual(cur->parent->name, 8109 BAD_CAST "fake node libxslt")))) 8110 return(NULL); 8111 return(cur->parent); 8112 case XML_ATTRIBUTE_NODE: { 8113 xmlAttrPtr att = (xmlAttrPtr) cur; 8114 8115 return(att->parent); 8116 } 8117 case XML_NAMESPACE_DECL: { 8118 xmlNsPtr ns = (xmlNsPtr) cur; 8119 8120 if ((ns->next != NULL) && 8121 (ns->next->type != XML_NAMESPACE_DECL)) 8122 return((xmlNodePtr) ns->next); 8123 /* Bad, how did that namespace end up here ? */ 8124 return(NULL); 8125 } 8126 case XML_DOCUMENT_NODE: 8127 case XML_DOCUMENT_TYPE_NODE: 8128 case XML_DOCUMENT_FRAG_NODE: 8129 case XML_HTML_DOCUMENT_NODE: 8130 #ifdef LIBXML_DOCB_ENABLED 8131 case XML_DOCB_DOCUMENT_NODE: 8132 #endif 8133 return(NULL); 8134 } 8135 return(NULL); 8136 } 8137 8138 /** 8139 * xmlXPathNextAncestorOrSelf: 8140 * @ctxt: the XPath Parser context 8141 * @cur: the current node in the traversal 8142 * 8143 * Traversal function for the "ancestor-or-self" direction 8144 * he ancestor-or-self axis contains the context node and ancestors of 8145 * the context node in reverse document order; thus the context node is 8146 * the first node on the axis, and the context node's parent the second; 8147 * parent here is defined the same as with the parent axis. 8148 * 8149 * Returns the next element following that axis 8150 */ 8151 xmlNodePtr 8152 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8153 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8154 if (cur == NULL) 8155 return(ctxt->context->node); 8156 return(xmlXPathNextAncestor(ctxt, cur)); 8157 } 8158 8159 /** 8160 * xmlXPathNextFollowingSibling: 8161 * @ctxt: the XPath Parser context 8162 * @cur: the current node in the traversal 8163 * 8164 * Traversal function for the "following-sibling" direction 8165 * The following-sibling axis contains the following siblings of the context 8166 * node in document order. 8167 * 8168 * Returns the next element following that axis 8169 */ 8170 xmlNodePtr 8171 xmlXPathNextFollowingSibling(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->next); 8180 return(cur->next); 8181 } 8182 8183 /** 8184 * xmlXPathNextPrecedingSibling: 8185 * @ctxt: the XPath Parser context 8186 * @cur: the current node in the traversal 8187 * 8188 * Traversal function for the "preceding-sibling" direction 8189 * The preceding-sibling axis contains the preceding siblings of the context 8190 * node in reverse document order; the first preceding sibling is first on the 8191 * axis; the sibling preceding that node is the second on the axis and so on. 8192 * 8193 * Returns the next element following that axis 8194 */ 8195 xmlNodePtr 8196 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8197 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8198 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 8199 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 8200 return(NULL); 8201 if (cur == (xmlNodePtr) ctxt->context->doc) 8202 return(NULL); 8203 if (cur == NULL) 8204 return(ctxt->context->node->prev); 8205 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) { 8206 cur = cur->prev; 8207 if (cur == NULL) 8208 return(ctxt->context->node->prev); 8209 } 8210 return(cur->prev); 8211 } 8212 8213 /** 8214 * xmlXPathNextFollowing: 8215 * @ctxt: the XPath Parser context 8216 * @cur: the current node in the traversal 8217 * 8218 * Traversal function for the "following" direction 8219 * The following axis contains all nodes in the same document as the context 8220 * node that are after the context node in document order, excluding any 8221 * descendants and excluding attribute nodes and namespace nodes; the nodes 8222 * are ordered in document order 8223 * 8224 * Returns the next element following that axis 8225 */ 8226 xmlNodePtr 8227 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8228 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8229 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) && 8230 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL)) 8231 return(cur->children); 8232 8233 if (cur == NULL) { 8234 cur = ctxt->context->node; 8235 if (cur->type == XML_ATTRIBUTE_NODE) { 8236 cur = cur->parent; 8237 } else if (cur->type == XML_NAMESPACE_DECL) { 8238 xmlNsPtr ns = (xmlNsPtr) cur; 8239 8240 if ((ns->next == NULL) || 8241 (ns->next->type == XML_NAMESPACE_DECL)) 8242 return (NULL); 8243 cur = (xmlNodePtr) ns->next; 8244 } 8245 } 8246 if (cur == NULL) return(NULL) ; /* ERROR */ 8247 if (cur->next != NULL) return(cur->next) ; 8248 do { 8249 cur = cur->parent; 8250 if (cur == NULL) break; 8251 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL); 8252 if (cur->next != NULL) return(cur->next); 8253 } while (cur != NULL); 8254 return(cur); 8255 } 8256 8257 /* 8258 * xmlXPathIsAncestor: 8259 * @ancestor: the ancestor node 8260 * @node: the current node 8261 * 8262 * Check that @ancestor is a @node's ancestor 8263 * 8264 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise. 8265 */ 8266 static int 8267 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) { 8268 if ((ancestor == NULL) || (node == NULL)) return(0); 8269 if (node->type == XML_NAMESPACE_DECL) 8270 return(0); 8271 if (ancestor->type == XML_NAMESPACE_DECL) 8272 return(0); 8273 /* nodes need to be in the same document */ 8274 if (ancestor->doc != node->doc) return(0); 8275 /* avoid searching if ancestor or node is the root node */ 8276 if (ancestor == (xmlNodePtr) node->doc) return(1); 8277 if (node == (xmlNodePtr) ancestor->doc) return(0); 8278 while (node->parent != NULL) { 8279 if (node->parent == ancestor) 8280 return(1); 8281 node = node->parent; 8282 } 8283 return(0); 8284 } 8285 8286 /** 8287 * xmlXPathNextPreceding: 8288 * @ctxt: the XPath Parser context 8289 * @cur: the current node in the traversal 8290 * 8291 * Traversal function for the "preceding" direction 8292 * the preceding axis contains all nodes in the same document as the context 8293 * node that are before the context node in document order, excluding any 8294 * ancestors and excluding attribute nodes and namespace nodes; the nodes are 8295 * ordered in reverse document order 8296 * 8297 * Returns the next element following that axis 8298 */ 8299 xmlNodePtr 8300 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) 8301 { 8302 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8303 if (cur == NULL) { 8304 cur = ctxt->context->node; 8305 if (cur->type == XML_ATTRIBUTE_NODE) { 8306 cur = cur->parent; 8307 } else if (cur->type == XML_NAMESPACE_DECL) { 8308 xmlNsPtr ns = (xmlNsPtr) cur; 8309 8310 if ((ns->next == NULL) || 8311 (ns->next->type == XML_NAMESPACE_DECL)) 8312 return (NULL); 8313 cur = (xmlNodePtr) ns->next; 8314 } 8315 } 8316 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) 8317 return (NULL); 8318 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) 8319 cur = cur->prev; 8320 do { 8321 if (cur->prev != NULL) { 8322 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ; 8323 return (cur); 8324 } 8325 8326 cur = cur->parent; 8327 if (cur == NULL) 8328 return (NULL); 8329 if (cur == ctxt->context->doc->children) 8330 return (NULL); 8331 } while (xmlXPathIsAncestor(cur, ctxt->context->node)); 8332 return (cur); 8333 } 8334 8335 /** 8336 * xmlXPathNextPrecedingInternal: 8337 * @ctxt: the XPath Parser context 8338 * @cur: the current node in the traversal 8339 * 8340 * Traversal function for the "preceding" direction 8341 * the preceding axis contains all nodes in the same document as the context 8342 * node that are before the context node in document order, excluding any 8343 * ancestors and excluding attribute nodes and namespace nodes; the nodes are 8344 * ordered in reverse document order 8345 * This is a faster implementation but internal only since it requires a 8346 * state kept in the parser context: ctxt->ancestor. 8347 * 8348 * Returns the next element following that axis 8349 */ 8350 static xmlNodePtr 8351 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt, 8352 xmlNodePtr cur) 8353 { 8354 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8355 if (cur == NULL) { 8356 cur = ctxt->context->node; 8357 if (cur == NULL) 8358 return (NULL); 8359 if (cur->type == XML_ATTRIBUTE_NODE) { 8360 cur = cur->parent; 8361 } else if (cur->type == XML_NAMESPACE_DECL) { 8362 xmlNsPtr ns = (xmlNsPtr) cur; 8363 8364 if ((ns->next == NULL) || 8365 (ns->next->type == XML_NAMESPACE_DECL)) 8366 return (NULL); 8367 cur = (xmlNodePtr) ns->next; 8368 } 8369 ctxt->ancestor = cur->parent; 8370 } 8371 if (cur->type == XML_NAMESPACE_DECL) 8372 return(NULL); 8373 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) 8374 cur = cur->prev; 8375 while (cur->prev == NULL) { 8376 cur = cur->parent; 8377 if (cur == NULL) 8378 return (NULL); 8379 if (cur == ctxt->context->doc->children) 8380 return (NULL); 8381 if (cur != ctxt->ancestor) 8382 return (cur); 8383 ctxt->ancestor = cur->parent; 8384 } 8385 cur = cur->prev; 8386 while (cur->last != NULL) 8387 cur = cur->last; 8388 return (cur); 8389 } 8390 8391 /** 8392 * xmlXPathNextNamespace: 8393 * @ctxt: the XPath Parser context 8394 * @cur: the current attribute in the traversal 8395 * 8396 * Traversal function for the "namespace" direction 8397 * the namespace axis contains the namespace nodes of the context node; 8398 * the order of nodes on this axis is implementation-defined; the axis will 8399 * be empty unless the context node is an element 8400 * 8401 * We keep the XML namespace node at the end of the list. 8402 * 8403 * Returns the next element following that axis 8404 */ 8405 xmlNodePtr 8406 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8407 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8408 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL); 8409 if (cur == NULL) { 8410 if (ctxt->context->tmpNsList != NULL) 8411 xmlFree(ctxt->context->tmpNsList); 8412 ctxt->context->tmpNsList = 8413 xmlGetNsList(ctxt->context->doc, ctxt->context->node); 8414 ctxt->context->tmpNsNr = 0; 8415 if (ctxt->context->tmpNsList != NULL) { 8416 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) { 8417 ctxt->context->tmpNsNr++; 8418 } 8419 } 8420 return((xmlNodePtr) xmlXPathXMLNamespace); 8421 } 8422 if (ctxt->context->tmpNsNr > 0) { 8423 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr]; 8424 } else { 8425 if (ctxt->context->tmpNsList != NULL) 8426 xmlFree(ctxt->context->tmpNsList); 8427 ctxt->context->tmpNsList = NULL; 8428 return(NULL); 8429 } 8430 } 8431 8432 /** 8433 * xmlXPathNextAttribute: 8434 * @ctxt: the XPath Parser context 8435 * @cur: the current attribute in the traversal 8436 * 8437 * Traversal function for the "attribute" direction 8438 * TODO: support DTD inherited default attributes 8439 * 8440 * Returns the next element following that axis 8441 */ 8442 xmlNodePtr 8443 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8444 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8445 if (ctxt->context->node == NULL) 8446 return(NULL); 8447 if (ctxt->context->node->type != XML_ELEMENT_NODE) 8448 return(NULL); 8449 if (cur == NULL) { 8450 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc) 8451 return(NULL); 8452 return((xmlNodePtr)ctxt->context->node->properties); 8453 } 8454 return((xmlNodePtr)cur->next); 8455 } 8456 8457 /************************************************************************ 8458 * * 8459 * NodeTest Functions * 8460 * * 8461 ************************************************************************/ 8462 8463 #define IS_FUNCTION 200 8464 8465 8466 /************************************************************************ 8467 * * 8468 * Implicit tree core function library * 8469 * * 8470 ************************************************************************/ 8471 8472 /** 8473 * xmlXPathRoot: 8474 * @ctxt: the XPath Parser context 8475 * 8476 * Initialize the context to the root of the document 8477 */ 8478 void 8479 xmlXPathRoot(xmlXPathParserContextPtr ctxt) { 8480 if ((ctxt == NULL) || (ctxt->context == NULL)) 8481 return; 8482 ctxt->context->node = (xmlNodePtr) ctxt->context->doc; 8483 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8484 ctxt->context->node)); 8485 } 8486 8487 /************************************************************************ 8488 * * 8489 * The explicit core function library * 8490 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib * 8491 * * 8492 ************************************************************************/ 8493 8494 8495 /** 8496 * xmlXPathLastFunction: 8497 * @ctxt: the XPath Parser context 8498 * @nargs: the number of arguments 8499 * 8500 * Implement the last() XPath function 8501 * number last() 8502 * The last function returns the number of nodes in the context node list. 8503 */ 8504 void 8505 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8506 CHECK_ARITY(0); 8507 if (ctxt->context->contextSize >= 0) { 8508 valuePush(ctxt, 8509 xmlXPathCacheNewFloat(ctxt->context, 8510 (double) ctxt->context->contextSize)); 8511 #ifdef DEBUG_EXPR 8512 xmlGenericError(xmlGenericErrorContext, 8513 "last() : %d\n", ctxt->context->contextSize); 8514 #endif 8515 } else { 8516 XP_ERROR(XPATH_INVALID_CTXT_SIZE); 8517 } 8518 } 8519 8520 /** 8521 * xmlXPathPositionFunction: 8522 * @ctxt: the XPath Parser context 8523 * @nargs: the number of arguments 8524 * 8525 * Implement the position() XPath function 8526 * number position() 8527 * The position function returns the position of the context node in the 8528 * context node list. The first position is 1, and so the last position 8529 * will be equal to last(). 8530 */ 8531 void 8532 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8533 CHECK_ARITY(0); 8534 if (ctxt->context->proximityPosition >= 0) { 8535 valuePush(ctxt, 8536 xmlXPathCacheNewFloat(ctxt->context, 8537 (double) ctxt->context->proximityPosition)); 8538 #ifdef DEBUG_EXPR 8539 xmlGenericError(xmlGenericErrorContext, "position() : %d\n", 8540 ctxt->context->proximityPosition); 8541 #endif 8542 } else { 8543 XP_ERROR(XPATH_INVALID_CTXT_POSITION); 8544 } 8545 } 8546 8547 /** 8548 * xmlXPathCountFunction: 8549 * @ctxt: the XPath Parser context 8550 * @nargs: the number of arguments 8551 * 8552 * Implement the count() XPath function 8553 * number count(node-set) 8554 */ 8555 void 8556 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8557 xmlXPathObjectPtr cur; 8558 8559 CHECK_ARITY(1); 8560 if ((ctxt->value == NULL) || 8561 ((ctxt->value->type != XPATH_NODESET) && 8562 (ctxt->value->type != XPATH_XSLT_TREE))) 8563 XP_ERROR(XPATH_INVALID_TYPE); 8564 cur = valuePop(ctxt); 8565 8566 if ((cur == NULL) || (cur->nodesetval == NULL)) 8567 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0)); 8568 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) { 8569 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 8570 (double) cur->nodesetval->nodeNr)); 8571 } else { 8572 if ((cur->nodesetval->nodeNr != 1) || 8573 (cur->nodesetval->nodeTab == NULL)) { 8574 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0)); 8575 } else { 8576 xmlNodePtr tmp; 8577 int i = 0; 8578 8579 tmp = cur->nodesetval->nodeTab[0]; 8580 if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) { 8581 tmp = tmp->children; 8582 while (tmp != NULL) { 8583 tmp = tmp->next; 8584 i++; 8585 } 8586 } 8587 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i)); 8588 } 8589 } 8590 xmlXPathReleaseObject(ctxt->context, cur); 8591 } 8592 8593 /** 8594 * xmlXPathGetElementsByIds: 8595 * @doc: the document 8596 * @ids: a whitespace separated list of IDs 8597 * 8598 * Selects elements by their unique ID. 8599 * 8600 * Returns a node-set of selected elements. 8601 */ 8602 static xmlNodeSetPtr 8603 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) { 8604 xmlNodeSetPtr ret; 8605 const xmlChar *cur = ids; 8606 xmlChar *ID; 8607 xmlAttrPtr attr; 8608 xmlNodePtr elem = NULL; 8609 8610 if (ids == NULL) return(NULL); 8611 8612 ret = xmlXPathNodeSetCreate(NULL); 8613 if (ret == NULL) 8614 return(ret); 8615 8616 while (IS_BLANK_CH(*cur)) cur++; 8617 while (*cur != 0) { 8618 while ((!IS_BLANK_CH(*cur)) && (*cur != 0)) 8619 cur++; 8620 8621 ID = xmlStrndup(ids, cur - ids); 8622 if (ID != NULL) { 8623 /* 8624 * We used to check the fact that the value passed 8625 * was an NCName, but this generated much troubles for 8626 * me and Aleksey Sanin, people blatantly violated that 8627 * constaint, like Visa3D spec. 8628 * if (xmlValidateNCName(ID, 1) == 0) 8629 */ 8630 attr = xmlGetID(doc, ID); 8631 if (attr != NULL) { 8632 if (attr->type == XML_ATTRIBUTE_NODE) 8633 elem = attr->parent; 8634 else if (attr->type == XML_ELEMENT_NODE) 8635 elem = (xmlNodePtr) attr; 8636 else 8637 elem = NULL; 8638 if (elem != NULL) 8639 xmlXPathNodeSetAdd(ret, elem); 8640 } 8641 xmlFree(ID); 8642 } 8643 8644 while (IS_BLANK_CH(*cur)) cur++; 8645 ids = cur; 8646 } 8647 return(ret); 8648 } 8649 8650 /** 8651 * xmlXPathIdFunction: 8652 * @ctxt: the XPath Parser context 8653 * @nargs: the number of arguments 8654 * 8655 * Implement the id() XPath function 8656 * node-set id(object) 8657 * The id function selects elements by their unique ID 8658 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set, 8659 * then the result is the union of the result of applying id to the 8660 * string value of each of the nodes in the argument node-set. When the 8661 * argument to id is of any other type, the argument is converted to a 8662 * string as if by a call to the string function; the string is split 8663 * into a whitespace-separated list of tokens (whitespace is any sequence 8664 * of characters matching the production S); the result is a node-set 8665 * containing the elements in the same document as the context node that 8666 * have a unique ID equal to any of the tokens in the list. 8667 */ 8668 void 8669 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8670 xmlChar *tokens; 8671 xmlNodeSetPtr ret; 8672 xmlXPathObjectPtr obj; 8673 8674 CHECK_ARITY(1); 8675 obj = valuePop(ctxt); 8676 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 8677 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) { 8678 xmlNodeSetPtr ns; 8679 int i; 8680 8681 ret = xmlXPathNodeSetCreate(NULL); 8682 /* 8683 * FIXME -- in an out-of-memory condition this will behave badly. 8684 * The solution is not clear -- we already popped an item from 8685 * ctxt, so the object is in a corrupt state. 8686 */ 8687 8688 if (obj->nodesetval != NULL) { 8689 for (i = 0; i < obj->nodesetval->nodeNr; i++) { 8690 tokens = 8691 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]); 8692 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens); 8693 ret = xmlXPathNodeSetMerge(ret, ns); 8694 xmlXPathFreeNodeSet(ns); 8695 if (tokens != NULL) 8696 xmlFree(tokens); 8697 } 8698 } 8699 xmlXPathReleaseObject(ctxt->context, obj); 8700 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret)); 8701 return; 8702 } 8703 obj = xmlXPathCacheConvertString(ctxt->context, obj); 8704 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval); 8705 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret)); 8706 xmlXPathReleaseObject(ctxt->context, obj); 8707 return; 8708 } 8709 8710 /** 8711 * xmlXPathLocalNameFunction: 8712 * @ctxt: the XPath Parser context 8713 * @nargs: the number of arguments 8714 * 8715 * Implement the local-name() XPath function 8716 * string local-name(node-set?) 8717 * The local-name function returns a string containing the local part 8718 * of the name of the node in the argument node-set that is first in 8719 * document order. If the node-set is empty or the first node has no 8720 * name, an empty string is returned. If the argument is omitted it 8721 * defaults to the context node. 8722 */ 8723 void 8724 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8725 xmlXPathObjectPtr cur; 8726 8727 if (ctxt == NULL) return; 8728 8729 if (nargs == 0) { 8730 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8731 ctxt->context->node)); 8732 nargs = 1; 8733 } 8734 8735 CHECK_ARITY(1); 8736 if ((ctxt->value == NULL) || 8737 ((ctxt->value->type != XPATH_NODESET) && 8738 (ctxt->value->type != XPATH_XSLT_TREE))) 8739 XP_ERROR(XPATH_INVALID_TYPE); 8740 cur = valuePop(ctxt); 8741 8742 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 8743 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8744 } else { 8745 int i = 0; /* Should be first in document order !!!!! */ 8746 switch (cur->nodesetval->nodeTab[i]->type) { 8747 case XML_ELEMENT_NODE: 8748 case XML_ATTRIBUTE_NODE: 8749 case XML_PI_NODE: 8750 if (cur->nodesetval->nodeTab[i]->name[0] == ' ') 8751 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8752 else 8753 valuePush(ctxt, 8754 xmlXPathCacheNewString(ctxt->context, 8755 cur->nodesetval->nodeTab[i]->name)); 8756 break; 8757 case XML_NAMESPACE_DECL: 8758 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 8759 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix)); 8760 break; 8761 default: 8762 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8763 } 8764 } 8765 xmlXPathReleaseObject(ctxt->context, cur); 8766 } 8767 8768 /** 8769 * xmlXPathNamespaceURIFunction: 8770 * @ctxt: the XPath Parser context 8771 * @nargs: the number of arguments 8772 * 8773 * Implement the namespace-uri() XPath function 8774 * string namespace-uri(node-set?) 8775 * The namespace-uri function returns a string containing the 8776 * namespace URI of the expanded name of the node in the argument 8777 * node-set that is first in document order. If the node-set is empty, 8778 * the first node has no name, or the expanded name has no namespace 8779 * URI, an empty string is returned. If the argument is omitted it 8780 * defaults to the context node. 8781 */ 8782 void 8783 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8784 xmlXPathObjectPtr cur; 8785 8786 if (ctxt == NULL) return; 8787 8788 if (nargs == 0) { 8789 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8790 ctxt->context->node)); 8791 nargs = 1; 8792 } 8793 CHECK_ARITY(1); 8794 if ((ctxt->value == NULL) || 8795 ((ctxt->value->type != XPATH_NODESET) && 8796 (ctxt->value->type != XPATH_XSLT_TREE))) 8797 XP_ERROR(XPATH_INVALID_TYPE); 8798 cur = valuePop(ctxt); 8799 8800 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 8801 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8802 } else { 8803 int i = 0; /* Should be first in document order !!!!! */ 8804 switch (cur->nodesetval->nodeTab[i]->type) { 8805 case XML_ELEMENT_NODE: 8806 case XML_ATTRIBUTE_NODE: 8807 if (cur->nodesetval->nodeTab[i]->ns == NULL) 8808 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8809 else 8810 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 8811 cur->nodesetval->nodeTab[i]->ns->href)); 8812 break; 8813 default: 8814 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8815 } 8816 } 8817 xmlXPathReleaseObject(ctxt->context, cur); 8818 } 8819 8820 /** 8821 * xmlXPathNameFunction: 8822 * @ctxt: the XPath Parser context 8823 * @nargs: the number of arguments 8824 * 8825 * Implement the name() XPath function 8826 * string name(node-set?) 8827 * The name function returns a string containing a QName representing 8828 * the name of the node in the argument node-set that is first in document 8829 * order. The QName must represent the name with respect to the namespace 8830 * declarations in effect on the node whose name is being represented. 8831 * Typically, this will be the form in which the name occurred in the XML 8832 * source. This need not be the case if there are namespace declarations 8833 * in effect on the node that associate multiple prefixes with the same 8834 * namespace. However, an implementation may include information about 8835 * the original prefix in its representation of nodes; in this case, an 8836 * implementation can ensure that the returned string is always the same 8837 * as the QName used in the XML source. If the argument it omitted it 8838 * defaults to the context node. 8839 * Libxml keep the original prefix so the "real qualified name" used is 8840 * returned. 8841 */ 8842 static void 8843 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) 8844 { 8845 xmlXPathObjectPtr cur; 8846 8847 if (nargs == 0) { 8848 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8849 ctxt->context->node)); 8850 nargs = 1; 8851 } 8852 8853 CHECK_ARITY(1); 8854 if ((ctxt->value == NULL) || 8855 ((ctxt->value->type != XPATH_NODESET) && 8856 (ctxt->value->type != XPATH_XSLT_TREE))) 8857 XP_ERROR(XPATH_INVALID_TYPE); 8858 cur = valuePop(ctxt); 8859 8860 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 8861 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8862 } else { 8863 int i = 0; /* Should be first in document order !!!!! */ 8864 8865 switch (cur->nodesetval->nodeTab[i]->type) { 8866 case XML_ELEMENT_NODE: 8867 case XML_ATTRIBUTE_NODE: 8868 if (cur->nodesetval->nodeTab[i]->name[0] == ' ') 8869 valuePush(ctxt, 8870 xmlXPathCacheNewCString(ctxt->context, "")); 8871 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) || 8872 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) { 8873 valuePush(ctxt, 8874 xmlXPathCacheNewString(ctxt->context, 8875 cur->nodesetval->nodeTab[i]->name)); 8876 } else { 8877 xmlChar *fullname; 8878 8879 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name, 8880 cur->nodesetval->nodeTab[i]->ns->prefix, 8881 NULL, 0); 8882 if (fullname == cur->nodesetval->nodeTab[i]->name) 8883 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name); 8884 if (fullname == NULL) { 8885 XP_ERROR(XPATH_MEMORY_ERROR); 8886 } 8887 valuePush(ctxt, xmlXPathCacheWrapString( 8888 ctxt->context, fullname)); 8889 } 8890 break; 8891 default: 8892 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8893 cur->nodesetval->nodeTab[i])); 8894 xmlXPathLocalNameFunction(ctxt, 1); 8895 } 8896 } 8897 xmlXPathReleaseObject(ctxt->context, cur); 8898 } 8899 8900 8901 /** 8902 * xmlXPathStringFunction: 8903 * @ctxt: the XPath Parser context 8904 * @nargs: the number of arguments 8905 * 8906 * Implement the string() XPath function 8907 * string string(object?) 8908 * The string function converts an object to a string as follows: 8909 * - A node-set is converted to a string by returning the value of 8910 * the node in the node-set that is first in document order. 8911 * If the node-set is empty, an empty string is returned. 8912 * - A number is converted to a string as follows 8913 * + NaN is converted to the string NaN 8914 * + positive zero is converted to the string 0 8915 * + negative zero is converted to the string 0 8916 * + positive infinity is converted to the string Infinity 8917 * + negative infinity is converted to the string -Infinity 8918 * + if the number is an integer, the number is represented in 8919 * decimal form as a Number with no decimal point and no leading 8920 * zeros, preceded by a minus sign (-) if the number is negative 8921 * + otherwise, the number is represented in decimal form as a 8922 * Number including a decimal point with at least one digit 8923 * before the decimal point and at least one digit after the 8924 * decimal point, preceded by a minus sign (-) if the number 8925 * is negative; there must be no leading zeros before the decimal 8926 * point apart possibly from the one required digit immediately 8927 * before the decimal point; beyond the one required digit 8928 * after the decimal point there must be as many, but only as 8929 * many, more digits as are needed to uniquely distinguish the 8930 * number from all other IEEE 754 numeric values. 8931 * - The boolean false value is converted to the string false. 8932 * The boolean true value is converted to the string true. 8933 * 8934 * If the argument is omitted, it defaults to a node-set with the 8935 * context node as its only member. 8936 */ 8937 void 8938 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8939 xmlXPathObjectPtr cur; 8940 8941 if (ctxt == NULL) return; 8942 if (nargs == 0) { 8943 valuePush(ctxt, 8944 xmlXPathCacheWrapString(ctxt->context, 8945 xmlXPathCastNodeToString(ctxt->context->node))); 8946 return; 8947 } 8948 8949 CHECK_ARITY(1); 8950 cur = valuePop(ctxt); 8951 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 8952 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur)); 8953 } 8954 8955 /** 8956 * xmlXPathStringLengthFunction: 8957 * @ctxt: the XPath Parser context 8958 * @nargs: the number of arguments 8959 * 8960 * Implement the string-length() XPath function 8961 * number string-length(string?) 8962 * The string-length returns the number of characters in the string 8963 * (see [3.6 Strings]). If the argument is omitted, it defaults to 8964 * the context node converted to a string, in other words the value 8965 * of the context node. 8966 */ 8967 void 8968 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8969 xmlXPathObjectPtr cur; 8970 8971 if (nargs == 0) { 8972 if ((ctxt == NULL) || (ctxt->context == NULL)) 8973 return; 8974 if (ctxt->context->node == NULL) { 8975 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0)); 8976 } else { 8977 xmlChar *content; 8978 8979 content = xmlXPathCastNodeToString(ctxt->context->node); 8980 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 8981 xmlUTF8Strlen(content))); 8982 xmlFree(content); 8983 } 8984 return; 8985 } 8986 CHECK_ARITY(1); 8987 CAST_TO_STRING; 8988 CHECK_TYPE(XPATH_STRING); 8989 cur = valuePop(ctxt); 8990 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 8991 xmlUTF8Strlen(cur->stringval))); 8992 xmlXPathReleaseObject(ctxt->context, cur); 8993 } 8994 8995 /** 8996 * xmlXPathConcatFunction: 8997 * @ctxt: the XPath Parser context 8998 * @nargs: the number of arguments 8999 * 9000 * Implement the concat() XPath function 9001 * string concat(string, string, string*) 9002 * The concat function returns the concatenation of its arguments. 9003 */ 9004 void 9005 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9006 xmlXPathObjectPtr cur, newobj; 9007 xmlChar *tmp; 9008 9009 if (ctxt == NULL) return; 9010 if (nargs < 2) { 9011 CHECK_ARITY(2); 9012 } 9013 9014 CAST_TO_STRING; 9015 cur = valuePop(ctxt); 9016 if ((cur == NULL) || (cur->type != XPATH_STRING)) { 9017 xmlXPathReleaseObject(ctxt->context, cur); 9018 return; 9019 } 9020 nargs--; 9021 9022 while (nargs > 0) { 9023 CAST_TO_STRING; 9024 newobj = valuePop(ctxt); 9025 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) { 9026 xmlXPathReleaseObject(ctxt->context, newobj); 9027 xmlXPathReleaseObject(ctxt->context, cur); 9028 XP_ERROR(XPATH_INVALID_TYPE); 9029 } 9030 tmp = xmlStrcat(newobj->stringval, cur->stringval); 9031 newobj->stringval = cur->stringval; 9032 cur->stringval = tmp; 9033 xmlXPathReleaseObject(ctxt->context, newobj); 9034 nargs--; 9035 } 9036 valuePush(ctxt, cur); 9037 } 9038 9039 /** 9040 * xmlXPathContainsFunction: 9041 * @ctxt: the XPath Parser context 9042 * @nargs: the number of arguments 9043 * 9044 * Implement the contains() XPath function 9045 * boolean contains(string, string) 9046 * The contains function returns true if the first argument string 9047 * contains the second argument string, and otherwise returns false. 9048 */ 9049 void 9050 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9051 xmlXPathObjectPtr hay, needle; 9052 9053 CHECK_ARITY(2); 9054 CAST_TO_STRING; 9055 CHECK_TYPE(XPATH_STRING); 9056 needle = valuePop(ctxt); 9057 CAST_TO_STRING; 9058 hay = valuePop(ctxt); 9059 9060 if ((hay == NULL) || (hay->type != XPATH_STRING)) { 9061 xmlXPathReleaseObject(ctxt->context, hay); 9062 xmlXPathReleaseObject(ctxt->context, needle); 9063 XP_ERROR(XPATH_INVALID_TYPE); 9064 } 9065 if (xmlStrstr(hay->stringval, needle->stringval)) 9066 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); 9067 else 9068 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); 9069 xmlXPathReleaseObject(ctxt->context, hay); 9070 xmlXPathReleaseObject(ctxt->context, needle); 9071 } 9072 9073 /** 9074 * xmlXPathStartsWithFunction: 9075 * @ctxt: the XPath Parser context 9076 * @nargs: the number of arguments 9077 * 9078 * Implement the starts-with() XPath function 9079 * boolean starts-with(string, string) 9080 * The starts-with function returns true if the first argument string 9081 * starts with the second argument string, and otherwise returns false. 9082 */ 9083 void 9084 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9085 xmlXPathObjectPtr hay, needle; 9086 int n; 9087 9088 CHECK_ARITY(2); 9089 CAST_TO_STRING; 9090 CHECK_TYPE(XPATH_STRING); 9091 needle = valuePop(ctxt); 9092 CAST_TO_STRING; 9093 hay = valuePop(ctxt); 9094 9095 if ((hay == NULL) || (hay->type != XPATH_STRING)) { 9096 xmlXPathReleaseObject(ctxt->context, hay); 9097 xmlXPathReleaseObject(ctxt->context, needle); 9098 XP_ERROR(XPATH_INVALID_TYPE); 9099 } 9100 n = xmlStrlen(needle->stringval); 9101 if (xmlStrncmp(hay->stringval, needle->stringval, n)) 9102 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); 9103 else 9104 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); 9105 xmlXPathReleaseObject(ctxt->context, hay); 9106 xmlXPathReleaseObject(ctxt->context, needle); 9107 } 9108 9109 /** 9110 * xmlXPathSubstringFunction: 9111 * @ctxt: the XPath Parser context 9112 * @nargs: the number of arguments 9113 * 9114 * Implement the substring() XPath function 9115 * string substring(string, number, number?) 9116 * The substring function returns the substring of the first argument 9117 * starting at the position specified in the second argument with 9118 * length specified in the third argument. For example, 9119 * substring("12345",2,3) returns "234". If the third argument is not 9120 * specified, it returns the substring starting at the position specified 9121 * in the second argument and continuing to the end of the string. For 9122 * example, substring("12345",2) returns "2345". More precisely, each 9123 * character in the string (see [3.6 Strings]) is considered to have a 9124 * numeric position: the position of the first character is 1, the position 9125 * of the second character is 2 and so on. The returned substring contains 9126 * those characters for which the position of the character is greater than 9127 * or equal to the second argument and, if the third argument is specified, 9128 * less than the sum of the second and third arguments; the comparisons 9129 * and addition used for the above follow the standard IEEE 754 rules. Thus: 9130 * - substring("12345", 1.5, 2.6) returns "234" 9131 * - substring("12345", 0, 3) returns "12" 9132 * - substring("12345", 0 div 0, 3) returns "" 9133 * - substring("12345", 1, 0 div 0) returns "" 9134 * - substring("12345", -42, 1 div 0) returns "12345" 9135 * - substring("12345", -1 div 0, 1 div 0) returns "" 9136 */ 9137 void 9138 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9139 xmlXPathObjectPtr str, start, len; 9140 double le=0, in; 9141 int i, l, m; 9142 xmlChar *ret; 9143 9144 if (nargs < 2) { 9145 CHECK_ARITY(2); 9146 } 9147 if (nargs > 3) { 9148 CHECK_ARITY(3); 9149 } 9150 /* 9151 * take care of possible last (position) argument 9152 */ 9153 if (nargs == 3) { 9154 CAST_TO_NUMBER; 9155 CHECK_TYPE(XPATH_NUMBER); 9156 len = valuePop(ctxt); 9157 le = len->floatval; 9158 xmlXPathReleaseObject(ctxt->context, len); 9159 } 9160 9161 CAST_TO_NUMBER; 9162 CHECK_TYPE(XPATH_NUMBER); 9163 start = valuePop(ctxt); 9164 in = start->floatval; 9165 xmlXPathReleaseObject(ctxt->context, start); 9166 CAST_TO_STRING; 9167 CHECK_TYPE(XPATH_STRING); 9168 str = valuePop(ctxt); 9169 m = xmlUTF8Strlen((const unsigned char *)str->stringval); 9170 9171 /* 9172 * If last pos not present, calculate last position 9173 */ 9174 if (nargs != 3) { 9175 le = (double)m; 9176 if (in < 1.0) 9177 in = 1.0; 9178 } 9179 9180 /* Need to check for the special cases where either 9181 * the index is NaN, the length is NaN, or both 9182 * arguments are infinity (relying on Inf + -Inf = NaN) 9183 */ 9184 if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) { 9185 /* 9186 * To meet the requirements of the spec, the arguments 9187 * must be converted to integer format before 9188 * initial index calculations are done 9189 * 9190 * First we go to integer form, rounding up 9191 * and checking for special cases 9192 */ 9193 i = (int) in; 9194 if (((double)i)+0.5 <= in) i++; 9195 9196 if (xmlXPathIsInf(le) == 1) { 9197 l = m; 9198 if (i < 1) 9199 i = 1; 9200 } 9201 else if (xmlXPathIsInf(le) == -1 || le < 0.0) 9202 l = 0; 9203 else { 9204 l = (int) le; 9205 if (((double)l)+0.5 <= le) l++; 9206 } 9207 9208 /* Now we normalize inidices */ 9209 i -= 1; 9210 l += i; 9211 if (i < 0) 9212 i = 0; 9213 if (l > m) 9214 l = m; 9215 9216 /* number of chars to copy */ 9217 l -= i; 9218 9219 ret = xmlUTF8Strsub(str->stringval, i, l); 9220 } 9221 else { 9222 ret = NULL; 9223 } 9224 if (ret == NULL) 9225 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 9226 else { 9227 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret)); 9228 xmlFree(ret); 9229 } 9230 xmlXPathReleaseObject(ctxt->context, str); 9231 } 9232 9233 /** 9234 * xmlXPathSubstringBeforeFunction: 9235 * @ctxt: the XPath Parser context 9236 * @nargs: the number of arguments 9237 * 9238 * Implement the substring-before() XPath function 9239 * string substring-before(string, string) 9240 * The substring-before function returns the substring of the first 9241 * argument string that precedes the first occurrence of the second 9242 * argument string in the first argument string, or the empty string 9243 * if the first argument string does not contain the second argument 9244 * string. For example, substring-before("1999/04/01","/") returns 1999. 9245 */ 9246 void 9247 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9248 xmlXPathObjectPtr str; 9249 xmlXPathObjectPtr find; 9250 xmlBufPtr target; 9251 const xmlChar *point; 9252 int offset; 9253 9254 CHECK_ARITY(2); 9255 CAST_TO_STRING; 9256 find = valuePop(ctxt); 9257 CAST_TO_STRING; 9258 str = valuePop(ctxt); 9259 9260 target = xmlBufCreate(); 9261 if (target) { 9262 point = xmlStrstr(str->stringval, find->stringval); 9263 if (point) { 9264 offset = (int)(point - str->stringval); 9265 xmlBufAdd(target, str->stringval, offset); 9266 } 9267 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9268 xmlBufContent(target))); 9269 xmlBufFree(target); 9270 } 9271 xmlXPathReleaseObject(ctxt->context, str); 9272 xmlXPathReleaseObject(ctxt->context, find); 9273 } 9274 9275 /** 9276 * xmlXPathSubstringAfterFunction: 9277 * @ctxt: the XPath Parser context 9278 * @nargs: the number of arguments 9279 * 9280 * Implement the substring-after() XPath function 9281 * string substring-after(string, string) 9282 * The substring-after function returns the substring of the first 9283 * argument string that follows the first occurrence of the second 9284 * argument string in the first argument string, or the empty stringi 9285 * if the first argument string does not contain the second argument 9286 * string. For example, substring-after("1999/04/01","/") returns 04/01, 9287 * and substring-after("1999/04/01","19") returns 99/04/01. 9288 */ 9289 void 9290 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9291 xmlXPathObjectPtr str; 9292 xmlXPathObjectPtr find; 9293 xmlBufPtr target; 9294 const xmlChar *point; 9295 int offset; 9296 9297 CHECK_ARITY(2); 9298 CAST_TO_STRING; 9299 find = valuePop(ctxt); 9300 CAST_TO_STRING; 9301 str = valuePop(ctxt); 9302 9303 target = xmlBufCreate(); 9304 if (target) { 9305 point = xmlStrstr(str->stringval, find->stringval); 9306 if (point) { 9307 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval); 9308 xmlBufAdd(target, &str->stringval[offset], 9309 xmlStrlen(str->stringval) - offset); 9310 } 9311 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9312 xmlBufContent(target))); 9313 xmlBufFree(target); 9314 } 9315 xmlXPathReleaseObject(ctxt->context, str); 9316 xmlXPathReleaseObject(ctxt->context, find); 9317 } 9318 9319 /** 9320 * xmlXPathNormalizeFunction: 9321 * @ctxt: the XPath Parser context 9322 * @nargs: the number of arguments 9323 * 9324 * Implement the normalize-space() XPath function 9325 * string normalize-space(string?) 9326 * The normalize-space function returns the argument string with white 9327 * space normalized by stripping leading and trailing whitespace 9328 * and replacing sequences of whitespace characters by a single 9329 * space. Whitespace characters are the same allowed by the S production 9330 * in XML. If the argument is omitted, it defaults to the context 9331 * node converted to a string, in other words the value of the context node. 9332 */ 9333 void 9334 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9335 xmlXPathObjectPtr obj = NULL; 9336 xmlChar *source = NULL; 9337 xmlBufPtr target; 9338 xmlChar blank; 9339 9340 if (ctxt == NULL) return; 9341 if (nargs == 0) { 9342 /* Use current context node */ 9343 valuePush(ctxt, 9344 xmlXPathCacheWrapString(ctxt->context, 9345 xmlXPathCastNodeToString(ctxt->context->node))); 9346 nargs = 1; 9347 } 9348 9349 CHECK_ARITY(1); 9350 CAST_TO_STRING; 9351 CHECK_TYPE(XPATH_STRING); 9352 obj = valuePop(ctxt); 9353 source = obj->stringval; 9354 9355 target = xmlBufCreate(); 9356 if (target && source) { 9357 9358 /* Skip leading whitespaces */ 9359 while (IS_BLANK_CH(*source)) 9360 source++; 9361 9362 /* Collapse intermediate whitespaces, and skip trailing whitespaces */ 9363 blank = 0; 9364 while (*source) { 9365 if (IS_BLANK_CH(*source)) { 9366 blank = 0x20; 9367 } else { 9368 if (blank) { 9369 xmlBufAdd(target, &blank, 1); 9370 blank = 0; 9371 } 9372 xmlBufAdd(target, source, 1); 9373 } 9374 source++; 9375 } 9376 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9377 xmlBufContent(target))); 9378 xmlBufFree(target); 9379 } 9380 xmlXPathReleaseObject(ctxt->context, obj); 9381 } 9382 9383 /** 9384 * xmlXPathTranslateFunction: 9385 * @ctxt: the XPath Parser context 9386 * @nargs: the number of arguments 9387 * 9388 * Implement the translate() XPath function 9389 * string translate(string, string, string) 9390 * The translate function returns the first argument string with 9391 * occurrences of characters in the second argument string replaced 9392 * by the character at the corresponding position in the third argument 9393 * string. For example, translate("bar","abc","ABC") returns the string 9394 * BAr. If there is a character in the second argument string with no 9395 * character at a corresponding position in the third argument string 9396 * (because the second argument string is longer than the third argument 9397 * string), then occurrences of that character in the first argument 9398 * string are removed. For example, translate("--aaa--","abc-","ABC") 9399 * returns "AAA". If a character occurs more than once in second 9400 * argument string, then the first occurrence determines the replacement 9401 * character. If the third argument string is longer than the second 9402 * argument string, then excess characters are ignored. 9403 */ 9404 void 9405 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9406 xmlXPathObjectPtr str; 9407 xmlXPathObjectPtr from; 9408 xmlXPathObjectPtr to; 9409 xmlBufPtr target; 9410 int offset, max; 9411 xmlChar ch; 9412 const xmlChar *point; 9413 xmlChar *cptr; 9414 9415 CHECK_ARITY(3); 9416 9417 CAST_TO_STRING; 9418 to = valuePop(ctxt); 9419 CAST_TO_STRING; 9420 from = valuePop(ctxt); 9421 CAST_TO_STRING; 9422 str = valuePop(ctxt); 9423 9424 target = xmlBufCreate(); 9425 if (target) { 9426 max = xmlUTF8Strlen(to->stringval); 9427 for (cptr = str->stringval; (ch=*cptr); ) { 9428 offset = xmlUTF8Strloc(from->stringval, cptr); 9429 if (offset >= 0) { 9430 if (offset < max) { 9431 point = xmlUTF8Strpos(to->stringval, offset); 9432 if (point) 9433 xmlBufAdd(target, point, xmlUTF8Strsize(point, 1)); 9434 } 9435 } else 9436 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1)); 9437 9438 /* Step to next character in input */ 9439 cptr++; 9440 if ( ch & 0x80 ) { 9441 /* if not simple ascii, verify proper format */ 9442 if ( (ch & 0xc0) != 0xc0 ) { 9443 xmlGenericError(xmlGenericErrorContext, 9444 "xmlXPathTranslateFunction: Invalid UTF8 string\n"); 9445 /* not asserting an XPath error is probably better */ 9446 break; 9447 } 9448 /* then skip over remaining bytes for this char */ 9449 while ( (ch <<= 1) & 0x80 ) 9450 if ( (*cptr++ & 0xc0) != 0x80 ) { 9451 xmlGenericError(xmlGenericErrorContext, 9452 "xmlXPathTranslateFunction: Invalid UTF8 string\n"); 9453 /* not asserting an XPath error is probably better */ 9454 break; 9455 } 9456 if (ch & 0x80) /* must have had error encountered */ 9457 break; 9458 } 9459 } 9460 } 9461 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9462 xmlBufContent(target))); 9463 xmlBufFree(target); 9464 xmlXPathReleaseObject(ctxt->context, str); 9465 xmlXPathReleaseObject(ctxt->context, from); 9466 xmlXPathReleaseObject(ctxt->context, to); 9467 } 9468 9469 /** 9470 * xmlXPathBooleanFunction: 9471 * @ctxt: the XPath Parser context 9472 * @nargs: the number of arguments 9473 * 9474 * Implement the boolean() XPath function 9475 * boolean boolean(object) 9476 * The boolean function converts its argument to a boolean as follows: 9477 * - a number is true if and only if it is neither positive or 9478 * negative zero nor NaN 9479 * - a node-set is true if and only if it is non-empty 9480 * - a string is true if and only if its length is non-zero 9481 */ 9482 void 9483 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9484 xmlXPathObjectPtr cur; 9485 9486 CHECK_ARITY(1); 9487 cur = valuePop(ctxt); 9488 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 9489 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur); 9490 valuePush(ctxt, cur); 9491 } 9492 9493 /** 9494 * xmlXPathNotFunction: 9495 * @ctxt: the XPath Parser context 9496 * @nargs: the number of arguments 9497 * 9498 * Implement the not() XPath function 9499 * boolean not(boolean) 9500 * The not function returns true if its argument is false, 9501 * and false otherwise. 9502 */ 9503 void 9504 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9505 CHECK_ARITY(1); 9506 CAST_TO_BOOLEAN; 9507 CHECK_TYPE(XPATH_BOOLEAN); 9508 ctxt->value->boolval = ! ctxt->value->boolval; 9509 } 9510 9511 /** 9512 * xmlXPathTrueFunction: 9513 * @ctxt: the XPath Parser context 9514 * @nargs: the number of arguments 9515 * 9516 * Implement the true() XPath function 9517 * boolean true() 9518 */ 9519 void 9520 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9521 CHECK_ARITY(0); 9522 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); 9523 } 9524 9525 /** 9526 * xmlXPathFalseFunction: 9527 * @ctxt: the XPath Parser context 9528 * @nargs: the number of arguments 9529 * 9530 * Implement the false() XPath function 9531 * boolean false() 9532 */ 9533 void 9534 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9535 CHECK_ARITY(0); 9536 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); 9537 } 9538 9539 /** 9540 * xmlXPathLangFunction: 9541 * @ctxt: the XPath Parser context 9542 * @nargs: the number of arguments 9543 * 9544 * Implement the lang() XPath function 9545 * boolean lang(string) 9546 * The lang function returns true or false depending on whether the 9547 * language of the context node as specified by xml:lang attributes 9548 * is the same as or is a sublanguage of the language specified by 9549 * the argument string. The language of the context node is determined 9550 * by the value of the xml:lang attribute on the context node, or, if 9551 * the context node has no xml:lang attribute, by the value of the 9552 * xml:lang attribute on the nearest ancestor of the context node that 9553 * has an xml:lang attribute. If there is no such attribute, then lang 9554 * returns false. If there is such an attribute, then lang returns 9555 * true if the attribute value is equal to the argument ignoring case, 9556 * or if there is some suffix starting with - such that the attribute 9557 * value is equal to the argument ignoring that suffix of the attribute 9558 * value and ignoring case. 9559 */ 9560 void 9561 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9562 xmlXPathObjectPtr val = NULL; 9563 const xmlChar *theLang = NULL; 9564 const xmlChar *lang; 9565 int ret = 0; 9566 int i; 9567 9568 CHECK_ARITY(1); 9569 CAST_TO_STRING; 9570 CHECK_TYPE(XPATH_STRING); 9571 val = valuePop(ctxt); 9572 lang = val->stringval; 9573 theLang = xmlNodeGetLang(ctxt->context->node); 9574 if ((theLang != NULL) && (lang != NULL)) { 9575 for (i = 0;lang[i] != 0;i++) 9576 if (toupper(lang[i]) != toupper(theLang[i])) 9577 goto not_equal; 9578 if ((theLang[i] == 0) || (theLang[i] == '-')) 9579 ret = 1; 9580 } 9581 not_equal: 9582 if (theLang != NULL) 9583 xmlFree((void *)theLang); 9584 9585 xmlXPathReleaseObject(ctxt->context, val); 9586 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret)); 9587 } 9588 9589 /** 9590 * xmlXPathNumberFunction: 9591 * @ctxt: the XPath Parser context 9592 * @nargs: the number of arguments 9593 * 9594 * Implement the number() XPath function 9595 * number number(object?) 9596 */ 9597 void 9598 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9599 xmlXPathObjectPtr cur; 9600 double res; 9601 9602 if (ctxt == NULL) return; 9603 if (nargs == 0) { 9604 if (ctxt->context->node == NULL) { 9605 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0)); 9606 } else { 9607 xmlChar* content = xmlNodeGetContent(ctxt->context->node); 9608 9609 res = xmlXPathStringEvalNumber(content); 9610 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res)); 9611 xmlFree(content); 9612 } 9613 return; 9614 } 9615 9616 CHECK_ARITY(1); 9617 cur = valuePop(ctxt); 9618 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur)); 9619 } 9620 9621 /** 9622 * xmlXPathSumFunction: 9623 * @ctxt: the XPath Parser context 9624 * @nargs: the number of arguments 9625 * 9626 * Implement the sum() XPath function 9627 * number sum(node-set) 9628 * The sum function returns the sum of the values of the nodes in 9629 * the argument node-set. 9630 */ 9631 void 9632 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9633 xmlXPathObjectPtr cur; 9634 int i; 9635 double res = 0.0; 9636 9637 CHECK_ARITY(1); 9638 if ((ctxt->value == NULL) || 9639 ((ctxt->value->type != XPATH_NODESET) && 9640 (ctxt->value->type != XPATH_XSLT_TREE))) 9641 XP_ERROR(XPATH_INVALID_TYPE); 9642 cur = valuePop(ctxt); 9643 9644 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) { 9645 for (i = 0; i < cur->nodesetval->nodeNr; i++) { 9646 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]); 9647 } 9648 } 9649 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res)); 9650 xmlXPathReleaseObject(ctxt->context, cur); 9651 } 9652 9653 /** 9654 * xmlXPathFloorFunction: 9655 * @ctxt: the XPath Parser context 9656 * @nargs: the number of arguments 9657 * 9658 * Implement the floor() XPath function 9659 * number floor(number) 9660 * The floor function returns the largest (closest to positive infinity) 9661 * number that is not greater than the argument and that is an integer. 9662 */ 9663 void 9664 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9665 CHECK_ARITY(1); 9666 CAST_TO_NUMBER; 9667 CHECK_TYPE(XPATH_NUMBER); 9668 9669 ctxt->value->floatval = floor(ctxt->value->floatval); 9670 } 9671 9672 /** 9673 * xmlXPathCeilingFunction: 9674 * @ctxt: the XPath Parser context 9675 * @nargs: the number of arguments 9676 * 9677 * Implement the ceiling() XPath function 9678 * number ceiling(number) 9679 * The ceiling function returns the smallest (closest to negative infinity) 9680 * number that is not less than the argument and that is an integer. 9681 */ 9682 void 9683 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9684 CHECK_ARITY(1); 9685 CAST_TO_NUMBER; 9686 CHECK_TYPE(XPATH_NUMBER); 9687 9688 ctxt->value->floatval = ceil(ctxt->value->floatval); 9689 } 9690 9691 /** 9692 * xmlXPathRoundFunction: 9693 * @ctxt: the XPath Parser context 9694 * @nargs: the number of arguments 9695 * 9696 * Implement the round() XPath function 9697 * number round(number) 9698 * The round function returns the number that is closest to the 9699 * argument and that is an integer. If there are two such numbers, 9700 * then the one that is closest to positive infinity is returned. 9701 */ 9702 void 9703 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9704 double f; 9705 9706 CHECK_ARITY(1); 9707 CAST_TO_NUMBER; 9708 CHECK_TYPE(XPATH_NUMBER); 9709 9710 f = ctxt->value->floatval; 9711 9712 if ((f >= -0.5) && (f < 0.5)) { 9713 /* Handles negative zero. */ 9714 ctxt->value->floatval *= 0.0; 9715 } 9716 else { 9717 double rounded = floor(f); 9718 if (f - rounded >= 0.5) 9719 rounded += 1.0; 9720 ctxt->value->floatval = rounded; 9721 } 9722 } 9723 9724 /************************************************************************ 9725 * * 9726 * The Parser * 9727 * * 9728 ************************************************************************/ 9729 9730 /* 9731 * a few forward declarations since we use a recursive call based 9732 * implementation. 9733 */ 9734 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort); 9735 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter); 9736 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt); 9737 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt); 9738 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, 9739 int qualified); 9740 9741 /** 9742 * xmlXPathCurrentChar: 9743 * @ctxt: the XPath parser context 9744 * @cur: pointer to the beginning of the char 9745 * @len: pointer to the length of the char read 9746 * 9747 * The current char value, if using UTF-8 this may actually span multiple 9748 * bytes in the input buffer. 9749 * 9750 * Returns the current char value and its length 9751 */ 9752 9753 static int 9754 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) { 9755 unsigned char c; 9756 unsigned int val; 9757 const xmlChar *cur; 9758 9759 if (ctxt == NULL) 9760 return(0); 9761 cur = ctxt->cur; 9762 9763 /* 9764 * We are supposed to handle UTF8, check it's valid 9765 * From rfc2044: encoding of the Unicode values on UTF-8: 9766 * 9767 * UCS-4 range (hex.) UTF-8 octet sequence (binary) 9768 * 0000 0000-0000 007F 0xxxxxxx 9769 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx 9770 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx 9771 * 9772 * Check for the 0x110000 limit too 9773 */ 9774 c = *cur; 9775 if (c & 0x80) { 9776 if ((cur[1] & 0xc0) != 0x80) 9777 goto encoding_error; 9778 if ((c & 0xe0) == 0xe0) { 9779 9780 if ((cur[2] & 0xc0) != 0x80) 9781 goto encoding_error; 9782 if ((c & 0xf0) == 0xf0) { 9783 if (((c & 0xf8) != 0xf0) || 9784 ((cur[3] & 0xc0) != 0x80)) 9785 goto encoding_error; 9786 /* 4-byte code */ 9787 *len = 4; 9788 val = (cur[0] & 0x7) << 18; 9789 val |= (cur[1] & 0x3f) << 12; 9790 val |= (cur[2] & 0x3f) << 6; 9791 val |= cur[3] & 0x3f; 9792 } else { 9793 /* 3-byte code */ 9794 *len = 3; 9795 val = (cur[0] & 0xf) << 12; 9796 val |= (cur[1] & 0x3f) << 6; 9797 val |= cur[2] & 0x3f; 9798 } 9799 } else { 9800 /* 2-byte code */ 9801 *len = 2; 9802 val = (cur[0] & 0x1f) << 6; 9803 val |= cur[1] & 0x3f; 9804 } 9805 if (!IS_CHAR(val)) { 9806 XP_ERROR0(XPATH_INVALID_CHAR_ERROR); 9807 } 9808 return(val); 9809 } else { 9810 /* 1-byte code */ 9811 *len = 1; 9812 return((int) *cur); 9813 } 9814 encoding_error: 9815 /* 9816 * If we detect an UTF8 error that probably means that the 9817 * input encoding didn't get properly advertised in the 9818 * declaration header. Report the error and switch the encoding 9819 * to ISO-Latin-1 (if you don't like this policy, just declare the 9820 * encoding !) 9821 */ 9822 *len = 0; 9823 XP_ERROR0(XPATH_ENCODING_ERROR); 9824 } 9825 9826 /** 9827 * xmlXPathParseNCName: 9828 * @ctxt: the XPath Parser context 9829 * 9830 * parse an XML namespace non qualified name. 9831 * 9832 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)* 9833 * 9834 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' | 9835 * CombiningChar | Extender 9836 * 9837 * Returns the namespace name or NULL 9838 */ 9839 9840 xmlChar * 9841 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) { 9842 const xmlChar *in; 9843 xmlChar *ret; 9844 int count = 0; 9845 9846 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL); 9847 /* 9848 * Accelerator for simple ASCII names 9849 */ 9850 in = ctxt->cur; 9851 if (((*in >= 0x61) && (*in <= 0x7A)) || 9852 ((*in >= 0x41) && (*in <= 0x5A)) || 9853 (*in == '_')) { 9854 in++; 9855 while (((*in >= 0x61) && (*in <= 0x7A)) || 9856 ((*in >= 0x41) && (*in <= 0x5A)) || 9857 ((*in >= 0x30) && (*in <= 0x39)) || 9858 (*in == '_') || (*in == '.') || 9859 (*in == '-')) 9860 in++; 9861 if ((*in == ' ') || (*in == '>') || (*in == '/') || 9862 (*in == '[') || (*in == ']') || (*in == ':') || 9863 (*in == '@') || (*in == '*')) { 9864 count = in - ctxt->cur; 9865 if (count == 0) 9866 return(NULL); 9867 ret = xmlStrndup(ctxt->cur, count); 9868 ctxt->cur = in; 9869 return(ret); 9870 } 9871 } 9872 return(xmlXPathParseNameComplex(ctxt, 0)); 9873 } 9874 9875 9876 /** 9877 * xmlXPathParseQName: 9878 * @ctxt: the XPath Parser context 9879 * @prefix: a xmlChar ** 9880 * 9881 * parse an XML qualified name 9882 * 9883 * [NS 5] QName ::= (Prefix ':')? LocalPart 9884 * 9885 * [NS 6] Prefix ::= NCName 9886 * 9887 * [NS 7] LocalPart ::= NCName 9888 * 9889 * Returns the function returns the local part, and prefix is updated 9890 * to get the Prefix if any. 9891 */ 9892 9893 static xmlChar * 9894 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) { 9895 xmlChar *ret = NULL; 9896 9897 *prefix = NULL; 9898 ret = xmlXPathParseNCName(ctxt); 9899 if (ret && CUR == ':') { 9900 *prefix = ret; 9901 NEXT; 9902 ret = xmlXPathParseNCName(ctxt); 9903 } 9904 return(ret); 9905 } 9906 9907 /** 9908 * xmlXPathParseName: 9909 * @ctxt: the XPath Parser context 9910 * 9911 * parse an XML name 9912 * 9913 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | 9914 * CombiningChar | Extender 9915 * 9916 * [5] Name ::= (Letter | '_' | ':') (NameChar)* 9917 * 9918 * Returns the namespace name or NULL 9919 */ 9920 9921 xmlChar * 9922 xmlXPathParseName(xmlXPathParserContextPtr ctxt) { 9923 const xmlChar *in; 9924 xmlChar *ret; 9925 size_t count = 0; 9926 9927 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL); 9928 /* 9929 * Accelerator for simple ASCII names 9930 */ 9931 in = ctxt->cur; 9932 if (((*in >= 0x61) && (*in <= 0x7A)) || 9933 ((*in >= 0x41) && (*in <= 0x5A)) || 9934 (*in == '_') || (*in == ':')) { 9935 in++; 9936 while (((*in >= 0x61) && (*in <= 0x7A)) || 9937 ((*in >= 0x41) && (*in <= 0x5A)) || 9938 ((*in >= 0x30) && (*in <= 0x39)) || 9939 (*in == '_') || (*in == '-') || 9940 (*in == ':') || (*in == '.')) 9941 in++; 9942 if ((*in > 0) && (*in < 0x80)) { 9943 count = in - ctxt->cur; 9944 if (count > XML_MAX_NAME_LENGTH) { 9945 ctxt->cur = in; 9946 XP_ERRORNULL(XPATH_EXPR_ERROR); 9947 } 9948 ret = xmlStrndup(ctxt->cur, count); 9949 ctxt->cur = in; 9950 return(ret); 9951 } 9952 } 9953 return(xmlXPathParseNameComplex(ctxt, 1)); 9954 } 9955 9956 static xmlChar * 9957 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) { 9958 xmlChar buf[XML_MAX_NAMELEN + 5]; 9959 int len = 0, l; 9960 int c; 9961 9962 /* 9963 * Handler for more complex cases 9964 */ 9965 c = CUR_CHAR(l); 9966 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */ 9967 (c == '[') || (c == ']') || (c == '@') || /* accelerators */ 9968 (c == '*') || /* accelerators */ 9969 (!IS_LETTER(c) && (c != '_') && 9970 ((!qualified) || (c != ':')))) { 9971 return(NULL); 9972 } 9973 9974 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */ 9975 ((IS_LETTER(c)) || (IS_DIGIT(c)) || 9976 (c == '.') || (c == '-') || 9977 (c == '_') || ((qualified) && (c == ':')) || 9978 (IS_COMBINING(c)) || 9979 (IS_EXTENDER(c)))) { 9980 COPY_BUF(l,buf,len,c); 9981 NEXTL(l); 9982 c = CUR_CHAR(l); 9983 if (len >= XML_MAX_NAMELEN) { 9984 /* 9985 * Okay someone managed to make a huge name, so he's ready to pay 9986 * for the processing speed. 9987 */ 9988 xmlChar *buffer; 9989 int max = len * 2; 9990 9991 if (len > XML_MAX_NAME_LENGTH) { 9992 XP_ERRORNULL(XPATH_EXPR_ERROR); 9993 } 9994 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar)); 9995 if (buffer == NULL) { 9996 XP_ERRORNULL(XPATH_MEMORY_ERROR); 9997 } 9998 memcpy(buffer, buf, len); 9999 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */ 10000 (c == '.') || (c == '-') || 10001 (c == '_') || ((qualified) && (c == ':')) || 10002 (IS_COMBINING(c)) || 10003 (IS_EXTENDER(c))) { 10004 if (len + 10 > max) { 10005 if (max > XML_MAX_NAME_LENGTH) { 10006 XP_ERRORNULL(XPATH_EXPR_ERROR); 10007 } 10008 max *= 2; 10009 buffer = (xmlChar *) xmlRealloc(buffer, 10010 max * sizeof(xmlChar)); 10011 if (buffer == NULL) { 10012 XP_ERRORNULL(XPATH_MEMORY_ERROR); 10013 } 10014 } 10015 COPY_BUF(l,buffer,len,c); 10016 NEXTL(l); 10017 c = CUR_CHAR(l); 10018 } 10019 buffer[len] = 0; 10020 return(buffer); 10021 } 10022 } 10023 if (len == 0) 10024 return(NULL); 10025 return(xmlStrndup(buf, len)); 10026 } 10027 10028 #define MAX_FRAC 20 10029 10030 /** 10031 * xmlXPathStringEvalNumber: 10032 * @str: A string to scan 10033 * 10034 * [30a] Float ::= Number ('e' Digits?)? 10035 * 10036 * [30] Number ::= Digits ('.' Digits?)? 10037 * | '.' Digits 10038 * [31] Digits ::= [0-9]+ 10039 * 10040 * Compile a Number in the string 10041 * In complement of the Number expression, this function also handles 10042 * negative values : '-' Number. 10043 * 10044 * Returns the double value. 10045 */ 10046 double 10047 xmlXPathStringEvalNumber(const xmlChar *str) { 10048 const xmlChar *cur = str; 10049 double ret; 10050 int ok = 0; 10051 int isneg = 0; 10052 int exponent = 0; 10053 int is_exponent_negative = 0; 10054 #ifdef __GNUC__ 10055 unsigned long tmp = 0; 10056 double temp; 10057 #endif 10058 if (cur == NULL) return(0); 10059 while (IS_BLANK_CH(*cur)) cur++; 10060 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) { 10061 return(NAN); 10062 } 10063 if (*cur == '-') { 10064 isneg = 1; 10065 cur++; 10066 } 10067 10068 #ifdef __GNUC__ 10069 /* 10070 * tmp/temp is a workaround against a gcc compiler bug 10071 * http://veillard.com/gcc.bug 10072 */ 10073 ret = 0; 10074 while ((*cur >= '0') && (*cur <= '9')) { 10075 ret = ret * 10; 10076 tmp = (*cur - '0'); 10077 ok = 1; 10078 cur++; 10079 temp = (double) tmp; 10080 ret = ret + temp; 10081 } 10082 #else 10083 ret = 0; 10084 while ((*cur >= '0') && (*cur <= '9')) { 10085 ret = ret * 10 + (*cur - '0'); 10086 ok = 1; 10087 cur++; 10088 } 10089 #endif 10090 10091 if (*cur == '.') { 10092 int v, frac = 0, max; 10093 double fraction = 0; 10094 10095 cur++; 10096 if (((*cur < '0') || (*cur > '9')) && (!ok)) { 10097 return(NAN); 10098 } 10099 while (*cur == '0') { 10100 frac = frac + 1; 10101 cur++; 10102 } 10103 max = frac + MAX_FRAC; 10104 while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) { 10105 v = (*cur - '0'); 10106 fraction = fraction * 10 + v; 10107 frac = frac + 1; 10108 cur++; 10109 } 10110 fraction /= pow(10.0, frac); 10111 ret = ret + fraction; 10112 while ((*cur >= '0') && (*cur <= '9')) 10113 cur++; 10114 } 10115 if ((*cur == 'e') || (*cur == 'E')) { 10116 cur++; 10117 if (*cur == '-') { 10118 is_exponent_negative = 1; 10119 cur++; 10120 } else if (*cur == '+') { 10121 cur++; 10122 } 10123 while ((*cur >= '0') && (*cur <= '9')) { 10124 if (exponent < 1000000) 10125 exponent = exponent * 10 + (*cur - '0'); 10126 cur++; 10127 } 10128 } 10129 while (IS_BLANK_CH(*cur)) cur++; 10130 if (*cur != 0) return(NAN); 10131 if (isneg) ret = -ret; 10132 if (is_exponent_negative) exponent = -exponent; 10133 ret *= pow(10.0, (double)exponent); 10134 return(ret); 10135 } 10136 10137 /** 10138 * xmlXPathCompNumber: 10139 * @ctxt: the XPath Parser context 10140 * 10141 * [30] Number ::= Digits ('.' Digits?)? 10142 * | '.' Digits 10143 * [31] Digits ::= [0-9]+ 10144 * 10145 * Compile a Number, then push it on the stack 10146 * 10147 */ 10148 static void 10149 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt) 10150 { 10151 double ret = 0.0; 10152 int ok = 0; 10153 int exponent = 0; 10154 int is_exponent_negative = 0; 10155 #ifdef __GNUC__ 10156 unsigned long tmp = 0; 10157 double temp; 10158 #endif 10159 10160 CHECK_ERROR; 10161 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) { 10162 XP_ERROR(XPATH_NUMBER_ERROR); 10163 } 10164 #ifdef __GNUC__ 10165 /* 10166 * tmp/temp is a workaround against a gcc compiler bug 10167 * http://veillard.com/gcc.bug 10168 */ 10169 ret = 0; 10170 while ((CUR >= '0') && (CUR <= '9')) { 10171 ret = ret * 10; 10172 tmp = (CUR - '0'); 10173 ok = 1; 10174 NEXT; 10175 temp = (double) tmp; 10176 ret = ret + temp; 10177 } 10178 #else 10179 ret = 0; 10180 while ((CUR >= '0') && (CUR <= '9')) { 10181 ret = ret * 10 + (CUR - '0'); 10182 ok = 1; 10183 NEXT; 10184 } 10185 #endif 10186 if (CUR == '.') { 10187 int v, frac = 0, max; 10188 double fraction = 0; 10189 10190 NEXT; 10191 if (((CUR < '0') || (CUR > '9')) && (!ok)) { 10192 XP_ERROR(XPATH_NUMBER_ERROR); 10193 } 10194 while (CUR == '0') { 10195 frac = frac + 1; 10196 NEXT; 10197 } 10198 max = frac + MAX_FRAC; 10199 while ((CUR >= '0') && (CUR <= '9') && (frac < max)) { 10200 v = (CUR - '0'); 10201 fraction = fraction * 10 + v; 10202 frac = frac + 1; 10203 NEXT; 10204 } 10205 fraction /= pow(10.0, frac); 10206 ret = ret + fraction; 10207 while ((CUR >= '0') && (CUR <= '9')) 10208 NEXT; 10209 } 10210 if ((CUR == 'e') || (CUR == 'E')) { 10211 NEXT; 10212 if (CUR == '-') { 10213 is_exponent_negative = 1; 10214 NEXT; 10215 } else if (CUR == '+') { 10216 NEXT; 10217 } 10218 while ((CUR >= '0') && (CUR <= '9')) { 10219 if (exponent < 1000000) 10220 exponent = exponent * 10 + (CUR - '0'); 10221 NEXT; 10222 } 10223 if (is_exponent_negative) 10224 exponent = -exponent; 10225 ret *= pow(10.0, (double) exponent); 10226 } 10227 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, 10228 xmlXPathCacheNewFloat(ctxt->context, ret), NULL); 10229 } 10230 10231 /** 10232 * xmlXPathParseLiteral: 10233 * @ctxt: the XPath Parser context 10234 * 10235 * Parse a Literal 10236 * 10237 * [29] Literal ::= '"' [^"]* '"' 10238 * | "'" [^']* "'" 10239 * 10240 * Returns the value found or NULL in case of error 10241 */ 10242 static xmlChar * 10243 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) { 10244 const xmlChar *q; 10245 xmlChar *ret = NULL; 10246 10247 if (CUR == '"') { 10248 NEXT; 10249 q = CUR_PTR; 10250 while ((IS_CHAR_CH(CUR)) && (CUR != '"')) 10251 NEXT; 10252 if (!IS_CHAR_CH(CUR)) { 10253 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR); 10254 } else { 10255 ret = xmlStrndup(q, CUR_PTR - q); 10256 NEXT; 10257 } 10258 } else if (CUR == '\'') { 10259 NEXT; 10260 q = CUR_PTR; 10261 while ((IS_CHAR_CH(CUR)) && (CUR != '\'')) 10262 NEXT; 10263 if (!IS_CHAR_CH(CUR)) { 10264 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR); 10265 } else { 10266 ret = xmlStrndup(q, CUR_PTR - q); 10267 NEXT; 10268 } 10269 } else { 10270 XP_ERRORNULL(XPATH_START_LITERAL_ERROR); 10271 } 10272 return(ret); 10273 } 10274 10275 /** 10276 * xmlXPathCompLiteral: 10277 * @ctxt: the XPath Parser context 10278 * 10279 * Parse a Literal and push it on the stack. 10280 * 10281 * [29] Literal ::= '"' [^"]* '"' 10282 * | "'" [^']* "'" 10283 * 10284 * TODO: xmlXPathCompLiteral memory allocation could be improved. 10285 */ 10286 static void 10287 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) { 10288 const xmlChar *q; 10289 xmlChar *ret = NULL; 10290 10291 if (CUR == '"') { 10292 NEXT; 10293 q = CUR_PTR; 10294 while ((IS_CHAR_CH(CUR)) && (CUR != '"')) 10295 NEXT; 10296 if (!IS_CHAR_CH(CUR)) { 10297 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR); 10298 } else { 10299 ret = xmlStrndup(q, CUR_PTR - q); 10300 NEXT; 10301 } 10302 } else if (CUR == '\'') { 10303 NEXT; 10304 q = CUR_PTR; 10305 while ((IS_CHAR_CH(CUR)) && (CUR != '\'')) 10306 NEXT; 10307 if (!IS_CHAR_CH(CUR)) { 10308 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR); 10309 } else { 10310 ret = xmlStrndup(q, CUR_PTR - q); 10311 NEXT; 10312 } 10313 } else { 10314 XP_ERROR(XPATH_START_LITERAL_ERROR); 10315 } 10316 if (ret == NULL) return; 10317 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, 10318 xmlXPathCacheNewString(ctxt->context, ret), NULL); 10319 xmlFree(ret); 10320 } 10321 10322 /** 10323 * xmlXPathCompVariableReference: 10324 * @ctxt: the XPath Parser context 10325 * 10326 * Parse a VariableReference, evaluate it and push it on the stack. 10327 * 10328 * The variable bindings consist of a mapping from variable names 10329 * to variable values. The value of a variable is an object, which can be 10330 * of any of the types that are possible for the value of an expression, 10331 * and may also be of additional types not specified here. 10332 * 10333 * Early evaluation is possible since: 10334 * The variable bindings [...] used to evaluate a subexpression are 10335 * always the same as those used to evaluate the containing expression. 10336 * 10337 * [36] VariableReference ::= '$' QName 10338 */ 10339 static void 10340 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) { 10341 xmlChar *name; 10342 xmlChar *prefix; 10343 10344 SKIP_BLANKS; 10345 if (CUR != '$') { 10346 XP_ERROR(XPATH_VARIABLE_REF_ERROR); 10347 } 10348 NEXT; 10349 name = xmlXPathParseQName(ctxt, &prefix); 10350 if (name == NULL) { 10351 xmlFree(prefix); 10352 XP_ERROR(XPATH_VARIABLE_REF_ERROR); 10353 } 10354 ctxt->comp->last = -1; 10355 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, 10356 name, prefix); 10357 SKIP_BLANKS; 10358 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) { 10359 XP_ERROR(XPATH_FORBID_VARIABLE_ERROR); 10360 } 10361 } 10362 10363 /** 10364 * xmlXPathIsNodeType: 10365 * @name: a name string 10366 * 10367 * Is the name given a NodeType one. 10368 * 10369 * [38] NodeType ::= 'comment' 10370 * | 'text' 10371 * | 'processing-instruction' 10372 * | 'node' 10373 * 10374 * Returns 1 if true 0 otherwise 10375 */ 10376 int 10377 xmlXPathIsNodeType(const xmlChar *name) { 10378 if (name == NULL) 10379 return(0); 10380 10381 if (xmlStrEqual(name, BAD_CAST "node")) 10382 return(1); 10383 if (xmlStrEqual(name, BAD_CAST "text")) 10384 return(1); 10385 if (xmlStrEqual(name, BAD_CAST "comment")) 10386 return(1); 10387 if (xmlStrEqual(name, BAD_CAST "processing-instruction")) 10388 return(1); 10389 return(0); 10390 } 10391 10392 /** 10393 * xmlXPathCompFunctionCall: 10394 * @ctxt: the XPath Parser context 10395 * 10396 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')' 10397 * [17] Argument ::= Expr 10398 * 10399 * Compile a function call, the evaluation of all arguments are 10400 * pushed on the stack 10401 */ 10402 static void 10403 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) { 10404 xmlChar *name; 10405 xmlChar *prefix; 10406 int nbargs = 0; 10407 int sort = 1; 10408 10409 name = xmlXPathParseQName(ctxt, &prefix); 10410 if (name == NULL) { 10411 xmlFree(prefix); 10412 XP_ERROR(XPATH_EXPR_ERROR); 10413 } 10414 SKIP_BLANKS; 10415 #ifdef DEBUG_EXPR 10416 if (prefix == NULL) 10417 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n", 10418 name); 10419 else 10420 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n", 10421 prefix, name); 10422 #endif 10423 10424 if (CUR != '(') { 10425 xmlFree(name); 10426 xmlFree(prefix); 10427 XP_ERROR(XPATH_EXPR_ERROR); 10428 } 10429 NEXT; 10430 SKIP_BLANKS; 10431 10432 /* 10433 * Optimization for count(): we don't need the node-set to be sorted. 10434 */ 10435 if ((prefix == NULL) && (name[0] == 'c') && 10436 xmlStrEqual(name, BAD_CAST "count")) 10437 { 10438 sort = 0; 10439 } 10440 ctxt->comp->last = -1; 10441 if (CUR != ')') { 10442 while (CUR != 0) { 10443 int op1 = ctxt->comp->last; 10444 ctxt->comp->last = -1; 10445 xmlXPathCompileExpr(ctxt, sort); 10446 if (ctxt->error != XPATH_EXPRESSION_OK) { 10447 xmlFree(name); 10448 xmlFree(prefix); 10449 return; 10450 } 10451 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0); 10452 nbargs++; 10453 if (CUR == ')') break; 10454 if (CUR != ',') { 10455 xmlFree(name); 10456 xmlFree(prefix); 10457 XP_ERROR(XPATH_EXPR_ERROR); 10458 } 10459 NEXT; 10460 SKIP_BLANKS; 10461 } 10462 } 10463 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, 10464 name, prefix); 10465 NEXT; 10466 SKIP_BLANKS; 10467 } 10468 10469 /** 10470 * xmlXPathCompPrimaryExpr: 10471 * @ctxt: the XPath Parser context 10472 * 10473 * [15] PrimaryExpr ::= VariableReference 10474 * | '(' Expr ')' 10475 * | Literal 10476 * | Number 10477 * | FunctionCall 10478 * 10479 * Compile a primary expression. 10480 */ 10481 static void 10482 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) { 10483 SKIP_BLANKS; 10484 if (CUR == '$') xmlXPathCompVariableReference(ctxt); 10485 else if (CUR == '(') { 10486 NEXT; 10487 SKIP_BLANKS; 10488 xmlXPathCompileExpr(ctxt, 1); 10489 CHECK_ERROR; 10490 if (CUR != ')') { 10491 XP_ERROR(XPATH_EXPR_ERROR); 10492 } 10493 NEXT; 10494 SKIP_BLANKS; 10495 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) { 10496 xmlXPathCompNumber(ctxt); 10497 } else if ((CUR == '\'') || (CUR == '"')) { 10498 xmlXPathCompLiteral(ctxt); 10499 } else { 10500 xmlXPathCompFunctionCall(ctxt); 10501 } 10502 SKIP_BLANKS; 10503 } 10504 10505 /** 10506 * xmlXPathCompFilterExpr: 10507 * @ctxt: the XPath Parser context 10508 * 10509 * [20] FilterExpr ::= PrimaryExpr 10510 * | FilterExpr Predicate 10511 * 10512 * Compile a filter expression. 10513 * Square brackets are used to filter expressions in the same way that 10514 * they are used in location paths. It is an error if the expression to 10515 * be filtered does not evaluate to a node-set. The context node list 10516 * used for evaluating the expression in square brackets is the node-set 10517 * to be filtered listed in document order. 10518 */ 10519 10520 static void 10521 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) { 10522 xmlXPathCompPrimaryExpr(ctxt); 10523 CHECK_ERROR; 10524 SKIP_BLANKS; 10525 10526 while (CUR == '[') { 10527 xmlXPathCompPredicate(ctxt, 1); 10528 SKIP_BLANKS; 10529 } 10530 10531 10532 } 10533 10534 /** 10535 * xmlXPathScanName: 10536 * @ctxt: the XPath Parser context 10537 * 10538 * Trickery: parse an XML name but without consuming the input flow 10539 * Needed to avoid insanity in the parser state. 10540 * 10541 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | 10542 * CombiningChar | Extender 10543 * 10544 * [5] Name ::= (Letter | '_' | ':') (NameChar)* 10545 * 10546 * [6] Names ::= Name (S Name)* 10547 * 10548 * Returns the Name parsed or NULL 10549 */ 10550 10551 static xmlChar * 10552 xmlXPathScanName(xmlXPathParserContextPtr ctxt) { 10553 int len = 0, l; 10554 int c; 10555 const xmlChar *cur; 10556 xmlChar *ret; 10557 10558 cur = ctxt->cur; 10559 10560 c = CUR_CHAR(l); 10561 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */ 10562 (!IS_LETTER(c) && (c != '_') && 10563 (c != ':'))) { 10564 return(NULL); 10565 } 10566 10567 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */ 10568 ((IS_LETTER(c)) || (IS_DIGIT(c)) || 10569 (c == '.') || (c == '-') || 10570 (c == '_') || (c == ':') || 10571 (IS_COMBINING(c)) || 10572 (IS_EXTENDER(c)))) { 10573 len += l; 10574 NEXTL(l); 10575 c = CUR_CHAR(l); 10576 } 10577 ret = xmlStrndup(cur, ctxt->cur - cur); 10578 ctxt->cur = cur; 10579 return(ret); 10580 } 10581 10582 /** 10583 * xmlXPathCompPathExpr: 10584 * @ctxt: the XPath Parser context 10585 * 10586 * [19] PathExpr ::= LocationPath 10587 * | FilterExpr 10588 * | FilterExpr '/' RelativeLocationPath 10589 * | FilterExpr '//' RelativeLocationPath 10590 * 10591 * Compile a path expression. 10592 * The / operator and // operators combine an arbitrary expression 10593 * and a relative location path. It is an error if the expression 10594 * does not evaluate to a node-set. 10595 * The / operator does composition in the same way as when / is 10596 * used in a location path. As in location paths, // is short for 10597 * /descendant-or-self::node()/. 10598 */ 10599 10600 static void 10601 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) { 10602 int lc = 1; /* Should we branch to LocationPath ? */ 10603 xmlChar *name = NULL; /* we may have to preparse a name to find out */ 10604 10605 SKIP_BLANKS; 10606 if ((CUR == '$') || (CUR == '(') || 10607 (IS_ASCII_DIGIT(CUR)) || 10608 (CUR == '\'') || (CUR == '"') || 10609 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) { 10610 lc = 0; 10611 } else if (CUR == '*') { 10612 /* relative or absolute location path */ 10613 lc = 1; 10614 } else if (CUR == '/') { 10615 /* relative or absolute location path */ 10616 lc = 1; 10617 } else if (CUR == '@') { 10618 /* relative abbreviated attribute location path */ 10619 lc = 1; 10620 } else if (CUR == '.') { 10621 /* relative abbreviated attribute location path */ 10622 lc = 1; 10623 } else { 10624 /* 10625 * Problem is finding if we have a name here whether it's: 10626 * - a nodetype 10627 * - a function call in which case it's followed by '(' 10628 * - an axis in which case it's followed by ':' 10629 * - a element name 10630 * We do an a priori analysis here rather than having to 10631 * maintain parsed token content through the recursive function 10632 * calls. This looks uglier but makes the code easier to 10633 * read/write/debug. 10634 */ 10635 SKIP_BLANKS; 10636 name = xmlXPathScanName(ctxt); 10637 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) { 10638 #ifdef DEBUG_STEP 10639 xmlGenericError(xmlGenericErrorContext, 10640 "PathExpr: Axis\n"); 10641 #endif 10642 lc = 1; 10643 xmlFree(name); 10644 } else if (name != NULL) { 10645 int len =xmlStrlen(name); 10646 10647 10648 while (NXT(len) != 0) { 10649 if (NXT(len) == '/') { 10650 /* element name */ 10651 #ifdef DEBUG_STEP 10652 xmlGenericError(xmlGenericErrorContext, 10653 "PathExpr: AbbrRelLocation\n"); 10654 #endif 10655 lc = 1; 10656 break; 10657 } else if (IS_BLANK_CH(NXT(len))) { 10658 /* ignore blanks */ 10659 ; 10660 } else if (NXT(len) == ':') { 10661 #ifdef DEBUG_STEP 10662 xmlGenericError(xmlGenericErrorContext, 10663 "PathExpr: AbbrRelLocation\n"); 10664 #endif 10665 lc = 1; 10666 break; 10667 } else if ((NXT(len) == '(')) { 10668 /* Node Type or Function */ 10669 if (xmlXPathIsNodeType(name)) { 10670 #ifdef DEBUG_STEP 10671 xmlGenericError(xmlGenericErrorContext, 10672 "PathExpr: Type search\n"); 10673 #endif 10674 lc = 1; 10675 #ifdef LIBXML_XPTR_ENABLED 10676 } else if (ctxt->xptr && 10677 xmlStrEqual(name, BAD_CAST "range-to")) { 10678 lc = 1; 10679 #endif 10680 } else { 10681 #ifdef DEBUG_STEP 10682 xmlGenericError(xmlGenericErrorContext, 10683 "PathExpr: function call\n"); 10684 #endif 10685 lc = 0; 10686 } 10687 break; 10688 } else if ((NXT(len) == '[')) { 10689 /* element name */ 10690 #ifdef DEBUG_STEP 10691 xmlGenericError(xmlGenericErrorContext, 10692 "PathExpr: AbbrRelLocation\n"); 10693 #endif 10694 lc = 1; 10695 break; 10696 } else if ((NXT(len) == '<') || (NXT(len) == '>') || 10697 (NXT(len) == '=')) { 10698 lc = 1; 10699 break; 10700 } else { 10701 lc = 1; 10702 break; 10703 } 10704 len++; 10705 } 10706 if (NXT(len) == 0) { 10707 #ifdef DEBUG_STEP 10708 xmlGenericError(xmlGenericErrorContext, 10709 "PathExpr: AbbrRelLocation\n"); 10710 #endif 10711 /* element name */ 10712 lc = 1; 10713 } 10714 xmlFree(name); 10715 } else { 10716 /* make sure all cases are covered explicitly */ 10717 XP_ERROR(XPATH_EXPR_ERROR); 10718 } 10719 } 10720 10721 if (lc) { 10722 if (CUR == '/') { 10723 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0); 10724 } else { 10725 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0); 10726 } 10727 xmlXPathCompLocationPath(ctxt); 10728 } else { 10729 xmlXPathCompFilterExpr(ctxt); 10730 CHECK_ERROR; 10731 if ((CUR == '/') && (NXT(1) == '/')) { 10732 SKIP(2); 10733 SKIP_BLANKS; 10734 10735 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 10736 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 10737 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0); 10738 10739 xmlXPathCompRelativeLocationPath(ctxt); 10740 } else if (CUR == '/') { 10741 xmlXPathCompRelativeLocationPath(ctxt); 10742 } 10743 } 10744 SKIP_BLANKS; 10745 } 10746 10747 /** 10748 * xmlXPathCompUnionExpr: 10749 * @ctxt: the XPath Parser context 10750 * 10751 * [18] UnionExpr ::= PathExpr 10752 * | UnionExpr '|' PathExpr 10753 * 10754 * Compile an union expression. 10755 */ 10756 10757 static void 10758 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) { 10759 xmlXPathCompPathExpr(ctxt); 10760 CHECK_ERROR; 10761 SKIP_BLANKS; 10762 while (CUR == '|') { 10763 int op1 = ctxt->comp->last; 10764 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0); 10765 10766 NEXT; 10767 SKIP_BLANKS; 10768 xmlXPathCompPathExpr(ctxt); 10769 10770 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0); 10771 10772 SKIP_BLANKS; 10773 } 10774 } 10775 10776 /** 10777 * xmlXPathCompUnaryExpr: 10778 * @ctxt: the XPath Parser context 10779 * 10780 * [27] UnaryExpr ::= UnionExpr 10781 * | '-' UnaryExpr 10782 * 10783 * Compile an unary expression. 10784 */ 10785 10786 static void 10787 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) { 10788 int minus = 0; 10789 int found = 0; 10790 10791 SKIP_BLANKS; 10792 while (CUR == '-') { 10793 minus = 1 - minus; 10794 found = 1; 10795 NEXT; 10796 SKIP_BLANKS; 10797 } 10798 10799 xmlXPathCompUnionExpr(ctxt); 10800 CHECK_ERROR; 10801 if (found) { 10802 if (minus) 10803 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0); 10804 else 10805 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0); 10806 } 10807 } 10808 10809 /** 10810 * xmlXPathCompMultiplicativeExpr: 10811 * @ctxt: the XPath Parser context 10812 * 10813 * [26] MultiplicativeExpr ::= UnaryExpr 10814 * | MultiplicativeExpr MultiplyOperator UnaryExpr 10815 * | MultiplicativeExpr 'div' UnaryExpr 10816 * | MultiplicativeExpr 'mod' UnaryExpr 10817 * [34] MultiplyOperator ::= '*' 10818 * 10819 * Compile an Additive expression. 10820 */ 10821 10822 static void 10823 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) { 10824 xmlXPathCompUnaryExpr(ctxt); 10825 CHECK_ERROR; 10826 SKIP_BLANKS; 10827 while ((CUR == '*') || 10828 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) || 10829 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) { 10830 int op = -1; 10831 int op1 = ctxt->comp->last; 10832 10833 if (CUR == '*') { 10834 op = 0; 10835 NEXT; 10836 } else if (CUR == 'd') { 10837 op = 1; 10838 SKIP(3); 10839 } else if (CUR == 'm') { 10840 op = 2; 10841 SKIP(3); 10842 } 10843 SKIP_BLANKS; 10844 xmlXPathCompUnaryExpr(ctxt); 10845 CHECK_ERROR; 10846 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0); 10847 SKIP_BLANKS; 10848 } 10849 } 10850 10851 /** 10852 * xmlXPathCompAdditiveExpr: 10853 * @ctxt: the XPath Parser context 10854 * 10855 * [25] AdditiveExpr ::= MultiplicativeExpr 10856 * | AdditiveExpr '+' MultiplicativeExpr 10857 * | AdditiveExpr '-' MultiplicativeExpr 10858 * 10859 * Compile an Additive expression. 10860 */ 10861 10862 static void 10863 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) { 10864 10865 xmlXPathCompMultiplicativeExpr(ctxt); 10866 CHECK_ERROR; 10867 SKIP_BLANKS; 10868 while ((CUR == '+') || (CUR == '-')) { 10869 int plus; 10870 int op1 = ctxt->comp->last; 10871 10872 if (CUR == '+') plus = 1; 10873 else plus = 0; 10874 NEXT; 10875 SKIP_BLANKS; 10876 xmlXPathCompMultiplicativeExpr(ctxt); 10877 CHECK_ERROR; 10878 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0); 10879 SKIP_BLANKS; 10880 } 10881 } 10882 10883 /** 10884 * xmlXPathCompRelationalExpr: 10885 * @ctxt: the XPath Parser context 10886 * 10887 * [24] RelationalExpr ::= AdditiveExpr 10888 * | RelationalExpr '<' AdditiveExpr 10889 * | RelationalExpr '>' AdditiveExpr 10890 * | RelationalExpr '<=' AdditiveExpr 10891 * | RelationalExpr '>=' AdditiveExpr 10892 * 10893 * A <= B > C is allowed ? Answer from James, yes with 10894 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr 10895 * which is basically what got implemented. 10896 * 10897 * Compile a Relational expression, then push the result 10898 * on the stack 10899 */ 10900 10901 static void 10902 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) { 10903 xmlXPathCompAdditiveExpr(ctxt); 10904 CHECK_ERROR; 10905 SKIP_BLANKS; 10906 while ((CUR == '<') || 10907 (CUR == '>') || 10908 ((CUR == '<') && (NXT(1) == '=')) || 10909 ((CUR == '>') && (NXT(1) == '='))) { 10910 int inf, strict; 10911 int op1 = ctxt->comp->last; 10912 10913 if (CUR == '<') inf = 1; 10914 else inf = 0; 10915 if (NXT(1) == '=') strict = 0; 10916 else strict = 1; 10917 NEXT; 10918 if (!strict) NEXT; 10919 SKIP_BLANKS; 10920 xmlXPathCompAdditiveExpr(ctxt); 10921 CHECK_ERROR; 10922 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict); 10923 SKIP_BLANKS; 10924 } 10925 } 10926 10927 /** 10928 * xmlXPathCompEqualityExpr: 10929 * @ctxt: the XPath Parser context 10930 * 10931 * [23] EqualityExpr ::= RelationalExpr 10932 * | EqualityExpr '=' RelationalExpr 10933 * | EqualityExpr '!=' RelationalExpr 10934 * 10935 * A != B != C is allowed ? Answer from James, yes with 10936 * (RelationalExpr = RelationalExpr) = RelationalExpr 10937 * (RelationalExpr != RelationalExpr) != RelationalExpr 10938 * which is basically what got implemented. 10939 * 10940 * Compile an Equality expression. 10941 * 10942 */ 10943 static void 10944 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) { 10945 xmlXPathCompRelationalExpr(ctxt); 10946 CHECK_ERROR; 10947 SKIP_BLANKS; 10948 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) { 10949 int eq; 10950 int op1 = ctxt->comp->last; 10951 10952 if (CUR == '=') eq = 1; 10953 else eq = 0; 10954 NEXT; 10955 if (!eq) NEXT; 10956 SKIP_BLANKS; 10957 xmlXPathCompRelationalExpr(ctxt); 10958 CHECK_ERROR; 10959 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0); 10960 SKIP_BLANKS; 10961 } 10962 } 10963 10964 /** 10965 * xmlXPathCompAndExpr: 10966 * @ctxt: the XPath Parser context 10967 * 10968 * [22] AndExpr ::= EqualityExpr 10969 * | AndExpr 'and' EqualityExpr 10970 * 10971 * Compile an AND expression. 10972 * 10973 */ 10974 static void 10975 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) { 10976 xmlXPathCompEqualityExpr(ctxt); 10977 CHECK_ERROR; 10978 SKIP_BLANKS; 10979 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) { 10980 int op1 = ctxt->comp->last; 10981 SKIP(3); 10982 SKIP_BLANKS; 10983 xmlXPathCompEqualityExpr(ctxt); 10984 CHECK_ERROR; 10985 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0); 10986 SKIP_BLANKS; 10987 } 10988 } 10989 10990 /** 10991 * xmlXPathCompileExpr: 10992 * @ctxt: the XPath Parser context 10993 * 10994 * [14] Expr ::= OrExpr 10995 * [21] OrExpr ::= AndExpr 10996 * | OrExpr 'or' AndExpr 10997 * 10998 * Parse and compile an expression 10999 */ 11000 static void 11001 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) { 11002 xmlXPathCompAndExpr(ctxt); 11003 CHECK_ERROR; 11004 SKIP_BLANKS; 11005 while ((CUR == 'o') && (NXT(1) == 'r')) { 11006 int op1 = ctxt->comp->last; 11007 SKIP(2); 11008 SKIP_BLANKS; 11009 xmlXPathCompAndExpr(ctxt); 11010 CHECK_ERROR; 11011 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0); 11012 SKIP_BLANKS; 11013 } 11014 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) { 11015 /* more ops could be optimized too */ 11016 /* 11017 * This is the main place to eliminate sorting for 11018 * operations which don't require a sorted node-set. 11019 * E.g. count(). 11020 */ 11021 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0); 11022 } 11023 } 11024 11025 /** 11026 * xmlXPathCompPredicate: 11027 * @ctxt: the XPath Parser context 11028 * @filter: act as a filter 11029 * 11030 * [8] Predicate ::= '[' PredicateExpr ']' 11031 * [9] PredicateExpr ::= Expr 11032 * 11033 * Compile a predicate expression 11034 */ 11035 static void 11036 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) { 11037 int op1 = ctxt->comp->last; 11038 11039 SKIP_BLANKS; 11040 if (CUR != '[') { 11041 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); 11042 } 11043 NEXT; 11044 SKIP_BLANKS; 11045 11046 ctxt->comp->last = -1; 11047 /* 11048 * This call to xmlXPathCompileExpr() will deactivate sorting 11049 * of the predicate result. 11050 * TODO: Sorting is still activated for filters, since I'm not 11051 * sure if needed. Normally sorting should not be needed, since 11052 * a filter can only diminish the number of items in a sequence, 11053 * but won't change its order; so if the initial sequence is sorted, 11054 * subsequent sorting is not needed. 11055 */ 11056 if (! filter) 11057 xmlXPathCompileExpr(ctxt, 0); 11058 else 11059 xmlXPathCompileExpr(ctxt, 1); 11060 CHECK_ERROR; 11061 11062 if (CUR != ']') { 11063 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); 11064 } 11065 11066 if (filter) 11067 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0); 11068 else 11069 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0); 11070 11071 NEXT; 11072 SKIP_BLANKS; 11073 } 11074 11075 /** 11076 * xmlXPathCompNodeTest: 11077 * @ctxt: the XPath Parser context 11078 * @test: pointer to a xmlXPathTestVal 11079 * @type: pointer to a xmlXPathTypeVal 11080 * @prefix: placeholder for a possible name prefix 11081 * 11082 * [7] NodeTest ::= NameTest 11083 * | NodeType '(' ')' 11084 * | 'processing-instruction' '(' Literal ')' 11085 * 11086 * [37] NameTest ::= '*' 11087 * | NCName ':' '*' 11088 * | QName 11089 * [38] NodeType ::= 'comment' 11090 * | 'text' 11091 * | 'processing-instruction' 11092 * | 'node' 11093 * 11094 * Returns the name found and updates @test, @type and @prefix appropriately 11095 */ 11096 static xmlChar * 11097 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test, 11098 xmlXPathTypeVal *type, const xmlChar **prefix, 11099 xmlChar *name) { 11100 int blanks; 11101 11102 if ((test == NULL) || (type == NULL) || (prefix == NULL)) { 11103 STRANGE; 11104 return(NULL); 11105 } 11106 *type = (xmlXPathTypeVal) 0; 11107 *test = (xmlXPathTestVal) 0; 11108 *prefix = NULL; 11109 SKIP_BLANKS; 11110 11111 if ((name == NULL) && (CUR == '*')) { 11112 /* 11113 * All elements 11114 */ 11115 NEXT; 11116 *test = NODE_TEST_ALL; 11117 return(NULL); 11118 } 11119 11120 if (name == NULL) 11121 name = xmlXPathParseNCName(ctxt); 11122 if (name == NULL) { 11123 XP_ERRORNULL(XPATH_EXPR_ERROR); 11124 } 11125 11126 blanks = IS_BLANK_CH(CUR); 11127 SKIP_BLANKS; 11128 if (CUR == '(') { 11129 NEXT; 11130 /* 11131 * NodeType or PI search 11132 */ 11133 if (xmlStrEqual(name, BAD_CAST "comment")) 11134 *type = NODE_TYPE_COMMENT; 11135 else if (xmlStrEqual(name, BAD_CAST "node")) 11136 *type = NODE_TYPE_NODE; 11137 else if (xmlStrEqual(name, BAD_CAST "processing-instruction")) 11138 *type = NODE_TYPE_PI; 11139 else if (xmlStrEqual(name, BAD_CAST "text")) 11140 *type = NODE_TYPE_TEXT; 11141 else { 11142 if (name != NULL) 11143 xmlFree(name); 11144 XP_ERRORNULL(XPATH_EXPR_ERROR); 11145 } 11146 11147 *test = NODE_TEST_TYPE; 11148 11149 SKIP_BLANKS; 11150 if (*type == NODE_TYPE_PI) { 11151 /* 11152 * Specific case: search a PI by name. 11153 */ 11154 if (name != NULL) 11155 xmlFree(name); 11156 name = NULL; 11157 if (CUR != ')') { 11158 name = xmlXPathParseLiteral(ctxt); 11159 CHECK_ERROR NULL; 11160 *test = NODE_TEST_PI; 11161 SKIP_BLANKS; 11162 } 11163 } 11164 if (CUR != ')') { 11165 if (name != NULL) 11166 xmlFree(name); 11167 XP_ERRORNULL(XPATH_UNCLOSED_ERROR); 11168 } 11169 NEXT; 11170 return(name); 11171 } 11172 *test = NODE_TEST_NAME; 11173 if ((!blanks) && (CUR == ':')) { 11174 NEXT; 11175 11176 /* 11177 * Since currently the parser context don't have a 11178 * namespace list associated: 11179 * The namespace name for this prefix can be computed 11180 * only at evaluation time. The compilation is done 11181 * outside of any context. 11182 */ 11183 #if 0 11184 *prefix = xmlXPathNsLookup(ctxt->context, name); 11185 if (name != NULL) 11186 xmlFree(name); 11187 if (*prefix == NULL) { 11188 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); 11189 } 11190 #else 11191 *prefix = name; 11192 #endif 11193 11194 if (CUR == '*') { 11195 /* 11196 * All elements 11197 */ 11198 NEXT; 11199 *test = NODE_TEST_ALL; 11200 return(NULL); 11201 } 11202 11203 name = xmlXPathParseNCName(ctxt); 11204 if (name == NULL) { 11205 XP_ERRORNULL(XPATH_EXPR_ERROR); 11206 } 11207 } 11208 return(name); 11209 } 11210 11211 /** 11212 * xmlXPathIsAxisName: 11213 * @name: a preparsed name token 11214 * 11215 * [6] AxisName ::= 'ancestor' 11216 * | 'ancestor-or-self' 11217 * | 'attribute' 11218 * | 'child' 11219 * | 'descendant' 11220 * | 'descendant-or-self' 11221 * | 'following' 11222 * | 'following-sibling' 11223 * | 'namespace' 11224 * | 'parent' 11225 * | 'preceding' 11226 * | 'preceding-sibling' 11227 * | 'self' 11228 * 11229 * Returns the axis or 0 11230 */ 11231 static xmlXPathAxisVal 11232 xmlXPathIsAxisName(const xmlChar *name) { 11233 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0; 11234 switch (name[0]) { 11235 case 'a': 11236 if (xmlStrEqual(name, BAD_CAST "ancestor")) 11237 ret = AXIS_ANCESTOR; 11238 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self")) 11239 ret = AXIS_ANCESTOR_OR_SELF; 11240 if (xmlStrEqual(name, BAD_CAST "attribute")) 11241 ret = AXIS_ATTRIBUTE; 11242 break; 11243 case 'c': 11244 if (xmlStrEqual(name, BAD_CAST "child")) 11245 ret = AXIS_CHILD; 11246 break; 11247 case 'd': 11248 if (xmlStrEqual(name, BAD_CAST "descendant")) 11249 ret = AXIS_DESCENDANT; 11250 if (xmlStrEqual(name, BAD_CAST "descendant-or-self")) 11251 ret = AXIS_DESCENDANT_OR_SELF; 11252 break; 11253 case 'f': 11254 if (xmlStrEqual(name, BAD_CAST "following")) 11255 ret = AXIS_FOLLOWING; 11256 if (xmlStrEqual(name, BAD_CAST "following-sibling")) 11257 ret = AXIS_FOLLOWING_SIBLING; 11258 break; 11259 case 'n': 11260 if (xmlStrEqual(name, BAD_CAST "namespace")) 11261 ret = AXIS_NAMESPACE; 11262 break; 11263 case 'p': 11264 if (xmlStrEqual(name, BAD_CAST "parent")) 11265 ret = AXIS_PARENT; 11266 if (xmlStrEqual(name, BAD_CAST "preceding")) 11267 ret = AXIS_PRECEDING; 11268 if (xmlStrEqual(name, BAD_CAST "preceding-sibling")) 11269 ret = AXIS_PRECEDING_SIBLING; 11270 break; 11271 case 's': 11272 if (xmlStrEqual(name, BAD_CAST "self")) 11273 ret = AXIS_SELF; 11274 break; 11275 } 11276 return(ret); 11277 } 11278 11279 /** 11280 * xmlXPathCompStep: 11281 * @ctxt: the XPath Parser context 11282 * 11283 * [4] Step ::= AxisSpecifier NodeTest Predicate* 11284 * | AbbreviatedStep 11285 * 11286 * [12] AbbreviatedStep ::= '.' | '..' 11287 * 11288 * [5] AxisSpecifier ::= AxisName '::' 11289 * | AbbreviatedAxisSpecifier 11290 * 11291 * [13] AbbreviatedAxisSpecifier ::= '@'? 11292 * 11293 * Modified for XPtr range support as: 11294 * 11295 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate* 11296 * | AbbreviatedStep 11297 * | 'range-to' '(' Expr ')' Predicate* 11298 * 11299 * Compile one step in a Location Path 11300 * A location step of . is short for self::node(). This is 11301 * particularly useful in conjunction with //. For example, the 11302 * location path .//para is short for 11303 * self::node()/descendant-or-self::node()/child::para 11304 * and so will select all para descendant elements of the context 11305 * node. 11306 * Similarly, a location step of .. is short for parent::node(). 11307 * For example, ../title is short for parent::node()/child::title 11308 * and so will select the title children of the parent of the context 11309 * node. 11310 */ 11311 static void 11312 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) { 11313 #ifdef LIBXML_XPTR_ENABLED 11314 int rangeto = 0; 11315 int op2 = -1; 11316 #endif 11317 11318 SKIP_BLANKS; 11319 if ((CUR == '.') && (NXT(1) == '.')) { 11320 SKIP(2); 11321 SKIP_BLANKS; 11322 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT, 11323 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11324 } else if (CUR == '.') { 11325 NEXT; 11326 SKIP_BLANKS; 11327 } else { 11328 xmlChar *name = NULL; 11329 const xmlChar *prefix = NULL; 11330 xmlXPathTestVal test = (xmlXPathTestVal) 0; 11331 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0; 11332 xmlXPathTypeVal type = (xmlXPathTypeVal) 0; 11333 int op1; 11334 11335 /* 11336 * The modification needed for XPointer change to the production 11337 */ 11338 #ifdef LIBXML_XPTR_ENABLED 11339 if (ctxt->xptr) { 11340 name = xmlXPathParseNCName(ctxt); 11341 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) { 11342 op2 = ctxt->comp->last; 11343 xmlFree(name); 11344 SKIP_BLANKS; 11345 if (CUR != '(') { 11346 XP_ERROR(XPATH_EXPR_ERROR); 11347 } 11348 NEXT; 11349 SKIP_BLANKS; 11350 11351 xmlXPathCompileExpr(ctxt, 1); 11352 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */ 11353 CHECK_ERROR; 11354 11355 SKIP_BLANKS; 11356 if (CUR != ')') { 11357 XP_ERROR(XPATH_EXPR_ERROR); 11358 } 11359 NEXT; 11360 rangeto = 1; 11361 goto eval_predicates; 11362 } 11363 } 11364 #endif 11365 if (CUR == '*') { 11366 axis = AXIS_CHILD; 11367 } else { 11368 if (name == NULL) 11369 name = xmlXPathParseNCName(ctxt); 11370 if (name != NULL) { 11371 axis = xmlXPathIsAxisName(name); 11372 if (axis != 0) { 11373 SKIP_BLANKS; 11374 if ((CUR == ':') && (NXT(1) == ':')) { 11375 SKIP(2); 11376 xmlFree(name); 11377 name = NULL; 11378 } else { 11379 /* an element name can conflict with an axis one :-\ */ 11380 axis = AXIS_CHILD; 11381 } 11382 } else { 11383 axis = AXIS_CHILD; 11384 } 11385 } else if (CUR == '@') { 11386 NEXT; 11387 axis = AXIS_ATTRIBUTE; 11388 } else { 11389 axis = AXIS_CHILD; 11390 } 11391 } 11392 11393 if (ctxt->error != XPATH_EXPRESSION_OK) { 11394 xmlFree(name); 11395 return; 11396 } 11397 11398 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name); 11399 if (test == 0) 11400 return; 11401 11402 if ((prefix != NULL) && (ctxt->context != NULL) && 11403 (ctxt->context->flags & XML_XPATH_CHECKNS)) { 11404 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) { 11405 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR); 11406 } 11407 } 11408 #ifdef DEBUG_STEP 11409 xmlGenericError(xmlGenericErrorContext, 11410 "Basis : computing new set\n"); 11411 #endif 11412 11413 #ifdef DEBUG_STEP 11414 xmlGenericError(xmlGenericErrorContext, "Basis : "); 11415 if (ctxt->value == NULL) 11416 xmlGenericError(xmlGenericErrorContext, "no value\n"); 11417 else if (ctxt->value->nodesetval == NULL) 11418 xmlGenericError(xmlGenericErrorContext, "Empty\n"); 11419 else 11420 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval); 11421 #endif 11422 11423 #ifdef LIBXML_XPTR_ENABLED 11424 eval_predicates: 11425 #endif 11426 op1 = ctxt->comp->last; 11427 ctxt->comp->last = -1; 11428 11429 SKIP_BLANKS; 11430 while (CUR == '[') { 11431 xmlXPathCompPredicate(ctxt, 0); 11432 } 11433 11434 #ifdef LIBXML_XPTR_ENABLED 11435 if (rangeto) { 11436 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0); 11437 } else 11438 #endif 11439 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis, 11440 test, type, (void *)prefix, (void *)name); 11441 11442 } 11443 #ifdef DEBUG_STEP 11444 xmlGenericError(xmlGenericErrorContext, "Step : "); 11445 if (ctxt->value == NULL) 11446 xmlGenericError(xmlGenericErrorContext, "no value\n"); 11447 else if (ctxt->value->nodesetval == NULL) 11448 xmlGenericError(xmlGenericErrorContext, "Empty\n"); 11449 else 11450 xmlGenericErrorContextNodeSet(xmlGenericErrorContext, 11451 ctxt->value->nodesetval); 11452 #endif 11453 } 11454 11455 /** 11456 * xmlXPathCompRelativeLocationPath: 11457 * @ctxt: the XPath Parser context 11458 * 11459 * [3] RelativeLocationPath ::= Step 11460 * | RelativeLocationPath '/' Step 11461 * | AbbreviatedRelativeLocationPath 11462 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step 11463 * 11464 * Compile a relative location path. 11465 */ 11466 static void 11467 xmlXPathCompRelativeLocationPath 11468 (xmlXPathParserContextPtr ctxt) { 11469 SKIP_BLANKS; 11470 if ((CUR == '/') && (NXT(1) == '/')) { 11471 SKIP(2); 11472 SKIP_BLANKS; 11473 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 11474 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11475 } else if (CUR == '/') { 11476 NEXT; 11477 SKIP_BLANKS; 11478 } 11479 xmlXPathCompStep(ctxt); 11480 CHECK_ERROR; 11481 SKIP_BLANKS; 11482 while (CUR == '/') { 11483 if ((CUR == '/') && (NXT(1) == '/')) { 11484 SKIP(2); 11485 SKIP_BLANKS; 11486 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 11487 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11488 xmlXPathCompStep(ctxt); 11489 } else if (CUR == '/') { 11490 NEXT; 11491 SKIP_BLANKS; 11492 xmlXPathCompStep(ctxt); 11493 } 11494 SKIP_BLANKS; 11495 } 11496 } 11497 11498 /** 11499 * xmlXPathCompLocationPath: 11500 * @ctxt: the XPath Parser context 11501 * 11502 * [1] LocationPath ::= RelativeLocationPath 11503 * | AbsoluteLocationPath 11504 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath? 11505 * | AbbreviatedAbsoluteLocationPath 11506 * [10] AbbreviatedAbsoluteLocationPath ::= 11507 * '//' RelativeLocationPath 11508 * 11509 * Compile a location path 11510 * 11511 * // is short for /descendant-or-self::node()/. For example, 11512 * //para is short for /descendant-or-self::node()/child::para and 11513 * so will select any para element in the document (even a para element 11514 * that is a document element will be selected by //para since the 11515 * document element node is a child of the root node); div//para is 11516 * short for div/descendant-or-self::node()/child::para and so will 11517 * select all para descendants of div children. 11518 */ 11519 static void 11520 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) { 11521 SKIP_BLANKS; 11522 if (CUR != '/') { 11523 xmlXPathCompRelativeLocationPath(ctxt); 11524 } else { 11525 while (CUR == '/') { 11526 if ((CUR == '/') && (NXT(1) == '/')) { 11527 SKIP(2); 11528 SKIP_BLANKS; 11529 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 11530 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11531 xmlXPathCompRelativeLocationPath(ctxt); 11532 } else if (CUR == '/') { 11533 NEXT; 11534 SKIP_BLANKS; 11535 if ((CUR != 0 ) && 11536 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') || 11537 (CUR == '@') || (CUR == '*'))) 11538 xmlXPathCompRelativeLocationPath(ctxt); 11539 } 11540 CHECK_ERROR; 11541 } 11542 } 11543 } 11544 11545 /************************************************************************ 11546 * * 11547 * XPath precompiled expression evaluation * 11548 * * 11549 ************************************************************************/ 11550 11551 static int 11552 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op); 11553 11554 #ifdef DEBUG_STEP 11555 static void 11556 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op, 11557 int nbNodes) 11558 { 11559 xmlGenericError(xmlGenericErrorContext, "new step : "); 11560 switch (op->value) { 11561 case AXIS_ANCESTOR: 11562 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' "); 11563 break; 11564 case AXIS_ANCESTOR_OR_SELF: 11565 xmlGenericError(xmlGenericErrorContext, 11566 "axis 'ancestors-or-self' "); 11567 break; 11568 case AXIS_ATTRIBUTE: 11569 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' "); 11570 break; 11571 case AXIS_CHILD: 11572 xmlGenericError(xmlGenericErrorContext, "axis 'child' "); 11573 break; 11574 case AXIS_DESCENDANT: 11575 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' "); 11576 break; 11577 case AXIS_DESCENDANT_OR_SELF: 11578 xmlGenericError(xmlGenericErrorContext, 11579 "axis 'descendant-or-self' "); 11580 break; 11581 case AXIS_FOLLOWING: 11582 xmlGenericError(xmlGenericErrorContext, "axis 'following' "); 11583 break; 11584 case AXIS_FOLLOWING_SIBLING: 11585 xmlGenericError(xmlGenericErrorContext, 11586 "axis 'following-siblings' "); 11587 break; 11588 case AXIS_NAMESPACE: 11589 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' "); 11590 break; 11591 case AXIS_PARENT: 11592 xmlGenericError(xmlGenericErrorContext, "axis 'parent' "); 11593 break; 11594 case AXIS_PRECEDING: 11595 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' "); 11596 break; 11597 case AXIS_PRECEDING_SIBLING: 11598 xmlGenericError(xmlGenericErrorContext, 11599 "axis 'preceding-sibling' "); 11600 break; 11601 case AXIS_SELF: 11602 xmlGenericError(xmlGenericErrorContext, "axis 'self' "); 11603 break; 11604 } 11605 xmlGenericError(xmlGenericErrorContext, 11606 " context contains %d nodes\n", nbNodes); 11607 switch (op->value2) { 11608 case NODE_TEST_NONE: 11609 xmlGenericError(xmlGenericErrorContext, 11610 " searching for none !!!\n"); 11611 break; 11612 case NODE_TEST_TYPE: 11613 xmlGenericError(xmlGenericErrorContext, 11614 " searching for type %d\n", op->value3); 11615 break; 11616 case NODE_TEST_PI: 11617 xmlGenericError(xmlGenericErrorContext, 11618 " searching for PI !!!\n"); 11619 break; 11620 case NODE_TEST_ALL: 11621 xmlGenericError(xmlGenericErrorContext, 11622 " searching for *\n"); 11623 break; 11624 case NODE_TEST_NS: 11625 xmlGenericError(xmlGenericErrorContext, 11626 " searching for namespace %s\n", 11627 op->value5); 11628 break; 11629 case NODE_TEST_NAME: 11630 xmlGenericError(xmlGenericErrorContext, 11631 " searching for name %s\n", op->value5); 11632 if (op->value4) 11633 xmlGenericError(xmlGenericErrorContext, 11634 " with namespace %s\n", op->value4); 11635 break; 11636 } 11637 xmlGenericError(xmlGenericErrorContext, "Testing : "); 11638 } 11639 #endif /* DEBUG_STEP */ 11640 11641 static int 11642 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt, 11643 xmlXPathStepOpPtr op, 11644 xmlNodeSetPtr set, 11645 int contextSize, 11646 int hasNsNodes) 11647 { 11648 if (op->ch1 != -1) { 11649 xmlXPathCompExprPtr comp = ctxt->comp; 11650 /* 11651 * Process inner predicates first. 11652 */ 11653 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) { 11654 /* 11655 * TODO: raise an internal error. 11656 */ 11657 } 11658 contextSize = xmlXPathCompOpEvalPredicate(ctxt, 11659 &comp->steps[op->ch1], set, contextSize, hasNsNodes); 11660 CHECK_ERROR0; 11661 if (contextSize <= 0) 11662 return(0); 11663 } 11664 if (op->ch2 != -1) { 11665 xmlXPathContextPtr xpctxt = ctxt->context; 11666 xmlNodePtr contextNode, oldContextNode; 11667 xmlDocPtr oldContextDoc; 11668 int i, res, contextPos = 0, newContextSize; 11669 xmlXPathStepOpPtr exprOp; 11670 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL; 11671 11672 #ifdef LIBXML_XPTR_ENABLED 11673 /* 11674 * URGENT TODO: Check the following: 11675 * We don't expect location sets if evaluating prediates, right? 11676 * Only filters should expect location sets, right? 11677 */ 11678 #endif 11679 /* 11680 * SPEC XPath 1.0: 11681 * "For each node in the node-set to be filtered, the 11682 * PredicateExpr is evaluated with that node as the 11683 * context node, with the number of nodes in the 11684 * node-set as the context size, and with the proximity 11685 * position of the node in the node-set with respect to 11686 * the axis as the context position;" 11687 * @oldset is the node-set" to be filtered. 11688 * 11689 * SPEC XPath 1.0: 11690 * "only predicates change the context position and 11691 * context size (see [2.4 Predicates])." 11692 * Example: 11693 * node-set context pos 11694 * nA 1 11695 * nB 2 11696 * nC 3 11697 * After applying predicate [position() > 1] : 11698 * node-set context pos 11699 * nB 1 11700 * nC 2 11701 */ 11702 oldContextNode = xpctxt->node; 11703 oldContextDoc = xpctxt->doc; 11704 /* 11705 * Get the expression of this predicate. 11706 */ 11707 exprOp = &ctxt->comp->steps[op->ch2]; 11708 newContextSize = 0; 11709 for (i = 0; i < set->nodeNr; i++) { 11710 if (set->nodeTab[i] == NULL) 11711 continue; 11712 11713 contextNode = set->nodeTab[i]; 11714 xpctxt->node = contextNode; 11715 xpctxt->contextSize = contextSize; 11716 xpctxt->proximityPosition = ++contextPos; 11717 11718 /* 11719 * Also set the xpath document in case things like 11720 * key() are evaluated in the predicate. 11721 */ 11722 if ((contextNode->type != XML_NAMESPACE_DECL) && 11723 (contextNode->doc != NULL)) 11724 xpctxt->doc = contextNode->doc; 11725 /* 11726 * Evaluate the predicate expression with 1 context node 11727 * at a time; this node is packaged into a node set; this 11728 * node set is handed over to the evaluation mechanism. 11729 */ 11730 if (contextObj == NULL) 11731 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode); 11732 else { 11733 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval, 11734 contextNode) < 0) { 11735 ctxt->error = XPATH_MEMORY_ERROR; 11736 goto evaluation_exit; 11737 } 11738 } 11739 11740 valuePush(ctxt, contextObj); 11741 11742 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1); 11743 11744 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) { 11745 xmlXPathNodeSetClear(set, hasNsNodes); 11746 newContextSize = 0; 11747 goto evaluation_exit; 11748 } 11749 11750 if (res != 0) { 11751 newContextSize++; 11752 } else { 11753 /* 11754 * Remove the entry from the initial node set. 11755 */ 11756 set->nodeTab[i] = NULL; 11757 if (contextNode->type == XML_NAMESPACE_DECL) 11758 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode); 11759 } 11760 if (ctxt->value == contextObj) { 11761 /* 11762 * Don't free the temporary XPath object holding the 11763 * context node, in order to avoid massive recreation 11764 * inside this loop. 11765 */ 11766 valuePop(ctxt); 11767 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes); 11768 } else { 11769 /* 11770 * TODO: The object was lost in the evaluation machinery. 11771 * Can this happen? Maybe in internal-error cases. 11772 */ 11773 contextObj = NULL; 11774 } 11775 } 11776 11777 if (contextObj != NULL) { 11778 if (ctxt->value == contextObj) 11779 valuePop(ctxt); 11780 xmlXPathReleaseObject(xpctxt, contextObj); 11781 } 11782 evaluation_exit: 11783 if (exprRes != NULL) 11784 xmlXPathReleaseObject(ctxt->context, exprRes); 11785 /* 11786 * Reset/invalidate the context. 11787 */ 11788 xpctxt->node = oldContextNode; 11789 xpctxt->doc = oldContextDoc; 11790 xpctxt->contextSize = -1; 11791 xpctxt->proximityPosition = -1; 11792 return(newContextSize); 11793 } 11794 return(contextSize); 11795 } 11796 11797 static int 11798 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt, 11799 xmlXPathStepOpPtr op, 11800 xmlNodeSetPtr set, 11801 int contextSize, 11802 int minPos, 11803 int maxPos, 11804 int hasNsNodes) 11805 { 11806 if (op->ch1 != -1) { 11807 xmlXPathCompExprPtr comp = ctxt->comp; 11808 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) { 11809 /* 11810 * TODO: raise an internal error. 11811 */ 11812 } 11813 contextSize = xmlXPathCompOpEvalPredicate(ctxt, 11814 &comp->steps[op->ch1], set, contextSize, hasNsNodes); 11815 CHECK_ERROR0; 11816 if (contextSize <= 0) 11817 return(0); 11818 } 11819 /* 11820 * Check if the node set contains a sufficient number of nodes for 11821 * the requested range. 11822 */ 11823 if (contextSize < minPos) { 11824 xmlXPathNodeSetClear(set, hasNsNodes); 11825 return(0); 11826 } 11827 if (op->ch2 == -1) { 11828 /* 11829 * TODO: Can this ever happen? 11830 */ 11831 return (contextSize); 11832 } else { 11833 xmlDocPtr oldContextDoc; 11834 int i, pos = 0, newContextSize = 0, contextPos = 0, res; 11835 xmlXPathStepOpPtr exprOp; 11836 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL; 11837 xmlNodePtr oldContextNode, contextNode = NULL; 11838 xmlXPathContextPtr xpctxt = ctxt->context; 11839 int frame; 11840 11841 #ifdef LIBXML_XPTR_ENABLED 11842 /* 11843 * URGENT TODO: Check the following: 11844 * We don't expect location sets if evaluating prediates, right? 11845 * Only filters should expect location sets, right? 11846 */ 11847 #endif /* LIBXML_XPTR_ENABLED */ 11848 11849 /* 11850 * Save old context. 11851 */ 11852 oldContextNode = xpctxt->node; 11853 oldContextDoc = xpctxt->doc; 11854 /* 11855 * Get the expression of this predicate. 11856 */ 11857 exprOp = &ctxt->comp->steps[op->ch2]; 11858 for (i = 0; i < set->nodeNr; i++) { 11859 xmlXPathObjectPtr tmp; 11860 11861 if (set->nodeTab[i] == NULL) 11862 continue; 11863 11864 contextNode = set->nodeTab[i]; 11865 xpctxt->node = contextNode; 11866 xpctxt->contextSize = contextSize; 11867 xpctxt->proximityPosition = ++contextPos; 11868 11869 /* 11870 * Initialize the new set. 11871 * Also set the xpath document in case things like 11872 * key() evaluation are attempted on the predicate 11873 */ 11874 if ((contextNode->type != XML_NAMESPACE_DECL) && 11875 (contextNode->doc != NULL)) 11876 xpctxt->doc = contextNode->doc; 11877 /* 11878 * Evaluate the predicate expression with 1 context node 11879 * at a time; this node is packaged into a node set; this 11880 * node set is handed over to the evaluation mechanism. 11881 */ 11882 if (contextObj == NULL) 11883 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode); 11884 else { 11885 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval, 11886 contextNode) < 0) { 11887 ctxt->error = XPATH_MEMORY_ERROR; 11888 goto evaluation_exit; 11889 } 11890 } 11891 11892 valuePush(ctxt, contextObj); 11893 frame = xmlXPathSetFrame(ctxt); 11894 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1); 11895 xmlXPathPopFrame(ctxt, frame); 11896 tmp = valuePop(ctxt); 11897 11898 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) { 11899 while (tmp != contextObj) { 11900 /* 11901 * Free up the result 11902 * then pop off contextObj, which will be freed later 11903 */ 11904 xmlXPathReleaseObject(xpctxt, tmp); 11905 tmp = valuePop(ctxt); 11906 } 11907 goto evaluation_error; 11908 } 11909 /* push the result back onto the stack */ 11910 valuePush(ctxt, tmp); 11911 11912 if (res) 11913 pos++; 11914 11915 if (res && (pos >= minPos) && (pos <= maxPos)) { 11916 /* 11917 * Fits in the requested range. 11918 */ 11919 newContextSize++; 11920 if (minPos == maxPos) { 11921 /* 11922 * Only 1 node was requested. 11923 */ 11924 if (contextNode->type == XML_NAMESPACE_DECL) { 11925 /* 11926 * As always: take care of those nasty 11927 * namespace nodes. 11928 */ 11929 set->nodeTab[i] = NULL; 11930 } 11931 xmlXPathNodeSetClear(set, hasNsNodes); 11932 set->nodeNr = 1; 11933 set->nodeTab[0] = contextNode; 11934 goto evaluation_exit; 11935 } 11936 if (pos == maxPos) { 11937 /* 11938 * We are done. 11939 */ 11940 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes); 11941 goto evaluation_exit; 11942 } 11943 } else { 11944 /* 11945 * Remove the entry from the initial node set. 11946 */ 11947 set->nodeTab[i] = NULL; 11948 if (contextNode->type == XML_NAMESPACE_DECL) 11949 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode); 11950 } 11951 if (exprRes != NULL) { 11952 xmlXPathReleaseObject(ctxt->context, exprRes); 11953 exprRes = NULL; 11954 } 11955 if (ctxt->value == contextObj) { 11956 /* 11957 * Don't free the temporary XPath object holding the 11958 * context node, in order to avoid massive recreation 11959 * inside this loop. 11960 */ 11961 valuePop(ctxt); 11962 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes); 11963 } else { 11964 /* 11965 * The object was lost in the evaluation machinery. 11966 * Can this happen? Maybe in case of internal-errors. 11967 */ 11968 contextObj = NULL; 11969 } 11970 } 11971 goto evaluation_exit; 11972 11973 evaluation_error: 11974 xmlXPathNodeSetClear(set, hasNsNodes); 11975 newContextSize = 0; 11976 11977 evaluation_exit: 11978 if (contextObj != NULL) { 11979 if (ctxt->value == contextObj) 11980 valuePop(ctxt); 11981 xmlXPathReleaseObject(xpctxt, contextObj); 11982 } 11983 if (exprRes != NULL) 11984 xmlXPathReleaseObject(ctxt->context, exprRes); 11985 /* 11986 * Reset/invalidate the context. 11987 */ 11988 xpctxt->node = oldContextNode; 11989 xpctxt->doc = oldContextDoc; 11990 xpctxt->contextSize = -1; 11991 xpctxt->proximityPosition = -1; 11992 return(newContextSize); 11993 } 11994 return(contextSize); 11995 } 11996 11997 static int 11998 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt, 11999 xmlXPathStepOpPtr op, 12000 int *maxPos) 12001 { 12002 12003 xmlXPathStepOpPtr exprOp; 12004 12005 /* 12006 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet! 12007 */ 12008 12009 /* 12010 * If not -1, then ch1 will point to: 12011 * 1) For predicates (XPATH_OP_PREDICATE): 12012 * - an inner predicate operator 12013 * 2) For filters (XPATH_OP_FILTER): 12014 * - an inner filter operater OR 12015 * - an expression selecting the node set. 12016 * E.g. "key('a', 'b')" or "(//foo | //bar)". 12017 */ 12018 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER)) 12019 return(0); 12020 12021 if (op->ch2 != -1) { 12022 exprOp = &ctxt->comp->steps[op->ch2]; 12023 } else 12024 return(0); 12025 12026 if ((exprOp != NULL) && 12027 (exprOp->op == XPATH_OP_VALUE) && 12028 (exprOp->value4 != NULL) && 12029 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER)) 12030 { 12031 double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval; 12032 12033 /* 12034 * We have a "[n]" predicate here. 12035 * TODO: Unfortunately this simplistic test here is not 12036 * able to detect a position() predicate in compound 12037 * expressions like "[@attr = 'a" and position() = 1], 12038 * and even not the usage of position() in 12039 * "[position() = 1]"; thus - obviously - a position-range, 12040 * like it "[position() < 5]", is also not detected. 12041 * Maybe we could rewrite the AST to ease the optimization. 12042 */ 12043 12044 if ((floatval > INT_MIN) && (floatval < INT_MAX)) { 12045 *maxPos = (int) floatval; 12046 if (floatval == (double) *maxPos) 12047 return(1); 12048 } 12049 } 12050 return(0); 12051 } 12052 12053 static int 12054 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, 12055 xmlXPathStepOpPtr op, 12056 xmlNodePtr * first, xmlNodePtr * last, 12057 int toBool) 12058 { 12059 12060 #define XP_TEST_HIT \ 12061 if (hasAxisRange != 0) { \ 12062 if (++pos == maxPos) { \ 12063 if (addNode(seq, cur) < 0) \ 12064 ctxt->error = XPATH_MEMORY_ERROR; \ 12065 goto axis_range_end; } \ 12066 } else { \ 12067 if (addNode(seq, cur) < 0) \ 12068 ctxt->error = XPATH_MEMORY_ERROR; \ 12069 if (breakOnFirstHit) goto first_hit; } 12070 12071 #define XP_TEST_HIT_NS \ 12072 if (hasAxisRange != 0) { \ 12073 if (++pos == maxPos) { \ 12074 hasNsNodes = 1; \ 12075 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \ 12076 ctxt->error = XPATH_MEMORY_ERROR; \ 12077 goto axis_range_end; } \ 12078 } else { \ 12079 hasNsNodes = 1; \ 12080 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \ 12081 ctxt->error = XPATH_MEMORY_ERROR; \ 12082 if (breakOnFirstHit) goto first_hit; } 12083 12084 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value; 12085 xmlXPathTestVal test = (xmlXPathTestVal) op->value2; 12086 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3; 12087 const xmlChar *prefix = op->value4; 12088 const xmlChar *name = op->value5; 12089 const xmlChar *URI = NULL; 12090 12091 #ifdef DEBUG_STEP 12092 int nbMatches = 0, prevMatches = 0; 12093 #endif 12094 int total = 0, hasNsNodes = 0; 12095 /* The popped object holding the context nodes */ 12096 xmlXPathObjectPtr obj; 12097 /* The set of context nodes for the node tests */ 12098 xmlNodeSetPtr contextSeq; 12099 int contextIdx; 12100 xmlNodePtr contextNode; 12101 /* The final resulting node set wrt to all context nodes */ 12102 xmlNodeSetPtr outSeq; 12103 /* 12104 * The temporary resulting node set wrt 1 context node. 12105 * Used to feed predicate evaluation. 12106 */ 12107 xmlNodeSetPtr seq; 12108 xmlNodePtr cur; 12109 /* First predicate operator */ 12110 xmlXPathStepOpPtr predOp; 12111 int maxPos; /* The requested position() (when a "[n]" predicate) */ 12112 int hasPredicateRange, hasAxisRange, pos, size, newSize; 12113 int breakOnFirstHit; 12114 12115 xmlXPathTraversalFunction next = NULL; 12116 int (*addNode) (xmlNodeSetPtr, xmlNodePtr); 12117 xmlXPathNodeSetMergeFunction mergeAndClear; 12118 xmlNodePtr oldContextNode; 12119 xmlXPathContextPtr xpctxt = ctxt->context; 12120 12121 12122 CHECK_TYPE0(XPATH_NODESET); 12123 obj = valuePop(ctxt); 12124 /* 12125 * Setup namespaces. 12126 */ 12127 if (prefix != NULL) { 12128 URI = xmlXPathNsLookup(xpctxt, prefix); 12129 if (URI == NULL) { 12130 xmlXPathReleaseObject(xpctxt, obj); 12131 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); 12132 } 12133 } 12134 /* 12135 * Setup axis. 12136 * 12137 * MAYBE FUTURE TODO: merging optimizations: 12138 * - If the nodes to be traversed wrt to the initial nodes and 12139 * the current axis cannot overlap, then we could avoid searching 12140 * for duplicates during the merge. 12141 * But the question is how/when to evaluate if they cannot overlap. 12142 * Example: if we know that for two initial nodes, the one is 12143 * not in the ancestor-or-self axis of the other, then we could safely 12144 * avoid a duplicate-aware merge, if the axis to be traversed is e.g. 12145 * the descendant-or-self axis. 12146 */ 12147 mergeAndClear = xmlXPathNodeSetMergeAndClear; 12148 switch (axis) { 12149 case AXIS_ANCESTOR: 12150 first = NULL; 12151 next = xmlXPathNextAncestor; 12152 break; 12153 case AXIS_ANCESTOR_OR_SELF: 12154 first = NULL; 12155 next = xmlXPathNextAncestorOrSelf; 12156 break; 12157 case AXIS_ATTRIBUTE: 12158 first = NULL; 12159 last = NULL; 12160 next = xmlXPathNextAttribute; 12161 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12162 break; 12163 case AXIS_CHILD: 12164 last = NULL; 12165 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) && 12166 (type == NODE_TYPE_NODE)) 12167 { 12168 /* 12169 * Optimization if an element node type is 'element'. 12170 */ 12171 next = xmlXPathNextChildElement; 12172 } else 12173 next = xmlXPathNextChild; 12174 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12175 break; 12176 case AXIS_DESCENDANT: 12177 last = NULL; 12178 next = xmlXPathNextDescendant; 12179 break; 12180 case AXIS_DESCENDANT_OR_SELF: 12181 last = NULL; 12182 next = xmlXPathNextDescendantOrSelf; 12183 break; 12184 case AXIS_FOLLOWING: 12185 last = NULL; 12186 next = xmlXPathNextFollowing; 12187 break; 12188 case AXIS_FOLLOWING_SIBLING: 12189 last = NULL; 12190 next = xmlXPathNextFollowingSibling; 12191 break; 12192 case AXIS_NAMESPACE: 12193 first = NULL; 12194 last = NULL; 12195 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; 12196 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12197 break; 12198 case AXIS_PARENT: 12199 first = NULL; 12200 next = xmlXPathNextParent; 12201 break; 12202 case AXIS_PRECEDING: 12203 first = NULL; 12204 next = xmlXPathNextPrecedingInternal; 12205 break; 12206 case AXIS_PRECEDING_SIBLING: 12207 first = NULL; 12208 next = xmlXPathNextPrecedingSibling; 12209 break; 12210 case AXIS_SELF: 12211 first = NULL; 12212 last = NULL; 12213 next = xmlXPathNextSelf; 12214 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12215 break; 12216 } 12217 12218 #ifdef DEBUG_STEP 12219 xmlXPathDebugDumpStepAxis(op, 12220 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0); 12221 #endif 12222 12223 if (next == NULL) { 12224 xmlXPathReleaseObject(xpctxt, obj); 12225 return(0); 12226 } 12227 contextSeq = obj->nodesetval; 12228 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) { 12229 xmlXPathReleaseObject(xpctxt, obj); 12230 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL)); 12231 return(0); 12232 } 12233 /* 12234 * Predicate optimization --------------------------------------------- 12235 * If this step has a last predicate, which contains a position(), 12236 * then we'll optimize (although not exactly "position()", but only 12237 * the short-hand form, i.e., "[n]". 12238 * 12239 * Example - expression "/foo[parent::bar][1]": 12240 * 12241 * COLLECT 'child' 'name' 'node' foo -- op (we are here) 12242 * ROOT -- op->ch1 12243 * PREDICATE -- op->ch2 (predOp) 12244 * PREDICATE -- predOp->ch1 = [parent::bar] 12245 * SORT 12246 * COLLECT 'parent' 'name' 'node' bar 12247 * NODE 12248 * ELEM Object is a number : 1 -- predOp->ch2 = [1] 12249 * 12250 */ 12251 maxPos = 0; 12252 predOp = NULL; 12253 hasPredicateRange = 0; 12254 hasAxisRange = 0; 12255 if (op->ch2 != -1) { 12256 /* 12257 * There's at least one predicate. 16 == XPATH_OP_PREDICATE 12258 */ 12259 predOp = &ctxt->comp->steps[op->ch2]; 12260 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) { 12261 if (predOp->ch1 != -1) { 12262 /* 12263 * Use the next inner predicate operator. 12264 */ 12265 predOp = &ctxt->comp->steps[predOp->ch1]; 12266 hasPredicateRange = 1; 12267 } else { 12268 /* 12269 * There's no other predicate than the [n] predicate. 12270 */ 12271 predOp = NULL; 12272 hasAxisRange = 1; 12273 } 12274 } 12275 } 12276 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0; 12277 /* 12278 * Axis traversal ----------------------------------------------------- 12279 */ 12280 /* 12281 * 2.3 Node Tests 12282 * - For the attribute axis, the principal node type is attribute. 12283 * - For the namespace axis, the principal node type is namespace. 12284 * - For other axes, the principal node type is element. 12285 * 12286 * A node test * is true for any node of the 12287 * principal node type. For example, child::* will 12288 * select all element children of the context node 12289 */ 12290 oldContextNode = xpctxt->node; 12291 addNode = xmlXPathNodeSetAddUnique; 12292 outSeq = NULL; 12293 seq = NULL; 12294 contextNode = NULL; 12295 contextIdx = 0; 12296 12297 12298 while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) && 12299 (ctxt->error == XPATH_EXPRESSION_OK)) { 12300 xpctxt->node = contextSeq->nodeTab[contextIdx++]; 12301 12302 if (seq == NULL) { 12303 seq = xmlXPathNodeSetCreate(NULL); 12304 if (seq == NULL) { 12305 total = 0; 12306 goto error; 12307 } 12308 } 12309 /* 12310 * Traverse the axis and test the nodes. 12311 */ 12312 pos = 0; 12313 cur = NULL; 12314 hasNsNodes = 0; 12315 do { 12316 cur = next(ctxt, cur); 12317 if (cur == NULL) 12318 break; 12319 12320 /* 12321 * QUESTION TODO: What does the "first" and "last" stuff do? 12322 */ 12323 if ((first != NULL) && (*first != NULL)) { 12324 if (*first == cur) 12325 break; 12326 if (((total % 256) == 0) && 12327 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 12328 (xmlXPathCmpNodesExt(*first, cur) >= 0)) 12329 #else 12330 (xmlXPathCmpNodes(*first, cur) >= 0)) 12331 #endif 12332 { 12333 break; 12334 } 12335 } 12336 if ((last != NULL) && (*last != NULL)) { 12337 if (*last == cur) 12338 break; 12339 if (((total % 256) == 0) && 12340 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 12341 (xmlXPathCmpNodesExt(cur, *last) >= 0)) 12342 #else 12343 (xmlXPathCmpNodes(cur, *last) >= 0)) 12344 #endif 12345 { 12346 break; 12347 } 12348 } 12349 12350 total++; 12351 12352 #ifdef DEBUG_STEP 12353 xmlGenericError(xmlGenericErrorContext, " %s", cur->name); 12354 #endif 12355 12356 switch (test) { 12357 case NODE_TEST_NONE: 12358 total = 0; 12359 STRANGE 12360 goto error; 12361 case NODE_TEST_TYPE: 12362 if (type == NODE_TYPE_NODE) { 12363 switch (cur->type) { 12364 case XML_DOCUMENT_NODE: 12365 case XML_HTML_DOCUMENT_NODE: 12366 #ifdef LIBXML_DOCB_ENABLED 12367 case XML_DOCB_DOCUMENT_NODE: 12368 #endif 12369 case XML_ELEMENT_NODE: 12370 case XML_ATTRIBUTE_NODE: 12371 case XML_PI_NODE: 12372 case XML_COMMENT_NODE: 12373 case XML_CDATA_SECTION_NODE: 12374 case XML_TEXT_NODE: 12375 XP_TEST_HIT 12376 break; 12377 case XML_NAMESPACE_DECL: { 12378 if (axis == AXIS_NAMESPACE) { 12379 XP_TEST_HIT_NS 12380 } else { 12381 hasNsNodes = 1; 12382 XP_TEST_HIT 12383 } 12384 break; 12385 } 12386 default: 12387 break; 12388 } 12389 } else if (cur->type == (xmlElementType) type) { 12390 if (cur->type == XML_NAMESPACE_DECL) 12391 XP_TEST_HIT_NS 12392 else 12393 XP_TEST_HIT 12394 } else if ((type == NODE_TYPE_TEXT) && 12395 (cur->type == XML_CDATA_SECTION_NODE)) 12396 { 12397 XP_TEST_HIT 12398 } 12399 break; 12400 case NODE_TEST_PI: 12401 if ((cur->type == XML_PI_NODE) && 12402 ((name == NULL) || xmlStrEqual(name, cur->name))) 12403 { 12404 XP_TEST_HIT 12405 } 12406 break; 12407 case NODE_TEST_ALL: 12408 if (axis == AXIS_ATTRIBUTE) { 12409 if (cur->type == XML_ATTRIBUTE_NODE) 12410 { 12411 if (prefix == NULL) 12412 { 12413 XP_TEST_HIT 12414 } else if ((cur->ns != NULL) && 12415 (xmlStrEqual(URI, cur->ns->href))) 12416 { 12417 XP_TEST_HIT 12418 } 12419 } 12420 } else if (axis == AXIS_NAMESPACE) { 12421 if (cur->type == XML_NAMESPACE_DECL) 12422 { 12423 XP_TEST_HIT_NS 12424 } 12425 } else { 12426 if (cur->type == XML_ELEMENT_NODE) { 12427 if (prefix == NULL) 12428 { 12429 XP_TEST_HIT 12430 12431 } else if ((cur->ns != NULL) && 12432 (xmlStrEqual(URI, cur->ns->href))) 12433 { 12434 XP_TEST_HIT 12435 } 12436 } 12437 } 12438 break; 12439 case NODE_TEST_NS:{ 12440 TODO; 12441 break; 12442 } 12443 case NODE_TEST_NAME: 12444 if (axis == AXIS_ATTRIBUTE) { 12445 if (cur->type != XML_ATTRIBUTE_NODE) 12446 break; 12447 } else if (axis == AXIS_NAMESPACE) { 12448 if (cur->type != XML_NAMESPACE_DECL) 12449 break; 12450 } else { 12451 if (cur->type != XML_ELEMENT_NODE) 12452 break; 12453 } 12454 switch (cur->type) { 12455 case XML_ELEMENT_NODE: 12456 if (xmlStrEqual(name, cur->name)) { 12457 if (prefix == NULL) { 12458 if (cur->ns == NULL) 12459 { 12460 XP_TEST_HIT 12461 } 12462 } else { 12463 if ((cur->ns != NULL) && 12464 (xmlStrEqual(URI, cur->ns->href))) 12465 { 12466 XP_TEST_HIT 12467 } 12468 } 12469 } 12470 break; 12471 case XML_ATTRIBUTE_NODE:{ 12472 xmlAttrPtr attr = (xmlAttrPtr) cur; 12473 12474 if (xmlStrEqual(name, attr->name)) { 12475 if (prefix == NULL) { 12476 if ((attr->ns == NULL) || 12477 (attr->ns->prefix == NULL)) 12478 { 12479 XP_TEST_HIT 12480 } 12481 } else { 12482 if ((attr->ns != NULL) && 12483 (xmlStrEqual(URI, 12484 attr->ns->href))) 12485 { 12486 XP_TEST_HIT 12487 } 12488 } 12489 } 12490 break; 12491 } 12492 case XML_NAMESPACE_DECL: 12493 if (cur->type == XML_NAMESPACE_DECL) { 12494 xmlNsPtr ns = (xmlNsPtr) cur; 12495 12496 if ((ns->prefix != NULL) && (name != NULL) 12497 && (xmlStrEqual(ns->prefix, name))) 12498 { 12499 XP_TEST_HIT_NS 12500 } 12501 } 12502 break; 12503 default: 12504 break; 12505 } 12506 break; 12507 } /* switch(test) */ 12508 } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK)); 12509 12510 goto apply_predicates; 12511 12512 axis_range_end: /* ----------------------------------------------------- */ 12513 /* 12514 * We have a "/foo[n]", and position() = n was reached. 12515 * Note that we can have as well "/foo/::parent::foo[1]", so 12516 * a duplicate-aware merge is still needed. 12517 * Merge with the result. 12518 */ 12519 if (outSeq == NULL) { 12520 outSeq = seq; 12521 seq = NULL; 12522 } else 12523 outSeq = mergeAndClear(outSeq, seq, 0); 12524 /* 12525 * Break if only a true/false result was requested. 12526 */ 12527 if (toBool) 12528 break; 12529 continue; 12530 12531 first_hit: /* ---------------------------------------------------------- */ 12532 /* 12533 * Break if only a true/false result was requested and 12534 * no predicates existed and a node test succeeded. 12535 */ 12536 if (outSeq == NULL) { 12537 outSeq = seq; 12538 seq = NULL; 12539 } else 12540 outSeq = mergeAndClear(outSeq, seq, 0); 12541 break; 12542 12543 #ifdef DEBUG_STEP 12544 if (seq != NULL) 12545 nbMatches += seq->nodeNr; 12546 #endif 12547 12548 apply_predicates: /* --------------------------------------------------- */ 12549 if (ctxt->error != XPATH_EXPRESSION_OK) 12550 goto error; 12551 12552 /* 12553 * Apply predicates. 12554 */ 12555 if ((predOp != NULL) && (seq->nodeNr > 0)) { 12556 /* 12557 * E.g. when we have a "/foo[some expression][n]". 12558 */ 12559 /* 12560 * QUESTION TODO: The old predicate evaluation took into 12561 * account location-sets. 12562 * (E.g. ctxt->value->type == XPATH_LOCATIONSET) 12563 * Do we expect such a set here? 12564 * All what I learned now from the evaluation semantics 12565 * does not indicate that a location-set will be processed 12566 * here, so this looks OK. 12567 */ 12568 /* 12569 * Iterate over all predicates, starting with the outermost 12570 * predicate. 12571 * TODO: Problem: we cannot execute the inner predicates first 12572 * since we cannot go back *up* the operator tree! 12573 * Options we have: 12574 * 1) Use of recursive functions (like is it currently done 12575 * via xmlXPathCompOpEval()) 12576 * 2) Add a predicate evaluation information stack to the 12577 * context struct 12578 * 3) Change the way the operators are linked; we need a 12579 * "parent" field on xmlXPathStepOp 12580 * 12581 * For the moment, I'll try to solve this with a recursive 12582 * function: xmlXPathCompOpEvalPredicate(). 12583 */ 12584 size = seq->nodeNr; 12585 if (hasPredicateRange != 0) 12586 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt, 12587 predOp, seq, size, maxPos, maxPos, hasNsNodes); 12588 else 12589 newSize = xmlXPathCompOpEvalPredicate(ctxt, 12590 predOp, seq, size, hasNsNodes); 12591 12592 if (ctxt->error != XPATH_EXPRESSION_OK) { 12593 total = 0; 12594 goto error; 12595 } 12596 /* 12597 * Add the filtered set of nodes to the result node set. 12598 */ 12599 if (newSize == 0) { 12600 /* 12601 * The predicates filtered all nodes out. 12602 */ 12603 xmlXPathNodeSetClear(seq, hasNsNodes); 12604 } else if (seq->nodeNr > 0) { 12605 /* 12606 * Add to result set. 12607 */ 12608 if (outSeq == NULL) { 12609 if (size != newSize) { 12610 /* 12611 * We need to merge and clear here, since 12612 * the sequence will contained NULLed entries. 12613 */ 12614 outSeq = mergeAndClear(NULL, seq, 1); 12615 } else { 12616 outSeq = seq; 12617 seq = NULL; 12618 } 12619 } else 12620 outSeq = mergeAndClear(outSeq, seq, 12621 (size != newSize) ? 1: 0); 12622 /* 12623 * Break if only a true/false result was requested. 12624 */ 12625 if (toBool) 12626 break; 12627 } 12628 } else if (seq->nodeNr > 0) { 12629 /* 12630 * Add to result set. 12631 */ 12632 if (outSeq == NULL) { 12633 outSeq = seq; 12634 seq = NULL; 12635 } else { 12636 outSeq = mergeAndClear(outSeq, seq, 0); 12637 } 12638 } 12639 } 12640 12641 error: 12642 if ((obj->boolval) && (obj->user != NULL)) { 12643 /* 12644 * QUESTION TODO: What does this do and why? 12645 * TODO: Do we have to do this also for the "error" 12646 * cleanup further down? 12647 */ 12648 ctxt->value->boolval = 1; 12649 ctxt->value->user = obj->user; 12650 obj->user = NULL; 12651 obj->boolval = 0; 12652 } 12653 xmlXPathReleaseObject(xpctxt, obj); 12654 12655 /* 12656 * Ensure we return at least an emtpy set. 12657 */ 12658 if (outSeq == NULL) { 12659 if ((seq != NULL) && (seq->nodeNr == 0)) 12660 outSeq = seq; 12661 else 12662 outSeq = xmlXPathNodeSetCreate(NULL); 12663 /* XXX what if xmlXPathNodeSetCreate returned NULL here? */ 12664 } 12665 if ((seq != NULL) && (seq != outSeq)) { 12666 xmlXPathFreeNodeSet(seq); 12667 } 12668 /* 12669 * Hand over the result. Better to push the set also in 12670 * case of errors. 12671 */ 12672 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq)); 12673 /* 12674 * Reset the context node. 12675 */ 12676 xpctxt->node = oldContextNode; 12677 /* 12678 * When traversing the namespace axis in "toBool" mode, it's 12679 * possible that tmpNsList wasn't freed. 12680 */ 12681 if (xpctxt->tmpNsList != NULL) { 12682 xmlFree(xpctxt->tmpNsList); 12683 xpctxt->tmpNsList = NULL; 12684 } 12685 12686 #ifdef DEBUG_STEP 12687 xmlGenericError(xmlGenericErrorContext, 12688 "\nExamined %d nodes, found %d nodes at that step\n", 12689 total, nbMatches); 12690 #endif 12691 12692 return(total); 12693 } 12694 12695 static int 12696 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt, 12697 xmlXPathStepOpPtr op, xmlNodePtr * first); 12698 12699 /** 12700 * xmlXPathCompOpEvalFirst: 12701 * @ctxt: the XPath parser context with the compiled expression 12702 * @op: an XPath compiled operation 12703 * @first: the first elem found so far 12704 * 12705 * Evaluate the Precompiled XPath operation searching only the first 12706 * element in document order 12707 * 12708 * Returns the number of examined objects. 12709 */ 12710 static int 12711 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt, 12712 xmlXPathStepOpPtr op, xmlNodePtr * first) 12713 { 12714 int total = 0, cur; 12715 xmlXPathCompExprPtr comp; 12716 xmlXPathObjectPtr arg1, arg2; 12717 12718 CHECK_ERROR0; 12719 comp = ctxt->comp; 12720 switch (op->op) { 12721 case XPATH_OP_END: 12722 return (0); 12723 case XPATH_OP_UNION: 12724 total = 12725 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1], 12726 first); 12727 CHECK_ERROR0; 12728 if ((ctxt->value != NULL) 12729 && (ctxt->value->type == XPATH_NODESET) 12730 && (ctxt->value->nodesetval != NULL) 12731 && (ctxt->value->nodesetval->nodeNr >= 1)) { 12732 /* 12733 * limit tree traversing to first node in the result 12734 */ 12735 /* 12736 * OPTIMIZE TODO: This implicitely sorts 12737 * the result, even if not needed. E.g. if the argument 12738 * of the count() function, no sorting is needed. 12739 * OPTIMIZE TODO: How do we know if the node-list wasn't 12740 * aready sorted? 12741 */ 12742 if (ctxt->value->nodesetval->nodeNr > 1) 12743 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12744 *first = ctxt->value->nodesetval->nodeTab[0]; 12745 } 12746 cur = 12747 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2], 12748 first); 12749 CHECK_ERROR0; 12750 12751 arg2 = valuePop(ctxt); 12752 arg1 = valuePop(ctxt); 12753 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) || 12754 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) { 12755 xmlXPathReleaseObject(ctxt->context, arg1); 12756 xmlXPathReleaseObject(ctxt->context, arg2); 12757 XP_ERROR0(XPATH_INVALID_TYPE); 12758 } 12759 12760 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 12761 arg2->nodesetval); 12762 valuePush(ctxt, arg1); 12763 xmlXPathReleaseObject(ctxt->context, arg2); 12764 /* optimizer */ 12765 if (total > cur) 12766 xmlXPathCompSwap(op); 12767 return (total + cur); 12768 case XPATH_OP_ROOT: 12769 xmlXPathRoot(ctxt); 12770 return (0); 12771 case XPATH_OP_NODE: 12772 if (op->ch1 != -1) 12773 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12774 CHECK_ERROR0; 12775 if (op->ch2 != -1) 12776 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12777 CHECK_ERROR0; 12778 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 12779 ctxt->context->node)); 12780 return (total); 12781 case XPATH_OP_RESET: 12782 if (op->ch1 != -1) 12783 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12784 CHECK_ERROR0; 12785 if (op->ch2 != -1) 12786 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12787 CHECK_ERROR0; 12788 ctxt->context->node = NULL; 12789 return (total); 12790 case XPATH_OP_COLLECT:{ 12791 if (op->ch1 == -1) 12792 return (total); 12793 12794 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12795 CHECK_ERROR0; 12796 12797 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0); 12798 return (total); 12799 } 12800 case XPATH_OP_VALUE: 12801 valuePush(ctxt, 12802 xmlXPathCacheObjectCopy(ctxt->context, 12803 (xmlXPathObjectPtr) op->value4)); 12804 return (0); 12805 case XPATH_OP_SORT: 12806 if (op->ch1 != -1) 12807 total += 12808 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1], 12809 first); 12810 CHECK_ERROR0; 12811 if ((ctxt->value != NULL) 12812 && (ctxt->value->type == XPATH_NODESET) 12813 && (ctxt->value->nodesetval != NULL) 12814 && (ctxt->value->nodesetval->nodeNr > 1)) 12815 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12816 return (total); 12817 #ifdef XP_OPTIMIZED_FILTER_FIRST 12818 case XPATH_OP_FILTER: 12819 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first); 12820 return (total); 12821 #endif 12822 default: 12823 return (xmlXPathCompOpEval(ctxt, op)); 12824 } 12825 } 12826 12827 /** 12828 * xmlXPathCompOpEvalLast: 12829 * @ctxt: the XPath parser context with the compiled expression 12830 * @op: an XPath compiled operation 12831 * @last: the last elem found so far 12832 * 12833 * Evaluate the Precompiled XPath operation searching only the last 12834 * element in document order 12835 * 12836 * Returns the number of nodes traversed 12837 */ 12838 static int 12839 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op, 12840 xmlNodePtr * last) 12841 { 12842 int total = 0, cur; 12843 xmlXPathCompExprPtr comp; 12844 xmlXPathObjectPtr arg1, arg2; 12845 xmlNodePtr bak; 12846 xmlDocPtr bakd; 12847 int pp; 12848 int cs; 12849 12850 CHECK_ERROR0; 12851 comp = ctxt->comp; 12852 switch (op->op) { 12853 case XPATH_OP_END: 12854 return (0); 12855 case XPATH_OP_UNION: 12856 bakd = ctxt->context->doc; 12857 bak = ctxt->context->node; 12858 pp = ctxt->context->proximityPosition; 12859 cs = ctxt->context->contextSize; 12860 total = 12861 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last); 12862 CHECK_ERROR0; 12863 if ((ctxt->value != NULL) 12864 && (ctxt->value->type == XPATH_NODESET) 12865 && (ctxt->value->nodesetval != NULL) 12866 && (ctxt->value->nodesetval->nodeNr >= 1)) { 12867 /* 12868 * limit tree traversing to first node in the result 12869 */ 12870 if (ctxt->value->nodesetval->nodeNr > 1) 12871 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12872 *last = 12873 ctxt->value->nodesetval->nodeTab[ctxt->value-> 12874 nodesetval->nodeNr - 12875 1]; 12876 } 12877 ctxt->context->doc = bakd; 12878 ctxt->context->node = bak; 12879 ctxt->context->proximityPosition = pp; 12880 ctxt->context->contextSize = cs; 12881 cur = 12882 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last); 12883 CHECK_ERROR0; 12884 if ((ctxt->value != NULL) 12885 && (ctxt->value->type == XPATH_NODESET) 12886 && (ctxt->value->nodesetval != NULL) 12887 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */ 12888 } 12889 12890 arg2 = valuePop(ctxt); 12891 arg1 = valuePop(ctxt); 12892 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) || 12893 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) { 12894 xmlXPathReleaseObject(ctxt->context, arg1); 12895 xmlXPathReleaseObject(ctxt->context, arg2); 12896 XP_ERROR0(XPATH_INVALID_TYPE); 12897 } 12898 12899 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 12900 arg2->nodesetval); 12901 valuePush(ctxt, arg1); 12902 xmlXPathReleaseObject(ctxt->context, arg2); 12903 /* optimizer */ 12904 if (total > cur) 12905 xmlXPathCompSwap(op); 12906 return (total + cur); 12907 case XPATH_OP_ROOT: 12908 xmlXPathRoot(ctxt); 12909 return (0); 12910 case XPATH_OP_NODE: 12911 if (op->ch1 != -1) 12912 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12913 CHECK_ERROR0; 12914 if (op->ch2 != -1) 12915 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12916 CHECK_ERROR0; 12917 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 12918 ctxt->context->node)); 12919 return (total); 12920 case XPATH_OP_RESET: 12921 if (op->ch1 != -1) 12922 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12923 CHECK_ERROR0; 12924 if (op->ch2 != -1) 12925 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12926 CHECK_ERROR0; 12927 ctxt->context->node = NULL; 12928 return (total); 12929 case XPATH_OP_COLLECT:{ 12930 if (op->ch1 == -1) 12931 return (0); 12932 12933 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12934 CHECK_ERROR0; 12935 12936 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0); 12937 return (total); 12938 } 12939 case XPATH_OP_VALUE: 12940 valuePush(ctxt, 12941 xmlXPathCacheObjectCopy(ctxt->context, 12942 (xmlXPathObjectPtr) op->value4)); 12943 return (0); 12944 case XPATH_OP_SORT: 12945 if (op->ch1 != -1) 12946 total += 12947 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], 12948 last); 12949 CHECK_ERROR0; 12950 if ((ctxt->value != NULL) 12951 && (ctxt->value->type == XPATH_NODESET) 12952 && (ctxt->value->nodesetval != NULL) 12953 && (ctxt->value->nodesetval->nodeNr > 1)) 12954 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12955 return (total); 12956 default: 12957 return (xmlXPathCompOpEval(ctxt, op)); 12958 } 12959 } 12960 12961 #ifdef XP_OPTIMIZED_FILTER_FIRST 12962 static int 12963 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt, 12964 xmlXPathStepOpPtr op, xmlNodePtr * first) 12965 { 12966 int total = 0; 12967 xmlXPathCompExprPtr comp; 12968 xmlXPathObjectPtr res; 12969 xmlXPathObjectPtr obj; 12970 xmlNodeSetPtr oldset; 12971 xmlNodePtr oldnode; 12972 xmlDocPtr oldDoc; 12973 int i; 12974 12975 CHECK_ERROR0; 12976 comp = ctxt->comp; 12977 /* 12978 * Optimization for ()[last()] selection i.e. the last elem 12979 */ 12980 if ((op->ch1 != -1) && (op->ch2 != -1) && 12981 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 12982 (comp->steps[op->ch2].op == XPATH_OP_SORT)) { 12983 int f = comp->steps[op->ch2].ch1; 12984 12985 if ((f != -1) && 12986 (comp->steps[f].op == XPATH_OP_FUNCTION) && 12987 (comp->steps[f].value5 == NULL) && 12988 (comp->steps[f].value == 0) && 12989 (comp->steps[f].value4 != NULL) && 12990 (xmlStrEqual 12991 (comp->steps[f].value4, BAD_CAST "last"))) { 12992 xmlNodePtr last = NULL; 12993 12994 total += 12995 xmlXPathCompOpEvalLast(ctxt, 12996 &comp->steps[op->ch1], 12997 &last); 12998 CHECK_ERROR0; 12999 /* 13000 * The nodeset should be in document order, 13001 * Keep only the last value 13002 */ 13003 if ((ctxt->value != NULL) && 13004 (ctxt->value->type == XPATH_NODESET) && 13005 (ctxt->value->nodesetval != NULL) && 13006 (ctxt->value->nodesetval->nodeTab != NULL) && 13007 (ctxt->value->nodesetval->nodeNr > 1)) { 13008 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval); 13009 *first = *(ctxt->value->nodesetval->nodeTab); 13010 } 13011 return (total); 13012 } 13013 } 13014 13015 if (op->ch1 != -1) 13016 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13017 CHECK_ERROR0; 13018 if (op->ch2 == -1) 13019 return (total); 13020 if (ctxt->value == NULL) 13021 return (total); 13022 13023 #ifdef LIBXML_XPTR_ENABLED 13024 oldnode = ctxt->context->node; 13025 /* 13026 * Hum are we filtering the result of an XPointer expression 13027 */ 13028 if (ctxt->value->type == XPATH_LOCATIONSET) { 13029 xmlXPathObjectPtr tmp = NULL; 13030 xmlLocationSetPtr newlocset = NULL; 13031 xmlLocationSetPtr oldlocset; 13032 13033 /* 13034 * Extract the old locset, and then evaluate the result of the 13035 * expression for all the element in the locset. use it to grow 13036 * up a new locset. 13037 */ 13038 CHECK_TYPE0(XPATH_LOCATIONSET); 13039 obj = valuePop(ctxt); 13040 oldlocset = obj->user; 13041 ctxt->context->node = NULL; 13042 13043 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) { 13044 ctxt->context->contextSize = 0; 13045 ctxt->context->proximityPosition = 0; 13046 if (op->ch2 != -1) 13047 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13048 res = valuePop(ctxt); 13049 if (res != NULL) { 13050 xmlXPathReleaseObject(ctxt->context, res); 13051 } 13052 valuePush(ctxt, obj); 13053 CHECK_ERROR0; 13054 return (total); 13055 } 13056 newlocset = xmlXPtrLocationSetCreate(NULL); 13057 13058 for (i = 0; i < oldlocset->locNr; i++) { 13059 /* 13060 * Run the evaluation with a node list made of a 13061 * single item in the nodelocset. 13062 */ 13063 ctxt->context->node = oldlocset->locTab[i]->user; 13064 ctxt->context->contextSize = oldlocset->locNr; 13065 ctxt->context->proximityPosition = i + 1; 13066 if (tmp == NULL) { 13067 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13068 ctxt->context->node); 13069 } else { 13070 if (xmlXPathNodeSetAddUnique(tmp->nodesetval, 13071 ctxt->context->node) < 0) { 13072 ctxt->error = XPATH_MEMORY_ERROR; 13073 } 13074 } 13075 valuePush(ctxt, tmp); 13076 if (op->ch2 != -1) 13077 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13078 if (ctxt->error != XPATH_EXPRESSION_OK) { 13079 xmlXPathFreeObject(obj); 13080 return(0); 13081 } 13082 /* 13083 * The result of the evaluation need to be tested to 13084 * decided whether the filter succeeded or not 13085 */ 13086 res = valuePop(ctxt); 13087 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 13088 xmlXPtrLocationSetAdd(newlocset, 13089 xmlXPathCacheObjectCopy(ctxt->context, 13090 oldlocset->locTab[i])); 13091 } 13092 /* 13093 * Cleanup 13094 */ 13095 if (res != NULL) { 13096 xmlXPathReleaseObject(ctxt->context, res); 13097 } 13098 if (ctxt->value == tmp) { 13099 valuePop(ctxt); 13100 xmlXPathNodeSetClear(tmp->nodesetval, 1); 13101 /* 13102 * REVISIT TODO: Don't create a temporary nodeset 13103 * for everly iteration. 13104 */ 13105 /* OLD: xmlXPathFreeObject(res); */ 13106 } else 13107 tmp = NULL; 13108 ctxt->context->node = NULL; 13109 /* 13110 * Only put the first node in the result, then leave. 13111 */ 13112 if (newlocset->locNr > 0) { 13113 *first = (xmlNodePtr) oldlocset->locTab[i]->user; 13114 break; 13115 } 13116 } 13117 if (tmp != NULL) { 13118 xmlXPathReleaseObject(ctxt->context, tmp); 13119 } 13120 /* 13121 * The result is used as the new evaluation locset. 13122 */ 13123 xmlXPathReleaseObject(ctxt->context, obj); 13124 ctxt->context->node = NULL; 13125 ctxt->context->contextSize = -1; 13126 ctxt->context->proximityPosition = -1; 13127 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset)); 13128 ctxt->context->node = oldnode; 13129 return (total); 13130 } 13131 #endif /* LIBXML_XPTR_ENABLED */ 13132 13133 /* 13134 * Extract the old set, and then evaluate the result of the 13135 * expression for all the element in the set. use it to grow 13136 * up a new set. 13137 */ 13138 CHECK_TYPE0(XPATH_NODESET); 13139 obj = valuePop(ctxt); 13140 oldset = obj->nodesetval; 13141 13142 oldnode = ctxt->context->node; 13143 oldDoc = ctxt->context->doc; 13144 ctxt->context->node = NULL; 13145 13146 if ((oldset == NULL) || (oldset->nodeNr == 0)) { 13147 ctxt->context->contextSize = 0; 13148 ctxt->context->proximityPosition = 0; 13149 /* QUESTION TODO: Why was this code commented out? 13150 if (op->ch2 != -1) 13151 total += 13152 xmlXPathCompOpEval(ctxt, 13153 &comp->steps[op->ch2]); 13154 CHECK_ERROR0; 13155 res = valuePop(ctxt); 13156 if (res != NULL) 13157 xmlXPathFreeObject(res); 13158 */ 13159 valuePush(ctxt, obj); 13160 ctxt->context->node = oldnode; 13161 CHECK_ERROR0; 13162 } else { 13163 xmlNodeSetPtr newset; 13164 xmlXPathObjectPtr tmp = NULL; 13165 /* 13166 * Initialize the new set. 13167 * Also set the xpath document in case things like 13168 * key() evaluation are attempted on the predicate 13169 */ 13170 newset = xmlXPathNodeSetCreate(NULL); 13171 /* XXX what if xmlXPathNodeSetCreate returned NULL? */ 13172 13173 for (i = 0; i < oldset->nodeNr; i++) { 13174 /* 13175 * Run the evaluation with a node list made of 13176 * a single item in the nodeset. 13177 */ 13178 ctxt->context->node = oldset->nodeTab[i]; 13179 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) && 13180 (oldset->nodeTab[i]->doc != NULL)) 13181 ctxt->context->doc = oldset->nodeTab[i]->doc; 13182 if (tmp == NULL) { 13183 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13184 ctxt->context->node); 13185 } else { 13186 if (xmlXPathNodeSetAddUnique(tmp->nodesetval, 13187 ctxt->context->node) < 0) { 13188 ctxt->error = XPATH_MEMORY_ERROR; 13189 } 13190 } 13191 valuePush(ctxt, tmp); 13192 ctxt->context->contextSize = oldset->nodeNr; 13193 ctxt->context->proximityPosition = i + 1; 13194 if (op->ch2 != -1) 13195 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13196 if (ctxt->error != XPATH_EXPRESSION_OK) { 13197 xmlXPathFreeNodeSet(newset); 13198 xmlXPathFreeObject(obj); 13199 return(0); 13200 } 13201 /* 13202 * The result of the evaluation needs to be tested to 13203 * decide whether the filter succeeded or not 13204 */ 13205 res = valuePop(ctxt); 13206 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 13207 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0) 13208 ctxt->error = XPATH_MEMORY_ERROR; 13209 } 13210 /* 13211 * Cleanup 13212 */ 13213 if (res != NULL) { 13214 xmlXPathReleaseObject(ctxt->context, res); 13215 } 13216 if (ctxt->value == tmp) { 13217 valuePop(ctxt); 13218 /* 13219 * Don't free the temporary nodeset 13220 * in order to avoid massive recreation inside this 13221 * loop. 13222 */ 13223 xmlXPathNodeSetClear(tmp->nodesetval, 1); 13224 } else 13225 tmp = NULL; 13226 ctxt->context->node = NULL; 13227 /* 13228 * Only put the first node in the result, then leave. 13229 */ 13230 if (newset->nodeNr > 0) { 13231 *first = *(newset->nodeTab); 13232 break; 13233 } 13234 } 13235 if (tmp != NULL) { 13236 xmlXPathReleaseObject(ctxt->context, tmp); 13237 } 13238 /* 13239 * The result is used as the new evaluation set. 13240 */ 13241 xmlXPathReleaseObject(ctxt->context, obj); 13242 ctxt->context->node = NULL; 13243 ctxt->context->contextSize = -1; 13244 ctxt->context->proximityPosition = -1; 13245 /* may want to move this past the '}' later */ 13246 ctxt->context->doc = oldDoc; 13247 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset)); 13248 } 13249 ctxt->context->node = oldnode; 13250 return(total); 13251 } 13252 #endif /* XP_OPTIMIZED_FILTER_FIRST */ 13253 13254 /** 13255 * xmlXPathCompOpEval: 13256 * @ctxt: the XPath parser context with the compiled expression 13257 * @op: an XPath compiled operation 13258 * 13259 * Evaluate the Precompiled XPath operation 13260 * Returns the number of nodes traversed 13261 */ 13262 static int 13263 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) 13264 { 13265 int total = 0; 13266 int equal, ret; 13267 xmlXPathCompExprPtr comp; 13268 xmlXPathObjectPtr arg1, arg2; 13269 xmlNodePtr bak; 13270 xmlDocPtr bakd; 13271 int pp; 13272 int cs; 13273 13274 CHECK_ERROR0; 13275 comp = ctxt->comp; 13276 switch (op->op) { 13277 case XPATH_OP_END: 13278 return (0); 13279 case XPATH_OP_AND: 13280 bakd = ctxt->context->doc; 13281 bak = ctxt->context->node; 13282 pp = ctxt->context->proximityPosition; 13283 cs = ctxt->context->contextSize; 13284 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13285 CHECK_ERROR0; 13286 xmlXPathBooleanFunction(ctxt, 1); 13287 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0)) 13288 return (total); 13289 arg2 = valuePop(ctxt); 13290 ctxt->context->doc = bakd; 13291 ctxt->context->node = bak; 13292 ctxt->context->proximityPosition = pp; 13293 ctxt->context->contextSize = cs; 13294 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13295 if (ctxt->error) { 13296 xmlXPathFreeObject(arg2); 13297 return(0); 13298 } 13299 xmlXPathBooleanFunction(ctxt, 1); 13300 arg1 = valuePop(ctxt); 13301 arg1->boolval &= arg2->boolval; 13302 valuePush(ctxt, arg1); 13303 xmlXPathReleaseObject(ctxt->context, arg2); 13304 return (total); 13305 case XPATH_OP_OR: 13306 bakd = ctxt->context->doc; 13307 bak = ctxt->context->node; 13308 pp = ctxt->context->proximityPosition; 13309 cs = ctxt->context->contextSize; 13310 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13311 CHECK_ERROR0; 13312 xmlXPathBooleanFunction(ctxt, 1); 13313 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1)) 13314 return (total); 13315 arg2 = valuePop(ctxt); 13316 ctxt->context->doc = bakd; 13317 ctxt->context->node = bak; 13318 ctxt->context->proximityPosition = pp; 13319 ctxt->context->contextSize = cs; 13320 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13321 if (ctxt->error) { 13322 xmlXPathFreeObject(arg2); 13323 return(0); 13324 } 13325 xmlXPathBooleanFunction(ctxt, 1); 13326 arg1 = valuePop(ctxt); 13327 arg1->boolval |= arg2->boolval; 13328 valuePush(ctxt, arg1); 13329 xmlXPathReleaseObject(ctxt->context, arg2); 13330 return (total); 13331 case XPATH_OP_EQUAL: 13332 bakd = ctxt->context->doc; 13333 bak = ctxt->context->node; 13334 pp = ctxt->context->proximityPosition; 13335 cs = ctxt->context->contextSize; 13336 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13337 CHECK_ERROR0; 13338 ctxt->context->doc = bakd; 13339 ctxt->context->node = bak; 13340 ctxt->context->proximityPosition = pp; 13341 ctxt->context->contextSize = cs; 13342 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13343 CHECK_ERROR0; 13344 if (op->value) 13345 equal = xmlXPathEqualValues(ctxt); 13346 else 13347 equal = xmlXPathNotEqualValues(ctxt); 13348 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal)); 13349 return (total); 13350 case XPATH_OP_CMP: 13351 bakd = ctxt->context->doc; 13352 bak = ctxt->context->node; 13353 pp = ctxt->context->proximityPosition; 13354 cs = ctxt->context->contextSize; 13355 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13356 CHECK_ERROR0; 13357 ctxt->context->doc = bakd; 13358 ctxt->context->node = bak; 13359 ctxt->context->proximityPosition = pp; 13360 ctxt->context->contextSize = cs; 13361 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13362 CHECK_ERROR0; 13363 ret = xmlXPathCompareValues(ctxt, op->value, op->value2); 13364 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret)); 13365 return (total); 13366 case XPATH_OP_PLUS: 13367 bakd = ctxt->context->doc; 13368 bak = ctxt->context->node; 13369 pp = ctxt->context->proximityPosition; 13370 cs = ctxt->context->contextSize; 13371 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13372 CHECK_ERROR0; 13373 if (op->ch2 != -1) { 13374 ctxt->context->doc = bakd; 13375 ctxt->context->node = bak; 13376 ctxt->context->proximityPosition = pp; 13377 ctxt->context->contextSize = cs; 13378 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13379 } 13380 CHECK_ERROR0; 13381 if (op->value == 0) 13382 xmlXPathSubValues(ctxt); 13383 else if (op->value == 1) 13384 xmlXPathAddValues(ctxt); 13385 else if (op->value == 2) 13386 xmlXPathValueFlipSign(ctxt); 13387 else if (op->value == 3) { 13388 CAST_TO_NUMBER; 13389 CHECK_TYPE0(XPATH_NUMBER); 13390 } 13391 return (total); 13392 case XPATH_OP_MULT: 13393 bakd = ctxt->context->doc; 13394 bak = ctxt->context->node; 13395 pp = ctxt->context->proximityPosition; 13396 cs = ctxt->context->contextSize; 13397 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13398 CHECK_ERROR0; 13399 ctxt->context->doc = bakd; 13400 ctxt->context->node = bak; 13401 ctxt->context->proximityPosition = pp; 13402 ctxt->context->contextSize = cs; 13403 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13404 CHECK_ERROR0; 13405 if (op->value == 0) 13406 xmlXPathMultValues(ctxt); 13407 else if (op->value == 1) 13408 xmlXPathDivValues(ctxt); 13409 else if (op->value == 2) 13410 xmlXPathModValues(ctxt); 13411 return (total); 13412 case XPATH_OP_UNION: 13413 bakd = ctxt->context->doc; 13414 bak = ctxt->context->node; 13415 pp = ctxt->context->proximityPosition; 13416 cs = ctxt->context->contextSize; 13417 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13418 CHECK_ERROR0; 13419 ctxt->context->doc = bakd; 13420 ctxt->context->node = bak; 13421 ctxt->context->proximityPosition = pp; 13422 ctxt->context->contextSize = cs; 13423 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13424 CHECK_ERROR0; 13425 13426 arg2 = valuePop(ctxt); 13427 arg1 = valuePop(ctxt); 13428 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) || 13429 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) { 13430 xmlXPathReleaseObject(ctxt->context, arg1); 13431 xmlXPathReleaseObject(ctxt->context, arg2); 13432 XP_ERROR0(XPATH_INVALID_TYPE); 13433 } 13434 13435 if ((arg1->nodesetval == NULL) || 13436 ((arg2->nodesetval != NULL) && 13437 (arg2->nodesetval->nodeNr != 0))) 13438 { 13439 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 13440 arg2->nodesetval); 13441 } 13442 13443 valuePush(ctxt, arg1); 13444 xmlXPathReleaseObject(ctxt->context, arg2); 13445 return (total); 13446 case XPATH_OP_ROOT: 13447 xmlXPathRoot(ctxt); 13448 return (total); 13449 case XPATH_OP_NODE: 13450 if (op->ch1 != -1) 13451 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13452 CHECK_ERROR0; 13453 if (op->ch2 != -1) 13454 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13455 CHECK_ERROR0; 13456 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 13457 ctxt->context->node)); 13458 return (total); 13459 case XPATH_OP_RESET: 13460 if (op->ch1 != -1) 13461 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13462 CHECK_ERROR0; 13463 if (op->ch2 != -1) 13464 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13465 CHECK_ERROR0; 13466 ctxt->context->node = NULL; 13467 return (total); 13468 case XPATH_OP_COLLECT:{ 13469 if (op->ch1 == -1) 13470 return (total); 13471 13472 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13473 CHECK_ERROR0; 13474 13475 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0); 13476 return (total); 13477 } 13478 case XPATH_OP_VALUE: 13479 valuePush(ctxt, 13480 xmlXPathCacheObjectCopy(ctxt->context, 13481 (xmlXPathObjectPtr) op->value4)); 13482 return (total); 13483 case XPATH_OP_VARIABLE:{ 13484 xmlXPathObjectPtr val; 13485 13486 if (op->ch1 != -1) 13487 total += 13488 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13489 if (op->value5 == NULL) { 13490 val = xmlXPathVariableLookup(ctxt->context, op->value4); 13491 if (val == NULL) 13492 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR); 13493 valuePush(ctxt, val); 13494 } else { 13495 const xmlChar *URI; 13496 13497 URI = xmlXPathNsLookup(ctxt->context, op->value5); 13498 if (URI == NULL) { 13499 xmlGenericError(xmlGenericErrorContext, 13500 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n", 13501 (char *) op->value4, (char *)op->value5); 13502 ctxt->error = XPATH_UNDEF_PREFIX_ERROR; 13503 return (total); 13504 } 13505 val = xmlXPathVariableLookupNS(ctxt->context, 13506 op->value4, URI); 13507 if (val == NULL) 13508 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR); 13509 valuePush(ctxt, val); 13510 } 13511 return (total); 13512 } 13513 case XPATH_OP_FUNCTION:{ 13514 xmlXPathFunction func; 13515 const xmlChar *oldFunc, *oldFuncURI; 13516 int i; 13517 int frame; 13518 13519 frame = xmlXPathSetFrame(ctxt); 13520 if (op->ch1 != -1) { 13521 total += 13522 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13523 if (ctxt->error != XPATH_EXPRESSION_OK) { 13524 xmlXPathPopFrame(ctxt, frame); 13525 return (total); 13526 } 13527 } 13528 if (ctxt->valueNr < ctxt->valueFrame + op->value) { 13529 xmlGenericError(xmlGenericErrorContext, 13530 "xmlXPathCompOpEval: parameter error\n"); 13531 ctxt->error = XPATH_INVALID_OPERAND; 13532 xmlXPathPopFrame(ctxt, frame); 13533 return (total); 13534 } 13535 for (i = 0; i < op->value; i++) { 13536 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) { 13537 xmlGenericError(xmlGenericErrorContext, 13538 "xmlXPathCompOpEval: parameter error\n"); 13539 ctxt->error = XPATH_INVALID_OPERAND; 13540 xmlXPathPopFrame(ctxt, frame); 13541 return (total); 13542 } 13543 } 13544 if (op->cache != NULL) 13545 func = op->cache; 13546 else { 13547 const xmlChar *URI = NULL; 13548 13549 if (op->value5 == NULL) 13550 func = 13551 xmlXPathFunctionLookup(ctxt->context, 13552 op->value4); 13553 else { 13554 URI = xmlXPathNsLookup(ctxt->context, op->value5); 13555 if (URI == NULL) { 13556 xmlGenericError(xmlGenericErrorContext, 13557 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n", 13558 (char *)op->value4, (char *)op->value5); 13559 xmlXPathPopFrame(ctxt, frame); 13560 ctxt->error = XPATH_UNDEF_PREFIX_ERROR; 13561 return (total); 13562 } 13563 func = xmlXPathFunctionLookupNS(ctxt->context, 13564 op->value4, URI); 13565 } 13566 if (func == NULL) { 13567 xmlGenericError(xmlGenericErrorContext, 13568 "xmlXPathCompOpEval: function %s not found\n", 13569 (char *)op->value4); 13570 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR); 13571 } 13572 op->cache = func; 13573 op->cacheURI = (void *) URI; 13574 } 13575 oldFunc = ctxt->context->function; 13576 oldFuncURI = ctxt->context->functionURI; 13577 ctxt->context->function = op->value4; 13578 ctxt->context->functionURI = op->cacheURI; 13579 func(ctxt, op->value); 13580 ctxt->context->function = oldFunc; 13581 ctxt->context->functionURI = oldFuncURI; 13582 xmlXPathPopFrame(ctxt, frame); 13583 return (total); 13584 } 13585 case XPATH_OP_ARG: 13586 bakd = ctxt->context->doc; 13587 bak = ctxt->context->node; 13588 pp = ctxt->context->proximityPosition; 13589 cs = ctxt->context->contextSize; 13590 if (op->ch1 != -1) { 13591 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13592 ctxt->context->contextSize = cs; 13593 ctxt->context->proximityPosition = pp; 13594 ctxt->context->node = bak; 13595 ctxt->context->doc = bakd; 13596 CHECK_ERROR0; 13597 } 13598 if (op->ch2 != -1) { 13599 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13600 ctxt->context->contextSize = cs; 13601 ctxt->context->proximityPosition = pp; 13602 ctxt->context->node = bak; 13603 ctxt->context->doc = bakd; 13604 CHECK_ERROR0; 13605 } 13606 return (total); 13607 case XPATH_OP_PREDICATE: 13608 case XPATH_OP_FILTER:{ 13609 xmlXPathObjectPtr res; 13610 xmlXPathObjectPtr obj, tmp; 13611 xmlNodeSetPtr newset = NULL; 13612 xmlNodeSetPtr oldset; 13613 xmlNodePtr oldnode; 13614 xmlDocPtr oldDoc; 13615 int i; 13616 13617 /* 13618 * Optimization for ()[1] selection i.e. the first elem 13619 */ 13620 if ((op->ch1 != -1) && (op->ch2 != -1) && 13621 #ifdef XP_OPTIMIZED_FILTER_FIRST 13622 /* 13623 * FILTER TODO: Can we assume that the inner processing 13624 * will result in an ordered list if we have an 13625 * XPATH_OP_FILTER? 13626 * What about an additional field or flag on 13627 * xmlXPathObject like @sorted ? This way we wouln'd need 13628 * to assume anything, so it would be more robust and 13629 * easier to optimize. 13630 */ 13631 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */ 13632 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */ 13633 #else 13634 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 13635 #endif 13636 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */ 13637 xmlXPathObjectPtr val; 13638 13639 val = comp->steps[op->ch2].value4; 13640 if ((val != NULL) && (val->type == XPATH_NUMBER) && 13641 (val->floatval == 1.0)) { 13642 xmlNodePtr first = NULL; 13643 13644 total += 13645 xmlXPathCompOpEvalFirst(ctxt, 13646 &comp->steps[op->ch1], 13647 &first); 13648 CHECK_ERROR0; 13649 /* 13650 * The nodeset should be in document order, 13651 * Keep only the first value 13652 */ 13653 if ((ctxt->value != NULL) && 13654 (ctxt->value->type == XPATH_NODESET) && 13655 (ctxt->value->nodesetval != NULL) && 13656 (ctxt->value->nodesetval->nodeNr > 1)) 13657 xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval, 13658 1, 1); 13659 return (total); 13660 } 13661 } 13662 /* 13663 * Optimization for ()[last()] selection i.e. the last elem 13664 */ 13665 if ((op->ch1 != -1) && (op->ch2 != -1) && 13666 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 13667 (comp->steps[op->ch2].op == XPATH_OP_SORT)) { 13668 int f = comp->steps[op->ch2].ch1; 13669 13670 if ((f != -1) && 13671 (comp->steps[f].op == XPATH_OP_FUNCTION) && 13672 (comp->steps[f].value5 == NULL) && 13673 (comp->steps[f].value == 0) && 13674 (comp->steps[f].value4 != NULL) && 13675 (xmlStrEqual 13676 (comp->steps[f].value4, BAD_CAST "last"))) { 13677 xmlNodePtr last = NULL; 13678 13679 total += 13680 xmlXPathCompOpEvalLast(ctxt, 13681 &comp->steps[op->ch1], 13682 &last); 13683 CHECK_ERROR0; 13684 /* 13685 * The nodeset should be in document order, 13686 * Keep only the last value 13687 */ 13688 if ((ctxt->value != NULL) && 13689 (ctxt->value->type == XPATH_NODESET) && 13690 (ctxt->value->nodesetval != NULL) && 13691 (ctxt->value->nodesetval->nodeTab != NULL) && 13692 (ctxt->value->nodesetval->nodeNr > 1)) 13693 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval); 13694 return (total); 13695 } 13696 } 13697 /* 13698 * Process inner predicates first. 13699 * Example "index[parent::book][1]": 13700 * ... 13701 * PREDICATE <-- we are here "[1]" 13702 * PREDICATE <-- process "[parent::book]" first 13703 * SORT 13704 * COLLECT 'parent' 'name' 'node' book 13705 * NODE 13706 * ELEM Object is a number : 1 13707 */ 13708 if (op->ch1 != -1) 13709 total += 13710 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13711 CHECK_ERROR0; 13712 if (op->ch2 == -1) 13713 return (total); 13714 if (ctxt->value == NULL) 13715 return (total); 13716 13717 oldnode = ctxt->context->node; 13718 13719 #ifdef LIBXML_XPTR_ENABLED 13720 /* 13721 * Hum are we filtering the result of an XPointer expression 13722 */ 13723 if (ctxt->value->type == XPATH_LOCATIONSET) { 13724 xmlLocationSetPtr newlocset = NULL; 13725 xmlLocationSetPtr oldlocset; 13726 13727 /* 13728 * Extract the old locset, and then evaluate the result of the 13729 * expression for all the element in the locset. use it to grow 13730 * up a new locset. 13731 */ 13732 CHECK_TYPE0(XPATH_LOCATIONSET); 13733 obj = valuePop(ctxt); 13734 oldlocset = obj->user; 13735 ctxt->context->node = NULL; 13736 13737 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) { 13738 ctxt->context->contextSize = 0; 13739 ctxt->context->proximityPosition = 0; 13740 if (op->ch2 != -1) 13741 total += 13742 xmlXPathCompOpEval(ctxt, 13743 &comp->steps[op->ch2]); 13744 res = valuePop(ctxt); 13745 if (res != NULL) { 13746 xmlXPathReleaseObject(ctxt->context, res); 13747 } 13748 valuePush(ctxt, obj); 13749 CHECK_ERROR0; 13750 return (total); 13751 } 13752 newlocset = xmlXPtrLocationSetCreate(NULL); 13753 13754 for (i = 0; i < oldlocset->locNr; i++) { 13755 /* 13756 * Run the evaluation with a node list made of a 13757 * single item in the nodelocset. 13758 */ 13759 ctxt->context->node = oldlocset->locTab[i]->user; 13760 ctxt->context->contextSize = oldlocset->locNr; 13761 ctxt->context->proximityPosition = i + 1; 13762 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13763 ctxt->context->node); 13764 valuePush(ctxt, tmp); 13765 13766 if (op->ch2 != -1) 13767 total += 13768 xmlXPathCompOpEval(ctxt, 13769 &comp->steps[op->ch2]); 13770 if (ctxt->error != XPATH_EXPRESSION_OK) { 13771 xmlXPathFreeObject(obj); 13772 return(0); 13773 } 13774 13775 /* 13776 * The result of the evaluation need to be tested to 13777 * decided whether the filter succeeded or not 13778 */ 13779 res = valuePop(ctxt); 13780 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 13781 xmlXPtrLocationSetAdd(newlocset, 13782 xmlXPathObjectCopy 13783 (oldlocset->locTab[i])); 13784 } 13785 13786 /* 13787 * Cleanup 13788 */ 13789 if (res != NULL) { 13790 xmlXPathReleaseObject(ctxt->context, res); 13791 } 13792 if (ctxt->value == tmp) { 13793 res = valuePop(ctxt); 13794 xmlXPathReleaseObject(ctxt->context, res); 13795 } 13796 13797 ctxt->context->node = NULL; 13798 } 13799 13800 /* 13801 * The result is used as the new evaluation locset. 13802 */ 13803 xmlXPathReleaseObject(ctxt->context, obj); 13804 ctxt->context->node = NULL; 13805 ctxt->context->contextSize = -1; 13806 ctxt->context->proximityPosition = -1; 13807 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset)); 13808 ctxt->context->node = oldnode; 13809 return (total); 13810 } 13811 #endif /* LIBXML_XPTR_ENABLED */ 13812 13813 /* 13814 * Extract the old set, and then evaluate the result of the 13815 * expression for all the element in the set. use it to grow 13816 * up a new set. 13817 */ 13818 CHECK_TYPE0(XPATH_NODESET); 13819 obj = valuePop(ctxt); 13820 oldset = obj->nodesetval; 13821 13822 oldnode = ctxt->context->node; 13823 oldDoc = ctxt->context->doc; 13824 ctxt->context->node = NULL; 13825 13826 if ((oldset == NULL) || (oldset->nodeNr == 0)) { 13827 ctxt->context->contextSize = 0; 13828 ctxt->context->proximityPosition = 0; 13829 /* 13830 if (op->ch2 != -1) 13831 total += 13832 xmlXPathCompOpEval(ctxt, 13833 &comp->steps[op->ch2]); 13834 CHECK_ERROR0; 13835 res = valuePop(ctxt); 13836 if (res != NULL) 13837 xmlXPathFreeObject(res); 13838 */ 13839 valuePush(ctxt, obj); 13840 ctxt->context->node = oldnode; 13841 CHECK_ERROR0; 13842 } else { 13843 tmp = NULL; 13844 /* 13845 * Initialize the new set. 13846 * Also set the xpath document in case things like 13847 * key() evaluation are attempted on the predicate 13848 */ 13849 newset = xmlXPathNodeSetCreate(NULL); 13850 /* 13851 * SPEC XPath 1.0: 13852 * "For each node in the node-set to be filtered, the 13853 * PredicateExpr is evaluated with that node as the 13854 * context node, with the number of nodes in the 13855 * node-set as the context size, and with the proximity 13856 * position of the node in the node-set with respect to 13857 * the axis as the context position;" 13858 * @oldset is the node-set" to be filtered. 13859 * 13860 * SPEC XPath 1.0: 13861 * "only predicates change the context position and 13862 * context size (see [2.4 Predicates])." 13863 * Example: 13864 * node-set context pos 13865 * nA 1 13866 * nB 2 13867 * nC 3 13868 * After applying predicate [position() > 1] : 13869 * node-set context pos 13870 * nB 1 13871 * nC 2 13872 * 13873 * removed the first node in the node-set, then 13874 * the context position of the 13875 */ 13876 for (i = 0; i < oldset->nodeNr; i++) { 13877 /* 13878 * Run the evaluation with a node list made of 13879 * a single item in the nodeset. 13880 */ 13881 ctxt->context->node = oldset->nodeTab[i]; 13882 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) && 13883 (oldset->nodeTab[i]->doc != NULL)) 13884 ctxt->context->doc = oldset->nodeTab[i]->doc; 13885 if (tmp == NULL) { 13886 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13887 ctxt->context->node); 13888 } else { 13889 if (xmlXPathNodeSetAddUnique(tmp->nodesetval, 13890 ctxt->context->node) < 0) { 13891 ctxt->error = XPATH_MEMORY_ERROR; 13892 } 13893 } 13894 valuePush(ctxt, tmp); 13895 ctxt->context->contextSize = oldset->nodeNr; 13896 ctxt->context->proximityPosition = i + 1; 13897 /* 13898 * Evaluate the predicate against the context node. 13899 * Can/should we optimize position() predicates 13900 * here (e.g. "[1]")? 13901 */ 13902 if (op->ch2 != -1) 13903 total += 13904 xmlXPathCompOpEval(ctxt, 13905 &comp->steps[op->ch2]); 13906 if (ctxt->error != XPATH_EXPRESSION_OK) { 13907 xmlXPathFreeNodeSet(newset); 13908 xmlXPathFreeObject(obj); 13909 return(0); 13910 } 13911 13912 /* 13913 * The result of the evaluation needs to be tested to 13914 * decide whether the filter succeeded or not 13915 */ 13916 /* 13917 * OPTIMIZE TODO: Can we use 13918 * xmlXPathNodeSetAdd*Unique()* instead? 13919 */ 13920 res = valuePop(ctxt); 13921 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 13922 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) 13923 < 0) 13924 ctxt->error = XPATH_MEMORY_ERROR; 13925 } 13926 13927 /* 13928 * Cleanup 13929 */ 13930 if (res != NULL) { 13931 xmlXPathReleaseObject(ctxt->context, res); 13932 } 13933 if (ctxt->value == tmp) { 13934 valuePop(ctxt); 13935 xmlXPathNodeSetClear(tmp->nodesetval, 1); 13936 /* 13937 * Don't free the temporary nodeset 13938 * in order to avoid massive recreation inside this 13939 * loop. 13940 */ 13941 } else 13942 tmp = NULL; 13943 ctxt->context->node = NULL; 13944 } 13945 if (tmp != NULL) 13946 xmlXPathReleaseObject(ctxt->context, tmp); 13947 /* 13948 * The result is used as the new evaluation set. 13949 */ 13950 xmlXPathReleaseObject(ctxt->context, obj); 13951 ctxt->context->node = NULL; 13952 ctxt->context->contextSize = -1; 13953 ctxt->context->proximityPosition = -1; 13954 /* may want to move this past the '}' later */ 13955 ctxt->context->doc = oldDoc; 13956 valuePush(ctxt, 13957 xmlXPathCacheWrapNodeSet(ctxt->context, newset)); 13958 } 13959 ctxt->context->node = oldnode; 13960 return (total); 13961 } 13962 case XPATH_OP_SORT: 13963 if (op->ch1 != -1) 13964 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13965 CHECK_ERROR0; 13966 if ((ctxt->value != NULL) && 13967 (ctxt->value->type == XPATH_NODESET) && 13968 (ctxt->value->nodesetval != NULL) && 13969 (ctxt->value->nodesetval->nodeNr > 1)) 13970 { 13971 xmlXPathNodeSetSort(ctxt->value->nodesetval); 13972 } 13973 return (total); 13974 #ifdef LIBXML_XPTR_ENABLED 13975 case XPATH_OP_RANGETO:{ 13976 xmlXPathObjectPtr range; 13977 xmlXPathObjectPtr res, obj; 13978 xmlXPathObjectPtr tmp; 13979 xmlLocationSetPtr newlocset = NULL; 13980 xmlLocationSetPtr oldlocset; 13981 xmlNodeSetPtr oldset; 13982 int i, j; 13983 13984 if (op->ch1 != -1) { 13985 total += 13986 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13987 CHECK_ERROR0; 13988 } 13989 if (ctxt->value == NULL) { 13990 XP_ERROR0(XPATH_INVALID_OPERAND); 13991 } 13992 if (op->ch2 == -1) 13993 return (total); 13994 13995 if (ctxt->value->type == XPATH_LOCATIONSET) { 13996 /* 13997 * Extract the old locset, and then evaluate the result of the 13998 * expression for all the element in the locset. use it to grow 13999 * up a new locset. 14000 */ 14001 CHECK_TYPE0(XPATH_LOCATIONSET); 14002 obj = valuePop(ctxt); 14003 oldlocset = obj->user; 14004 14005 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) { 14006 ctxt->context->node = NULL; 14007 ctxt->context->contextSize = 0; 14008 ctxt->context->proximityPosition = 0; 14009 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]); 14010 res = valuePop(ctxt); 14011 if (res != NULL) { 14012 xmlXPathReleaseObject(ctxt->context, res); 14013 } 14014 valuePush(ctxt, obj); 14015 CHECK_ERROR0; 14016 return (total); 14017 } 14018 newlocset = xmlXPtrLocationSetCreate(NULL); 14019 14020 for (i = 0; i < oldlocset->locNr; i++) { 14021 /* 14022 * Run the evaluation with a node list made of a 14023 * single item in the nodelocset. 14024 */ 14025 ctxt->context->node = oldlocset->locTab[i]->user; 14026 ctxt->context->contextSize = oldlocset->locNr; 14027 ctxt->context->proximityPosition = i + 1; 14028 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 14029 ctxt->context->node); 14030 valuePush(ctxt, tmp); 14031 14032 if (op->ch2 != -1) 14033 total += 14034 xmlXPathCompOpEval(ctxt, 14035 &comp->steps[op->ch2]); 14036 if (ctxt->error != XPATH_EXPRESSION_OK) { 14037 xmlXPathFreeObject(obj); 14038 return(0); 14039 } 14040 14041 res = valuePop(ctxt); 14042 if (res->type == XPATH_LOCATIONSET) { 14043 xmlLocationSetPtr rloc = 14044 (xmlLocationSetPtr)res->user; 14045 for (j=0; j<rloc->locNr; j++) { 14046 range = xmlXPtrNewRange( 14047 oldlocset->locTab[i]->user, 14048 oldlocset->locTab[i]->index, 14049 rloc->locTab[j]->user2, 14050 rloc->locTab[j]->index2); 14051 if (range != NULL) { 14052 xmlXPtrLocationSetAdd(newlocset, range); 14053 } 14054 } 14055 } else { 14056 range = xmlXPtrNewRangeNodeObject( 14057 (xmlNodePtr)oldlocset->locTab[i]->user, res); 14058 if (range != NULL) { 14059 xmlXPtrLocationSetAdd(newlocset,range); 14060 } 14061 } 14062 14063 /* 14064 * Cleanup 14065 */ 14066 if (res != NULL) { 14067 xmlXPathReleaseObject(ctxt->context, res); 14068 } 14069 if (ctxt->value == tmp) { 14070 res = valuePop(ctxt); 14071 xmlXPathReleaseObject(ctxt->context, res); 14072 } 14073 14074 ctxt->context->node = NULL; 14075 } 14076 } else { /* Not a location set */ 14077 CHECK_TYPE0(XPATH_NODESET); 14078 obj = valuePop(ctxt); 14079 oldset = obj->nodesetval; 14080 ctxt->context->node = NULL; 14081 14082 newlocset = xmlXPtrLocationSetCreate(NULL); 14083 14084 if (oldset != NULL) { 14085 for (i = 0; i < oldset->nodeNr; i++) { 14086 /* 14087 * Run the evaluation with a node list made of a single item 14088 * in the nodeset. 14089 */ 14090 ctxt->context->node = oldset->nodeTab[i]; 14091 /* 14092 * OPTIMIZE TODO: Avoid recreation for every iteration. 14093 */ 14094 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 14095 ctxt->context->node); 14096 valuePush(ctxt, tmp); 14097 14098 if (op->ch2 != -1) 14099 total += 14100 xmlXPathCompOpEval(ctxt, 14101 &comp->steps[op->ch2]); 14102 if (ctxt->error != XPATH_EXPRESSION_OK) { 14103 xmlXPathFreeObject(obj); 14104 return(0); 14105 } 14106 14107 res = valuePop(ctxt); 14108 range = 14109 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i], 14110 res); 14111 if (range != NULL) { 14112 xmlXPtrLocationSetAdd(newlocset, range); 14113 } 14114 14115 /* 14116 * Cleanup 14117 */ 14118 if (res != NULL) { 14119 xmlXPathReleaseObject(ctxt->context, res); 14120 } 14121 if (ctxt->value == tmp) { 14122 res = valuePop(ctxt); 14123 xmlXPathReleaseObject(ctxt->context, res); 14124 } 14125 14126 ctxt->context->node = NULL; 14127 } 14128 } 14129 } 14130 14131 /* 14132 * The result is used as the new evaluation set. 14133 */ 14134 xmlXPathReleaseObject(ctxt->context, obj); 14135 ctxt->context->node = NULL; 14136 ctxt->context->contextSize = -1; 14137 ctxt->context->proximityPosition = -1; 14138 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset)); 14139 return (total); 14140 } 14141 #endif /* LIBXML_XPTR_ENABLED */ 14142 } 14143 xmlGenericError(xmlGenericErrorContext, 14144 "XPath: unknown precompiled operation %d\n", op->op); 14145 ctxt->error = XPATH_INVALID_OPERAND; 14146 return (total); 14147 } 14148 14149 /** 14150 * xmlXPathCompOpEvalToBoolean: 14151 * @ctxt: the XPath parser context 14152 * 14153 * Evaluates if the expression evaluates to true. 14154 * 14155 * Returns 1 if true, 0 if false and -1 on API or internal errors. 14156 */ 14157 static int 14158 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt, 14159 xmlXPathStepOpPtr op, 14160 int isPredicate) 14161 { 14162 xmlXPathObjectPtr resObj = NULL; 14163 14164 start: 14165 /* comp = ctxt->comp; */ 14166 switch (op->op) { 14167 case XPATH_OP_END: 14168 return (0); 14169 case XPATH_OP_VALUE: 14170 resObj = (xmlXPathObjectPtr) op->value4; 14171 if (isPredicate) 14172 return(xmlXPathEvaluatePredicateResult(ctxt, resObj)); 14173 return(xmlXPathCastToBoolean(resObj)); 14174 case XPATH_OP_SORT: 14175 /* 14176 * We don't need sorting for boolean results. Skip this one. 14177 */ 14178 if (op->ch1 != -1) { 14179 op = &ctxt->comp->steps[op->ch1]; 14180 goto start; 14181 } 14182 return(0); 14183 case XPATH_OP_COLLECT: 14184 if (op->ch1 == -1) 14185 return(0); 14186 14187 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]); 14188 if (ctxt->error != XPATH_EXPRESSION_OK) 14189 return(-1); 14190 14191 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1); 14192 if (ctxt->error != XPATH_EXPRESSION_OK) 14193 return(-1); 14194 14195 resObj = valuePop(ctxt); 14196 if (resObj == NULL) 14197 return(-1); 14198 break; 14199 default: 14200 /* 14201 * Fallback to call xmlXPathCompOpEval(). 14202 */ 14203 xmlXPathCompOpEval(ctxt, op); 14204 if (ctxt->error != XPATH_EXPRESSION_OK) 14205 return(-1); 14206 14207 resObj = valuePop(ctxt); 14208 if (resObj == NULL) 14209 return(-1); 14210 break; 14211 } 14212 14213 if (resObj) { 14214 int res; 14215 14216 if (resObj->type == XPATH_BOOLEAN) { 14217 res = resObj->boolval; 14218 } else if (isPredicate) { 14219 /* 14220 * For predicates a result of type "number" is handled 14221 * differently: 14222 * SPEC XPath 1.0: 14223 * "If the result is a number, the result will be converted 14224 * to true if the number is equal to the context position 14225 * and will be converted to false otherwise;" 14226 */ 14227 res = xmlXPathEvaluatePredicateResult(ctxt, resObj); 14228 } else { 14229 res = xmlXPathCastToBoolean(resObj); 14230 } 14231 xmlXPathReleaseObject(ctxt->context, resObj); 14232 return(res); 14233 } 14234 14235 return(0); 14236 } 14237 14238 #ifdef XPATH_STREAMING 14239 /** 14240 * xmlXPathRunStreamEval: 14241 * @ctxt: the XPath parser context with the compiled expression 14242 * 14243 * Evaluate the Precompiled Streamable XPath expression in the given context. 14244 */ 14245 static int 14246 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp, 14247 xmlXPathObjectPtr *resultSeq, int toBool) 14248 { 14249 int max_depth, min_depth; 14250 int from_root; 14251 int ret, depth; 14252 int eval_all_nodes; 14253 xmlNodePtr cur = NULL, limit = NULL; 14254 xmlStreamCtxtPtr patstream = NULL; 14255 14256 int nb_nodes = 0; 14257 14258 if ((ctxt == NULL) || (comp == NULL)) 14259 return(-1); 14260 max_depth = xmlPatternMaxDepth(comp); 14261 if (max_depth == -1) 14262 return(-1); 14263 if (max_depth == -2) 14264 max_depth = 10000; 14265 min_depth = xmlPatternMinDepth(comp); 14266 if (min_depth == -1) 14267 return(-1); 14268 from_root = xmlPatternFromRoot(comp); 14269 if (from_root < 0) 14270 return(-1); 14271 #if 0 14272 printf("stream eval: depth %d from root %d\n", max_depth, from_root); 14273 #endif 14274 14275 if (! toBool) { 14276 if (resultSeq == NULL) 14277 return(-1); 14278 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL); 14279 if (*resultSeq == NULL) 14280 return(-1); 14281 } 14282 14283 /* 14284 * handle the special cases of "/" amd "." being matched 14285 */ 14286 if (min_depth == 0) { 14287 if (from_root) { 14288 /* Select "/" */ 14289 if (toBool) 14290 return(1); 14291 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, 14292 (xmlNodePtr) ctxt->doc); 14293 } else { 14294 /* Select "self::node()" */ 14295 if (toBool) 14296 return(1); 14297 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node); 14298 } 14299 } 14300 if (max_depth == 0) { 14301 return(0); 14302 } 14303 14304 if (from_root) { 14305 cur = (xmlNodePtr)ctxt->doc; 14306 } else if (ctxt->node != NULL) { 14307 switch (ctxt->node->type) { 14308 case XML_ELEMENT_NODE: 14309 case XML_DOCUMENT_NODE: 14310 case XML_DOCUMENT_FRAG_NODE: 14311 case XML_HTML_DOCUMENT_NODE: 14312 #ifdef LIBXML_DOCB_ENABLED 14313 case XML_DOCB_DOCUMENT_NODE: 14314 #endif 14315 cur = ctxt->node; 14316 break; 14317 case XML_ATTRIBUTE_NODE: 14318 case XML_TEXT_NODE: 14319 case XML_CDATA_SECTION_NODE: 14320 case XML_ENTITY_REF_NODE: 14321 case XML_ENTITY_NODE: 14322 case XML_PI_NODE: 14323 case XML_COMMENT_NODE: 14324 case XML_NOTATION_NODE: 14325 case XML_DTD_NODE: 14326 case XML_DOCUMENT_TYPE_NODE: 14327 case XML_ELEMENT_DECL: 14328 case XML_ATTRIBUTE_DECL: 14329 case XML_ENTITY_DECL: 14330 case XML_NAMESPACE_DECL: 14331 case XML_XINCLUDE_START: 14332 case XML_XINCLUDE_END: 14333 break; 14334 } 14335 limit = cur; 14336 } 14337 if (cur == NULL) { 14338 return(0); 14339 } 14340 14341 patstream = xmlPatternGetStreamCtxt(comp); 14342 if (patstream == NULL) { 14343 /* 14344 * QUESTION TODO: Is this an error? 14345 */ 14346 return(0); 14347 } 14348 14349 eval_all_nodes = xmlStreamWantsAnyNode(patstream); 14350 14351 if (from_root) { 14352 ret = xmlStreamPush(patstream, NULL, NULL); 14353 if (ret < 0) { 14354 } else if (ret == 1) { 14355 if (toBool) 14356 goto return_1; 14357 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur); 14358 } 14359 } 14360 depth = 0; 14361 goto scan_children; 14362 next_node: 14363 do { 14364 nb_nodes++; 14365 14366 switch (cur->type) { 14367 case XML_ELEMENT_NODE: 14368 case XML_TEXT_NODE: 14369 case XML_CDATA_SECTION_NODE: 14370 case XML_COMMENT_NODE: 14371 case XML_PI_NODE: 14372 if (cur->type == XML_ELEMENT_NODE) { 14373 ret = xmlStreamPush(patstream, cur->name, 14374 (cur->ns ? cur->ns->href : NULL)); 14375 } else if (eval_all_nodes) 14376 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type); 14377 else 14378 break; 14379 14380 if (ret < 0) { 14381 /* NOP. */ 14382 } else if (ret == 1) { 14383 if (toBool) 14384 goto return_1; 14385 if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur) 14386 < 0) { 14387 ctxt->lastError.domain = XML_FROM_XPATH; 14388 ctxt->lastError.code = XML_ERR_NO_MEMORY; 14389 } 14390 } 14391 if ((cur->children == NULL) || (depth >= max_depth)) { 14392 ret = xmlStreamPop(patstream); 14393 while (cur->next != NULL) { 14394 cur = cur->next; 14395 if ((cur->type != XML_ENTITY_DECL) && 14396 (cur->type != XML_DTD_NODE)) 14397 goto next_node; 14398 } 14399 } 14400 default: 14401 break; 14402 } 14403 14404 scan_children: 14405 if (cur->type == XML_NAMESPACE_DECL) break; 14406 if ((cur->children != NULL) && (depth < max_depth)) { 14407 /* 14408 * Do not descend on entities declarations 14409 */ 14410 if (cur->children->type != XML_ENTITY_DECL) { 14411 cur = cur->children; 14412 depth++; 14413 /* 14414 * Skip DTDs 14415 */ 14416 if (cur->type != XML_DTD_NODE) 14417 continue; 14418 } 14419 } 14420 14421 if (cur == limit) 14422 break; 14423 14424 while (cur->next != NULL) { 14425 cur = cur->next; 14426 if ((cur->type != XML_ENTITY_DECL) && 14427 (cur->type != XML_DTD_NODE)) 14428 goto next_node; 14429 } 14430 14431 do { 14432 cur = cur->parent; 14433 depth--; 14434 if ((cur == NULL) || (cur == limit)) 14435 goto done; 14436 if (cur->type == XML_ELEMENT_NODE) { 14437 ret = xmlStreamPop(patstream); 14438 } else if ((eval_all_nodes) && 14439 ((cur->type == XML_TEXT_NODE) || 14440 (cur->type == XML_CDATA_SECTION_NODE) || 14441 (cur->type == XML_COMMENT_NODE) || 14442 (cur->type == XML_PI_NODE))) 14443 { 14444 ret = xmlStreamPop(patstream); 14445 } 14446 if (cur->next != NULL) { 14447 cur = cur->next; 14448 break; 14449 } 14450 } while (cur != NULL); 14451 14452 } while ((cur != NULL) && (depth >= 0)); 14453 14454 done: 14455 14456 #if 0 14457 printf("stream eval: checked %d nodes selected %d\n", 14458 nb_nodes, retObj->nodesetval->nodeNr); 14459 #endif 14460 14461 if (patstream) 14462 xmlFreeStreamCtxt(patstream); 14463 return(0); 14464 14465 return_1: 14466 if (patstream) 14467 xmlFreeStreamCtxt(patstream); 14468 return(1); 14469 } 14470 #endif /* XPATH_STREAMING */ 14471 14472 /** 14473 * xmlXPathRunEval: 14474 * @ctxt: the XPath parser context with the compiled expression 14475 * @toBool: evaluate to a boolean result 14476 * 14477 * Evaluate the Precompiled XPath expression in the given context. 14478 */ 14479 static int 14480 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool) 14481 { 14482 xmlXPathCompExprPtr comp; 14483 14484 if ((ctxt == NULL) || (ctxt->comp == NULL)) 14485 return(-1); 14486 14487 if (ctxt->valueTab == NULL) { 14488 /* Allocate the value stack */ 14489 ctxt->valueTab = (xmlXPathObjectPtr *) 14490 xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); 14491 if (ctxt->valueTab == NULL) { 14492 xmlXPathPErrMemory(ctxt, "creating evaluation context\n"); 14493 xmlFree(ctxt); 14494 } 14495 ctxt->valueNr = 0; 14496 ctxt->valueMax = 10; 14497 ctxt->value = NULL; 14498 ctxt->valueFrame = 0; 14499 } 14500 #ifdef XPATH_STREAMING 14501 if (ctxt->comp->stream) { 14502 int res; 14503 14504 if (toBool) { 14505 /* 14506 * Evaluation to boolean result. 14507 */ 14508 res = xmlXPathRunStreamEval(ctxt->context, 14509 ctxt->comp->stream, NULL, 1); 14510 if (res != -1) 14511 return(res); 14512 } else { 14513 xmlXPathObjectPtr resObj = NULL; 14514 14515 /* 14516 * Evaluation to a sequence. 14517 */ 14518 res = xmlXPathRunStreamEval(ctxt->context, 14519 ctxt->comp->stream, &resObj, 0); 14520 14521 if ((res != -1) && (resObj != NULL)) { 14522 valuePush(ctxt, resObj); 14523 return(0); 14524 } 14525 if (resObj != NULL) 14526 xmlXPathReleaseObject(ctxt->context, resObj); 14527 } 14528 /* 14529 * QUESTION TODO: This falls back to normal XPath evaluation 14530 * if res == -1. Is this intended? 14531 */ 14532 } 14533 #endif 14534 comp = ctxt->comp; 14535 if (comp->last < 0) { 14536 xmlGenericError(xmlGenericErrorContext, 14537 "xmlXPathRunEval: last is less than zero\n"); 14538 return(-1); 14539 } 14540 if (toBool) 14541 return(xmlXPathCompOpEvalToBoolean(ctxt, 14542 &comp->steps[comp->last], 0)); 14543 else 14544 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]); 14545 14546 return(0); 14547 } 14548 14549 /************************************************************************ 14550 * * 14551 * Public interfaces * 14552 * * 14553 ************************************************************************/ 14554 14555 /** 14556 * xmlXPathEvalPredicate: 14557 * @ctxt: the XPath context 14558 * @res: the Predicate Expression evaluation result 14559 * 14560 * Evaluate a predicate result for the current node. 14561 * A PredicateExpr is evaluated by evaluating the Expr and converting 14562 * the result to a boolean. If the result is a number, the result will 14563 * be converted to true if the number is equal to the position of the 14564 * context node in the context node list (as returned by the position 14565 * function) and will be converted to false otherwise; if the result 14566 * is not a number, then the result will be converted as if by a call 14567 * to the boolean function. 14568 * 14569 * Returns 1 if predicate is true, 0 otherwise 14570 */ 14571 int 14572 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) { 14573 if ((ctxt == NULL) || (res == NULL)) return(0); 14574 switch (res->type) { 14575 case XPATH_BOOLEAN: 14576 return(res->boolval); 14577 case XPATH_NUMBER: 14578 return(res->floatval == ctxt->proximityPosition); 14579 case XPATH_NODESET: 14580 case XPATH_XSLT_TREE: 14581 if (res->nodesetval == NULL) 14582 return(0); 14583 return(res->nodesetval->nodeNr != 0); 14584 case XPATH_STRING: 14585 return((res->stringval != NULL) && 14586 (xmlStrlen(res->stringval) != 0)); 14587 default: 14588 STRANGE 14589 } 14590 return(0); 14591 } 14592 14593 /** 14594 * xmlXPathEvaluatePredicateResult: 14595 * @ctxt: the XPath Parser context 14596 * @res: the Predicate Expression evaluation result 14597 * 14598 * Evaluate a predicate result for the current node. 14599 * A PredicateExpr is evaluated by evaluating the Expr and converting 14600 * the result to a boolean. If the result is a number, the result will 14601 * be converted to true if the number is equal to the position of the 14602 * context node in the context node list (as returned by the position 14603 * function) and will be converted to false otherwise; if the result 14604 * is not a number, then the result will be converted as if by a call 14605 * to the boolean function. 14606 * 14607 * Returns 1 if predicate is true, 0 otherwise 14608 */ 14609 int 14610 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt, 14611 xmlXPathObjectPtr res) { 14612 if ((ctxt == NULL) || (res == NULL)) return(0); 14613 switch (res->type) { 14614 case XPATH_BOOLEAN: 14615 return(res->boolval); 14616 case XPATH_NUMBER: 14617 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200)) 14618 return((res->floatval == ctxt->context->proximityPosition) && 14619 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/ 14620 #else 14621 return(res->floatval == ctxt->context->proximityPosition); 14622 #endif 14623 case XPATH_NODESET: 14624 case XPATH_XSLT_TREE: 14625 if (res->nodesetval == NULL) 14626 return(0); 14627 return(res->nodesetval->nodeNr != 0); 14628 case XPATH_STRING: 14629 return((res->stringval != NULL) && (res->stringval[0] != 0)); 14630 #ifdef LIBXML_XPTR_ENABLED 14631 case XPATH_LOCATIONSET:{ 14632 xmlLocationSetPtr ptr = res->user; 14633 if (ptr == NULL) 14634 return(0); 14635 return (ptr->locNr != 0); 14636 } 14637 #endif 14638 default: 14639 STRANGE 14640 } 14641 return(0); 14642 } 14643 14644 #ifdef XPATH_STREAMING 14645 /** 14646 * xmlXPathTryStreamCompile: 14647 * @ctxt: an XPath context 14648 * @str: the XPath expression 14649 * 14650 * Try to compile the XPath expression as a streamable subset. 14651 * 14652 * Returns the compiled expression or NULL if failed to compile. 14653 */ 14654 static xmlXPathCompExprPtr 14655 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { 14656 /* 14657 * Optimization: use streaming patterns when the XPath expression can 14658 * be compiled to a stream lookup 14659 */ 14660 xmlPatternPtr stream; 14661 xmlXPathCompExprPtr comp; 14662 xmlDictPtr dict = NULL; 14663 const xmlChar **namespaces = NULL; 14664 xmlNsPtr ns; 14665 int i, j; 14666 14667 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) && 14668 (!xmlStrchr(str, '@'))) { 14669 const xmlChar *tmp; 14670 14671 /* 14672 * We don't try to handle expressions using the verbose axis 14673 * specifiers ("::"), just the simplied form at this point. 14674 * Additionally, if there is no list of namespaces available and 14675 * there's a ":" in the expression, indicating a prefixed QName, 14676 * then we won't try to compile either. xmlPatterncompile() needs 14677 * to have a list of namespaces at compilation time in order to 14678 * compile prefixed name tests. 14679 */ 14680 tmp = xmlStrchr(str, ':'); 14681 if ((tmp != NULL) && 14682 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':'))) 14683 return(NULL); 14684 14685 if (ctxt != NULL) { 14686 dict = ctxt->dict; 14687 if (ctxt->nsNr > 0) { 14688 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*)); 14689 if (namespaces == NULL) { 14690 xmlXPathErrMemory(ctxt, "allocating namespaces array\n"); 14691 return(NULL); 14692 } 14693 for (i = 0, j = 0; (j < ctxt->nsNr); j++) { 14694 ns = ctxt->namespaces[j]; 14695 namespaces[i++] = ns->href; 14696 namespaces[i++] = ns->prefix; 14697 } 14698 namespaces[i++] = NULL; 14699 namespaces[i] = NULL; 14700 } 14701 } 14702 14703 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, 14704 &namespaces[0]); 14705 if (namespaces != NULL) { 14706 xmlFree((xmlChar **)namespaces); 14707 } 14708 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) { 14709 comp = xmlXPathNewCompExpr(); 14710 if (comp == NULL) { 14711 xmlXPathErrMemory(ctxt, "allocating streamable expression\n"); 14712 return(NULL); 14713 } 14714 comp->stream = stream; 14715 comp->dict = dict; 14716 if (comp->dict) 14717 xmlDictReference(comp->dict); 14718 return(comp); 14719 } 14720 xmlFreePattern(stream); 14721 } 14722 return(NULL); 14723 } 14724 #endif /* XPATH_STREAMING */ 14725 14726 static void 14727 xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op) 14728 { 14729 /* 14730 * Try to rewrite "descendant-or-self::node()/foo" to an optimized 14731 * internal representation. 14732 */ 14733 14734 if ((op->op == XPATH_OP_COLLECT /* 11 */) && 14735 (op->ch1 != -1) && 14736 (op->ch2 == -1 /* no predicate */)) 14737 { 14738 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1]; 14739 14740 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) && 14741 ((xmlXPathAxisVal) prevop->value == 14742 AXIS_DESCENDANT_OR_SELF) && 14743 (prevop->ch2 == -1) && 14744 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) && 14745 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE)) 14746 { 14747 /* 14748 * This is a "descendant-or-self::node()" without predicates. 14749 * Try to eliminate it. 14750 */ 14751 14752 switch ((xmlXPathAxisVal) op->value) { 14753 case AXIS_CHILD: 14754 case AXIS_DESCENDANT: 14755 /* 14756 * Convert "descendant-or-self::node()/child::" or 14757 * "descendant-or-self::node()/descendant::" to 14758 * "descendant::" 14759 */ 14760 op->ch1 = prevop->ch1; 14761 op->value = AXIS_DESCENDANT; 14762 break; 14763 case AXIS_SELF: 14764 case AXIS_DESCENDANT_OR_SELF: 14765 /* 14766 * Convert "descendant-or-self::node()/self::" or 14767 * "descendant-or-self::node()/descendant-or-self::" to 14768 * to "descendant-or-self::" 14769 */ 14770 op->ch1 = prevop->ch1; 14771 op->value = AXIS_DESCENDANT_OR_SELF; 14772 break; 14773 default: 14774 break; 14775 } 14776 } 14777 } 14778 14779 /* OP_VALUE has invalid ch1. */ 14780 if (op->op == XPATH_OP_VALUE) 14781 return; 14782 14783 /* Recurse */ 14784 if (op->ch1 != -1) 14785 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]); 14786 if (op->ch2 != -1) 14787 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]); 14788 } 14789 14790 /** 14791 * xmlXPathCtxtCompile: 14792 * @ctxt: an XPath context 14793 * @str: the XPath expression 14794 * 14795 * Compile an XPath expression 14796 * 14797 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL. 14798 * the caller has to free the object. 14799 */ 14800 xmlXPathCompExprPtr 14801 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { 14802 xmlXPathParserContextPtr pctxt; 14803 xmlXPathCompExprPtr comp; 14804 14805 #ifdef XPATH_STREAMING 14806 comp = xmlXPathTryStreamCompile(ctxt, str); 14807 if (comp != NULL) 14808 return(comp); 14809 #endif 14810 14811 xmlXPathInit(); 14812 14813 pctxt = xmlXPathNewParserContext(str, ctxt); 14814 if (pctxt == NULL) 14815 return NULL; 14816 xmlXPathCompileExpr(pctxt, 1); 14817 14818 if( pctxt->error != XPATH_EXPRESSION_OK ) 14819 { 14820 xmlXPathFreeParserContext(pctxt); 14821 return(NULL); 14822 } 14823 14824 if (*pctxt->cur != 0) { 14825 /* 14826 * aleksey: in some cases this line prints *second* error message 14827 * (see bug #78858) and probably this should be fixed. 14828 * However, we are not sure that all error messages are printed 14829 * out in other places. It's not critical so we leave it as-is for now 14830 */ 14831 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR); 14832 comp = NULL; 14833 } else { 14834 comp = pctxt->comp; 14835 pctxt->comp = NULL; 14836 } 14837 xmlXPathFreeParserContext(pctxt); 14838 14839 if (comp != NULL) { 14840 comp->expr = xmlStrdup(str); 14841 #ifdef DEBUG_EVAL_COUNTS 14842 comp->string = xmlStrdup(str); 14843 comp->nb = 0; 14844 #endif 14845 if ((comp->nbStep > 1) && (comp->last >= 0)) { 14846 xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]); 14847 } 14848 } 14849 return(comp); 14850 } 14851 14852 /** 14853 * xmlXPathCompile: 14854 * @str: the XPath expression 14855 * 14856 * Compile an XPath expression 14857 * 14858 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL. 14859 * the caller has to free the object. 14860 */ 14861 xmlXPathCompExprPtr 14862 xmlXPathCompile(const xmlChar *str) { 14863 return(xmlXPathCtxtCompile(NULL, str)); 14864 } 14865 14866 /** 14867 * xmlXPathCompiledEvalInternal: 14868 * @comp: the compiled XPath expression 14869 * @ctxt: the XPath context 14870 * @resObj: the resulting XPath object or NULL 14871 * @toBool: 1 if only a boolean result is requested 14872 * 14873 * Evaluate the Precompiled XPath expression in the given context. 14874 * The caller has to free @resObj. 14875 * 14876 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14877 * the caller has to free the object. 14878 */ 14879 static int 14880 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp, 14881 xmlXPathContextPtr ctxt, 14882 xmlXPathObjectPtr *resObjPtr, 14883 int toBool) 14884 { 14885 xmlXPathParserContextPtr pctxt; 14886 xmlXPathObjectPtr resObj; 14887 #ifndef LIBXML_THREAD_ENABLED 14888 static int reentance = 0; 14889 #endif 14890 int res; 14891 14892 CHECK_CTXT_NEG(ctxt) 14893 14894 if (comp == NULL) 14895 return(-1); 14896 xmlXPathInit(); 14897 14898 #ifndef LIBXML_THREAD_ENABLED 14899 reentance++; 14900 if (reentance > 1) 14901 xmlXPathDisableOptimizer = 1; 14902 #endif 14903 14904 #ifdef DEBUG_EVAL_COUNTS 14905 comp->nb++; 14906 if ((comp->string != NULL) && (comp->nb > 100)) { 14907 fprintf(stderr, "100 x %s\n", comp->string); 14908 comp->nb = 0; 14909 } 14910 #endif 14911 pctxt = xmlXPathCompParserContext(comp, ctxt); 14912 res = xmlXPathRunEval(pctxt, toBool); 14913 14914 if (pctxt->error != XPATH_EXPRESSION_OK) { 14915 resObj = NULL; 14916 } else { 14917 resObj = valuePop(pctxt); 14918 if (resObj == NULL) { 14919 if (!toBool) 14920 xmlGenericError(xmlGenericErrorContext, 14921 "xmlXPathCompiledEval: No result on the stack.\n"); 14922 } else if (pctxt->valueNr > 0) { 14923 xmlGenericError(xmlGenericErrorContext, 14924 "xmlXPathCompiledEval: %d object(s) left on the stack.\n", 14925 pctxt->valueNr); 14926 } 14927 } 14928 14929 if (resObjPtr) 14930 *resObjPtr = resObj; 14931 else 14932 xmlXPathReleaseObject(ctxt, resObj); 14933 14934 pctxt->comp = NULL; 14935 xmlXPathFreeParserContext(pctxt); 14936 #ifndef LIBXML_THREAD_ENABLED 14937 reentance--; 14938 #endif 14939 14940 return(res); 14941 } 14942 14943 /** 14944 * xmlXPathCompiledEval: 14945 * @comp: the compiled XPath expression 14946 * @ctx: the XPath context 14947 * 14948 * Evaluate the Precompiled XPath expression in the given context. 14949 * 14950 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14951 * the caller has to free the object. 14952 */ 14953 xmlXPathObjectPtr 14954 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) 14955 { 14956 xmlXPathObjectPtr res = NULL; 14957 14958 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0); 14959 return(res); 14960 } 14961 14962 /** 14963 * xmlXPathCompiledEvalToBoolean: 14964 * @comp: the compiled XPath expression 14965 * @ctxt: the XPath context 14966 * 14967 * Applies the XPath boolean() function on the result of the given 14968 * compiled expression. 14969 * 14970 * Returns 1 if the expression evaluated to true, 0 if to false and 14971 * -1 in API and internal errors. 14972 */ 14973 int 14974 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp, 14975 xmlXPathContextPtr ctxt) 14976 { 14977 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1)); 14978 } 14979 14980 /** 14981 * xmlXPathEvalExpr: 14982 * @ctxt: the XPath Parser context 14983 * 14984 * Parse and evaluate an XPath expression in the given context, 14985 * then push the result on the context stack 14986 */ 14987 void 14988 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) { 14989 #ifdef XPATH_STREAMING 14990 xmlXPathCompExprPtr comp; 14991 #endif 14992 14993 if (ctxt == NULL) return; 14994 14995 #ifdef XPATH_STREAMING 14996 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base); 14997 if (comp != NULL) { 14998 if (ctxt->comp != NULL) 14999 xmlXPathFreeCompExpr(ctxt->comp); 15000 ctxt->comp = comp; 15001 } else 15002 #endif 15003 { 15004 xmlXPathCompileExpr(ctxt, 1); 15005 CHECK_ERROR; 15006 15007 /* Check for trailing characters. */ 15008 if (*ctxt->cur != 0) 15009 XP_ERROR(XPATH_EXPR_ERROR); 15010 15011 if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) 15012 xmlXPathOptimizeExpression(ctxt->comp, 15013 &ctxt->comp->steps[ctxt->comp->last]); 15014 } 15015 15016 xmlXPathRunEval(ctxt, 0); 15017 } 15018 15019 /** 15020 * xmlXPathEval: 15021 * @str: the XPath expression 15022 * @ctx: the XPath context 15023 * 15024 * Evaluate the XPath Location Path in the given context. 15025 * 15026 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 15027 * the caller has to free the object. 15028 */ 15029 xmlXPathObjectPtr 15030 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) { 15031 xmlXPathParserContextPtr ctxt; 15032 xmlXPathObjectPtr res; 15033 15034 CHECK_CTXT(ctx) 15035 15036 xmlXPathInit(); 15037 15038 ctxt = xmlXPathNewParserContext(str, ctx); 15039 if (ctxt == NULL) 15040 return NULL; 15041 xmlXPathEvalExpr(ctxt); 15042 15043 if (ctxt->error != XPATH_EXPRESSION_OK) { 15044 res = NULL; 15045 } else { 15046 res = valuePop(ctxt); 15047 if (res == NULL) { 15048 xmlGenericError(xmlGenericErrorContext, 15049 "xmlXPathCompiledEval: No result on the stack.\n"); 15050 } else if (ctxt->valueNr > 0) { 15051 xmlGenericError(xmlGenericErrorContext, 15052 "xmlXPathCompiledEval: %d object(s) left on the stack.\n", 15053 ctxt->valueNr); 15054 } 15055 } 15056 15057 xmlXPathFreeParserContext(ctxt); 15058 return(res); 15059 } 15060 15061 /** 15062 * xmlXPathSetContextNode: 15063 * @node: the node to to use as the context node 15064 * @ctx: the XPath context 15065 * 15066 * Sets 'node' as the context node. The node must be in the same 15067 * document as that associated with the context. 15068 * 15069 * Returns -1 in case of error or 0 if successful 15070 */ 15071 int 15072 xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) { 15073 if ((node == NULL) || (ctx == NULL)) 15074 return(-1); 15075 15076 if (node->doc == ctx->doc) { 15077 ctx->node = node; 15078 return(0); 15079 } 15080 return(-1); 15081 } 15082 15083 /** 15084 * xmlXPathNodeEval: 15085 * @node: the node to to use as the context node 15086 * @str: the XPath expression 15087 * @ctx: the XPath context 15088 * 15089 * Evaluate the XPath Location Path in the given context. The node 'node' 15090 * is set as the context node. The context node is not restored. 15091 * 15092 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 15093 * the caller has to free the object. 15094 */ 15095 xmlXPathObjectPtr 15096 xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) { 15097 if (str == NULL) 15098 return(NULL); 15099 if (xmlXPathSetContextNode(node, ctx) < 0) 15100 return(NULL); 15101 return(xmlXPathEval(str, ctx)); 15102 } 15103 15104 /** 15105 * xmlXPathEvalExpression: 15106 * @str: the XPath expression 15107 * @ctxt: the XPath context 15108 * 15109 * Alias for xmlXPathEval(). 15110 * 15111 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 15112 * the caller has to free the object. 15113 */ 15114 xmlXPathObjectPtr 15115 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) { 15116 return(xmlXPathEval(str, ctxt)); 15117 } 15118 15119 /************************************************************************ 15120 * * 15121 * Extra functions not pertaining to the XPath spec * 15122 * * 15123 ************************************************************************/ 15124 /** 15125 * xmlXPathEscapeUriFunction: 15126 * @ctxt: the XPath Parser context 15127 * @nargs: the number of arguments 15128 * 15129 * Implement the escape-uri() XPath function 15130 * string escape-uri(string $str, bool $escape-reserved) 15131 * 15132 * This function applies the URI escaping rules defined in section 2 of [RFC 15133 * 2396] to the string supplied as $uri-part, which typically represents all 15134 * or part of a URI. The effect of the function is to replace any special 15135 * character in the string by an escape sequence of the form %xx%yy..., 15136 * where xxyy... is the hexadecimal representation of the octets used to 15137 * represent the character in UTF-8. 15138 * 15139 * The set of characters that are escaped depends on the setting of the 15140 * boolean argument $escape-reserved. 15141 * 15142 * If $escape-reserved is true, all characters are escaped other than lower 15143 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters 15144 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!" 15145 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only 15146 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and 15147 * A-F). 15148 * 15149 * If $escape-reserved is false, the behavior differs in that characters 15150 * referred to in [RFC 2396] as reserved characters are not escaped. These 15151 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",". 15152 * 15153 * [RFC 2396] does not define whether escaped URIs should use lower case or 15154 * upper case for hexadecimal digits. To ensure that escaped URIs can be 15155 * compared using string comparison functions, this function must always use 15156 * the upper-case letters A-F. 15157 * 15158 * Generally, $escape-reserved should be set to true when escaping a string 15159 * that is to form a single part of a URI, and to false when escaping an 15160 * entire URI or URI reference. 15161 * 15162 * In the case of non-ascii characters, the string is encoded according to 15163 * utf-8 and then converted according to RFC 2396. 15164 * 15165 * Examples 15166 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true()) 15167 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean" 15168 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false()) 15169 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean" 15170 * 15171 */ 15172 static void 15173 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) { 15174 xmlXPathObjectPtr str; 15175 int escape_reserved; 15176 xmlBufPtr target; 15177 xmlChar *cptr; 15178 xmlChar escape[4]; 15179 15180 CHECK_ARITY(2); 15181 15182 escape_reserved = xmlXPathPopBoolean(ctxt); 15183 15184 CAST_TO_STRING; 15185 str = valuePop(ctxt); 15186 15187 target = xmlBufCreate(); 15188 15189 escape[0] = '%'; 15190 escape[3] = 0; 15191 15192 if (target) { 15193 for (cptr = str->stringval; *cptr; cptr++) { 15194 if ((*cptr >= 'A' && *cptr <= 'Z') || 15195 (*cptr >= 'a' && *cptr <= 'z') || 15196 (*cptr >= '0' && *cptr <= '9') || 15197 *cptr == '-' || *cptr == '_' || *cptr == '.' || 15198 *cptr == '!' || *cptr == '~' || *cptr == '*' || 15199 *cptr == '\''|| *cptr == '(' || *cptr == ')' || 15200 (*cptr == '%' && 15201 ((cptr[1] >= 'A' && cptr[1] <= 'F') || 15202 (cptr[1] >= 'a' && cptr[1] <= 'f') || 15203 (cptr[1] >= '0' && cptr[1] <= '9')) && 15204 ((cptr[2] >= 'A' && cptr[2] <= 'F') || 15205 (cptr[2] >= 'a' && cptr[2] <= 'f') || 15206 (cptr[2] >= '0' && cptr[2] <= '9'))) || 15207 (!escape_reserved && 15208 (*cptr == ';' || *cptr == '/' || *cptr == '?' || 15209 *cptr == ':' || *cptr == '@' || *cptr == '&' || 15210 *cptr == '=' || *cptr == '+' || *cptr == '$' || 15211 *cptr == ','))) { 15212 xmlBufAdd(target, cptr, 1); 15213 } else { 15214 if ((*cptr >> 4) < 10) 15215 escape[1] = '0' + (*cptr >> 4); 15216 else 15217 escape[1] = 'A' - 10 + (*cptr >> 4); 15218 if ((*cptr & 0xF) < 10) 15219 escape[2] = '0' + (*cptr & 0xF); 15220 else 15221 escape[2] = 'A' - 10 + (*cptr & 0xF); 15222 15223 xmlBufAdd(target, &escape[0], 3); 15224 } 15225 } 15226 } 15227 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 15228 xmlBufContent(target))); 15229 xmlBufFree(target); 15230 xmlXPathReleaseObject(ctxt->context, str); 15231 } 15232 15233 /** 15234 * xmlXPathRegisterAllFunctions: 15235 * @ctxt: the XPath context 15236 * 15237 * Registers all default XPath functions in this context 15238 */ 15239 void 15240 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt) 15241 { 15242 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean", 15243 xmlXPathBooleanFunction); 15244 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling", 15245 xmlXPathCeilingFunction); 15246 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count", 15247 xmlXPathCountFunction); 15248 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat", 15249 xmlXPathConcatFunction); 15250 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains", 15251 xmlXPathContainsFunction); 15252 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id", 15253 xmlXPathIdFunction); 15254 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false", 15255 xmlXPathFalseFunction); 15256 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor", 15257 xmlXPathFloorFunction); 15258 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last", 15259 xmlXPathLastFunction); 15260 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang", 15261 xmlXPathLangFunction); 15262 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name", 15263 xmlXPathLocalNameFunction); 15264 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not", 15265 xmlXPathNotFunction); 15266 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name", 15267 xmlXPathNameFunction); 15268 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri", 15269 xmlXPathNamespaceURIFunction); 15270 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space", 15271 xmlXPathNormalizeFunction); 15272 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number", 15273 xmlXPathNumberFunction); 15274 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position", 15275 xmlXPathPositionFunction); 15276 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round", 15277 xmlXPathRoundFunction); 15278 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string", 15279 xmlXPathStringFunction); 15280 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length", 15281 xmlXPathStringLengthFunction); 15282 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with", 15283 xmlXPathStartsWithFunction); 15284 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring", 15285 xmlXPathSubstringFunction); 15286 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before", 15287 xmlXPathSubstringBeforeFunction); 15288 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after", 15289 xmlXPathSubstringAfterFunction); 15290 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum", 15291 xmlXPathSumFunction); 15292 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true", 15293 xmlXPathTrueFunction); 15294 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate", 15295 xmlXPathTranslateFunction); 15296 15297 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri", 15298 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions", 15299 xmlXPathEscapeUriFunction); 15300 } 15301 15302 #endif /* LIBXML_XPATH_ENABLED */ 15303 #define bottom_xpath 15304 #include "elfgcchack.h" 15305