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 #define IN_LIBXML 18 #include "libxml.h" 19 20 #include <string.h> 21 22 #ifdef HAVE_SYS_TYPES_H 23 #include <sys/types.h> 24 #endif 25 #ifdef HAVE_MATH_H 26 #include <math.h> 27 #endif 28 #ifdef HAVE_FLOAT_H 29 #include <float.h> 30 #endif 31 #ifdef HAVE_CTYPE_H 32 #include <ctype.h> 33 #endif 34 #ifdef HAVE_SIGNAL_H 35 #include <signal.h> 36 #endif 37 38 #include <libxml/xmlmemory.h> 39 #include <libxml/tree.h> 40 #include <libxml/valid.h> 41 #include <libxml/xpath.h> 42 #include <libxml/xpathInternals.h> 43 #include <libxml/parserInternals.h> 44 #include <libxml/hash.h> 45 #ifdef LIBXML_XPTR_ENABLED 46 #include <libxml/xpointer.h> 47 #endif 48 #ifdef LIBXML_DEBUG_ENABLED 49 #include <libxml/debugXML.h> 50 #endif 51 #include <libxml/xmlerror.h> 52 #include <libxml/threads.h> 53 #include <libxml/globals.h> 54 #ifdef LIBXML_PATTERN_ENABLED 55 #include <libxml/pattern.h> 56 #endif 57 58 #include "buf.h" 59 60 #ifdef LIBXML_PATTERN_ENABLED 61 #define XPATH_STREAMING 62 #endif 63 64 #define TODO \ 65 xmlGenericError(xmlGenericErrorContext, \ 66 "Unimplemented block at %s:%d\n", \ 67 __FILE__, __LINE__); 68 69 /** 70 * WITH_TIM_SORT: 71 * 72 * Use the Timsort algorithm provided in timsort.h to sort 73 * nodeset as this is a great improvement over the old Shell sort 74 * used in xmlXPathNodeSetSort() 75 */ 76 #define WITH_TIM_SORT 77 78 /* 79 * XP_OPTIMIZED_NON_ELEM_COMPARISON: 80 * If defined, this will use xmlXPathCmpNodesExt() instead of 81 * xmlXPathCmpNodes(). The new function is optimized comparison of 82 * non-element nodes; actually it will speed up comparison only if 83 * xmlXPathOrderDocElems() was called in order to index the elements of 84 * a tree in document order; Libxslt does such an indexing, thus it will 85 * benefit from this optimization. 86 */ 87 #define XP_OPTIMIZED_NON_ELEM_COMPARISON 88 89 /* 90 * XP_OPTIMIZED_FILTER_FIRST: 91 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]" 92 * in a way, that it stop evaluation at the first node. 93 */ 94 #define XP_OPTIMIZED_FILTER_FIRST 95 96 /* 97 * XP_DEBUG_OBJ_USAGE: 98 * Internal flag to enable tracking of how much XPath objects have been 99 * created. 100 */ 101 /* #define XP_DEBUG_OBJ_USAGE */ 102 103 /* 104 * XPATH_MAX_STEPS: 105 * when compiling an XPath expression we arbitrary limit the maximum 106 * number of step operation in the compiled expression. 1000000 is 107 * an insanely large value which should never be reached under normal 108 * circumstances 109 */ 110 #define XPATH_MAX_STEPS 1000000 111 112 /* 113 * XPATH_MAX_STACK_DEPTH: 114 * when evaluating an XPath expression we arbitrary limit the maximum 115 * number of object allowed to be pushed on the stack. 1000000 is 116 * an insanely large value which should never be reached under normal 117 * circumstances 118 */ 119 #define XPATH_MAX_STACK_DEPTH 1000000 120 121 /* 122 * XPATH_MAX_NODESET_LENGTH: 123 * when evaluating an XPath expression nodesets are created and we 124 * arbitrary limit the maximum length of those node set. 10000000 is 125 * an insanely large value which should never be reached under normal 126 * circumstances, one would first need to construct an in memory tree 127 * with more than 10 millions nodes. 128 */ 129 #define XPATH_MAX_NODESET_LENGTH 10000000 130 131 /* 132 * TODO: 133 * There are a few spots where some tests are done which depend upon ascii 134 * data. These should be enhanced for full UTF8 support (see particularly 135 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT) 136 */ 137 138 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 139 /** 140 * xmlXPathCmpNodesExt: 141 * @node1: the first node 142 * @node2: the second node 143 * 144 * Compare two nodes w.r.t document order. 145 * This one is optimized for handling of non-element nodes. 146 * 147 * Returns -2 in case of error 1 if first point < second point, 0 if 148 * it's the same node, -1 otherwise 149 */ 150 static int 151 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) { 152 int depth1, depth2; 153 int misc = 0, precedence1 = 0, precedence2 = 0; 154 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL; 155 xmlNodePtr cur, root; 156 long l1, l2; 157 158 if ((node1 == NULL) || (node2 == NULL)) 159 return(-2); 160 161 if (node1 == node2) 162 return(0); 163 164 /* 165 * a couple of optimizations which will avoid computations in most cases 166 */ 167 switch (node1->type) { 168 case XML_ELEMENT_NODE: 169 if (node2->type == XML_ELEMENT_NODE) { 170 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */ 171 (0 > (long) node2->content) && 172 (node1->doc == node2->doc)) 173 { 174 l1 = -((long) node1->content); 175 l2 = -((long) node2->content); 176 if (l1 < l2) 177 return(1); 178 if (l1 > l2) 179 return(-1); 180 } else 181 goto turtle_comparison; 182 } 183 break; 184 case XML_ATTRIBUTE_NODE: 185 precedence1 = 1; /* element is owner */ 186 miscNode1 = node1; 187 node1 = node1->parent; 188 misc = 1; 189 break; 190 case XML_TEXT_NODE: 191 case XML_CDATA_SECTION_NODE: 192 case XML_COMMENT_NODE: 193 case XML_PI_NODE: { 194 miscNode1 = node1; 195 /* 196 * Find nearest element node. 197 */ 198 if (node1->prev != NULL) { 199 do { 200 node1 = node1->prev; 201 if (node1->type == XML_ELEMENT_NODE) { 202 precedence1 = 3; /* element in prev-sibl axis */ 203 break; 204 } 205 if (node1->prev == NULL) { 206 precedence1 = 2; /* element is parent */ 207 /* 208 * URGENT TODO: Are there any cases, where the 209 * parent of such a node is not an element node? 210 */ 211 node1 = node1->parent; 212 break; 213 } 214 } while (1); 215 } else { 216 precedence1 = 2; /* element is parent */ 217 node1 = node1->parent; 218 } 219 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) || 220 (0 <= (long) node1->content)) { 221 /* 222 * Fallback for whatever case. 223 */ 224 node1 = miscNode1; 225 precedence1 = 0; 226 } else 227 misc = 1; 228 } 229 break; 230 case XML_NAMESPACE_DECL: 231 /* 232 * TODO: why do we return 1 for namespace nodes? 233 */ 234 return(1); 235 default: 236 break; 237 } 238 switch (node2->type) { 239 case XML_ELEMENT_NODE: 240 break; 241 case XML_ATTRIBUTE_NODE: 242 precedence2 = 1; /* element is owner */ 243 miscNode2 = node2; 244 node2 = node2->parent; 245 misc = 1; 246 break; 247 case XML_TEXT_NODE: 248 case XML_CDATA_SECTION_NODE: 249 case XML_COMMENT_NODE: 250 case XML_PI_NODE: { 251 miscNode2 = node2; 252 if (node2->prev != NULL) { 253 do { 254 node2 = node2->prev; 255 if (node2->type == XML_ELEMENT_NODE) { 256 precedence2 = 3; /* element in prev-sibl axis */ 257 break; 258 } 259 if (node2->prev == NULL) { 260 precedence2 = 2; /* element is parent */ 261 node2 = node2->parent; 262 break; 263 } 264 } while (1); 265 } else { 266 precedence2 = 2; /* element is parent */ 267 node2 = node2->parent; 268 } 269 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) || 270 (0 <= (long) node2->content)) 271 { 272 node2 = miscNode2; 273 precedence2 = 0; 274 } else 275 misc = 1; 276 } 277 break; 278 case XML_NAMESPACE_DECL: 279 return(1); 280 default: 281 break; 282 } 283 if (misc) { 284 if (node1 == node2) { 285 if (precedence1 == precedence2) { 286 /* 287 * The ugly case; but normally there aren't many 288 * adjacent non-element nodes around. 289 */ 290 cur = miscNode2->prev; 291 while (cur != NULL) { 292 if (cur == miscNode1) 293 return(1); 294 if (cur->type == XML_ELEMENT_NODE) 295 return(-1); 296 cur = cur->prev; 297 } 298 return (-1); 299 } else { 300 /* 301 * Evaluate based on higher precedence wrt to the element. 302 * TODO: This assumes attributes are sorted before content. 303 * Is this 100% correct? 304 */ 305 if (precedence1 < precedence2) 306 return(1); 307 else 308 return(-1); 309 } 310 } 311 /* 312 * Special case: One of the helper-elements is contained by the other. 313 * <foo> 314 * <node2> 315 * <node1>Text-1(precedence1 == 2)</node1> 316 * </node2> 317 * Text-6(precedence2 == 3) 318 * </foo> 319 */ 320 if ((precedence2 == 3) && (precedence1 > 1)) { 321 cur = node1->parent; 322 while (cur) { 323 if (cur == node2) 324 return(1); 325 cur = cur->parent; 326 } 327 } 328 if ((precedence1 == 3) && (precedence2 > 1)) { 329 cur = node2->parent; 330 while (cur) { 331 if (cur == node1) 332 return(-1); 333 cur = cur->parent; 334 } 335 } 336 } 337 338 /* 339 * Speedup using document order if availble. 340 */ 341 if ((node1->type == XML_ELEMENT_NODE) && 342 (node2->type == XML_ELEMENT_NODE) && 343 (0 > (long) node1->content) && 344 (0 > (long) node2->content) && 345 (node1->doc == node2->doc)) { 346 347 l1 = -((long) node1->content); 348 l2 = -((long) node2->content); 349 if (l1 < l2) 350 return(1); 351 if (l1 > l2) 352 return(-1); 353 } 354 355 turtle_comparison: 356 357 if (node1 == node2->prev) 358 return(1); 359 if (node1 == node2->next) 360 return(-1); 361 /* 362 * compute depth to root 363 */ 364 for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) { 365 if (cur->parent == node1) 366 return(1); 367 depth2++; 368 } 369 root = cur; 370 for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) { 371 if (cur->parent == node2) 372 return(-1); 373 depth1++; 374 } 375 /* 376 * Distinct document (or distinct entities :-( ) case. 377 */ 378 if (root != cur) { 379 return(-2); 380 } 381 /* 382 * get the nearest common ancestor. 383 */ 384 while (depth1 > depth2) { 385 depth1--; 386 node1 = node1->parent; 387 } 388 while (depth2 > depth1) { 389 depth2--; 390 node2 = node2->parent; 391 } 392 while (node1->parent != node2->parent) { 393 node1 = node1->parent; 394 node2 = node2->parent; 395 /* should not happen but just in case ... */ 396 if ((node1 == NULL) || (node2 == NULL)) 397 return(-2); 398 } 399 /* 400 * Find who's first. 401 */ 402 if (node1 == node2->prev) 403 return(1); 404 if (node1 == node2->next) 405 return(-1); 406 /* 407 * Speedup using document order if availble. 408 */ 409 if ((node1->type == XML_ELEMENT_NODE) && 410 (node2->type == XML_ELEMENT_NODE) && 411 (0 > (long) node1->content) && 412 (0 > (long) node2->content) && 413 (node1->doc == node2->doc)) { 414 415 l1 = -((long) node1->content); 416 l2 = -((long) node2->content); 417 if (l1 < l2) 418 return(1); 419 if (l1 > l2) 420 return(-1); 421 } 422 423 for (cur = node1->next;cur != NULL;cur = cur->next) 424 if (cur == node2) 425 return(1); 426 return(-1); /* assume there is no sibling list corruption */ 427 } 428 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */ 429 430 /* 431 * Wrapper for the Timsort argorithm from timsort.h 432 */ 433 #ifdef WITH_TIM_SORT 434 #define SORT_NAME libxml_domnode 435 #define SORT_TYPE xmlNodePtr 436 /** 437 * wrap_cmp: 438 * @x: a node 439 * @y: another node 440 * 441 * Comparison function for the Timsort implementation 442 * 443 * Returns -2 in case of error -1 if first point < second point, 0 if 444 * it's the same node, +1 otherwise 445 */ 446 static 447 int wrap_cmp( xmlNodePtr x, xmlNodePtr y ); 448 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 449 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y ) 450 { 451 int res = xmlXPathCmpNodesExt(x, y); 452 return res == -2 ? res : -res; 453 } 454 #else 455 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y ) 456 { 457 int res = xmlXPathCmpNodes(x, y); 458 return res == -2 ? res : -res; 459 } 460 #endif 461 #define SORT_CMP(x, y) (wrap_cmp(x, y)) 462 #include "timsort.h" 463 #endif /* WITH_TIM_SORT */ 464 465 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) 466 467 /************************************************************************ 468 * * 469 * Floating point stuff * 470 * * 471 ************************************************************************/ 472 473 #ifndef TRIO_REPLACE_STDIO 474 #define TRIO_PUBLIC static 475 #endif 476 #include "trionan.c" 477 478 /* 479 * The lack of portability of this section of the libc is annoying ! 480 */ 481 double xmlXPathNAN = 0; 482 double xmlXPathPINF = 1; 483 double xmlXPathNINF = -1; 484 static double xmlXPathNZERO = 0; /* not exported from headers */ 485 static int xmlXPathInitialized = 0; 486 487 /** 488 * xmlXPathInit: 489 * 490 * Initialize the XPath environment 491 */ 492 void 493 xmlXPathInit(void) { 494 if (xmlXPathInitialized) return; 495 496 xmlXPathPINF = trio_pinf(); 497 xmlXPathNINF = trio_ninf(); 498 xmlXPathNAN = trio_nan(); 499 xmlXPathNZERO = trio_nzero(); 500 501 xmlXPathInitialized = 1; 502 } 503 504 /** 505 * xmlXPathIsNaN: 506 * @val: a double value 507 * 508 * Provides a portable isnan() function to detect whether a double 509 * is a NotaNumber. Based on trio code 510 * http://sourceforge.net/projects/ctrio/ 511 * 512 * Returns 1 if the value is a NaN, 0 otherwise 513 */ 514 int 515 xmlXPathIsNaN(double val) { 516 return(trio_isnan(val)); 517 } 518 519 /** 520 * xmlXPathIsInf: 521 * @val: a double value 522 * 523 * Provides a portable isinf() function to detect whether a double 524 * is a +Infinite or -Infinite. Based on trio code 525 * http://sourceforge.net/projects/ctrio/ 526 * 527 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise 528 */ 529 int 530 xmlXPathIsInf(double val) { 531 return(trio_isinf(val)); 532 } 533 534 #endif /* SCHEMAS or XPATH */ 535 #ifdef LIBXML_XPATH_ENABLED 536 /** 537 * xmlXPathGetSign: 538 * @val: a double value 539 * 540 * Provides a portable function to detect the sign of a double 541 * Modified from trio code 542 * http://sourceforge.net/projects/ctrio/ 543 * 544 * Returns 1 if the value is Negative, 0 if positive 545 */ 546 static int 547 xmlXPathGetSign(double val) { 548 return(trio_signbit(val)); 549 } 550 551 552 /* 553 * TODO: when compatibility allows remove all "fake node libxslt" strings 554 * the test should just be name[0] = ' ' 555 */ 556 #ifdef DEBUG_XPATH_EXPRESSION 557 #define DEBUG_STEP 558 #define DEBUG_EXPR 559 #define DEBUG_EVAL_COUNTS 560 #endif 561 562 static xmlNs xmlXPathXMLNamespaceStruct = { 563 NULL, 564 XML_NAMESPACE_DECL, 565 XML_XML_NAMESPACE, 566 BAD_CAST "xml", 567 NULL, 568 NULL 569 }; 570 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct; 571 #ifndef LIBXML_THREAD_ENABLED 572 /* 573 * Optimizer is disabled only when threaded apps are detected while 574 * the library ain't compiled for thread safety. 575 */ 576 static int xmlXPathDisableOptimizer = 0; 577 #endif 578 579 /************************************************************************ 580 * * 581 * Error handling routines * 582 * * 583 ************************************************************************/ 584 585 /** 586 * XP_ERRORNULL: 587 * @X: the error code 588 * 589 * Macro to raise an XPath error and return NULL. 590 */ 591 #define XP_ERRORNULL(X) \ 592 { xmlXPathErr(ctxt, X); return(NULL); } 593 594 /* 595 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError 596 */ 597 static const char *xmlXPathErrorMessages[] = { 598 "Ok\n", 599 "Number encoding\n", 600 "Unfinished literal\n", 601 "Start of literal\n", 602 "Expected $ for variable reference\n", 603 "Undefined variable\n", 604 "Invalid predicate\n", 605 "Invalid expression\n", 606 "Missing closing curly brace\n", 607 "Unregistered function\n", 608 "Invalid operand\n", 609 "Invalid type\n", 610 "Invalid number of arguments\n", 611 "Invalid context size\n", 612 "Invalid context position\n", 613 "Memory allocation error\n", 614 "Syntax error\n", 615 "Resource error\n", 616 "Sub resource error\n", 617 "Undefined namespace prefix\n", 618 "Encoding error\n", 619 "Char out of XML range\n", 620 "Invalid or incomplete context\n", 621 "Stack usage error\n", 622 "Forbidden variable\n", 623 "?? Unknown error ??\n" /* Must be last in the list! */ 624 }; 625 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \ 626 sizeof(xmlXPathErrorMessages[0])) - 1) 627 /** 628 * xmlXPathErrMemory: 629 * @ctxt: an XPath context 630 * @extra: extra informations 631 * 632 * Handle a redefinition of attribute error 633 */ 634 static void 635 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra) 636 { 637 if (ctxt != NULL) { 638 if (extra) { 639 xmlChar buf[200]; 640 641 xmlStrPrintf(buf, 200, 642 "Memory allocation failed : %s\n", 643 extra); 644 ctxt->lastError.message = (char *) xmlStrdup(buf); 645 } else { 646 ctxt->lastError.message = (char *) 647 xmlStrdup(BAD_CAST "Memory allocation failed\n"); 648 } 649 ctxt->lastError.domain = XML_FROM_XPATH; 650 ctxt->lastError.code = XML_ERR_NO_MEMORY; 651 if (ctxt->error != NULL) 652 ctxt->error(ctxt->userData, &ctxt->lastError); 653 } else { 654 if (extra) 655 __xmlRaiseError(NULL, NULL, NULL, 656 NULL, NULL, XML_FROM_XPATH, 657 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, 658 extra, NULL, NULL, 0, 0, 659 "Memory allocation failed : %s\n", extra); 660 else 661 __xmlRaiseError(NULL, NULL, NULL, 662 NULL, NULL, XML_FROM_XPATH, 663 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, 664 NULL, NULL, NULL, 0, 0, 665 "Memory allocation failed\n"); 666 } 667 } 668 669 /** 670 * xmlXPathPErrMemory: 671 * @ctxt: an XPath parser context 672 * @extra: extra informations 673 * 674 * Handle a redefinition of attribute error 675 */ 676 static void 677 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra) 678 { 679 if (ctxt == NULL) 680 xmlXPathErrMemory(NULL, extra); 681 else { 682 ctxt->error = XPATH_MEMORY_ERROR; 683 xmlXPathErrMemory(ctxt->context, extra); 684 } 685 } 686 687 /** 688 * xmlXPathErr: 689 * @ctxt: a XPath parser context 690 * @error: the error code 691 * 692 * Handle an XPath error 693 */ 694 void 695 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error) 696 { 697 if ((error < 0) || (error > MAXERRNO)) 698 error = MAXERRNO; 699 if (ctxt == NULL) { 700 __xmlRaiseError(NULL, NULL, NULL, 701 NULL, NULL, XML_FROM_XPATH, 702 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, 703 XML_ERR_ERROR, NULL, 0, 704 NULL, NULL, NULL, 0, 0, 705 "%s", xmlXPathErrorMessages[error]); 706 return; 707 } 708 ctxt->error = error; 709 if (ctxt->context == NULL) { 710 __xmlRaiseError(NULL, NULL, NULL, 711 NULL, NULL, XML_FROM_XPATH, 712 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, 713 XML_ERR_ERROR, NULL, 0, 714 (const char *) ctxt->base, NULL, NULL, 715 ctxt->cur - ctxt->base, 0, 716 "%s", xmlXPathErrorMessages[error]); 717 return; 718 } 719 720 /* cleanup current last error */ 721 xmlResetError(&ctxt->context->lastError); 722 723 ctxt->context->lastError.domain = XML_FROM_XPATH; 724 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK - 725 XPATH_EXPRESSION_OK; 726 ctxt->context->lastError.level = XML_ERR_ERROR; 727 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base); 728 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base; 729 ctxt->context->lastError.node = ctxt->context->debugNode; 730 if (ctxt->context->error != NULL) { 731 ctxt->context->error(ctxt->context->userData, 732 &ctxt->context->lastError); 733 } else { 734 __xmlRaiseError(NULL, NULL, NULL, 735 NULL, ctxt->context->debugNode, XML_FROM_XPATH, 736 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, 737 XML_ERR_ERROR, NULL, 0, 738 (const char *) ctxt->base, NULL, NULL, 739 ctxt->cur - ctxt->base, 0, 740 "%s", xmlXPathErrorMessages[error]); 741 } 742 743 } 744 745 /** 746 * xmlXPatherror: 747 * @ctxt: the XPath Parser context 748 * @file: the file name 749 * @line: the line number 750 * @no: the error number 751 * 752 * Formats an error message. 753 */ 754 void 755 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED, 756 int line ATTRIBUTE_UNUSED, int no) { 757 xmlXPathErr(ctxt, no); 758 } 759 760 /************************************************************************ 761 * * 762 * Utilities * 763 * * 764 ************************************************************************/ 765 766 /** 767 * xsltPointerList: 768 * 769 * Pointer-list for various purposes. 770 */ 771 typedef struct _xmlPointerList xmlPointerList; 772 typedef xmlPointerList *xmlPointerListPtr; 773 struct _xmlPointerList { 774 void **items; 775 int number; 776 int size; 777 }; 778 /* 779 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt 780 * and here, we should make the functions public. 781 */ 782 static int 783 xmlPointerListAddSize(xmlPointerListPtr list, 784 void *item, 785 int initialSize) 786 { 787 if (list->items == NULL) { 788 if (initialSize <= 0) 789 initialSize = 1; 790 list->items = (void **) xmlMalloc(initialSize * sizeof(void *)); 791 if (list->items == NULL) { 792 xmlXPathErrMemory(NULL, 793 "xmlPointerListCreate: allocating item\n"); 794 return(-1); 795 } 796 list->number = 0; 797 list->size = initialSize; 798 } else if (list->size <= list->number) { 799 if (list->size > 50000000) { 800 xmlXPathErrMemory(NULL, 801 "xmlPointerListAddSize: re-allocating item\n"); 802 return(-1); 803 } 804 list->size *= 2; 805 list->items = (void **) xmlRealloc(list->items, 806 list->size * sizeof(void *)); 807 if (list->items == NULL) { 808 xmlXPathErrMemory(NULL, 809 "xmlPointerListAddSize: re-allocating item\n"); 810 list->size = 0; 811 return(-1); 812 } 813 } 814 list->items[list->number++] = item; 815 return(0); 816 } 817 818 /** 819 * xsltPointerListCreate: 820 * 821 * Creates an xsltPointerList structure. 822 * 823 * Returns a xsltPointerList structure or NULL in case of an error. 824 */ 825 static xmlPointerListPtr 826 xmlPointerListCreate(int initialSize) 827 { 828 xmlPointerListPtr ret; 829 830 ret = xmlMalloc(sizeof(xmlPointerList)); 831 if (ret == NULL) { 832 xmlXPathErrMemory(NULL, 833 "xmlPointerListCreate: allocating item\n"); 834 return (NULL); 835 } 836 memset(ret, 0, sizeof(xmlPointerList)); 837 if (initialSize > 0) { 838 xmlPointerListAddSize(ret, NULL, initialSize); 839 ret->number = 0; 840 } 841 return (ret); 842 } 843 844 /** 845 * xsltPointerListFree: 846 * 847 * Frees the xsltPointerList structure. This does not free 848 * the content of the list. 849 */ 850 static void 851 xmlPointerListFree(xmlPointerListPtr list) 852 { 853 if (list == NULL) 854 return; 855 if (list->items != NULL) 856 xmlFree(list->items); 857 xmlFree(list); 858 } 859 860 /************************************************************************ 861 * * 862 * Parser Types * 863 * * 864 ************************************************************************/ 865 866 /* 867 * Types are private: 868 */ 869 870 typedef enum { 871 XPATH_OP_END=0, 872 XPATH_OP_AND, 873 XPATH_OP_OR, 874 XPATH_OP_EQUAL, 875 XPATH_OP_CMP, 876 XPATH_OP_PLUS, 877 XPATH_OP_MULT, 878 XPATH_OP_UNION, 879 XPATH_OP_ROOT, 880 XPATH_OP_NODE, 881 XPATH_OP_RESET, /* 10 */ 882 XPATH_OP_COLLECT, 883 XPATH_OP_VALUE, /* 12 */ 884 XPATH_OP_VARIABLE, 885 XPATH_OP_FUNCTION, 886 XPATH_OP_ARG, 887 XPATH_OP_PREDICATE, 888 XPATH_OP_FILTER, /* 17 */ 889 XPATH_OP_SORT /* 18 */ 890 #ifdef LIBXML_XPTR_ENABLED 891 ,XPATH_OP_RANGETO 892 #endif 893 } xmlXPathOp; 894 895 typedef enum { 896 AXIS_ANCESTOR = 1, 897 AXIS_ANCESTOR_OR_SELF, 898 AXIS_ATTRIBUTE, 899 AXIS_CHILD, 900 AXIS_DESCENDANT, 901 AXIS_DESCENDANT_OR_SELF, 902 AXIS_FOLLOWING, 903 AXIS_FOLLOWING_SIBLING, 904 AXIS_NAMESPACE, 905 AXIS_PARENT, 906 AXIS_PRECEDING, 907 AXIS_PRECEDING_SIBLING, 908 AXIS_SELF 909 } xmlXPathAxisVal; 910 911 typedef enum { 912 NODE_TEST_NONE = 0, 913 NODE_TEST_TYPE = 1, 914 NODE_TEST_PI = 2, 915 NODE_TEST_ALL = 3, 916 NODE_TEST_NS = 4, 917 NODE_TEST_NAME = 5 918 } xmlXPathTestVal; 919 920 typedef enum { 921 NODE_TYPE_NODE = 0, 922 NODE_TYPE_COMMENT = XML_COMMENT_NODE, 923 NODE_TYPE_TEXT = XML_TEXT_NODE, 924 NODE_TYPE_PI = XML_PI_NODE 925 } xmlXPathTypeVal; 926 927 typedef struct _xmlXPathStepOp xmlXPathStepOp; 928 typedef xmlXPathStepOp *xmlXPathStepOpPtr; 929 struct _xmlXPathStepOp { 930 xmlXPathOp op; /* The identifier of the operation */ 931 int ch1; /* First child */ 932 int ch2; /* Second child */ 933 int value; 934 int value2; 935 int value3; 936 void *value4; 937 void *value5; 938 void *cache; 939 void *cacheURI; 940 }; 941 942 struct _xmlXPathCompExpr { 943 int nbStep; /* Number of steps in this expression */ 944 int maxStep; /* Maximum number of steps allocated */ 945 xmlXPathStepOp *steps; /* ops for computation of this expression */ 946 int last; /* index of last step in expression */ 947 xmlChar *expr; /* the expression being computed */ 948 xmlDictPtr dict; /* the dictionary to use if any */ 949 #ifdef DEBUG_EVAL_COUNTS 950 int nb; 951 xmlChar *string; 952 #endif 953 #ifdef XPATH_STREAMING 954 xmlPatternPtr stream; 955 #endif 956 }; 957 958 /************************************************************************ 959 * * 960 * Forward declarations * 961 * * 962 ************************************************************************/ 963 static void 964 xmlXPathFreeValueTree(xmlNodeSetPtr obj); 965 static void 966 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj); 967 static int 968 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt, 969 xmlXPathStepOpPtr op, xmlNodePtr *first); 970 static int 971 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt, 972 xmlXPathStepOpPtr op, 973 int isPredicate); 974 975 /************************************************************************ 976 * * 977 * Parser Type functions * 978 * * 979 ************************************************************************/ 980 981 /** 982 * xmlXPathNewCompExpr: 983 * 984 * Create a new Xpath component 985 * 986 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error 987 */ 988 static xmlXPathCompExprPtr 989 xmlXPathNewCompExpr(void) { 990 xmlXPathCompExprPtr cur; 991 992 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr)); 993 if (cur == NULL) { 994 xmlXPathErrMemory(NULL, "allocating component\n"); 995 return(NULL); 996 } 997 memset(cur, 0, sizeof(xmlXPathCompExpr)); 998 cur->maxStep = 10; 999 cur->nbStep = 0; 1000 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep * 1001 sizeof(xmlXPathStepOp)); 1002 if (cur->steps == NULL) { 1003 xmlXPathErrMemory(NULL, "allocating steps\n"); 1004 xmlFree(cur); 1005 return(NULL); 1006 } 1007 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp)); 1008 cur->last = -1; 1009 #ifdef DEBUG_EVAL_COUNTS 1010 cur->nb = 0; 1011 #endif 1012 return(cur); 1013 } 1014 1015 /** 1016 * xmlXPathFreeCompExpr: 1017 * @comp: an XPATH comp 1018 * 1019 * Free up the memory allocated by @comp 1020 */ 1021 void 1022 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp) 1023 { 1024 xmlXPathStepOpPtr op; 1025 int i; 1026 1027 if (comp == NULL) 1028 return; 1029 if (comp->dict == NULL) { 1030 for (i = 0; i < comp->nbStep; i++) { 1031 op = &comp->steps[i]; 1032 if (op->value4 != NULL) { 1033 if (op->op == XPATH_OP_VALUE) 1034 xmlXPathFreeObject(op->value4); 1035 else 1036 xmlFree(op->value4); 1037 } 1038 if (op->value5 != NULL) 1039 xmlFree(op->value5); 1040 } 1041 } else { 1042 for (i = 0; i < comp->nbStep; i++) { 1043 op = &comp->steps[i]; 1044 if (op->value4 != NULL) { 1045 if (op->op == XPATH_OP_VALUE) 1046 xmlXPathFreeObject(op->value4); 1047 } 1048 } 1049 xmlDictFree(comp->dict); 1050 } 1051 if (comp->steps != NULL) { 1052 xmlFree(comp->steps); 1053 } 1054 #ifdef DEBUG_EVAL_COUNTS 1055 if (comp->string != NULL) { 1056 xmlFree(comp->string); 1057 } 1058 #endif 1059 #ifdef XPATH_STREAMING 1060 if (comp->stream != NULL) { 1061 xmlFreePatternList(comp->stream); 1062 } 1063 #endif 1064 if (comp->expr != NULL) { 1065 xmlFree(comp->expr); 1066 } 1067 1068 xmlFree(comp); 1069 } 1070 1071 /** 1072 * xmlXPathCompExprAdd: 1073 * @comp: the compiled expression 1074 * @ch1: first child index 1075 * @ch2: second child index 1076 * @op: an op 1077 * @value: the first int value 1078 * @value2: the second int value 1079 * @value3: the third int value 1080 * @value4: the first string value 1081 * @value5: the second string value 1082 * 1083 * Add a step to an XPath Compiled Expression 1084 * 1085 * Returns -1 in case of failure, the index otherwise 1086 */ 1087 static int 1088 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2, 1089 xmlXPathOp op, int value, 1090 int value2, int value3, void *value4, void *value5) { 1091 if (comp->nbStep >= comp->maxStep) { 1092 xmlXPathStepOp *real; 1093 1094 if (comp->maxStep >= XPATH_MAX_STEPS) { 1095 xmlXPathErrMemory(NULL, "adding step\n"); 1096 return(-1); 1097 } 1098 comp->maxStep *= 2; 1099 real = (xmlXPathStepOp *) xmlRealloc(comp->steps, 1100 comp->maxStep * sizeof(xmlXPathStepOp)); 1101 if (real == NULL) { 1102 comp->maxStep /= 2; 1103 xmlXPathErrMemory(NULL, "adding step\n"); 1104 return(-1); 1105 } 1106 comp->steps = real; 1107 } 1108 comp->last = comp->nbStep; 1109 comp->steps[comp->nbStep].ch1 = ch1; 1110 comp->steps[comp->nbStep].ch2 = ch2; 1111 comp->steps[comp->nbStep].op = op; 1112 comp->steps[comp->nbStep].value = value; 1113 comp->steps[comp->nbStep].value2 = value2; 1114 comp->steps[comp->nbStep].value3 = value3; 1115 if ((comp->dict != NULL) && 1116 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) || 1117 (op == XPATH_OP_COLLECT))) { 1118 if (value4 != NULL) { 1119 comp->steps[comp->nbStep].value4 = (xmlChar *) 1120 (void *)xmlDictLookup(comp->dict, value4, -1); 1121 xmlFree(value4); 1122 } else 1123 comp->steps[comp->nbStep].value4 = NULL; 1124 if (value5 != NULL) { 1125 comp->steps[comp->nbStep].value5 = (xmlChar *) 1126 (void *)xmlDictLookup(comp->dict, value5, -1); 1127 xmlFree(value5); 1128 } else 1129 comp->steps[comp->nbStep].value5 = NULL; 1130 } else { 1131 comp->steps[comp->nbStep].value4 = value4; 1132 comp->steps[comp->nbStep].value5 = value5; 1133 } 1134 comp->steps[comp->nbStep].cache = NULL; 1135 return(comp->nbStep++); 1136 } 1137 1138 /** 1139 * xmlXPathCompSwap: 1140 * @comp: the compiled expression 1141 * @op: operation index 1142 * 1143 * Swaps 2 operations in the compiled expression 1144 */ 1145 static void 1146 xmlXPathCompSwap(xmlXPathStepOpPtr op) { 1147 int tmp; 1148 1149 #ifndef LIBXML_THREAD_ENABLED 1150 /* 1151 * Since this manipulates possibly shared variables, this is 1152 * disabled if one detects that the library is used in a multithreaded 1153 * application 1154 */ 1155 if (xmlXPathDisableOptimizer) 1156 return; 1157 #endif 1158 1159 tmp = op->ch1; 1160 op->ch1 = op->ch2; 1161 op->ch2 = tmp; 1162 } 1163 1164 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \ 1165 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \ 1166 (op), (val), (val2), (val3), (val4), (val5)) 1167 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \ 1168 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \ 1169 (op), (val), (val2), (val3), (val4), (val5)) 1170 1171 #define PUSH_LEAVE_EXPR(op, val, val2) \ 1172 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL) 1173 1174 #define PUSH_UNARY_EXPR(op, ch, val, val2) \ 1175 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL) 1176 1177 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \ 1178 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \ 1179 (val), (val2), 0 ,NULL ,NULL) 1180 1181 /************************************************************************ 1182 * * 1183 * XPath object cache structures * 1184 * * 1185 ************************************************************************/ 1186 1187 /* #define XP_DEFAULT_CACHE_ON */ 1188 1189 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL)) 1190 1191 typedef struct _xmlXPathContextCache xmlXPathContextCache; 1192 typedef xmlXPathContextCache *xmlXPathContextCachePtr; 1193 struct _xmlXPathContextCache { 1194 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */ 1195 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */ 1196 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */ 1197 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */ 1198 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */ 1199 int maxNodeset; 1200 int maxString; 1201 int maxBoolean; 1202 int maxNumber; 1203 int maxMisc; 1204 #ifdef XP_DEBUG_OBJ_USAGE 1205 int dbgCachedAll; 1206 int dbgCachedNodeset; 1207 int dbgCachedString; 1208 int dbgCachedBool; 1209 int dbgCachedNumber; 1210 int dbgCachedPoint; 1211 int dbgCachedRange; 1212 int dbgCachedLocset; 1213 int dbgCachedUsers; 1214 int dbgCachedXSLTTree; 1215 int dbgCachedUndefined; 1216 1217 1218 int dbgReusedAll; 1219 int dbgReusedNodeset; 1220 int dbgReusedString; 1221 int dbgReusedBool; 1222 int dbgReusedNumber; 1223 int dbgReusedPoint; 1224 int dbgReusedRange; 1225 int dbgReusedLocset; 1226 int dbgReusedUsers; 1227 int dbgReusedXSLTTree; 1228 int dbgReusedUndefined; 1229 1230 #endif 1231 }; 1232 1233 /************************************************************************ 1234 * * 1235 * Debugging related functions * 1236 * * 1237 ************************************************************************/ 1238 1239 #define STRANGE \ 1240 xmlGenericError(xmlGenericErrorContext, \ 1241 "Internal error at %s:%d\n", \ 1242 __FILE__, __LINE__); 1243 1244 #ifdef LIBXML_DEBUG_ENABLED 1245 static void 1246 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) { 1247 int i; 1248 char shift[100]; 1249 1250 for (i = 0;((i < depth) && (i < 25));i++) 1251 shift[2 * i] = shift[2 * i + 1] = ' '; 1252 shift[2 * i] = shift[2 * i + 1] = 0; 1253 if (cur == NULL) { 1254 fprintf(output, "%s", shift); 1255 fprintf(output, "Node is NULL !\n"); 1256 return; 1257 1258 } 1259 1260 if ((cur->type == XML_DOCUMENT_NODE) || 1261 (cur->type == XML_HTML_DOCUMENT_NODE)) { 1262 fprintf(output, "%s", shift); 1263 fprintf(output, " /\n"); 1264 } else if (cur->type == XML_ATTRIBUTE_NODE) 1265 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth); 1266 else 1267 xmlDebugDumpOneNode(output, cur, depth); 1268 } 1269 static void 1270 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) { 1271 xmlNodePtr tmp; 1272 int i; 1273 char shift[100]; 1274 1275 for (i = 0;((i < depth) && (i < 25));i++) 1276 shift[2 * i] = shift[2 * i + 1] = ' '; 1277 shift[2 * i] = shift[2 * i + 1] = 0; 1278 if (cur == NULL) { 1279 fprintf(output, "%s", shift); 1280 fprintf(output, "Node is NULL !\n"); 1281 return; 1282 1283 } 1284 1285 while (cur != NULL) { 1286 tmp = cur; 1287 cur = cur->next; 1288 xmlDebugDumpOneNode(output, tmp, depth); 1289 } 1290 } 1291 1292 static void 1293 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) { 1294 int i; 1295 char shift[100]; 1296 1297 for (i = 0;((i < depth) && (i < 25));i++) 1298 shift[2 * i] = shift[2 * i + 1] = ' '; 1299 shift[2 * i] = shift[2 * i + 1] = 0; 1300 1301 if (cur == NULL) { 1302 fprintf(output, "%s", shift); 1303 fprintf(output, "NodeSet is NULL !\n"); 1304 return; 1305 1306 } 1307 1308 if (cur != NULL) { 1309 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr); 1310 for (i = 0;i < cur->nodeNr;i++) { 1311 fprintf(output, "%s", shift); 1312 fprintf(output, "%d", i + 1); 1313 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1); 1314 } 1315 } 1316 } 1317 1318 static void 1319 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) { 1320 int i; 1321 char shift[100]; 1322 1323 for (i = 0;((i < depth) && (i < 25));i++) 1324 shift[2 * i] = shift[2 * i + 1] = ' '; 1325 shift[2 * i] = shift[2 * i + 1] = 0; 1326 1327 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) { 1328 fprintf(output, "%s", shift); 1329 fprintf(output, "Value Tree is NULL !\n"); 1330 return; 1331 1332 } 1333 1334 fprintf(output, "%s", shift); 1335 fprintf(output, "%d", i + 1); 1336 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1); 1337 } 1338 #if defined(LIBXML_XPTR_ENABLED) 1339 static void 1340 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) { 1341 int i; 1342 char shift[100]; 1343 1344 for (i = 0;((i < depth) && (i < 25));i++) 1345 shift[2 * i] = shift[2 * i + 1] = ' '; 1346 shift[2 * i] = shift[2 * i + 1] = 0; 1347 1348 if (cur == NULL) { 1349 fprintf(output, "%s", shift); 1350 fprintf(output, "LocationSet is NULL !\n"); 1351 return; 1352 1353 } 1354 1355 for (i = 0;i < cur->locNr;i++) { 1356 fprintf(output, "%s", shift); 1357 fprintf(output, "%d : ", i + 1); 1358 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1); 1359 } 1360 } 1361 #endif /* LIBXML_XPTR_ENABLED */ 1362 1363 /** 1364 * xmlXPathDebugDumpObject: 1365 * @output: the FILE * to dump the output 1366 * @cur: the object to inspect 1367 * @depth: indentation level 1368 * 1369 * Dump the content of the object for debugging purposes 1370 */ 1371 void 1372 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) { 1373 int i; 1374 char shift[100]; 1375 1376 if (output == NULL) return; 1377 1378 for (i = 0;((i < depth) && (i < 25));i++) 1379 shift[2 * i] = shift[2 * i + 1] = ' '; 1380 shift[2 * i] = shift[2 * i + 1] = 0; 1381 1382 1383 fprintf(output, "%s", shift); 1384 1385 if (cur == NULL) { 1386 fprintf(output, "Object is empty (NULL)\n"); 1387 return; 1388 } 1389 switch(cur->type) { 1390 case XPATH_UNDEFINED: 1391 fprintf(output, "Object is uninitialized\n"); 1392 break; 1393 case XPATH_NODESET: 1394 fprintf(output, "Object is a Node Set :\n"); 1395 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth); 1396 break; 1397 case XPATH_XSLT_TREE: 1398 fprintf(output, "Object is an XSLT value tree :\n"); 1399 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth); 1400 break; 1401 case XPATH_BOOLEAN: 1402 fprintf(output, "Object is a Boolean : "); 1403 if (cur->boolval) fprintf(output, "true\n"); 1404 else fprintf(output, "false\n"); 1405 break; 1406 case XPATH_NUMBER: 1407 switch (xmlXPathIsInf(cur->floatval)) { 1408 case 1: 1409 fprintf(output, "Object is a number : Infinity\n"); 1410 break; 1411 case -1: 1412 fprintf(output, "Object is a number : -Infinity\n"); 1413 break; 1414 default: 1415 if (xmlXPathIsNaN(cur->floatval)) { 1416 fprintf(output, "Object is a number : NaN\n"); 1417 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) { 1418 fprintf(output, "Object is a number : 0\n"); 1419 } else { 1420 fprintf(output, "Object is a number : %0g\n", cur->floatval); 1421 } 1422 } 1423 break; 1424 case XPATH_STRING: 1425 fprintf(output, "Object is a string : "); 1426 xmlDebugDumpString(output, cur->stringval); 1427 fprintf(output, "\n"); 1428 break; 1429 case XPATH_POINT: 1430 fprintf(output, "Object is a point : index %d in node", cur->index); 1431 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1); 1432 fprintf(output, "\n"); 1433 break; 1434 case XPATH_RANGE: 1435 if ((cur->user2 == NULL) || 1436 ((cur->user2 == cur->user) && (cur->index == cur->index2))) { 1437 fprintf(output, "Object is a collapsed range :\n"); 1438 fprintf(output, "%s", shift); 1439 if (cur->index >= 0) 1440 fprintf(output, "index %d in ", cur->index); 1441 fprintf(output, "node\n"); 1442 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, 1443 depth + 1); 1444 } else { 1445 fprintf(output, "Object is a range :\n"); 1446 fprintf(output, "%s", shift); 1447 fprintf(output, "From "); 1448 if (cur->index >= 0) 1449 fprintf(output, "index %d in ", cur->index); 1450 fprintf(output, "node\n"); 1451 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, 1452 depth + 1); 1453 fprintf(output, "%s", shift); 1454 fprintf(output, "To "); 1455 if (cur->index2 >= 0) 1456 fprintf(output, "index %d in ", cur->index2); 1457 fprintf(output, "node\n"); 1458 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2, 1459 depth + 1); 1460 fprintf(output, "\n"); 1461 } 1462 break; 1463 case XPATH_LOCATIONSET: 1464 #if defined(LIBXML_XPTR_ENABLED) 1465 fprintf(output, "Object is a Location Set:\n"); 1466 xmlXPathDebugDumpLocationSet(output, 1467 (xmlLocationSetPtr) cur->user, depth); 1468 #endif 1469 break; 1470 case XPATH_USERS: 1471 fprintf(output, "Object is user defined\n"); 1472 break; 1473 } 1474 } 1475 1476 static void 1477 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp, 1478 xmlXPathStepOpPtr op, int depth) { 1479 int i; 1480 char shift[100]; 1481 1482 for (i = 0;((i < depth) && (i < 25));i++) 1483 shift[2 * i] = shift[2 * i + 1] = ' '; 1484 shift[2 * i] = shift[2 * i + 1] = 0; 1485 1486 fprintf(output, "%s", shift); 1487 if (op == NULL) { 1488 fprintf(output, "Step is NULL\n"); 1489 return; 1490 } 1491 switch (op->op) { 1492 case XPATH_OP_END: 1493 fprintf(output, "END"); break; 1494 case XPATH_OP_AND: 1495 fprintf(output, "AND"); break; 1496 case XPATH_OP_OR: 1497 fprintf(output, "OR"); break; 1498 case XPATH_OP_EQUAL: 1499 if (op->value) 1500 fprintf(output, "EQUAL ="); 1501 else 1502 fprintf(output, "EQUAL !="); 1503 break; 1504 case XPATH_OP_CMP: 1505 if (op->value) 1506 fprintf(output, "CMP <"); 1507 else 1508 fprintf(output, "CMP >"); 1509 if (!op->value2) 1510 fprintf(output, "="); 1511 break; 1512 case XPATH_OP_PLUS: 1513 if (op->value == 0) 1514 fprintf(output, "PLUS -"); 1515 else if (op->value == 1) 1516 fprintf(output, "PLUS +"); 1517 else if (op->value == 2) 1518 fprintf(output, "PLUS unary -"); 1519 else if (op->value == 3) 1520 fprintf(output, "PLUS unary - -"); 1521 break; 1522 case XPATH_OP_MULT: 1523 if (op->value == 0) 1524 fprintf(output, "MULT *"); 1525 else if (op->value == 1) 1526 fprintf(output, "MULT div"); 1527 else 1528 fprintf(output, "MULT mod"); 1529 break; 1530 case XPATH_OP_UNION: 1531 fprintf(output, "UNION"); break; 1532 case XPATH_OP_ROOT: 1533 fprintf(output, "ROOT"); break; 1534 case XPATH_OP_NODE: 1535 fprintf(output, "NODE"); break; 1536 case XPATH_OP_RESET: 1537 fprintf(output, "RESET"); break; 1538 case XPATH_OP_SORT: 1539 fprintf(output, "SORT"); break; 1540 case XPATH_OP_COLLECT: { 1541 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value; 1542 xmlXPathTestVal test = (xmlXPathTestVal)op->value2; 1543 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3; 1544 const xmlChar *prefix = op->value4; 1545 const xmlChar *name = op->value5; 1546 1547 fprintf(output, "COLLECT "); 1548 switch (axis) { 1549 case AXIS_ANCESTOR: 1550 fprintf(output, " 'ancestors' "); break; 1551 case AXIS_ANCESTOR_OR_SELF: 1552 fprintf(output, " 'ancestors-or-self' "); break; 1553 case AXIS_ATTRIBUTE: 1554 fprintf(output, " 'attributes' "); break; 1555 case AXIS_CHILD: 1556 fprintf(output, " 'child' "); break; 1557 case AXIS_DESCENDANT: 1558 fprintf(output, " 'descendant' "); break; 1559 case AXIS_DESCENDANT_OR_SELF: 1560 fprintf(output, " 'descendant-or-self' "); break; 1561 case AXIS_FOLLOWING: 1562 fprintf(output, " 'following' "); break; 1563 case AXIS_FOLLOWING_SIBLING: 1564 fprintf(output, " 'following-siblings' "); break; 1565 case AXIS_NAMESPACE: 1566 fprintf(output, " 'namespace' "); break; 1567 case AXIS_PARENT: 1568 fprintf(output, " 'parent' "); break; 1569 case AXIS_PRECEDING: 1570 fprintf(output, " 'preceding' "); break; 1571 case AXIS_PRECEDING_SIBLING: 1572 fprintf(output, " 'preceding-sibling' "); break; 1573 case AXIS_SELF: 1574 fprintf(output, " 'self' "); break; 1575 } 1576 switch (test) { 1577 case NODE_TEST_NONE: 1578 fprintf(output, "'none' "); break; 1579 case NODE_TEST_TYPE: 1580 fprintf(output, "'type' "); break; 1581 case NODE_TEST_PI: 1582 fprintf(output, "'PI' "); break; 1583 case NODE_TEST_ALL: 1584 fprintf(output, "'all' "); break; 1585 case NODE_TEST_NS: 1586 fprintf(output, "'namespace' "); break; 1587 case NODE_TEST_NAME: 1588 fprintf(output, "'name' "); break; 1589 } 1590 switch (type) { 1591 case NODE_TYPE_NODE: 1592 fprintf(output, "'node' "); break; 1593 case NODE_TYPE_COMMENT: 1594 fprintf(output, "'comment' "); break; 1595 case NODE_TYPE_TEXT: 1596 fprintf(output, "'text' "); break; 1597 case NODE_TYPE_PI: 1598 fprintf(output, "'PI' "); break; 1599 } 1600 if (prefix != NULL) 1601 fprintf(output, "%s:", prefix); 1602 if (name != NULL) 1603 fprintf(output, "%s", (const char *) name); 1604 break; 1605 1606 } 1607 case XPATH_OP_VALUE: { 1608 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4; 1609 1610 fprintf(output, "ELEM "); 1611 xmlXPathDebugDumpObject(output, object, 0); 1612 goto finish; 1613 } 1614 case XPATH_OP_VARIABLE: { 1615 const xmlChar *prefix = op->value5; 1616 const xmlChar *name = op->value4; 1617 1618 if (prefix != NULL) 1619 fprintf(output, "VARIABLE %s:%s", prefix, name); 1620 else 1621 fprintf(output, "VARIABLE %s", name); 1622 break; 1623 } 1624 case XPATH_OP_FUNCTION: { 1625 int nbargs = op->value; 1626 const xmlChar *prefix = op->value5; 1627 const xmlChar *name = op->value4; 1628 1629 if (prefix != NULL) 1630 fprintf(output, "FUNCTION %s:%s(%d args)", 1631 prefix, name, nbargs); 1632 else 1633 fprintf(output, "FUNCTION %s(%d args)", name, nbargs); 1634 break; 1635 } 1636 case XPATH_OP_ARG: fprintf(output, "ARG"); break; 1637 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break; 1638 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break; 1639 #ifdef LIBXML_XPTR_ENABLED 1640 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break; 1641 #endif 1642 default: 1643 fprintf(output, "UNKNOWN %d\n", op->op); return; 1644 } 1645 fprintf(output, "\n"); 1646 finish: 1647 if (op->ch1 >= 0) 1648 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1); 1649 if (op->ch2 >= 0) 1650 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1); 1651 } 1652 1653 /** 1654 * xmlXPathDebugDumpCompExpr: 1655 * @output: the FILE * for the output 1656 * @comp: the precompiled XPath expression 1657 * @depth: the indentation level. 1658 * 1659 * Dumps the tree of the compiled XPath expression. 1660 */ 1661 void 1662 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp, 1663 int depth) { 1664 int i; 1665 char shift[100]; 1666 1667 if ((output == NULL) || (comp == NULL)) return; 1668 1669 for (i = 0;((i < depth) && (i < 25));i++) 1670 shift[2 * i] = shift[2 * i + 1] = ' '; 1671 shift[2 * i] = shift[2 * i + 1] = 0; 1672 1673 fprintf(output, "%s", shift); 1674 1675 fprintf(output, "Compiled Expression : %d elements\n", 1676 comp->nbStep); 1677 i = comp->last; 1678 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1); 1679 } 1680 1681 #ifdef XP_DEBUG_OBJ_USAGE 1682 1683 /* 1684 * XPath object usage related debugging variables. 1685 */ 1686 static int xmlXPathDebugObjCounterUndefined = 0; 1687 static int xmlXPathDebugObjCounterNodeset = 0; 1688 static int xmlXPathDebugObjCounterBool = 0; 1689 static int xmlXPathDebugObjCounterNumber = 0; 1690 static int xmlXPathDebugObjCounterString = 0; 1691 static int xmlXPathDebugObjCounterPoint = 0; 1692 static int xmlXPathDebugObjCounterRange = 0; 1693 static int xmlXPathDebugObjCounterLocset = 0; 1694 static int xmlXPathDebugObjCounterUsers = 0; 1695 static int xmlXPathDebugObjCounterXSLTTree = 0; 1696 static int xmlXPathDebugObjCounterAll = 0; 1697 1698 static int xmlXPathDebugObjTotalUndefined = 0; 1699 static int xmlXPathDebugObjTotalNodeset = 0; 1700 static int xmlXPathDebugObjTotalBool = 0; 1701 static int xmlXPathDebugObjTotalNumber = 0; 1702 static int xmlXPathDebugObjTotalString = 0; 1703 static int xmlXPathDebugObjTotalPoint = 0; 1704 static int xmlXPathDebugObjTotalRange = 0; 1705 static int xmlXPathDebugObjTotalLocset = 0; 1706 static int xmlXPathDebugObjTotalUsers = 0; 1707 static int xmlXPathDebugObjTotalXSLTTree = 0; 1708 static int xmlXPathDebugObjTotalAll = 0; 1709 1710 static int xmlXPathDebugObjMaxUndefined = 0; 1711 static int xmlXPathDebugObjMaxNodeset = 0; 1712 static int xmlXPathDebugObjMaxBool = 0; 1713 static int xmlXPathDebugObjMaxNumber = 0; 1714 static int xmlXPathDebugObjMaxString = 0; 1715 static int xmlXPathDebugObjMaxPoint = 0; 1716 static int xmlXPathDebugObjMaxRange = 0; 1717 static int xmlXPathDebugObjMaxLocset = 0; 1718 static int xmlXPathDebugObjMaxUsers = 0; 1719 static int xmlXPathDebugObjMaxXSLTTree = 0; 1720 static int xmlXPathDebugObjMaxAll = 0; 1721 1722 /* REVISIT TODO: Make this static when committing */ 1723 static void 1724 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt) 1725 { 1726 if (ctxt != NULL) { 1727 if (ctxt->cache != NULL) { 1728 xmlXPathContextCachePtr cache = 1729 (xmlXPathContextCachePtr) ctxt->cache; 1730 1731 cache->dbgCachedAll = 0; 1732 cache->dbgCachedNodeset = 0; 1733 cache->dbgCachedString = 0; 1734 cache->dbgCachedBool = 0; 1735 cache->dbgCachedNumber = 0; 1736 cache->dbgCachedPoint = 0; 1737 cache->dbgCachedRange = 0; 1738 cache->dbgCachedLocset = 0; 1739 cache->dbgCachedUsers = 0; 1740 cache->dbgCachedXSLTTree = 0; 1741 cache->dbgCachedUndefined = 0; 1742 1743 cache->dbgReusedAll = 0; 1744 cache->dbgReusedNodeset = 0; 1745 cache->dbgReusedString = 0; 1746 cache->dbgReusedBool = 0; 1747 cache->dbgReusedNumber = 0; 1748 cache->dbgReusedPoint = 0; 1749 cache->dbgReusedRange = 0; 1750 cache->dbgReusedLocset = 0; 1751 cache->dbgReusedUsers = 0; 1752 cache->dbgReusedXSLTTree = 0; 1753 cache->dbgReusedUndefined = 0; 1754 } 1755 } 1756 1757 xmlXPathDebugObjCounterUndefined = 0; 1758 xmlXPathDebugObjCounterNodeset = 0; 1759 xmlXPathDebugObjCounterBool = 0; 1760 xmlXPathDebugObjCounterNumber = 0; 1761 xmlXPathDebugObjCounterString = 0; 1762 xmlXPathDebugObjCounterPoint = 0; 1763 xmlXPathDebugObjCounterRange = 0; 1764 xmlXPathDebugObjCounterLocset = 0; 1765 xmlXPathDebugObjCounterUsers = 0; 1766 xmlXPathDebugObjCounterXSLTTree = 0; 1767 xmlXPathDebugObjCounterAll = 0; 1768 1769 xmlXPathDebugObjTotalUndefined = 0; 1770 xmlXPathDebugObjTotalNodeset = 0; 1771 xmlXPathDebugObjTotalBool = 0; 1772 xmlXPathDebugObjTotalNumber = 0; 1773 xmlXPathDebugObjTotalString = 0; 1774 xmlXPathDebugObjTotalPoint = 0; 1775 xmlXPathDebugObjTotalRange = 0; 1776 xmlXPathDebugObjTotalLocset = 0; 1777 xmlXPathDebugObjTotalUsers = 0; 1778 xmlXPathDebugObjTotalXSLTTree = 0; 1779 xmlXPathDebugObjTotalAll = 0; 1780 1781 xmlXPathDebugObjMaxUndefined = 0; 1782 xmlXPathDebugObjMaxNodeset = 0; 1783 xmlXPathDebugObjMaxBool = 0; 1784 xmlXPathDebugObjMaxNumber = 0; 1785 xmlXPathDebugObjMaxString = 0; 1786 xmlXPathDebugObjMaxPoint = 0; 1787 xmlXPathDebugObjMaxRange = 0; 1788 xmlXPathDebugObjMaxLocset = 0; 1789 xmlXPathDebugObjMaxUsers = 0; 1790 xmlXPathDebugObjMaxXSLTTree = 0; 1791 xmlXPathDebugObjMaxAll = 0; 1792 1793 } 1794 1795 static void 1796 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt, 1797 xmlXPathObjectType objType) 1798 { 1799 int isCached = 0; 1800 1801 if (ctxt != NULL) { 1802 if (ctxt->cache != NULL) { 1803 xmlXPathContextCachePtr cache = 1804 (xmlXPathContextCachePtr) ctxt->cache; 1805 1806 isCached = 1; 1807 1808 cache->dbgReusedAll++; 1809 switch (objType) { 1810 case XPATH_UNDEFINED: 1811 cache->dbgReusedUndefined++; 1812 break; 1813 case XPATH_NODESET: 1814 cache->dbgReusedNodeset++; 1815 break; 1816 case XPATH_BOOLEAN: 1817 cache->dbgReusedBool++; 1818 break; 1819 case XPATH_NUMBER: 1820 cache->dbgReusedNumber++; 1821 break; 1822 case XPATH_STRING: 1823 cache->dbgReusedString++; 1824 break; 1825 case XPATH_POINT: 1826 cache->dbgReusedPoint++; 1827 break; 1828 case XPATH_RANGE: 1829 cache->dbgReusedRange++; 1830 break; 1831 case XPATH_LOCATIONSET: 1832 cache->dbgReusedLocset++; 1833 break; 1834 case XPATH_USERS: 1835 cache->dbgReusedUsers++; 1836 break; 1837 case XPATH_XSLT_TREE: 1838 cache->dbgReusedXSLTTree++; 1839 break; 1840 default: 1841 break; 1842 } 1843 } 1844 } 1845 1846 switch (objType) { 1847 case XPATH_UNDEFINED: 1848 if (! isCached) 1849 xmlXPathDebugObjTotalUndefined++; 1850 xmlXPathDebugObjCounterUndefined++; 1851 if (xmlXPathDebugObjCounterUndefined > 1852 xmlXPathDebugObjMaxUndefined) 1853 xmlXPathDebugObjMaxUndefined = 1854 xmlXPathDebugObjCounterUndefined; 1855 break; 1856 case XPATH_NODESET: 1857 if (! isCached) 1858 xmlXPathDebugObjTotalNodeset++; 1859 xmlXPathDebugObjCounterNodeset++; 1860 if (xmlXPathDebugObjCounterNodeset > 1861 xmlXPathDebugObjMaxNodeset) 1862 xmlXPathDebugObjMaxNodeset = 1863 xmlXPathDebugObjCounterNodeset; 1864 break; 1865 case XPATH_BOOLEAN: 1866 if (! isCached) 1867 xmlXPathDebugObjTotalBool++; 1868 xmlXPathDebugObjCounterBool++; 1869 if (xmlXPathDebugObjCounterBool > 1870 xmlXPathDebugObjMaxBool) 1871 xmlXPathDebugObjMaxBool = 1872 xmlXPathDebugObjCounterBool; 1873 break; 1874 case XPATH_NUMBER: 1875 if (! isCached) 1876 xmlXPathDebugObjTotalNumber++; 1877 xmlXPathDebugObjCounterNumber++; 1878 if (xmlXPathDebugObjCounterNumber > 1879 xmlXPathDebugObjMaxNumber) 1880 xmlXPathDebugObjMaxNumber = 1881 xmlXPathDebugObjCounterNumber; 1882 break; 1883 case XPATH_STRING: 1884 if (! isCached) 1885 xmlXPathDebugObjTotalString++; 1886 xmlXPathDebugObjCounterString++; 1887 if (xmlXPathDebugObjCounterString > 1888 xmlXPathDebugObjMaxString) 1889 xmlXPathDebugObjMaxString = 1890 xmlXPathDebugObjCounterString; 1891 break; 1892 case XPATH_POINT: 1893 if (! isCached) 1894 xmlXPathDebugObjTotalPoint++; 1895 xmlXPathDebugObjCounterPoint++; 1896 if (xmlXPathDebugObjCounterPoint > 1897 xmlXPathDebugObjMaxPoint) 1898 xmlXPathDebugObjMaxPoint = 1899 xmlXPathDebugObjCounterPoint; 1900 break; 1901 case XPATH_RANGE: 1902 if (! isCached) 1903 xmlXPathDebugObjTotalRange++; 1904 xmlXPathDebugObjCounterRange++; 1905 if (xmlXPathDebugObjCounterRange > 1906 xmlXPathDebugObjMaxRange) 1907 xmlXPathDebugObjMaxRange = 1908 xmlXPathDebugObjCounterRange; 1909 break; 1910 case XPATH_LOCATIONSET: 1911 if (! isCached) 1912 xmlXPathDebugObjTotalLocset++; 1913 xmlXPathDebugObjCounterLocset++; 1914 if (xmlXPathDebugObjCounterLocset > 1915 xmlXPathDebugObjMaxLocset) 1916 xmlXPathDebugObjMaxLocset = 1917 xmlXPathDebugObjCounterLocset; 1918 break; 1919 case XPATH_USERS: 1920 if (! isCached) 1921 xmlXPathDebugObjTotalUsers++; 1922 xmlXPathDebugObjCounterUsers++; 1923 if (xmlXPathDebugObjCounterUsers > 1924 xmlXPathDebugObjMaxUsers) 1925 xmlXPathDebugObjMaxUsers = 1926 xmlXPathDebugObjCounterUsers; 1927 break; 1928 case XPATH_XSLT_TREE: 1929 if (! isCached) 1930 xmlXPathDebugObjTotalXSLTTree++; 1931 xmlXPathDebugObjCounterXSLTTree++; 1932 if (xmlXPathDebugObjCounterXSLTTree > 1933 xmlXPathDebugObjMaxXSLTTree) 1934 xmlXPathDebugObjMaxXSLTTree = 1935 xmlXPathDebugObjCounterXSLTTree; 1936 break; 1937 default: 1938 break; 1939 } 1940 if (! isCached) 1941 xmlXPathDebugObjTotalAll++; 1942 xmlXPathDebugObjCounterAll++; 1943 if (xmlXPathDebugObjCounterAll > 1944 xmlXPathDebugObjMaxAll) 1945 xmlXPathDebugObjMaxAll = 1946 xmlXPathDebugObjCounterAll; 1947 } 1948 1949 static void 1950 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt, 1951 xmlXPathObjectType objType) 1952 { 1953 int isCached = 0; 1954 1955 if (ctxt != NULL) { 1956 if (ctxt->cache != NULL) { 1957 xmlXPathContextCachePtr cache = 1958 (xmlXPathContextCachePtr) ctxt->cache; 1959 1960 isCached = 1; 1961 1962 cache->dbgCachedAll++; 1963 switch (objType) { 1964 case XPATH_UNDEFINED: 1965 cache->dbgCachedUndefined++; 1966 break; 1967 case XPATH_NODESET: 1968 cache->dbgCachedNodeset++; 1969 break; 1970 case XPATH_BOOLEAN: 1971 cache->dbgCachedBool++; 1972 break; 1973 case XPATH_NUMBER: 1974 cache->dbgCachedNumber++; 1975 break; 1976 case XPATH_STRING: 1977 cache->dbgCachedString++; 1978 break; 1979 case XPATH_POINT: 1980 cache->dbgCachedPoint++; 1981 break; 1982 case XPATH_RANGE: 1983 cache->dbgCachedRange++; 1984 break; 1985 case XPATH_LOCATIONSET: 1986 cache->dbgCachedLocset++; 1987 break; 1988 case XPATH_USERS: 1989 cache->dbgCachedUsers++; 1990 break; 1991 case XPATH_XSLT_TREE: 1992 cache->dbgCachedXSLTTree++; 1993 break; 1994 default: 1995 break; 1996 } 1997 1998 } 1999 } 2000 switch (objType) { 2001 case XPATH_UNDEFINED: 2002 xmlXPathDebugObjCounterUndefined--; 2003 break; 2004 case XPATH_NODESET: 2005 xmlXPathDebugObjCounterNodeset--; 2006 break; 2007 case XPATH_BOOLEAN: 2008 xmlXPathDebugObjCounterBool--; 2009 break; 2010 case XPATH_NUMBER: 2011 xmlXPathDebugObjCounterNumber--; 2012 break; 2013 case XPATH_STRING: 2014 xmlXPathDebugObjCounterString--; 2015 break; 2016 case XPATH_POINT: 2017 xmlXPathDebugObjCounterPoint--; 2018 break; 2019 case XPATH_RANGE: 2020 xmlXPathDebugObjCounterRange--; 2021 break; 2022 case XPATH_LOCATIONSET: 2023 xmlXPathDebugObjCounterLocset--; 2024 break; 2025 case XPATH_USERS: 2026 xmlXPathDebugObjCounterUsers--; 2027 break; 2028 case XPATH_XSLT_TREE: 2029 xmlXPathDebugObjCounterXSLTTree--; 2030 break; 2031 default: 2032 break; 2033 } 2034 xmlXPathDebugObjCounterAll--; 2035 } 2036 2037 /* REVISIT TODO: Make this static when committing */ 2038 static void 2039 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt) 2040 { 2041 int reqAll, reqNodeset, reqString, reqBool, reqNumber, 2042 reqXSLTTree, reqUndefined; 2043 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0, 2044 caNumber = 0, caXSLTTree = 0, caUndefined = 0; 2045 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0, 2046 reNumber = 0, reXSLTTree = 0, reUndefined = 0; 2047 int leftObjs = xmlXPathDebugObjCounterAll; 2048 2049 reqAll = xmlXPathDebugObjTotalAll; 2050 reqNodeset = xmlXPathDebugObjTotalNodeset; 2051 reqString = xmlXPathDebugObjTotalString; 2052 reqBool = xmlXPathDebugObjTotalBool; 2053 reqNumber = xmlXPathDebugObjTotalNumber; 2054 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree; 2055 reqUndefined = xmlXPathDebugObjTotalUndefined; 2056 2057 printf("# XPath object usage:\n"); 2058 2059 if (ctxt != NULL) { 2060 if (ctxt->cache != NULL) { 2061 xmlXPathContextCachePtr cache = 2062 (xmlXPathContextCachePtr) ctxt->cache; 2063 2064 reAll = cache->dbgReusedAll; 2065 reqAll += reAll; 2066 reNodeset = cache->dbgReusedNodeset; 2067 reqNodeset += reNodeset; 2068 reString = cache->dbgReusedString; 2069 reqString += reString; 2070 reBool = cache->dbgReusedBool; 2071 reqBool += reBool; 2072 reNumber = cache->dbgReusedNumber; 2073 reqNumber += reNumber; 2074 reXSLTTree = cache->dbgReusedXSLTTree; 2075 reqXSLTTree += reXSLTTree; 2076 reUndefined = cache->dbgReusedUndefined; 2077 reqUndefined += reUndefined; 2078 2079 caAll = cache->dbgCachedAll; 2080 caBool = cache->dbgCachedBool; 2081 caNodeset = cache->dbgCachedNodeset; 2082 caString = cache->dbgCachedString; 2083 caNumber = cache->dbgCachedNumber; 2084 caXSLTTree = cache->dbgCachedXSLTTree; 2085 caUndefined = cache->dbgCachedUndefined; 2086 2087 if (cache->nodesetObjs) 2088 leftObjs -= cache->nodesetObjs->number; 2089 if (cache->stringObjs) 2090 leftObjs -= cache->stringObjs->number; 2091 if (cache->booleanObjs) 2092 leftObjs -= cache->booleanObjs->number; 2093 if (cache->numberObjs) 2094 leftObjs -= cache->numberObjs->number; 2095 if (cache->miscObjs) 2096 leftObjs -= cache->miscObjs->number; 2097 } 2098 } 2099 2100 printf("# all\n"); 2101 printf("# total : %d\n", reqAll); 2102 printf("# left : %d\n", leftObjs); 2103 printf("# created: %d\n", xmlXPathDebugObjTotalAll); 2104 printf("# reused : %d\n", reAll); 2105 printf("# max : %d\n", xmlXPathDebugObjMaxAll); 2106 2107 printf("# node-sets\n"); 2108 printf("# total : %d\n", reqNodeset); 2109 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset); 2110 printf("# reused : %d\n", reNodeset); 2111 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset); 2112 2113 printf("# strings\n"); 2114 printf("# total : %d\n", reqString); 2115 printf("# created: %d\n", xmlXPathDebugObjTotalString); 2116 printf("# reused : %d\n", reString); 2117 printf("# max : %d\n", xmlXPathDebugObjMaxString); 2118 2119 printf("# booleans\n"); 2120 printf("# total : %d\n", reqBool); 2121 printf("# created: %d\n", xmlXPathDebugObjTotalBool); 2122 printf("# reused : %d\n", reBool); 2123 printf("# max : %d\n", xmlXPathDebugObjMaxBool); 2124 2125 printf("# numbers\n"); 2126 printf("# total : %d\n", reqNumber); 2127 printf("# created: %d\n", xmlXPathDebugObjTotalNumber); 2128 printf("# reused : %d\n", reNumber); 2129 printf("# max : %d\n", xmlXPathDebugObjMaxNumber); 2130 2131 printf("# XSLT result tree fragments\n"); 2132 printf("# total : %d\n", reqXSLTTree); 2133 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree); 2134 printf("# reused : %d\n", reXSLTTree); 2135 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree); 2136 2137 printf("# undefined\n"); 2138 printf("# total : %d\n", reqUndefined); 2139 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined); 2140 printf("# reused : %d\n", reUndefined); 2141 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined); 2142 2143 } 2144 2145 #endif /* XP_DEBUG_OBJ_USAGE */ 2146 2147 #endif /* LIBXML_DEBUG_ENABLED */ 2148 2149 /************************************************************************ 2150 * * 2151 * XPath object caching * 2152 * * 2153 ************************************************************************/ 2154 2155 /** 2156 * xmlXPathNewCache: 2157 * 2158 * Create a new object cache 2159 * 2160 * Returns the xmlXPathCache just allocated. 2161 */ 2162 static xmlXPathContextCachePtr 2163 xmlXPathNewCache(void) 2164 { 2165 xmlXPathContextCachePtr ret; 2166 2167 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache)); 2168 if (ret == NULL) { 2169 xmlXPathErrMemory(NULL, "creating object cache\n"); 2170 return(NULL); 2171 } 2172 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache)); 2173 ret->maxNodeset = 100; 2174 ret->maxString = 100; 2175 ret->maxBoolean = 100; 2176 ret->maxNumber = 100; 2177 ret->maxMisc = 100; 2178 return(ret); 2179 } 2180 2181 static void 2182 xmlXPathCacheFreeObjectList(xmlPointerListPtr list) 2183 { 2184 int i; 2185 xmlXPathObjectPtr obj; 2186 2187 if (list == NULL) 2188 return; 2189 2190 for (i = 0; i < list->number; i++) { 2191 obj = list->items[i]; 2192 /* 2193 * Note that it is already assured that we don't need to 2194 * look out for namespace nodes in the node-set. 2195 */ 2196 if (obj->nodesetval != NULL) { 2197 if (obj->nodesetval->nodeTab != NULL) 2198 xmlFree(obj->nodesetval->nodeTab); 2199 xmlFree(obj->nodesetval); 2200 } 2201 xmlFree(obj); 2202 #ifdef XP_DEBUG_OBJ_USAGE 2203 xmlXPathDebugObjCounterAll--; 2204 #endif 2205 } 2206 xmlPointerListFree(list); 2207 } 2208 2209 static void 2210 xmlXPathFreeCache(xmlXPathContextCachePtr cache) 2211 { 2212 if (cache == NULL) 2213 return; 2214 if (cache->nodesetObjs) 2215 xmlXPathCacheFreeObjectList(cache->nodesetObjs); 2216 if (cache->stringObjs) 2217 xmlXPathCacheFreeObjectList(cache->stringObjs); 2218 if (cache->booleanObjs) 2219 xmlXPathCacheFreeObjectList(cache->booleanObjs); 2220 if (cache->numberObjs) 2221 xmlXPathCacheFreeObjectList(cache->numberObjs); 2222 if (cache->miscObjs) 2223 xmlXPathCacheFreeObjectList(cache->miscObjs); 2224 xmlFree(cache); 2225 } 2226 2227 /** 2228 * xmlXPathContextSetCache: 2229 * 2230 * @ctxt: the XPath context 2231 * @active: enables/disables (creates/frees) the cache 2232 * @value: a value with semantics dependant on @options 2233 * @options: options (currently only the value 0 is used) 2234 * 2235 * Creates/frees an object cache on the XPath context. 2236 * If activates XPath objects (xmlXPathObject) will be cached internally 2237 * to be reused. 2238 * @options: 2239 * 0: This will set the XPath object caching: 2240 * @value: 2241 * This will set the maximum number of XPath objects 2242 * to be cached per slot 2243 * There are 5 slots for: node-set, string, number, boolean, and 2244 * misc objects. Use <0 for the default number (100). 2245 * Other values for @options have currently no effect. 2246 * 2247 * Returns 0 if the setting succeeded, and -1 on API or internal errors. 2248 */ 2249 int 2250 xmlXPathContextSetCache(xmlXPathContextPtr ctxt, 2251 int active, 2252 int value, 2253 int options) 2254 { 2255 if (ctxt == NULL) 2256 return(-1); 2257 if (active) { 2258 xmlXPathContextCachePtr cache; 2259 2260 if (ctxt->cache == NULL) { 2261 ctxt->cache = xmlXPathNewCache(); 2262 if (ctxt->cache == NULL) 2263 return(-1); 2264 } 2265 cache = (xmlXPathContextCachePtr) ctxt->cache; 2266 if (options == 0) { 2267 if (value < 0) 2268 value = 100; 2269 cache->maxNodeset = value; 2270 cache->maxString = value; 2271 cache->maxNumber = value; 2272 cache->maxBoolean = value; 2273 cache->maxMisc = value; 2274 } 2275 } else if (ctxt->cache != NULL) { 2276 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache); 2277 ctxt->cache = NULL; 2278 } 2279 return(0); 2280 } 2281 2282 /** 2283 * xmlXPathCacheWrapNodeSet: 2284 * @ctxt: the XPath context 2285 * @val: the NodePtr value 2286 * 2287 * This is the cached version of xmlXPathWrapNodeSet(). 2288 * Wrap the Nodeset @val in a new xmlXPathObjectPtr 2289 * 2290 * Returns the created or reused object. 2291 */ 2292 static xmlXPathObjectPtr 2293 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val) 2294 { 2295 if ((ctxt != NULL) && (ctxt->cache != NULL)) { 2296 xmlXPathContextCachePtr cache = 2297 (xmlXPathContextCachePtr) ctxt->cache; 2298 2299 if ((cache->miscObjs != NULL) && 2300 (cache->miscObjs->number != 0)) 2301 { 2302 xmlXPathObjectPtr ret; 2303 2304 ret = (xmlXPathObjectPtr) 2305 cache->miscObjs->items[--cache->miscObjs->number]; 2306 ret->type = XPATH_NODESET; 2307 ret->nodesetval = val; 2308 #ifdef XP_DEBUG_OBJ_USAGE 2309 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 2310 #endif 2311 return(ret); 2312 } 2313 } 2314 2315 return(xmlXPathWrapNodeSet(val)); 2316 2317 } 2318 2319 /** 2320 * xmlXPathCacheWrapString: 2321 * @ctxt: the XPath context 2322 * @val: the xmlChar * value 2323 * 2324 * This is the cached version of xmlXPathWrapString(). 2325 * Wraps the @val string into an XPath object. 2326 * 2327 * Returns the created or reused object. 2328 */ 2329 static xmlXPathObjectPtr 2330 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val) 2331 { 2332 if ((ctxt != NULL) && (ctxt->cache != NULL)) { 2333 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2334 2335 if ((cache->stringObjs != NULL) && 2336 (cache->stringObjs->number != 0)) 2337 { 2338 2339 xmlXPathObjectPtr ret; 2340 2341 ret = (xmlXPathObjectPtr) 2342 cache->stringObjs->items[--cache->stringObjs->number]; 2343 ret->type = XPATH_STRING; 2344 ret->stringval = val; 2345 #ifdef XP_DEBUG_OBJ_USAGE 2346 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2347 #endif 2348 return(ret); 2349 } else if ((cache->miscObjs != NULL) && 2350 (cache->miscObjs->number != 0)) 2351 { 2352 xmlXPathObjectPtr ret; 2353 /* 2354 * Fallback to misc-cache. 2355 */ 2356 ret = (xmlXPathObjectPtr) 2357 cache->miscObjs->items[--cache->miscObjs->number]; 2358 2359 ret->type = XPATH_STRING; 2360 ret->stringval = val; 2361 #ifdef XP_DEBUG_OBJ_USAGE 2362 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2363 #endif 2364 return(ret); 2365 } 2366 } 2367 return(xmlXPathWrapString(val)); 2368 } 2369 2370 /** 2371 * xmlXPathCacheNewNodeSet: 2372 * @ctxt: the XPath context 2373 * @val: the NodePtr value 2374 * 2375 * This is the cached version of xmlXPathNewNodeSet(). 2376 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize 2377 * it with the single Node @val 2378 * 2379 * Returns the created or reused object. 2380 */ 2381 static xmlXPathObjectPtr 2382 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val) 2383 { 2384 if ((ctxt != NULL) && (ctxt->cache)) { 2385 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2386 2387 if ((cache->nodesetObjs != NULL) && 2388 (cache->nodesetObjs->number != 0)) 2389 { 2390 xmlXPathObjectPtr ret; 2391 /* 2392 * Use the nodset-cache. 2393 */ 2394 ret = (xmlXPathObjectPtr) 2395 cache->nodesetObjs->items[--cache->nodesetObjs->number]; 2396 ret->type = XPATH_NODESET; 2397 ret->boolval = 0; 2398 if (val) { 2399 if ((ret->nodesetval->nodeMax == 0) || 2400 (val->type == XML_NAMESPACE_DECL)) 2401 { 2402 xmlXPathNodeSetAddUnique(ret->nodesetval, val); 2403 } else { 2404 ret->nodesetval->nodeTab[0] = val; 2405 ret->nodesetval->nodeNr = 1; 2406 } 2407 } 2408 #ifdef XP_DEBUG_OBJ_USAGE 2409 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 2410 #endif 2411 return(ret); 2412 } else if ((cache->miscObjs != NULL) && 2413 (cache->miscObjs->number != 0)) 2414 { 2415 xmlXPathObjectPtr ret; 2416 /* 2417 * Fallback to misc-cache. 2418 */ 2419 2420 ret = (xmlXPathObjectPtr) 2421 cache->miscObjs->items[--cache->miscObjs->number]; 2422 2423 ret->type = XPATH_NODESET; 2424 ret->boolval = 0; 2425 ret->nodesetval = xmlXPathNodeSetCreate(val); 2426 if (ret->nodesetval == NULL) { 2427 ctxt->lastError.domain = XML_FROM_XPATH; 2428 ctxt->lastError.code = XML_ERR_NO_MEMORY; 2429 return(NULL); 2430 } 2431 #ifdef XP_DEBUG_OBJ_USAGE 2432 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 2433 #endif 2434 return(ret); 2435 } 2436 } 2437 return(xmlXPathNewNodeSet(val)); 2438 } 2439 2440 /** 2441 * xmlXPathCacheNewCString: 2442 * @ctxt: the XPath context 2443 * @val: the char * value 2444 * 2445 * This is the cached version of xmlXPathNewCString(). 2446 * Acquire an xmlXPathObjectPtr of type string and of value @val 2447 * 2448 * Returns the created or reused object. 2449 */ 2450 static xmlXPathObjectPtr 2451 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val) 2452 { 2453 if ((ctxt != NULL) && (ctxt->cache)) { 2454 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2455 2456 if ((cache->stringObjs != NULL) && 2457 (cache->stringObjs->number != 0)) 2458 { 2459 xmlXPathObjectPtr ret; 2460 2461 ret = (xmlXPathObjectPtr) 2462 cache->stringObjs->items[--cache->stringObjs->number]; 2463 2464 ret->type = XPATH_STRING; 2465 ret->stringval = xmlStrdup(BAD_CAST val); 2466 #ifdef XP_DEBUG_OBJ_USAGE 2467 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2468 #endif 2469 return(ret); 2470 } else if ((cache->miscObjs != NULL) && 2471 (cache->miscObjs->number != 0)) 2472 { 2473 xmlXPathObjectPtr ret; 2474 2475 ret = (xmlXPathObjectPtr) 2476 cache->miscObjs->items[--cache->miscObjs->number]; 2477 2478 ret->type = XPATH_STRING; 2479 ret->stringval = xmlStrdup(BAD_CAST val); 2480 #ifdef XP_DEBUG_OBJ_USAGE 2481 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2482 #endif 2483 return(ret); 2484 } 2485 } 2486 return(xmlXPathNewCString(val)); 2487 } 2488 2489 /** 2490 * xmlXPathCacheNewString: 2491 * @ctxt: the XPath context 2492 * @val: the xmlChar * value 2493 * 2494 * This is the cached version of xmlXPathNewString(). 2495 * Acquire an xmlXPathObjectPtr of type string and of value @val 2496 * 2497 * Returns the created or reused object. 2498 */ 2499 static xmlXPathObjectPtr 2500 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val) 2501 { 2502 if ((ctxt != NULL) && (ctxt->cache)) { 2503 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2504 2505 if ((cache->stringObjs != NULL) && 2506 (cache->stringObjs->number != 0)) 2507 { 2508 xmlXPathObjectPtr ret; 2509 2510 ret = (xmlXPathObjectPtr) 2511 cache->stringObjs->items[--cache->stringObjs->number]; 2512 ret->type = XPATH_STRING; 2513 if (val != NULL) 2514 ret->stringval = xmlStrdup(val); 2515 else 2516 ret->stringval = xmlStrdup((const xmlChar *)""); 2517 #ifdef XP_DEBUG_OBJ_USAGE 2518 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2519 #endif 2520 return(ret); 2521 } else if ((cache->miscObjs != NULL) && 2522 (cache->miscObjs->number != 0)) 2523 { 2524 xmlXPathObjectPtr ret; 2525 2526 ret = (xmlXPathObjectPtr) 2527 cache->miscObjs->items[--cache->miscObjs->number]; 2528 2529 ret->type = XPATH_STRING; 2530 if (val != NULL) 2531 ret->stringval = xmlStrdup(val); 2532 else 2533 ret->stringval = xmlStrdup((const xmlChar *)""); 2534 #ifdef XP_DEBUG_OBJ_USAGE 2535 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2536 #endif 2537 return(ret); 2538 } 2539 } 2540 return(xmlXPathNewString(val)); 2541 } 2542 2543 /** 2544 * xmlXPathCacheNewBoolean: 2545 * @ctxt: the XPath context 2546 * @val: the boolean value 2547 * 2548 * This is the cached version of xmlXPathNewBoolean(). 2549 * Acquires an xmlXPathObjectPtr of type boolean and of value @val 2550 * 2551 * Returns the created or reused object. 2552 */ 2553 static xmlXPathObjectPtr 2554 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val) 2555 { 2556 if ((ctxt != NULL) && (ctxt->cache)) { 2557 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2558 2559 if ((cache->booleanObjs != NULL) && 2560 (cache->booleanObjs->number != 0)) 2561 { 2562 xmlXPathObjectPtr ret; 2563 2564 ret = (xmlXPathObjectPtr) 2565 cache->booleanObjs->items[--cache->booleanObjs->number]; 2566 ret->type = XPATH_BOOLEAN; 2567 ret->boolval = (val != 0); 2568 #ifdef XP_DEBUG_OBJ_USAGE 2569 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN); 2570 #endif 2571 return(ret); 2572 } else if ((cache->miscObjs != NULL) && 2573 (cache->miscObjs->number != 0)) 2574 { 2575 xmlXPathObjectPtr ret; 2576 2577 ret = (xmlXPathObjectPtr) 2578 cache->miscObjs->items[--cache->miscObjs->number]; 2579 2580 ret->type = XPATH_BOOLEAN; 2581 ret->boolval = (val != 0); 2582 #ifdef XP_DEBUG_OBJ_USAGE 2583 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN); 2584 #endif 2585 return(ret); 2586 } 2587 } 2588 return(xmlXPathNewBoolean(val)); 2589 } 2590 2591 /** 2592 * xmlXPathCacheNewFloat: 2593 * @ctxt: the XPath context 2594 * @val: the double value 2595 * 2596 * This is the cached version of xmlXPathNewFloat(). 2597 * Acquires an xmlXPathObjectPtr of type double and of value @val 2598 * 2599 * Returns the created or reused object. 2600 */ 2601 static xmlXPathObjectPtr 2602 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val) 2603 { 2604 if ((ctxt != NULL) && (ctxt->cache)) { 2605 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2606 2607 if ((cache->numberObjs != NULL) && 2608 (cache->numberObjs->number != 0)) 2609 { 2610 xmlXPathObjectPtr ret; 2611 2612 ret = (xmlXPathObjectPtr) 2613 cache->numberObjs->items[--cache->numberObjs->number]; 2614 ret->type = XPATH_NUMBER; 2615 ret->floatval = val; 2616 #ifdef XP_DEBUG_OBJ_USAGE 2617 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER); 2618 #endif 2619 return(ret); 2620 } else if ((cache->miscObjs != NULL) && 2621 (cache->miscObjs->number != 0)) 2622 { 2623 xmlXPathObjectPtr ret; 2624 2625 ret = (xmlXPathObjectPtr) 2626 cache->miscObjs->items[--cache->miscObjs->number]; 2627 2628 ret->type = XPATH_NUMBER; 2629 ret->floatval = val; 2630 #ifdef XP_DEBUG_OBJ_USAGE 2631 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER); 2632 #endif 2633 return(ret); 2634 } 2635 } 2636 return(xmlXPathNewFloat(val)); 2637 } 2638 2639 /** 2640 * xmlXPathCacheConvertString: 2641 * @ctxt: the XPath context 2642 * @val: an XPath object 2643 * 2644 * This is the cached version of xmlXPathConvertString(). 2645 * Converts an existing object to its string() equivalent 2646 * 2647 * Returns a created or reused object, the old one is freed (cached) 2648 * (or the operation is done directly on @val) 2649 */ 2650 2651 static xmlXPathObjectPtr 2652 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 2653 xmlChar *res = NULL; 2654 2655 if (val == NULL) 2656 return(xmlXPathCacheNewCString(ctxt, "")); 2657 2658 switch (val->type) { 2659 case XPATH_UNDEFINED: 2660 #ifdef DEBUG_EXPR 2661 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n"); 2662 #endif 2663 break; 2664 case XPATH_NODESET: 2665 case XPATH_XSLT_TREE: 2666 res = xmlXPathCastNodeSetToString(val->nodesetval); 2667 break; 2668 case XPATH_STRING: 2669 return(val); 2670 case XPATH_BOOLEAN: 2671 res = xmlXPathCastBooleanToString(val->boolval); 2672 break; 2673 case XPATH_NUMBER: 2674 res = xmlXPathCastNumberToString(val->floatval); 2675 break; 2676 case XPATH_USERS: 2677 case XPATH_POINT: 2678 case XPATH_RANGE: 2679 case XPATH_LOCATIONSET: 2680 TODO; 2681 break; 2682 } 2683 xmlXPathReleaseObject(ctxt, val); 2684 if (res == NULL) 2685 return(xmlXPathCacheNewCString(ctxt, "")); 2686 return(xmlXPathCacheWrapString(ctxt, res)); 2687 } 2688 2689 /** 2690 * xmlXPathCacheObjectCopy: 2691 * @ctxt: the XPath context 2692 * @val: the original object 2693 * 2694 * This is the cached version of xmlXPathObjectCopy(). 2695 * Acquire a copy of a given object 2696 * 2697 * Returns a created or reused created object. 2698 */ 2699 static xmlXPathObjectPtr 2700 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) 2701 { 2702 if (val == NULL) 2703 return(NULL); 2704 2705 if (XP_HAS_CACHE(ctxt)) { 2706 switch (val->type) { 2707 case XPATH_NODESET: 2708 return(xmlXPathCacheWrapNodeSet(ctxt, 2709 xmlXPathNodeSetMerge(NULL, val->nodesetval))); 2710 case XPATH_STRING: 2711 return(xmlXPathCacheNewString(ctxt, val->stringval)); 2712 case XPATH_BOOLEAN: 2713 return(xmlXPathCacheNewBoolean(ctxt, val->boolval)); 2714 case XPATH_NUMBER: 2715 return(xmlXPathCacheNewFloat(ctxt, val->floatval)); 2716 default: 2717 break; 2718 } 2719 } 2720 return(xmlXPathObjectCopy(val)); 2721 } 2722 2723 /** 2724 * xmlXPathCacheConvertBoolean: 2725 * @ctxt: the XPath context 2726 * @val: an XPath object 2727 * 2728 * This is the cached version of xmlXPathConvertBoolean(). 2729 * Converts an existing object to its boolean() equivalent 2730 * 2731 * Returns a created or reused object, the old one is freed (or the operation 2732 * is done directly on @val) 2733 */ 2734 static xmlXPathObjectPtr 2735 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 2736 xmlXPathObjectPtr ret; 2737 2738 if (val == NULL) 2739 return(xmlXPathCacheNewBoolean(ctxt, 0)); 2740 if (val->type == XPATH_BOOLEAN) 2741 return(val); 2742 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val)); 2743 xmlXPathReleaseObject(ctxt, val); 2744 return(ret); 2745 } 2746 2747 /** 2748 * xmlXPathCacheConvertNumber: 2749 * @ctxt: the XPath context 2750 * @val: an XPath object 2751 * 2752 * This is the cached version of xmlXPathConvertNumber(). 2753 * Converts an existing object to its number() equivalent 2754 * 2755 * Returns a created or reused object, the old one is freed (or the operation 2756 * is done directly on @val) 2757 */ 2758 static xmlXPathObjectPtr 2759 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 2760 xmlXPathObjectPtr ret; 2761 2762 if (val == NULL) 2763 return(xmlXPathCacheNewFloat(ctxt, 0.0)); 2764 if (val->type == XPATH_NUMBER) 2765 return(val); 2766 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val)); 2767 xmlXPathReleaseObject(ctxt, val); 2768 return(ret); 2769 } 2770 2771 /************************************************************************ 2772 * * 2773 * Parser stacks related functions and macros * 2774 * * 2775 ************************************************************************/ 2776 2777 /** 2778 * xmlXPathSetFrame: 2779 * @ctxt: an XPath parser context 2780 * 2781 * Set the callee evaluation frame 2782 * 2783 * Returns the previous frame value to be restored once done 2784 */ 2785 static int 2786 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) { 2787 int ret; 2788 2789 if (ctxt == NULL) 2790 return(0); 2791 ret = ctxt->valueFrame; 2792 ctxt->valueFrame = ctxt->valueNr; 2793 return(ret); 2794 } 2795 2796 /** 2797 * xmlXPathPopFrame: 2798 * @ctxt: an XPath parser context 2799 * @frame: the previous frame value 2800 * 2801 * Remove the callee evaluation frame 2802 */ 2803 static void 2804 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) { 2805 if (ctxt == NULL) 2806 return; 2807 if (ctxt->valueNr < ctxt->valueFrame) { 2808 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR); 2809 } 2810 ctxt->valueFrame = frame; 2811 } 2812 2813 /** 2814 * valuePop: 2815 * @ctxt: an XPath evaluation context 2816 * 2817 * Pops the top XPath object from the value stack 2818 * 2819 * Returns the XPath object just removed 2820 */ 2821 xmlXPathObjectPtr 2822 valuePop(xmlXPathParserContextPtr ctxt) 2823 { 2824 xmlXPathObjectPtr ret; 2825 2826 if ((ctxt == NULL) || (ctxt->valueNr <= 0)) 2827 return (NULL); 2828 2829 if (ctxt->valueNr <= ctxt->valueFrame) { 2830 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR); 2831 return (NULL); 2832 } 2833 2834 ctxt->valueNr--; 2835 if (ctxt->valueNr > 0) 2836 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1]; 2837 else 2838 ctxt->value = NULL; 2839 ret = ctxt->valueTab[ctxt->valueNr]; 2840 ctxt->valueTab[ctxt->valueNr] = NULL; 2841 return (ret); 2842 } 2843 /** 2844 * valuePush: 2845 * @ctxt: an XPath evaluation context 2846 * @value: the XPath object 2847 * 2848 * Pushes a new XPath object on top of the value stack 2849 * 2850 * returns the number of items on the value stack 2851 */ 2852 int 2853 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value) 2854 { 2855 if ((ctxt == NULL) || (value == NULL)) return(-1); 2856 if (ctxt->valueNr >= ctxt->valueMax) { 2857 xmlXPathObjectPtr *tmp; 2858 2859 if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) { 2860 xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n"); 2861 ctxt->error = XPATH_MEMORY_ERROR; 2862 return (0); 2863 } 2864 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab, 2865 2 * ctxt->valueMax * 2866 sizeof(ctxt->valueTab[0])); 2867 if (tmp == NULL) { 2868 xmlXPathErrMemory(NULL, "pushing value\n"); 2869 ctxt->error = XPATH_MEMORY_ERROR; 2870 return (0); 2871 } 2872 ctxt->valueMax *= 2; 2873 ctxt->valueTab = tmp; 2874 } 2875 ctxt->valueTab[ctxt->valueNr] = value; 2876 ctxt->value = value; 2877 return (ctxt->valueNr++); 2878 } 2879 2880 /** 2881 * xmlXPathPopBoolean: 2882 * @ctxt: an XPath parser context 2883 * 2884 * Pops a boolean from the stack, handling conversion if needed. 2885 * Check error with #xmlXPathCheckError. 2886 * 2887 * Returns the boolean 2888 */ 2889 int 2890 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) { 2891 xmlXPathObjectPtr obj; 2892 int ret; 2893 2894 obj = valuePop(ctxt); 2895 if (obj == NULL) { 2896 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2897 return(0); 2898 } 2899 if (obj->type != XPATH_BOOLEAN) 2900 ret = xmlXPathCastToBoolean(obj); 2901 else 2902 ret = obj->boolval; 2903 xmlXPathReleaseObject(ctxt->context, obj); 2904 return(ret); 2905 } 2906 2907 /** 2908 * xmlXPathPopNumber: 2909 * @ctxt: an XPath parser context 2910 * 2911 * Pops a number from the stack, handling conversion if needed. 2912 * Check error with #xmlXPathCheckError. 2913 * 2914 * Returns the number 2915 */ 2916 double 2917 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) { 2918 xmlXPathObjectPtr obj; 2919 double ret; 2920 2921 obj = valuePop(ctxt); 2922 if (obj == NULL) { 2923 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2924 return(0); 2925 } 2926 if (obj->type != XPATH_NUMBER) 2927 ret = xmlXPathCastToNumber(obj); 2928 else 2929 ret = obj->floatval; 2930 xmlXPathReleaseObject(ctxt->context, obj); 2931 return(ret); 2932 } 2933 2934 /** 2935 * xmlXPathPopString: 2936 * @ctxt: an XPath parser context 2937 * 2938 * Pops a string from the stack, handling conversion if needed. 2939 * Check error with #xmlXPathCheckError. 2940 * 2941 * Returns the string 2942 */ 2943 xmlChar * 2944 xmlXPathPopString (xmlXPathParserContextPtr ctxt) { 2945 xmlXPathObjectPtr obj; 2946 xmlChar * ret; 2947 2948 obj = valuePop(ctxt); 2949 if (obj == NULL) { 2950 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2951 return(NULL); 2952 } 2953 ret = xmlXPathCastToString(obj); /* this does required strdup */ 2954 /* TODO: needs refactoring somewhere else */ 2955 if (obj->stringval == ret) 2956 obj->stringval = NULL; 2957 xmlXPathReleaseObject(ctxt->context, obj); 2958 return(ret); 2959 } 2960 2961 /** 2962 * xmlXPathPopNodeSet: 2963 * @ctxt: an XPath parser context 2964 * 2965 * Pops a node-set from the stack, handling conversion if needed. 2966 * Check error with #xmlXPathCheckError. 2967 * 2968 * Returns the node-set 2969 */ 2970 xmlNodeSetPtr 2971 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) { 2972 xmlXPathObjectPtr obj; 2973 xmlNodeSetPtr ret; 2974 2975 if (ctxt == NULL) return(NULL); 2976 if (ctxt->value == NULL) { 2977 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2978 return(NULL); 2979 } 2980 if (!xmlXPathStackIsNodeSet(ctxt)) { 2981 xmlXPathSetTypeError(ctxt); 2982 return(NULL); 2983 } 2984 obj = valuePop(ctxt); 2985 ret = obj->nodesetval; 2986 #if 0 2987 /* to fix memory leak of not clearing obj->user */ 2988 if (obj->boolval && obj->user != NULL) 2989 xmlFreeNodeList((xmlNodePtr) obj->user); 2990 #endif 2991 obj->nodesetval = NULL; 2992 xmlXPathReleaseObject(ctxt->context, obj); 2993 return(ret); 2994 } 2995 2996 /** 2997 * xmlXPathPopExternal: 2998 * @ctxt: an XPath parser context 2999 * 3000 * Pops an external object from the stack, handling conversion if needed. 3001 * Check error with #xmlXPathCheckError. 3002 * 3003 * Returns the object 3004 */ 3005 void * 3006 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) { 3007 xmlXPathObjectPtr obj; 3008 void * ret; 3009 3010 if ((ctxt == NULL) || (ctxt->value == NULL)) { 3011 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 3012 return(NULL); 3013 } 3014 if (ctxt->value->type != XPATH_USERS) { 3015 xmlXPathSetTypeError(ctxt); 3016 return(NULL); 3017 } 3018 obj = valuePop(ctxt); 3019 ret = obj->user; 3020 obj->user = NULL; 3021 xmlXPathReleaseObject(ctxt->context, obj); 3022 return(ret); 3023 } 3024 3025 /* 3026 * Macros for accessing the content. Those should be used only by the parser, 3027 * and not exported. 3028 * 3029 * Dirty macros, i.e. one need to make assumption on the context to use them 3030 * 3031 * CUR_PTR return the current pointer to the xmlChar to be parsed. 3032 * CUR returns the current xmlChar value, i.e. a 8 bit value 3033 * in ISO-Latin or UTF-8. 3034 * This should be used internally by the parser 3035 * only to compare to ASCII values otherwise it would break when 3036 * running with UTF-8 encoding. 3037 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only 3038 * to compare on ASCII based substring. 3039 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined 3040 * strings within the parser. 3041 * CURRENT Returns the current char value, with the full decoding of 3042 * UTF-8 if we are using this mode. It returns an int. 3043 * NEXT Skip to the next character, this does the proper decoding 3044 * in UTF-8 mode. It also pop-up unfinished entities on the fly. 3045 * It returns the pointer to the current xmlChar. 3046 */ 3047 3048 #define CUR (*ctxt->cur) 3049 #define SKIP(val) ctxt->cur += (val) 3050 #define NXT(val) ctxt->cur[(val)] 3051 #define CUR_PTR ctxt->cur 3052 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l) 3053 3054 #define COPY_BUF(l,b,i,v) \ 3055 if (l == 1) b[i++] = (xmlChar) v; \ 3056 else i += xmlCopyChar(l,&b[i],v) 3057 3058 #define NEXTL(l) ctxt->cur += l 3059 3060 #define SKIP_BLANKS \ 3061 while (IS_BLANK_CH(*(ctxt->cur))) NEXT 3062 3063 #define CURRENT (*ctxt->cur) 3064 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur) 3065 3066 3067 #ifndef DBL_DIG 3068 #define DBL_DIG 16 3069 #endif 3070 #ifndef DBL_EPSILON 3071 #define DBL_EPSILON 1E-9 3072 #endif 3073 3074 #define UPPER_DOUBLE 1E9 3075 #define LOWER_DOUBLE 1E-5 3076 #define LOWER_DOUBLE_EXP 5 3077 3078 #define INTEGER_DIGITS DBL_DIG 3079 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP)) 3080 #define EXPONENT_DIGITS (3 + 2) 3081 3082 /** 3083 * xmlXPathFormatNumber: 3084 * @number: number to format 3085 * @buffer: output buffer 3086 * @buffersize: size of output buffer 3087 * 3088 * Convert the number into a string representation. 3089 */ 3090 static void 3091 xmlXPathFormatNumber(double number, char buffer[], int buffersize) 3092 { 3093 switch (xmlXPathIsInf(number)) { 3094 case 1: 3095 if (buffersize > (int)sizeof("Infinity")) 3096 snprintf(buffer, buffersize, "Infinity"); 3097 break; 3098 case -1: 3099 if (buffersize > (int)sizeof("-Infinity")) 3100 snprintf(buffer, buffersize, "-Infinity"); 3101 break; 3102 default: 3103 if (xmlXPathIsNaN(number)) { 3104 if (buffersize > (int)sizeof("NaN")) 3105 snprintf(buffer, buffersize, "NaN"); 3106 } else if (number == 0 && xmlXPathGetSign(number) != 0) { 3107 snprintf(buffer, buffersize, "0"); 3108 } else if (number == ((int) number)) { 3109 char work[30]; 3110 char *ptr, *cur; 3111 int value = (int) number; 3112 3113 ptr = &buffer[0]; 3114 if (value == 0) { 3115 *ptr++ = '0'; 3116 } else { 3117 snprintf(work, 29, "%d", value); 3118 cur = &work[0]; 3119 while ((*cur) && (ptr - buffer < buffersize)) { 3120 *ptr++ = *cur++; 3121 } 3122 } 3123 if (ptr - buffer < buffersize) { 3124 *ptr = 0; 3125 } else if (buffersize > 0) { 3126 ptr--; 3127 *ptr = 0; 3128 } 3129 } else { 3130 /* 3131 For the dimension of work, 3132 DBL_DIG is number of significant digits 3133 EXPONENT is only needed for "scientific notation" 3134 3 is sign, decimal point, and terminating zero 3135 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction 3136 Note that this dimension is slightly (a few characters) 3137 larger than actually necessary. 3138 */ 3139 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP]; 3140 int integer_place, fraction_place; 3141 char *ptr; 3142 char *after_fraction; 3143 double absolute_value; 3144 int size; 3145 3146 absolute_value = fabs(number); 3147 3148 /* 3149 * First choose format - scientific or regular floating point. 3150 * In either case, result is in work, and after_fraction points 3151 * just past the fractional part. 3152 */ 3153 if ( ((absolute_value > UPPER_DOUBLE) || 3154 (absolute_value < LOWER_DOUBLE)) && 3155 (absolute_value != 0.0) ) { 3156 /* Use scientific notation */ 3157 integer_place = DBL_DIG + EXPONENT_DIGITS + 1; 3158 fraction_place = DBL_DIG - 1; 3159 size = snprintf(work, sizeof(work),"%*.*e", 3160 integer_place, fraction_place, number); 3161 while ((size > 0) && (work[size] != 'e')) size--; 3162 3163 } 3164 else { 3165 /* Use regular notation */ 3166 if (absolute_value > 0.0) { 3167 integer_place = (int)log10(absolute_value); 3168 if (integer_place > 0) 3169 fraction_place = DBL_DIG - integer_place - 1; 3170 else 3171 fraction_place = DBL_DIG - integer_place; 3172 } else { 3173 fraction_place = 1; 3174 } 3175 size = snprintf(work, sizeof(work), "%0.*f", 3176 fraction_place, number); 3177 } 3178 3179 /* Remove leading spaces sometimes inserted by snprintf */ 3180 while (work[0] == ' ') { 3181 for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++); 3182 size--; 3183 } 3184 3185 /* Remove fractional trailing zeroes */ 3186 after_fraction = work + size; 3187 ptr = after_fraction; 3188 while (*(--ptr) == '0') 3189 ; 3190 if (*ptr != '.') 3191 ptr++; 3192 while ((*ptr++ = *after_fraction++) != 0); 3193 3194 /* Finally copy result back to caller */ 3195 size = strlen(work) + 1; 3196 if (size > buffersize) { 3197 work[buffersize - 1] = 0; 3198 size = buffersize; 3199 } 3200 memmove(buffer, work, size); 3201 } 3202 break; 3203 } 3204 } 3205 3206 3207 /************************************************************************ 3208 * * 3209 * Routines to handle NodeSets * 3210 * * 3211 ************************************************************************/ 3212 3213 /** 3214 * xmlXPathOrderDocElems: 3215 * @doc: an input document 3216 * 3217 * Call this routine to speed up XPath computation on static documents. 3218 * This stamps all the element nodes with the document order 3219 * Like for line information, the order is kept in the element->content 3220 * field, the value stored is actually - the node number (starting at -1) 3221 * to be able to differentiate from line numbers. 3222 * 3223 * Returns the number of elements found in the document or -1 in case 3224 * of error. 3225 */ 3226 long 3227 xmlXPathOrderDocElems(xmlDocPtr doc) { 3228 long count = 0; 3229 xmlNodePtr cur; 3230 3231 if (doc == NULL) 3232 return(-1); 3233 cur = doc->children; 3234 while (cur != NULL) { 3235 if (cur->type == XML_ELEMENT_NODE) { 3236 cur->content = (void *) (-(++count)); 3237 if (cur->children != NULL) { 3238 cur = cur->children; 3239 continue; 3240 } 3241 } 3242 if (cur->next != NULL) { 3243 cur = cur->next; 3244 continue; 3245 } 3246 do { 3247 cur = cur->parent; 3248 if (cur == NULL) 3249 break; 3250 if (cur == (xmlNodePtr) doc) { 3251 cur = NULL; 3252 break; 3253 } 3254 if (cur->next != NULL) { 3255 cur = cur->next; 3256 break; 3257 } 3258 } while (cur != NULL); 3259 } 3260 return(count); 3261 } 3262 3263 /** 3264 * xmlXPathCmpNodes: 3265 * @node1: the first node 3266 * @node2: the second node 3267 * 3268 * Compare two nodes w.r.t document order 3269 * 3270 * Returns -2 in case of error 1 if first point < second point, 0 if 3271 * it's the same node, -1 otherwise 3272 */ 3273 int 3274 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) { 3275 int depth1, depth2; 3276 int attr1 = 0, attr2 = 0; 3277 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL; 3278 xmlNodePtr cur, root; 3279 3280 if ((node1 == NULL) || (node2 == NULL)) 3281 return(-2); 3282 /* 3283 * a couple of optimizations which will avoid computations in most cases 3284 */ 3285 if (node1 == node2) /* trivial case */ 3286 return(0); 3287 if (node1->type == XML_ATTRIBUTE_NODE) { 3288 attr1 = 1; 3289 attrNode1 = node1; 3290 node1 = node1->parent; 3291 } 3292 if (node2->type == XML_ATTRIBUTE_NODE) { 3293 attr2 = 1; 3294 attrNode2 = node2; 3295 node2 = node2->parent; 3296 } 3297 if (node1 == node2) { 3298 if (attr1 == attr2) { 3299 /* not required, but we keep attributes in order */ 3300 if (attr1 != 0) { 3301 cur = attrNode2->prev; 3302 while (cur != NULL) { 3303 if (cur == attrNode1) 3304 return (1); 3305 cur = cur->prev; 3306 } 3307 return (-1); 3308 } 3309 return(0); 3310 } 3311 if (attr2 == 1) 3312 return(1); 3313 return(-1); 3314 } 3315 if ((node1->type == XML_NAMESPACE_DECL) || 3316 (node2->type == XML_NAMESPACE_DECL)) 3317 return(1); 3318 if (node1 == node2->prev) 3319 return(1); 3320 if (node1 == node2->next) 3321 return(-1); 3322 3323 /* 3324 * Speedup using document order if availble. 3325 */ 3326 if ((node1->type == XML_ELEMENT_NODE) && 3327 (node2->type == XML_ELEMENT_NODE) && 3328 (0 > (long) node1->content) && 3329 (0 > (long) node2->content) && 3330 (node1->doc == node2->doc)) { 3331 long l1, l2; 3332 3333 l1 = -((long) node1->content); 3334 l2 = -((long) node2->content); 3335 if (l1 < l2) 3336 return(1); 3337 if (l1 > l2) 3338 return(-1); 3339 } 3340 3341 /* 3342 * compute depth to root 3343 */ 3344 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) { 3345 if (cur == node1) 3346 return(1); 3347 depth2++; 3348 } 3349 root = cur; 3350 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) { 3351 if (cur == node2) 3352 return(-1); 3353 depth1++; 3354 } 3355 /* 3356 * Distinct document (or distinct entities :-( ) case. 3357 */ 3358 if (root != cur) { 3359 return(-2); 3360 } 3361 /* 3362 * get the nearest common ancestor. 3363 */ 3364 while (depth1 > depth2) { 3365 depth1--; 3366 node1 = node1->parent; 3367 } 3368 while (depth2 > depth1) { 3369 depth2--; 3370 node2 = node2->parent; 3371 } 3372 while (node1->parent != node2->parent) { 3373 node1 = node1->parent; 3374 node2 = node2->parent; 3375 /* should not happen but just in case ... */ 3376 if ((node1 == NULL) || (node2 == NULL)) 3377 return(-2); 3378 } 3379 /* 3380 * Find who's first. 3381 */ 3382 if (node1 == node2->prev) 3383 return(1); 3384 if (node1 == node2->next) 3385 return(-1); 3386 /* 3387 * Speedup using document order if availble. 3388 */ 3389 if ((node1->type == XML_ELEMENT_NODE) && 3390 (node2->type == XML_ELEMENT_NODE) && 3391 (0 > (long) node1->content) && 3392 (0 > (long) node2->content) && 3393 (node1->doc == node2->doc)) { 3394 long l1, l2; 3395 3396 l1 = -((long) node1->content); 3397 l2 = -((long) node2->content); 3398 if (l1 < l2) 3399 return(1); 3400 if (l1 > l2) 3401 return(-1); 3402 } 3403 3404 for (cur = node1->next;cur != NULL;cur = cur->next) 3405 if (cur == node2) 3406 return(1); 3407 return(-1); /* assume there is no sibling list corruption */ 3408 } 3409 3410 /** 3411 * xmlXPathNodeSetSort: 3412 * @set: the node set 3413 * 3414 * Sort the node set in document order 3415 */ 3416 void 3417 xmlXPathNodeSetSort(xmlNodeSetPtr set) { 3418 #ifndef WITH_TIM_SORT 3419 int i, j, incr, len; 3420 xmlNodePtr tmp; 3421 #endif 3422 3423 if (set == NULL) 3424 return; 3425 3426 #ifndef WITH_TIM_SORT 3427 /* 3428 * Use the old Shell's sort implementation to sort the node-set 3429 * Timsort ought to be quite faster 3430 */ 3431 len = set->nodeNr; 3432 for (incr = len / 2; incr > 0; incr /= 2) { 3433 for (i = incr; i < len; i++) { 3434 j = i - incr; 3435 while (j >= 0) { 3436 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 3437 if (xmlXPathCmpNodesExt(set->nodeTab[j], 3438 set->nodeTab[j + incr]) == -1) 3439 #else 3440 if (xmlXPathCmpNodes(set->nodeTab[j], 3441 set->nodeTab[j + incr]) == -1) 3442 #endif 3443 { 3444 tmp = set->nodeTab[j]; 3445 set->nodeTab[j] = set->nodeTab[j + incr]; 3446 set->nodeTab[j + incr] = tmp; 3447 j -= incr; 3448 } else 3449 break; 3450 } 3451 } 3452 } 3453 #else /* WITH_TIM_SORT */ 3454 libxml_domnode_tim_sort(set->nodeTab, set->nodeNr); 3455 #endif /* WITH_TIM_SORT */ 3456 } 3457 3458 #define XML_NODESET_DEFAULT 10 3459 /** 3460 * xmlXPathNodeSetDupNs: 3461 * @node: the parent node of the namespace XPath node 3462 * @ns: the libxml namespace declaration node. 3463 * 3464 * Namespace node in libxml don't match the XPath semantic. In a node set 3465 * the namespace nodes are duplicated and the next pointer is set to the 3466 * parent node in the XPath semantic. 3467 * 3468 * Returns the newly created object. 3469 */ 3470 static xmlNodePtr 3471 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) { 3472 xmlNsPtr cur; 3473 3474 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) 3475 return(NULL); 3476 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) 3477 return((xmlNodePtr) ns); 3478 3479 /* 3480 * Allocate a new Namespace and fill the fields. 3481 */ 3482 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); 3483 if (cur == NULL) { 3484 xmlXPathErrMemory(NULL, "duplicating namespace\n"); 3485 return(NULL); 3486 } 3487 memset(cur, 0, sizeof(xmlNs)); 3488 cur->type = XML_NAMESPACE_DECL; 3489 if (ns->href != NULL) 3490 cur->href = xmlStrdup(ns->href); 3491 if (ns->prefix != NULL) 3492 cur->prefix = xmlStrdup(ns->prefix); 3493 cur->next = (xmlNsPtr) node; 3494 return((xmlNodePtr) cur); 3495 } 3496 3497 /** 3498 * xmlXPathNodeSetFreeNs: 3499 * @ns: the XPath namespace node found in a nodeset. 3500 * 3501 * Namespace nodes in libxml don't match the XPath semantic. In a node set 3502 * the namespace nodes are duplicated and the next pointer is set to the 3503 * parent node in the XPath semantic. Check if such a node needs to be freed 3504 */ 3505 void 3506 xmlXPathNodeSetFreeNs(xmlNsPtr ns) { 3507 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) 3508 return; 3509 3510 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) { 3511 if (ns->href != NULL) 3512 xmlFree((xmlChar *)ns->href); 3513 if (ns->prefix != NULL) 3514 xmlFree((xmlChar *)ns->prefix); 3515 xmlFree(ns); 3516 } 3517 } 3518 3519 /** 3520 * xmlXPathNodeSetCreate: 3521 * @val: an initial xmlNodePtr, or NULL 3522 * 3523 * Create a new xmlNodeSetPtr of type double and of value @val 3524 * 3525 * Returns the newly created object. 3526 */ 3527 xmlNodeSetPtr 3528 xmlXPathNodeSetCreate(xmlNodePtr val) { 3529 xmlNodeSetPtr ret; 3530 3531 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet)); 3532 if (ret == NULL) { 3533 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3534 return(NULL); 3535 } 3536 memset(ret, 0 , (size_t) sizeof(xmlNodeSet)); 3537 if (val != NULL) { 3538 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3539 sizeof(xmlNodePtr)); 3540 if (ret->nodeTab == NULL) { 3541 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3542 xmlFree(ret); 3543 return(NULL); 3544 } 3545 memset(ret->nodeTab, 0 , 3546 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3547 ret->nodeMax = XML_NODESET_DEFAULT; 3548 if (val->type == XML_NAMESPACE_DECL) { 3549 xmlNsPtr ns = (xmlNsPtr) val; 3550 3551 ret->nodeTab[ret->nodeNr++] = 3552 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3553 } else 3554 ret->nodeTab[ret->nodeNr++] = val; 3555 } 3556 return(ret); 3557 } 3558 3559 /** 3560 * xmlXPathNodeSetCreateSize: 3561 * @size: the initial size of the set 3562 * 3563 * Create a new xmlNodeSetPtr of type double and of value @val 3564 * 3565 * Returns the newly created object. 3566 */ 3567 static xmlNodeSetPtr 3568 xmlXPathNodeSetCreateSize(int size) { 3569 xmlNodeSetPtr ret; 3570 3571 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet)); 3572 if (ret == NULL) { 3573 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3574 return(NULL); 3575 } 3576 memset(ret, 0 , (size_t) sizeof(xmlNodeSet)); 3577 if (size < XML_NODESET_DEFAULT) 3578 size = XML_NODESET_DEFAULT; 3579 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr)); 3580 if (ret->nodeTab == NULL) { 3581 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3582 xmlFree(ret); 3583 return(NULL); 3584 } 3585 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr)); 3586 ret->nodeMax = size; 3587 return(ret); 3588 } 3589 3590 /** 3591 * xmlXPathNodeSetContains: 3592 * @cur: the node-set 3593 * @val: the node 3594 * 3595 * checks whether @cur contains @val 3596 * 3597 * Returns true (1) if @cur contains @val, false (0) otherwise 3598 */ 3599 int 3600 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) { 3601 int i; 3602 3603 if ((cur == NULL) || (val == NULL)) return(0); 3604 if (val->type == XML_NAMESPACE_DECL) { 3605 for (i = 0; i < cur->nodeNr; i++) { 3606 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) { 3607 xmlNsPtr ns1, ns2; 3608 3609 ns1 = (xmlNsPtr) val; 3610 ns2 = (xmlNsPtr) cur->nodeTab[i]; 3611 if (ns1 == ns2) 3612 return(1); 3613 if ((ns1->next != NULL) && (ns2->next == ns1->next) && 3614 (xmlStrEqual(ns1->prefix, ns2->prefix))) 3615 return(1); 3616 } 3617 } 3618 } else { 3619 for (i = 0; i < cur->nodeNr; i++) { 3620 if (cur->nodeTab[i] == val) 3621 return(1); 3622 } 3623 } 3624 return(0); 3625 } 3626 3627 /** 3628 * xmlXPathNodeSetAddNs: 3629 * @cur: the initial node set 3630 * @node: the hosting node 3631 * @ns: a the namespace node 3632 * 3633 * add a new namespace node to an existing NodeSet 3634 * 3635 * Returns 0 in case of success and -1 in case of error 3636 */ 3637 int 3638 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) { 3639 int i; 3640 3641 3642 if ((cur == NULL) || (ns == NULL) || (node == NULL) || 3643 (ns->type != XML_NAMESPACE_DECL) || 3644 (node->type != XML_ELEMENT_NODE)) 3645 return(-1); 3646 3647 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3648 /* 3649 * prevent duplicates 3650 */ 3651 for (i = 0;i < cur->nodeNr;i++) { 3652 if ((cur->nodeTab[i] != NULL) && 3653 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) && 3654 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) && 3655 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix))) 3656 return(0); 3657 } 3658 3659 /* 3660 * grow the nodeTab if needed 3661 */ 3662 if (cur->nodeMax == 0) { 3663 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3664 sizeof(xmlNodePtr)); 3665 if (cur->nodeTab == NULL) { 3666 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3667 return(-1); 3668 } 3669 memset(cur->nodeTab, 0 , 3670 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3671 cur->nodeMax = XML_NODESET_DEFAULT; 3672 } else if (cur->nodeNr == cur->nodeMax) { 3673 xmlNodePtr *temp; 3674 3675 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 3676 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n"); 3677 return(-1); 3678 } 3679 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 * 3680 sizeof(xmlNodePtr)); 3681 if (temp == NULL) { 3682 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3683 return(-1); 3684 } 3685 cur->nodeMax *= 2; 3686 cur->nodeTab = temp; 3687 } 3688 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns); 3689 return(0); 3690 } 3691 3692 /** 3693 * xmlXPathNodeSetAdd: 3694 * @cur: the initial node set 3695 * @val: a new xmlNodePtr 3696 * 3697 * add a new xmlNodePtr to an existing NodeSet 3698 * 3699 * Returns 0 in case of success, and -1 in case of error 3700 */ 3701 int 3702 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) { 3703 int i; 3704 3705 if ((cur == NULL) || (val == NULL)) return(-1); 3706 3707 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3708 /* 3709 * prevent duplicates 3710 */ 3711 for (i = 0;i < cur->nodeNr;i++) 3712 if (cur->nodeTab[i] == val) return(0); 3713 3714 /* 3715 * grow the nodeTab if needed 3716 */ 3717 if (cur->nodeMax == 0) { 3718 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3719 sizeof(xmlNodePtr)); 3720 if (cur->nodeTab == NULL) { 3721 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3722 return(-1); 3723 } 3724 memset(cur->nodeTab, 0 , 3725 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3726 cur->nodeMax = XML_NODESET_DEFAULT; 3727 } else if (cur->nodeNr == cur->nodeMax) { 3728 xmlNodePtr *temp; 3729 3730 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 3731 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n"); 3732 return(-1); 3733 } 3734 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 * 3735 sizeof(xmlNodePtr)); 3736 if (temp == NULL) { 3737 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3738 return(-1); 3739 } 3740 cur->nodeMax *= 2; 3741 cur->nodeTab = temp; 3742 } 3743 if (val->type == XML_NAMESPACE_DECL) { 3744 xmlNsPtr ns = (xmlNsPtr) val; 3745 3746 cur->nodeTab[cur->nodeNr++] = 3747 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3748 } else 3749 cur->nodeTab[cur->nodeNr++] = val; 3750 return(0); 3751 } 3752 3753 /** 3754 * xmlXPathNodeSetAddUnique: 3755 * @cur: the initial node set 3756 * @val: a new xmlNodePtr 3757 * 3758 * add a new xmlNodePtr to an existing NodeSet, optimized version 3759 * when we are sure the node is not already in the set. 3760 * 3761 * Returns 0 in case of success and -1 in case of failure 3762 */ 3763 int 3764 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) { 3765 if ((cur == NULL) || (val == NULL)) return(-1); 3766 3767 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3768 /* 3769 * grow the nodeTab if needed 3770 */ 3771 if (cur->nodeMax == 0) { 3772 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3773 sizeof(xmlNodePtr)); 3774 if (cur->nodeTab == NULL) { 3775 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3776 return(-1); 3777 } 3778 memset(cur->nodeTab, 0 , 3779 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3780 cur->nodeMax = XML_NODESET_DEFAULT; 3781 } else if (cur->nodeNr == cur->nodeMax) { 3782 xmlNodePtr *temp; 3783 3784 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 3785 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n"); 3786 return(-1); 3787 } 3788 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 * 3789 sizeof(xmlNodePtr)); 3790 if (temp == NULL) { 3791 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3792 return(-1); 3793 } 3794 cur->nodeTab = temp; 3795 cur->nodeMax *= 2; 3796 } 3797 if (val->type == XML_NAMESPACE_DECL) { 3798 xmlNsPtr ns = (xmlNsPtr) val; 3799 3800 cur->nodeTab[cur->nodeNr++] = 3801 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3802 } else 3803 cur->nodeTab[cur->nodeNr++] = val; 3804 return(0); 3805 } 3806 3807 /** 3808 * xmlXPathNodeSetMerge: 3809 * @val1: the first NodeSet or NULL 3810 * @val2: the second NodeSet 3811 * 3812 * Merges two nodesets, all nodes from @val2 are added to @val1 3813 * if @val1 is NULL, a new set is created and copied from @val2 3814 * 3815 * Returns @val1 once extended or NULL in case of error. 3816 */ 3817 xmlNodeSetPtr 3818 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) { 3819 int i, j, initNr, skip; 3820 xmlNodePtr n1, n2; 3821 3822 if (val2 == NULL) return(val1); 3823 if (val1 == NULL) { 3824 val1 = xmlXPathNodeSetCreate(NULL); 3825 if (val1 == NULL) 3826 return (NULL); 3827 #if 0 3828 /* 3829 * TODO: The optimization won't work in every case, since 3830 * those nasty namespace nodes need to be added with 3831 * xmlXPathNodeSetDupNs() to the set; thus a pure 3832 * memcpy is not possible. 3833 * If there was a flag on the nodesetval, indicating that 3834 * some temporary nodes are in, that would be helpfull. 3835 */ 3836 /* 3837 * Optimization: Create an equally sized node-set 3838 * and memcpy the content. 3839 */ 3840 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr); 3841 if (val1 == NULL) 3842 return(NULL); 3843 if (val2->nodeNr != 0) { 3844 if (val2->nodeNr == 1) 3845 *(val1->nodeTab) = *(val2->nodeTab); 3846 else { 3847 memcpy(val1->nodeTab, val2->nodeTab, 3848 val2->nodeNr * sizeof(xmlNodePtr)); 3849 } 3850 val1->nodeNr = val2->nodeNr; 3851 } 3852 return(val1); 3853 #endif 3854 } 3855 3856 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3857 initNr = val1->nodeNr; 3858 3859 for (i = 0;i < val2->nodeNr;i++) { 3860 n2 = val2->nodeTab[i]; 3861 /* 3862 * check against duplicates 3863 */ 3864 skip = 0; 3865 for (j = 0; j < initNr; j++) { 3866 n1 = val1->nodeTab[j]; 3867 if (n1 == n2) { 3868 skip = 1; 3869 break; 3870 } else if ((n1->type == XML_NAMESPACE_DECL) && 3871 (n2->type == XML_NAMESPACE_DECL)) { 3872 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) && 3873 (xmlStrEqual(((xmlNsPtr) n1)->prefix, 3874 ((xmlNsPtr) n2)->prefix))) 3875 { 3876 skip = 1; 3877 break; 3878 } 3879 } 3880 } 3881 if (skip) 3882 continue; 3883 3884 /* 3885 * grow the nodeTab if needed 3886 */ 3887 if (val1->nodeMax == 0) { 3888 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3889 sizeof(xmlNodePtr)); 3890 if (val1->nodeTab == NULL) { 3891 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3892 return(NULL); 3893 } 3894 memset(val1->nodeTab, 0 , 3895 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3896 val1->nodeMax = XML_NODESET_DEFAULT; 3897 } else if (val1->nodeNr == val1->nodeMax) { 3898 xmlNodePtr *temp; 3899 3900 if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 3901 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n"); 3902 return(NULL); 3903 } 3904 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 * 3905 sizeof(xmlNodePtr)); 3906 if (temp == NULL) { 3907 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3908 return(NULL); 3909 } 3910 val1->nodeTab = temp; 3911 val1->nodeMax *= 2; 3912 } 3913 if (n2->type == XML_NAMESPACE_DECL) { 3914 xmlNsPtr ns = (xmlNsPtr) n2; 3915 3916 val1->nodeTab[val1->nodeNr++] = 3917 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3918 } else 3919 val1->nodeTab[val1->nodeNr++] = n2; 3920 } 3921 3922 return(val1); 3923 } 3924 3925 3926 /** 3927 * xmlXPathNodeSetMergeAndClear: 3928 * @set1: the first NodeSet or NULL 3929 * @set2: the second NodeSet 3930 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes 3931 * 3932 * Merges two nodesets, all nodes from @set2 are added to @set1 3933 * if @set1 is NULL, a new set is created and copied from @set2. 3934 * Checks for duplicate nodes. Clears set2. 3935 * 3936 * Returns @set1 once extended or NULL in case of error. 3937 */ 3938 static xmlNodeSetPtr 3939 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2, 3940 int hasNullEntries) 3941 { 3942 if ((set1 == NULL) && (hasNullEntries == 0)) { 3943 /* 3944 * Note that doing a memcpy of the list, namespace nodes are 3945 * just assigned to set1, since set2 is cleared anyway. 3946 */ 3947 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr); 3948 if (set1 == NULL) 3949 return(NULL); 3950 if (set2->nodeNr != 0) { 3951 memcpy(set1->nodeTab, set2->nodeTab, 3952 set2->nodeNr * sizeof(xmlNodePtr)); 3953 set1->nodeNr = set2->nodeNr; 3954 } 3955 } else { 3956 int i, j, initNbSet1; 3957 xmlNodePtr n1, n2; 3958 3959 if (set1 == NULL) 3960 set1 = xmlXPathNodeSetCreate(NULL); 3961 if (set1 == NULL) 3962 return (NULL); 3963 3964 initNbSet1 = set1->nodeNr; 3965 for (i = 0;i < set2->nodeNr;i++) { 3966 n2 = set2->nodeTab[i]; 3967 /* 3968 * Skip NULLed entries. 3969 */ 3970 if (n2 == NULL) 3971 continue; 3972 /* 3973 * Skip duplicates. 3974 */ 3975 for (j = 0; j < initNbSet1; j++) { 3976 n1 = set1->nodeTab[j]; 3977 if (n1 == n2) { 3978 goto skip_node; 3979 } else if ((n1->type == XML_NAMESPACE_DECL) && 3980 (n2->type == XML_NAMESPACE_DECL)) 3981 { 3982 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) && 3983 (xmlStrEqual(((xmlNsPtr) n1)->prefix, 3984 ((xmlNsPtr) n2)->prefix))) 3985 { 3986 /* 3987 * Free the namespace node. 3988 */ 3989 set2->nodeTab[i] = NULL; 3990 xmlXPathNodeSetFreeNs((xmlNsPtr) n2); 3991 goto skip_node; 3992 } 3993 } 3994 } 3995 /* 3996 * grow the nodeTab if needed 3997 */ 3998 if (set1->nodeMax == 0) { 3999 set1->nodeTab = (xmlNodePtr *) xmlMalloc( 4000 XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); 4001 if (set1->nodeTab == NULL) { 4002 xmlXPathErrMemory(NULL, "merging nodeset\n"); 4003 return(NULL); 4004 } 4005 memset(set1->nodeTab, 0, 4006 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 4007 set1->nodeMax = XML_NODESET_DEFAULT; 4008 } else if (set1->nodeNr >= set1->nodeMax) { 4009 xmlNodePtr *temp; 4010 4011 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 4012 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n"); 4013 return(NULL); 4014 } 4015 temp = (xmlNodePtr *) xmlRealloc( 4016 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr)); 4017 if (temp == NULL) { 4018 xmlXPathErrMemory(NULL, "merging nodeset\n"); 4019 return(NULL); 4020 } 4021 set1->nodeTab = temp; 4022 set1->nodeMax *= 2; 4023 } 4024 if (n2->type == XML_NAMESPACE_DECL) { 4025 xmlNsPtr ns = (xmlNsPtr) n2; 4026 4027 set1->nodeTab[set1->nodeNr++] = 4028 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 4029 } else 4030 set1->nodeTab[set1->nodeNr++] = n2; 4031 skip_node: 4032 {} 4033 } 4034 } 4035 set2->nodeNr = 0; 4036 return(set1); 4037 } 4038 4039 /** 4040 * xmlXPathNodeSetMergeAndClearNoDupls: 4041 * @set1: the first NodeSet or NULL 4042 * @set2: the second NodeSet 4043 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes 4044 * 4045 * Merges two nodesets, all nodes from @set2 are added to @set1 4046 * if @set1 is NULL, a new set is created and copied from @set2. 4047 * Doesn't chack for duplicate nodes. Clears set2. 4048 * 4049 * Returns @set1 once extended or NULL in case of error. 4050 */ 4051 static xmlNodeSetPtr 4052 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2, 4053 int hasNullEntries) 4054 { 4055 if (set2 == NULL) 4056 return(set1); 4057 if ((set1 == NULL) && (hasNullEntries == 0)) { 4058 /* 4059 * Note that doing a memcpy of the list, namespace nodes are 4060 * just assigned to set1, since set2 is cleared anyway. 4061 */ 4062 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr); 4063 if (set1 == NULL) 4064 return(NULL); 4065 if (set2->nodeNr != 0) { 4066 memcpy(set1->nodeTab, set2->nodeTab, 4067 set2->nodeNr * sizeof(xmlNodePtr)); 4068 set1->nodeNr = set2->nodeNr; 4069 } 4070 } else { 4071 int i; 4072 xmlNodePtr n2; 4073 4074 if (set1 == NULL) 4075 set1 = xmlXPathNodeSetCreate(NULL); 4076 if (set1 == NULL) 4077 return (NULL); 4078 4079 for (i = 0;i < set2->nodeNr;i++) { 4080 n2 = set2->nodeTab[i]; 4081 /* 4082 * Skip NULLed entries. 4083 */ 4084 if (n2 == NULL) 4085 continue; 4086 if (set1->nodeMax == 0) { 4087 set1->nodeTab = (xmlNodePtr *) xmlMalloc( 4088 XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); 4089 if (set1->nodeTab == NULL) { 4090 xmlXPathErrMemory(NULL, "merging nodeset\n"); 4091 return(NULL); 4092 } 4093 memset(set1->nodeTab, 0, 4094 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 4095 set1->nodeMax = XML_NODESET_DEFAULT; 4096 } else if (set1->nodeNr >= set1->nodeMax) { 4097 xmlNodePtr *temp; 4098 4099 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 4100 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n"); 4101 return(NULL); 4102 } 4103 temp = (xmlNodePtr *) xmlRealloc( 4104 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr)); 4105 if (temp == NULL) { 4106 xmlXPathErrMemory(NULL, "merging nodeset\n"); 4107 return(NULL); 4108 } 4109 set1->nodeTab = temp; 4110 set1->nodeMax *= 2; 4111 } 4112 set1->nodeTab[set1->nodeNr++] = n2; 4113 } 4114 } 4115 set2->nodeNr = 0; 4116 return(set1); 4117 } 4118 4119 /** 4120 * xmlXPathNodeSetDel: 4121 * @cur: the initial node set 4122 * @val: an xmlNodePtr 4123 * 4124 * Removes an xmlNodePtr from an existing NodeSet 4125 */ 4126 void 4127 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) { 4128 int i; 4129 4130 if (cur == NULL) return; 4131 if (val == NULL) return; 4132 4133 /* 4134 * find node in nodeTab 4135 */ 4136 for (i = 0;i < cur->nodeNr;i++) 4137 if (cur->nodeTab[i] == val) break; 4138 4139 if (i >= cur->nodeNr) { /* not found */ 4140 #ifdef DEBUG 4141 xmlGenericError(xmlGenericErrorContext, 4142 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n", 4143 val->name); 4144 #endif 4145 return; 4146 } 4147 if ((cur->nodeTab[i] != NULL) && 4148 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL)) 4149 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]); 4150 cur->nodeNr--; 4151 for (;i < cur->nodeNr;i++) 4152 cur->nodeTab[i] = cur->nodeTab[i + 1]; 4153 cur->nodeTab[cur->nodeNr] = NULL; 4154 } 4155 4156 /** 4157 * xmlXPathNodeSetRemove: 4158 * @cur: the initial node set 4159 * @val: the index to remove 4160 * 4161 * Removes an entry from an existing NodeSet list. 4162 */ 4163 void 4164 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) { 4165 if (cur == NULL) return; 4166 if (val >= cur->nodeNr) return; 4167 if ((cur->nodeTab[val] != NULL) && 4168 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL)) 4169 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]); 4170 cur->nodeNr--; 4171 for (;val < cur->nodeNr;val++) 4172 cur->nodeTab[val] = cur->nodeTab[val + 1]; 4173 cur->nodeTab[cur->nodeNr] = NULL; 4174 } 4175 4176 /** 4177 * xmlXPathFreeNodeSet: 4178 * @obj: the xmlNodeSetPtr to free 4179 * 4180 * Free the NodeSet compound (not the actual nodes !). 4181 */ 4182 void 4183 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) { 4184 if (obj == NULL) return; 4185 if (obj->nodeTab != NULL) { 4186 int i; 4187 4188 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 4189 for (i = 0;i < obj->nodeNr;i++) 4190 if ((obj->nodeTab[i] != NULL) && 4191 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL)) 4192 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]); 4193 xmlFree(obj->nodeTab); 4194 } 4195 xmlFree(obj); 4196 } 4197 4198 /** 4199 * xmlXPathNodeSetClear: 4200 * @set: the node set to clear 4201 * 4202 * Clears the list from all temporary XPath objects (e.g. namespace nodes 4203 * are feed), but does *not* free the list itself. Sets the length of the 4204 * list to 0. 4205 */ 4206 static void 4207 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes) 4208 { 4209 if ((set == NULL) || (set->nodeNr <= 0)) 4210 return; 4211 else if (hasNsNodes) { 4212 int i; 4213 xmlNodePtr node; 4214 4215 for (i = 0; i < set->nodeNr; i++) { 4216 node = set->nodeTab[i]; 4217 if ((node != NULL) && 4218 (node->type == XML_NAMESPACE_DECL)) 4219 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 4220 } 4221 } 4222 set->nodeNr = 0; 4223 } 4224 4225 /** 4226 * xmlXPathNodeSetClearFromPos: 4227 * @set: the node set to be cleared 4228 * @pos: the start position to clear from 4229 * 4230 * Clears the list from temporary XPath objects (e.g. namespace nodes 4231 * are feed) starting with the entry at @pos, but does *not* free the list 4232 * itself. Sets the length of the list to @pos. 4233 */ 4234 static void 4235 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes) 4236 { 4237 if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr)) 4238 return; 4239 else if ((hasNsNodes)) { 4240 int i; 4241 xmlNodePtr node; 4242 4243 for (i = pos; i < set->nodeNr; i++) { 4244 node = set->nodeTab[i]; 4245 if ((node != NULL) && 4246 (node->type == XML_NAMESPACE_DECL)) 4247 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 4248 } 4249 } 4250 set->nodeNr = pos; 4251 } 4252 4253 /** 4254 * xmlXPathFreeValueTree: 4255 * @obj: the xmlNodeSetPtr to free 4256 * 4257 * Free the NodeSet compound and the actual tree, this is different 4258 * from xmlXPathFreeNodeSet() 4259 */ 4260 static void 4261 xmlXPathFreeValueTree(xmlNodeSetPtr obj) { 4262 int i; 4263 4264 if (obj == NULL) return; 4265 4266 if (obj->nodeTab != NULL) { 4267 for (i = 0;i < obj->nodeNr;i++) { 4268 if (obj->nodeTab[i] != NULL) { 4269 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) { 4270 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]); 4271 } else { 4272 xmlFreeNodeList(obj->nodeTab[i]); 4273 } 4274 } 4275 } 4276 xmlFree(obj->nodeTab); 4277 } 4278 xmlFree(obj); 4279 } 4280 4281 #if defined(DEBUG) || defined(DEBUG_STEP) 4282 /** 4283 * xmlGenericErrorContextNodeSet: 4284 * @output: a FILE * for the output 4285 * @obj: the xmlNodeSetPtr to display 4286 * 4287 * Quick display of a NodeSet 4288 */ 4289 void 4290 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) { 4291 int i; 4292 4293 if (output == NULL) output = xmlGenericErrorContext; 4294 if (obj == NULL) { 4295 fprintf(output, "NodeSet == NULL !\n"); 4296 return; 4297 } 4298 if (obj->nodeNr == 0) { 4299 fprintf(output, "NodeSet is empty\n"); 4300 return; 4301 } 4302 if (obj->nodeTab == NULL) { 4303 fprintf(output, " nodeTab == NULL !\n"); 4304 return; 4305 } 4306 for (i = 0; i < obj->nodeNr; i++) { 4307 if (obj->nodeTab[i] == NULL) { 4308 fprintf(output, " NULL !\n"); 4309 return; 4310 } 4311 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) || 4312 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE)) 4313 fprintf(output, " /"); 4314 else if (obj->nodeTab[i]->name == NULL) 4315 fprintf(output, " noname!"); 4316 else fprintf(output, " %s", obj->nodeTab[i]->name); 4317 } 4318 fprintf(output, "\n"); 4319 } 4320 #endif 4321 4322 /** 4323 * xmlXPathNewNodeSet: 4324 * @val: the NodePtr value 4325 * 4326 * Create a new xmlXPathObjectPtr of type NodeSet and initialize 4327 * it with the single Node @val 4328 * 4329 * Returns the newly created object. 4330 */ 4331 xmlXPathObjectPtr 4332 xmlXPathNewNodeSet(xmlNodePtr val) { 4333 xmlXPathObjectPtr ret; 4334 4335 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4336 if (ret == NULL) { 4337 xmlXPathErrMemory(NULL, "creating nodeset\n"); 4338 return(NULL); 4339 } 4340 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4341 ret->type = XPATH_NODESET; 4342 ret->boolval = 0; 4343 ret->nodesetval = xmlXPathNodeSetCreate(val); 4344 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 4345 #ifdef XP_DEBUG_OBJ_USAGE 4346 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET); 4347 #endif 4348 return(ret); 4349 } 4350 4351 /** 4352 * xmlXPathNewValueTree: 4353 * @val: the NodePtr value 4354 * 4355 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize 4356 * it with the tree root @val 4357 * 4358 * Returns the newly created object. 4359 */ 4360 xmlXPathObjectPtr 4361 xmlXPathNewValueTree(xmlNodePtr val) { 4362 xmlXPathObjectPtr ret; 4363 4364 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4365 if (ret == NULL) { 4366 xmlXPathErrMemory(NULL, "creating result value tree\n"); 4367 return(NULL); 4368 } 4369 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4370 ret->type = XPATH_XSLT_TREE; 4371 ret->boolval = 0; 4372 ret->user = (void *) val; 4373 ret->nodesetval = xmlXPathNodeSetCreate(val); 4374 #ifdef XP_DEBUG_OBJ_USAGE 4375 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE); 4376 #endif 4377 return(ret); 4378 } 4379 4380 /** 4381 * xmlXPathNewNodeSetList: 4382 * @val: an existing NodeSet 4383 * 4384 * Create a new xmlXPathObjectPtr of type NodeSet and initialize 4385 * it with the Nodeset @val 4386 * 4387 * Returns the newly created object. 4388 */ 4389 xmlXPathObjectPtr 4390 xmlXPathNewNodeSetList(xmlNodeSetPtr val) 4391 { 4392 xmlXPathObjectPtr ret; 4393 int i; 4394 4395 if (val == NULL) 4396 ret = NULL; 4397 else if (val->nodeTab == NULL) 4398 ret = xmlXPathNewNodeSet(NULL); 4399 else { 4400 ret = xmlXPathNewNodeSet(val->nodeTab[0]); 4401 if (ret) { 4402 for (i = 1; i < val->nodeNr; ++i) { 4403 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]) 4404 < 0) break; 4405 } 4406 } 4407 } 4408 4409 return (ret); 4410 } 4411 4412 /** 4413 * xmlXPathWrapNodeSet: 4414 * @val: the NodePtr value 4415 * 4416 * Wrap the Nodeset @val in a new xmlXPathObjectPtr 4417 * 4418 * Returns the newly created object. 4419 */ 4420 xmlXPathObjectPtr 4421 xmlXPathWrapNodeSet(xmlNodeSetPtr val) { 4422 xmlXPathObjectPtr ret; 4423 4424 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4425 if (ret == NULL) { 4426 xmlXPathErrMemory(NULL, "creating node set object\n"); 4427 return(NULL); 4428 } 4429 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4430 ret->type = XPATH_NODESET; 4431 ret->nodesetval = val; 4432 #ifdef XP_DEBUG_OBJ_USAGE 4433 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET); 4434 #endif 4435 return(ret); 4436 } 4437 4438 /** 4439 * xmlXPathFreeNodeSetList: 4440 * @obj: an existing NodeSetList object 4441 * 4442 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in 4443 * the list contrary to xmlXPathFreeObject(). 4444 */ 4445 void 4446 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) { 4447 if (obj == NULL) return; 4448 #ifdef XP_DEBUG_OBJ_USAGE 4449 xmlXPathDebugObjUsageReleased(NULL, obj->type); 4450 #endif 4451 xmlFree(obj); 4452 } 4453 4454 /** 4455 * xmlXPathDifference: 4456 * @nodes1: a node-set 4457 * @nodes2: a node-set 4458 * 4459 * Implements the EXSLT - Sets difference() function: 4460 * node-set set:difference (node-set, node-set) 4461 * 4462 * Returns the difference between the two node sets, or nodes1 if 4463 * nodes2 is empty 4464 */ 4465 xmlNodeSetPtr 4466 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4467 xmlNodeSetPtr ret; 4468 int i, l1; 4469 xmlNodePtr cur; 4470 4471 if (xmlXPathNodeSetIsEmpty(nodes2)) 4472 return(nodes1); 4473 4474 ret = xmlXPathNodeSetCreate(NULL); 4475 if (xmlXPathNodeSetIsEmpty(nodes1)) 4476 return(ret); 4477 4478 l1 = xmlXPathNodeSetGetLength(nodes1); 4479 4480 for (i = 0; i < l1; i++) { 4481 cur = xmlXPathNodeSetItem(nodes1, i); 4482 if (!xmlXPathNodeSetContains(nodes2, cur)) { 4483 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) 4484 break; 4485 } 4486 } 4487 return(ret); 4488 } 4489 4490 /** 4491 * xmlXPathIntersection: 4492 * @nodes1: a node-set 4493 * @nodes2: a node-set 4494 * 4495 * Implements the EXSLT - Sets intersection() function: 4496 * node-set set:intersection (node-set, node-set) 4497 * 4498 * Returns a node set comprising the nodes that are within both the 4499 * node sets passed as arguments 4500 */ 4501 xmlNodeSetPtr 4502 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4503 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL); 4504 int i, l1; 4505 xmlNodePtr cur; 4506 4507 if (ret == NULL) 4508 return(ret); 4509 if (xmlXPathNodeSetIsEmpty(nodes1)) 4510 return(ret); 4511 if (xmlXPathNodeSetIsEmpty(nodes2)) 4512 return(ret); 4513 4514 l1 = xmlXPathNodeSetGetLength(nodes1); 4515 4516 for (i = 0; i < l1; i++) { 4517 cur = xmlXPathNodeSetItem(nodes1, i); 4518 if (xmlXPathNodeSetContains(nodes2, cur)) { 4519 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) 4520 break; 4521 } 4522 } 4523 return(ret); 4524 } 4525 4526 /** 4527 * xmlXPathDistinctSorted: 4528 * @nodes: a node-set, sorted by document order 4529 * 4530 * Implements the EXSLT - Sets distinct() function: 4531 * node-set set:distinct (node-set) 4532 * 4533 * Returns a subset of the nodes contained in @nodes, or @nodes if 4534 * it is empty 4535 */ 4536 xmlNodeSetPtr 4537 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) { 4538 xmlNodeSetPtr ret; 4539 xmlHashTablePtr hash; 4540 int i, l; 4541 xmlChar * strval; 4542 xmlNodePtr cur; 4543 4544 if (xmlXPathNodeSetIsEmpty(nodes)) 4545 return(nodes); 4546 4547 ret = xmlXPathNodeSetCreate(NULL); 4548 if (ret == NULL) 4549 return(ret); 4550 l = xmlXPathNodeSetGetLength(nodes); 4551 hash = xmlHashCreate (l); 4552 for (i = 0; i < l; i++) { 4553 cur = xmlXPathNodeSetItem(nodes, i); 4554 strval = xmlXPathCastNodeToString(cur); 4555 if (xmlHashLookup(hash, strval) == NULL) { 4556 xmlHashAddEntry(hash, strval, strval); 4557 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) 4558 break; 4559 } else { 4560 xmlFree(strval); 4561 } 4562 } 4563 xmlHashFree(hash, (xmlHashDeallocator) xmlFree); 4564 return(ret); 4565 } 4566 4567 /** 4568 * xmlXPathDistinct: 4569 * @nodes: a node-set 4570 * 4571 * Implements the EXSLT - Sets distinct() function: 4572 * node-set set:distinct (node-set) 4573 * @nodes is sorted by document order, then #exslSetsDistinctSorted 4574 * is called with the sorted node-set 4575 * 4576 * Returns a subset of the nodes contained in @nodes, or @nodes if 4577 * it is empty 4578 */ 4579 xmlNodeSetPtr 4580 xmlXPathDistinct (xmlNodeSetPtr nodes) { 4581 if (xmlXPathNodeSetIsEmpty(nodes)) 4582 return(nodes); 4583 4584 xmlXPathNodeSetSort(nodes); 4585 return(xmlXPathDistinctSorted(nodes)); 4586 } 4587 4588 /** 4589 * xmlXPathHasSameNodes: 4590 * @nodes1: a node-set 4591 * @nodes2: a node-set 4592 * 4593 * Implements the EXSLT - Sets has-same-nodes function: 4594 * boolean set:has-same-node(node-set, node-set) 4595 * 4596 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0) 4597 * otherwise 4598 */ 4599 int 4600 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4601 int i, l; 4602 xmlNodePtr cur; 4603 4604 if (xmlXPathNodeSetIsEmpty(nodes1) || 4605 xmlXPathNodeSetIsEmpty(nodes2)) 4606 return(0); 4607 4608 l = xmlXPathNodeSetGetLength(nodes1); 4609 for (i = 0; i < l; i++) { 4610 cur = xmlXPathNodeSetItem(nodes1, i); 4611 if (xmlXPathNodeSetContains(nodes2, cur)) 4612 return(1); 4613 } 4614 return(0); 4615 } 4616 4617 /** 4618 * xmlXPathNodeLeadingSorted: 4619 * @nodes: a node-set, sorted by document order 4620 * @node: a node 4621 * 4622 * Implements the EXSLT - Sets leading() function: 4623 * node-set set:leading (node-set, node-set) 4624 * 4625 * Returns the nodes in @nodes that precede @node in document order, 4626 * @nodes if @node is NULL or an empty node-set if @nodes 4627 * doesn't contain @node 4628 */ 4629 xmlNodeSetPtr 4630 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { 4631 int i, l; 4632 xmlNodePtr cur; 4633 xmlNodeSetPtr ret; 4634 4635 if (node == NULL) 4636 return(nodes); 4637 4638 ret = xmlXPathNodeSetCreate(NULL); 4639 if (ret == NULL) 4640 return(ret); 4641 if (xmlXPathNodeSetIsEmpty(nodes) || 4642 (!xmlXPathNodeSetContains(nodes, node))) 4643 return(ret); 4644 4645 l = xmlXPathNodeSetGetLength(nodes); 4646 for (i = 0; i < l; i++) { 4647 cur = xmlXPathNodeSetItem(nodes, i); 4648 if (cur == node) 4649 break; 4650 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) 4651 break; 4652 } 4653 return(ret); 4654 } 4655 4656 /** 4657 * xmlXPathNodeLeading: 4658 * @nodes: a node-set 4659 * @node: a node 4660 * 4661 * Implements the EXSLT - Sets leading() function: 4662 * node-set set:leading (node-set, node-set) 4663 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted 4664 * is called. 4665 * 4666 * Returns the nodes in @nodes that precede @node in document order, 4667 * @nodes if @node is NULL or an empty node-set if @nodes 4668 * doesn't contain @node 4669 */ 4670 xmlNodeSetPtr 4671 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) { 4672 xmlXPathNodeSetSort(nodes); 4673 return(xmlXPathNodeLeadingSorted(nodes, node)); 4674 } 4675 4676 /** 4677 * xmlXPathLeadingSorted: 4678 * @nodes1: a node-set, sorted by document order 4679 * @nodes2: a node-set, sorted by document order 4680 * 4681 * Implements the EXSLT - Sets leading() function: 4682 * node-set set:leading (node-set, node-set) 4683 * 4684 * Returns the nodes in @nodes1 that precede the first node in @nodes2 4685 * in document order, @nodes1 if @nodes2 is NULL or empty or 4686 * an empty node-set if @nodes1 doesn't contain @nodes2 4687 */ 4688 xmlNodeSetPtr 4689 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4690 if (xmlXPathNodeSetIsEmpty(nodes2)) 4691 return(nodes1); 4692 return(xmlXPathNodeLeadingSorted(nodes1, 4693 xmlXPathNodeSetItem(nodes2, 1))); 4694 } 4695 4696 /** 4697 * xmlXPathLeading: 4698 * @nodes1: a node-set 4699 * @nodes2: a node-set 4700 * 4701 * Implements the EXSLT - Sets leading() function: 4702 * node-set set:leading (node-set, node-set) 4703 * @nodes1 and @nodes2 are sorted by document order, then 4704 * #exslSetsLeadingSorted is called. 4705 * 4706 * Returns the nodes in @nodes1 that precede the first node in @nodes2 4707 * in document order, @nodes1 if @nodes2 is NULL or empty or 4708 * an empty node-set if @nodes1 doesn't contain @nodes2 4709 */ 4710 xmlNodeSetPtr 4711 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4712 if (xmlXPathNodeSetIsEmpty(nodes2)) 4713 return(nodes1); 4714 if (xmlXPathNodeSetIsEmpty(nodes1)) 4715 return(xmlXPathNodeSetCreate(NULL)); 4716 xmlXPathNodeSetSort(nodes1); 4717 xmlXPathNodeSetSort(nodes2); 4718 return(xmlXPathNodeLeadingSorted(nodes1, 4719 xmlXPathNodeSetItem(nodes2, 1))); 4720 } 4721 4722 /** 4723 * xmlXPathNodeTrailingSorted: 4724 * @nodes: a node-set, sorted by document order 4725 * @node: a node 4726 * 4727 * Implements the EXSLT - Sets trailing() function: 4728 * node-set set:trailing (node-set, node-set) 4729 * 4730 * Returns the nodes in @nodes that follow @node in document order, 4731 * @nodes if @node is NULL or an empty node-set if @nodes 4732 * doesn't contain @node 4733 */ 4734 xmlNodeSetPtr 4735 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { 4736 int i, l; 4737 xmlNodePtr cur; 4738 xmlNodeSetPtr ret; 4739 4740 if (node == NULL) 4741 return(nodes); 4742 4743 ret = xmlXPathNodeSetCreate(NULL); 4744 if (ret == NULL) 4745 return(ret); 4746 if (xmlXPathNodeSetIsEmpty(nodes) || 4747 (!xmlXPathNodeSetContains(nodes, node))) 4748 return(ret); 4749 4750 l = xmlXPathNodeSetGetLength(nodes); 4751 for (i = l - 1; i >= 0; i--) { 4752 cur = xmlXPathNodeSetItem(nodes, i); 4753 if (cur == node) 4754 break; 4755 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) 4756 break; 4757 } 4758 xmlXPathNodeSetSort(ret); /* bug 413451 */ 4759 return(ret); 4760 } 4761 4762 /** 4763 * xmlXPathNodeTrailing: 4764 * @nodes: a node-set 4765 * @node: a node 4766 * 4767 * Implements the EXSLT - Sets trailing() function: 4768 * node-set set:trailing (node-set, node-set) 4769 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted 4770 * is called. 4771 * 4772 * Returns the nodes in @nodes that follow @node in document order, 4773 * @nodes if @node is NULL or an empty node-set if @nodes 4774 * doesn't contain @node 4775 */ 4776 xmlNodeSetPtr 4777 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) { 4778 xmlXPathNodeSetSort(nodes); 4779 return(xmlXPathNodeTrailingSorted(nodes, node)); 4780 } 4781 4782 /** 4783 * xmlXPathTrailingSorted: 4784 * @nodes1: a node-set, sorted by document order 4785 * @nodes2: a node-set, sorted by document order 4786 * 4787 * Implements the EXSLT - Sets trailing() function: 4788 * node-set set:trailing (node-set, node-set) 4789 * 4790 * Returns the nodes in @nodes1 that follow the first node in @nodes2 4791 * in document order, @nodes1 if @nodes2 is NULL or empty or 4792 * an empty node-set if @nodes1 doesn't contain @nodes2 4793 */ 4794 xmlNodeSetPtr 4795 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4796 if (xmlXPathNodeSetIsEmpty(nodes2)) 4797 return(nodes1); 4798 return(xmlXPathNodeTrailingSorted(nodes1, 4799 xmlXPathNodeSetItem(nodes2, 0))); 4800 } 4801 4802 /** 4803 * xmlXPathTrailing: 4804 * @nodes1: a node-set 4805 * @nodes2: a node-set 4806 * 4807 * Implements the EXSLT - Sets trailing() function: 4808 * node-set set:trailing (node-set, node-set) 4809 * @nodes1 and @nodes2 are sorted by document order, then 4810 * #xmlXPathTrailingSorted is called. 4811 * 4812 * Returns the nodes in @nodes1 that follow the first node in @nodes2 4813 * in document order, @nodes1 if @nodes2 is NULL or empty or 4814 * an empty node-set if @nodes1 doesn't contain @nodes2 4815 */ 4816 xmlNodeSetPtr 4817 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4818 if (xmlXPathNodeSetIsEmpty(nodes2)) 4819 return(nodes1); 4820 if (xmlXPathNodeSetIsEmpty(nodes1)) 4821 return(xmlXPathNodeSetCreate(NULL)); 4822 xmlXPathNodeSetSort(nodes1); 4823 xmlXPathNodeSetSort(nodes2); 4824 return(xmlXPathNodeTrailingSorted(nodes1, 4825 xmlXPathNodeSetItem(nodes2, 0))); 4826 } 4827 4828 /************************************************************************ 4829 * * 4830 * Routines to handle extra functions * 4831 * * 4832 ************************************************************************/ 4833 4834 /** 4835 * xmlXPathRegisterFunc: 4836 * @ctxt: the XPath context 4837 * @name: the function name 4838 * @f: the function implementation or NULL 4839 * 4840 * Register a new function. If @f is NULL it unregisters the function 4841 * 4842 * Returns 0 in case of success, -1 in case of error 4843 */ 4844 int 4845 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name, 4846 xmlXPathFunction f) { 4847 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f)); 4848 } 4849 4850 /** 4851 * xmlXPathRegisterFuncNS: 4852 * @ctxt: the XPath context 4853 * @name: the function name 4854 * @ns_uri: the function namespace URI 4855 * @f: the function implementation or NULL 4856 * 4857 * Register a new function. If @f is NULL it unregisters the function 4858 * 4859 * Returns 0 in case of success, -1 in case of error 4860 */ 4861 int 4862 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name, 4863 const xmlChar *ns_uri, xmlXPathFunction f) { 4864 if (ctxt == NULL) 4865 return(-1); 4866 if (name == NULL) 4867 return(-1); 4868 4869 if (ctxt->funcHash == NULL) 4870 ctxt->funcHash = xmlHashCreate(0); 4871 if (ctxt->funcHash == NULL) 4872 return(-1); 4873 if (f == NULL) 4874 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL)); 4875 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f))); 4876 } 4877 4878 /** 4879 * xmlXPathRegisterFuncLookup: 4880 * @ctxt: the XPath context 4881 * @f: the lookup function 4882 * @funcCtxt: the lookup data 4883 * 4884 * Registers an external mechanism to do function lookup. 4885 */ 4886 void 4887 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt, 4888 xmlXPathFuncLookupFunc f, 4889 void *funcCtxt) { 4890 if (ctxt == NULL) 4891 return; 4892 ctxt->funcLookupFunc = f; 4893 ctxt->funcLookupData = funcCtxt; 4894 } 4895 4896 /** 4897 * xmlXPathFunctionLookup: 4898 * @ctxt: the XPath context 4899 * @name: the function name 4900 * 4901 * Search in the Function array of the context for the given 4902 * function. 4903 * 4904 * Returns the xmlXPathFunction or NULL if not found 4905 */ 4906 xmlXPathFunction 4907 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { 4908 if (ctxt == NULL) 4909 return (NULL); 4910 4911 if (ctxt->funcLookupFunc != NULL) { 4912 xmlXPathFunction ret; 4913 xmlXPathFuncLookupFunc f; 4914 4915 f = ctxt->funcLookupFunc; 4916 ret = f(ctxt->funcLookupData, name, NULL); 4917 if (ret != NULL) 4918 return(ret); 4919 } 4920 return(xmlXPathFunctionLookupNS(ctxt, name, NULL)); 4921 } 4922 4923 /** 4924 * xmlXPathFunctionLookupNS: 4925 * @ctxt: the XPath context 4926 * @name: the function name 4927 * @ns_uri: the function namespace URI 4928 * 4929 * Search in the Function array of the context for the given 4930 * function. 4931 * 4932 * Returns the xmlXPathFunction or NULL if not found 4933 */ 4934 xmlXPathFunction 4935 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name, 4936 const xmlChar *ns_uri) { 4937 xmlXPathFunction ret; 4938 4939 if (ctxt == NULL) 4940 return(NULL); 4941 if (name == NULL) 4942 return(NULL); 4943 4944 if (ctxt->funcLookupFunc != NULL) { 4945 xmlXPathFuncLookupFunc f; 4946 4947 f = ctxt->funcLookupFunc; 4948 ret = f(ctxt->funcLookupData, name, ns_uri); 4949 if (ret != NULL) 4950 return(ret); 4951 } 4952 4953 if (ctxt->funcHash == NULL) 4954 return(NULL); 4955 4956 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri); 4957 return(ret); 4958 } 4959 4960 /** 4961 * xmlXPathRegisteredFuncsCleanup: 4962 * @ctxt: the XPath context 4963 * 4964 * Cleanup the XPath context data associated to registered functions 4965 */ 4966 void 4967 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) { 4968 if (ctxt == NULL) 4969 return; 4970 4971 xmlHashFree(ctxt->funcHash, NULL); 4972 ctxt->funcHash = NULL; 4973 } 4974 4975 /************************************************************************ 4976 * * 4977 * Routines to handle Variables * 4978 * * 4979 ************************************************************************/ 4980 4981 /** 4982 * xmlXPathRegisterVariable: 4983 * @ctxt: the XPath context 4984 * @name: the variable name 4985 * @value: the variable value or NULL 4986 * 4987 * Register a new variable value. If @value is NULL it unregisters 4988 * the variable 4989 * 4990 * Returns 0 in case of success, -1 in case of error 4991 */ 4992 int 4993 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name, 4994 xmlXPathObjectPtr value) { 4995 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value)); 4996 } 4997 4998 /** 4999 * xmlXPathRegisterVariableNS: 5000 * @ctxt: the XPath context 5001 * @name: the variable name 5002 * @ns_uri: the variable namespace URI 5003 * @value: the variable value or NULL 5004 * 5005 * Register a new variable value. If @value is NULL it unregisters 5006 * the variable 5007 * 5008 * Returns 0 in case of success, -1 in case of error 5009 */ 5010 int 5011 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name, 5012 const xmlChar *ns_uri, 5013 xmlXPathObjectPtr value) { 5014 if (ctxt == NULL) 5015 return(-1); 5016 if (name == NULL) 5017 return(-1); 5018 5019 if (ctxt->varHash == NULL) 5020 ctxt->varHash = xmlHashCreate(0); 5021 if (ctxt->varHash == NULL) 5022 return(-1); 5023 if (value == NULL) 5024 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri, 5025 (xmlHashDeallocator)xmlXPathFreeObject)); 5026 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri, 5027 (void *) value, 5028 (xmlHashDeallocator)xmlXPathFreeObject)); 5029 } 5030 5031 /** 5032 * xmlXPathRegisterVariableLookup: 5033 * @ctxt: the XPath context 5034 * @f: the lookup function 5035 * @data: the lookup data 5036 * 5037 * register an external mechanism to do variable lookup 5038 */ 5039 void 5040 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt, 5041 xmlXPathVariableLookupFunc f, void *data) { 5042 if (ctxt == NULL) 5043 return; 5044 ctxt->varLookupFunc = f; 5045 ctxt->varLookupData = data; 5046 } 5047 5048 /** 5049 * xmlXPathVariableLookup: 5050 * @ctxt: the XPath context 5051 * @name: the variable name 5052 * 5053 * Search in the Variable array of the context for the given 5054 * variable value. 5055 * 5056 * Returns a copy of the value or NULL if not found 5057 */ 5058 xmlXPathObjectPtr 5059 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { 5060 if (ctxt == NULL) 5061 return(NULL); 5062 5063 if (ctxt->varLookupFunc != NULL) { 5064 xmlXPathObjectPtr ret; 5065 5066 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc) 5067 (ctxt->varLookupData, name, NULL); 5068 return(ret); 5069 } 5070 return(xmlXPathVariableLookupNS(ctxt, name, NULL)); 5071 } 5072 5073 /** 5074 * xmlXPathVariableLookupNS: 5075 * @ctxt: the XPath context 5076 * @name: the variable name 5077 * @ns_uri: the variable namespace URI 5078 * 5079 * Search in the Variable array of the context for the given 5080 * variable value. 5081 * 5082 * Returns the a copy of the value or NULL if not found 5083 */ 5084 xmlXPathObjectPtr 5085 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name, 5086 const xmlChar *ns_uri) { 5087 if (ctxt == NULL) 5088 return(NULL); 5089 5090 if (ctxt->varLookupFunc != NULL) { 5091 xmlXPathObjectPtr ret; 5092 5093 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc) 5094 (ctxt->varLookupData, name, ns_uri); 5095 if (ret != NULL) return(ret); 5096 } 5097 5098 if (ctxt->varHash == NULL) 5099 return(NULL); 5100 if (name == NULL) 5101 return(NULL); 5102 5103 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr) 5104 xmlHashLookup2(ctxt->varHash, name, ns_uri))); 5105 } 5106 5107 /** 5108 * xmlXPathRegisteredVariablesCleanup: 5109 * @ctxt: the XPath context 5110 * 5111 * Cleanup the XPath context data associated to registered variables 5112 */ 5113 void 5114 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) { 5115 if (ctxt == NULL) 5116 return; 5117 5118 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject); 5119 ctxt->varHash = NULL; 5120 } 5121 5122 /** 5123 * xmlXPathRegisterNs: 5124 * @ctxt: the XPath context 5125 * @prefix: the namespace prefix cannot be NULL or empty string 5126 * @ns_uri: the namespace name 5127 * 5128 * Register a new namespace. If @ns_uri is NULL it unregisters 5129 * the namespace 5130 * 5131 * Returns 0 in case of success, -1 in case of error 5132 */ 5133 int 5134 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix, 5135 const xmlChar *ns_uri) { 5136 if (ctxt == NULL) 5137 return(-1); 5138 if (prefix == NULL) 5139 return(-1); 5140 if (prefix[0] == 0) 5141 return(-1); 5142 5143 if (ctxt->nsHash == NULL) 5144 ctxt->nsHash = xmlHashCreate(10); 5145 if (ctxt->nsHash == NULL) 5146 return(-1); 5147 if (ns_uri == NULL) 5148 return(xmlHashRemoveEntry(ctxt->nsHash, prefix, 5149 (xmlHashDeallocator)xmlFree)); 5150 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri), 5151 (xmlHashDeallocator)xmlFree)); 5152 } 5153 5154 /** 5155 * xmlXPathNsLookup: 5156 * @ctxt: the XPath context 5157 * @prefix: the namespace prefix value 5158 * 5159 * Search in the namespace declaration array of the context for the given 5160 * namespace name associated to the given prefix 5161 * 5162 * Returns the value or NULL if not found 5163 */ 5164 const xmlChar * 5165 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) { 5166 if (ctxt == NULL) 5167 return(NULL); 5168 if (prefix == NULL) 5169 return(NULL); 5170 5171 #ifdef XML_XML_NAMESPACE 5172 if (xmlStrEqual(prefix, (const xmlChar *) "xml")) 5173 return(XML_XML_NAMESPACE); 5174 #endif 5175 5176 if (ctxt->namespaces != NULL) { 5177 int i; 5178 5179 for (i = 0;i < ctxt->nsNr;i++) { 5180 if ((ctxt->namespaces[i] != NULL) && 5181 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix))) 5182 return(ctxt->namespaces[i]->href); 5183 } 5184 } 5185 5186 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix)); 5187 } 5188 5189 /** 5190 * xmlXPathRegisteredNsCleanup: 5191 * @ctxt: the XPath context 5192 * 5193 * Cleanup the XPath context data associated to registered variables 5194 */ 5195 void 5196 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) { 5197 if (ctxt == NULL) 5198 return; 5199 5200 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree); 5201 ctxt->nsHash = NULL; 5202 } 5203 5204 /************************************************************************ 5205 * * 5206 * Routines to handle Values * 5207 * * 5208 ************************************************************************/ 5209 5210 /* Allocations are terrible, one needs to optimize all this !!! */ 5211 5212 /** 5213 * xmlXPathNewFloat: 5214 * @val: the double value 5215 * 5216 * Create a new xmlXPathObjectPtr of type double and of value @val 5217 * 5218 * Returns the newly created object. 5219 */ 5220 xmlXPathObjectPtr 5221 xmlXPathNewFloat(double val) { 5222 xmlXPathObjectPtr ret; 5223 5224 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5225 if (ret == NULL) { 5226 xmlXPathErrMemory(NULL, "creating float object\n"); 5227 return(NULL); 5228 } 5229 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5230 ret->type = XPATH_NUMBER; 5231 ret->floatval = val; 5232 #ifdef XP_DEBUG_OBJ_USAGE 5233 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER); 5234 #endif 5235 return(ret); 5236 } 5237 5238 /** 5239 * xmlXPathNewBoolean: 5240 * @val: the boolean value 5241 * 5242 * Create a new xmlXPathObjectPtr of type boolean and of value @val 5243 * 5244 * Returns the newly created object. 5245 */ 5246 xmlXPathObjectPtr 5247 xmlXPathNewBoolean(int val) { 5248 xmlXPathObjectPtr ret; 5249 5250 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5251 if (ret == NULL) { 5252 xmlXPathErrMemory(NULL, "creating boolean object\n"); 5253 return(NULL); 5254 } 5255 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5256 ret->type = XPATH_BOOLEAN; 5257 ret->boolval = (val != 0); 5258 #ifdef XP_DEBUG_OBJ_USAGE 5259 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN); 5260 #endif 5261 return(ret); 5262 } 5263 5264 /** 5265 * xmlXPathNewString: 5266 * @val: the xmlChar * value 5267 * 5268 * Create a new xmlXPathObjectPtr of type string and of value @val 5269 * 5270 * Returns the newly created object. 5271 */ 5272 xmlXPathObjectPtr 5273 xmlXPathNewString(const xmlChar *val) { 5274 xmlXPathObjectPtr ret; 5275 5276 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5277 if (ret == NULL) { 5278 xmlXPathErrMemory(NULL, "creating string object\n"); 5279 return(NULL); 5280 } 5281 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5282 ret->type = XPATH_STRING; 5283 if (val != NULL) 5284 ret->stringval = xmlStrdup(val); 5285 else 5286 ret->stringval = xmlStrdup((const xmlChar *)""); 5287 #ifdef XP_DEBUG_OBJ_USAGE 5288 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); 5289 #endif 5290 return(ret); 5291 } 5292 5293 /** 5294 * xmlXPathWrapString: 5295 * @val: the xmlChar * value 5296 * 5297 * Wraps the @val string into an XPath object. 5298 * 5299 * Returns the newly created object. 5300 */ 5301 xmlXPathObjectPtr 5302 xmlXPathWrapString (xmlChar *val) { 5303 xmlXPathObjectPtr ret; 5304 5305 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5306 if (ret == NULL) { 5307 xmlXPathErrMemory(NULL, "creating string object\n"); 5308 return(NULL); 5309 } 5310 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5311 ret->type = XPATH_STRING; 5312 ret->stringval = val; 5313 #ifdef XP_DEBUG_OBJ_USAGE 5314 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); 5315 #endif 5316 return(ret); 5317 } 5318 5319 /** 5320 * xmlXPathNewCString: 5321 * @val: the char * value 5322 * 5323 * Create a new xmlXPathObjectPtr of type string and of value @val 5324 * 5325 * Returns the newly created object. 5326 */ 5327 xmlXPathObjectPtr 5328 xmlXPathNewCString(const char *val) { 5329 xmlXPathObjectPtr ret; 5330 5331 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5332 if (ret == NULL) { 5333 xmlXPathErrMemory(NULL, "creating string object\n"); 5334 return(NULL); 5335 } 5336 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5337 ret->type = XPATH_STRING; 5338 ret->stringval = xmlStrdup(BAD_CAST val); 5339 #ifdef XP_DEBUG_OBJ_USAGE 5340 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); 5341 #endif 5342 return(ret); 5343 } 5344 5345 /** 5346 * xmlXPathWrapCString: 5347 * @val: the char * value 5348 * 5349 * Wraps a string into an XPath object. 5350 * 5351 * Returns the newly created object. 5352 */ 5353 xmlXPathObjectPtr 5354 xmlXPathWrapCString (char * val) { 5355 return(xmlXPathWrapString((xmlChar *)(val))); 5356 } 5357 5358 /** 5359 * xmlXPathWrapExternal: 5360 * @val: the user data 5361 * 5362 * Wraps the @val data into an XPath object. 5363 * 5364 * Returns the newly created object. 5365 */ 5366 xmlXPathObjectPtr 5367 xmlXPathWrapExternal (void *val) { 5368 xmlXPathObjectPtr ret; 5369 5370 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5371 if (ret == NULL) { 5372 xmlXPathErrMemory(NULL, "creating user object\n"); 5373 return(NULL); 5374 } 5375 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5376 ret->type = XPATH_USERS; 5377 ret->user = val; 5378 #ifdef XP_DEBUG_OBJ_USAGE 5379 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS); 5380 #endif 5381 return(ret); 5382 } 5383 5384 /** 5385 * xmlXPathObjectCopy: 5386 * @val: the original object 5387 * 5388 * allocate a new copy of a given object 5389 * 5390 * Returns the newly created object. 5391 */ 5392 xmlXPathObjectPtr 5393 xmlXPathObjectCopy(xmlXPathObjectPtr val) { 5394 xmlXPathObjectPtr ret; 5395 5396 if (val == NULL) 5397 return(NULL); 5398 5399 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5400 if (ret == NULL) { 5401 xmlXPathErrMemory(NULL, "copying object\n"); 5402 return(NULL); 5403 } 5404 memcpy(ret, val , (size_t) sizeof(xmlXPathObject)); 5405 #ifdef XP_DEBUG_OBJ_USAGE 5406 xmlXPathDebugObjUsageRequested(NULL, val->type); 5407 #endif 5408 switch (val->type) { 5409 case XPATH_BOOLEAN: 5410 case XPATH_NUMBER: 5411 case XPATH_POINT: 5412 case XPATH_RANGE: 5413 break; 5414 case XPATH_STRING: 5415 ret->stringval = xmlStrdup(val->stringval); 5416 break; 5417 case XPATH_XSLT_TREE: 5418 #if 0 5419 /* 5420 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that 5421 this previous handling is no longer correct, and can cause some serious 5422 problems (ref. bug 145547) 5423 */ 5424 if ((val->nodesetval != NULL) && 5425 (val->nodesetval->nodeTab != NULL)) { 5426 xmlNodePtr cur, tmp; 5427 xmlDocPtr top; 5428 5429 ret->boolval = 1; 5430 top = xmlNewDoc(NULL); 5431 top->name = (char *) 5432 xmlStrdup(val->nodesetval->nodeTab[0]->name); 5433 ret->user = top; 5434 if (top != NULL) { 5435 top->doc = top; 5436 cur = val->nodesetval->nodeTab[0]->children; 5437 while (cur != NULL) { 5438 tmp = xmlDocCopyNode(cur, top, 1); 5439 xmlAddChild((xmlNodePtr) top, tmp); 5440 cur = cur->next; 5441 } 5442 } 5443 5444 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top); 5445 } else 5446 ret->nodesetval = xmlXPathNodeSetCreate(NULL); 5447 /* Deallocate the copied tree value */ 5448 break; 5449 #endif 5450 case XPATH_NODESET: 5451 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval); 5452 /* Do not deallocate the copied tree value */ 5453 ret->boolval = 0; 5454 break; 5455 case XPATH_LOCATIONSET: 5456 #ifdef LIBXML_XPTR_ENABLED 5457 { 5458 xmlLocationSetPtr loc = val->user; 5459 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc); 5460 break; 5461 } 5462 #endif 5463 case XPATH_USERS: 5464 ret->user = val->user; 5465 break; 5466 case XPATH_UNDEFINED: 5467 xmlGenericError(xmlGenericErrorContext, 5468 "xmlXPathObjectCopy: unsupported type %d\n", 5469 val->type); 5470 break; 5471 } 5472 return(ret); 5473 } 5474 5475 /** 5476 * xmlXPathFreeObject: 5477 * @obj: the object to free 5478 * 5479 * Free up an xmlXPathObjectPtr object. 5480 */ 5481 void 5482 xmlXPathFreeObject(xmlXPathObjectPtr obj) { 5483 if (obj == NULL) return; 5484 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) { 5485 if (obj->boolval) { 5486 #if 0 5487 if (obj->user != NULL) { 5488 xmlXPathFreeNodeSet(obj->nodesetval); 5489 xmlFreeNodeList((xmlNodePtr) obj->user); 5490 } else 5491 #endif 5492 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */ 5493 if (obj->nodesetval != NULL) 5494 xmlXPathFreeValueTree(obj->nodesetval); 5495 } else { 5496 if (obj->nodesetval != NULL) 5497 xmlXPathFreeNodeSet(obj->nodesetval); 5498 } 5499 #ifdef LIBXML_XPTR_ENABLED 5500 } else if (obj->type == XPATH_LOCATIONSET) { 5501 if (obj->user != NULL) 5502 xmlXPtrFreeLocationSet(obj->user); 5503 #endif 5504 } else if (obj->type == XPATH_STRING) { 5505 if (obj->stringval != NULL) 5506 xmlFree(obj->stringval); 5507 } 5508 #ifdef XP_DEBUG_OBJ_USAGE 5509 xmlXPathDebugObjUsageReleased(NULL, obj->type); 5510 #endif 5511 xmlFree(obj); 5512 } 5513 5514 /** 5515 * xmlXPathReleaseObject: 5516 * @obj: the xmlXPathObjectPtr to free or to cache 5517 * 5518 * Depending on the state of the cache this frees the given 5519 * XPath object or stores it in the cache. 5520 */ 5521 static void 5522 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj) 5523 { 5524 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \ 5525 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \ 5526 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj; 5527 5528 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n)) 5529 5530 if (obj == NULL) 5531 return; 5532 if ((ctxt == NULL) || (ctxt->cache == NULL)) { 5533 xmlXPathFreeObject(obj); 5534 } else { 5535 xmlXPathContextCachePtr cache = 5536 (xmlXPathContextCachePtr) ctxt->cache; 5537 5538 switch (obj->type) { 5539 case XPATH_NODESET: 5540 case XPATH_XSLT_TREE: 5541 if (obj->nodesetval != NULL) { 5542 if (obj->boolval) { 5543 /* 5544 * It looks like the @boolval is used for 5545 * evaluation if this an XSLT Result Tree Fragment. 5546 * TODO: Check if this assumption is correct. 5547 */ 5548 obj->type = XPATH_XSLT_TREE; /* just for debugging */ 5549 xmlXPathFreeValueTree(obj->nodesetval); 5550 obj->nodesetval = NULL; 5551 } else if ((obj->nodesetval->nodeMax <= 40) && 5552 (XP_CACHE_WANTS(cache->nodesetObjs, 5553 cache->maxNodeset))) 5554 { 5555 XP_CACHE_ADD(cache->nodesetObjs, obj); 5556 goto obj_cached; 5557 } else { 5558 xmlXPathFreeNodeSet(obj->nodesetval); 5559 obj->nodesetval = NULL; 5560 } 5561 } 5562 break; 5563 case XPATH_STRING: 5564 if (obj->stringval != NULL) 5565 xmlFree(obj->stringval); 5566 5567 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) { 5568 XP_CACHE_ADD(cache->stringObjs, obj); 5569 goto obj_cached; 5570 } 5571 break; 5572 case XPATH_BOOLEAN: 5573 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) { 5574 XP_CACHE_ADD(cache->booleanObjs, obj); 5575 goto obj_cached; 5576 } 5577 break; 5578 case XPATH_NUMBER: 5579 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) { 5580 XP_CACHE_ADD(cache->numberObjs, obj); 5581 goto obj_cached; 5582 } 5583 break; 5584 #ifdef LIBXML_XPTR_ENABLED 5585 case XPATH_LOCATIONSET: 5586 if (obj->user != NULL) { 5587 xmlXPtrFreeLocationSet(obj->user); 5588 } 5589 goto free_obj; 5590 #endif 5591 default: 5592 goto free_obj; 5593 } 5594 5595 /* 5596 * Fallback to adding to the misc-objects slot. 5597 */ 5598 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) { 5599 XP_CACHE_ADD(cache->miscObjs, obj); 5600 } else 5601 goto free_obj; 5602 5603 obj_cached: 5604 5605 #ifdef XP_DEBUG_OBJ_USAGE 5606 xmlXPathDebugObjUsageReleased(ctxt, obj->type); 5607 #endif 5608 5609 if (obj->nodesetval != NULL) { 5610 xmlNodeSetPtr tmpset = obj->nodesetval; 5611 5612 /* 5613 * TODO: Due to those nasty ns-nodes, we need to traverse 5614 * the list and free the ns-nodes. 5615 * URGENT TODO: Check if it's actually slowing things down. 5616 * Maybe we shouldn't try to preserve the list. 5617 */ 5618 if (tmpset->nodeNr > 1) { 5619 int i; 5620 xmlNodePtr node; 5621 5622 for (i = 0; i < tmpset->nodeNr; i++) { 5623 node = tmpset->nodeTab[i]; 5624 if ((node != NULL) && 5625 (node->type == XML_NAMESPACE_DECL)) 5626 { 5627 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 5628 } 5629 } 5630 } else if (tmpset->nodeNr == 1) { 5631 if ((tmpset->nodeTab[0] != NULL) && 5632 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL)) 5633 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]); 5634 } 5635 tmpset->nodeNr = 0; 5636 memset(obj, 0, sizeof(xmlXPathObject)); 5637 obj->nodesetval = tmpset; 5638 } else 5639 memset(obj, 0, sizeof(xmlXPathObject)); 5640 5641 return; 5642 5643 free_obj: 5644 /* 5645 * Cache is full; free the object. 5646 */ 5647 if (obj->nodesetval != NULL) 5648 xmlXPathFreeNodeSet(obj->nodesetval); 5649 #ifdef XP_DEBUG_OBJ_USAGE 5650 xmlXPathDebugObjUsageReleased(NULL, obj->type); 5651 #endif 5652 xmlFree(obj); 5653 } 5654 return; 5655 } 5656 5657 5658 /************************************************************************ 5659 * * 5660 * Type Casting Routines * 5661 * * 5662 ************************************************************************/ 5663 5664 /** 5665 * xmlXPathCastBooleanToString: 5666 * @val: a boolean 5667 * 5668 * Converts a boolean to its string value. 5669 * 5670 * Returns a newly allocated string. 5671 */ 5672 xmlChar * 5673 xmlXPathCastBooleanToString (int val) { 5674 xmlChar *ret; 5675 if (val) 5676 ret = xmlStrdup((const xmlChar *) "true"); 5677 else 5678 ret = xmlStrdup((const xmlChar *) "false"); 5679 return(ret); 5680 } 5681 5682 /** 5683 * xmlXPathCastNumberToString: 5684 * @val: a number 5685 * 5686 * Converts a number to its string value. 5687 * 5688 * Returns a newly allocated string. 5689 */ 5690 xmlChar * 5691 xmlXPathCastNumberToString (double val) { 5692 xmlChar *ret; 5693 switch (xmlXPathIsInf(val)) { 5694 case 1: 5695 ret = xmlStrdup((const xmlChar *) "Infinity"); 5696 break; 5697 case -1: 5698 ret = xmlStrdup((const xmlChar *) "-Infinity"); 5699 break; 5700 default: 5701 if (xmlXPathIsNaN(val)) { 5702 ret = xmlStrdup((const xmlChar *) "NaN"); 5703 } else if (val == 0 && xmlXPathGetSign(val) != 0) { 5704 ret = xmlStrdup((const xmlChar *) "0"); 5705 } else { 5706 /* could be improved */ 5707 char buf[100]; 5708 xmlXPathFormatNumber(val, buf, 99); 5709 buf[99] = 0; 5710 ret = xmlStrdup((const xmlChar *) buf); 5711 } 5712 } 5713 return(ret); 5714 } 5715 5716 /** 5717 * xmlXPathCastNodeToString: 5718 * @node: a node 5719 * 5720 * Converts a node to its string value. 5721 * 5722 * Returns a newly allocated string. 5723 */ 5724 xmlChar * 5725 xmlXPathCastNodeToString (xmlNodePtr node) { 5726 xmlChar *ret; 5727 if ((ret = xmlNodeGetContent(node)) == NULL) 5728 ret = xmlStrdup((const xmlChar *) ""); 5729 return(ret); 5730 } 5731 5732 /** 5733 * xmlXPathCastNodeSetToString: 5734 * @ns: a node-set 5735 * 5736 * Converts a node-set to its string value. 5737 * 5738 * Returns a newly allocated string. 5739 */ 5740 xmlChar * 5741 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) { 5742 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL)) 5743 return(xmlStrdup((const xmlChar *) "")); 5744 5745 if (ns->nodeNr > 1) 5746 xmlXPathNodeSetSort(ns); 5747 return(xmlXPathCastNodeToString(ns->nodeTab[0])); 5748 } 5749 5750 /** 5751 * xmlXPathCastToString: 5752 * @val: an XPath object 5753 * 5754 * Converts an existing object to its string() equivalent 5755 * 5756 * Returns the allocated string value of the object, NULL in case of error. 5757 * It's up to the caller to free the string memory with xmlFree(). 5758 */ 5759 xmlChar * 5760 xmlXPathCastToString(xmlXPathObjectPtr val) { 5761 xmlChar *ret = NULL; 5762 5763 if (val == NULL) 5764 return(xmlStrdup((const xmlChar *) "")); 5765 switch (val->type) { 5766 case XPATH_UNDEFINED: 5767 #ifdef DEBUG_EXPR 5768 xmlGenericError(xmlGenericErrorContext, "String: undefined\n"); 5769 #endif 5770 ret = xmlStrdup((const xmlChar *) ""); 5771 break; 5772 case XPATH_NODESET: 5773 case XPATH_XSLT_TREE: 5774 ret = xmlXPathCastNodeSetToString(val->nodesetval); 5775 break; 5776 case XPATH_STRING: 5777 return(xmlStrdup(val->stringval)); 5778 case XPATH_BOOLEAN: 5779 ret = xmlXPathCastBooleanToString(val->boolval); 5780 break; 5781 case XPATH_NUMBER: { 5782 ret = xmlXPathCastNumberToString(val->floatval); 5783 break; 5784 } 5785 case XPATH_USERS: 5786 case XPATH_POINT: 5787 case XPATH_RANGE: 5788 case XPATH_LOCATIONSET: 5789 TODO 5790 ret = xmlStrdup((const xmlChar *) ""); 5791 break; 5792 } 5793 return(ret); 5794 } 5795 5796 /** 5797 * xmlXPathConvertString: 5798 * @val: an XPath object 5799 * 5800 * Converts an existing object to its string() equivalent 5801 * 5802 * Returns the new object, the old one is freed (or the operation 5803 * is done directly on @val) 5804 */ 5805 xmlXPathObjectPtr 5806 xmlXPathConvertString(xmlXPathObjectPtr val) { 5807 xmlChar *res = NULL; 5808 5809 if (val == NULL) 5810 return(xmlXPathNewCString("")); 5811 5812 switch (val->type) { 5813 case XPATH_UNDEFINED: 5814 #ifdef DEBUG_EXPR 5815 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n"); 5816 #endif 5817 break; 5818 case XPATH_NODESET: 5819 case XPATH_XSLT_TREE: 5820 res = xmlXPathCastNodeSetToString(val->nodesetval); 5821 break; 5822 case XPATH_STRING: 5823 return(val); 5824 case XPATH_BOOLEAN: 5825 res = xmlXPathCastBooleanToString(val->boolval); 5826 break; 5827 case XPATH_NUMBER: 5828 res = xmlXPathCastNumberToString(val->floatval); 5829 break; 5830 case XPATH_USERS: 5831 case XPATH_POINT: 5832 case XPATH_RANGE: 5833 case XPATH_LOCATIONSET: 5834 TODO; 5835 break; 5836 } 5837 xmlXPathFreeObject(val); 5838 if (res == NULL) 5839 return(xmlXPathNewCString("")); 5840 return(xmlXPathWrapString(res)); 5841 } 5842 5843 /** 5844 * xmlXPathCastBooleanToNumber: 5845 * @val: a boolean 5846 * 5847 * Converts a boolean to its number value 5848 * 5849 * Returns the number value 5850 */ 5851 double 5852 xmlXPathCastBooleanToNumber(int val) { 5853 if (val) 5854 return(1.0); 5855 return(0.0); 5856 } 5857 5858 /** 5859 * xmlXPathCastStringToNumber: 5860 * @val: a string 5861 * 5862 * Converts a string to its number value 5863 * 5864 * Returns the number value 5865 */ 5866 double 5867 xmlXPathCastStringToNumber(const xmlChar * val) { 5868 return(xmlXPathStringEvalNumber(val)); 5869 } 5870 5871 /** 5872 * xmlXPathCastNodeToNumber: 5873 * @node: a node 5874 * 5875 * Converts a node to its number value 5876 * 5877 * Returns the number value 5878 */ 5879 double 5880 xmlXPathCastNodeToNumber (xmlNodePtr node) { 5881 xmlChar *strval; 5882 double ret; 5883 5884 if (node == NULL) 5885 return(xmlXPathNAN); 5886 strval = xmlXPathCastNodeToString(node); 5887 if (strval == NULL) 5888 return(xmlXPathNAN); 5889 ret = xmlXPathCastStringToNumber(strval); 5890 xmlFree(strval); 5891 5892 return(ret); 5893 } 5894 5895 /** 5896 * xmlXPathCastNodeSetToNumber: 5897 * @ns: a node-set 5898 * 5899 * Converts a node-set to its number value 5900 * 5901 * Returns the number value 5902 */ 5903 double 5904 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) { 5905 xmlChar *str; 5906 double ret; 5907 5908 if (ns == NULL) 5909 return(xmlXPathNAN); 5910 str = xmlXPathCastNodeSetToString(ns); 5911 ret = xmlXPathCastStringToNumber(str); 5912 xmlFree(str); 5913 return(ret); 5914 } 5915 5916 /** 5917 * xmlXPathCastToNumber: 5918 * @val: an XPath object 5919 * 5920 * Converts an XPath object to its number value 5921 * 5922 * Returns the number value 5923 */ 5924 double 5925 xmlXPathCastToNumber(xmlXPathObjectPtr val) { 5926 double ret = 0.0; 5927 5928 if (val == NULL) 5929 return(xmlXPathNAN); 5930 switch (val->type) { 5931 case XPATH_UNDEFINED: 5932 #ifdef DEGUB_EXPR 5933 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n"); 5934 #endif 5935 ret = xmlXPathNAN; 5936 break; 5937 case XPATH_NODESET: 5938 case XPATH_XSLT_TREE: 5939 ret = xmlXPathCastNodeSetToNumber(val->nodesetval); 5940 break; 5941 case XPATH_STRING: 5942 ret = xmlXPathCastStringToNumber(val->stringval); 5943 break; 5944 case XPATH_NUMBER: 5945 ret = val->floatval; 5946 break; 5947 case XPATH_BOOLEAN: 5948 ret = xmlXPathCastBooleanToNumber(val->boolval); 5949 break; 5950 case XPATH_USERS: 5951 case XPATH_POINT: 5952 case XPATH_RANGE: 5953 case XPATH_LOCATIONSET: 5954 TODO; 5955 ret = xmlXPathNAN; 5956 break; 5957 } 5958 return(ret); 5959 } 5960 5961 /** 5962 * xmlXPathConvertNumber: 5963 * @val: an XPath object 5964 * 5965 * Converts an existing object to its number() equivalent 5966 * 5967 * Returns the new object, the old one is freed (or the operation 5968 * is done directly on @val) 5969 */ 5970 xmlXPathObjectPtr 5971 xmlXPathConvertNumber(xmlXPathObjectPtr val) { 5972 xmlXPathObjectPtr ret; 5973 5974 if (val == NULL) 5975 return(xmlXPathNewFloat(0.0)); 5976 if (val->type == XPATH_NUMBER) 5977 return(val); 5978 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val)); 5979 xmlXPathFreeObject(val); 5980 return(ret); 5981 } 5982 5983 /** 5984 * xmlXPathCastNumberToBoolean: 5985 * @val: a number 5986 * 5987 * Converts a number to its boolean value 5988 * 5989 * Returns the boolean value 5990 */ 5991 int 5992 xmlXPathCastNumberToBoolean (double val) { 5993 if (xmlXPathIsNaN(val) || (val == 0.0)) 5994 return(0); 5995 return(1); 5996 } 5997 5998 /** 5999 * xmlXPathCastStringToBoolean: 6000 * @val: a string 6001 * 6002 * Converts a string to its boolean value 6003 * 6004 * Returns the boolean value 6005 */ 6006 int 6007 xmlXPathCastStringToBoolean (const xmlChar *val) { 6008 if ((val == NULL) || (xmlStrlen(val) == 0)) 6009 return(0); 6010 return(1); 6011 } 6012 6013 /** 6014 * xmlXPathCastNodeSetToBoolean: 6015 * @ns: a node-set 6016 * 6017 * Converts a node-set to its boolean value 6018 * 6019 * Returns the boolean value 6020 */ 6021 int 6022 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) { 6023 if ((ns == NULL) || (ns->nodeNr == 0)) 6024 return(0); 6025 return(1); 6026 } 6027 6028 /** 6029 * xmlXPathCastToBoolean: 6030 * @val: an XPath object 6031 * 6032 * Converts an XPath object to its boolean value 6033 * 6034 * Returns the boolean value 6035 */ 6036 int 6037 xmlXPathCastToBoolean (xmlXPathObjectPtr val) { 6038 int ret = 0; 6039 6040 if (val == NULL) 6041 return(0); 6042 switch (val->type) { 6043 case XPATH_UNDEFINED: 6044 #ifdef DEBUG_EXPR 6045 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n"); 6046 #endif 6047 ret = 0; 6048 break; 6049 case XPATH_NODESET: 6050 case XPATH_XSLT_TREE: 6051 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval); 6052 break; 6053 case XPATH_STRING: 6054 ret = xmlXPathCastStringToBoolean(val->stringval); 6055 break; 6056 case XPATH_NUMBER: 6057 ret = xmlXPathCastNumberToBoolean(val->floatval); 6058 break; 6059 case XPATH_BOOLEAN: 6060 ret = val->boolval; 6061 break; 6062 case XPATH_USERS: 6063 case XPATH_POINT: 6064 case XPATH_RANGE: 6065 case XPATH_LOCATIONSET: 6066 TODO; 6067 ret = 0; 6068 break; 6069 } 6070 return(ret); 6071 } 6072 6073 6074 /** 6075 * xmlXPathConvertBoolean: 6076 * @val: an XPath object 6077 * 6078 * Converts an existing object to its boolean() equivalent 6079 * 6080 * Returns the new object, the old one is freed (or the operation 6081 * is done directly on @val) 6082 */ 6083 xmlXPathObjectPtr 6084 xmlXPathConvertBoolean(xmlXPathObjectPtr val) { 6085 xmlXPathObjectPtr ret; 6086 6087 if (val == NULL) 6088 return(xmlXPathNewBoolean(0)); 6089 if (val->type == XPATH_BOOLEAN) 6090 return(val); 6091 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val)); 6092 xmlXPathFreeObject(val); 6093 return(ret); 6094 } 6095 6096 /************************************************************************ 6097 * * 6098 * Routines to handle XPath contexts * 6099 * * 6100 ************************************************************************/ 6101 6102 /** 6103 * xmlXPathNewContext: 6104 * @doc: the XML document 6105 * 6106 * Create a new xmlXPathContext 6107 * 6108 * Returns the xmlXPathContext just allocated. The caller will need to free it. 6109 */ 6110 xmlXPathContextPtr 6111 xmlXPathNewContext(xmlDocPtr doc) { 6112 xmlXPathContextPtr ret; 6113 6114 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext)); 6115 if (ret == NULL) { 6116 xmlXPathErrMemory(NULL, "creating context\n"); 6117 return(NULL); 6118 } 6119 memset(ret, 0 , (size_t) sizeof(xmlXPathContext)); 6120 ret->doc = doc; 6121 ret->node = NULL; 6122 6123 ret->varHash = NULL; 6124 6125 ret->nb_types = 0; 6126 ret->max_types = 0; 6127 ret->types = NULL; 6128 6129 ret->funcHash = xmlHashCreate(0); 6130 6131 ret->nb_axis = 0; 6132 ret->max_axis = 0; 6133 ret->axis = NULL; 6134 6135 ret->nsHash = NULL; 6136 ret->user = NULL; 6137 6138 ret->contextSize = -1; 6139 ret->proximityPosition = -1; 6140 6141 #ifdef XP_DEFAULT_CACHE_ON 6142 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) { 6143 xmlXPathFreeContext(ret); 6144 return(NULL); 6145 } 6146 #endif 6147 6148 xmlXPathRegisterAllFunctions(ret); 6149 6150 return(ret); 6151 } 6152 6153 /** 6154 * xmlXPathFreeContext: 6155 * @ctxt: the context to free 6156 * 6157 * Free up an xmlXPathContext 6158 */ 6159 void 6160 xmlXPathFreeContext(xmlXPathContextPtr ctxt) { 6161 if (ctxt == NULL) return; 6162 6163 if (ctxt->cache != NULL) 6164 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache); 6165 xmlXPathRegisteredNsCleanup(ctxt); 6166 xmlXPathRegisteredFuncsCleanup(ctxt); 6167 xmlXPathRegisteredVariablesCleanup(ctxt); 6168 xmlResetError(&ctxt->lastError); 6169 xmlFree(ctxt); 6170 } 6171 6172 /************************************************************************ 6173 * * 6174 * Routines to handle XPath parser contexts * 6175 * * 6176 ************************************************************************/ 6177 6178 #define CHECK_CTXT(ctxt) \ 6179 if (ctxt == NULL) { \ 6180 __xmlRaiseError(NULL, NULL, NULL, \ 6181 NULL, NULL, XML_FROM_XPATH, \ 6182 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \ 6183 __FILE__, __LINE__, \ 6184 NULL, NULL, NULL, 0, 0, \ 6185 "NULL context pointer\n"); \ 6186 return(NULL); \ 6187 } \ 6188 6189 #define CHECK_CTXT_NEG(ctxt) \ 6190 if (ctxt == NULL) { \ 6191 __xmlRaiseError(NULL, NULL, NULL, \ 6192 NULL, NULL, XML_FROM_XPATH, \ 6193 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \ 6194 __FILE__, __LINE__, \ 6195 NULL, NULL, NULL, 0, 0, \ 6196 "NULL context pointer\n"); \ 6197 return(-1); \ 6198 } \ 6199 6200 6201 #define CHECK_CONTEXT(ctxt) \ 6202 if ((ctxt == NULL) || (ctxt->doc == NULL) || \ 6203 (ctxt->doc->children == NULL)) { \ 6204 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \ 6205 return(NULL); \ 6206 } 6207 6208 6209 /** 6210 * xmlXPathNewParserContext: 6211 * @str: the XPath expression 6212 * @ctxt: the XPath context 6213 * 6214 * Create a new xmlXPathParserContext 6215 * 6216 * Returns the xmlXPathParserContext just allocated. 6217 */ 6218 xmlXPathParserContextPtr 6219 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) { 6220 xmlXPathParserContextPtr ret; 6221 6222 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext)); 6223 if (ret == NULL) { 6224 xmlXPathErrMemory(ctxt, "creating parser context\n"); 6225 return(NULL); 6226 } 6227 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext)); 6228 ret->cur = ret->base = str; 6229 ret->context = ctxt; 6230 6231 ret->comp = xmlXPathNewCompExpr(); 6232 if (ret->comp == NULL) { 6233 xmlFree(ret->valueTab); 6234 xmlFree(ret); 6235 return(NULL); 6236 } 6237 if ((ctxt != NULL) && (ctxt->dict != NULL)) { 6238 ret->comp->dict = ctxt->dict; 6239 xmlDictReference(ret->comp->dict); 6240 } 6241 6242 return(ret); 6243 } 6244 6245 /** 6246 * xmlXPathCompParserContext: 6247 * @comp: the XPath compiled expression 6248 * @ctxt: the XPath context 6249 * 6250 * Create a new xmlXPathParserContext when processing a compiled expression 6251 * 6252 * Returns the xmlXPathParserContext just allocated. 6253 */ 6254 static xmlXPathParserContextPtr 6255 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) { 6256 xmlXPathParserContextPtr ret; 6257 6258 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext)); 6259 if (ret == NULL) { 6260 xmlXPathErrMemory(ctxt, "creating evaluation context\n"); 6261 return(NULL); 6262 } 6263 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext)); 6264 6265 /* Allocate the value stack */ 6266 ret->valueTab = (xmlXPathObjectPtr *) 6267 xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); 6268 if (ret->valueTab == NULL) { 6269 xmlFree(ret); 6270 xmlXPathErrMemory(ctxt, "creating evaluation context\n"); 6271 return(NULL); 6272 } 6273 ret->valueNr = 0; 6274 ret->valueMax = 10; 6275 ret->value = NULL; 6276 ret->valueFrame = 0; 6277 6278 ret->context = ctxt; 6279 ret->comp = comp; 6280 6281 return(ret); 6282 } 6283 6284 /** 6285 * xmlXPathFreeParserContext: 6286 * @ctxt: the context to free 6287 * 6288 * Free up an xmlXPathParserContext 6289 */ 6290 void 6291 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) { 6292 if (ctxt->valueTab != NULL) { 6293 xmlFree(ctxt->valueTab); 6294 } 6295 if (ctxt->comp != NULL) { 6296 #ifdef XPATH_STREAMING 6297 if (ctxt->comp->stream != NULL) { 6298 xmlFreePatternList(ctxt->comp->stream); 6299 ctxt->comp->stream = NULL; 6300 } 6301 #endif 6302 xmlXPathFreeCompExpr(ctxt->comp); 6303 } 6304 xmlFree(ctxt); 6305 } 6306 6307 /************************************************************************ 6308 * * 6309 * The implicit core function library * 6310 * * 6311 ************************************************************************/ 6312 6313 /** 6314 * xmlXPathNodeValHash: 6315 * @node: a node pointer 6316 * 6317 * Function computing the beginning of the string value of the node, 6318 * used to speed up comparisons 6319 * 6320 * Returns an int usable as a hash 6321 */ 6322 static unsigned int 6323 xmlXPathNodeValHash(xmlNodePtr node) { 6324 int len = 2; 6325 const xmlChar * string = NULL; 6326 xmlNodePtr tmp = NULL; 6327 unsigned int ret = 0; 6328 6329 if (node == NULL) 6330 return(0); 6331 6332 if (node->type == XML_DOCUMENT_NODE) { 6333 tmp = xmlDocGetRootElement((xmlDocPtr) node); 6334 if (tmp == NULL) 6335 node = node->children; 6336 else 6337 node = tmp; 6338 6339 if (node == NULL) 6340 return(0); 6341 } 6342 6343 switch (node->type) { 6344 case XML_COMMENT_NODE: 6345 case XML_PI_NODE: 6346 case XML_CDATA_SECTION_NODE: 6347 case XML_TEXT_NODE: 6348 string = node->content; 6349 if (string == NULL) 6350 return(0); 6351 if (string[0] == 0) 6352 return(0); 6353 return(((unsigned int) string[0]) + 6354 (((unsigned int) string[1]) << 8)); 6355 case XML_NAMESPACE_DECL: 6356 string = ((xmlNsPtr)node)->href; 6357 if (string == NULL) 6358 return(0); 6359 if (string[0] == 0) 6360 return(0); 6361 return(((unsigned int) string[0]) + 6362 (((unsigned int) string[1]) << 8)); 6363 case XML_ATTRIBUTE_NODE: 6364 tmp = ((xmlAttrPtr) node)->children; 6365 break; 6366 case XML_ELEMENT_NODE: 6367 tmp = node->children; 6368 break; 6369 default: 6370 return(0); 6371 } 6372 while (tmp != NULL) { 6373 switch (tmp->type) { 6374 case XML_COMMENT_NODE: 6375 case XML_PI_NODE: 6376 case XML_CDATA_SECTION_NODE: 6377 case XML_TEXT_NODE: 6378 string = tmp->content; 6379 break; 6380 case XML_NAMESPACE_DECL: 6381 string = ((xmlNsPtr)tmp)->href; 6382 break; 6383 default: 6384 break; 6385 } 6386 if ((string != NULL) && (string[0] != 0)) { 6387 if (len == 1) { 6388 return(ret + (((unsigned int) string[0]) << 8)); 6389 } 6390 if (string[1] == 0) { 6391 len = 1; 6392 ret = (unsigned int) string[0]; 6393 } else { 6394 return(((unsigned int) string[0]) + 6395 (((unsigned int) string[1]) << 8)); 6396 } 6397 } 6398 /* 6399 * Skip to next node 6400 */ 6401 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) { 6402 if (tmp->children->type != XML_ENTITY_DECL) { 6403 tmp = tmp->children; 6404 continue; 6405 } 6406 } 6407 if (tmp == node) 6408 break; 6409 6410 if (tmp->next != NULL) { 6411 tmp = tmp->next; 6412 continue; 6413 } 6414 6415 do { 6416 tmp = tmp->parent; 6417 if (tmp == NULL) 6418 break; 6419 if (tmp == node) { 6420 tmp = NULL; 6421 break; 6422 } 6423 if (tmp->next != NULL) { 6424 tmp = tmp->next; 6425 break; 6426 } 6427 } while (tmp != NULL); 6428 } 6429 return(ret); 6430 } 6431 6432 /** 6433 * xmlXPathStringHash: 6434 * @string: a string 6435 * 6436 * Function computing the beginning of the string value of the node, 6437 * used to speed up comparisons 6438 * 6439 * Returns an int usable as a hash 6440 */ 6441 static unsigned int 6442 xmlXPathStringHash(const xmlChar * string) { 6443 if (string == NULL) 6444 return((unsigned int) 0); 6445 if (string[0] == 0) 6446 return(0); 6447 return(((unsigned int) string[0]) + 6448 (((unsigned int) string[1]) << 8)); 6449 } 6450 6451 /** 6452 * xmlXPathCompareNodeSetFloat: 6453 * @ctxt: the XPath Parser context 6454 * @inf: less than (1) or greater than (0) 6455 * @strict: is the comparison strict 6456 * @arg: the node set 6457 * @f: the value 6458 * 6459 * Implement the compare operation between a nodeset and a number 6460 * @ns < @val (1, 1, ... 6461 * @ns <= @val (1, 0, ... 6462 * @ns > @val (0, 1, ... 6463 * @ns >= @val (0, 0, ... 6464 * 6465 * If one object to be compared is a node-set and the other is a number, 6466 * then the comparison will be true if and only if there is a node in the 6467 * node-set such that the result of performing the comparison on the number 6468 * to be compared and on the result of converting the string-value of that 6469 * node to a number using the number function is true. 6470 * 6471 * Returns 0 or 1 depending on the results of the test. 6472 */ 6473 static int 6474 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict, 6475 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) { 6476 int i, ret = 0; 6477 xmlNodeSetPtr ns; 6478 xmlChar *str2; 6479 6480 if ((f == NULL) || (arg == NULL) || 6481 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) { 6482 xmlXPathReleaseObject(ctxt->context, arg); 6483 xmlXPathReleaseObject(ctxt->context, f); 6484 return(0); 6485 } 6486 ns = arg->nodesetval; 6487 if (ns != NULL) { 6488 for (i = 0;i < ns->nodeNr;i++) { 6489 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 6490 if (str2 != NULL) { 6491 valuePush(ctxt, 6492 xmlXPathCacheNewString(ctxt->context, str2)); 6493 xmlFree(str2); 6494 xmlXPathNumberFunction(ctxt, 1); 6495 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f)); 6496 ret = xmlXPathCompareValues(ctxt, inf, strict); 6497 if (ret) 6498 break; 6499 } 6500 } 6501 } 6502 xmlXPathReleaseObject(ctxt->context, arg); 6503 xmlXPathReleaseObject(ctxt->context, f); 6504 return(ret); 6505 } 6506 6507 /** 6508 * xmlXPathCompareNodeSetString: 6509 * @ctxt: the XPath Parser context 6510 * @inf: less than (1) or greater than (0) 6511 * @strict: is the comparison strict 6512 * @arg: the node set 6513 * @s: the value 6514 * 6515 * Implement the compare operation between a nodeset and a string 6516 * @ns < @val (1, 1, ... 6517 * @ns <= @val (1, 0, ... 6518 * @ns > @val (0, 1, ... 6519 * @ns >= @val (0, 0, ... 6520 * 6521 * If one object to be compared is a node-set and the other is a string, 6522 * then the comparison will be true if and only if there is a node in 6523 * the node-set such that the result of performing the comparison on the 6524 * string-value of the node and the other string is true. 6525 * 6526 * Returns 0 or 1 depending on the results of the test. 6527 */ 6528 static int 6529 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict, 6530 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) { 6531 int i, ret = 0; 6532 xmlNodeSetPtr ns; 6533 xmlChar *str2; 6534 6535 if ((s == NULL) || (arg == NULL) || 6536 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) { 6537 xmlXPathReleaseObject(ctxt->context, arg); 6538 xmlXPathReleaseObject(ctxt->context, s); 6539 return(0); 6540 } 6541 ns = arg->nodesetval; 6542 if (ns != NULL) { 6543 for (i = 0;i < ns->nodeNr;i++) { 6544 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 6545 if (str2 != NULL) { 6546 valuePush(ctxt, 6547 xmlXPathCacheNewString(ctxt->context, str2)); 6548 xmlFree(str2); 6549 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s)); 6550 ret = xmlXPathCompareValues(ctxt, inf, strict); 6551 if (ret) 6552 break; 6553 } 6554 } 6555 } 6556 xmlXPathReleaseObject(ctxt->context, arg); 6557 xmlXPathReleaseObject(ctxt->context, s); 6558 return(ret); 6559 } 6560 6561 /** 6562 * xmlXPathCompareNodeSets: 6563 * @inf: less than (1) or greater than (0) 6564 * @strict: is the comparison strict 6565 * @arg1: the first node set object 6566 * @arg2: the second node set object 6567 * 6568 * Implement the compare operation on nodesets: 6569 * 6570 * If both objects to be compared are node-sets, then the comparison 6571 * will be true if and only if there is a node in the first node-set 6572 * and a node in the second node-set such that the result of performing 6573 * the comparison on the string-values of the two nodes is true. 6574 * .... 6575 * When neither object to be compared is a node-set and the operator 6576 * is <=, <, >= or >, then the objects are compared by converting both 6577 * objects to numbers and comparing the numbers according to IEEE 754. 6578 * .... 6579 * The number function converts its argument to a number as follows: 6580 * - a string that consists of optional whitespace followed by an 6581 * optional minus sign followed by a Number followed by whitespace 6582 * is converted to the IEEE 754 number that is nearest (according 6583 * to the IEEE 754 round-to-nearest rule) to the mathematical value 6584 * represented by the string; any other string is converted to NaN 6585 * 6586 * Conclusion all nodes need to be converted first to their string value 6587 * and then the comparison must be done when possible 6588 */ 6589 static int 6590 xmlXPathCompareNodeSets(int inf, int strict, 6591 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) { 6592 int i, j, init = 0; 6593 double val1; 6594 double *values2; 6595 int ret = 0; 6596 xmlNodeSetPtr ns1; 6597 xmlNodeSetPtr ns2; 6598 6599 if ((arg1 == NULL) || 6600 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) { 6601 xmlXPathFreeObject(arg2); 6602 return(0); 6603 } 6604 if ((arg2 == NULL) || 6605 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) { 6606 xmlXPathFreeObject(arg1); 6607 xmlXPathFreeObject(arg2); 6608 return(0); 6609 } 6610 6611 ns1 = arg1->nodesetval; 6612 ns2 = arg2->nodesetval; 6613 6614 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) { 6615 xmlXPathFreeObject(arg1); 6616 xmlXPathFreeObject(arg2); 6617 return(0); 6618 } 6619 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) { 6620 xmlXPathFreeObject(arg1); 6621 xmlXPathFreeObject(arg2); 6622 return(0); 6623 } 6624 6625 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double)); 6626 if (values2 == NULL) { 6627 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6628 xmlXPathFreeObject(arg1); 6629 xmlXPathFreeObject(arg2); 6630 return(0); 6631 } 6632 for (i = 0;i < ns1->nodeNr;i++) { 6633 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]); 6634 if (xmlXPathIsNaN(val1)) 6635 continue; 6636 for (j = 0;j < ns2->nodeNr;j++) { 6637 if (init == 0) { 6638 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]); 6639 } 6640 if (xmlXPathIsNaN(values2[j])) 6641 continue; 6642 if (inf && strict) 6643 ret = (val1 < values2[j]); 6644 else if (inf && !strict) 6645 ret = (val1 <= values2[j]); 6646 else if (!inf && strict) 6647 ret = (val1 > values2[j]); 6648 else if (!inf && !strict) 6649 ret = (val1 >= values2[j]); 6650 if (ret) 6651 break; 6652 } 6653 if (ret) 6654 break; 6655 init = 1; 6656 } 6657 xmlFree(values2); 6658 xmlXPathFreeObject(arg1); 6659 xmlXPathFreeObject(arg2); 6660 return(ret); 6661 } 6662 6663 /** 6664 * xmlXPathCompareNodeSetValue: 6665 * @ctxt: the XPath Parser context 6666 * @inf: less than (1) or greater than (0) 6667 * @strict: is the comparison strict 6668 * @arg: the node set 6669 * @val: the value 6670 * 6671 * Implement the compare operation between a nodeset and a value 6672 * @ns < @val (1, 1, ... 6673 * @ns <= @val (1, 0, ... 6674 * @ns > @val (0, 1, ... 6675 * @ns >= @val (0, 0, ... 6676 * 6677 * If one object to be compared is a node-set and the other is a boolean, 6678 * then the comparison will be true if and only if the result of performing 6679 * the comparison on the boolean and on the result of converting 6680 * the node-set to a boolean using the boolean function is true. 6681 * 6682 * Returns 0 or 1 depending on the results of the test. 6683 */ 6684 static int 6685 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict, 6686 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) { 6687 if ((val == NULL) || (arg == NULL) || 6688 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 6689 return(0); 6690 6691 switch(val->type) { 6692 case XPATH_NUMBER: 6693 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val)); 6694 case XPATH_NODESET: 6695 case XPATH_XSLT_TREE: 6696 return(xmlXPathCompareNodeSets(inf, strict, arg, val)); 6697 case XPATH_STRING: 6698 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val)); 6699 case XPATH_BOOLEAN: 6700 valuePush(ctxt, arg); 6701 xmlXPathBooleanFunction(ctxt, 1); 6702 valuePush(ctxt, val); 6703 return(xmlXPathCompareValues(ctxt, inf, strict)); 6704 default: 6705 TODO 6706 } 6707 return(0); 6708 } 6709 6710 /** 6711 * xmlXPathEqualNodeSetString: 6712 * @arg: the nodeset object argument 6713 * @str: the string to compare to. 6714 * @neq: flag to show whether for '=' (0) or '!=' (1) 6715 * 6716 * Implement the equal operation on XPath objects content: @arg1 == @arg2 6717 * If one object to be compared is a node-set and the other is a string, 6718 * then the comparison will be true if and only if there is a node in 6719 * the node-set such that the result of performing the comparison on the 6720 * string-value of the node and the other string is true. 6721 * 6722 * Returns 0 or 1 depending on the results of the test. 6723 */ 6724 static int 6725 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq) 6726 { 6727 int i; 6728 xmlNodeSetPtr ns; 6729 xmlChar *str2; 6730 unsigned int hash; 6731 6732 if ((str == NULL) || (arg == NULL) || 6733 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 6734 return (0); 6735 ns = arg->nodesetval; 6736 /* 6737 * A NULL nodeset compared with a string is always false 6738 * (since there is no node equal, and no node not equal) 6739 */ 6740 if ((ns == NULL) || (ns->nodeNr <= 0) ) 6741 return (0); 6742 hash = xmlXPathStringHash(str); 6743 for (i = 0; i < ns->nodeNr; i++) { 6744 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) { 6745 str2 = xmlNodeGetContent(ns->nodeTab[i]); 6746 if ((str2 != NULL) && (xmlStrEqual(str, str2))) { 6747 xmlFree(str2); 6748 if (neq) 6749 continue; 6750 return (1); 6751 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) { 6752 if (neq) 6753 continue; 6754 return (1); 6755 } else if (neq) { 6756 if (str2 != NULL) 6757 xmlFree(str2); 6758 return (1); 6759 } 6760 if (str2 != NULL) 6761 xmlFree(str2); 6762 } else if (neq) 6763 return (1); 6764 } 6765 return (0); 6766 } 6767 6768 /** 6769 * xmlXPathEqualNodeSetFloat: 6770 * @arg: the nodeset object argument 6771 * @f: the float to compare to 6772 * @neq: flag to show whether to compare '=' (0) or '!=' (1) 6773 * 6774 * Implement the equal operation on XPath objects content: @arg1 == @arg2 6775 * If one object to be compared is a node-set and the other is a number, 6776 * then the comparison will be true if and only if there is a node in 6777 * the node-set such that the result of performing the comparison on the 6778 * number to be compared and on the result of converting the string-value 6779 * of that node to a number using the number function is true. 6780 * 6781 * Returns 0 or 1 depending on the results of the test. 6782 */ 6783 static int 6784 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt, 6785 xmlXPathObjectPtr arg, double f, int neq) { 6786 int i, ret=0; 6787 xmlNodeSetPtr ns; 6788 xmlChar *str2; 6789 xmlXPathObjectPtr val; 6790 double v; 6791 6792 if ((arg == NULL) || 6793 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 6794 return(0); 6795 6796 ns = arg->nodesetval; 6797 if (ns != NULL) { 6798 for (i=0;i<ns->nodeNr;i++) { 6799 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 6800 if (str2 != NULL) { 6801 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2)); 6802 xmlFree(str2); 6803 xmlXPathNumberFunction(ctxt, 1); 6804 val = valuePop(ctxt); 6805 v = val->floatval; 6806 xmlXPathReleaseObject(ctxt->context, val); 6807 if (!xmlXPathIsNaN(v)) { 6808 if ((!neq) && (v==f)) { 6809 ret = 1; 6810 break; 6811 } else if ((neq) && (v!=f)) { 6812 ret = 1; 6813 break; 6814 } 6815 } else { /* NaN is unequal to any value */ 6816 if (neq) 6817 ret = 1; 6818 } 6819 } 6820 } 6821 } 6822 6823 return(ret); 6824 } 6825 6826 6827 /** 6828 * xmlXPathEqualNodeSets: 6829 * @arg1: first nodeset object argument 6830 * @arg2: second nodeset object argument 6831 * @neq: flag to show whether to test '=' (0) or '!=' (1) 6832 * 6833 * Implement the equal / not equal operation on XPath nodesets: 6834 * @arg1 == @arg2 or @arg1 != @arg2 6835 * If both objects to be compared are node-sets, then the comparison 6836 * will be true if and only if there is a node in the first node-set and 6837 * a node in the second node-set such that the result of performing the 6838 * comparison on the string-values of the two nodes is true. 6839 * 6840 * (needless to say, this is a costly operation) 6841 * 6842 * Returns 0 or 1 depending on the results of the test. 6843 */ 6844 static int 6845 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) { 6846 int i, j; 6847 unsigned int *hashs1; 6848 unsigned int *hashs2; 6849 xmlChar **values1; 6850 xmlChar **values2; 6851 int ret = 0; 6852 xmlNodeSetPtr ns1; 6853 xmlNodeSetPtr ns2; 6854 6855 if ((arg1 == NULL) || 6856 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) 6857 return(0); 6858 if ((arg2 == NULL) || 6859 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) 6860 return(0); 6861 6862 ns1 = arg1->nodesetval; 6863 ns2 = arg2->nodesetval; 6864 6865 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) 6866 return(0); 6867 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) 6868 return(0); 6869 6870 /* 6871 * for equal, check if there is a node pertaining to both sets 6872 */ 6873 if (neq == 0) 6874 for (i = 0;i < ns1->nodeNr;i++) 6875 for (j = 0;j < ns2->nodeNr;j++) 6876 if (ns1->nodeTab[i] == ns2->nodeTab[j]) 6877 return(1); 6878 6879 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *)); 6880 if (values1 == NULL) { 6881 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6882 return(0); 6883 } 6884 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int)); 6885 if (hashs1 == NULL) { 6886 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6887 xmlFree(values1); 6888 return(0); 6889 } 6890 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *)); 6891 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *)); 6892 if (values2 == NULL) { 6893 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6894 xmlFree(hashs1); 6895 xmlFree(values1); 6896 return(0); 6897 } 6898 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int)); 6899 if (hashs2 == NULL) { 6900 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6901 xmlFree(hashs1); 6902 xmlFree(values1); 6903 xmlFree(values2); 6904 return(0); 6905 } 6906 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *)); 6907 for (i = 0;i < ns1->nodeNr;i++) { 6908 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]); 6909 for (j = 0;j < ns2->nodeNr;j++) { 6910 if (i == 0) 6911 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]); 6912 if (hashs1[i] != hashs2[j]) { 6913 if (neq) { 6914 ret = 1; 6915 break; 6916 } 6917 } 6918 else { 6919 if (values1[i] == NULL) 6920 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]); 6921 if (values2[j] == NULL) 6922 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]); 6923 ret = xmlStrEqual(values1[i], values2[j]) ^ neq; 6924 if (ret) 6925 break; 6926 } 6927 } 6928 if (ret) 6929 break; 6930 } 6931 for (i = 0;i < ns1->nodeNr;i++) 6932 if (values1[i] != NULL) 6933 xmlFree(values1[i]); 6934 for (j = 0;j < ns2->nodeNr;j++) 6935 if (values2[j] != NULL) 6936 xmlFree(values2[j]); 6937 xmlFree(values1); 6938 xmlFree(values2); 6939 xmlFree(hashs1); 6940 xmlFree(hashs2); 6941 return(ret); 6942 } 6943 6944 static int 6945 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt, 6946 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) { 6947 int ret = 0; 6948 /* 6949 *At this point we are assured neither arg1 nor arg2 6950 *is a nodeset, so we can just pick the appropriate routine. 6951 */ 6952 switch (arg1->type) { 6953 case XPATH_UNDEFINED: 6954 #ifdef DEBUG_EXPR 6955 xmlGenericError(xmlGenericErrorContext, 6956 "Equal: undefined\n"); 6957 #endif 6958 break; 6959 case XPATH_BOOLEAN: 6960 switch (arg2->type) { 6961 case XPATH_UNDEFINED: 6962 #ifdef DEBUG_EXPR 6963 xmlGenericError(xmlGenericErrorContext, 6964 "Equal: undefined\n"); 6965 #endif 6966 break; 6967 case XPATH_BOOLEAN: 6968 #ifdef DEBUG_EXPR 6969 xmlGenericError(xmlGenericErrorContext, 6970 "Equal: %d boolean %d \n", 6971 arg1->boolval, arg2->boolval); 6972 #endif 6973 ret = (arg1->boolval == arg2->boolval); 6974 break; 6975 case XPATH_NUMBER: 6976 ret = (arg1->boolval == 6977 xmlXPathCastNumberToBoolean(arg2->floatval)); 6978 break; 6979 case XPATH_STRING: 6980 if ((arg2->stringval == NULL) || 6981 (arg2->stringval[0] == 0)) ret = 0; 6982 else 6983 ret = 1; 6984 ret = (arg1->boolval == ret); 6985 break; 6986 case XPATH_USERS: 6987 case XPATH_POINT: 6988 case XPATH_RANGE: 6989 case XPATH_LOCATIONSET: 6990 TODO 6991 break; 6992 case XPATH_NODESET: 6993 case XPATH_XSLT_TREE: 6994 break; 6995 } 6996 break; 6997 case XPATH_NUMBER: 6998 switch (arg2->type) { 6999 case XPATH_UNDEFINED: 7000 #ifdef DEBUG_EXPR 7001 xmlGenericError(xmlGenericErrorContext, 7002 "Equal: undefined\n"); 7003 #endif 7004 break; 7005 case XPATH_BOOLEAN: 7006 ret = (arg2->boolval== 7007 xmlXPathCastNumberToBoolean(arg1->floatval)); 7008 break; 7009 case XPATH_STRING: 7010 valuePush(ctxt, arg2); 7011 xmlXPathNumberFunction(ctxt, 1); 7012 arg2 = valuePop(ctxt); 7013 /* no break on purpose */ 7014 case XPATH_NUMBER: 7015 /* Hand check NaN and Infinity equalities */ 7016 if (xmlXPathIsNaN(arg1->floatval) || 7017 xmlXPathIsNaN(arg2->floatval)) { 7018 ret = 0; 7019 } else if (xmlXPathIsInf(arg1->floatval) == 1) { 7020 if (xmlXPathIsInf(arg2->floatval) == 1) 7021 ret = 1; 7022 else 7023 ret = 0; 7024 } else if (xmlXPathIsInf(arg1->floatval) == -1) { 7025 if (xmlXPathIsInf(arg2->floatval) == -1) 7026 ret = 1; 7027 else 7028 ret = 0; 7029 } else if (xmlXPathIsInf(arg2->floatval) == 1) { 7030 if (xmlXPathIsInf(arg1->floatval) == 1) 7031 ret = 1; 7032 else 7033 ret = 0; 7034 } else if (xmlXPathIsInf(arg2->floatval) == -1) { 7035 if (xmlXPathIsInf(arg1->floatval) == -1) 7036 ret = 1; 7037 else 7038 ret = 0; 7039 } else { 7040 ret = (arg1->floatval == arg2->floatval); 7041 } 7042 break; 7043 case XPATH_USERS: 7044 case XPATH_POINT: 7045 case XPATH_RANGE: 7046 case XPATH_LOCATIONSET: 7047 TODO 7048 break; 7049 case XPATH_NODESET: 7050 case XPATH_XSLT_TREE: 7051 break; 7052 } 7053 break; 7054 case XPATH_STRING: 7055 switch (arg2->type) { 7056 case XPATH_UNDEFINED: 7057 #ifdef DEBUG_EXPR 7058 xmlGenericError(xmlGenericErrorContext, 7059 "Equal: undefined\n"); 7060 #endif 7061 break; 7062 case XPATH_BOOLEAN: 7063 if ((arg1->stringval == NULL) || 7064 (arg1->stringval[0] == 0)) ret = 0; 7065 else 7066 ret = 1; 7067 ret = (arg2->boolval == ret); 7068 break; 7069 case XPATH_STRING: 7070 ret = xmlStrEqual(arg1->stringval, arg2->stringval); 7071 break; 7072 case XPATH_NUMBER: 7073 valuePush(ctxt, arg1); 7074 xmlXPathNumberFunction(ctxt, 1); 7075 arg1 = valuePop(ctxt); 7076 /* Hand check NaN and Infinity equalities */ 7077 if (xmlXPathIsNaN(arg1->floatval) || 7078 xmlXPathIsNaN(arg2->floatval)) { 7079 ret = 0; 7080 } else if (xmlXPathIsInf(arg1->floatval) == 1) { 7081 if (xmlXPathIsInf(arg2->floatval) == 1) 7082 ret = 1; 7083 else 7084 ret = 0; 7085 } else if (xmlXPathIsInf(arg1->floatval) == -1) { 7086 if (xmlXPathIsInf(arg2->floatval) == -1) 7087 ret = 1; 7088 else 7089 ret = 0; 7090 } else if (xmlXPathIsInf(arg2->floatval) == 1) { 7091 if (xmlXPathIsInf(arg1->floatval) == 1) 7092 ret = 1; 7093 else 7094 ret = 0; 7095 } else if (xmlXPathIsInf(arg2->floatval) == -1) { 7096 if (xmlXPathIsInf(arg1->floatval) == -1) 7097 ret = 1; 7098 else 7099 ret = 0; 7100 } else { 7101 ret = (arg1->floatval == arg2->floatval); 7102 } 7103 break; 7104 case XPATH_USERS: 7105 case XPATH_POINT: 7106 case XPATH_RANGE: 7107 case XPATH_LOCATIONSET: 7108 TODO 7109 break; 7110 case XPATH_NODESET: 7111 case XPATH_XSLT_TREE: 7112 break; 7113 } 7114 break; 7115 case XPATH_USERS: 7116 case XPATH_POINT: 7117 case XPATH_RANGE: 7118 case XPATH_LOCATIONSET: 7119 TODO 7120 break; 7121 case XPATH_NODESET: 7122 case XPATH_XSLT_TREE: 7123 break; 7124 } 7125 xmlXPathReleaseObject(ctxt->context, arg1); 7126 xmlXPathReleaseObject(ctxt->context, arg2); 7127 return(ret); 7128 } 7129 7130 /** 7131 * xmlXPathEqualValues: 7132 * @ctxt: the XPath Parser context 7133 * 7134 * Implement the equal operation on XPath objects content: @arg1 == @arg2 7135 * 7136 * Returns 0 or 1 depending on the results of the test. 7137 */ 7138 int 7139 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) { 7140 xmlXPathObjectPtr arg1, arg2, argtmp; 7141 int ret = 0; 7142 7143 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); 7144 arg2 = valuePop(ctxt); 7145 arg1 = valuePop(ctxt); 7146 if ((arg1 == NULL) || (arg2 == NULL)) { 7147 if (arg1 != NULL) 7148 xmlXPathReleaseObject(ctxt->context, arg1); 7149 else 7150 xmlXPathReleaseObject(ctxt->context, arg2); 7151 XP_ERROR0(XPATH_INVALID_OPERAND); 7152 } 7153 7154 if (arg1 == arg2) { 7155 #ifdef DEBUG_EXPR 7156 xmlGenericError(xmlGenericErrorContext, 7157 "Equal: by pointer\n"); 7158 #endif 7159 xmlXPathFreeObject(arg1); 7160 return(1); 7161 } 7162 7163 /* 7164 *If either argument is a nodeset, it's a 'special case' 7165 */ 7166 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 7167 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7168 /* 7169 *Hack it to assure arg1 is the nodeset 7170 */ 7171 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) { 7172 argtmp = arg2; 7173 arg2 = arg1; 7174 arg1 = argtmp; 7175 } 7176 switch (arg2->type) { 7177 case XPATH_UNDEFINED: 7178 #ifdef DEBUG_EXPR 7179 xmlGenericError(xmlGenericErrorContext, 7180 "Equal: undefined\n"); 7181 #endif 7182 break; 7183 case XPATH_NODESET: 7184 case XPATH_XSLT_TREE: 7185 ret = xmlXPathEqualNodeSets(arg1, arg2, 0); 7186 break; 7187 case XPATH_BOOLEAN: 7188 if ((arg1->nodesetval == NULL) || 7189 (arg1->nodesetval->nodeNr == 0)) ret = 0; 7190 else 7191 ret = 1; 7192 ret = (ret == arg2->boolval); 7193 break; 7194 case XPATH_NUMBER: 7195 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0); 7196 break; 7197 case XPATH_STRING: 7198 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0); 7199 break; 7200 case XPATH_USERS: 7201 case XPATH_POINT: 7202 case XPATH_RANGE: 7203 case XPATH_LOCATIONSET: 7204 TODO 7205 break; 7206 } 7207 xmlXPathReleaseObject(ctxt->context, arg1); 7208 xmlXPathReleaseObject(ctxt->context, arg2); 7209 return(ret); 7210 } 7211 7212 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2)); 7213 } 7214 7215 /** 7216 * xmlXPathNotEqualValues: 7217 * @ctxt: the XPath Parser context 7218 * 7219 * Implement the equal operation on XPath objects content: @arg1 == @arg2 7220 * 7221 * Returns 0 or 1 depending on the results of the test. 7222 */ 7223 int 7224 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) { 7225 xmlXPathObjectPtr arg1, arg2, argtmp; 7226 int ret = 0; 7227 7228 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); 7229 arg2 = valuePop(ctxt); 7230 arg1 = valuePop(ctxt); 7231 if ((arg1 == NULL) || (arg2 == NULL)) { 7232 if (arg1 != NULL) 7233 xmlXPathReleaseObject(ctxt->context, arg1); 7234 else 7235 xmlXPathReleaseObject(ctxt->context, arg2); 7236 XP_ERROR0(XPATH_INVALID_OPERAND); 7237 } 7238 7239 if (arg1 == arg2) { 7240 #ifdef DEBUG_EXPR 7241 xmlGenericError(xmlGenericErrorContext, 7242 "NotEqual: by pointer\n"); 7243 #endif 7244 xmlXPathReleaseObject(ctxt->context, arg1); 7245 return(0); 7246 } 7247 7248 /* 7249 *If either argument is a nodeset, it's a 'special case' 7250 */ 7251 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 7252 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7253 /* 7254 *Hack it to assure arg1 is the nodeset 7255 */ 7256 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) { 7257 argtmp = arg2; 7258 arg2 = arg1; 7259 arg1 = argtmp; 7260 } 7261 switch (arg2->type) { 7262 case XPATH_UNDEFINED: 7263 #ifdef DEBUG_EXPR 7264 xmlGenericError(xmlGenericErrorContext, 7265 "NotEqual: undefined\n"); 7266 #endif 7267 break; 7268 case XPATH_NODESET: 7269 case XPATH_XSLT_TREE: 7270 ret = xmlXPathEqualNodeSets(arg1, arg2, 1); 7271 break; 7272 case XPATH_BOOLEAN: 7273 if ((arg1->nodesetval == NULL) || 7274 (arg1->nodesetval->nodeNr == 0)) ret = 0; 7275 else 7276 ret = 1; 7277 ret = (ret != arg2->boolval); 7278 break; 7279 case XPATH_NUMBER: 7280 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1); 7281 break; 7282 case XPATH_STRING: 7283 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1); 7284 break; 7285 case XPATH_USERS: 7286 case XPATH_POINT: 7287 case XPATH_RANGE: 7288 case XPATH_LOCATIONSET: 7289 TODO 7290 break; 7291 } 7292 xmlXPathReleaseObject(ctxt->context, arg1); 7293 xmlXPathReleaseObject(ctxt->context, arg2); 7294 return(ret); 7295 } 7296 7297 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2)); 7298 } 7299 7300 /** 7301 * xmlXPathCompareValues: 7302 * @ctxt: the XPath Parser context 7303 * @inf: less than (1) or greater than (0) 7304 * @strict: is the comparison strict 7305 * 7306 * Implement the compare operation on XPath objects: 7307 * @arg1 < @arg2 (1, 1, ... 7308 * @arg1 <= @arg2 (1, 0, ... 7309 * @arg1 > @arg2 (0, 1, ... 7310 * @arg1 >= @arg2 (0, 0, ... 7311 * 7312 * When neither object to be compared is a node-set and the operator is 7313 * <=, <, >=, >, then the objects are compared by converted both objects 7314 * to numbers and comparing the numbers according to IEEE 754. The < 7315 * comparison will be true if and only if the first number is less than the 7316 * second number. The <= comparison will be true if and only if the first 7317 * number is less than or equal to the second number. The > comparison 7318 * will be true if and only if the first number is greater than the second 7319 * number. The >= comparison will be true if and only if the first number 7320 * is greater than or equal to the second number. 7321 * 7322 * Returns 1 if the comparison succeeded, 0 if it failed 7323 */ 7324 int 7325 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) { 7326 int ret = 0, arg1i = 0, arg2i = 0; 7327 xmlXPathObjectPtr arg1, arg2; 7328 7329 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); 7330 arg2 = valuePop(ctxt); 7331 arg1 = valuePop(ctxt); 7332 if ((arg1 == NULL) || (arg2 == NULL)) { 7333 if (arg1 != NULL) 7334 xmlXPathReleaseObject(ctxt->context, arg1); 7335 else 7336 xmlXPathReleaseObject(ctxt->context, arg2); 7337 XP_ERROR0(XPATH_INVALID_OPERAND); 7338 } 7339 7340 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 7341 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7342 /* 7343 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments 7344 * are not freed from within this routine; they will be freed from the 7345 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue 7346 */ 7347 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) && 7348 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){ 7349 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2); 7350 } else { 7351 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7352 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict, 7353 arg1, arg2); 7354 } else { 7355 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict, 7356 arg2, arg1); 7357 } 7358 } 7359 return(ret); 7360 } 7361 7362 if (arg1->type != XPATH_NUMBER) { 7363 valuePush(ctxt, arg1); 7364 xmlXPathNumberFunction(ctxt, 1); 7365 arg1 = valuePop(ctxt); 7366 } 7367 if (arg1->type != XPATH_NUMBER) { 7368 xmlXPathFreeObject(arg1); 7369 xmlXPathFreeObject(arg2); 7370 XP_ERROR0(XPATH_INVALID_OPERAND); 7371 } 7372 if (arg2->type != XPATH_NUMBER) { 7373 valuePush(ctxt, arg2); 7374 xmlXPathNumberFunction(ctxt, 1); 7375 arg2 = valuePop(ctxt); 7376 } 7377 if (arg2->type != XPATH_NUMBER) { 7378 xmlXPathReleaseObject(ctxt->context, arg1); 7379 xmlXPathReleaseObject(ctxt->context, arg2); 7380 XP_ERROR0(XPATH_INVALID_OPERAND); 7381 } 7382 /* 7383 * Add tests for infinity and nan 7384 * => feedback on 3.4 for Inf and NaN 7385 */ 7386 /* Hand check NaN and Infinity comparisons */ 7387 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) { 7388 ret=0; 7389 } else { 7390 arg1i=xmlXPathIsInf(arg1->floatval); 7391 arg2i=xmlXPathIsInf(arg2->floatval); 7392 if (inf && strict) { 7393 if ((arg1i == -1 && arg2i != -1) || 7394 (arg2i == 1 && arg1i != 1)) { 7395 ret = 1; 7396 } else if (arg1i == 0 && arg2i == 0) { 7397 ret = (arg1->floatval < arg2->floatval); 7398 } else { 7399 ret = 0; 7400 } 7401 } 7402 else if (inf && !strict) { 7403 if (arg1i == -1 || arg2i == 1) { 7404 ret = 1; 7405 } else if (arg1i == 0 && arg2i == 0) { 7406 ret = (arg1->floatval <= arg2->floatval); 7407 } else { 7408 ret = 0; 7409 } 7410 } 7411 else if (!inf && strict) { 7412 if ((arg1i == 1 && arg2i != 1) || 7413 (arg2i == -1 && arg1i != -1)) { 7414 ret = 1; 7415 } else if (arg1i == 0 && arg2i == 0) { 7416 ret = (arg1->floatval > arg2->floatval); 7417 } else { 7418 ret = 0; 7419 } 7420 } 7421 else if (!inf && !strict) { 7422 if (arg1i == 1 || arg2i == -1) { 7423 ret = 1; 7424 } else if (arg1i == 0 && arg2i == 0) { 7425 ret = (arg1->floatval >= arg2->floatval); 7426 } else { 7427 ret = 0; 7428 } 7429 } 7430 } 7431 xmlXPathReleaseObject(ctxt->context, arg1); 7432 xmlXPathReleaseObject(ctxt->context, arg2); 7433 return(ret); 7434 } 7435 7436 /** 7437 * xmlXPathValueFlipSign: 7438 * @ctxt: the XPath Parser context 7439 * 7440 * Implement the unary - operation on an XPath object 7441 * The numeric operators convert their operands to numbers as if 7442 * by calling the number function. 7443 */ 7444 void 7445 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) { 7446 if ((ctxt == NULL) || (ctxt->context == NULL)) return; 7447 CAST_TO_NUMBER; 7448 CHECK_TYPE(XPATH_NUMBER); 7449 if (xmlXPathIsNaN(ctxt->value->floatval)) 7450 ctxt->value->floatval=xmlXPathNAN; 7451 else if (xmlXPathIsInf(ctxt->value->floatval) == 1) 7452 ctxt->value->floatval=xmlXPathNINF; 7453 else if (xmlXPathIsInf(ctxt->value->floatval) == -1) 7454 ctxt->value->floatval=xmlXPathPINF; 7455 else if (ctxt->value->floatval == 0) { 7456 if (xmlXPathGetSign(ctxt->value->floatval) == 0) 7457 ctxt->value->floatval = xmlXPathNZERO; 7458 else 7459 ctxt->value->floatval = 0; 7460 } 7461 else 7462 ctxt->value->floatval = - ctxt->value->floatval; 7463 } 7464 7465 /** 7466 * xmlXPathAddValues: 7467 * @ctxt: the XPath Parser context 7468 * 7469 * Implement the add operation on XPath objects: 7470 * The numeric operators convert their operands to numbers as if 7471 * by calling the number function. 7472 */ 7473 void 7474 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) { 7475 xmlXPathObjectPtr arg; 7476 double val; 7477 7478 arg = valuePop(ctxt); 7479 if (arg == NULL) 7480 XP_ERROR(XPATH_INVALID_OPERAND); 7481 val = xmlXPathCastToNumber(arg); 7482 xmlXPathReleaseObject(ctxt->context, arg); 7483 CAST_TO_NUMBER; 7484 CHECK_TYPE(XPATH_NUMBER); 7485 ctxt->value->floatval += val; 7486 } 7487 7488 /** 7489 * xmlXPathSubValues: 7490 * @ctxt: the XPath Parser context 7491 * 7492 * Implement the subtraction operation on XPath objects: 7493 * The numeric operators convert their operands to numbers as if 7494 * by calling the number function. 7495 */ 7496 void 7497 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) { 7498 xmlXPathObjectPtr arg; 7499 double val; 7500 7501 arg = valuePop(ctxt); 7502 if (arg == NULL) 7503 XP_ERROR(XPATH_INVALID_OPERAND); 7504 val = xmlXPathCastToNumber(arg); 7505 xmlXPathReleaseObject(ctxt->context, arg); 7506 CAST_TO_NUMBER; 7507 CHECK_TYPE(XPATH_NUMBER); 7508 ctxt->value->floatval -= val; 7509 } 7510 7511 /** 7512 * xmlXPathMultValues: 7513 * @ctxt: the XPath Parser context 7514 * 7515 * Implement the multiply operation on XPath objects: 7516 * The numeric operators convert their operands to numbers as if 7517 * by calling the number function. 7518 */ 7519 void 7520 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) { 7521 xmlXPathObjectPtr arg; 7522 double val; 7523 7524 arg = valuePop(ctxt); 7525 if (arg == NULL) 7526 XP_ERROR(XPATH_INVALID_OPERAND); 7527 val = xmlXPathCastToNumber(arg); 7528 xmlXPathReleaseObject(ctxt->context, arg); 7529 CAST_TO_NUMBER; 7530 CHECK_TYPE(XPATH_NUMBER); 7531 ctxt->value->floatval *= val; 7532 } 7533 7534 /** 7535 * xmlXPathDivValues: 7536 * @ctxt: the XPath Parser context 7537 * 7538 * Implement the div operation on XPath objects @arg1 / @arg2: 7539 * The numeric operators convert their operands to numbers as if 7540 * by calling the number function. 7541 */ 7542 void 7543 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) { 7544 xmlXPathObjectPtr arg; 7545 double val; 7546 7547 arg = valuePop(ctxt); 7548 if (arg == NULL) 7549 XP_ERROR(XPATH_INVALID_OPERAND); 7550 val = xmlXPathCastToNumber(arg); 7551 xmlXPathReleaseObject(ctxt->context, arg); 7552 CAST_TO_NUMBER; 7553 CHECK_TYPE(XPATH_NUMBER); 7554 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval)) 7555 ctxt->value->floatval = xmlXPathNAN; 7556 else if (val == 0 && xmlXPathGetSign(val) != 0) { 7557 if (ctxt->value->floatval == 0) 7558 ctxt->value->floatval = xmlXPathNAN; 7559 else if (ctxt->value->floatval > 0) 7560 ctxt->value->floatval = xmlXPathNINF; 7561 else if (ctxt->value->floatval < 0) 7562 ctxt->value->floatval = xmlXPathPINF; 7563 } 7564 else if (val == 0) { 7565 if (ctxt->value->floatval == 0) 7566 ctxt->value->floatval = xmlXPathNAN; 7567 else if (ctxt->value->floatval > 0) 7568 ctxt->value->floatval = xmlXPathPINF; 7569 else if (ctxt->value->floatval < 0) 7570 ctxt->value->floatval = xmlXPathNINF; 7571 } else 7572 ctxt->value->floatval /= val; 7573 } 7574 7575 /** 7576 * xmlXPathModValues: 7577 * @ctxt: the XPath Parser context 7578 * 7579 * Implement the mod operation on XPath objects: @arg1 / @arg2 7580 * The numeric operators convert their operands to numbers as if 7581 * by calling the number function. 7582 */ 7583 void 7584 xmlXPathModValues(xmlXPathParserContextPtr ctxt) { 7585 xmlXPathObjectPtr arg; 7586 double arg1, arg2; 7587 7588 arg = valuePop(ctxt); 7589 if (arg == NULL) 7590 XP_ERROR(XPATH_INVALID_OPERAND); 7591 arg2 = xmlXPathCastToNumber(arg); 7592 xmlXPathReleaseObject(ctxt->context, arg); 7593 CAST_TO_NUMBER; 7594 CHECK_TYPE(XPATH_NUMBER); 7595 arg1 = ctxt->value->floatval; 7596 if (arg2 == 0) 7597 ctxt->value->floatval = xmlXPathNAN; 7598 else { 7599 ctxt->value->floatval = fmod(arg1, arg2); 7600 } 7601 } 7602 7603 /************************************************************************ 7604 * * 7605 * The traversal functions * 7606 * * 7607 ************************************************************************/ 7608 7609 /* 7610 * A traversal function enumerates nodes along an axis. 7611 * Initially it must be called with NULL, and it indicates 7612 * termination on the axis by returning NULL. 7613 */ 7614 typedef xmlNodePtr (*xmlXPathTraversalFunction) 7615 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur); 7616 7617 /* 7618 * xmlXPathTraversalFunctionExt: 7619 * A traversal function enumerates nodes along an axis. 7620 * Initially it must be called with NULL, and it indicates 7621 * termination on the axis by returning NULL. 7622 * The context node of the traversal is specified via @contextNode. 7623 */ 7624 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt) 7625 (xmlNodePtr cur, xmlNodePtr contextNode); 7626 7627 /* 7628 * xmlXPathNodeSetMergeFunction: 7629 * Used for merging node sets in xmlXPathCollectAndTest(). 7630 */ 7631 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction) 7632 (xmlNodeSetPtr, xmlNodeSetPtr, int); 7633 7634 7635 /** 7636 * xmlXPathNextSelf: 7637 * @ctxt: the XPath Parser context 7638 * @cur: the current node in the traversal 7639 * 7640 * Traversal function for the "self" direction 7641 * The self axis contains just the context node itself 7642 * 7643 * Returns the next element following that axis 7644 */ 7645 xmlNodePtr 7646 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7647 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7648 if (cur == NULL) 7649 return(ctxt->context->node); 7650 return(NULL); 7651 } 7652 7653 /** 7654 * xmlXPathNextChild: 7655 * @ctxt: the XPath Parser context 7656 * @cur: the current node in the traversal 7657 * 7658 * Traversal function for the "child" direction 7659 * The child axis contains the children of the context node in document order. 7660 * 7661 * Returns the next element following that axis 7662 */ 7663 xmlNodePtr 7664 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7665 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7666 if (cur == NULL) { 7667 if (ctxt->context->node == NULL) return(NULL); 7668 switch (ctxt->context->node->type) { 7669 case XML_ELEMENT_NODE: 7670 case XML_TEXT_NODE: 7671 case XML_CDATA_SECTION_NODE: 7672 case XML_ENTITY_REF_NODE: 7673 case XML_ENTITY_NODE: 7674 case XML_PI_NODE: 7675 case XML_COMMENT_NODE: 7676 case XML_NOTATION_NODE: 7677 case XML_DTD_NODE: 7678 return(ctxt->context->node->children); 7679 case XML_DOCUMENT_NODE: 7680 case XML_DOCUMENT_TYPE_NODE: 7681 case XML_DOCUMENT_FRAG_NODE: 7682 case XML_HTML_DOCUMENT_NODE: 7683 #ifdef LIBXML_DOCB_ENABLED 7684 case XML_DOCB_DOCUMENT_NODE: 7685 #endif 7686 return(((xmlDocPtr) ctxt->context->node)->children); 7687 case XML_ELEMENT_DECL: 7688 case XML_ATTRIBUTE_DECL: 7689 case XML_ENTITY_DECL: 7690 case XML_ATTRIBUTE_NODE: 7691 case XML_NAMESPACE_DECL: 7692 case XML_XINCLUDE_START: 7693 case XML_XINCLUDE_END: 7694 return(NULL); 7695 } 7696 return(NULL); 7697 } 7698 if ((cur->type == XML_DOCUMENT_NODE) || 7699 (cur->type == XML_HTML_DOCUMENT_NODE)) 7700 return(NULL); 7701 return(cur->next); 7702 } 7703 7704 /** 7705 * xmlXPathNextChildElement: 7706 * @ctxt: the XPath Parser context 7707 * @cur: the current node in the traversal 7708 * 7709 * Traversal function for the "child" direction and nodes of type element. 7710 * The child axis contains the children of the context node in document order. 7711 * 7712 * Returns the next element following that axis 7713 */ 7714 static xmlNodePtr 7715 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7716 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7717 if (cur == NULL) { 7718 cur = ctxt->context->node; 7719 if (cur == NULL) return(NULL); 7720 /* 7721 * Get the first element child. 7722 */ 7723 switch (cur->type) { 7724 case XML_ELEMENT_NODE: 7725 case XML_DOCUMENT_FRAG_NODE: 7726 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */ 7727 case XML_ENTITY_NODE: 7728 cur = cur->children; 7729 if (cur != NULL) { 7730 if (cur->type == XML_ELEMENT_NODE) 7731 return(cur); 7732 do { 7733 cur = cur->next; 7734 } while ((cur != NULL) && 7735 (cur->type != XML_ELEMENT_NODE)); 7736 return(cur); 7737 } 7738 return(NULL); 7739 case XML_DOCUMENT_NODE: 7740 case XML_HTML_DOCUMENT_NODE: 7741 #ifdef LIBXML_DOCB_ENABLED 7742 case XML_DOCB_DOCUMENT_NODE: 7743 #endif 7744 return(xmlDocGetRootElement((xmlDocPtr) cur)); 7745 default: 7746 return(NULL); 7747 } 7748 return(NULL); 7749 } 7750 /* 7751 * Get the next sibling element node. 7752 */ 7753 switch (cur->type) { 7754 case XML_ELEMENT_NODE: 7755 case XML_TEXT_NODE: 7756 case XML_ENTITY_REF_NODE: 7757 case XML_ENTITY_NODE: 7758 case XML_CDATA_SECTION_NODE: 7759 case XML_PI_NODE: 7760 case XML_COMMENT_NODE: 7761 case XML_XINCLUDE_END: 7762 break; 7763 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */ 7764 default: 7765 return(NULL); 7766 } 7767 if (cur->next != NULL) { 7768 if (cur->next->type == XML_ELEMENT_NODE) 7769 return(cur->next); 7770 cur = cur->next; 7771 do { 7772 cur = cur->next; 7773 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE)); 7774 return(cur); 7775 } 7776 return(NULL); 7777 } 7778 7779 #if 0 7780 /** 7781 * xmlXPathNextDescendantOrSelfElemParent: 7782 * @ctxt: the XPath Parser context 7783 * @cur: the current node in the traversal 7784 * 7785 * Traversal function for the "descendant-or-self" axis. 7786 * Additionally it returns only nodes which can be parents of 7787 * element nodes. 7788 * 7789 * 7790 * Returns the next element following that axis 7791 */ 7792 static xmlNodePtr 7793 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur, 7794 xmlNodePtr contextNode) 7795 { 7796 if (cur == NULL) { 7797 if (contextNode == NULL) 7798 return(NULL); 7799 switch (contextNode->type) { 7800 case XML_ELEMENT_NODE: 7801 case XML_XINCLUDE_START: 7802 case XML_DOCUMENT_FRAG_NODE: 7803 case XML_DOCUMENT_NODE: 7804 #ifdef LIBXML_DOCB_ENABLED 7805 case XML_DOCB_DOCUMENT_NODE: 7806 #endif 7807 case XML_HTML_DOCUMENT_NODE: 7808 return(contextNode); 7809 default: 7810 return(NULL); 7811 } 7812 return(NULL); 7813 } else { 7814 xmlNodePtr start = cur; 7815 7816 while (cur != NULL) { 7817 switch (cur->type) { 7818 case XML_ELEMENT_NODE: 7819 /* TODO: OK to have XInclude here? */ 7820 case XML_XINCLUDE_START: 7821 case XML_DOCUMENT_FRAG_NODE: 7822 if (cur != start) 7823 return(cur); 7824 if (cur->children != NULL) { 7825 cur = cur->children; 7826 continue; 7827 } 7828 break; 7829 /* Not sure if we need those here. */ 7830 case XML_DOCUMENT_NODE: 7831 #ifdef LIBXML_DOCB_ENABLED 7832 case XML_DOCB_DOCUMENT_NODE: 7833 #endif 7834 case XML_HTML_DOCUMENT_NODE: 7835 if (cur != start) 7836 return(cur); 7837 return(xmlDocGetRootElement((xmlDocPtr) cur)); 7838 default: 7839 break; 7840 } 7841 7842 next_sibling: 7843 if ((cur == NULL) || (cur == contextNode)) 7844 return(NULL); 7845 if (cur->next != NULL) { 7846 cur = cur->next; 7847 } else { 7848 cur = cur->parent; 7849 goto next_sibling; 7850 } 7851 } 7852 } 7853 return(NULL); 7854 } 7855 #endif 7856 7857 /** 7858 * xmlXPathNextDescendant: 7859 * @ctxt: the XPath Parser context 7860 * @cur: the current node in the traversal 7861 * 7862 * Traversal function for the "descendant" direction 7863 * the descendant axis contains the descendants of the context node in document 7864 * order; a descendant is a child or a child of a child and so on. 7865 * 7866 * Returns the next element following that axis 7867 */ 7868 xmlNodePtr 7869 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7870 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7871 if (cur == NULL) { 7872 if (ctxt->context->node == NULL) 7873 return(NULL); 7874 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 7875 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 7876 return(NULL); 7877 7878 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc) 7879 return(ctxt->context->doc->children); 7880 return(ctxt->context->node->children); 7881 } 7882 7883 if (cur->type == XML_NAMESPACE_DECL) 7884 return(NULL); 7885 if (cur->children != NULL) { 7886 /* 7887 * Do not descend on entities declarations 7888 */ 7889 if (cur->children->type != XML_ENTITY_DECL) { 7890 cur = cur->children; 7891 /* 7892 * Skip DTDs 7893 */ 7894 if (cur->type != XML_DTD_NODE) 7895 return(cur); 7896 } 7897 } 7898 7899 if (cur == ctxt->context->node) return(NULL); 7900 7901 while (cur->next != NULL) { 7902 cur = cur->next; 7903 if ((cur->type != XML_ENTITY_DECL) && 7904 (cur->type != XML_DTD_NODE)) 7905 return(cur); 7906 } 7907 7908 do { 7909 cur = cur->parent; 7910 if (cur == NULL) break; 7911 if (cur == ctxt->context->node) return(NULL); 7912 if (cur->next != NULL) { 7913 cur = cur->next; 7914 return(cur); 7915 } 7916 } while (cur != NULL); 7917 return(cur); 7918 } 7919 7920 /** 7921 * xmlXPathNextDescendantOrSelf: 7922 * @ctxt: the XPath Parser context 7923 * @cur: the current node in the traversal 7924 * 7925 * Traversal function for the "descendant-or-self" direction 7926 * the descendant-or-self axis contains the context node and the descendants 7927 * of the context node in document order; thus the context node is the first 7928 * node on the axis, and the first child of the context node is the second node 7929 * on the axis 7930 * 7931 * Returns the next element following that axis 7932 */ 7933 xmlNodePtr 7934 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7935 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7936 if (cur == NULL) 7937 return(ctxt->context->node); 7938 7939 if (ctxt->context->node == NULL) 7940 return(NULL); 7941 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 7942 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 7943 return(NULL); 7944 7945 return(xmlXPathNextDescendant(ctxt, cur)); 7946 } 7947 7948 /** 7949 * xmlXPathNextParent: 7950 * @ctxt: the XPath Parser context 7951 * @cur: the current node in the traversal 7952 * 7953 * Traversal function for the "parent" direction 7954 * The parent axis contains the parent of the context node, if there is one. 7955 * 7956 * Returns the next element following that axis 7957 */ 7958 xmlNodePtr 7959 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7960 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7961 /* 7962 * the parent of an attribute or namespace node is the element 7963 * to which the attribute or namespace node is attached 7964 * Namespace handling !!! 7965 */ 7966 if (cur == NULL) { 7967 if (ctxt->context->node == NULL) return(NULL); 7968 switch (ctxt->context->node->type) { 7969 case XML_ELEMENT_NODE: 7970 case XML_TEXT_NODE: 7971 case XML_CDATA_SECTION_NODE: 7972 case XML_ENTITY_REF_NODE: 7973 case XML_ENTITY_NODE: 7974 case XML_PI_NODE: 7975 case XML_COMMENT_NODE: 7976 case XML_NOTATION_NODE: 7977 case XML_DTD_NODE: 7978 case XML_ELEMENT_DECL: 7979 case XML_ATTRIBUTE_DECL: 7980 case XML_XINCLUDE_START: 7981 case XML_XINCLUDE_END: 7982 case XML_ENTITY_DECL: 7983 if (ctxt->context->node->parent == NULL) 7984 return((xmlNodePtr) ctxt->context->doc); 7985 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) && 7986 ((ctxt->context->node->parent->name[0] == ' ') || 7987 (xmlStrEqual(ctxt->context->node->parent->name, 7988 BAD_CAST "fake node libxslt")))) 7989 return(NULL); 7990 return(ctxt->context->node->parent); 7991 case XML_ATTRIBUTE_NODE: { 7992 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node; 7993 7994 return(att->parent); 7995 } 7996 case XML_DOCUMENT_NODE: 7997 case XML_DOCUMENT_TYPE_NODE: 7998 case XML_DOCUMENT_FRAG_NODE: 7999 case XML_HTML_DOCUMENT_NODE: 8000 #ifdef LIBXML_DOCB_ENABLED 8001 case XML_DOCB_DOCUMENT_NODE: 8002 #endif 8003 return(NULL); 8004 case XML_NAMESPACE_DECL: { 8005 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; 8006 8007 if ((ns->next != NULL) && 8008 (ns->next->type != XML_NAMESPACE_DECL)) 8009 return((xmlNodePtr) ns->next); 8010 return(NULL); 8011 } 8012 } 8013 } 8014 return(NULL); 8015 } 8016 8017 /** 8018 * xmlXPathNextAncestor: 8019 * @ctxt: the XPath Parser context 8020 * @cur: the current node in the traversal 8021 * 8022 * Traversal function for the "ancestor" direction 8023 * the ancestor axis contains the ancestors of the context node; the ancestors 8024 * of the context node consist of the parent of context node and the parent's 8025 * parent and so on; the nodes are ordered in reverse document order; thus the 8026 * parent is the first node on the axis, and the parent's parent is the second 8027 * node on the axis 8028 * 8029 * Returns the next element following that axis 8030 */ 8031 xmlNodePtr 8032 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8033 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8034 /* 8035 * the parent of an attribute or namespace node is the element 8036 * to which the attribute or namespace node is attached 8037 * !!!!!!!!!!!!! 8038 */ 8039 if (cur == NULL) { 8040 if (ctxt->context->node == NULL) return(NULL); 8041 switch (ctxt->context->node->type) { 8042 case XML_ELEMENT_NODE: 8043 case XML_TEXT_NODE: 8044 case XML_CDATA_SECTION_NODE: 8045 case XML_ENTITY_REF_NODE: 8046 case XML_ENTITY_NODE: 8047 case XML_PI_NODE: 8048 case XML_COMMENT_NODE: 8049 case XML_DTD_NODE: 8050 case XML_ELEMENT_DECL: 8051 case XML_ATTRIBUTE_DECL: 8052 case XML_ENTITY_DECL: 8053 case XML_NOTATION_NODE: 8054 case XML_XINCLUDE_START: 8055 case XML_XINCLUDE_END: 8056 if (ctxt->context->node->parent == NULL) 8057 return((xmlNodePtr) ctxt->context->doc); 8058 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) && 8059 ((ctxt->context->node->parent->name[0] == ' ') || 8060 (xmlStrEqual(ctxt->context->node->parent->name, 8061 BAD_CAST "fake node libxslt")))) 8062 return(NULL); 8063 return(ctxt->context->node->parent); 8064 case XML_ATTRIBUTE_NODE: { 8065 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node; 8066 8067 return(tmp->parent); 8068 } 8069 case XML_DOCUMENT_NODE: 8070 case XML_DOCUMENT_TYPE_NODE: 8071 case XML_DOCUMENT_FRAG_NODE: 8072 case XML_HTML_DOCUMENT_NODE: 8073 #ifdef LIBXML_DOCB_ENABLED 8074 case XML_DOCB_DOCUMENT_NODE: 8075 #endif 8076 return(NULL); 8077 case XML_NAMESPACE_DECL: { 8078 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; 8079 8080 if ((ns->next != NULL) && 8081 (ns->next->type != XML_NAMESPACE_DECL)) 8082 return((xmlNodePtr) ns->next); 8083 /* Bad, how did that namespace end up here ? */ 8084 return(NULL); 8085 } 8086 } 8087 return(NULL); 8088 } 8089 if (cur == ctxt->context->doc->children) 8090 return((xmlNodePtr) ctxt->context->doc); 8091 if (cur == (xmlNodePtr) ctxt->context->doc) 8092 return(NULL); 8093 switch (cur->type) { 8094 case XML_ELEMENT_NODE: 8095 case XML_TEXT_NODE: 8096 case XML_CDATA_SECTION_NODE: 8097 case XML_ENTITY_REF_NODE: 8098 case XML_ENTITY_NODE: 8099 case XML_PI_NODE: 8100 case XML_COMMENT_NODE: 8101 case XML_NOTATION_NODE: 8102 case XML_DTD_NODE: 8103 case XML_ELEMENT_DECL: 8104 case XML_ATTRIBUTE_DECL: 8105 case XML_ENTITY_DECL: 8106 case XML_XINCLUDE_START: 8107 case XML_XINCLUDE_END: 8108 if (cur->parent == NULL) 8109 return(NULL); 8110 if ((cur->parent->type == XML_ELEMENT_NODE) && 8111 ((cur->parent->name[0] == ' ') || 8112 (xmlStrEqual(cur->parent->name, 8113 BAD_CAST "fake node libxslt")))) 8114 return(NULL); 8115 return(cur->parent); 8116 case XML_ATTRIBUTE_NODE: { 8117 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node; 8118 8119 return(att->parent); 8120 } 8121 case XML_NAMESPACE_DECL: { 8122 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; 8123 8124 if ((ns->next != NULL) && 8125 (ns->next->type != XML_NAMESPACE_DECL)) 8126 return((xmlNodePtr) ns->next); 8127 /* Bad, how did that namespace end up here ? */ 8128 return(NULL); 8129 } 8130 case XML_DOCUMENT_NODE: 8131 case XML_DOCUMENT_TYPE_NODE: 8132 case XML_DOCUMENT_FRAG_NODE: 8133 case XML_HTML_DOCUMENT_NODE: 8134 #ifdef LIBXML_DOCB_ENABLED 8135 case XML_DOCB_DOCUMENT_NODE: 8136 #endif 8137 return(NULL); 8138 } 8139 return(NULL); 8140 } 8141 8142 /** 8143 * xmlXPathNextAncestorOrSelf: 8144 * @ctxt: the XPath Parser context 8145 * @cur: the current node in the traversal 8146 * 8147 * Traversal function for the "ancestor-or-self" direction 8148 * he ancestor-or-self axis contains the context node and ancestors of 8149 * the context node in reverse document order; thus the context node is 8150 * the first node on the axis, and the context node's parent the second; 8151 * parent here is defined the same as with the parent axis. 8152 * 8153 * Returns the next element following that axis 8154 */ 8155 xmlNodePtr 8156 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8157 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8158 if (cur == NULL) 8159 return(ctxt->context->node); 8160 return(xmlXPathNextAncestor(ctxt, cur)); 8161 } 8162 8163 /** 8164 * xmlXPathNextFollowingSibling: 8165 * @ctxt: the XPath Parser context 8166 * @cur: the current node in the traversal 8167 * 8168 * Traversal function for the "following-sibling" direction 8169 * The following-sibling axis contains the following siblings of the context 8170 * node in document order. 8171 * 8172 * Returns the next element following that axis 8173 */ 8174 xmlNodePtr 8175 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8176 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8177 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 8178 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 8179 return(NULL); 8180 if (cur == (xmlNodePtr) ctxt->context->doc) 8181 return(NULL); 8182 if (cur == NULL) 8183 return(ctxt->context->node->next); 8184 return(cur->next); 8185 } 8186 8187 /** 8188 * xmlXPathNextPrecedingSibling: 8189 * @ctxt: the XPath Parser context 8190 * @cur: the current node in the traversal 8191 * 8192 * Traversal function for the "preceding-sibling" direction 8193 * The preceding-sibling axis contains the preceding siblings of the context 8194 * node in reverse document order; the first preceding sibling is first on the 8195 * axis; the sibling preceding that node is the second on the axis and so on. 8196 * 8197 * Returns the next element following that axis 8198 */ 8199 xmlNodePtr 8200 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8201 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8202 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 8203 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 8204 return(NULL); 8205 if (cur == (xmlNodePtr) ctxt->context->doc) 8206 return(NULL); 8207 if (cur == NULL) 8208 return(ctxt->context->node->prev); 8209 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) { 8210 cur = cur->prev; 8211 if (cur == NULL) 8212 return(ctxt->context->node->prev); 8213 } 8214 return(cur->prev); 8215 } 8216 8217 /** 8218 * xmlXPathNextFollowing: 8219 * @ctxt: the XPath Parser context 8220 * @cur: the current node in the traversal 8221 * 8222 * Traversal function for the "following" direction 8223 * The following axis contains all nodes in the same document as the context 8224 * node that are after the context node in document order, excluding any 8225 * descendants and excluding attribute nodes and namespace nodes; the nodes 8226 * are ordered in document order 8227 * 8228 * Returns the next element following that axis 8229 */ 8230 xmlNodePtr 8231 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8232 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8233 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) && 8234 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL)) 8235 return(cur->children); 8236 8237 if (cur == NULL) { 8238 cur = ctxt->context->node; 8239 if (cur->type == XML_NAMESPACE_DECL) 8240 return(NULL); 8241 if (cur->type == XML_ATTRIBUTE_NODE) 8242 cur = cur->parent; 8243 } 8244 if (cur == NULL) return(NULL) ; /* ERROR */ 8245 if (cur->next != NULL) return(cur->next) ; 8246 do { 8247 cur = cur->parent; 8248 if (cur == NULL) break; 8249 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL); 8250 if (cur->next != NULL) return(cur->next); 8251 } while (cur != NULL); 8252 return(cur); 8253 } 8254 8255 /* 8256 * xmlXPathIsAncestor: 8257 * @ancestor: the ancestor node 8258 * @node: the current node 8259 * 8260 * Check that @ancestor is a @node's ancestor 8261 * 8262 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise. 8263 */ 8264 static int 8265 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) { 8266 if ((ancestor == NULL) || (node == NULL)) return(0); 8267 if (node->type == XML_NAMESPACE_DECL) 8268 return(0); 8269 if (ancestor->type == XML_NAMESPACE_DECL) 8270 return(0); 8271 /* nodes need to be in the same document */ 8272 if (ancestor->doc != node->doc) return(0); 8273 /* avoid searching if ancestor or node is the root node */ 8274 if (ancestor == (xmlNodePtr) node->doc) return(1); 8275 if (node == (xmlNodePtr) ancestor->doc) return(0); 8276 while (node->parent != NULL) { 8277 if (node->parent == ancestor) 8278 return(1); 8279 node = node->parent; 8280 } 8281 return(0); 8282 } 8283 8284 /** 8285 * xmlXPathNextPreceding: 8286 * @ctxt: the XPath Parser context 8287 * @cur: the current node in the traversal 8288 * 8289 * Traversal function for the "preceding" direction 8290 * the preceding axis contains all nodes in the same document as the context 8291 * node that are before the context node in document order, excluding any 8292 * ancestors and excluding attribute nodes and namespace nodes; the nodes are 8293 * ordered in reverse document order 8294 * 8295 * Returns the next element following that axis 8296 */ 8297 xmlNodePtr 8298 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) 8299 { 8300 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8301 if (cur == NULL) { 8302 cur = ctxt->context->node; 8303 if (cur->type == XML_NAMESPACE_DECL) 8304 return(NULL); 8305 if (cur->type == XML_ATTRIBUTE_NODE) 8306 return(cur->parent); 8307 } 8308 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) 8309 return (NULL); 8310 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) 8311 cur = cur->prev; 8312 do { 8313 if (cur->prev != NULL) { 8314 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ; 8315 return (cur); 8316 } 8317 8318 cur = cur->parent; 8319 if (cur == NULL) 8320 return (NULL); 8321 if (cur == ctxt->context->doc->children) 8322 return (NULL); 8323 } while (xmlXPathIsAncestor(cur, ctxt->context->node)); 8324 return (cur); 8325 } 8326 8327 /** 8328 * xmlXPathNextPrecedingInternal: 8329 * @ctxt: the XPath Parser context 8330 * @cur: the current node in the traversal 8331 * 8332 * Traversal function for the "preceding" direction 8333 * the preceding axis contains all nodes in the same document as the context 8334 * node that are before the context node in document order, excluding any 8335 * ancestors and excluding attribute nodes and namespace nodes; the nodes are 8336 * ordered in reverse document order 8337 * This is a faster implementation but internal only since it requires a 8338 * state kept in the parser context: ctxt->ancestor. 8339 * 8340 * Returns the next element following that axis 8341 */ 8342 static xmlNodePtr 8343 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt, 8344 xmlNodePtr cur) 8345 { 8346 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8347 if (cur == NULL) { 8348 cur = ctxt->context->node; 8349 if (cur == NULL) 8350 return (NULL); 8351 if (cur->type == XML_NAMESPACE_DECL) 8352 return (NULL); 8353 ctxt->ancestor = cur->parent; 8354 } 8355 if (cur->type == XML_NAMESPACE_DECL) 8356 return(NULL); 8357 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) 8358 cur = cur->prev; 8359 while (cur->prev == NULL) { 8360 cur = cur->parent; 8361 if (cur == NULL) 8362 return (NULL); 8363 if (cur == ctxt->context->doc->children) 8364 return (NULL); 8365 if (cur != ctxt->ancestor) 8366 return (cur); 8367 ctxt->ancestor = cur->parent; 8368 } 8369 cur = cur->prev; 8370 while (cur->last != NULL) 8371 cur = cur->last; 8372 return (cur); 8373 } 8374 8375 /** 8376 * xmlXPathNextNamespace: 8377 * @ctxt: the XPath Parser context 8378 * @cur: the current attribute in the traversal 8379 * 8380 * Traversal function for the "namespace" direction 8381 * the namespace axis contains the namespace nodes of the context node; 8382 * the order of nodes on this axis is implementation-defined; the axis will 8383 * be empty unless the context node is an element 8384 * 8385 * We keep the XML namespace node at the end of the list. 8386 * 8387 * Returns the next element following that axis 8388 */ 8389 xmlNodePtr 8390 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8391 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8392 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL); 8393 if (cur == NULL) { 8394 if (ctxt->context->tmpNsList != NULL) 8395 xmlFree(ctxt->context->tmpNsList); 8396 ctxt->context->tmpNsList = 8397 xmlGetNsList(ctxt->context->doc, ctxt->context->node); 8398 ctxt->context->tmpNsNr = 0; 8399 if (ctxt->context->tmpNsList != NULL) { 8400 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) { 8401 ctxt->context->tmpNsNr++; 8402 } 8403 } 8404 return((xmlNodePtr) xmlXPathXMLNamespace); 8405 } 8406 if (ctxt->context->tmpNsNr > 0) { 8407 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr]; 8408 } else { 8409 if (ctxt->context->tmpNsList != NULL) 8410 xmlFree(ctxt->context->tmpNsList); 8411 ctxt->context->tmpNsList = NULL; 8412 return(NULL); 8413 } 8414 } 8415 8416 /** 8417 * xmlXPathNextAttribute: 8418 * @ctxt: the XPath Parser context 8419 * @cur: the current attribute in the traversal 8420 * 8421 * Traversal function for the "attribute" direction 8422 * TODO: support DTD inherited default attributes 8423 * 8424 * Returns the next element following that axis 8425 */ 8426 xmlNodePtr 8427 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8428 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8429 if (ctxt->context->node == NULL) 8430 return(NULL); 8431 if (ctxt->context->node->type != XML_ELEMENT_NODE) 8432 return(NULL); 8433 if (cur == NULL) { 8434 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc) 8435 return(NULL); 8436 return((xmlNodePtr)ctxt->context->node->properties); 8437 } 8438 return((xmlNodePtr)cur->next); 8439 } 8440 8441 /************************************************************************ 8442 * * 8443 * NodeTest Functions * 8444 * * 8445 ************************************************************************/ 8446 8447 #define IS_FUNCTION 200 8448 8449 8450 /************************************************************************ 8451 * * 8452 * Implicit tree core function library * 8453 * * 8454 ************************************************************************/ 8455 8456 /** 8457 * xmlXPathRoot: 8458 * @ctxt: the XPath Parser context 8459 * 8460 * Initialize the context to the root of the document 8461 */ 8462 void 8463 xmlXPathRoot(xmlXPathParserContextPtr ctxt) { 8464 if ((ctxt == NULL) || (ctxt->context == NULL)) 8465 return; 8466 ctxt->context->node = (xmlNodePtr) ctxt->context->doc; 8467 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8468 ctxt->context->node)); 8469 } 8470 8471 /************************************************************************ 8472 * * 8473 * The explicit core function library * 8474 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib * 8475 * * 8476 ************************************************************************/ 8477 8478 8479 /** 8480 * xmlXPathLastFunction: 8481 * @ctxt: the XPath Parser context 8482 * @nargs: the number of arguments 8483 * 8484 * Implement the last() XPath function 8485 * number last() 8486 * The last function returns the number of nodes in the context node list. 8487 */ 8488 void 8489 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8490 CHECK_ARITY(0); 8491 if (ctxt->context->contextSize >= 0) { 8492 valuePush(ctxt, 8493 xmlXPathCacheNewFloat(ctxt->context, 8494 (double) ctxt->context->contextSize)); 8495 #ifdef DEBUG_EXPR 8496 xmlGenericError(xmlGenericErrorContext, 8497 "last() : %d\n", ctxt->context->contextSize); 8498 #endif 8499 } else { 8500 XP_ERROR(XPATH_INVALID_CTXT_SIZE); 8501 } 8502 } 8503 8504 /** 8505 * xmlXPathPositionFunction: 8506 * @ctxt: the XPath Parser context 8507 * @nargs: the number of arguments 8508 * 8509 * Implement the position() XPath function 8510 * number position() 8511 * The position function returns the position of the context node in the 8512 * context node list. The first position is 1, and so the last position 8513 * will be equal to last(). 8514 */ 8515 void 8516 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8517 CHECK_ARITY(0); 8518 if (ctxt->context->proximityPosition >= 0) { 8519 valuePush(ctxt, 8520 xmlXPathCacheNewFloat(ctxt->context, 8521 (double) ctxt->context->proximityPosition)); 8522 #ifdef DEBUG_EXPR 8523 xmlGenericError(xmlGenericErrorContext, "position() : %d\n", 8524 ctxt->context->proximityPosition); 8525 #endif 8526 } else { 8527 XP_ERROR(XPATH_INVALID_CTXT_POSITION); 8528 } 8529 } 8530 8531 /** 8532 * xmlXPathCountFunction: 8533 * @ctxt: the XPath Parser context 8534 * @nargs: the number of arguments 8535 * 8536 * Implement the count() XPath function 8537 * number count(node-set) 8538 */ 8539 void 8540 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8541 xmlXPathObjectPtr cur; 8542 8543 CHECK_ARITY(1); 8544 if ((ctxt->value == NULL) || 8545 ((ctxt->value->type != XPATH_NODESET) && 8546 (ctxt->value->type != XPATH_XSLT_TREE))) 8547 XP_ERROR(XPATH_INVALID_TYPE); 8548 cur = valuePop(ctxt); 8549 8550 if ((cur == NULL) || (cur->nodesetval == NULL)) 8551 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0)); 8552 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) { 8553 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 8554 (double) cur->nodesetval->nodeNr)); 8555 } else { 8556 if ((cur->nodesetval->nodeNr != 1) || 8557 (cur->nodesetval->nodeTab == NULL)) { 8558 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0)); 8559 } else { 8560 xmlNodePtr tmp; 8561 int i = 0; 8562 8563 tmp = cur->nodesetval->nodeTab[0]; 8564 if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) { 8565 tmp = tmp->children; 8566 while (tmp != NULL) { 8567 tmp = tmp->next; 8568 i++; 8569 } 8570 } 8571 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i)); 8572 } 8573 } 8574 xmlXPathReleaseObject(ctxt->context, cur); 8575 } 8576 8577 /** 8578 * xmlXPathGetElementsByIds: 8579 * @doc: the document 8580 * @ids: a whitespace separated list of IDs 8581 * 8582 * Selects elements by their unique ID. 8583 * 8584 * Returns a node-set of selected elements. 8585 */ 8586 static xmlNodeSetPtr 8587 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) { 8588 xmlNodeSetPtr ret; 8589 const xmlChar *cur = ids; 8590 xmlChar *ID; 8591 xmlAttrPtr attr; 8592 xmlNodePtr elem = NULL; 8593 8594 if (ids == NULL) return(NULL); 8595 8596 ret = xmlXPathNodeSetCreate(NULL); 8597 if (ret == NULL) 8598 return(ret); 8599 8600 while (IS_BLANK_CH(*cur)) cur++; 8601 while (*cur != 0) { 8602 while ((!IS_BLANK_CH(*cur)) && (*cur != 0)) 8603 cur++; 8604 8605 ID = xmlStrndup(ids, cur - ids); 8606 if (ID != NULL) { 8607 /* 8608 * We used to check the fact that the value passed 8609 * was an NCName, but this generated much troubles for 8610 * me and Aleksey Sanin, people blatantly violated that 8611 * constaint, like Visa3D spec. 8612 * if (xmlValidateNCName(ID, 1) == 0) 8613 */ 8614 attr = xmlGetID(doc, ID); 8615 if (attr != NULL) { 8616 if (attr->type == XML_ATTRIBUTE_NODE) 8617 elem = attr->parent; 8618 else if (attr->type == XML_ELEMENT_NODE) 8619 elem = (xmlNodePtr) attr; 8620 else 8621 elem = NULL; 8622 if (elem != NULL) 8623 xmlXPathNodeSetAdd(ret, elem); 8624 } 8625 xmlFree(ID); 8626 } 8627 8628 while (IS_BLANK_CH(*cur)) cur++; 8629 ids = cur; 8630 } 8631 return(ret); 8632 } 8633 8634 /** 8635 * xmlXPathIdFunction: 8636 * @ctxt: the XPath Parser context 8637 * @nargs: the number of arguments 8638 * 8639 * Implement the id() XPath function 8640 * node-set id(object) 8641 * The id function selects elements by their unique ID 8642 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set, 8643 * then the result is the union of the result of applying id to the 8644 * string value of each of the nodes in the argument node-set. When the 8645 * argument to id is of any other type, the argument is converted to a 8646 * string as if by a call to the string function; the string is split 8647 * into a whitespace-separated list of tokens (whitespace is any sequence 8648 * of characters matching the production S); the result is a node-set 8649 * containing the elements in the same document as the context node that 8650 * have a unique ID equal to any of the tokens in the list. 8651 */ 8652 void 8653 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8654 xmlChar *tokens; 8655 xmlNodeSetPtr ret; 8656 xmlXPathObjectPtr obj; 8657 8658 CHECK_ARITY(1); 8659 obj = valuePop(ctxt); 8660 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 8661 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) { 8662 xmlNodeSetPtr ns; 8663 int i; 8664 8665 ret = xmlXPathNodeSetCreate(NULL); 8666 /* 8667 * FIXME -- in an out-of-memory condition this will behave badly. 8668 * The solution is not clear -- we already popped an item from 8669 * ctxt, so the object is in a corrupt state. 8670 */ 8671 8672 if (obj->nodesetval != NULL) { 8673 for (i = 0; i < obj->nodesetval->nodeNr; i++) { 8674 tokens = 8675 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]); 8676 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens); 8677 ret = xmlXPathNodeSetMerge(ret, ns); 8678 xmlXPathFreeNodeSet(ns); 8679 if (tokens != NULL) 8680 xmlFree(tokens); 8681 } 8682 } 8683 xmlXPathReleaseObject(ctxt->context, obj); 8684 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret)); 8685 return; 8686 } 8687 obj = xmlXPathCacheConvertString(ctxt->context, obj); 8688 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval); 8689 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret)); 8690 xmlXPathReleaseObject(ctxt->context, obj); 8691 return; 8692 } 8693 8694 /** 8695 * xmlXPathLocalNameFunction: 8696 * @ctxt: the XPath Parser context 8697 * @nargs: the number of arguments 8698 * 8699 * Implement the local-name() XPath function 8700 * string local-name(node-set?) 8701 * The local-name function returns a string containing the local part 8702 * of the name of the node in the argument node-set that is first in 8703 * document order. If the node-set is empty or the first node has no 8704 * name, an empty string is returned. If the argument is omitted it 8705 * defaults to the context node. 8706 */ 8707 void 8708 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8709 xmlXPathObjectPtr cur; 8710 8711 if (ctxt == NULL) return; 8712 8713 if (nargs == 0) { 8714 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8715 ctxt->context->node)); 8716 nargs = 1; 8717 } 8718 8719 CHECK_ARITY(1); 8720 if ((ctxt->value == NULL) || 8721 ((ctxt->value->type != XPATH_NODESET) && 8722 (ctxt->value->type != XPATH_XSLT_TREE))) 8723 XP_ERROR(XPATH_INVALID_TYPE); 8724 cur = valuePop(ctxt); 8725 8726 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 8727 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8728 } else { 8729 int i = 0; /* Should be first in document order !!!!! */ 8730 switch (cur->nodesetval->nodeTab[i]->type) { 8731 case XML_ELEMENT_NODE: 8732 case XML_ATTRIBUTE_NODE: 8733 case XML_PI_NODE: 8734 if (cur->nodesetval->nodeTab[i]->name[0] == ' ') 8735 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8736 else 8737 valuePush(ctxt, 8738 xmlXPathCacheNewString(ctxt->context, 8739 cur->nodesetval->nodeTab[i]->name)); 8740 break; 8741 case XML_NAMESPACE_DECL: 8742 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 8743 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix)); 8744 break; 8745 default: 8746 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8747 } 8748 } 8749 xmlXPathReleaseObject(ctxt->context, cur); 8750 } 8751 8752 /** 8753 * xmlXPathNamespaceURIFunction: 8754 * @ctxt: the XPath Parser context 8755 * @nargs: the number of arguments 8756 * 8757 * Implement the namespace-uri() XPath function 8758 * string namespace-uri(node-set?) 8759 * The namespace-uri function returns a string containing the 8760 * namespace URI of the expanded name of the node in the argument 8761 * node-set that is first in document order. If the node-set is empty, 8762 * the first node has no name, or the expanded name has no namespace 8763 * URI, an empty string is returned. If the argument is omitted it 8764 * defaults to the context node. 8765 */ 8766 void 8767 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8768 xmlXPathObjectPtr cur; 8769 8770 if (ctxt == NULL) return; 8771 8772 if (nargs == 0) { 8773 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8774 ctxt->context->node)); 8775 nargs = 1; 8776 } 8777 CHECK_ARITY(1); 8778 if ((ctxt->value == NULL) || 8779 ((ctxt->value->type != XPATH_NODESET) && 8780 (ctxt->value->type != XPATH_XSLT_TREE))) 8781 XP_ERROR(XPATH_INVALID_TYPE); 8782 cur = valuePop(ctxt); 8783 8784 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 8785 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8786 } else { 8787 int i = 0; /* Should be first in document order !!!!! */ 8788 switch (cur->nodesetval->nodeTab[i]->type) { 8789 case XML_ELEMENT_NODE: 8790 case XML_ATTRIBUTE_NODE: 8791 if (cur->nodesetval->nodeTab[i]->ns == NULL) 8792 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8793 else 8794 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 8795 cur->nodesetval->nodeTab[i]->ns->href)); 8796 break; 8797 default: 8798 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8799 } 8800 } 8801 xmlXPathReleaseObject(ctxt->context, cur); 8802 } 8803 8804 /** 8805 * xmlXPathNameFunction: 8806 * @ctxt: the XPath Parser context 8807 * @nargs: the number of arguments 8808 * 8809 * Implement the name() XPath function 8810 * string name(node-set?) 8811 * The name function returns a string containing a QName representing 8812 * the name of the node in the argument node-set that is first in document 8813 * order. The QName must represent the name with respect to the namespace 8814 * declarations in effect on the node whose name is being represented. 8815 * Typically, this will be the form in which the name occurred in the XML 8816 * source. This need not be the case if there are namespace declarations 8817 * in effect on the node that associate multiple prefixes with the same 8818 * namespace. However, an implementation may include information about 8819 * the original prefix in its representation of nodes; in this case, an 8820 * implementation can ensure that the returned string is always the same 8821 * as the QName used in the XML source. If the argument it omitted it 8822 * defaults to the context node. 8823 * Libxml keep the original prefix so the "real qualified name" used is 8824 * returned. 8825 */ 8826 static void 8827 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) 8828 { 8829 xmlXPathObjectPtr cur; 8830 8831 if (nargs == 0) { 8832 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8833 ctxt->context->node)); 8834 nargs = 1; 8835 } 8836 8837 CHECK_ARITY(1); 8838 if ((ctxt->value == NULL) || 8839 ((ctxt->value->type != XPATH_NODESET) && 8840 (ctxt->value->type != XPATH_XSLT_TREE))) 8841 XP_ERROR(XPATH_INVALID_TYPE); 8842 cur = valuePop(ctxt); 8843 8844 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 8845 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8846 } else { 8847 int i = 0; /* Should be first in document order !!!!! */ 8848 8849 switch (cur->nodesetval->nodeTab[i]->type) { 8850 case XML_ELEMENT_NODE: 8851 case XML_ATTRIBUTE_NODE: 8852 if (cur->nodesetval->nodeTab[i]->name[0] == ' ') 8853 valuePush(ctxt, 8854 xmlXPathCacheNewCString(ctxt->context, "")); 8855 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) || 8856 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) { 8857 valuePush(ctxt, 8858 xmlXPathCacheNewString(ctxt->context, 8859 cur->nodesetval->nodeTab[i]->name)); 8860 } else { 8861 xmlChar *fullname; 8862 8863 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name, 8864 cur->nodesetval->nodeTab[i]->ns->prefix, 8865 NULL, 0); 8866 if (fullname == cur->nodesetval->nodeTab[i]->name) 8867 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name); 8868 if (fullname == NULL) { 8869 XP_ERROR(XPATH_MEMORY_ERROR); 8870 } 8871 valuePush(ctxt, xmlXPathCacheWrapString( 8872 ctxt->context, fullname)); 8873 } 8874 break; 8875 default: 8876 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8877 cur->nodesetval->nodeTab[i])); 8878 xmlXPathLocalNameFunction(ctxt, 1); 8879 } 8880 } 8881 xmlXPathReleaseObject(ctxt->context, cur); 8882 } 8883 8884 8885 /** 8886 * xmlXPathStringFunction: 8887 * @ctxt: the XPath Parser context 8888 * @nargs: the number of arguments 8889 * 8890 * Implement the string() XPath function 8891 * string string(object?) 8892 * The string function converts an object to a string as follows: 8893 * - A node-set is converted to a string by returning the value of 8894 * the node in the node-set that is first in document order. 8895 * If the node-set is empty, an empty string is returned. 8896 * - A number is converted to a string as follows 8897 * + NaN is converted to the string NaN 8898 * + positive zero is converted to the string 0 8899 * + negative zero is converted to the string 0 8900 * + positive infinity is converted to the string Infinity 8901 * + negative infinity is converted to the string -Infinity 8902 * + if the number is an integer, the number is represented in 8903 * decimal form as a Number with no decimal point and no leading 8904 * zeros, preceded by a minus sign (-) if the number is negative 8905 * + otherwise, the number is represented in decimal form as a 8906 * Number including a decimal point with at least one digit 8907 * before the decimal point and at least one digit after the 8908 * decimal point, preceded by a minus sign (-) if the number 8909 * is negative; there must be no leading zeros before the decimal 8910 * point apart possibly from the one required digit immediately 8911 * before the decimal point; beyond the one required digit 8912 * after the decimal point there must be as many, but only as 8913 * many, more digits as are needed to uniquely distinguish the 8914 * number from all other IEEE 754 numeric values. 8915 * - The boolean false value is converted to the string false. 8916 * The boolean true value is converted to the string true. 8917 * 8918 * If the argument is omitted, it defaults to a node-set with the 8919 * context node as its only member. 8920 */ 8921 void 8922 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8923 xmlXPathObjectPtr cur; 8924 8925 if (ctxt == NULL) return; 8926 if (nargs == 0) { 8927 valuePush(ctxt, 8928 xmlXPathCacheWrapString(ctxt->context, 8929 xmlXPathCastNodeToString(ctxt->context->node))); 8930 return; 8931 } 8932 8933 CHECK_ARITY(1); 8934 cur = valuePop(ctxt); 8935 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 8936 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur)); 8937 } 8938 8939 /** 8940 * xmlXPathStringLengthFunction: 8941 * @ctxt: the XPath Parser context 8942 * @nargs: the number of arguments 8943 * 8944 * Implement the string-length() XPath function 8945 * number string-length(string?) 8946 * The string-length returns the number of characters in the string 8947 * (see [3.6 Strings]). If the argument is omitted, it defaults to 8948 * the context node converted to a string, in other words the value 8949 * of the context node. 8950 */ 8951 void 8952 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8953 xmlXPathObjectPtr cur; 8954 8955 if (nargs == 0) { 8956 if ((ctxt == NULL) || (ctxt->context == NULL)) 8957 return; 8958 if (ctxt->context->node == NULL) { 8959 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0)); 8960 } else { 8961 xmlChar *content; 8962 8963 content = xmlXPathCastNodeToString(ctxt->context->node); 8964 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 8965 xmlUTF8Strlen(content))); 8966 xmlFree(content); 8967 } 8968 return; 8969 } 8970 CHECK_ARITY(1); 8971 CAST_TO_STRING; 8972 CHECK_TYPE(XPATH_STRING); 8973 cur = valuePop(ctxt); 8974 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 8975 xmlUTF8Strlen(cur->stringval))); 8976 xmlXPathReleaseObject(ctxt->context, cur); 8977 } 8978 8979 /** 8980 * xmlXPathConcatFunction: 8981 * @ctxt: the XPath Parser context 8982 * @nargs: the number of arguments 8983 * 8984 * Implement the concat() XPath function 8985 * string concat(string, string, string*) 8986 * The concat function returns the concatenation of its arguments. 8987 */ 8988 void 8989 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8990 xmlXPathObjectPtr cur, newobj; 8991 xmlChar *tmp; 8992 8993 if (ctxt == NULL) return; 8994 if (nargs < 2) { 8995 CHECK_ARITY(2); 8996 } 8997 8998 CAST_TO_STRING; 8999 cur = valuePop(ctxt); 9000 if ((cur == NULL) || (cur->type != XPATH_STRING)) { 9001 xmlXPathReleaseObject(ctxt->context, cur); 9002 return; 9003 } 9004 nargs--; 9005 9006 while (nargs > 0) { 9007 CAST_TO_STRING; 9008 newobj = valuePop(ctxt); 9009 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) { 9010 xmlXPathReleaseObject(ctxt->context, newobj); 9011 xmlXPathReleaseObject(ctxt->context, cur); 9012 XP_ERROR(XPATH_INVALID_TYPE); 9013 } 9014 tmp = xmlStrcat(newobj->stringval, cur->stringval); 9015 newobj->stringval = cur->stringval; 9016 cur->stringval = tmp; 9017 xmlXPathReleaseObject(ctxt->context, newobj); 9018 nargs--; 9019 } 9020 valuePush(ctxt, cur); 9021 } 9022 9023 /** 9024 * xmlXPathContainsFunction: 9025 * @ctxt: the XPath Parser context 9026 * @nargs: the number of arguments 9027 * 9028 * Implement the contains() XPath function 9029 * boolean contains(string, string) 9030 * The contains function returns true if the first argument string 9031 * contains the second argument string, and otherwise returns false. 9032 */ 9033 void 9034 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9035 xmlXPathObjectPtr hay, needle; 9036 9037 CHECK_ARITY(2); 9038 CAST_TO_STRING; 9039 CHECK_TYPE(XPATH_STRING); 9040 needle = valuePop(ctxt); 9041 CAST_TO_STRING; 9042 hay = valuePop(ctxt); 9043 9044 if ((hay == NULL) || (hay->type != XPATH_STRING)) { 9045 xmlXPathReleaseObject(ctxt->context, hay); 9046 xmlXPathReleaseObject(ctxt->context, needle); 9047 XP_ERROR(XPATH_INVALID_TYPE); 9048 } 9049 if (xmlStrstr(hay->stringval, needle->stringval)) 9050 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); 9051 else 9052 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); 9053 xmlXPathReleaseObject(ctxt->context, hay); 9054 xmlXPathReleaseObject(ctxt->context, needle); 9055 } 9056 9057 /** 9058 * xmlXPathStartsWithFunction: 9059 * @ctxt: the XPath Parser context 9060 * @nargs: the number of arguments 9061 * 9062 * Implement the starts-with() XPath function 9063 * boolean starts-with(string, string) 9064 * The starts-with function returns true if the first argument string 9065 * starts with the second argument string, and otherwise returns false. 9066 */ 9067 void 9068 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9069 xmlXPathObjectPtr hay, needle; 9070 int n; 9071 9072 CHECK_ARITY(2); 9073 CAST_TO_STRING; 9074 CHECK_TYPE(XPATH_STRING); 9075 needle = valuePop(ctxt); 9076 CAST_TO_STRING; 9077 hay = valuePop(ctxt); 9078 9079 if ((hay == NULL) || (hay->type != XPATH_STRING)) { 9080 xmlXPathReleaseObject(ctxt->context, hay); 9081 xmlXPathReleaseObject(ctxt->context, needle); 9082 XP_ERROR(XPATH_INVALID_TYPE); 9083 } 9084 n = xmlStrlen(needle->stringval); 9085 if (xmlStrncmp(hay->stringval, needle->stringval, n)) 9086 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); 9087 else 9088 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); 9089 xmlXPathReleaseObject(ctxt->context, hay); 9090 xmlXPathReleaseObject(ctxt->context, needle); 9091 } 9092 9093 /** 9094 * xmlXPathSubstringFunction: 9095 * @ctxt: the XPath Parser context 9096 * @nargs: the number of arguments 9097 * 9098 * Implement the substring() XPath function 9099 * string substring(string, number, number?) 9100 * The substring function returns the substring of the first argument 9101 * starting at the position specified in the second argument with 9102 * length specified in the third argument. For example, 9103 * substring("12345",2,3) returns "234". If the third argument is not 9104 * specified, it returns the substring starting at the position specified 9105 * in the second argument and continuing to the end of the string. For 9106 * example, substring("12345",2) returns "2345". More precisely, each 9107 * character in the string (see [3.6 Strings]) is considered to have a 9108 * numeric position: the position of the first character is 1, the position 9109 * of the second character is 2 and so on. The returned substring contains 9110 * those characters for which the position of the character is greater than 9111 * or equal to the second argument and, if the third argument is specified, 9112 * less than the sum of the second and third arguments; the comparisons 9113 * and addition used for the above follow the standard IEEE 754 rules. Thus: 9114 * - substring("12345", 1.5, 2.6) returns "234" 9115 * - substring("12345", 0, 3) returns "12" 9116 * - substring("12345", 0 div 0, 3) returns "" 9117 * - substring("12345", 1, 0 div 0) returns "" 9118 * - substring("12345", -42, 1 div 0) returns "12345" 9119 * - substring("12345", -1 div 0, 1 div 0) returns "" 9120 */ 9121 void 9122 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9123 xmlXPathObjectPtr str, start, len; 9124 double le=0, in; 9125 int i, l, m; 9126 xmlChar *ret; 9127 9128 if (nargs < 2) { 9129 CHECK_ARITY(2); 9130 } 9131 if (nargs > 3) { 9132 CHECK_ARITY(3); 9133 } 9134 /* 9135 * take care of possible last (position) argument 9136 */ 9137 if (nargs == 3) { 9138 CAST_TO_NUMBER; 9139 CHECK_TYPE(XPATH_NUMBER); 9140 len = valuePop(ctxt); 9141 le = len->floatval; 9142 xmlXPathReleaseObject(ctxt->context, len); 9143 } 9144 9145 CAST_TO_NUMBER; 9146 CHECK_TYPE(XPATH_NUMBER); 9147 start = valuePop(ctxt); 9148 in = start->floatval; 9149 xmlXPathReleaseObject(ctxt->context, start); 9150 CAST_TO_STRING; 9151 CHECK_TYPE(XPATH_STRING); 9152 str = valuePop(ctxt); 9153 m = xmlUTF8Strlen((const unsigned char *)str->stringval); 9154 9155 /* 9156 * If last pos not present, calculate last position 9157 */ 9158 if (nargs != 3) { 9159 le = (double)m; 9160 if (in < 1.0) 9161 in = 1.0; 9162 } 9163 9164 /* Need to check for the special cases where either 9165 * the index is NaN, the length is NaN, or both 9166 * arguments are infinity (relying on Inf + -Inf = NaN) 9167 */ 9168 if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) { 9169 /* 9170 * To meet the requirements of the spec, the arguments 9171 * must be converted to integer format before 9172 * initial index calculations are done 9173 * 9174 * First we go to integer form, rounding up 9175 * and checking for special cases 9176 */ 9177 i = (int) in; 9178 if (((double)i)+0.5 <= in) i++; 9179 9180 if (xmlXPathIsInf(le) == 1) { 9181 l = m; 9182 if (i < 1) 9183 i = 1; 9184 } 9185 else if (xmlXPathIsInf(le) == -1 || le < 0.0) 9186 l = 0; 9187 else { 9188 l = (int) le; 9189 if (((double)l)+0.5 <= le) l++; 9190 } 9191 9192 /* Now we normalize inidices */ 9193 i -= 1; 9194 l += i; 9195 if (i < 0) 9196 i = 0; 9197 if (l > m) 9198 l = m; 9199 9200 /* number of chars to copy */ 9201 l -= i; 9202 9203 ret = xmlUTF8Strsub(str->stringval, i, l); 9204 } 9205 else { 9206 ret = NULL; 9207 } 9208 if (ret == NULL) 9209 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 9210 else { 9211 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret)); 9212 xmlFree(ret); 9213 } 9214 xmlXPathReleaseObject(ctxt->context, str); 9215 } 9216 9217 /** 9218 * xmlXPathSubstringBeforeFunction: 9219 * @ctxt: the XPath Parser context 9220 * @nargs: the number of arguments 9221 * 9222 * Implement the substring-before() XPath function 9223 * string substring-before(string, string) 9224 * The substring-before function returns the substring of the first 9225 * argument string that precedes the first occurrence of the second 9226 * argument string in the first argument string, or the empty string 9227 * if the first argument string does not contain the second argument 9228 * string. For example, substring-before("1999/04/01","/") returns 1999. 9229 */ 9230 void 9231 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9232 xmlXPathObjectPtr str; 9233 xmlXPathObjectPtr find; 9234 xmlBufPtr target; 9235 const xmlChar *point; 9236 int offset; 9237 9238 CHECK_ARITY(2); 9239 CAST_TO_STRING; 9240 find = valuePop(ctxt); 9241 CAST_TO_STRING; 9242 str = valuePop(ctxt); 9243 9244 target = xmlBufCreate(); 9245 if (target) { 9246 point = xmlStrstr(str->stringval, find->stringval); 9247 if (point) { 9248 offset = (int)(point - str->stringval); 9249 xmlBufAdd(target, str->stringval, offset); 9250 } 9251 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9252 xmlBufContent(target))); 9253 xmlBufFree(target); 9254 } 9255 xmlXPathReleaseObject(ctxt->context, str); 9256 xmlXPathReleaseObject(ctxt->context, find); 9257 } 9258 9259 /** 9260 * xmlXPathSubstringAfterFunction: 9261 * @ctxt: the XPath Parser context 9262 * @nargs: the number of arguments 9263 * 9264 * Implement the substring-after() XPath function 9265 * string substring-after(string, string) 9266 * The substring-after function returns the substring of the first 9267 * argument string that follows the first occurrence of the second 9268 * argument string in the first argument string, or the empty stringi 9269 * if the first argument string does not contain the second argument 9270 * string. For example, substring-after("1999/04/01","/") returns 04/01, 9271 * and substring-after("1999/04/01","19") returns 99/04/01. 9272 */ 9273 void 9274 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9275 xmlXPathObjectPtr str; 9276 xmlXPathObjectPtr find; 9277 xmlBufPtr target; 9278 const xmlChar *point; 9279 int offset; 9280 9281 CHECK_ARITY(2); 9282 CAST_TO_STRING; 9283 find = valuePop(ctxt); 9284 CAST_TO_STRING; 9285 str = valuePop(ctxt); 9286 9287 target = xmlBufCreate(); 9288 if (target) { 9289 point = xmlStrstr(str->stringval, find->stringval); 9290 if (point) { 9291 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval); 9292 xmlBufAdd(target, &str->stringval[offset], 9293 xmlStrlen(str->stringval) - offset); 9294 } 9295 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9296 xmlBufContent(target))); 9297 xmlBufFree(target); 9298 } 9299 xmlXPathReleaseObject(ctxt->context, str); 9300 xmlXPathReleaseObject(ctxt->context, find); 9301 } 9302 9303 /** 9304 * xmlXPathNormalizeFunction: 9305 * @ctxt: the XPath Parser context 9306 * @nargs: the number of arguments 9307 * 9308 * Implement the normalize-space() XPath function 9309 * string normalize-space(string?) 9310 * The normalize-space function returns the argument string with white 9311 * space normalized by stripping leading and trailing whitespace 9312 * and replacing sequences of whitespace characters by a single 9313 * space. Whitespace characters are the same allowed by the S production 9314 * in XML. If the argument is omitted, it defaults to the context 9315 * node converted to a string, in other words the value of the context node. 9316 */ 9317 void 9318 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9319 xmlXPathObjectPtr obj = NULL; 9320 xmlChar *source = NULL; 9321 xmlBufPtr target; 9322 xmlChar blank; 9323 9324 if (ctxt == NULL) return; 9325 if (nargs == 0) { 9326 /* Use current context node */ 9327 valuePush(ctxt, 9328 xmlXPathCacheWrapString(ctxt->context, 9329 xmlXPathCastNodeToString(ctxt->context->node))); 9330 nargs = 1; 9331 } 9332 9333 CHECK_ARITY(1); 9334 CAST_TO_STRING; 9335 CHECK_TYPE(XPATH_STRING); 9336 obj = valuePop(ctxt); 9337 source = obj->stringval; 9338 9339 target = xmlBufCreate(); 9340 if (target && source) { 9341 9342 /* Skip leading whitespaces */ 9343 while (IS_BLANK_CH(*source)) 9344 source++; 9345 9346 /* Collapse intermediate whitespaces, and skip trailing whitespaces */ 9347 blank = 0; 9348 while (*source) { 9349 if (IS_BLANK_CH(*source)) { 9350 blank = 0x20; 9351 } else { 9352 if (blank) { 9353 xmlBufAdd(target, &blank, 1); 9354 blank = 0; 9355 } 9356 xmlBufAdd(target, source, 1); 9357 } 9358 source++; 9359 } 9360 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9361 xmlBufContent(target))); 9362 xmlBufFree(target); 9363 } 9364 xmlXPathReleaseObject(ctxt->context, obj); 9365 } 9366 9367 /** 9368 * xmlXPathTranslateFunction: 9369 * @ctxt: the XPath Parser context 9370 * @nargs: the number of arguments 9371 * 9372 * Implement the translate() XPath function 9373 * string translate(string, string, string) 9374 * The translate function returns the first argument string with 9375 * occurrences of characters in the second argument string replaced 9376 * by the character at the corresponding position in the third argument 9377 * string. For example, translate("bar","abc","ABC") returns the string 9378 * BAr. If there is a character in the second argument string with no 9379 * character at a corresponding position in the third argument string 9380 * (because the second argument string is longer than the third argument 9381 * string), then occurrences of that character in the first argument 9382 * string are removed. For example, translate("--aaa--","abc-","ABC") 9383 * returns "AAA". If a character occurs more than once in second 9384 * argument string, then the first occurrence determines the replacement 9385 * character. If the third argument string is longer than the second 9386 * argument string, then excess characters are ignored. 9387 */ 9388 void 9389 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9390 xmlXPathObjectPtr str; 9391 xmlXPathObjectPtr from; 9392 xmlXPathObjectPtr to; 9393 xmlBufPtr target; 9394 int offset, max; 9395 xmlChar ch; 9396 const xmlChar *point; 9397 xmlChar *cptr; 9398 9399 CHECK_ARITY(3); 9400 9401 CAST_TO_STRING; 9402 to = valuePop(ctxt); 9403 CAST_TO_STRING; 9404 from = valuePop(ctxt); 9405 CAST_TO_STRING; 9406 str = valuePop(ctxt); 9407 9408 target = xmlBufCreate(); 9409 if (target) { 9410 max = xmlUTF8Strlen(to->stringval); 9411 for (cptr = str->stringval; (ch=*cptr); ) { 9412 offset = xmlUTF8Strloc(from->stringval, cptr); 9413 if (offset >= 0) { 9414 if (offset < max) { 9415 point = xmlUTF8Strpos(to->stringval, offset); 9416 if (point) 9417 xmlBufAdd(target, point, xmlUTF8Strsize(point, 1)); 9418 } 9419 } else 9420 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1)); 9421 9422 /* Step to next character in input */ 9423 cptr++; 9424 if ( ch & 0x80 ) { 9425 /* if not simple ascii, verify proper format */ 9426 if ( (ch & 0xc0) != 0xc0 ) { 9427 xmlGenericError(xmlGenericErrorContext, 9428 "xmlXPathTranslateFunction: Invalid UTF8 string\n"); 9429 /* not asserting an XPath error is probably better */ 9430 break; 9431 } 9432 /* then skip over remaining bytes for this char */ 9433 while ( (ch <<= 1) & 0x80 ) 9434 if ( (*cptr++ & 0xc0) != 0x80 ) { 9435 xmlGenericError(xmlGenericErrorContext, 9436 "xmlXPathTranslateFunction: Invalid UTF8 string\n"); 9437 /* not asserting an XPath error is probably better */ 9438 break; 9439 } 9440 if (ch & 0x80) /* must have had error encountered */ 9441 break; 9442 } 9443 } 9444 } 9445 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9446 xmlBufContent(target))); 9447 xmlBufFree(target); 9448 xmlXPathReleaseObject(ctxt->context, str); 9449 xmlXPathReleaseObject(ctxt->context, from); 9450 xmlXPathReleaseObject(ctxt->context, to); 9451 } 9452 9453 /** 9454 * xmlXPathBooleanFunction: 9455 * @ctxt: the XPath Parser context 9456 * @nargs: the number of arguments 9457 * 9458 * Implement the boolean() XPath function 9459 * boolean boolean(object) 9460 * The boolean function converts its argument to a boolean as follows: 9461 * - a number is true if and only if it is neither positive or 9462 * negative zero nor NaN 9463 * - a node-set is true if and only if it is non-empty 9464 * - a string is true if and only if its length is non-zero 9465 */ 9466 void 9467 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9468 xmlXPathObjectPtr cur; 9469 9470 CHECK_ARITY(1); 9471 cur = valuePop(ctxt); 9472 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 9473 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur); 9474 valuePush(ctxt, cur); 9475 } 9476 9477 /** 9478 * xmlXPathNotFunction: 9479 * @ctxt: the XPath Parser context 9480 * @nargs: the number of arguments 9481 * 9482 * Implement the not() XPath function 9483 * boolean not(boolean) 9484 * The not function returns true if its argument is false, 9485 * and false otherwise. 9486 */ 9487 void 9488 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9489 CHECK_ARITY(1); 9490 CAST_TO_BOOLEAN; 9491 CHECK_TYPE(XPATH_BOOLEAN); 9492 ctxt->value->boolval = ! ctxt->value->boolval; 9493 } 9494 9495 /** 9496 * xmlXPathTrueFunction: 9497 * @ctxt: the XPath Parser context 9498 * @nargs: the number of arguments 9499 * 9500 * Implement the true() XPath function 9501 * boolean true() 9502 */ 9503 void 9504 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9505 CHECK_ARITY(0); 9506 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); 9507 } 9508 9509 /** 9510 * xmlXPathFalseFunction: 9511 * @ctxt: the XPath Parser context 9512 * @nargs: the number of arguments 9513 * 9514 * Implement the false() XPath function 9515 * boolean false() 9516 */ 9517 void 9518 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9519 CHECK_ARITY(0); 9520 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); 9521 } 9522 9523 /** 9524 * xmlXPathLangFunction: 9525 * @ctxt: the XPath Parser context 9526 * @nargs: the number of arguments 9527 * 9528 * Implement the lang() XPath function 9529 * boolean lang(string) 9530 * The lang function returns true or false depending on whether the 9531 * language of the context node as specified by xml:lang attributes 9532 * is the same as or is a sublanguage of the language specified by 9533 * the argument string. The language of the context node is determined 9534 * by the value of the xml:lang attribute on the context node, or, if 9535 * the context node has no xml:lang attribute, by the value of the 9536 * xml:lang attribute on the nearest ancestor of the context node that 9537 * has an xml:lang attribute. If there is no such attribute, then lang 9538 * returns false. If there is such an attribute, then lang returns 9539 * true if the attribute value is equal to the argument ignoring case, 9540 * or if there is some suffix starting with - such that the attribute 9541 * value is equal to the argument ignoring that suffix of the attribute 9542 * value and ignoring case. 9543 */ 9544 void 9545 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9546 xmlXPathObjectPtr val = NULL; 9547 const xmlChar *theLang = NULL; 9548 const xmlChar *lang; 9549 int ret = 0; 9550 int i; 9551 9552 CHECK_ARITY(1); 9553 CAST_TO_STRING; 9554 CHECK_TYPE(XPATH_STRING); 9555 val = valuePop(ctxt); 9556 lang = val->stringval; 9557 theLang = xmlNodeGetLang(ctxt->context->node); 9558 if ((theLang != NULL) && (lang != NULL)) { 9559 for (i = 0;lang[i] != 0;i++) 9560 if (toupper(lang[i]) != toupper(theLang[i])) 9561 goto not_equal; 9562 if ((theLang[i] == 0) || (theLang[i] == '-')) 9563 ret = 1; 9564 } 9565 not_equal: 9566 if (theLang != NULL) 9567 xmlFree((void *)theLang); 9568 9569 xmlXPathReleaseObject(ctxt->context, val); 9570 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret)); 9571 } 9572 9573 /** 9574 * xmlXPathNumberFunction: 9575 * @ctxt: the XPath Parser context 9576 * @nargs: the number of arguments 9577 * 9578 * Implement the number() XPath function 9579 * number number(object?) 9580 */ 9581 void 9582 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9583 xmlXPathObjectPtr cur; 9584 double res; 9585 9586 if (ctxt == NULL) return; 9587 if (nargs == 0) { 9588 if (ctxt->context->node == NULL) { 9589 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0)); 9590 } else { 9591 xmlChar* content = xmlNodeGetContent(ctxt->context->node); 9592 9593 res = xmlXPathStringEvalNumber(content); 9594 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res)); 9595 xmlFree(content); 9596 } 9597 return; 9598 } 9599 9600 CHECK_ARITY(1); 9601 cur = valuePop(ctxt); 9602 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur)); 9603 } 9604 9605 /** 9606 * xmlXPathSumFunction: 9607 * @ctxt: the XPath Parser context 9608 * @nargs: the number of arguments 9609 * 9610 * Implement the sum() XPath function 9611 * number sum(node-set) 9612 * The sum function returns the sum of the values of the nodes in 9613 * the argument node-set. 9614 */ 9615 void 9616 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9617 xmlXPathObjectPtr cur; 9618 int i; 9619 double res = 0.0; 9620 9621 CHECK_ARITY(1); 9622 if ((ctxt->value == NULL) || 9623 ((ctxt->value->type != XPATH_NODESET) && 9624 (ctxt->value->type != XPATH_XSLT_TREE))) 9625 XP_ERROR(XPATH_INVALID_TYPE); 9626 cur = valuePop(ctxt); 9627 9628 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) { 9629 for (i = 0; i < cur->nodesetval->nodeNr; i++) { 9630 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]); 9631 } 9632 } 9633 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res)); 9634 xmlXPathReleaseObject(ctxt->context, cur); 9635 } 9636 9637 /* 9638 * To assure working code on multiple platforms, we want to only depend 9639 * upon the characteristic truncation of converting a floating point value 9640 * to an integer. Unfortunately, because of the different storage sizes 9641 * of our internal floating point value (double) and integer (int), we 9642 * can't directly convert (see bug 301162). This macro is a messy 9643 * 'workaround' 9644 */ 9645 #define XTRUNC(f, v) \ 9646 f = fmod((v), INT_MAX); \ 9647 f = (v) - (f) + (double)((int)(f)); 9648 9649 /** 9650 * xmlXPathFloorFunction: 9651 * @ctxt: the XPath Parser context 9652 * @nargs: the number of arguments 9653 * 9654 * Implement the floor() XPath function 9655 * number floor(number) 9656 * The floor function returns the largest (closest to positive infinity) 9657 * number that is not greater than the argument and that is an integer. 9658 */ 9659 void 9660 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9661 double f; 9662 9663 CHECK_ARITY(1); 9664 CAST_TO_NUMBER; 9665 CHECK_TYPE(XPATH_NUMBER); 9666 9667 XTRUNC(f, ctxt->value->floatval); 9668 if (f != ctxt->value->floatval) { 9669 if (ctxt->value->floatval > 0) 9670 ctxt->value->floatval = f; 9671 else 9672 ctxt->value->floatval = f - 1; 9673 } 9674 } 9675 9676 /** 9677 * xmlXPathCeilingFunction: 9678 * @ctxt: the XPath Parser context 9679 * @nargs: the number of arguments 9680 * 9681 * Implement the ceiling() XPath function 9682 * number ceiling(number) 9683 * The ceiling function returns the smallest (closest to negative infinity) 9684 * number that is not less than the argument and that is an integer. 9685 */ 9686 void 9687 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9688 double f; 9689 9690 CHECK_ARITY(1); 9691 CAST_TO_NUMBER; 9692 CHECK_TYPE(XPATH_NUMBER); 9693 9694 #if 0 9695 ctxt->value->floatval = ceil(ctxt->value->floatval); 9696 #else 9697 XTRUNC(f, ctxt->value->floatval); 9698 if (f != ctxt->value->floatval) { 9699 if (ctxt->value->floatval > 0) 9700 ctxt->value->floatval = f + 1; 9701 else { 9702 if (ctxt->value->floatval < 0 && f == 0) 9703 ctxt->value->floatval = xmlXPathNZERO; 9704 else 9705 ctxt->value->floatval = f; 9706 } 9707 9708 } 9709 #endif 9710 } 9711 9712 /** 9713 * xmlXPathRoundFunction: 9714 * @ctxt: the XPath Parser context 9715 * @nargs: the number of arguments 9716 * 9717 * Implement the round() XPath function 9718 * number round(number) 9719 * The round function returns the number that is closest to the 9720 * argument and that is an integer. If there are two such numbers, 9721 * then the one that is even is returned. 9722 */ 9723 void 9724 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9725 double f; 9726 9727 CHECK_ARITY(1); 9728 CAST_TO_NUMBER; 9729 CHECK_TYPE(XPATH_NUMBER); 9730 9731 if ((xmlXPathIsNaN(ctxt->value->floatval)) || 9732 (xmlXPathIsInf(ctxt->value->floatval) == 1) || 9733 (xmlXPathIsInf(ctxt->value->floatval) == -1) || 9734 (ctxt->value->floatval == 0.0)) 9735 return; 9736 9737 XTRUNC(f, ctxt->value->floatval); 9738 if (ctxt->value->floatval < 0) { 9739 if (ctxt->value->floatval < f - 0.5) 9740 ctxt->value->floatval = f - 1; 9741 else 9742 ctxt->value->floatval = f; 9743 if (ctxt->value->floatval == 0) 9744 ctxt->value->floatval = xmlXPathNZERO; 9745 } else { 9746 if (ctxt->value->floatval < f + 0.5) 9747 ctxt->value->floatval = f; 9748 else 9749 ctxt->value->floatval = f + 1; 9750 } 9751 } 9752 9753 /************************************************************************ 9754 * * 9755 * The Parser * 9756 * * 9757 ************************************************************************/ 9758 9759 /* 9760 * a few forward declarations since we use a recursive call based 9761 * implementation. 9762 */ 9763 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort); 9764 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter); 9765 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt); 9766 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt); 9767 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, 9768 int qualified); 9769 9770 /** 9771 * xmlXPathCurrentChar: 9772 * @ctxt: the XPath parser context 9773 * @cur: pointer to the beginning of the char 9774 * @len: pointer to the length of the char read 9775 * 9776 * The current char value, if using UTF-8 this may actually span multiple 9777 * bytes in the input buffer. 9778 * 9779 * Returns the current char value and its length 9780 */ 9781 9782 static int 9783 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) { 9784 unsigned char c; 9785 unsigned int val; 9786 const xmlChar *cur; 9787 9788 if (ctxt == NULL) 9789 return(0); 9790 cur = ctxt->cur; 9791 9792 /* 9793 * We are supposed to handle UTF8, check it's valid 9794 * From rfc2044: encoding of the Unicode values on UTF-8: 9795 * 9796 * UCS-4 range (hex.) UTF-8 octet sequence (binary) 9797 * 0000 0000-0000 007F 0xxxxxxx 9798 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx 9799 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx 9800 * 9801 * Check for the 0x110000 limit too 9802 */ 9803 c = *cur; 9804 if (c & 0x80) { 9805 if ((cur[1] & 0xc0) != 0x80) 9806 goto encoding_error; 9807 if ((c & 0xe0) == 0xe0) { 9808 9809 if ((cur[2] & 0xc0) != 0x80) 9810 goto encoding_error; 9811 if ((c & 0xf0) == 0xf0) { 9812 if (((c & 0xf8) != 0xf0) || 9813 ((cur[3] & 0xc0) != 0x80)) 9814 goto encoding_error; 9815 /* 4-byte code */ 9816 *len = 4; 9817 val = (cur[0] & 0x7) << 18; 9818 val |= (cur[1] & 0x3f) << 12; 9819 val |= (cur[2] & 0x3f) << 6; 9820 val |= cur[3] & 0x3f; 9821 } else { 9822 /* 3-byte code */ 9823 *len = 3; 9824 val = (cur[0] & 0xf) << 12; 9825 val |= (cur[1] & 0x3f) << 6; 9826 val |= cur[2] & 0x3f; 9827 } 9828 } else { 9829 /* 2-byte code */ 9830 *len = 2; 9831 val = (cur[0] & 0x1f) << 6; 9832 val |= cur[1] & 0x3f; 9833 } 9834 if (!IS_CHAR(val)) { 9835 XP_ERROR0(XPATH_INVALID_CHAR_ERROR); 9836 } 9837 return(val); 9838 } else { 9839 /* 1-byte code */ 9840 *len = 1; 9841 return((int) *cur); 9842 } 9843 encoding_error: 9844 /* 9845 * If we detect an UTF8 error that probably means that the 9846 * input encoding didn't get properly advertised in the 9847 * declaration header. Report the error and switch the encoding 9848 * to ISO-Latin-1 (if you don't like this policy, just declare the 9849 * encoding !) 9850 */ 9851 *len = 0; 9852 XP_ERROR0(XPATH_ENCODING_ERROR); 9853 } 9854 9855 /** 9856 * xmlXPathParseNCName: 9857 * @ctxt: the XPath Parser context 9858 * 9859 * parse an XML namespace non qualified name. 9860 * 9861 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)* 9862 * 9863 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' | 9864 * CombiningChar | Extender 9865 * 9866 * Returns the namespace name or NULL 9867 */ 9868 9869 xmlChar * 9870 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) { 9871 const xmlChar *in; 9872 xmlChar *ret; 9873 int count = 0; 9874 9875 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL); 9876 /* 9877 * Accelerator for simple ASCII names 9878 */ 9879 in = ctxt->cur; 9880 if (((*in >= 0x61) && (*in <= 0x7A)) || 9881 ((*in >= 0x41) && (*in <= 0x5A)) || 9882 (*in == '_')) { 9883 in++; 9884 while (((*in >= 0x61) && (*in <= 0x7A)) || 9885 ((*in >= 0x41) && (*in <= 0x5A)) || 9886 ((*in >= 0x30) && (*in <= 0x39)) || 9887 (*in == '_') || (*in == '.') || 9888 (*in == '-')) 9889 in++; 9890 if ((*in == ' ') || (*in == '>') || (*in == '/') || 9891 (*in == '[') || (*in == ']') || (*in == ':') || 9892 (*in == '@') || (*in == '*')) { 9893 count = in - ctxt->cur; 9894 if (count == 0) 9895 return(NULL); 9896 ret = xmlStrndup(ctxt->cur, count); 9897 ctxt->cur = in; 9898 return(ret); 9899 } 9900 } 9901 return(xmlXPathParseNameComplex(ctxt, 0)); 9902 } 9903 9904 9905 /** 9906 * xmlXPathParseQName: 9907 * @ctxt: the XPath Parser context 9908 * @prefix: a xmlChar ** 9909 * 9910 * parse an XML qualified name 9911 * 9912 * [NS 5] QName ::= (Prefix ':')? LocalPart 9913 * 9914 * [NS 6] Prefix ::= NCName 9915 * 9916 * [NS 7] LocalPart ::= NCName 9917 * 9918 * Returns the function returns the local part, and prefix is updated 9919 * to get the Prefix if any. 9920 */ 9921 9922 static xmlChar * 9923 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) { 9924 xmlChar *ret = NULL; 9925 9926 *prefix = NULL; 9927 ret = xmlXPathParseNCName(ctxt); 9928 if (ret && CUR == ':') { 9929 *prefix = ret; 9930 NEXT; 9931 ret = xmlXPathParseNCName(ctxt); 9932 } 9933 return(ret); 9934 } 9935 9936 /** 9937 * xmlXPathParseName: 9938 * @ctxt: the XPath Parser context 9939 * 9940 * parse an XML name 9941 * 9942 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | 9943 * CombiningChar | Extender 9944 * 9945 * [5] Name ::= (Letter | '_' | ':') (NameChar)* 9946 * 9947 * Returns the namespace name or NULL 9948 */ 9949 9950 xmlChar * 9951 xmlXPathParseName(xmlXPathParserContextPtr ctxt) { 9952 const xmlChar *in; 9953 xmlChar *ret; 9954 size_t count = 0; 9955 9956 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL); 9957 /* 9958 * Accelerator for simple ASCII names 9959 */ 9960 in = ctxt->cur; 9961 if (((*in >= 0x61) && (*in <= 0x7A)) || 9962 ((*in >= 0x41) && (*in <= 0x5A)) || 9963 (*in == '_') || (*in == ':')) { 9964 in++; 9965 while (((*in >= 0x61) && (*in <= 0x7A)) || 9966 ((*in >= 0x41) && (*in <= 0x5A)) || 9967 ((*in >= 0x30) && (*in <= 0x39)) || 9968 (*in == '_') || (*in == '-') || 9969 (*in == ':') || (*in == '.')) 9970 in++; 9971 if ((*in > 0) && (*in < 0x80)) { 9972 count = in - ctxt->cur; 9973 if (count > XML_MAX_NAME_LENGTH) { 9974 ctxt->cur = in; 9975 XP_ERRORNULL(XPATH_EXPR_ERROR); 9976 } 9977 ret = xmlStrndup(ctxt->cur, count); 9978 ctxt->cur = in; 9979 return(ret); 9980 } 9981 } 9982 return(xmlXPathParseNameComplex(ctxt, 1)); 9983 } 9984 9985 static xmlChar * 9986 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) { 9987 xmlChar buf[XML_MAX_NAMELEN + 5]; 9988 int len = 0, l; 9989 int c; 9990 9991 /* 9992 * Handler for more complex cases 9993 */ 9994 c = CUR_CHAR(l); 9995 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */ 9996 (c == '[') || (c == ']') || (c == '@') || /* accelerators */ 9997 (c == '*') || /* accelerators */ 9998 (!IS_LETTER(c) && (c != '_') && 9999 ((!qualified) || (c != ':')))) { 10000 return(NULL); 10001 } 10002 10003 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */ 10004 ((IS_LETTER(c)) || (IS_DIGIT(c)) || 10005 (c == '.') || (c == '-') || 10006 (c == '_') || ((qualified) && (c == ':')) || 10007 (IS_COMBINING(c)) || 10008 (IS_EXTENDER(c)))) { 10009 COPY_BUF(l,buf,len,c); 10010 NEXTL(l); 10011 c = CUR_CHAR(l); 10012 if (len >= XML_MAX_NAMELEN) { 10013 /* 10014 * Okay someone managed to make a huge name, so he's ready to pay 10015 * for the processing speed. 10016 */ 10017 xmlChar *buffer; 10018 int max = len * 2; 10019 10020 if (len > XML_MAX_NAME_LENGTH) { 10021 XP_ERRORNULL(XPATH_EXPR_ERROR); 10022 } 10023 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar)); 10024 if (buffer == NULL) { 10025 XP_ERRORNULL(XPATH_MEMORY_ERROR); 10026 } 10027 memcpy(buffer, buf, len); 10028 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */ 10029 (c == '.') || (c == '-') || 10030 (c == '_') || ((qualified) && (c == ':')) || 10031 (IS_COMBINING(c)) || 10032 (IS_EXTENDER(c))) { 10033 if (len + 10 > max) { 10034 if (max > XML_MAX_NAME_LENGTH) { 10035 XP_ERRORNULL(XPATH_EXPR_ERROR); 10036 } 10037 max *= 2; 10038 buffer = (xmlChar *) xmlRealloc(buffer, 10039 max * sizeof(xmlChar)); 10040 if (buffer == NULL) { 10041 XP_ERRORNULL(XPATH_MEMORY_ERROR); 10042 } 10043 } 10044 COPY_BUF(l,buffer,len,c); 10045 NEXTL(l); 10046 c = CUR_CHAR(l); 10047 } 10048 buffer[len] = 0; 10049 return(buffer); 10050 } 10051 } 10052 if (len == 0) 10053 return(NULL); 10054 return(xmlStrndup(buf, len)); 10055 } 10056 10057 #define MAX_FRAC 20 10058 10059 /* 10060 * These are used as divisors for the fractional part of a number. 10061 * Since the table includes 1.0 (representing '0' fractional digits), 10062 * it must be dimensioned at MAX_FRAC+1 (bug 133921) 10063 */ 10064 static double my_pow10[MAX_FRAC+1] = { 10065 1.0, 10.0, 100.0, 1000.0, 10000.0, 10066 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0, 10067 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0, 10068 100000000000000.0, 10069 1000000000000000.0, 10000000000000000.0, 100000000000000000.0, 10070 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0 10071 }; 10072 10073 /** 10074 * xmlXPathStringEvalNumber: 10075 * @str: A string to scan 10076 * 10077 * [30a] Float ::= Number ('e' Digits?)? 10078 * 10079 * [30] Number ::= Digits ('.' Digits?)? 10080 * | '.' Digits 10081 * [31] Digits ::= [0-9]+ 10082 * 10083 * Compile a Number in the string 10084 * In complement of the Number expression, this function also handles 10085 * negative values : '-' Number. 10086 * 10087 * Returns the double value. 10088 */ 10089 double 10090 xmlXPathStringEvalNumber(const xmlChar *str) { 10091 const xmlChar *cur = str; 10092 double ret; 10093 int ok = 0; 10094 int isneg = 0; 10095 int exponent = 0; 10096 int is_exponent_negative = 0; 10097 #ifdef __GNUC__ 10098 unsigned long tmp = 0; 10099 double temp; 10100 #endif 10101 if (cur == NULL) return(0); 10102 while (IS_BLANK_CH(*cur)) cur++; 10103 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) { 10104 return(xmlXPathNAN); 10105 } 10106 if (*cur == '-') { 10107 isneg = 1; 10108 cur++; 10109 } 10110 10111 #ifdef __GNUC__ 10112 /* 10113 * tmp/temp is a workaround against a gcc compiler bug 10114 * http://veillard.com/gcc.bug 10115 */ 10116 ret = 0; 10117 while ((*cur >= '0') && (*cur <= '9')) { 10118 ret = ret * 10; 10119 tmp = (*cur - '0'); 10120 ok = 1; 10121 cur++; 10122 temp = (double) tmp; 10123 ret = ret + temp; 10124 } 10125 #else 10126 ret = 0; 10127 while ((*cur >= '0') && (*cur <= '9')) { 10128 ret = ret * 10 + (*cur - '0'); 10129 ok = 1; 10130 cur++; 10131 } 10132 #endif 10133 10134 if (*cur == '.') { 10135 int v, frac = 0; 10136 double fraction = 0; 10137 10138 cur++; 10139 if (((*cur < '0') || (*cur > '9')) && (!ok)) { 10140 return(xmlXPathNAN); 10141 } 10142 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) { 10143 v = (*cur - '0'); 10144 fraction = fraction * 10 + v; 10145 frac = frac + 1; 10146 cur++; 10147 } 10148 fraction /= my_pow10[frac]; 10149 ret = ret + fraction; 10150 while ((*cur >= '0') && (*cur <= '9')) 10151 cur++; 10152 } 10153 if ((*cur == 'e') || (*cur == 'E')) { 10154 cur++; 10155 if (*cur == '-') { 10156 is_exponent_negative = 1; 10157 cur++; 10158 } else if (*cur == '+') { 10159 cur++; 10160 } 10161 while ((*cur >= '0') && (*cur <= '9')) { 10162 exponent = exponent * 10 + (*cur - '0'); 10163 cur++; 10164 } 10165 } 10166 while (IS_BLANK_CH(*cur)) cur++; 10167 if (*cur != 0) return(xmlXPathNAN); 10168 if (isneg) ret = -ret; 10169 if (is_exponent_negative) exponent = -exponent; 10170 ret *= pow(10.0, (double)exponent); 10171 return(ret); 10172 } 10173 10174 /** 10175 * xmlXPathCompNumber: 10176 * @ctxt: the XPath Parser context 10177 * 10178 * [30] Number ::= Digits ('.' Digits?)? 10179 * | '.' Digits 10180 * [31] Digits ::= [0-9]+ 10181 * 10182 * Compile a Number, then push it on the stack 10183 * 10184 */ 10185 static void 10186 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt) 10187 { 10188 double ret = 0.0; 10189 int ok = 0; 10190 int exponent = 0; 10191 int is_exponent_negative = 0; 10192 #ifdef __GNUC__ 10193 unsigned long tmp = 0; 10194 double temp; 10195 #endif 10196 10197 CHECK_ERROR; 10198 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) { 10199 XP_ERROR(XPATH_NUMBER_ERROR); 10200 } 10201 #ifdef __GNUC__ 10202 /* 10203 * tmp/temp is a workaround against a gcc compiler bug 10204 * http://veillard.com/gcc.bug 10205 */ 10206 ret = 0; 10207 while ((CUR >= '0') && (CUR <= '9')) { 10208 ret = ret * 10; 10209 tmp = (CUR - '0'); 10210 ok = 1; 10211 NEXT; 10212 temp = (double) tmp; 10213 ret = ret + temp; 10214 } 10215 #else 10216 ret = 0; 10217 while ((CUR >= '0') && (CUR <= '9')) { 10218 ret = ret * 10 + (CUR - '0'); 10219 ok = 1; 10220 NEXT; 10221 } 10222 #endif 10223 if (CUR == '.') { 10224 int v, frac = 0; 10225 double fraction = 0; 10226 10227 NEXT; 10228 if (((CUR < '0') || (CUR > '9')) && (!ok)) { 10229 XP_ERROR(XPATH_NUMBER_ERROR); 10230 } 10231 while ((CUR >= '0') && (CUR <= '9') && (frac < MAX_FRAC)) { 10232 v = (CUR - '0'); 10233 fraction = fraction * 10 + v; 10234 frac = frac + 1; 10235 NEXT; 10236 } 10237 fraction /= my_pow10[frac]; 10238 ret = ret + fraction; 10239 while ((CUR >= '0') && (CUR <= '9')) 10240 NEXT; 10241 } 10242 if ((CUR == 'e') || (CUR == 'E')) { 10243 NEXT; 10244 if (CUR == '-') { 10245 is_exponent_negative = 1; 10246 NEXT; 10247 } else if (CUR == '+') { 10248 NEXT; 10249 } 10250 while ((CUR >= '0') && (CUR <= '9')) { 10251 exponent = exponent * 10 + (CUR - '0'); 10252 NEXT; 10253 } 10254 if (is_exponent_negative) 10255 exponent = -exponent; 10256 ret *= pow(10.0, (double) exponent); 10257 } 10258 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, 10259 xmlXPathCacheNewFloat(ctxt->context, ret), NULL); 10260 } 10261 10262 /** 10263 * xmlXPathParseLiteral: 10264 * @ctxt: the XPath Parser context 10265 * 10266 * Parse a Literal 10267 * 10268 * [29] Literal ::= '"' [^"]* '"' 10269 * | "'" [^']* "'" 10270 * 10271 * Returns the value found or NULL in case of error 10272 */ 10273 static xmlChar * 10274 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) { 10275 const xmlChar *q; 10276 xmlChar *ret = NULL; 10277 10278 if (CUR == '"') { 10279 NEXT; 10280 q = CUR_PTR; 10281 while ((IS_CHAR_CH(CUR)) && (CUR != '"')) 10282 NEXT; 10283 if (!IS_CHAR_CH(CUR)) { 10284 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR); 10285 } else { 10286 ret = xmlStrndup(q, CUR_PTR - q); 10287 NEXT; 10288 } 10289 } else if (CUR == '\'') { 10290 NEXT; 10291 q = CUR_PTR; 10292 while ((IS_CHAR_CH(CUR)) && (CUR != '\'')) 10293 NEXT; 10294 if (!IS_CHAR_CH(CUR)) { 10295 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR); 10296 } else { 10297 ret = xmlStrndup(q, CUR_PTR - q); 10298 NEXT; 10299 } 10300 } else { 10301 XP_ERRORNULL(XPATH_START_LITERAL_ERROR); 10302 } 10303 return(ret); 10304 } 10305 10306 /** 10307 * xmlXPathCompLiteral: 10308 * @ctxt: the XPath Parser context 10309 * 10310 * Parse a Literal and push it on the stack. 10311 * 10312 * [29] Literal ::= '"' [^"]* '"' 10313 * | "'" [^']* "'" 10314 * 10315 * TODO: xmlXPathCompLiteral memory allocation could be improved. 10316 */ 10317 static void 10318 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) { 10319 const xmlChar *q; 10320 xmlChar *ret = NULL; 10321 10322 if (CUR == '"') { 10323 NEXT; 10324 q = CUR_PTR; 10325 while ((IS_CHAR_CH(CUR)) && (CUR != '"')) 10326 NEXT; 10327 if (!IS_CHAR_CH(CUR)) { 10328 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR); 10329 } else { 10330 ret = xmlStrndup(q, CUR_PTR - q); 10331 NEXT; 10332 } 10333 } else if (CUR == '\'') { 10334 NEXT; 10335 q = CUR_PTR; 10336 while ((IS_CHAR_CH(CUR)) && (CUR != '\'')) 10337 NEXT; 10338 if (!IS_CHAR_CH(CUR)) { 10339 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR); 10340 } else { 10341 ret = xmlStrndup(q, CUR_PTR - q); 10342 NEXT; 10343 } 10344 } else { 10345 XP_ERROR(XPATH_START_LITERAL_ERROR); 10346 } 10347 if (ret == NULL) return; 10348 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, 10349 xmlXPathCacheNewString(ctxt->context, ret), NULL); 10350 xmlFree(ret); 10351 } 10352 10353 /** 10354 * xmlXPathCompVariableReference: 10355 * @ctxt: the XPath Parser context 10356 * 10357 * Parse a VariableReference, evaluate it and push it on the stack. 10358 * 10359 * The variable bindings consist of a mapping from variable names 10360 * to variable values. The value of a variable is an object, which can be 10361 * of any of the types that are possible for the value of an expression, 10362 * and may also be of additional types not specified here. 10363 * 10364 * Early evaluation is possible since: 10365 * The variable bindings [...] used to evaluate a subexpression are 10366 * always the same as those used to evaluate the containing expression. 10367 * 10368 * [36] VariableReference ::= '$' QName 10369 */ 10370 static void 10371 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) { 10372 xmlChar *name; 10373 xmlChar *prefix; 10374 10375 SKIP_BLANKS; 10376 if (CUR != '$') { 10377 XP_ERROR(XPATH_VARIABLE_REF_ERROR); 10378 } 10379 NEXT; 10380 name = xmlXPathParseQName(ctxt, &prefix); 10381 if (name == NULL) { 10382 XP_ERROR(XPATH_VARIABLE_REF_ERROR); 10383 } 10384 ctxt->comp->last = -1; 10385 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, 10386 name, prefix); 10387 SKIP_BLANKS; 10388 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) { 10389 XP_ERROR(XPATH_FORBID_VARIABLE_ERROR); 10390 } 10391 } 10392 10393 /** 10394 * xmlXPathIsNodeType: 10395 * @name: a name string 10396 * 10397 * Is the name given a NodeType one. 10398 * 10399 * [38] NodeType ::= 'comment' 10400 * | 'text' 10401 * | 'processing-instruction' 10402 * | 'node' 10403 * 10404 * Returns 1 if true 0 otherwise 10405 */ 10406 int 10407 xmlXPathIsNodeType(const xmlChar *name) { 10408 if (name == NULL) 10409 return(0); 10410 10411 if (xmlStrEqual(name, BAD_CAST "node")) 10412 return(1); 10413 if (xmlStrEqual(name, BAD_CAST "text")) 10414 return(1); 10415 if (xmlStrEqual(name, BAD_CAST "comment")) 10416 return(1); 10417 if (xmlStrEqual(name, BAD_CAST "processing-instruction")) 10418 return(1); 10419 return(0); 10420 } 10421 10422 /** 10423 * xmlXPathCompFunctionCall: 10424 * @ctxt: the XPath Parser context 10425 * 10426 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')' 10427 * [17] Argument ::= Expr 10428 * 10429 * Compile a function call, the evaluation of all arguments are 10430 * pushed on the stack 10431 */ 10432 static void 10433 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) { 10434 xmlChar *name; 10435 xmlChar *prefix; 10436 int nbargs = 0; 10437 int sort = 1; 10438 10439 name = xmlXPathParseQName(ctxt, &prefix); 10440 if (name == NULL) { 10441 xmlFree(prefix); 10442 XP_ERROR(XPATH_EXPR_ERROR); 10443 } 10444 SKIP_BLANKS; 10445 #ifdef DEBUG_EXPR 10446 if (prefix == NULL) 10447 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n", 10448 name); 10449 else 10450 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n", 10451 prefix, name); 10452 #endif 10453 10454 if (CUR != '(') { 10455 XP_ERROR(XPATH_EXPR_ERROR); 10456 } 10457 NEXT; 10458 SKIP_BLANKS; 10459 10460 /* 10461 * Optimization for count(): we don't need the node-set to be sorted. 10462 */ 10463 if ((prefix == NULL) && (name[0] == 'c') && 10464 xmlStrEqual(name, BAD_CAST "count")) 10465 { 10466 sort = 0; 10467 } 10468 ctxt->comp->last = -1; 10469 if (CUR != ')') { 10470 while (CUR != 0) { 10471 int op1 = ctxt->comp->last; 10472 ctxt->comp->last = -1; 10473 xmlXPathCompileExpr(ctxt, sort); 10474 if (ctxt->error != XPATH_EXPRESSION_OK) { 10475 xmlFree(name); 10476 xmlFree(prefix); 10477 return; 10478 } 10479 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0); 10480 nbargs++; 10481 if (CUR == ')') break; 10482 if (CUR != ',') { 10483 XP_ERROR(XPATH_EXPR_ERROR); 10484 } 10485 NEXT; 10486 SKIP_BLANKS; 10487 } 10488 } 10489 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, 10490 name, prefix); 10491 NEXT; 10492 SKIP_BLANKS; 10493 } 10494 10495 /** 10496 * xmlXPathCompPrimaryExpr: 10497 * @ctxt: the XPath Parser context 10498 * 10499 * [15] PrimaryExpr ::= VariableReference 10500 * | '(' Expr ')' 10501 * | Literal 10502 * | Number 10503 * | FunctionCall 10504 * 10505 * Compile a primary expression. 10506 */ 10507 static void 10508 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) { 10509 SKIP_BLANKS; 10510 if (CUR == '$') xmlXPathCompVariableReference(ctxt); 10511 else if (CUR == '(') { 10512 NEXT; 10513 SKIP_BLANKS; 10514 xmlXPathCompileExpr(ctxt, 1); 10515 CHECK_ERROR; 10516 if (CUR != ')') { 10517 XP_ERROR(XPATH_EXPR_ERROR); 10518 } 10519 NEXT; 10520 SKIP_BLANKS; 10521 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) { 10522 xmlXPathCompNumber(ctxt); 10523 } else if ((CUR == '\'') || (CUR == '"')) { 10524 xmlXPathCompLiteral(ctxt); 10525 } else { 10526 xmlXPathCompFunctionCall(ctxt); 10527 } 10528 SKIP_BLANKS; 10529 } 10530 10531 /** 10532 * xmlXPathCompFilterExpr: 10533 * @ctxt: the XPath Parser context 10534 * 10535 * [20] FilterExpr ::= PrimaryExpr 10536 * | FilterExpr Predicate 10537 * 10538 * Compile a filter expression. 10539 * Square brackets are used to filter expressions in the same way that 10540 * they are used in location paths. It is an error if the expression to 10541 * be filtered does not evaluate to a node-set. The context node list 10542 * used for evaluating the expression in square brackets is the node-set 10543 * to be filtered listed in document order. 10544 */ 10545 10546 static void 10547 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) { 10548 xmlXPathCompPrimaryExpr(ctxt); 10549 CHECK_ERROR; 10550 SKIP_BLANKS; 10551 10552 while (CUR == '[') { 10553 xmlXPathCompPredicate(ctxt, 1); 10554 SKIP_BLANKS; 10555 } 10556 10557 10558 } 10559 10560 /** 10561 * xmlXPathScanName: 10562 * @ctxt: the XPath Parser context 10563 * 10564 * Trickery: parse an XML name but without consuming the input flow 10565 * Needed to avoid insanity in the parser state. 10566 * 10567 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | 10568 * CombiningChar | Extender 10569 * 10570 * [5] Name ::= (Letter | '_' | ':') (NameChar)* 10571 * 10572 * [6] Names ::= Name (S Name)* 10573 * 10574 * Returns the Name parsed or NULL 10575 */ 10576 10577 static xmlChar * 10578 xmlXPathScanName(xmlXPathParserContextPtr ctxt) { 10579 int len = 0, l; 10580 int c; 10581 const xmlChar *cur; 10582 xmlChar *ret; 10583 10584 cur = ctxt->cur; 10585 10586 c = CUR_CHAR(l); 10587 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */ 10588 (!IS_LETTER(c) && (c != '_') && 10589 (c != ':'))) { 10590 return(NULL); 10591 } 10592 10593 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */ 10594 ((IS_LETTER(c)) || (IS_DIGIT(c)) || 10595 (c == '.') || (c == '-') || 10596 (c == '_') || (c == ':') || 10597 (IS_COMBINING(c)) || 10598 (IS_EXTENDER(c)))) { 10599 len += l; 10600 NEXTL(l); 10601 c = CUR_CHAR(l); 10602 } 10603 ret = xmlStrndup(cur, ctxt->cur - cur); 10604 ctxt->cur = cur; 10605 return(ret); 10606 } 10607 10608 /** 10609 * xmlXPathCompPathExpr: 10610 * @ctxt: the XPath Parser context 10611 * 10612 * [19] PathExpr ::= LocationPath 10613 * | FilterExpr 10614 * | FilterExpr '/' RelativeLocationPath 10615 * | FilterExpr '//' RelativeLocationPath 10616 * 10617 * Compile a path expression. 10618 * The / operator and // operators combine an arbitrary expression 10619 * and a relative location path. It is an error if the expression 10620 * does not evaluate to a node-set. 10621 * The / operator does composition in the same way as when / is 10622 * used in a location path. As in location paths, // is short for 10623 * /descendant-or-self::node()/. 10624 */ 10625 10626 static void 10627 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) { 10628 int lc = 1; /* Should we branch to LocationPath ? */ 10629 xmlChar *name = NULL; /* we may have to preparse a name to find out */ 10630 10631 SKIP_BLANKS; 10632 if ((CUR == '$') || (CUR == '(') || 10633 (IS_ASCII_DIGIT(CUR)) || 10634 (CUR == '\'') || (CUR == '"') || 10635 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) { 10636 lc = 0; 10637 } else if (CUR == '*') { 10638 /* relative or absolute location path */ 10639 lc = 1; 10640 } else if (CUR == '/') { 10641 /* relative or absolute location path */ 10642 lc = 1; 10643 } else if (CUR == '@') { 10644 /* relative abbreviated attribute location path */ 10645 lc = 1; 10646 } else if (CUR == '.') { 10647 /* relative abbreviated attribute location path */ 10648 lc = 1; 10649 } else { 10650 /* 10651 * Problem is finding if we have a name here whether it's: 10652 * - a nodetype 10653 * - a function call in which case it's followed by '(' 10654 * - an axis in which case it's followed by ':' 10655 * - a element name 10656 * We do an a priori analysis here rather than having to 10657 * maintain parsed token content through the recursive function 10658 * calls. This looks uglier but makes the code easier to 10659 * read/write/debug. 10660 */ 10661 SKIP_BLANKS; 10662 name = xmlXPathScanName(ctxt); 10663 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) { 10664 #ifdef DEBUG_STEP 10665 xmlGenericError(xmlGenericErrorContext, 10666 "PathExpr: Axis\n"); 10667 #endif 10668 lc = 1; 10669 xmlFree(name); 10670 } else if (name != NULL) { 10671 int len =xmlStrlen(name); 10672 10673 10674 while (NXT(len) != 0) { 10675 if (NXT(len) == '/') { 10676 /* element name */ 10677 #ifdef DEBUG_STEP 10678 xmlGenericError(xmlGenericErrorContext, 10679 "PathExpr: AbbrRelLocation\n"); 10680 #endif 10681 lc = 1; 10682 break; 10683 } else if (IS_BLANK_CH(NXT(len))) { 10684 /* ignore blanks */ 10685 ; 10686 } else if (NXT(len) == ':') { 10687 #ifdef DEBUG_STEP 10688 xmlGenericError(xmlGenericErrorContext, 10689 "PathExpr: AbbrRelLocation\n"); 10690 #endif 10691 lc = 1; 10692 break; 10693 } else if ((NXT(len) == '(')) { 10694 /* Node Type or Function */ 10695 if (xmlXPathIsNodeType(name)) { 10696 #ifdef DEBUG_STEP 10697 xmlGenericError(xmlGenericErrorContext, 10698 "PathExpr: Type search\n"); 10699 #endif 10700 lc = 1; 10701 #ifdef LIBXML_XPTR_ENABLED 10702 } else if (ctxt->xptr && 10703 xmlStrEqual(name, BAD_CAST "range-to")) { 10704 lc = 1; 10705 #endif 10706 } else { 10707 #ifdef DEBUG_STEP 10708 xmlGenericError(xmlGenericErrorContext, 10709 "PathExpr: function call\n"); 10710 #endif 10711 lc = 0; 10712 } 10713 break; 10714 } else if ((NXT(len) == '[')) { 10715 /* element name */ 10716 #ifdef DEBUG_STEP 10717 xmlGenericError(xmlGenericErrorContext, 10718 "PathExpr: AbbrRelLocation\n"); 10719 #endif 10720 lc = 1; 10721 break; 10722 } else if ((NXT(len) == '<') || (NXT(len) == '>') || 10723 (NXT(len) == '=')) { 10724 lc = 1; 10725 break; 10726 } else { 10727 lc = 1; 10728 break; 10729 } 10730 len++; 10731 } 10732 if (NXT(len) == 0) { 10733 #ifdef DEBUG_STEP 10734 xmlGenericError(xmlGenericErrorContext, 10735 "PathExpr: AbbrRelLocation\n"); 10736 #endif 10737 /* element name */ 10738 lc = 1; 10739 } 10740 xmlFree(name); 10741 } else { 10742 /* make sure all cases are covered explicitly */ 10743 XP_ERROR(XPATH_EXPR_ERROR); 10744 } 10745 } 10746 10747 if (lc) { 10748 if (CUR == '/') { 10749 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0); 10750 } else { 10751 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0); 10752 } 10753 xmlXPathCompLocationPath(ctxt); 10754 } else { 10755 xmlXPathCompFilterExpr(ctxt); 10756 CHECK_ERROR; 10757 if ((CUR == '/') && (NXT(1) == '/')) { 10758 SKIP(2); 10759 SKIP_BLANKS; 10760 10761 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 10762 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 10763 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0); 10764 10765 xmlXPathCompRelativeLocationPath(ctxt); 10766 } else if (CUR == '/') { 10767 xmlXPathCompRelativeLocationPath(ctxt); 10768 } 10769 } 10770 SKIP_BLANKS; 10771 } 10772 10773 /** 10774 * xmlXPathCompUnionExpr: 10775 * @ctxt: the XPath Parser context 10776 * 10777 * [18] UnionExpr ::= PathExpr 10778 * | UnionExpr '|' PathExpr 10779 * 10780 * Compile an union expression. 10781 */ 10782 10783 static void 10784 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) { 10785 xmlXPathCompPathExpr(ctxt); 10786 CHECK_ERROR; 10787 SKIP_BLANKS; 10788 while (CUR == '|') { 10789 int op1 = ctxt->comp->last; 10790 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0); 10791 10792 NEXT; 10793 SKIP_BLANKS; 10794 xmlXPathCompPathExpr(ctxt); 10795 10796 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0); 10797 10798 SKIP_BLANKS; 10799 } 10800 } 10801 10802 /** 10803 * xmlXPathCompUnaryExpr: 10804 * @ctxt: the XPath Parser context 10805 * 10806 * [27] UnaryExpr ::= UnionExpr 10807 * | '-' UnaryExpr 10808 * 10809 * Compile an unary expression. 10810 */ 10811 10812 static void 10813 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) { 10814 int minus = 0; 10815 int found = 0; 10816 10817 SKIP_BLANKS; 10818 while (CUR == '-') { 10819 minus = 1 - minus; 10820 found = 1; 10821 NEXT; 10822 SKIP_BLANKS; 10823 } 10824 10825 xmlXPathCompUnionExpr(ctxt); 10826 CHECK_ERROR; 10827 if (found) { 10828 if (minus) 10829 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0); 10830 else 10831 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0); 10832 } 10833 } 10834 10835 /** 10836 * xmlXPathCompMultiplicativeExpr: 10837 * @ctxt: the XPath Parser context 10838 * 10839 * [26] MultiplicativeExpr ::= UnaryExpr 10840 * | MultiplicativeExpr MultiplyOperator UnaryExpr 10841 * | MultiplicativeExpr 'div' UnaryExpr 10842 * | MultiplicativeExpr 'mod' UnaryExpr 10843 * [34] MultiplyOperator ::= '*' 10844 * 10845 * Compile an Additive expression. 10846 */ 10847 10848 static void 10849 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) { 10850 xmlXPathCompUnaryExpr(ctxt); 10851 CHECK_ERROR; 10852 SKIP_BLANKS; 10853 while ((CUR == '*') || 10854 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) || 10855 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) { 10856 int op = -1; 10857 int op1 = ctxt->comp->last; 10858 10859 if (CUR == '*') { 10860 op = 0; 10861 NEXT; 10862 } else if (CUR == 'd') { 10863 op = 1; 10864 SKIP(3); 10865 } else if (CUR == 'm') { 10866 op = 2; 10867 SKIP(3); 10868 } 10869 SKIP_BLANKS; 10870 xmlXPathCompUnaryExpr(ctxt); 10871 CHECK_ERROR; 10872 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0); 10873 SKIP_BLANKS; 10874 } 10875 } 10876 10877 /** 10878 * xmlXPathCompAdditiveExpr: 10879 * @ctxt: the XPath Parser context 10880 * 10881 * [25] AdditiveExpr ::= MultiplicativeExpr 10882 * | AdditiveExpr '+' MultiplicativeExpr 10883 * | AdditiveExpr '-' MultiplicativeExpr 10884 * 10885 * Compile an Additive expression. 10886 */ 10887 10888 static void 10889 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) { 10890 10891 xmlXPathCompMultiplicativeExpr(ctxt); 10892 CHECK_ERROR; 10893 SKIP_BLANKS; 10894 while ((CUR == '+') || (CUR == '-')) { 10895 int plus; 10896 int op1 = ctxt->comp->last; 10897 10898 if (CUR == '+') plus = 1; 10899 else plus = 0; 10900 NEXT; 10901 SKIP_BLANKS; 10902 xmlXPathCompMultiplicativeExpr(ctxt); 10903 CHECK_ERROR; 10904 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0); 10905 SKIP_BLANKS; 10906 } 10907 } 10908 10909 /** 10910 * xmlXPathCompRelationalExpr: 10911 * @ctxt: the XPath Parser context 10912 * 10913 * [24] RelationalExpr ::= AdditiveExpr 10914 * | RelationalExpr '<' AdditiveExpr 10915 * | RelationalExpr '>' AdditiveExpr 10916 * | RelationalExpr '<=' AdditiveExpr 10917 * | RelationalExpr '>=' AdditiveExpr 10918 * 10919 * A <= B > C is allowed ? Answer from James, yes with 10920 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr 10921 * which is basically what got implemented. 10922 * 10923 * Compile a Relational expression, then push the result 10924 * on the stack 10925 */ 10926 10927 static void 10928 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) { 10929 xmlXPathCompAdditiveExpr(ctxt); 10930 CHECK_ERROR; 10931 SKIP_BLANKS; 10932 while ((CUR == '<') || 10933 (CUR == '>') || 10934 ((CUR == '<') && (NXT(1) == '=')) || 10935 ((CUR == '>') && (NXT(1) == '='))) { 10936 int inf, strict; 10937 int op1 = ctxt->comp->last; 10938 10939 if (CUR == '<') inf = 1; 10940 else inf = 0; 10941 if (NXT(1) == '=') strict = 0; 10942 else strict = 1; 10943 NEXT; 10944 if (!strict) NEXT; 10945 SKIP_BLANKS; 10946 xmlXPathCompAdditiveExpr(ctxt); 10947 CHECK_ERROR; 10948 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict); 10949 SKIP_BLANKS; 10950 } 10951 } 10952 10953 /** 10954 * xmlXPathCompEqualityExpr: 10955 * @ctxt: the XPath Parser context 10956 * 10957 * [23] EqualityExpr ::= RelationalExpr 10958 * | EqualityExpr '=' RelationalExpr 10959 * | EqualityExpr '!=' RelationalExpr 10960 * 10961 * A != B != C is allowed ? Answer from James, yes with 10962 * (RelationalExpr = RelationalExpr) = RelationalExpr 10963 * (RelationalExpr != RelationalExpr) != RelationalExpr 10964 * which is basically what got implemented. 10965 * 10966 * Compile an Equality expression. 10967 * 10968 */ 10969 static void 10970 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) { 10971 xmlXPathCompRelationalExpr(ctxt); 10972 CHECK_ERROR; 10973 SKIP_BLANKS; 10974 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) { 10975 int eq; 10976 int op1 = ctxt->comp->last; 10977 10978 if (CUR == '=') eq = 1; 10979 else eq = 0; 10980 NEXT; 10981 if (!eq) NEXT; 10982 SKIP_BLANKS; 10983 xmlXPathCompRelationalExpr(ctxt); 10984 CHECK_ERROR; 10985 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0); 10986 SKIP_BLANKS; 10987 } 10988 } 10989 10990 /** 10991 * xmlXPathCompAndExpr: 10992 * @ctxt: the XPath Parser context 10993 * 10994 * [22] AndExpr ::= EqualityExpr 10995 * | AndExpr 'and' EqualityExpr 10996 * 10997 * Compile an AND expression. 10998 * 10999 */ 11000 static void 11001 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) { 11002 xmlXPathCompEqualityExpr(ctxt); 11003 CHECK_ERROR; 11004 SKIP_BLANKS; 11005 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) { 11006 int op1 = ctxt->comp->last; 11007 SKIP(3); 11008 SKIP_BLANKS; 11009 xmlXPathCompEqualityExpr(ctxt); 11010 CHECK_ERROR; 11011 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0); 11012 SKIP_BLANKS; 11013 } 11014 } 11015 11016 /** 11017 * xmlXPathCompileExpr: 11018 * @ctxt: the XPath Parser context 11019 * 11020 * [14] Expr ::= OrExpr 11021 * [21] OrExpr ::= AndExpr 11022 * | OrExpr 'or' AndExpr 11023 * 11024 * Parse and compile an expression 11025 */ 11026 static void 11027 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) { 11028 xmlXPathCompAndExpr(ctxt); 11029 CHECK_ERROR; 11030 SKIP_BLANKS; 11031 while ((CUR == 'o') && (NXT(1) == 'r')) { 11032 int op1 = ctxt->comp->last; 11033 SKIP(2); 11034 SKIP_BLANKS; 11035 xmlXPathCompAndExpr(ctxt); 11036 CHECK_ERROR; 11037 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0); 11038 SKIP_BLANKS; 11039 } 11040 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) { 11041 /* more ops could be optimized too */ 11042 /* 11043 * This is the main place to eliminate sorting for 11044 * operations which don't require a sorted node-set. 11045 * E.g. count(). 11046 */ 11047 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0); 11048 } 11049 } 11050 11051 /** 11052 * xmlXPathCompPredicate: 11053 * @ctxt: the XPath Parser context 11054 * @filter: act as a filter 11055 * 11056 * [8] Predicate ::= '[' PredicateExpr ']' 11057 * [9] PredicateExpr ::= Expr 11058 * 11059 * Compile a predicate expression 11060 */ 11061 static void 11062 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) { 11063 int op1 = ctxt->comp->last; 11064 11065 SKIP_BLANKS; 11066 if (CUR != '[') { 11067 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); 11068 } 11069 NEXT; 11070 SKIP_BLANKS; 11071 11072 ctxt->comp->last = -1; 11073 /* 11074 * This call to xmlXPathCompileExpr() will deactivate sorting 11075 * of the predicate result. 11076 * TODO: Sorting is still activated for filters, since I'm not 11077 * sure if needed. Normally sorting should not be needed, since 11078 * a filter can only diminish the number of items in a sequence, 11079 * but won't change its order; so if the initial sequence is sorted, 11080 * subsequent sorting is not needed. 11081 */ 11082 if (! filter) 11083 xmlXPathCompileExpr(ctxt, 0); 11084 else 11085 xmlXPathCompileExpr(ctxt, 1); 11086 CHECK_ERROR; 11087 11088 if (CUR != ']') { 11089 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); 11090 } 11091 11092 if (filter) 11093 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0); 11094 else 11095 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0); 11096 11097 NEXT; 11098 SKIP_BLANKS; 11099 } 11100 11101 /** 11102 * xmlXPathCompNodeTest: 11103 * @ctxt: the XPath Parser context 11104 * @test: pointer to a xmlXPathTestVal 11105 * @type: pointer to a xmlXPathTypeVal 11106 * @prefix: placeholder for a possible name prefix 11107 * 11108 * [7] NodeTest ::= NameTest 11109 * | NodeType '(' ')' 11110 * | 'processing-instruction' '(' Literal ')' 11111 * 11112 * [37] NameTest ::= '*' 11113 * | NCName ':' '*' 11114 * | QName 11115 * [38] NodeType ::= 'comment' 11116 * | 'text' 11117 * | 'processing-instruction' 11118 * | 'node' 11119 * 11120 * Returns the name found and updates @test, @type and @prefix appropriately 11121 */ 11122 static xmlChar * 11123 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test, 11124 xmlXPathTypeVal *type, const xmlChar **prefix, 11125 xmlChar *name) { 11126 int blanks; 11127 11128 if ((test == NULL) || (type == NULL) || (prefix == NULL)) { 11129 STRANGE; 11130 return(NULL); 11131 } 11132 *type = (xmlXPathTypeVal) 0; 11133 *test = (xmlXPathTestVal) 0; 11134 *prefix = NULL; 11135 SKIP_BLANKS; 11136 11137 if ((name == NULL) && (CUR == '*')) { 11138 /* 11139 * All elements 11140 */ 11141 NEXT; 11142 *test = NODE_TEST_ALL; 11143 return(NULL); 11144 } 11145 11146 if (name == NULL) 11147 name = xmlXPathParseNCName(ctxt); 11148 if (name == NULL) { 11149 XP_ERRORNULL(XPATH_EXPR_ERROR); 11150 } 11151 11152 blanks = IS_BLANK_CH(CUR); 11153 SKIP_BLANKS; 11154 if (CUR == '(') { 11155 NEXT; 11156 /* 11157 * NodeType or PI search 11158 */ 11159 if (xmlStrEqual(name, BAD_CAST "comment")) 11160 *type = NODE_TYPE_COMMENT; 11161 else if (xmlStrEqual(name, BAD_CAST "node")) 11162 *type = NODE_TYPE_NODE; 11163 else if (xmlStrEqual(name, BAD_CAST "processing-instruction")) 11164 *type = NODE_TYPE_PI; 11165 else if (xmlStrEqual(name, BAD_CAST "text")) 11166 *type = NODE_TYPE_TEXT; 11167 else { 11168 if (name != NULL) 11169 xmlFree(name); 11170 XP_ERRORNULL(XPATH_EXPR_ERROR); 11171 } 11172 11173 *test = NODE_TEST_TYPE; 11174 11175 SKIP_BLANKS; 11176 if (*type == NODE_TYPE_PI) { 11177 /* 11178 * Specific case: search a PI by name. 11179 */ 11180 if (name != NULL) 11181 xmlFree(name); 11182 name = NULL; 11183 if (CUR != ')') { 11184 name = xmlXPathParseLiteral(ctxt); 11185 CHECK_ERROR NULL; 11186 *test = NODE_TEST_PI; 11187 SKIP_BLANKS; 11188 } 11189 } 11190 if (CUR != ')') { 11191 if (name != NULL) 11192 xmlFree(name); 11193 XP_ERRORNULL(XPATH_UNCLOSED_ERROR); 11194 } 11195 NEXT; 11196 return(name); 11197 } 11198 *test = NODE_TEST_NAME; 11199 if ((!blanks) && (CUR == ':')) { 11200 NEXT; 11201 11202 /* 11203 * Since currently the parser context don't have a 11204 * namespace list associated: 11205 * The namespace name for this prefix can be computed 11206 * only at evaluation time. The compilation is done 11207 * outside of any context. 11208 */ 11209 #if 0 11210 *prefix = xmlXPathNsLookup(ctxt->context, name); 11211 if (name != NULL) 11212 xmlFree(name); 11213 if (*prefix == NULL) { 11214 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); 11215 } 11216 #else 11217 *prefix = name; 11218 #endif 11219 11220 if (CUR == '*') { 11221 /* 11222 * All elements 11223 */ 11224 NEXT; 11225 *test = NODE_TEST_ALL; 11226 return(NULL); 11227 } 11228 11229 name = xmlXPathParseNCName(ctxt); 11230 if (name == NULL) { 11231 XP_ERRORNULL(XPATH_EXPR_ERROR); 11232 } 11233 } 11234 return(name); 11235 } 11236 11237 /** 11238 * xmlXPathIsAxisName: 11239 * @name: a preparsed name token 11240 * 11241 * [6] AxisName ::= 'ancestor' 11242 * | 'ancestor-or-self' 11243 * | 'attribute' 11244 * | 'child' 11245 * | 'descendant' 11246 * | 'descendant-or-self' 11247 * | 'following' 11248 * | 'following-sibling' 11249 * | 'namespace' 11250 * | 'parent' 11251 * | 'preceding' 11252 * | 'preceding-sibling' 11253 * | 'self' 11254 * 11255 * Returns the axis or 0 11256 */ 11257 static xmlXPathAxisVal 11258 xmlXPathIsAxisName(const xmlChar *name) { 11259 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0; 11260 switch (name[0]) { 11261 case 'a': 11262 if (xmlStrEqual(name, BAD_CAST "ancestor")) 11263 ret = AXIS_ANCESTOR; 11264 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self")) 11265 ret = AXIS_ANCESTOR_OR_SELF; 11266 if (xmlStrEqual(name, BAD_CAST "attribute")) 11267 ret = AXIS_ATTRIBUTE; 11268 break; 11269 case 'c': 11270 if (xmlStrEqual(name, BAD_CAST "child")) 11271 ret = AXIS_CHILD; 11272 break; 11273 case 'd': 11274 if (xmlStrEqual(name, BAD_CAST "descendant")) 11275 ret = AXIS_DESCENDANT; 11276 if (xmlStrEqual(name, BAD_CAST "descendant-or-self")) 11277 ret = AXIS_DESCENDANT_OR_SELF; 11278 break; 11279 case 'f': 11280 if (xmlStrEqual(name, BAD_CAST "following")) 11281 ret = AXIS_FOLLOWING; 11282 if (xmlStrEqual(name, BAD_CAST "following-sibling")) 11283 ret = AXIS_FOLLOWING_SIBLING; 11284 break; 11285 case 'n': 11286 if (xmlStrEqual(name, BAD_CAST "namespace")) 11287 ret = AXIS_NAMESPACE; 11288 break; 11289 case 'p': 11290 if (xmlStrEqual(name, BAD_CAST "parent")) 11291 ret = AXIS_PARENT; 11292 if (xmlStrEqual(name, BAD_CAST "preceding")) 11293 ret = AXIS_PRECEDING; 11294 if (xmlStrEqual(name, BAD_CAST "preceding-sibling")) 11295 ret = AXIS_PRECEDING_SIBLING; 11296 break; 11297 case 's': 11298 if (xmlStrEqual(name, BAD_CAST "self")) 11299 ret = AXIS_SELF; 11300 break; 11301 } 11302 return(ret); 11303 } 11304 11305 /** 11306 * xmlXPathCompStep: 11307 * @ctxt: the XPath Parser context 11308 * 11309 * [4] Step ::= AxisSpecifier NodeTest Predicate* 11310 * | AbbreviatedStep 11311 * 11312 * [12] AbbreviatedStep ::= '.' | '..' 11313 * 11314 * [5] AxisSpecifier ::= AxisName '::' 11315 * | AbbreviatedAxisSpecifier 11316 * 11317 * [13] AbbreviatedAxisSpecifier ::= '@'? 11318 * 11319 * Modified for XPtr range support as: 11320 * 11321 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate* 11322 * | AbbreviatedStep 11323 * | 'range-to' '(' Expr ')' Predicate* 11324 * 11325 * Compile one step in a Location Path 11326 * A location step of . is short for self::node(). This is 11327 * particularly useful in conjunction with //. For example, the 11328 * location path .//para is short for 11329 * self::node()/descendant-or-self::node()/child::para 11330 * and so will select all para descendant elements of the context 11331 * node. 11332 * Similarly, a location step of .. is short for parent::node(). 11333 * For example, ../title is short for parent::node()/child::title 11334 * and so will select the title children of the parent of the context 11335 * node. 11336 */ 11337 static void 11338 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) { 11339 #ifdef LIBXML_XPTR_ENABLED 11340 int rangeto = 0; 11341 int op2 = -1; 11342 #endif 11343 11344 SKIP_BLANKS; 11345 if ((CUR == '.') && (NXT(1) == '.')) { 11346 SKIP(2); 11347 SKIP_BLANKS; 11348 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT, 11349 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11350 } else if (CUR == '.') { 11351 NEXT; 11352 SKIP_BLANKS; 11353 } else { 11354 xmlChar *name = NULL; 11355 const xmlChar *prefix = NULL; 11356 xmlXPathTestVal test = (xmlXPathTestVal) 0; 11357 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0; 11358 xmlXPathTypeVal type = (xmlXPathTypeVal) 0; 11359 int op1; 11360 11361 /* 11362 * The modification needed for XPointer change to the production 11363 */ 11364 #ifdef LIBXML_XPTR_ENABLED 11365 if (ctxt->xptr) { 11366 name = xmlXPathParseNCName(ctxt); 11367 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) { 11368 op2 = ctxt->comp->last; 11369 xmlFree(name); 11370 SKIP_BLANKS; 11371 if (CUR != '(') { 11372 XP_ERROR(XPATH_EXPR_ERROR); 11373 } 11374 NEXT; 11375 SKIP_BLANKS; 11376 11377 xmlXPathCompileExpr(ctxt, 1); 11378 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */ 11379 CHECK_ERROR; 11380 11381 SKIP_BLANKS; 11382 if (CUR != ')') { 11383 XP_ERROR(XPATH_EXPR_ERROR); 11384 } 11385 NEXT; 11386 rangeto = 1; 11387 goto eval_predicates; 11388 } 11389 } 11390 #endif 11391 if (CUR == '*') { 11392 axis = AXIS_CHILD; 11393 } else { 11394 if (name == NULL) 11395 name = xmlXPathParseNCName(ctxt); 11396 if (name != NULL) { 11397 axis = xmlXPathIsAxisName(name); 11398 if (axis != 0) { 11399 SKIP_BLANKS; 11400 if ((CUR == ':') && (NXT(1) == ':')) { 11401 SKIP(2); 11402 xmlFree(name); 11403 name = NULL; 11404 } else { 11405 /* an element name can conflict with an axis one :-\ */ 11406 axis = AXIS_CHILD; 11407 } 11408 } else { 11409 axis = AXIS_CHILD; 11410 } 11411 } else if (CUR == '@') { 11412 NEXT; 11413 axis = AXIS_ATTRIBUTE; 11414 } else { 11415 axis = AXIS_CHILD; 11416 } 11417 } 11418 11419 if (ctxt->error != XPATH_EXPRESSION_OK) { 11420 xmlFree(name); 11421 return; 11422 } 11423 11424 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name); 11425 if (test == 0) 11426 return; 11427 11428 if ((prefix != NULL) && (ctxt->context != NULL) && 11429 (ctxt->context->flags & XML_XPATH_CHECKNS)) { 11430 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) { 11431 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR); 11432 } 11433 } 11434 #ifdef DEBUG_STEP 11435 xmlGenericError(xmlGenericErrorContext, 11436 "Basis : computing new set\n"); 11437 #endif 11438 11439 #ifdef DEBUG_STEP 11440 xmlGenericError(xmlGenericErrorContext, "Basis : "); 11441 if (ctxt->value == NULL) 11442 xmlGenericError(xmlGenericErrorContext, "no value\n"); 11443 else if (ctxt->value->nodesetval == NULL) 11444 xmlGenericError(xmlGenericErrorContext, "Empty\n"); 11445 else 11446 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval); 11447 #endif 11448 11449 #ifdef LIBXML_XPTR_ENABLED 11450 eval_predicates: 11451 #endif 11452 op1 = ctxt->comp->last; 11453 ctxt->comp->last = -1; 11454 11455 SKIP_BLANKS; 11456 while (CUR == '[') { 11457 xmlXPathCompPredicate(ctxt, 0); 11458 } 11459 11460 #ifdef LIBXML_XPTR_ENABLED 11461 if (rangeto) { 11462 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0); 11463 } else 11464 #endif 11465 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis, 11466 test, type, (void *)prefix, (void *)name); 11467 11468 } 11469 #ifdef DEBUG_STEP 11470 xmlGenericError(xmlGenericErrorContext, "Step : "); 11471 if (ctxt->value == NULL) 11472 xmlGenericError(xmlGenericErrorContext, "no value\n"); 11473 else if (ctxt->value->nodesetval == NULL) 11474 xmlGenericError(xmlGenericErrorContext, "Empty\n"); 11475 else 11476 xmlGenericErrorContextNodeSet(xmlGenericErrorContext, 11477 ctxt->value->nodesetval); 11478 #endif 11479 } 11480 11481 /** 11482 * xmlXPathCompRelativeLocationPath: 11483 * @ctxt: the XPath Parser context 11484 * 11485 * [3] RelativeLocationPath ::= Step 11486 * | RelativeLocationPath '/' Step 11487 * | AbbreviatedRelativeLocationPath 11488 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step 11489 * 11490 * Compile a relative location path. 11491 */ 11492 static void 11493 xmlXPathCompRelativeLocationPath 11494 (xmlXPathParserContextPtr ctxt) { 11495 SKIP_BLANKS; 11496 if ((CUR == '/') && (NXT(1) == '/')) { 11497 SKIP(2); 11498 SKIP_BLANKS; 11499 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 11500 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11501 } else if (CUR == '/') { 11502 NEXT; 11503 SKIP_BLANKS; 11504 } 11505 xmlXPathCompStep(ctxt); 11506 CHECK_ERROR; 11507 SKIP_BLANKS; 11508 while (CUR == '/') { 11509 if ((CUR == '/') && (NXT(1) == '/')) { 11510 SKIP(2); 11511 SKIP_BLANKS; 11512 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 11513 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11514 xmlXPathCompStep(ctxt); 11515 } else if (CUR == '/') { 11516 NEXT; 11517 SKIP_BLANKS; 11518 xmlXPathCompStep(ctxt); 11519 } 11520 SKIP_BLANKS; 11521 } 11522 } 11523 11524 /** 11525 * xmlXPathCompLocationPath: 11526 * @ctxt: the XPath Parser context 11527 * 11528 * [1] LocationPath ::= RelativeLocationPath 11529 * | AbsoluteLocationPath 11530 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath? 11531 * | AbbreviatedAbsoluteLocationPath 11532 * [10] AbbreviatedAbsoluteLocationPath ::= 11533 * '//' RelativeLocationPath 11534 * 11535 * Compile a location path 11536 * 11537 * // is short for /descendant-or-self::node()/. For example, 11538 * //para is short for /descendant-or-self::node()/child::para and 11539 * so will select any para element in the document (even a para element 11540 * that is a document element will be selected by //para since the 11541 * document element node is a child of the root node); div//para is 11542 * short for div/descendant-or-self::node()/child::para and so will 11543 * select all para descendants of div children. 11544 */ 11545 static void 11546 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) { 11547 SKIP_BLANKS; 11548 if (CUR != '/') { 11549 xmlXPathCompRelativeLocationPath(ctxt); 11550 } else { 11551 while (CUR == '/') { 11552 if ((CUR == '/') && (NXT(1) == '/')) { 11553 SKIP(2); 11554 SKIP_BLANKS; 11555 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 11556 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11557 xmlXPathCompRelativeLocationPath(ctxt); 11558 } else if (CUR == '/') { 11559 NEXT; 11560 SKIP_BLANKS; 11561 if ((CUR != 0 ) && 11562 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') || 11563 (CUR == '@') || (CUR == '*'))) 11564 xmlXPathCompRelativeLocationPath(ctxt); 11565 } 11566 CHECK_ERROR; 11567 } 11568 } 11569 } 11570 11571 /************************************************************************ 11572 * * 11573 * XPath precompiled expression evaluation * 11574 * * 11575 ************************************************************************/ 11576 11577 static int 11578 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op); 11579 11580 #ifdef DEBUG_STEP 11581 static void 11582 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op, 11583 int nbNodes) 11584 { 11585 xmlGenericError(xmlGenericErrorContext, "new step : "); 11586 switch (op->value) { 11587 case AXIS_ANCESTOR: 11588 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' "); 11589 break; 11590 case AXIS_ANCESTOR_OR_SELF: 11591 xmlGenericError(xmlGenericErrorContext, 11592 "axis 'ancestors-or-self' "); 11593 break; 11594 case AXIS_ATTRIBUTE: 11595 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' "); 11596 break; 11597 case AXIS_CHILD: 11598 xmlGenericError(xmlGenericErrorContext, "axis 'child' "); 11599 break; 11600 case AXIS_DESCENDANT: 11601 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' "); 11602 break; 11603 case AXIS_DESCENDANT_OR_SELF: 11604 xmlGenericError(xmlGenericErrorContext, 11605 "axis 'descendant-or-self' "); 11606 break; 11607 case AXIS_FOLLOWING: 11608 xmlGenericError(xmlGenericErrorContext, "axis 'following' "); 11609 break; 11610 case AXIS_FOLLOWING_SIBLING: 11611 xmlGenericError(xmlGenericErrorContext, 11612 "axis 'following-siblings' "); 11613 break; 11614 case AXIS_NAMESPACE: 11615 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' "); 11616 break; 11617 case AXIS_PARENT: 11618 xmlGenericError(xmlGenericErrorContext, "axis 'parent' "); 11619 break; 11620 case AXIS_PRECEDING: 11621 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' "); 11622 break; 11623 case AXIS_PRECEDING_SIBLING: 11624 xmlGenericError(xmlGenericErrorContext, 11625 "axis 'preceding-sibling' "); 11626 break; 11627 case AXIS_SELF: 11628 xmlGenericError(xmlGenericErrorContext, "axis 'self' "); 11629 break; 11630 } 11631 xmlGenericError(xmlGenericErrorContext, 11632 " context contains %d nodes\n", nbNodes); 11633 switch (op->value2) { 11634 case NODE_TEST_NONE: 11635 xmlGenericError(xmlGenericErrorContext, 11636 " searching for none !!!\n"); 11637 break; 11638 case NODE_TEST_TYPE: 11639 xmlGenericError(xmlGenericErrorContext, 11640 " searching for type %d\n", op->value3); 11641 break; 11642 case NODE_TEST_PI: 11643 xmlGenericError(xmlGenericErrorContext, 11644 " searching for PI !!!\n"); 11645 break; 11646 case NODE_TEST_ALL: 11647 xmlGenericError(xmlGenericErrorContext, 11648 " searching for *\n"); 11649 break; 11650 case NODE_TEST_NS: 11651 xmlGenericError(xmlGenericErrorContext, 11652 " searching for namespace %s\n", 11653 op->value5); 11654 break; 11655 case NODE_TEST_NAME: 11656 xmlGenericError(xmlGenericErrorContext, 11657 " searching for name %s\n", op->value5); 11658 if (op->value4) 11659 xmlGenericError(xmlGenericErrorContext, 11660 " with namespace %s\n", op->value4); 11661 break; 11662 } 11663 xmlGenericError(xmlGenericErrorContext, "Testing : "); 11664 } 11665 #endif /* DEBUG_STEP */ 11666 11667 static int 11668 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt, 11669 xmlXPathStepOpPtr op, 11670 xmlNodeSetPtr set, 11671 int contextSize, 11672 int hasNsNodes) 11673 { 11674 if (op->ch1 != -1) { 11675 xmlXPathCompExprPtr comp = ctxt->comp; 11676 /* 11677 * Process inner predicates first. 11678 */ 11679 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) { 11680 /* 11681 * TODO: raise an internal error. 11682 */ 11683 } 11684 contextSize = xmlXPathCompOpEvalPredicate(ctxt, 11685 &comp->steps[op->ch1], set, contextSize, hasNsNodes); 11686 CHECK_ERROR0; 11687 if (contextSize <= 0) 11688 return(0); 11689 } 11690 if (op->ch2 != -1) { 11691 xmlXPathContextPtr xpctxt = ctxt->context; 11692 xmlNodePtr contextNode, oldContextNode; 11693 xmlDocPtr oldContextDoc; 11694 int i, res, contextPos = 0, newContextSize; 11695 xmlXPathStepOpPtr exprOp; 11696 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL; 11697 11698 #ifdef LIBXML_XPTR_ENABLED 11699 /* 11700 * URGENT TODO: Check the following: 11701 * We don't expect location sets if evaluating prediates, right? 11702 * Only filters should expect location sets, right? 11703 */ 11704 #endif 11705 /* 11706 * SPEC XPath 1.0: 11707 * "For each node in the node-set to be filtered, the 11708 * PredicateExpr is evaluated with that node as the 11709 * context node, with the number of nodes in the 11710 * node-set as the context size, and with the proximity 11711 * position of the node in the node-set with respect to 11712 * the axis as the context position;" 11713 * @oldset is the node-set" to be filtered. 11714 * 11715 * SPEC XPath 1.0: 11716 * "only predicates change the context position and 11717 * context size (see [2.4 Predicates])." 11718 * Example: 11719 * node-set context pos 11720 * nA 1 11721 * nB 2 11722 * nC 3 11723 * After applying predicate [position() > 1] : 11724 * node-set context pos 11725 * nB 1 11726 * nC 2 11727 */ 11728 oldContextNode = xpctxt->node; 11729 oldContextDoc = xpctxt->doc; 11730 /* 11731 * Get the expression of this predicate. 11732 */ 11733 exprOp = &ctxt->comp->steps[op->ch2]; 11734 newContextSize = 0; 11735 for (i = 0; i < set->nodeNr; i++) { 11736 if (set->nodeTab[i] == NULL) 11737 continue; 11738 11739 contextNode = set->nodeTab[i]; 11740 xpctxt->node = contextNode; 11741 xpctxt->contextSize = contextSize; 11742 xpctxt->proximityPosition = ++contextPos; 11743 11744 /* 11745 * Also set the xpath document in case things like 11746 * key() are evaluated in the predicate. 11747 */ 11748 if ((contextNode->type != XML_NAMESPACE_DECL) && 11749 (contextNode->doc != NULL)) 11750 xpctxt->doc = contextNode->doc; 11751 /* 11752 * Evaluate the predicate expression with 1 context node 11753 * at a time; this node is packaged into a node set; this 11754 * node set is handed over to the evaluation mechanism. 11755 */ 11756 if (contextObj == NULL) 11757 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode); 11758 else { 11759 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval, 11760 contextNode) < 0) { 11761 ctxt->error = XPATH_MEMORY_ERROR; 11762 goto evaluation_exit; 11763 } 11764 } 11765 11766 valuePush(ctxt, contextObj); 11767 11768 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1); 11769 11770 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) { 11771 xmlXPathNodeSetClear(set, hasNsNodes); 11772 newContextSize = 0; 11773 goto evaluation_exit; 11774 } 11775 11776 if (res != 0) { 11777 newContextSize++; 11778 } else { 11779 /* 11780 * Remove the entry from the initial node set. 11781 */ 11782 set->nodeTab[i] = NULL; 11783 if (contextNode->type == XML_NAMESPACE_DECL) 11784 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode); 11785 } 11786 if (ctxt->value == contextObj) { 11787 /* 11788 * Don't free the temporary XPath object holding the 11789 * context node, in order to avoid massive recreation 11790 * inside this loop. 11791 */ 11792 valuePop(ctxt); 11793 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes); 11794 } else { 11795 /* 11796 * TODO: The object was lost in the evaluation machinery. 11797 * Can this happen? Maybe in internal-error cases. 11798 */ 11799 contextObj = NULL; 11800 } 11801 } 11802 11803 if (contextObj != NULL) { 11804 if (ctxt->value == contextObj) 11805 valuePop(ctxt); 11806 xmlXPathReleaseObject(xpctxt, contextObj); 11807 } 11808 evaluation_exit: 11809 if (exprRes != NULL) 11810 xmlXPathReleaseObject(ctxt->context, exprRes); 11811 /* 11812 * Reset/invalidate the context. 11813 */ 11814 xpctxt->node = oldContextNode; 11815 xpctxt->doc = oldContextDoc; 11816 xpctxt->contextSize = -1; 11817 xpctxt->proximityPosition = -1; 11818 return(newContextSize); 11819 } 11820 return(contextSize); 11821 } 11822 11823 static int 11824 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt, 11825 xmlXPathStepOpPtr op, 11826 xmlNodeSetPtr set, 11827 int contextSize, 11828 int minPos, 11829 int maxPos, 11830 int hasNsNodes) 11831 { 11832 if (op->ch1 != -1) { 11833 xmlXPathCompExprPtr comp = ctxt->comp; 11834 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) { 11835 /* 11836 * TODO: raise an internal error. 11837 */ 11838 } 11839 contextSize = xmlXPathCompOpEvalPredicate(ctxt, 11840 &comp->steps[op->ch1], set, contextSize, hasNsNodes); 11841 CHECK_ERROR0; 11842 if (contextSize <= 0) 11843 return(0); 11844 } 11845 /* 11846 * Check if the node set contains a sufficient number of nodes for 11847 * the requested range. 11848 */ 11849 if (contextSize < minPos) { 11850 xmlXPathNodeSetClear(set, hasNsNodes); 11851 return(0); 11852 } 11853 if (op->ch2 == -1) { 11854 /* 11855 * TODO: Can this ever happen? 11856 */ 11857 return (contextSize); 11858 } else { 11859 xmlDocPtr oldContextDoc; 11860 int i, pos = 0, newContextSize = 0, contextPos = 0, res; 11861 xmlXPathStepOpPtr exprOp; 11862 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL; 11863 xmlNodePtr oldContextNode, contextNode = NULL; 11864 xmlXPathContextPtr xpctxt = ctxt->context; 11865 int frame; 11866 11867 #ifdef LIBXML_XPTR_ENABLED 11868 /* 11869 * URGENT TODO: Check the following: 11870 * We don't expect location sets if evaluating prediates, right? 11871 * Only filters should expect location sets, right? 11872 */ 11873 #endif /* LIBXML_XPTR_ENABLED */ 11874 11875 /* 11876 * Save old context. 11877 */ 11878 oldContextNode = xpctxt->node; 11879 oldContextDoc = xpctxt->doc; 11880 /* 11881 * Get the expression of this predicate. 11882 */ 11883 exprOp = &ctxt->comp->steps[op->ch2]; 11884 for (i = 0; i < set->nodeNr; i++) { 11885 xmlXPathObjectPtr tmp; 11886 11887 if (set->nodeTab[i] == NULL) 11888 continue; 11889 11890 contextNode = set->nodeTab[i]; 11891 xpctxt->node = contextNode; 11892 xpctxt->contextSize = contextSize; 11893 xpctxt->proximityPosition = ++contextPos; 11894 11895 /* 11896 * Initialize the new set. 11897 * Also set the xpath document in case things like 11898 * key() evaluation are attempted on the predicate 11899 */ 11900 if ((contextNode->type != XML_NAMESPACE_DECL) && 11901 (contextNode->doc != NULL)) 11902 xpctxt->doc = contextNode->doc; 11903 /* 11904 * Evaluate the predicate expression with 1 context node 11905 * at a time; this node is packaged into a node set; this 11906 * node set is handed over to the evaluation mechanism. 11907 */ 11908 if (contextObj == NULL) 11909 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode); 11910 else { 11911 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval, 11912 contextNode) < 0) { 11913 ctxt->error = XPATH_MEMORY_ERROR; 11914 goto evaluation_exit; 11915 } 11916 } 11917 11918 frame = xmlXPathSetFrame(ctxt); 11919 valuePush(ctxt, contextObj); 11920 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1); 11921 tmp = valuePop(ctxt); 11922 xmlXPathPopFrame(ctxt, frame); 11923 11924 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) { 11925 while (tmp != contextObj) { 11926 /* 11927 * Free up the result 11928 * then pop off contextObj, which will be freed later 11929 */ 11930 xmlXPathReleaseObject(xpctxt, tmp); 11931 tmp = valuePop(ctxt); 11932 } 11933 goto evaluation_error; 11934 } 11935 /* push the result back onto the stack */ 11936 valuePush(ctxt, tmp); 11937 11938 if (res) 11939 pos++; 11940 11941 if (res && (pos >= minPos) && (pos <= maxPos)) { 11942 /* 11943 * Fits in the requested range. 11944 */ 11945 newContextSize++; 11946 if (minPos == maxPos) { 11947 /* 11948 * Only 1 node was requested. 11949 */ 11950 if (contextNode->type == XML_NAMESPACE_DECL) { 11951 /* 11952 * As always: take care of those nasty 11953 * namespace nodes. 11954 */ 11955 set->nodeTab[i] = NULL; 11956 } 11957 xmlXPathNodeSetClear(set, hasNsNodes); 11958 set->nodeNr = 1; 11959 set->nodeTab[0] = contextNode; 11960 goto evaluation_exit; 11961 } 11962 if (pos == maxPos) { 11963 /* 11964 * We are done. 11965 */ 11966 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes); 11967 goto evaluation_exit; 11968 } 11969 } else { 11970 /* 11971 * Remove the entry from the initial node set. 11972 */ 11973 set->nodeTab[i] = NULL; 11974 if (contextNode->type == XML_NAMESPACE_DECL) 11975 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode); 11976 } 11977 if (exprRes != NULL) { 11978 xmlXPathReleaseObject(ctxt->context, exprRes); 11979 exprRes = NULL; 11980 } 11981 if (ctxt->value == contextObj) { 11982 /* 11983 * Don't free the temporary XPath object holding the 11984 * context node, in order to avoid massive recreation 11985 * inside this loop. 11986 */ 11987 valuePop(ctxt); 11988 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes); 11989 } else { 11990 /* 11991 * The object was lost in the evaluation machinery. 11992 * Can this happen? Maybe in case of internal-errors. 11993 */ 11994 contextObj = NULL; 11995 } 11996 } 11997 goto evaluation_exit; 11998 11999 evaluation_error: 12000 xmlXPathNodeSetClear(set, hasNsNodes); 12001 newContextSize = 0; 12002 12003 evaluation_exit: 12004 if (contextObj != NULL) { 12005 if (ctxt->value == contextObj) 12006 valuePop(ctxt); 12007 xmlXPathReleaseObject(xpctxt, contextObj); 12008 } 12009 if (exprRes != NULL) 12010 xmlXPathReleaseObject(ctxt->context, exprRes); 12011 /* 12012 * Reset/invalidate the context. 12013 */ 12014 xpctxt->node = oldContextNode; 12015 xpctxt->doc = oldContextDoc; 12016 xpctxt->contextSize = -1; 12017 xpctxt->proximityPosition = -1; 12018 return(newContextSize); 12019 } 12020 return(contextSize); 12021 } 12022 12023 static int 12024 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt, 12025 xmlXPathStepOpPtr op, 12026 int *maxPos) 12027 { 12028 12029 xmlXPathStepOpPtr exprOp; 12030 12031 /* 12032 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet! 12033 */ 12034 12035 /* 12036 * If not -1, then ch1 will point to: 12037 * 1) For predicates (XPATH_OP_PREDICATE): 12038 * - an inner predicate operator 12039 * 2) For filters (XPATH_OP_FILTER): 12040 * - an inner filter operater OR 12041 * - an expression selecting the node set. 12042 * E.g. "key('a', 'b')" or "(//foo | //bar)". 12043 */ 12044 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER)) 12045 return(0); 12046 12047 if (op->ch2 != -1) { 12048 exprOp = &ctxt->comp->steps[op->ch2]; 12049 } else 12050 return(0); 12051 12052 if ((exprOp != NULL) && 12053 (exprOp->op == XPATH_OP_VALUE) && 12054 (exprOp->value4 != NULL) && 12055 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER)) 12056 { 12057 /* 12058 * We have a "[n]" predicate here. 12059 * TODO: Unfortunately this simplistic test here is not 12060 * able to detect a position() predicate in compound 12061 * expressions like "[@attr = 'a" and position() = 1], 12062 * and even not the usage of position() in 12063 * "[position() = 1]"; thus - obviously - a position-range, 12064 * like it "[position() < 5]", is also not detected. 12065 * Maybe we could rewrite the AST to ease the optimization. 12066 */ 12067 *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval; 12068 12069 if (((xmlXPathObjectPtr) exprOp->value4)->floatval == 12070 (float) *maxPos) 12071 { 12072 return(1); 12073 } 12074 } 12075 return(0); 12076 } 12077 12078 static int 12079 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, 12080 xmlXPathStepOpPtr op, 12081 xmlNodePtr * first, xmlNodePtr * last, 12082 int toBool) 12083 { 12084 12085 #define XP_TEST_HIT \ 12086 if (hasAxisRange != 0) { \ 12087 if (++pos == maxPos) { \ 12088 if (addNode(seq, cur) < 0) \ 12089 ctxt->error = XPATH_MEMORY_ERROR; \ 12090 goto axis_range_end; } \ 12091 } else { \ 12092 if (addNode(seq, cur) < 0) \ 12093 ctxt->error = XPATH_MEMORY_ERROR; \ 12094 if (breakOnFirstHit) goto first_hit; } 12095 12096 #define XP_TEST_HIT_NS \ 12097 if (hasAxisRange != 0) { \ 12098 if (++pos == maxPos) { \ 12099 hasNsNodes = 1; \ 12100 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \ 12101 ctxt->error = XPATH_MEMORY_ERROR; \ 12102 goto axis_range_end; } \ 12103 } else { \ 12104 hasNsNodes = 1; \ 12105 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \ 12106 ctxt->error = XPATH_MEMORY_ERROR; \ 12107 if (breakOnFirstHit) goto first_hit; } 12108 12109 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value; 12110 xmlXPathTestVal test = (xmlXPathTestVal) op->value2; 12111 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3; 12112 const xmlChar *prefix = op->value4; 12113 const xmlChar *name = op->value5; 12114 const xmlChar *URI = NULL; 12115 12116 #ifdef DEBUG_STEP 12117 int nbMatches = 0, prevMatches = 0; 12118 #endif 12119 int total = 0, hasNsNodes = 0; 12120 /* The popped object holding the context nodes */ 12121 xmlXPathObjectPtr obj; 12122 /* The set of context nodes for the node tests */ 12123 xmlNodeSetPtr contextSeq; 12124 int contextIdx; 12125 xmlNodePtr contextNode; 12126 /* The final resulting node set wrt to all context nodes */ 12127 xmlNodeSetPtr outSeq; 12128 /* 12129 * The temporary resulting node set wrt 1 context node. 12130 * Used to feed predicate evaluation. 12131 */ 12132 xmlNodeSetPtr seq; 12133 xmlNodePtr cur; 12134 /* First predicate operator */ 12135 xmlXPathStepOpPtr predOp; 12136 int maxPos; /* The requested position() (when a "[n]" predicate) */ 12137 int hasPredicateRange, hasAxisRange, pos, size, newSize; 12138 int breakOnFirstHit; 12139 12140 xmlXPathTraversalFunction next = NULL; 12141 int (*addNode) (xmlNodeSetPtr, xmlNodePtr); 12142 xmlXPathNodeSetMergeFunction mergeAndClear; 12143 xmlNodePtr oldContextNode; 12144 xmlXPathContextPtr xpctxt = ctxt->context; 12145 12146 12147 CHECK_TYPE0(XPATH_NODESET); 12148 obj = valuePop(ctxt); 12149 /* 12150 * Setup namespaces. 12151 */ 12152 if (prefix != NULL) { 12153 URI = xmlXPathNsLookup(xpctxt, prefix); 12154 if (URI == NULL) { 12155 xmlXPathReleaseObject(xpctxt, obj); 12156 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); 12157 } 12158 } 12159 /* 12160 * Setup axis. 12161 * 12162 * MAYBE FUTURE TODO: merging optimizations: 12163 * - If the nodes to be traversed wrt to the initial nodes and 12164 * the current axis cannot overlap, then we could avoid searching 12165 * for duplicates during the merge. 12166 * But the question is how/when to evaluate if they cannot overlap. 12167 * Example: if we know that for two initial nodes, the one is 12168 * not in the ancestor-or-self axis of the other, then we could safely 12169 * avoid a duplicate-aware merge, if the axis to be traversed is e.g. 12170 * the descendant-or-self axis. 12171 */ 12172 mergeAndClear = xmlXPathNodeSetMergeAndClear; 12173 switch (axis) { 12174 case AXIS_ANCESTOR: 12175 first = NULL; 12176 next = xmlXPathNextAncestor; 12177 break; 12178 case AXIS_ANCESTOR_OR_SELF: 12179 first = NULL; 12180 next = xmlXPathNextAncestorOrSelf; 12181 break; 12182 case AXIS_ATTRIBUTE: 12183 first = NULL; 12184 last = NULL; 12185 next = xmlXPathNextAttribute; 12186 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12187 break; 12188 case AXIS_CHILD: 12189 last = NULL; 12190 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) && 12191 (type == NODE_TYPE_NODE)) 12192 { 12193 /* 12194 * Optimization if an element node type is 'element'. 12195 */ 12196 next = xmlXPathNextChildElement; 12197 } else 12198 next = xmlXPathNextChild; 12199 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12200 break; 12201 case AXIS_DESCENDANT: 12202 last = NULL; 12203 next = xmlXPathNextDescendant; 12204 break; 12205 case AXIS_DESCENDANT_OR_SELF: 12206 last = NULL; 12207 next = xmlXPathNextDescendantOrSelf; 12208 break; 12209 case AXIS_FOLLOWING: 12210 last = NULL; 12211 next = xmlXPathNextFollowing; 12212 break; 12213 case AXIS_FOLLOWING_SIBLING: 12214 last = NULL; 12215 next = xmlXPathNextFollowingSibling; 12216 break; 12217 case AXIS_NAMESPACE: 12218 first = NULL; 12219 last = NULL; 12220 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; 12221 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12222 break; 12223 case AXIS_PARENT: 12224 first = NULL; 12225 next = xmlXPathNextParent; 12226 break; 12227 case AXIS_PRECEDING: 12228 first = NULL; 12229 next = xmlXPathNextPrecedingInternal; 12230 break; 12231 case AXIS_PRECEDING_SIBLING: 12232 first = NULL; 12233 next = xmlXPathNextPrecedingSibling; 12234 break; 12235 case AXIS_SELF: 12236 first = NULL; 12237 last = NULL; 12238 next = xmlXPathNextSelf; 12239 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12240 break; 12241 } 12242 12243 #ifdef DEBUG_STEP 12244 xmlXPathDebugDumpStepAxis(op, 12245 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0); 12246 #endif 12247 12248 if (next == NULL) { 12249 xmlXPathReleaseObject(xpctxt, obj); 12250 return(0); 12251 } 12252 contextSeq = obj->nodesetval; 12253 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) { 12254 xmlXPathReleaseObject(xpctxt, obj); 12255 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL)); 12256 return(0); 12257 } 12258 /* 12259 * Predicate optimization --------------------------------------------- 12260 * If this step has a last predicate, which contains a position(), 12261 * then we'll optimize (although not exactly "position()", but only 12262 * the short-hand form, i.e., "[n]". 12263 * 12264 * Example - expression "/foo[parent::bar][1]": 12265 * 12266 * COLLECT 'child' 'name' 'node' foo -- op (we are here) 12267 * ROOT -- op->ch1 12268 * PREDICATE -- op->ch2 (predOp) 12269 * PREDICATE -- predOp->ch1 = [parent::bar] 12270 * SORT 12271 * COLLECT 'parent' 'name' 'node' bar 12272 * NODE 12273 * ELEM Object is a number : 1 -- predOp->ch2 = [1] 12274 * 12275 */ 12276 maxPos = 0; 12277 predOp = NULL; 12278 hasPredicateRange = 0; 12279 hasAxisRange = 0; 12280 if (op->ch2 != -1) { 12281 /* 12282 * There's at least one predicate. 16 == XPATH_OP_PREDICATE 12283 */ 12284 predOp = &ctxt->comp->steps[op->ch2]; 12285 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) { 12286 if (predOp->ch1 != -1) { 12287 /* 12288 * Use the next inner predicate operator. 12289 */ 12290 predOp = &ctxt->comp->steps[predOp->ch1]; 12291 hasPredicateRange = 1; 12292 } else { 12293 /* 12294 * There's no other predicate than the [n] predicate. 12295 */ 12296 predOp = NULL; 12297 hasAxisRange = 1; 12298 } 12299 } 12300 } 12301 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0; 12302 /* 12303 * Axis traversal ----------------------------------------------------- 12304 */ 12305 /* 12306 * 2.3 Node Tests 12307 * - For the attribute axis, the principal node type is attribute. 12308 * - For the namespace axis, the principal node type is namespace. 12309 * - For other axes, the principal node type is element. 12310 * 12311 * A node test * is true for any node of the 12312 * principal node type. For example, child::* will 12313 * select all element children of the context node 12314 */ 12315 oldContextNode = xpctxt->node; 12316 addNode = xmlXPathNodeSetAddUnique; 12317 outSeq = NULL; 12318 seq = NULL; 12319 contextNode = NULL; 12320 contextIdx = 0; 12321 12322 12323 while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) && 12324 (ctxt->error == XPATH_EXPRESSION_OK)) { 12325 xpctxt->node = contextSeq->nodeTab[contextIdx++]; 12326 12327 if (seq == NULL) { 12328 seq = xmlXPathNodeSetCreate(NULL); 12329 if (seq == NULL) { 12330 total = 0; 12331 goto error; 12332 } 12333 } 12334 /* 12335 * Traverse the axis and test the nodes. 12336 */ 12337 pos = 0; 12338 cur = NULL; 12339 hasNsNodes = 0; 12340 do { 12341 cur = next(ctxt, cur); 12342 if (cur == NULL) 12343 break; 12344 12345 /* 12346 * QUESTION TODO: What does the "first" and "last" stuff do? 12347 */ 12348 if ((first != NULL) && (*first != NULL)) { 12349 if (*first == cur) 12350 break; 12351 if (((total % 256) == 0) && 12352 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 12353 (xmlXPathCmpNodesExt(*first, cur) >= 0)) 12354 #else 12355 (xmlXPathCmpNodes(*first, cur) >= 0)) 12356 #endif 12357 { 12358 break; 12359 } 12360 } 12361 if ((last != NULL) && (*last != NULL)) { 12362 if (*last == cur) 12363 break; 12364 if (((total % 256) == 0) && 12365 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 12366 (xmlXPathCmpNodesExt(cur, *last) >= 0)) 12367 #else 12368 (xmlXPathCmpNodes(cur, *last) >= 0)) 12369 #endif 12370 { 12371 break; 12372 } 12373 } 12374 12375 total++; 12376 12377 #ifdef DEBUG_STEP 12378 xmlGenericError(xmlGenericErrorContext, " %s", cur->name); 12379 #endif 12380 12381 switch (test) { 12382 case NODE_TEST_NONE: 12383 total = 0; 12384 STRANGE 12385 goto error; 12386 case NODE_TEST_TYPE: 12387 if (type == NODE_TYPE_NODE) { 12388 switch (cur->type) { 12389 case XML_DOCUMENT_NODE: 12390 case XML_HTML_DOCUMENT_NODE: 12391 #ifdef LIBXML_DOCB_ENABLED 12392 case XML_DOCB_DOCUMENT_NODE: 12393 #endif 12394 case XML_ELEMENT_NODE: 12395 case XML_ATTRIBUTE_NODE: 12396 case XML_PI_NODE: 12397 case XML_COMMENT_NODE: 12398 case XML_CDATA_SECTION_NODE: 12399 case XML_TEXT_NODE: 12400 XP_TEST_HIT 12401 break; 12402 case XML_NAMESPACE_DECL: { 12403 if (axis == AXIS_NAMESPACE) { 12404 XP_TEST_HIT_NS 12405 } else { 12406 hasNsNodes = 1; 12407 XP_TEST_HIT 12408 } 12409 break; 12410 } 12411 default: 12412 break; 12413 } 12414 } else if (cur->type == type) { 12415 if (cur->type == XML_NAMESPACE_DECL) 12416 XP_TEST_HIT_NS 12417 else 12418 XP_TEST_HIT 12419 } else if ((type == NODE_TYPE_TEXT) && 12420 (cur->type == XML_CDATA_SECTION_NODE)) 12421 { 12422 XP_TEST_HIT 12423 } 12424 break; 12425 case NODE_TEST_PI: 12426 if ((cur->type == XML_PI_NODE) && 12427 ((name == NULL) || xmlStrEqual(name, cur->name))) 12428 { 12429 XP_TEST_HIT 12430 } 12431 break; 12432 case NODE_TEST_ALL: 12433 if (axis == AXIS_ATTRIBUTE) { 12434 if (cur->type == XML_ATTRIBUTE_NODE) 12435 { 12436 if (prefix == NULL) 12437 { 12438 XP_TEST_HIT 12439 } else if ((cur->ns != NULL) && 12440 (xmlStrEqual(URI, cur->ns->href))) 12441 { 12442 XP_TEST_HIT 12443 } 12444 } 12445 } else if (axis == AXIS_NAMESPACE) { 12446 if (cur->type == XML_NAMESPACE_DECL) 12447 { 12448 XP_TEST_HIT_NS 12449 } 12450 } else { 12451 if (cur->type == XML_ELEMENT_NODE) { 12452 if (prefix == NULL) 12453 { 12454 XP_TEST_HIT 12455 12456 } else if ((cur->ns != NULL) && 12457 (xmlStrEqual(URI, cur->ns->href))) 12458 { 12459 XP_TEST_HIT 12460 } 12461 } 12462 } 12463 break; 12464 case NODE_TEST_NS:{ 12465 TODO; 12466 break; 12467 } 12468 case NODE_TEST_NAME: 12469 if (axis == AXIS_ATTRIBUTE) { 12470 if (cur->type != XML_ATTRIBUTE_NODE) 12471 break; 12472 } else if (axis == AXIS_NAMESPACE) { 12473 if (cur->type != XML_NAMESPACE_DECL) 12474 break; 12475 } else { 12476 if (cur->type != XML_ELEMENT_NODE) 12477 break; 12478 } 12479 switch (cur->type) { 12480 case XML_ELEMENT_NODE: 12481 if (xmlStrEqual(name, cur->name)) { 12482 if (prefix == NULL) { 12483 if (cur->ns == NULL) 12484 { 12485 XP_TEST_HIT 12486 } 12487 } else { 12488 if ((cur->ns != NULL) && 12489 (xmlStrEqual(URI, cur->ns->href))) 12490 { 12491 XP_TEST_HIT 12492 } 12493 } 12494 } 12495 break; 12496 case XML_ATTRIBUTE_NODE:{ 12497 xmlAttrPtr attr = (xmlAttrPtr) cur; 12498 12499 if (xmlStrEqual(name, attr->name)) { 12500 if (prefix == NULL) { 12501 if ((attr->ns == NULL) || 12502 (attr->ns->prefix == NULL)) 12503 { 12504 XP_TEST_HIT 12505 } 12506 } else { 12507 if ((attr->ns != NULL) && 12508 (xmlStrEqual(URI, 12509 attr->ns->href))) 12510 { 12511 XP_TEST_HIT 12512 } 12513 } 12514 } 12515 break; 12516 } 12517 case XML_NAMESPACE_DECL: 12518 if (cur->type == XML_NAMESPACE_DECL) { 12519 xmlNsPtr ns = (xmlNsPtr) cur; 12520 12521 if ((ns->prefix != NULL) && (name != NULL) 12522 && (xmlStrEqual(ns->prefix, name))) 12523 { 12524 XP_TEST_HIT_NS 12525 } 12526 } 12527 break; 12528 default: 12529 break; 12530 } 12531 break; 12532 } /* switch(test) */ 12533 } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK)); 12534 12535 goto apply_predicates; 12536 12537 axis_range_end: /* ----------------------------------------------------- */ 12538 /* 12539 * We have a "/foo[n]", and position() = n was reached. 12540 * Note that we can have as well "/foo/::parent::foo[1]", so 12541 * a duplicate-aware merge is still needed. 12542 * Merge with the result. 12543 */ 12544 if (outSeq == NULL) { 12545 outSeq = seq; 12546 seq = NULL; 12547 } else 12548 outSeq = mergeAndClear(outSeq, seq, 0); 12549 /* 12550 * Break if only a true/false result was requested. 12551 */ 12552 if (toBool) 12553 break; 12554 continue; 12555 12556 first_hit: /* ---------------------------------------------------------- */ 12557 /* 12558 * Break if only a true/false result was requested and 12559 * no predicates existed and a node test succeeded. 12560 */ 12561 if (outSeq == NULL) { 12562 outSeq = seq; 12563 seq = NULL; 12564 } else 12565 outSeq = mergeAndClear(outSeq, seq, 0); 12566 break; 12567 12568 #ifdef DEBUG_STEP 12569 if (seq != NULL) 12570 nbMatches += seq->nodeNr; 12571 #endif 12572 12573 apply_predicates: /* --------------------------------------------------- */ 12574 if (ctxt->error != XPATH_EXPRESSION_OK) 12575 goto error; 12576 12577 /* 12578 * Apply predicates. 12579 */ 12580 if ((predOp != NULL) && (seq->nodeNr > 0)) { 12581 /* 12582 * E.g. when we have a "/foo[some expression][n]". 12583 */ 12584 /* 12585 * QUESTION TODO: The old predicate evaluation took into 12586 * account location-sets. 12587 * (E.g. ctxt->value->type == XPATH_LOCATIONSET) 12588 * Do we expect such a set here? 12589 * All what I learned now from the evaluation semantics 12590 * does not indicate that a location-set will be processed 12591 * here, so this looks OK. 12592 */ 12593 /* 12594 * Iterate over all predicates, starting with the outermost 12595 * predicate. 12596 * TODO: Problem: we cannot execute the inner predicates first 12597 * since we cannot go back *up* the operator tree! 12598 * Options we have: 12599 * 1) Use of recursive functions (like is it currently done 12600 * via xmlXPathCompOpEval()) 12601 * 2) Add a predicate evaluation information stack to the 12602 * context struct 12603 * 3) Change the way the operators are linked; we need a 12604 * "parent" field on xmlXPathStepOp 12605 * 12606 * For the moment, I'll try to solve this with a recursive 12607 * function: xmlXPathCompOpEvalPredicate(). 12608 */ 12609 size = seq->nodeNr; 12610 if (hasPredicateRange != 0) 12611 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt, 12612 predOp, seq, size, maxPos, maxPos, hasNsNodes); 12613 else 12614 newSize = xmlXPathCompOpEvalPredicate(ctxt, 12615 predOp, seq, size, hasNsNodes); 12616 12617 if (ctxt->error != XPATH_EXPRESSION_OK) { 12618 total = 0; 12619 goto error; 12620 } 12621 /* 12622 * Add the filtered set of nodes to the result node set. 12623 */ 12624 if (newSize == 0) { 12625 /* 12626 * The predicates filtered all nodes out. 12627 */ 12628 xmlXPathNodeSetClear(seq, hasNsNodes); 12629 } else if (seq->nodeNr > 0) { 12630 /* 12631 * Add to result set. 12632 */ 12633 if (outSeq == NULL) { 12634 if (size != newSize) { 12635 /* 12636 * We need to merge and clear here, since 12637 * the sequence will contained NULLed entries. 12638 */ 12639 outSeq = mergeAndClear(NULL, seq, 1); 12640 } else { 12641 outSeq = seq; 12642 seq = NULL; 12643 } 12644 } else 12645 outSeq = mergeAndClear(outSeq, seq, 12646 (size != newSize) ? 1: 0); 12647 /* 12648 * Break if only a true/false result was requested. 12649 */ 12650 if (toBool) 12651 break; 12652 } 12653 } else if (seq->nodeNr > 0) { 12654 /* 12655 * Add to result set. 12656 */ 12657 if (outSeq == NULL) { 12658 outSeq = seq; 12659 seq = NULL; 12660 } else { 12661 outSeq = mergeAndClear(outSeq, seq, 0); 12662 } 12663 } 12664 } 12665 12666 error: 12667 if ((obj->boolval) && (obj->user != NULL)) { 12668 /* 12669 * QUESTION TODO: What does this do and why? 12670 * TODO: Do we have to do this also for the "error" 12671 * cleanup further down? 12672 */ 12673 ctxt->value->boolval = 1; 12674 ctxt->value->user = obj->user; 12675 obj->user = NULL; 12676 obj->boolval = 0; 12677 } 12678 xmlXPathReleaseObject(xpctxt, obj); 12679 12680 /* 12681 * Ensure we return at least an emtpy set. 12682 */ 12683 if (outSeq == NULL) { 12684 if ((seq != NULL) && (seq->nodeNr == 0)) 12685 outSeq = seq; 12686 else 12687 outSeq = xmlXPathNodeSetCreate(NULL); 12688 /* XXX what if xmlXPathNodeSetCreate returned NULL here? */ 12689 } 12690 if ((seq != NULL) && (seq != outSeq)) { 12691 xmlXPathFreeNodeSet(seq); 12692 } 12693 /* 12694 * Hand over the result. Better to push the set also in 12695 * case of errors. 12696 */ 12697 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq)); 12698 /* 12699 * Reset the context node. 12700 */ 12701 xpctxt->node = oldContextNode; 12702 /* 12703 * When traversing the namespace axis in "toBool" mode, it's 12704 * possible that tmpNsList wasn't freed. 12705 */ 12706 if (xpctxt->tmpNsList != NULL) { 12707 xmlFree(xpctxt->tmpNsList); 12708 xpctxt->tmpNsList = NULL; 12709 } 12710 12711 #ifdef DEBUG_STEP 12712 xmlGenericError(xmlGenericErrorContext, 12713 "\nExamined %d nodes, found %d nodes at that step\n", 12714 total, nbMatches); 12715 #endif 12716 12717 return(total); 12718 } 12719 12720 static int 12721 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt, 12722 xmlXPathStepOpPtr op, xmlNodePtr * first); 12723 12724 /** 12725 * xmlXPathCompOpEvalFirst: 12726 * @ctxt: the XPath parser context with the compiled expression 12727 * @op: an XPath compiled operation 12728 * @first: the first elem found so far 12729 * 12730 * Evaluate the Precompiled XPath operation searching only the first 12731 * element in document order 12732 * 12733 * Returns the number of examined objects. 12734 */ 12735 static int 12736 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt, 12737 xmlXPathStepOpPtr op, xmlNodePtr * first) 12738 { 12739 int total = 0, cur; 12740 xmlXPathCompExprPtr comp; 12741 xmlXPathObjectPtr arg1, arg2; 12742 12743 CHECK_ERROR0; 12744 comp = ctxt->comp; 12745 switch (op->op) { 12746 case XPATH_OP_END: 12747 return (0); 12748 case XPATH_OP_UNION: 12749 total = 12750 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1], 12751 first); 12752 CHECK_ERROR0; 12753 if ((ctxt->value != NULL) 12754 && (ctxt->value->type == XPATH_NODESET) 12755 && (ctxt->value->nodesetval != NULL) 12756 && (ctxt->value->nodesetval->nodeNr >= 1)) { 12757 /* 12758 * limit tree traversing to first node in the result 12759 */ 12760 /* 12761 * OPTIMIZE TODO: This implicitely sorts 12762 * the result, even if not needed. E.g. if the argument 12763 * of the count() function, no sorting is needed. 12764 * OPTIMIZE TODO: How do we know if the node-list wasn't 12765 * aready sorted? 12766 */ 12767 if (ctxt->value->nodesetval->nodeNr > 1) 12768 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12769 *first = ctxt->value->nodesetval->nodeTab[0]; 12770 } 12771 cur = 12772 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2], 12773 first); 12774 CHECK_ERROR0; 12775 CHECK_TYPE0(XPATH_NODESET); 12776 arg2 = valuePop(ctxt); 12777 12778 CHECK_TYPE0(XPATH_NODESET); 12779 arg1 = valuePop(ctxt); 12780 12781 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 12782 arg2->nodesetval); 12783 valuePush(ctxt, arg1); 12784 xmlXPathReleaseObject(ctxt->context, arg2); 12785 /* optimizer */ 12786 if (total > cur) 12787 xmlXPathCompSwap(op); 12788 return (total + cur); 12789 case XPATH_OP_ROOT: 12790 xmlXPathRoot(ctxt); 12791 return (0); 12792 case XPATH_OP_NODE: 12793 if (op->ch1 != -1) 12794 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12795 CHECK_ERROR0; 12796 if (op->ch2 != -1) 12797 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12798 CHECK_ERROR0; 12799 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 12800 ctxt->context->node)); 12801 return (total); 12802 case XPATH_OP_RESET: 12803 if (op->ch1 != -1) 12804 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12805 CHECK_ERROR0; 12806 if (op->ch2 != -1) 12807 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12808 CHECK_ERROR0; 12809 ctxt->context->node = NULL; 12810 return (total); 12811 case XPATH_OP_COLLECT:{ 12812 if (op->ch1 == -1) 12813 return (total); 12814 12815 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12816 CHECK_ERROR0; 12817 12818 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0); 12819 return (total); 12820 } 12821 case XPATH_OP_VALUE: 12822 valuePush(ctxt, 12823 xmlXPathCacheObjectCopy(ctxt->context, 12824 (xmlXPathObjectPtr) op->value4)); 12825 return (0); 12826 case XPATH_OP_SORT: 12827 if (op->ch1 != -1) 12828 total += 12829 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1], 12830 first); 12831 CHECK_ERROR0; 12832 if ((ctxt->value != NULL) 12833 && (ctxt->value->type == XPATH_NODESET) 12834 && (ctxt->value->nodesetval != NULL) 12835 && (ctxt->value->nodesetval->nodeNr > 1)) 12836 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12837 return (total); 12838 #ifdef XP_OPTIMIZED_FILTER_FIRST 12839 case XPATH_OP_FILTER: 12840 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first); 12841 return (total); 12842 #endif 12843 default: 12844 return (xmlXPathCompOpEval(ctxt, op)); 12845 } 12846 } 12847 12848 /** 12849 * xmlXPathCompOpEvalLast: 12850 * @ctxt: the XPath parser context with the compiled expression 12851 * @op: an XPath compiled operation 12852 * @last: the last elem found so far 12853 * 12854 * Evaluate the Precompiled XPath operation searching only the last 12855 * element in document order 12856 * 12857 * Returns the number of nodes traversed 12858 */ 12859 static int 12860 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op, 12861 xmlNodePtr * last) 12862 { 12863 int total = 0, cur; 12864 xmlXPathCompExprPtr comp; 12865 xmlXPathObjectPtr arg1, arg2; 12866 xmlNodePtr bak; 12867 xmlDocPtr bakd; 12868 int pp; 12869 int cs; 12870 12871 CHECK_ERROR0; 12872 comp = ctxt->comp; 12873 switch (op->op) { 12874 case XPATH_OP_END: 12875 return (0); 12876 case XPATH_OP_UNION: 12877 bakd = ctxt->context->doc; 12878 bak = ctxt->context->node; 12879 pp = ctxt->context->proximityPosition; 12880 cs = ctxt->context->contextSize; 12881 total = 12882 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], 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)) { 12888 /* 12889 * limit tree traversing to first node in the result 12890 */ 12891 if (ctxt->value->nodesetval->nodeNr > 1) 12892 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12893 *last = 12894 ctxt->value->nodesetval->nodeTab[ctxt->value-> 12895 nodesetval->nodeNr - 12896 1]; 12897 } 12898 ctxt->context->doc = bakd; 12899 ctxt->context->node = bak; 12900 ctxt->context->proximityPosition = pp; 12901 ctxt->context->contextSize = cs; 12902 cur = 12903 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last); 12904 CHECK_ERROR0; 12905 if ((ctxt->value != NULL) 12906 && (ctxt->value->type == XPATH_NODESET) 12907 && (ctxt->value->nodesetval != NULL) 12908 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */ 12909 } 12910 CHECK_TYPE0(XPATH_NODESET); 12911 arg2 = valuePop(ctxt); 12912 12913 CHECK_TYPE0(XPATH_NODESET); 12914 arg1 = valuePop(ctxt); 12915 12916 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 12917 arg2->nodesetval); 12918 valuePush(ctxt, arg1); 12919 xmlXPathReleaseObject(ctxt->context, arg2); 12920 /* optimizer */ 12921 if (total > cur) 12922 xmlXPathCompSwap(op); 12923 return (total + cur); 12924 case XPATH_OP_ROOT: 12925 xmlXPathRoot(ctxt); 12926 return (0); 12927 case XPATH_OP_NODE: 12928 if (op->ch1 != -1) 12929 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12930 CHECK_ERROR0; 12931 if (op->ch2 != -1) 12932 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12933 CHECK_ERROR0; 12934 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 12935 ctxt->context->node)); 12936 return (total); 12937 case XPATH_OP_RESET: 12938 if (op->ch1 != -1) 12939 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12940 CHECK_ERROR0; 12941 if (op->ch2 != -1) 12942 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12943 CHECK_ERROR0; 12944 ctxt->context->node = NULL; 12945 return (total); 12946 case XPATH_OP_COLLECT:{ 12947 if (op->ch1 == -1) 12948 return (0); 12949 12950 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12951 CHECK_ERROR0; 12952 12953 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0); 12954 return (total); 12955 } 12956 case XPATH_OP_VALUE: 12957 valuePush(ctxt, 12958 xmlXPathCacheObjectCopy(ctxt->context, 12959 (xmlXPathObjectPtr) op->value4)); 12960 return (0); 12961 case XPATH_OP_SORT: 12962 if (op->ch1 != -1) 12963 total += 12964 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], 12965 last); 12966 CHECK_ERROR0; 12967 if ((ctxt->value != NULL) 12968 && (ctxt->value->type == XPATH_NODESET) 12969 && (ctxt->value->nodesetval != NULL) 12970 && (ctxt->value->nodesetval->nodeNr > 1)) 12971 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12972 return (total); 12973 default: 12974 return (xmlXPathCompOpEval(ctxt, op)); 12975 } 12976 } 12977 12978 #ifdef XP_OPTIMIZED_FILTER_FIRST 12979 static int 12980 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt, 12981 xmlXPathStepOpPtr op, xmlNodePtr * first) 12982 { 12983 int total = 0; 12984 xmlXPathCompExprPtr comp; 12985 xmlXPathObjectPtr res; 12986 xmlXPathObjectPtr obj; 12987 xmlNodeSetPtr oldset; 12988 xmlNodePtr oldnode; 12989 xmlDocPtr oldDoc; 12990 int i; 12991 12992 CHECK_ERROR0; 12993 comp = ctxt->comp; 12994 /* 12995 * Optimization for ()[last()] selection i.e. the last elem 12996 */ 12997 if ((op->ch1 != -1) && (op->ch2 != -1) && 12998 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 12999 (comp->steps[op->ch2].op == XPATH_OP_SORT)) { 13000 int f = comp->steps[op->ch2].ch1; 13001 13002 if ((f != -1) && 13003 (comp->steps[f].op == XPATH_OP_FUNCTION) && 13004 (comp->steps[f].value5 == NULL) && 13005 (comp->steps[f].value == 0) && 13006 (comp->steps[f].value4 != NULL) && 13007 (xmlStrEqual 13008 (comp->steps[f].value4, BAD_CAST "last"))) { 13009 xmlNodePtr last = NULL; 13010 13011 total += 13012 xmlXPathCompOpEvalLast(ctxt, 13013 &comp->steps[op->ch1], 13014 &last); 13015 CHECK_ERROR0; 13016 /* 13017 * The nodeset should be in document order, 13018 * Keep only the last value 13019 */ 13020 if ((ctxt->value != NULL) && 13021 (ctxt->value->type == XPATH_NODESET) && 13022 (ctxt->value->nodesetval != NULL) && 13023 (ctxt->value->nodesetval->nodeTab != NULL) && 13024 (ctxt->value->nodesetval->nodeNr > 1)) { 13025 ctxt->value->nodesetval->nodeTab[0] = 13026 ctxt->value->nodesetval->nodeTab[ctxt-> 13027 value-> 13028 nodesetval-> 13029 nodeNr - 13030 1]; 13031 ctxt->value->nodesetval->nodeNr = 1; 13032 *first = *(ctxt->value->nodesetval->nodeTab); 13033 } 13034 return (total); 13035 } 13036 } 13037 13038 if (op->ch1 != -1) 13039 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13040 CHECK_ERROR0; 13041 if (op->ch2 == -1) 13042 return (total); 13043 if (ctxt->value == NULL) 13044 return (total); 13045 13046 #ifdef LIBXML_XPTR_ENABLED 13047 oldnode = ctxt->context->node; 13048 /* 13049 * Hum are we filtering the result of an XPointer expression 13050 */ 13051 if (ctxt->value->type == XPATH_LOCATIONSET) { 13052 xmlXPathObjectPtr tmp = NULL; 13053 xmlLocationSetPtr newlocset = NULL; 13054 xmlLocationSetPtr oldlocset; 13055 13056 /* 13057 * Extract the old locset, and then evaluate the result of the 13058 * expression for all the element in the locset. use it to grow 13059 * up a new locset. 13060 */ 13061 CHECK_TYPE0(XPATH_LOCATIONSET); 13062 obj = valuePop(ctxt); 13063 oldlocset = obj->user; 13064 ctxt->context->node = NULL; 13065 13066 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) { 13067 ctxt->context->contextSize = 0; 13068 ctxt->context->proximityPosition = 0; 13069 if (op->ch2 != -1) 13070 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13071 res = valuePop(ctxt); 13072 if (res != NULL) { 13073 xmlXPathReleaseObject(ctxt->context, res); 13074 } 13075 valuePush(ctxt, obj); 13076 CHECK_ERROR0; 13077 return (total); 13078 } 13079 newlocset = xmlXPtrLocationSetCreate(NULL); 13080 13081 for (i = 0; i < oldlocset->locNr; i++) { 13082 /* 13083 * Run the evaluation with a node list made of a 13084 * single item in the nodelocset. 13085 */ 13086 ctxt->context->node = oldlocset->locTab[i]->user; 13087 ctxt->context->contextSize = oldlocset->locNr; 13088 ctxt->context->proximityPosition = i + 1; 13089 if (tmp == NULL) { 13090 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13091 ctxt->context->node); 13092 } else { 13093 if (xmlXPathNodeSetAddUnique(tmp->nodesetval, 13094 ctxt->context->node) < 0) { 13095 ctxt->error = XPATH_MEMORY_ERROR; 13096 } 13097 } 13098 valuePush(ctxt, tmp); 13099 if (op->ch2 != -1) 13100 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13101 if (ctxt->error != XPATH_EXPRESSION_OK) { 13102 xmlXPathFreeObject(obj); 13103 return(0); 13104 } 13105 /* 13106 * The result of the evaluation need to be tested to 13107 * decided whether the filter succeeded or not 13108 */ 13109 res = valuePop(ctxt); 13110 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 13111 xmlXPtrLocationSetAdd(newlocset, 13112 xmlXPathCacheObjectCopy(ctxt->context, 13113 oldlocset->locTab[i])); 13114 } 13115 /* 13116 * Cleanup 13117 */ 13118 if (res != NULL) { 13119 xmlXPathReleaseObject(ctxt->context, res); 13120 } 13121 if (ctxt->value == tmp) { 13122 valuePop(ctxt); 13123 xmlXPathNodeSetClear(tmp->nodesetval, 1); 13124 /* 13125 * REVISIT TODO: Don't create a temporary nodeset 13126 * for everly iteration. 13127 */ 13128 /* OLD: xmlXPathFreeObject(res); */ 13129 } else 13130 tmp = NULL; 13131 ctxt->context->node = NULL; 13132 /* 13133 * Only put the first node in the result, then leave. 13134 */ 13135 if (newlocset->locNr > 0) { 13136 *first = (xmlNodePtr) oldlocset->locTab[i]->user; 13137 break; 13138 } 13139 } 13140 if (tmp != NULL) { 13141 xmlXPathReleaseObject(ctxt->context, tmp); 13142 } 13143 /* 13144 * The result is used as the new evaluation locset. 13145 */ 13146 xmlXPathReleaseObject(ctxt->context, obj); 13147 ctxt->context->node = NULL; 13148 ctxt->context->contextSize = -1; 13149 ctxt->context->proximityPosition = -1; 13150 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset)); 13151 ctxt->context->node = oldnode; 13152 return (total); 13153 } 13154 #endif /* LIBXML_XPTR_ENABLED */ 13155 13156 /* 13157 * Extract the old set, and then evaluate the result of the 13158 * expression for all the element in the set. use it to grow 13159 * up a new set. 13160 */ 13161 CHECK_TYPE0(XPATH_NODESET); 13162 obj = valuePop(ctxt); 13163 oldset = obj->nodesetval; 13164 13165 oldnode = ctxt->context->node; 13166 oldDoc = ctxt->context->doc; 13167 ctxt->context->node = NULL; 13168 13169 if ((oldset == NULL) || (oldset->nodeNr == 0)) { 13170 ctxt->context->contextSize = 0; 13171 ctxt->context->proximityPosition = 0; 13172 /* QUESTION TODO: Why was this code commented out? 13173 if (op->ch2 != -1) 13174 total += 13175 xmlXPathCompOpEval(ctxt, 13176 &comp->steps[op->ch2]); 13177 CHECK_ERROR0; 13178 res = valuePop(ctxt); 13179 if (res != NULL) 13180 xmlXPathFreeObject(res); 13181 */ 13182 valuePush(ctxt, obj); 13183 ctxt->context->node = oldnode; 13184 CHECK_ERROR0; 13185 } else { 13186 xmlNodeSetPtr newset; 13187 xmlXPathObjectPtr tmp = NULL; 13188 /* 13189 * Initialize the new set. 13190 * Also set the xpath document in case things like 13191 * key() evaluation are attempted on the predicate 13192 */ 13193 newset = xmlXPathNodeSetCreate(NULL); 13194 /* XXX what if xmlXPathNodeSetCreate returned NULL? */ 13195 13196 for (i = 0; i < oldset->nodeNr; i++) { 13197 /* 13198 * Run the evaluation with a node list made of 13199 * a single item in the nodeset. 13200 */ 13201 ctxt->context->node = oldset->nodeTab[i]; 13202 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) && 13203 (oldset->nodeTab[i]->doc != NULL)) 13204 ctxt->context->doc = oldset->nodeTab[i]->doc; 13205 if (tmp == NULL) { 13206 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13207 ctxt->context->node); 13208 } else { 13209 if (xmlXPathNodeSetAddUnique(tmp->nodesetval, 13210 ctxt->context->node) < 0) { 13211 ctxt->error = XPATH_MEMORY_ERROR; 13212 } 13213 } 13214 valuePush(ctxt, tmp); 13215 ctxt->context->contextSize = oldset->nodeNr; 13216 ctxt->context->proximityPosition = i + 1; 13217 if (op->ch2 != -1) 13218 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13219 if (ctxt->error != XPATH_EXPRESSION_OK) { 13220 xmlXPathFreeNodeSet(newset); 13221 xmlXPathFreeObject(obj); 13222 return(0); 13223 } 13224 /* 13225 * The result of the evaluation needs to be tested to 13226 * decide whether the filter succeeded or not 13227 */ 13228 res = valuePop(ctxt); 13229 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 13230 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0) 13231 ctxt->error = XPATH_MEMORY_ERROR; 13232 } 13233 /* 13234 * Cleanup 13235 */ 13236 if (res != NULL) { 13237 xmlXPathReleaseObject(ctxt->context, res); 13238 } 13239 if (ctxt->value == tmp) { 13240 valuePop(ctxt); 13241 /* 13242 * Don't free the temporary nodeset 13243 * in order to avoid massive recreation inside this 13244 * loop. 13245 */ 13246 xmlXPathNodeSetClear(tmp->nodesetval, 1); 13247 } else 13248 tmp = NULL; 13249 ctxt->context->node = NULL; 13250 /* 13251 * Only put the first node in the result, then leave. 13252 */ 13253 if (newset->nodeNr > 0) { 13254 *first = *(newset->nodeTab); 13255 break; 13256 } 13257 } 13258 if (tmp != NULL) { 13259 xmlXPathReleaseObject(ctxt->context, tmp); 13260 } 13261 /* 13262 * The result is used as the new evaluation set. 13263 */ 13264 xmlXPathReleaseObject(ctxt->context, obj); 13265 ctxt->context->node = NULL; 13266 ctxt->context->contextSize = -1; 13267 ctxt->context->proximityPosition = -1; 13268 /* may want to move this past the '}' later */ 13269 ctxt->context->doc = oldDoc; 13270 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset)); 13271 } 13272 ctxt->context->node = oldnode; 13273 return(total); 13274 } 13275 #endif /* XP_OPTIMIZED_FILTER_FIRST */ 13276 13277 /** 13278 * xmlXPathCompOpEval: 13279 * @ctxt: the XPath parser context with the compiled expression 13280 * @op: an XPath compiled operation 13281 * 13282 * Evaluate the Precompiled XPath operation 13283 * Returns the number of nodes traversed 13284 */ 13285 static int 13286 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) 13287 { 13288 int total = 0; 13289 int equal, ret; 13290 xmlXPathCompExprPtr comp; 13291 xmlXPathObjectPtr arg1, arg2; 13292 xmlNodePtr bak; 13293 xmlDocPtr bakd; 13294 int pp; 13295 int cs; 13296 13297 CHECK_ERROR0; 13298 comp = ctxt->comp; 13299 switch (op->op) { 13300 case XPATH_OP_END: 13301 return (0); 13302 case XPATH_OP_AND: 13303 bakd = ctxt->context->doc; 13304 bak = ctxt->context->node; 13305 pp = ctxt->context->proximityPosition; 13306 cs = ctxt->context->contextSize; 13307 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13308 CHECK_ERROR0; 13309 xmlXPathBooleanFunction(ctxt, 1); 13310 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0)) 13311 return (total); 13312 arg2 = valuePop(ctxt); 13313 ctxt->context->doc = bakd; 13314 ctxt->context->node = bak; 13315 ctxt->context->proximityPosition = pp; 13316 ctxt->context->contextSize = cs; 13317 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13318 if (ctxt->error) { 13319 xmlXPathFreeObject(arg2); 13320 return(0); 13321 } 13322 xmlXPathBooleanFunction(ctxt, 1); 13323 arg1 = valuePop(ctxt); 13324 arg1->boolval &= arg2->boolval; 13325 valuePush(ctxt, arg1); 13326 xmlXPathReleaseObject(ctxt->context, arg2); 13327 return (total); 13328 case XPATH_OP_OR: 13329 bakd = ctxt->context->doc; 13330 bak = ctxt->context->node; 13331 pp = ctxt->context->proximityPosition; 13332 cs = ctxt->context->contextSize; 13333 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13334 CHECK_ERROR0; 13335 xmlXPathBooleanFunction(ctxt, 1); 13336 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1)) 13337 return (total); 13338 arg2 = valuePop(ctxt); 13339 ctxt->context->doc = bakd; 13340 ctxt->context->node = bak; 13341 ctxt->context->proximityPosition = pp; 13342 ctxt->context->contextSize = cs; 13343 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13344 if (ctxt->error) { 13345 xmlXPathFreeObject(arg2); 13346 return(0); 13347 } 13348 xmlXPathBooleanFunction(ctxt, 1); 13349 arg1 = valuePop(ctxt); 13350 arg1->boolval |= arg2->boolval; 13351 valuePush(ctxt, arg1); 13352 xmlXPathReleaseObject(ctxt->context, arg2); 13353 return (total); 13354 case XPATH_OP_EQUAL: 13355 bakd = ctxt->context->doc; 13356 bak = ctxt->context->node; 13357 pp = ctxt->context->proximityPosition; 13358 cs = ctxt->context->contextSize; 13359 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13360 CHECK_ERROR0; 13361 ctxt->context->doc = bakd; 13362 ctxt->context->node = bak; 13363 ctxt->context->proximityPosition = pp; 13364 ctxt->context->contextSize = cs; 13365 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13366 CHECK_ERROR0; 13367 if (op->value) 13368 equal = xmlXPathEqualValues(ctxt); 13369 else 13370 equal = xmlXPathNotEqualValues(ctxt); 13371 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal)); 13372 return (total); 13373 case XPATH_OP_CMP: 13374 bakd = ctxt->context->doc; 13375 bak = ctxt->context->node; 13376 pp = ctxt->context->proximityPosition; 13377 cs = ctxt->context->contextSize; 13378 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13379 CHECK_ERROR0; 13380 ctxt->context->doc = bakd; 13381 ctxt->context->node = bak; 13382 ctxt->context->proximityPosition = pp; 13383 ctxt->context->contextSize = cs; 13384 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13385 CHECK_ERROR0; 13386 ret = xmlXPathCompareValues(ctxt, op->value, op->value2); 13387 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret)); 13388 return (total); 13389 case XPATH_OP_PLUS: 13390 bakd = ctxt->context->doc; 13391 bak = ctxt->context->node; 13392 pp = ctxt->context->proximityPosition; 13393 cs = ctxt->context->contextSize; 13394 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13395 CHECK_ERROR0; 13396 if (op->ch2 != -1) { 13397 ctxt->context->doc = bakd; 13398 ctxt->context->node = bak; 13399 ctxt->context->proximityPosition = pp; 13400 ctxt->context->contextSize = cs; 13401 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13402 } 13403 CHECK_ERROR0; 13404 if (op->value == 0) 13405 xmlXPathSubValues(ctxt); 13406 else if (op->value == 1) 13407 xmlXPathAddValues(ctxt); 13408 else if (op->value == 2) 13409 xmlXPathValueFlipSign(ctxt); 13410 else if (op->value == 3) { 13411 CAST_TO_NUMBER; 13412 CHECK_TYPE0(XPATH_NUMBER); 13413 } 13414 return (total); 13415 case XPATH_OP_MULT: 13416 bakd = ctxt->context->doc; 13417 bak = ctxt->context->node; 13418 pp = ctxt->context->proximityPosition; 13419 cs = ctxt->context->contextSize; 13420 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13421 CHECK_ERROR0; 13422 ctxt->context->doc = bakd; 13423 ctxt->context->node = bak; 13424 ctxt->context->proximityPosition = pp; 13425 ctxt->context->contextSize = cs; 13426 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13427 CHECK_ERROR0; 13428 if (op->value == 0) 13429 xmlXPathMultValues(ctxt); 13430 else if (op->value == 1) 13431 xmlXPathDivValues(ctxt); 13432 else if (op->value == 2) 13433 xmlXPathModValues(ctxt); 13434 return (total); 13435 case XPATH_OP_UNION: 13436 bakd = ctxt->context->doc; 13437 bak = ctxt->context->node; 13438 pp = ctxt->context->proximityPosition; 13439 cs = ctxt->context->contextSize; 13440 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13441 CHECK_ERROR0; 13442 ctxt->context->doc = bakd; 13443 ctxt->context->node = bak; 13444 ctxt->context->proximityPosition = pp; 13445 ctxt->context->contextSize = cs; 13446 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13447 CHECK_ERROR0; 13448 CHECK_TYPE0(XPATH_NODESET); 13449 arg2 = valuePop(ctxt); 13450 13451 CHECK_TYPE0(XPATH_NODESET); 13452 arg1 = valuePop(ctxt); 13453 13454 if ((arg1->nodesetval == NULL) || 13455 ((arg2->nodesetval != NULL) && 13456 (arg2->nodesetval->nodeNr != 0))) 13457 { 13458 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 13459 arg2->nodesetval); 13460 } 13461 13462 valuePush(ctxt, arg1); 13463 xmlXPathReleaseObject(ctxt->context, arg2); 13464 return (total); 13465 case XPATH_OP_ROOT: 13466 xmlXPathRoot(ctxt); 13467 return (total); 13468 case XPATH_OP_NODE: 13469 if (op->ch1 != -1) 13470 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13471 CHECK_ERROR0; 13472 if (op->ch2 != -1) 13473 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13474 CHECK_ERROR0; 13475 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 13476 ctxt->context->node)); 13477 return (total); 13478 case XPATH_OP_RESET: 13479 if (op->ch1 != -1) 13480 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13481 CHECK_ERROR0; 13482 if (op->ch2 != -1) 13483 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13484 CHECK_ERROR0; 13485 ctxt->context->node = NULL; 13486 return (total); 13487 case XPATH_OP_COLLECT:{ 13488 if (op->ch1 == -1) 13489 return (total); 13490 13491 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13492 CHECK_ERROR0; 13493 13494 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0); 13495 return (total); 13496 } 13497 case XPATH_OP_VALUE: 13498 valuePush(ctxt, 13499 xmlXPathCacheObjectCopy(ctxt->context, 13500 (xmlXPathObjectPtr) op->value4)); 13501 return (total); 13502 case XPATH_OP_VARIABLE:{ 13503 xmlXPathObjectPtr val; 13504 13505 if (op->ch1 != -1) 13506 total += 13507 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13508 if (op->value5 == NULL) { 13509 val = xmlXPathVariableLookup(ctxt->context, op->value4); 13510 if (val == NULL) { 13511 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR; 13512 return(0); 13513 } 13514 valuePush(ctxt, val); 13515 } else { 13516 const xmlChar *URI; 13517 13518 URI = xmlXPathNsLookup(ctxt->context, op->value5); 13519 if (URI == NULL) { 13520 xmlGenericError(xmlGenericErrorContext, 13521 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n", 13522 (char *) op->value4, (char *)op->value5); 13523 ctxt->error = XPATH_UNDEF_PREFIX_ERROR; 13524 return (total); 13525 } 13526 val = xmlXPathVariableLookupNS(ctxt->context, 13527 op->value4, URI); 13528 if (val == NULL) { 13529 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR; 13530 return(0); 13531 } 13532 valuePush(ctxt, val); 13533 } 13534 return (total); 13535 } 13536 case XPATH_OP_FUNCTION:{ 13537 xmlXPathFunction func; 13538 const xmlChar *oldFunc, *oldFuncURI; 13539 int i; 13540 int frame; 13541 13542 frame = xmlXPathSetFrame(ctxt); 13543 if (op->ch1 != -1) { 13544 total += 13545 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13546 if (ctxt->error != XPATH_EXPRESSION_OK) { 13547 xmlXPathPopFrame(ctxt, frame); 13548 return (total); 13549 } 13550 } 13551 if (ctxt->valueNr < ctxt->valueFrame + op->value) { 13552 xmlGenericError(xmlGenericErrorContext, 13553 "xmlXPathCompOpEval: parameter error\n"); 13554 ctxt->error = XPATH_INVALID_OPERAND; 13555 xmlXPathPopFrame(ctxt, frame); 13556 return (total); 13557 } 13558 for (i = 0; i < op->value; i++) { 13559 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) { 13560 xmlGenericError(xmlGenericErrorContext, 13561 "xmlXPathCompOpEval: parameter error\n"); 13562 ctxt->error = XPATH_INVALID_OPERAND; 13563 xmlXPathPopFrame(ctxt, frame); 13564 return (total); 13565 } 13566 } 13567 if (op->cache != NULL) 13568 XML_CAST_FPTR(func) = op->cache; 13569 else { 13570 const xmlChar *URI = NULL; 13571 13572 if (op->value5 == NULL) 13573 func = 13574 xmlXPathFunctionLookup(ctxt->context, 13575 op->value4); 13576 else { 13577 URI = xmlXPathNsLookup(ctxt->context, op->value5); 13578 if (URI == NULL) { 13579 xmlGenericError(xmlGenericErrorContext, 13580 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n", 13581 (char *)op->value4, (char *)op->value5); 13582 xmlXPathPopFrame(ctxt, frame); 13583 ctxt->error = XPATH_UNDEF_PREFIX_ERROR; 13584 return (total); 13585 } 13586 func = xmlXPathFunctionLookupNS(ctxt->context, 13587 op->value4, URI); 13588 } 13589 if (func == NULL) { 13590 xmlGenericError(xmlGenericErrorContext, 13591 "xmlXPathCompOpEval: function %s not found\n", 13592 (char *)op->value4); 13593 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR); 13594 } 13595 op->cache = XML_CAST_FPTR(func); 13596 op->cacheURI = (void *) URI; 13597 } 13598 oldFunc = ctxt->context->function; 13599 oldFuncURI = ctxt->context->functionURI; 13600 ctxt->context->function = op->value4; 13601 ctxt->context->functionURI = op->cacheURI; 13602 func(ctxt, op->value); 13603 ctxt->context->function = oldFunc; 13604 ctxt->context->functionURI = oldFuncURI; 13605 xmlXPathPopFrame(ctxt, frame); 13606 return (total); 13607 } 13608 case XPATH_OP_ARG: 13609 bakd = ctxt->context->doc; 13610 bak = ctxt->context->node; 13611 pp = ctxt->context->proximityPosition; 13612 cs = ctxt->context->contextSize; 13613 if (op->ch1 != -1) { 13614 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13615 ctxt->context->contextSize = cs; 13616 ctxt->context->proximityPosition = pp; 13617 ctxt->context->node = bak; 13618 ctxt->context->doc = bakd; 13619 CHECK_ERROR0; 13620 } 13621 if (op->ch2 != -1) { 13622 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13623 ctxt->context->contextSize = cs; 13624 ctxt->context->proximityPosition = pp; 13625 ctxt->context->node = bak; 13626 ctxt->context->doc = bakd; 13627 CHECK_ERROR0; 13628 } 13629 return (total); 13630 case XPATH_OP_PREDICATE: 13631 case XPATH_OP_FILTER:{ 13632 xmlXPathObjectPtr res; 13633 xmlXPathObjectPtr obj, tmp; 13634 xmlNodeSetPtr newset = NULL; 13635 xmlNodeSetPtr oldset; 13636 xmlNodePtr oldnode; 13637 xmlDocPtr oldDoc; 13638 int i; 13639 13640 /* 13641 * Optimization for ()[1] selection i.e. the first elem 13642 */ 13643 if ((op->ch1 != -1) && (op->ch2 != -1) && 13644 #ifdef XP_OPTIMIZED_FILTER_FIRST 13645 /* 13646 * FILTER TODO: Can we assume that the inner processing 13647 * will result in an ordered list if we have an 13648 * XPATH_OP_FILTER? 13649 * What about an additional field or flag on 13650 * xmlXPathObject like @sorted ? This way we wouln'd need 13651 * to assume anything, so it would be more robust and 13652 * easier to optimize. 13653 */ 13654 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */ 13655 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */ 13656 #else 13657 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 13658 #endif 13659 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */ 13660 xmlXPathObjectPtr val; 13661 13662 val = comp->steps[op->ch2].value4; 13663 if ((val != NULL) && (val->type == XPATH_NUMBER) && 13664 (val->floatval == 1.0)) { 13665 xmlNodePtr first = NULL; 13666 13667 total += 13668 xmlXPathCompOpEvalFirst(ctxt, 13669 &comp->steps[op->ch1], 13670 &first); 13671 CHECK_ERROR0; 13672 /* 13673 * The nodeset should be in document order, 13674 * Keep only the first value 13675 */ 13676 if ((ctxt->value != NULL) && 13677 (ctxt->value->type == XPATH_NODESET) && 13678 (ctxt->value->nodesetval != NULL) && 13679 (ctxt->value->nodesetval->nodeNr > 1)) 13680 ctxt->value->nodesetval->nodeNr = 1; 13681 return (total); 13682 } 13683 } 13684 /* 13685 * Optimization for ()[last()] selection i.e. the last elem 13686 */ 13687 if ((op->ch1 != -1) && (op->ch2 != -1) && 13688 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 13689 (comp->steps[op->ch2].op == XPATH_OP_SORT)) { 13690 int f = comp->steps[op->ch2].ch1; 13691 13692 if ((f != -1) && 13693 (comp->steps[f].op == XPATH_OP_FUNCTION) && 13694 (comp->steps[f].value5 == NULL) && 13695 (comp->steps[f].value == 0) && 13696 (comp->steps[f].value4 != NULL) && 13697 (xmlStrEqual 13698 (comp->steps[f].value4, BAD_CAST "last"))) { 13699 xmlNodePtr last = NULL; 13700 13701 total += 13702 xmlXPathCompOpEvalLast(ctxt, 13703 &comp->steps[op->ch1], 13704 &last); 13705 CHECK_ERROR0; 13706 /* 13707 * The nodeset should be in document order, 13708 * Keep only the last value 13709 */ 13710 if ((ctxt->value != NULL) && 13711 (ctxt->value->type == XPATH_NODESET) && 13712 (ctxt->value->nodesetval != NULL) && 13713 (ctxt->value->nodesetval->nodeTab != NULL) && 13714 (ctxt->value->nodesetval->nodeNr > 1)) { 13715 ctxt->value->nodesetval->nodeTab[0] = 13716 ctxt->value->nodesetval->nodeTab[ctxt-> 13717 value-> 13718 nodesetval-> 13719 nodeNr - 13720 1]; 13721 ctxt->value->nodesetval->nodeNr = 1; 13722 } 13723 return (total); 13724 } 13725 } 13726 /* 13727 * Process inner predicates first. 13728 * Example "index[parent::book][1]": 13729 * ... 13730 * PREDICATE <-- we are here "[1]" 13731 * PREDICATE <-- process "[parent::book]" first 13732 * SORT 13733 * COLLECT 'parent' 'name' 'node' book 13734 * NODE 13735 * ELEM Object is a number : 1 13736 */ 13737 if (op->ch1 != -1) 13738 total += 13739 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13740 CHECK_ERROR0; 13741 if (op->ch2 == -1) 13742 return (total); 13743 if (ctxt->value == NULL) 13744 return (total); 13745 13746 oldnode = ctxt->context->node; 13747 13748 #ifdef LIBXML_XPTR_ENABLED 13749 /* 13750 * Hum are we filtering the result of an XPointer expression 13751 */ 13752 if (ctxt->value->type == XPATH_LOCATIONSET) { 13753 xmlLocationSetPtr newlocset = NULL; 13754 xmlLocationSetPtr oldlocset; 13755 13756 /* 13757 * Extract the old locset, and then evaluate the result of the 13758 * expression for all the element in the locset. use it to grow 13759 * up a new locset. 13760 */ 13761 CHECK_TYPE0(XPATH_LOCATIONSET); 13762 obj = valuePop(ctxt); 13763 oldlocset = obj->user; 13764 ctxt->context->node = NULL; 13765 13766 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) { 13767 ctxt->context->contextSize = 0; 13768 ctxt->context->proximityPosition = 0; 13769 if (op->ch2 != -1) 13770 total += 13771 xmlXPathCompOpEval(ctxt, 13772 &comp->steps[op->ch2]); 13773 res = valuePop(ctxt); 13774 if (res != NULL) { 13775 xmlXPathReleaseObject(ctxt->context, res); 13776 } 13777 valuePush(ctxt, obj); 13778 CHECK_ERROR0; 13779 return (total); 13780 } 13781 newlocset = xmlXPtrLocationSetCreate(NULL); 13782 13783 for (i = 0; i < oldlocset->locNr; i++) { 13784 /* 13785 * Run the evaluation with a node list made of a 13786 * single item in the nodelocset. 13787 */ 13788 ctxt->context->node = oldlocset->locTab[i]->user; 13789 ctxt->context->contextSize = oldlocset->locNr; 13790 ctxt->context->proximityPosition = i + 1; 13791 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13792 ctxt->context->node); 13793 valuePush(ctxt, tmp); 13794 13795 if (op->ch2 != -1) 13796 total += 13797 xmlXPathCompOpEval(ctxt, 13798 &comp->steps[op->ch2]); 13799 if (ctxt->error != XPATH_EXPRESSION_OK) { 13800 xmlXPathFreeObject(obj); 13801 return(0); 13802 } 13803 13804 /* 13805 * The result of the evaluation need to be tested to 13806 * decided whether the filter succeeded or not 13807 */ 13808 res = valuePop(ctxt); 13809 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 13810 xmlXPtrLocationSetAdd(newlocset, 13811 xmlXPathObjectCopy 13812 (oldlocset->locTab[i])); 13813 } 13814 13815 /* 13816 * Cleanup 13817 */ 13818 if (res != NULL) { 13819 xmlXPathReleaseObject(ctxt->context, res); 13820 } 13821 if (ctxt->value == tmp) { 13822 res = valuePop(ctxt); 13823 xmlXPathReleaseObject(ctxt->context, res); 13824 } 13825 13826 ctxt->context->node = NULL; 13827 } 13828 13829 /* 13830 * The result is used as the new evaluation locset. 13831 */ 13832 xmlXPathReleaseObject(ctxt->context, obj); 13833 ctxt->context->node = NULL; 13834 ctxt->context->contextSize = -1; 13835 ctxt->context->proximityPosition = -1; 13836 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset)); 13837 ctxt->context->node = oldnode; 13838 return (total); 13839 } 13840 #endif /* LIBXML_XPTR_ENABLED */ 13841 13842 /* 13843 * Extract the old set, and then evaluate the result of the 13844 * expression for all the element in the set. use it to grow 13845 * up a new set. 13846 */ 13847 CHECK_TYPE0(XPATH_NODESET); 13848 obj = valuePop(ctxt); 13849 oldset = obj->nodesetval; 13850 13851 oldnode = ctxt->context->node; 13852 oldDoc = ctxt->context->doc; 13853 ctxt->context->node = NULL; 13854 13855 if ((oldset == NULL) || (oldset->nodeNr == 0)) { 13856 ctxt->context->contextSize = 0; 13857 ctxt->context->proximityPosition = 0; 13858 /* 13859 if (op->ch2 != -1) 13860 total += 13861 xmlXPathCompOpEval(ctxt, 13862 &comp->steps[op->ch2]); 13863 CHECK_ERROR0; 13864 res = valuePop(ctxt); 13865 if (res != NULL) 13866 xmlXPathFreeObject(res); 13867 */ 13868 valuePush(ctxt, obj); 13869 ctxt->context->node = oldnode; 13870 CHECK_ERROR0; 13871 } else { 13872 tmp = NULL; 13873 /* 13874 * Initialize the new set. 13875 * Also set the xpath document in case things like 13876 * key() evaluation are attempted on the predicate 13877 */ 13878 newset = xmlXPathNodeSetCreate(NULL); 13879 /* 13880 * SPEC XPath 1.0: 13881 * "For each node in the node-set to be filtered, the 13882 * PredicateExpr is evaluated with that node as the 13883 * context node, with the number of nodes in the 13884 * node-set as the context size, and with the proximity 13885 * position of the node in the node-set with respect to 13886 * the axis as the context position;" 13887 * @oldset is the node-set" to be filtered. 13888 * 13889 * SPEC XPath 1.0: 13890 * "only predicates change the context position and 13891 * context size (see [2.4 Predicates])." 13892 * Example: 13893 * node-set context pos 13894 * nA 1 13895 * nB 2 13896 * nC 3 13897 * After applying predicate [position() > 1] : 13898 * node-set context pos 13899 * nB 1 13900 * nC 2 13901 * 13902 * removed the first node in the node-set, then 13903 * the context position of the 13904 */ 13905 for (i = 0; i < oldset->nodeNr; i++) { 13906 /* 13907 * Run the evaluation with a node list made of 13908 * a single item in the nodeset. 13909 */ 13910 ctxt->context->node = oldset->nodeTab[i]; 13911 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) && 13912 (oldset->nodeTab[i]->doc != NULL)) 13913 ctxt->context->doc = oldset->nodeTab[i]->doc; 13914 if (tmp == NULL) { 13915 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13916 ctxt->context->node); 13917 } else { 13918 if (xmlXPathNodeSetAddUnique(tmp->nodesetval, 13919 ctxt->context->node) < 0) { 13920 ctxt->error = XPATH_MEMORY_ERROR; 13921 } 13922 } 13923 valuePush(ctxt, tmp); 13924 ctxt->context->contextSize = oldset->nodeNr; 13925 ctxt->context->proximityPosition = i + 1; 13926 /* 13927 * Evaluate the predicate against the context node. 13928 * Can/should we optimize position() predicates 13929 * here (e.g. "[1]")? 13930 */ 13931 if (op->ch2 != -1) 13932 total += 13933 xmlXPathCompOpEval(ctxt, 13934 &comp->steps[op->ch2]); 13935 if (ctxt->error != XPATH_EXPRESSION_OK) { 13936 xmlXPathFreeNodeSet(newset); 13937 xmlXPathFreeObject(obj); 13938 return(0); 13939 } 13940 13941 /* 13942 * The result of the evaluation needs to be tested to 13943 * decide whether the filter succeeded or not 13944 */ 13945 /* 13946 * OPTIMIZE TODO: Can we use 13947 * xmlXPathNodeSetAdd*Unique()* instead? 13948 */ 13949 res = valuePop(ctxt); 13950 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 13951 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) 13952 < 0) 13953 ctxt->error = XPATH_MEMORY_ERROR; 13954 } 13955 13956 /* 13957 * Cleanup 13958 */ 13959 if (res != NULL) { 13960 xmlXPathReleaseObject(ctxt->context, res); 13961 } 13962 if (ctxt->value == tmp) { 13963 valuePop(ctxt); 13964 xmlXPathNodeSetClear(tmp->nodesetval, 1); 13965 /* 13966 * Don't free the temporary nodeset 13967 * in order to avoid massive recreation inside this 13968 * loop. 13969 */ 13970 } else 13971 tmp = NULL; 13972 ctxt->context->node = NULL; 13973 } 13974 if (tmp != NULL) 13975 xmlXPathReleaseObject(ctxt->context, tmp); 13976 /* 13977 * The result is used as the new evaluation set. 13978 */ 13979 xmlXPathReleaseObject(ctxt->context, obj); 13980 ctxt->context->node = NULL; 13981 ctxt->context->contextSize = -1; 13982 ctxt->context->proximityPosition = -1; 13983 /* may want to move this past the '}' later */ 13984 ctxt->context->doc = oldDoc; 13985 valuePush(ctxt, 13986 xmlXPathCacheWrapNodeSet(ctxt->context, newset)); 13987 } 13988 ctxt->context->node = oldnode; 13989 return (total); 13990 } 13991 case XPATH_OP_SORT: 13992 if (op->ch1 != -1) 13993 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13994 CHECK_ERROR0; 13995 if ((ctxt->value != NULL) && 13996 (ctxt->value->type == XPATH_NODESET) && 13997 (ctxt->value->nodesetval != NULL) && 13998 (ctxt->value->nodesetval->nodeNr > 1)) 13999 { 14000 xmlXPathNodeSetSort(ctxt->value->nodesetval); 14001 } 14002 return (total); 14003 #ifdef LIBXML_XPTR_ENABLED 14004 case XPATH_OP_RANGETO:{ 14005 xmlXPathObjectPtr range; 14006 xmlXPathObjectPtr res, obj; 14007 xmlXPathObjectPtr tmp; 14008 xmlLocationSetPtr newlocset = NULL; 14009 xmlLocationSetPtr oldlocset; 14010 xmlNodeSetPtr oldset; 14011 int i, j; 14012 14013 if (op->ch1 != -1) { 14014 total += 14015 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 14016 CHECK_ERROR0; 14017 } 14018 if (ctxt->value == NULL) { 14019 XP_ERROR0(XPATH_INVALID_OPERAND); 14020 } 14021 if (op->ch2 == -1) 14022 return (total); 14023 14024 if (ctxt->value->type == XPATH_LOCATIONSET) { 14025 /* 14026 * Extract the old locset, and then evaluate the result of the 14027 * expression for all the element in the locset. use it to grow 14028 * up a new locset. 14029 */ 14030 CHECK_TYPE0(XPATH_LOCATIONSET); 14031 obj = valuePop(ctxt); 14032 oldlocset = obj->user; 14033 14034 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) { 14035 ctxt->context->node = NULL; 14036 ctxt->context->contextSize = 0; 14037 ctxt->context->proximityPosition = 0; 14038 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]); 14039 res = valuePop(ctxt); 14040 if (res != NULL) { 14041 xmlXPathReleaseObject(ctxt->context, res); 14042 } 14043 valuePush(ctxt, obj); 14044 CHECK_ERROR0; 14045 return (total); 14046 } 14047 newlocset = xmlXPtrLocationSetCreate(NULL); 14048 14049 for (i = 0; i < oldlocset->locNr; i++) { 14050 /* 14051 * Run the evaluation with a node list made of a 14052 * single item in the nodelocset. 14053 */ 14054 ctxt->context->node = oldlocset->locTab[i]->user; 14055 ctxt->context->contextSize = oldlocset->locNr; 14056 ctxt->context->proximityPosition = i + 1; 14057 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 14058 ctxt->context->node); 14059 valuePush(ctxt, tmp); 14060 14061 if (op->ch2 != -1) 14062 total += 14063 xmlXPathCompOpEval(ctxt, 14064 &comp->steps[op->ch2]); 14065 if (ctxt->error != XPATH_EXPRESSION_OK) { 14066 xmlXPathFreeObject(obj); 14067 return(0); 14068 } 14069 14070 res = valuePop(ctxt); 14071 if (res->type == XPATH_LOCATIONSET) { 14072 xmlLocationSetPtr rloc = 14073 (xmlLocationSetPtr)res->user; 14074 for (j=0; j<rloc->locNr; j++) { 14075 range = xmlXPtrNewRange( 14076 oldlocset->locTab[i]->user, 14077 oldlocset->locTab[i]->index, 14078 rloc->locTab[j]->user2, 14079 rloc->locTab[j]->index2); 14080 if (range != NULL) { 14081 xmlXPtrLocationSetAdd(newlocset, range); 14082 } 14083 } 14084 } else { 14085 range = xmlXPtrNewRangeNodeObject( 14086 (xmlNodePtr)oldlocset->locTab[i]->user, res); 14087 if (range != NULL) { 14088 xmlXPtrLocationSetAdd(newlocset,range); 14089 } 14090 } 14091 14092 /* 14093 * Cleanup 14094 */ 14095 if (res != NULL) { 14096 xmlXPathReleaseObject(ctxt->context, res); 14097 } 14098 if (ctxt->value == tmp) { 14099 res = valuePop(ctxt); 14100 xmlXPathReleaseObject(ctxt->context, res); 14101 } 14102 14103 ctxt->context->node = NULL; 14104 } 14105 } else { /* Not a location set */ 14106 CHECK_TYPE0(XPATH_NODESET); 14107 obj = valuePop(ctxt); 14108 oldset = obj->nodesetval; 14109 ctxt->context->node = NULL; 14110 14111 newlocset = xmlXPtrLocationSetCreate(NULL); 14112 14113 if (oldset != NULL) { 14114 for (i = 0; i < oldset->nodeNr; i++) { 14115 /* 14116 * Run the evaluation with a node list made of a single item 14117 * in the nodeset. 14118 */ 14119 ctxt->context->node = oldset->nodeTab[i]; 14120 /* 14121 * OPTIMIZE TODO: Avoid recreation for every iteration. 14122 */ 14123 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 14124 ctxt->context->node); 14125 valuePush(ctxt, tmp); 14126 14127 if (op->ch2 != -1) 14128 total += 14129 xmlXPathCompOpEval(ctxt, 14130 &comp->steps[op->ch2]); 14131 if (ctxt->error != XPATH_EXPRESSION_OK) { 14132 xmlXPathFreeObject(obj); 14133 return(0); 14134 } 14135 14136 res = valuePop(ctxt); 14137 range = 14138 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i], 14139 res); 14140 if (range != NULL) { 14141 xmlXPtrLocationSetAdd(newlocset, range); 14142 } 14143 14144 /* 14145 * Cleanup 14146 */ 14147 if (res != NULL) { 14148 xmlXPathReleaseObject(ctxt->context, res); 14149 } 14150 if (ctxt->value == tmp) { 14151 res = valuePop(ctxt); 14152 xmlXPathReleaseObject(ctxt->context, res); 14153 } 14154 14155 ctxt->context->node = NULL; 14156 } 14157 } 14158 } 14159 14160 /* 14161 * The result is used as the new evaluation set. 14162 */ 14163 xmlXPathReleaseObject(ctxt->context, obj); 14164 ctxt->context->node = NULL; 14165 ctxt->context->contextSize = -1; 14166 ctxt->context->proximityPosition = -1; 14167 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset)); 14168 return (total); 14169 } 14170 #endif /* LIBXML_XPTR_ENABLED */ 14171 } 14172 xmlGenericError(xmlGenericErrorContext, 14173 "XPath: unknown precompiled operation %d\n", op->op); 14174 ctxt->error = XPATH_INVALID_OPERAND; 14175 return (total); 14176 } 14177 14178 /** 14179 * xmlXPathCompOpEvalToBoolean: 14180 * @ctxt: the XPath parser context 14181 * 14182 * Evaluates if the expression evaluates to true. 14183 * 14184 * Returns 1 if true, 0 if false and -1 on API or internal errors. 14185 */ 14186 static int 14187 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt, 14188 xmlXPathStepOpPtr op, 14189 int isPredicate) 14190 { 14191 xmlXPathObjectPtr resObj = NULL; 14192 14193 start: 14194 /* comp = ctxt->comp; */ 14195 switch (op->op) { 14196 case XPATH_OP_END: 14197 return (0); 14198 case XPATH_OP_VALUE: 14199 resObj = (xmlXPathObjectPtr) op->value4; 14200 if (isPredicate) 14201 return(xmlXPathEvaluatePredicateResult(ctxt, resObj)); 14202 return(xmlXPathCastToBoolean(resObj)); 14203 case XPATH_OP_SORT: 14204 /* 14205 * We don't need sorting for boolean results. Skip this one. 14206 */ 14207 if (op->ch1 != -1) { 14208 op = &ctxt->comp->steps[op->ch1]; 14209 goto start; 14210 } 14211 return(0); 14212 case XPATH_OP_COLLECT: 14213 if (op->ch1 == -1) 14214 return(0); 14215 14216 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]); 14217 if (ctxt->error != XPATH_EXPRESSION_OK) 14218 return(-1); 14219 14220 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1); 14221 if (ctxt->error != XPATH_EXPRESSION_OK) 14222 return(-1); 14223 14224 resObj = valuePop(ctxt); 14225 if (resObj == NULL) 14226 return(-1); 14227 break; 14228 default: 14229 /* 14230 * Fallback to call xmlXPathCompOpEval(). 14231 */ 14232 xmlXPathCompOpEval(ctxt, op); 14233 if (ctxt->error != XPATH_EXPRESSION_OK) 14234 return(-1); 14235 14236 resObj = valuePop(ctxt); 14237 if (resObj == NULL) 14238 return(-1); 14239 break; 14240 } 14241 14242 if (resObj) { 14243 int res; 14244 14245 if (resObj->type == XPATH_BOOLEAN) { 14246 res = resObj->boolval; 14247 } else if (isPredicate) { 14248 /* 14249 * For predicates a result of type "number" is handled 14250 * differently: 14251 * SPEC XPath 1.0: 14252 * "If the result is a number, the result will be converted 14253 * to true if the number is equal to the context position 14254 * and will be converted to false otherwise;" 14255 */ 14256 res = xmlXPathEvaluatePredicateResult(ctxt, resObj); 14257 } else { 14258 res = xmlXPathCastToBoolean(resObj); 14259 } 14260 xmlXPathReleaseObject(ctxt->context, resObj); 14261 return(res); 14262 } 14263 14264 return(0); 14265 } 14266 14267 #ifdef XPATH_STREAMING 14268 /** 14269 * xmlXPathRunStreamEval: 14270 * @ctxt: the XPath parser context with the compiled expression 14271 * 14272 * Evaluate the Precompiled Streamable XPath expression in the given context. 14273 */ 14274 static int 14275 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp, 14276 xmlXPathObjectPtr *resultSeq, int toBool) 14277 { 14278 int max_depth, min_depth; 14279 int from_root; 14280 int ret, depth; 14281 int eval_all_nodes; 14282 xmlNodePtr cur = NULL, limit = NULL; 14283 xmlStreamCtxtPtr patstream = NULL; 14284 14285 int nb_nodes = 0; 14286 14287 if ((ctxt == NULL) || (comp == NULL)) 14288 return(-1); 14289 max_depth = xmlPatternMaxDepth(comp); 14290 if (max_depth == -1) 14291 return(-1); 14292 if (max_depth == -2) 14293 max_depth = 10000; 14294 min_depth = xmlPatternMinDepth(comp); 14295 if (min_depth == -1) 14296 return(-1); 14297 from_root = xmlPatternFromRoot(comp); 14298 if (from_root < 0) 14299 return(-1); 14300 #if 0 14301 printf("stream eval: depth %d from root %d\n", max_depth, from_root); 14302 #endif 14303 14304 if (! toBool) { 14305 if (resultSeq == NULL) 14306 return(-1); 14307 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL); 14308 if (*resultSeq == NULL) 14309 return(-1); 14310 } 14311 14312 /* 14313 * handle the special cases of "/" amd "." being matched 14314 */ 14315 if (min_depth == 0) { 14316 if (from_root) { 14317 /* Select "/" */ 14318 if (toBool) 14319 return(1); 14320 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, 14321 (xmlNodePtr) ctxt->doc); 14322 } else { 14323 /* Select "self::node()" */ 14324 if (toBool) 14325 return(1); 14326 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node); 14327 } 14328 } 14329 if (max_depth == 0) { 14330 return(0); 14331 } 14332 14333 if (from_root) { 14334 cur = (xmlNodePtr)ctxt->doc; 14335 } else if (ctxt->node != NULL) { 14336 switch (ctxt->node->type) { 14337 case XML_ELEMENT_NODE: 14338 case XML_DOCUMENT_NODE: 14339 case XML_DOCUMENT_FRAG_NODE: 14340 case XML_HTML_DOCUMENT_NODE: 14341 #ifdef LIBXML_DOCB_ENABLED 14342 case XML_DOCB_DOCUMENT_NODE: 14343 #endif 14344 cur = ctxt->node; 14345 break; 14346 case XML_ATTRIBUTE_NODE: 14347 case XML_TEXT_NODE: 14348 case XML_CDATA_SECTION_NODE: 14349 case XML_ENTITY_REF_NODE: 14350 case XML_ENTITY_NODE: 14351 case XML_PI_NODE: 14352 case XML_COMMENT_NODE: 14353 case XML_NOTATION_NODE: 14354 case XML_DTD_NODE: 14355 case XML_DOCUMENT_TYPE_NODE: 14356 case XML_ELEMENT_DECL: 14357 case XML_ATTRIBUTE_DECL: 14358 case XML_ENTITY_DECL: 14359 case XML_NAMESPACE_DECL: 14360 case XML_XINCLUDE_START: 14361 case XML_XINCLUDE_END: 14362 break; 14363 } 14364 limit = cur; 14365 } 14366 if (cur == NULL) { 14367 return(0); 14368 } 14369 14370 patstream = xmlPatternGetStreamCtxt(comp); 14371 if (patstream == NULL) { 14372 /* 14373 * QUESTION TODO: Is this an error? 14374 */ 14375 return(0); 14376 } 14377 14378 eval_all_nodes = xmlStreamWantsAnyNode(patstream); 14379 14380 if (from_root) { 14381 ret = xmlStreamPush(patstream, NULL, NULL); 14382 if (ret < 0) { 14383 } else if (ret == 1) { 14384 if (toBool) 14385 goto return_1; 14386 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur); 14387 } 14388 } 14389 depth = 0; 14390 goto scan_children; 14391 next_node: 14392 do { 14393 nb_nodes++; 14394 14395 switch (cur->type) { 14396 case XML_ELEMENT_NODE: 14397 case XML_TEXT_NODE: 14398 case XML_CDATA_SECTION_NODE: 14399 case XML_COMMENT_NODE: 14400 case XML_PI_NODE: 14401 if (cur->type == XML_ELEMENT_NODE) { 14402 ret = xmlStreamPush(patstream, cur->name, 14403 (cur->ns ? cur->ns->href : NULL)); 14404 } else if (eval_all_nodes) 14405 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type); 14406 else 14407 break; 14408 14409 if (ret < 0) { 14410 /* NOP. */ 14411 } else if (ret == 1) { 14412 if (toBool) 14413 goto return_1; 14414 if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur) 14415 < 0) { 14416 ctxt->lastError.domain = XML_FROM_XPATH; 14417 ctxt->lastError.code = XML_ERR_NO_MEMORY; 14418 } 14419 } 14420 if ((cur->children == NULL) || (depth >= max_depth)) { 14421 ret = xmlStreamPop(patstream); 14422 while (cur->next != NULL) { 14423 cur = cur->next; 14424 if ((cur->type != XML_ENTITY_DECL) && 14425 (cur->type != XML_DTD_NODE)) 14426 goto next_node; 14427 } 14428 } 14429 default: 14430 break; 14431 } 14432 14433 scan_children: 14434 if (cur->type == XML_NAMESPACE_DECL) break; 14435 if ((cur->children != NULL) && (depth < max_depth)) { 14436 /* 14437 * Do not descend on entities declarations 14438 */ 14439 if (cur->children->type != XML_ENTITY_DECL) { 14440 cur = cur->children; 14441 depth++; 14442 /* 14443 * Skip DTDs 14444 */ 14445 if (cur->type != XML_DTD_NODE) 14446 continue; 14447 } 14448 } 14449 14450 if (cur == limit) 14451 break; 14452 14453 while (cur->next != NULL) { 14454 cur = cur->next; 14455 if ((cur->type != XML_ENTITY_DECL) && 14456 (cur->type != XML_DTD_NODE)) 14457 goto next_node; 14458 } 14459 14460 do { 14461 cur = cur->parent; 14462 depth--; 14463 if ((cur == NULL) || (cur == limit)) 14464 goto done; 14465 if (cur->type == XML_ELEMENT_NODE) { 14466 ret = xmlStreamPop(patstream); 14467 } else if ((eval_all_nodes) && 14468 ((cur->type == XML_TEXT_NODE) || 14469 (cur->type == XML_CDATA_SECTION_NODE) || 14470 (cur->type == XML_COMMENT_NODE) || 14471 (cur->type == XML_PI_NODE))) 14472 { 14473 ret = xmlStreamPop(patstream); 14474 } 14475 if (cur->next != NULL) { 14476 cur = cur->next; 14477 break; 14478 } 14479 } while (cur != NULL); 14480 14481 } while ((cur != NULL) && (depth >= 0)); 14482 14483 done: 14484 14485 #if 0 14486 printf("stream eval: checked %d nodes selected %d\n", 14487 nb_nodes, retObj->nodesetval->nodeNr); 14488 #endif 14489 14490 if (patstream) 14491 xmlFreeStreamCtxt(patstream); 14492 return(0); 14493 14494 return_1: 14495 if (patstream) 14496 xmlFreeStreamCtxt(patstream); 14497 return(1); 14498 } 14499 #endif /* XPATH_STREAMING */ 14500 14501 /** 14502 * xmlXPathRunEval: 14503 * @ctxt: the XPath parser context with the compiled expression 14504 * @toBool: evaluate to a boolean result 14505 * 14506 * Evaluate the Precompiled XPath expression in the given context. 14507 */ 14508 static int 14509 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool) 14510 { 14511 xmlXPathCompExprPtr comp; 14512 14513 if ((ctxt == NULL) || (ctxt->comp == NULL)) 14514 return(-1); 14515 14516 if (ctxt->valueTab == NULL) { 14517 /* Allocate the value stack */ 14518 ctxt->valueTab = (xmlXPathObjectPtr *) 14519 xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); 14520 if (ctxt->valueTab == NULL) { 14521 xmlXPathPErrMemory(ctxt, "creating evaluation context\n"); 14522 xmlFree(ctxt); 14523 } 14524 ctxt->valueNr = 0; 14525 ctxt->valueMax = 10; 14526 ctxt->value = NULL; 14527 ctxt->valueFrame = 0; 14528 } 14529 #ifdef XPATH_STREAMING 14530 if (ctxt->comp->stream) { 14531 int res; 14532 14533 if (toBool) { 14534 /* 14535 * Evaluation to boolean result. 14536 */ 14537 res = xmlXPathRunStreamEval(ctxt->context, 14538 ctxt->comp->stream, NULL, 1); 14539 if (res != -1) 14540 return(res); 14541 } else { 14542 xmlXPathObjectPtr resObj = NULL; 14543 14544 /* 14545 * Evaluation to a sequence. 14546 */ 14547 res = xmlXPathRunStreamEval(ctxt->context, 14548 ctxt->comp->stream, &resObj, 0); 14549 14550 if ((res != -1) && (resObj != NULL)) { 14551 valuePush(ctxt, resObj); 14552 return(0); 14553 } 14554 if (resObj != NULL) 14555 xmlXPathReleaseObject(ctxt->context, resObj); 14556 } 14557 /* 14558 * QUESTION TODO: This falls back to normal XPath evaluation 14559 * if res == -1. Is this intended? 14560 */ 14561 } 14562 #endif 14563 comp = ctxt->comp; 14564 if (comp->last < 0) { 14565 xmlGenericError(xmlGenericErrorContext, 14566 "xmlXPathRunEval: last is less than zero\n"); 14567 return(-1); 14568 } 14569 if (toBool) 14570 return(xmlXPathCompOpEvalToBoolean(ctxt, 14571 &comp->steps[comp->last], 0)); 14572 else 14573 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]); 14574 14575 return(0); 14576 } 14577 14578 /************************************************************************ 14579 * * 14580 * Public interfaces * 14581 * * 14582 ************************************************************************/ 14583 14584 /** 14585 * xmlXPathEvalPredicate: 14586 * @ctxt: the XPath context 14587 * @res: the Predicate Expression evaluation result 14588 * 14589 * Evaluate a predicate result for the current node. 14590 * A PredicateExpr is evaluated by evaluating the Expr and converting 14591 * the result to a boolean. If the result is a number, the result will 14592 * be converted to true if the number is equal to the position of the 14593 * context node in the context node list (as returned by the position 14594 * function) and will be converted to false otherwise; if the result 14595 * is not a number, then the result will be converted as if by a call 14596 * to the boolean function. 14597 * 14598 * Returns 1 if predicate is true, 0 otherwise 14599 */ 14600 int 14601 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) { 14602 if ((ctxt == NULL) || (res == NULL)) return(0); 14603 switch (res->type) { 14604 case XPATH_BOOLEAN: 14605 return(res->boolval); 14606 case XPATH_NUMBER: 14607 return(res->floatval == ctxt->proximityPosition); 14608 case XPATH_NODESET: 14609 case XPATH_XSLT_TREE: 14610 if (res->nodesetval == NULL) 14611 return(0); 14612 return(res->nodesetval->nodeNr != 0); 14613 case XPATH_STRING: 14614 return((res->stringval != NULL) && 14615 (xmlStrlen(res->stringval) != 0)); 14616 default: 14617 STRANGE 14618 } 14619 return(0); 14620 } 14621 14622 /** 14623 * xmlXPathEvaluatePredicateResult: 14624 * @ctxt: the XPath Parser context 14625 * @res: the Predicate Expression evaluation result 14626 * 14627 * Evaluate a predicate result for the current node. 14628 * A PredicateExpr is evaluated by evaluating the Expr and converting 14629 * the result to a boolean. If the result is a number, the result will 14630 * be converted to true if the number is equal to the position of the 14631 * context node in the context node list (as returned by the position 14632 * function) and will be converted to false otherwise; if the result 14633 * is not a number, then the result will be converted as if by a call 14634 * to the boolean function. 14635 * 14636 * Returns 1 if predicate is true, 0 otherwise 14637 */ 14638 int 14639 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt, 14640 xmlXPathObjectPtr res) { 14641 if ((ctxt == NULL) || (res == NULL)) return(0); 14642 switch (res->type) { 14643 case XPATH_BOOLEAN: 14644 return(res->boolval); 14645 case XPATH_NUMBER: 14646 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200)) 14647 return((res->floatval == ctxt->context->proximityPosition) && 14648 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/ 14649 #else 14650 return(res->floatval == ctxt->context->proximityPosition); 14651 #endif 14652 case XPATH_NODESET: 14653 case XPATH_XSLT_TREE: 14654 if (res->nodesetval == NULL) 14655 return(0); 14656 return(res->nodesetval->nodeNr != 0); 14657 case XPATH_STRING: 14658 return((res->stringval != NULL) && (res->stringval[0] != 0)); 14659 #ifdef LIBXML_XPTR_ENABLED 14660 case XPATH_LOCATIONSET:{ 14661 xmlLocationSetPtr ptr = res->user; 14662 if (ptr == NULL) 14663 return(0); 14664 return (ptr->locNr != 0); 14665 } 14666 #endif 14667 default: 14668 STRANGE 14669 } 14670 return(0); 14671 } 14672 14673 #ifdef XPATH_STREAMING 14674 /** 14675 * xmlXPathTryStreamCompile: 14676 * @ctxt: an XPath context 14677 * @str: the XPath expression 14678 * 14679 * Try to compile the XPath expression as a streamable subset. 14680 * 14681 * Returns the compiled expression or NULL if failed to compile. 14682 */ 14683 static xmlXPathCompExprPtr 14684 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { 14685 /* 14686 * Optimization: use streaming patterns when the XPath expression can 14687 * be compiled to a stream lookup 14688 */ 14689 xmlPatternPtr stream; 14690 xmlXPathCompExprPtr comp; 14691 xmlDictPtr dict = NULL; 14692 const xmlChar **namespaces = NULL; 14693 xmlNsPtr ns; 14694 int i, j; 14695 14696 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) && 14697 (!xmlStrchr(str, '@'))) { 14698 const xmlChar *tmp; 14699 14700 /* 14701 * We don't try to handle expressions using the verbose axis 14702 * specifiers ("::"), just the simplied form at this point. 14703 * Additionally, if there is no list of namespaces available and 14704 * there's a ":" in the expression, indicating a prefixed QName, 14705 * then we won't try to compile either. xmlPatterncompile() needs 14706 * to have a list of namespaces at compilation time in order to 14707 * compile prefixed name tests. 14708 */ 14709 tmp = xmlStrchr(str, ':'); 14710 if ((tmp != NULL) && 14711 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':'))) 14712 return(NULL); 14713 14714 if (ctxt != NULL) { 14715 dict = ctxt->dict; 14716 if (ctxt->nsNr > 0) { 14717 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*)); 14718 if (namespaces == NULL) { 14719 xmlXPathErrMemory(ctxt, "allocating namespaces array\n"); 14720 return(NULL); 14721 } 14722 for (i = 0, j = 0; (j < ctxt->nsNr); j++) { 14723 ns = ctxt->namespaces[j]; 14724 namespaces[i++] = ns->href; 14725 namespaces[i++] = ns->prefix; 14726 } 14727 namespaces[i++] = NULL; 14728 namespaces[i] = NULL; 14729 } 14730 } 14731 14732 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, 14733 &namespaces[0]); 14734 if (namespaces != NULL) { 14735 xmlFree((xmlChar **)namespaces); 14736 } 14737 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) { 14738 comp = xmlXPathNewCompExpr(); 14739 if (comp == NULL) { 14740 xmlXPathErrMemory(ctxt, "allocating streamable expression\n"); 14741 return(NULL); 14742 } 14743 comp->stream = stream; 14744 comp->dict = dict; 14745 if (comp->dict) 14746 xmlDictReference(comp->dict); 14747 return(comp); 14748 } 14749 xmlFreePattern(stream); 14750 } 14751 return(NULL); 14752 } 14753 #endif /* XPATH_STREAMING */ 14754 14755 static void 14756 xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op) 14757 { 14758 /* 14759 * Try to rewrite "descendant-or-self::node()/foo" to an optimized 14760 * internal representation. 14761 */ 14762 14763 if ((op->op == XPATH_OP_COLLECT /* 11 */) && 14764 (op->ch1 != -1) && 14765 (op->ch2 == -1 /* no predicate */)) 14766 { 14767 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1]; 14768 14769 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) && 14770 ((xmlXPathAxisVal) prevop->value == 14771 AXIS_DESCENDANT_OR_SELF) && 14772 (prevop->ch2 == -1) && 14773 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) && 14774 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE)) 14775 { 14776 /* 14777 * This is a "descendant-or-self::node()" without predicates. 14778 * Try to eliminate it. 14779 */ 14780 14781 switch ((xmlXPathAxisVal) op->value) { 14782 case AXIS_CHILD: 14783 case AXIS_DESCENDANT: 14784 /* 14785 * Convert "descendant-or-self::node()/child::" or 14786 * "descendant-or-self::node()/descendant::" to 14787 * "descendant::" 14788 */ 14789 op->ch1 = prevop->ch1; 14790 op->value = AXIS_DESCENDANT; 14791 break; 14792 case AXIS_SELF: 14793 case AXIS_DESCENDANT_OR_SELF: 14794 /* 14795 * Convert "descendant-or-self::node()/self::" or 14796 * "descendant-or-self::node()/descendant-or-self::" to 14797 * to "descendant-or-self::" 14798 */ 14799 op->ch1 = prevop->ch1; 14800 op->value = AXIS_DESCENDANT_OR_SELF; 14801 break; 14802 default: 14803 break; 14804 } 14805 } 14806 } 14807 14808 /* OP_VALUE has invalid ch1. */ 14809 if (op->op == XPATH_OP_VALUE) 14810 return; 14811 14812 /* Recurse */ 14813 if (op->ch1 != -1) 14814 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]); 14815 if (op->ch2 != -1) 14816 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]); 14817 } 14818 14819 /** 14820 * xmlXPathCtxtCompile: 14821 * @ctxt: an XPath context 14822 * @str: the XPath expression 14823 * 14824 * Compile an XPath expression 14825 * 14826 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL. 14827 * the caller has to free the object. 14828 */ 14829 xmlXPathCompExprPtr 14830 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { 14831 xmlXPathParserContextPtr pctxt; 14832 xmlXPathCompExprPtr comp; 14833 14834 #ifdef XPATH_STREAMING 14835 comp = xmlXPathTryStreamCompile(ctxt, str); 14836 if (comp != NULL) 14837 return(comp); 14838 #endif 14839 14840 xmlXPathInit(); 14841 14842 pctxt = xmlXPathNewParserContext(str, ctxt); 14843 if (pctxt == NULL) 14844 return NULL; 14845 xmlXPathCompileExpr(pctxt, 1); 14846 14847 if( pctxt->error != XPATH_EXPRESSION_OK ) 14848 { 14849 xmlXPathFreeParserContext(pctxt); 14850 return(NULL); 14851 } 14852 14853 if (*pctxt->cur != 0) { 14854 /* 14855 * aleksey: in some cases this line prints *second* error message 14856 * (see bug #78858) and probably this should be fixed. 14857 * However, we are not sure that all error messages are printed 14858 * out in other places. It's not critical so we leave it as-is for now 14859 */ 14860 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR); 14861 comp = NULL; 14862 } else { 14863 comp = pctxt->comp; 14864 pctxt->comp = NULL; 14865 } 14866 xmlXPathFreeParserContext(pctxt); 14867 14868 if (comp != NULL) { 14869 comp->expr = xmlStrdup(str); 14870 #ifdef DEBUG_EVAL_COUNTS 14871 comp->string = xmlStrdup(str); 14872 comp->nb = 0; 14873 #endif 14874 if ((comp->nbStep > 1) && (comp->last >= 0)) { 14875 xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]); 14876 } 14877 } 14878 return(comp); 14879 } 14880 14881 /** 14882 * xmlXPathCompile: 14883 * @str: the XPath expression 14884 * 14885 * Compile an XPath expression 14886 * 14887 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL. 14888 * the caller has to free the object. 14889 */ 14890 xmlXPathCompExprPtr 14891 xmlXPathCompile(const xmlChar *str) { 14892 return(xmlXPathCtxtCompile(NULL, str)); 14893 } 14894 14895 /** 14896 * xmlXPathCompiledEvalInternal: 14897 * @comp: the compiled XPath expression 14898 * @ctxt: the XPath context 14899 * @resObj: the resulting XPath object or NULL 14900 * @toBool: 1 if only a boolean result is requested 14901 * 14902 * Evaluate the Precompiled XPath expression in the given context. 14903 * The caller has to free @resObj. 14904 * 14905 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14906 * the caller has to free the object. 14907 */ 14908 static int 14909 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp, 14910 xmlXPathContextPtr ctxt, 14911 xmlXPathObjectPtr *resObj, 14912 int toBool) 14913 { 14914 xmlXPathParserContextPtr pctxt; 14915 #ifndef LIBXML_THREAD_ENABLED 14916 static int reentance = 0; 14917 #endif 14918 int res; 14919 14920 CHECK_CTXT_NEG(ctxt) 14921 14922 if (comp == NULL) 14923 return(-1); 14924 xmlXPathInit(); 14925 14926 #ifndef LIBXML_THREAD_ENABLED 14927 reentance++; 14928 if (reentance > 1) 14929 xmlXPathDisableOptimizer = 1; 14930 #endif 14931 14932 #ifdef DEBUG_EVAL_COUNTS 14933 comp->nb++; 14934 if ((comp->string != NULL) && (comp->nb > 100)) { 14935 fprintf(stderr, "100 x %s\n", comp->string); 14936 comp->nb = 0; 14937 } 14938 #endif 14939 pctxt = xmlXPathCompParserContext(comp, ctxt); 14940 res = xmlXPathRunEval(pctxt, toBool); 14941 14942 if (resObj) { 14943 if (pctxt->value == NULL) { 14944 xmlGenericError(xmlGenericErrorContext, 14945 "xmlXPathCompiledEval: evaluation failed\n"); 14946 *resObj = NULL; 14947 } else { 14948 *resObj = valuePop(pctxt); 14949 } 14950 } 14951 14952 /* 14953 * Pop all remaining objects from the stack. 14954 */ 14955 if (pctxt->valueNr > 0) { 14956 xmlXPathObjectPtr tmp; 14957 int stack = 0; 14958 14959 do { 14960 tmp = valuePop(pctxt); 14961 if (tmp != NULL) { 14962 stack++; 14963 xmlXPathReleaseObject(ctxt, tmp); 14964 } 14965 } while (tmp != NULL); 14966 if ((stack != 0) && 14967 ((toBool) || ((resObj) && (*resObj)))) 14968 { 14969 xmlGenericError(xmlGenericErrorContext, 14970 "xmlXPathCompiledEval: %d objects left on the stack.\n", 14971 stack); 14972 } 14973 } 14974 14975 if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) { 14976 xmlXPathFreeObject(*resObj); 14977 *resObj = NULL; 14978 } 14979 pctxt->comp = NULL; 14980 xmlXPathFreeParserContext(pctxt); 14981 #ifndef LIBXML_THREAD_ENABLED 14982 reentance--; 14983 #endif 14984 14985 return(res); 14986 } 14987 14988 /** 14989 * xmlXPathCompiledEval: 14990 * @comp: the compiled XPath expression 14991 * @ctx: the XPath context 14992 * 14993 * Evaluate the Precompiled XPath expression in the given context. 14994 * 14995 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14996 * the caller has to free the object. 14997 */ 14998 xmlXPathObjectPtr 14999 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) 15000 { 15001 xmlXPathObjectPtr res = NULL; 15002 15003 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0); 15004 return(res); 15005 } 15006 15007 /** 15008 * xmlXPathCompiledEvalToBoolean: 15009 * @comp: the compiled XPath expression 15010 * @ctxt: the XPath context 15011 * 15012 * Applies the XPath boolean() function on the result of the given 15013 * compiled expression. 15014 * 15015 * Returns 1 if the expression evaluated to true, 0 if to false and 15016 * -1 in API and internal errors. 15017 */ 15018 int 15019 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp, 15020 xmlXPathContextPtr ctxt) 15021 { 15022 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1)); 15023 } 15024 15025 /** 15026 * xmlXPathEvalExpr: 15027 * @ctxt: the XPath Parser context 15028 * 15029 * Parse and evaluate an XPath expression in the given context, 15030 * then push the result on the context stack 15031 */ 15032 void 15033 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) { 15034 #ifdef XPATH_STREAMING 15035 xmlXPathCompExprPtr comp; 15036 #endif 15037 15038 if (ctxt == NULL) return; 15039 15040 #ifdef XPATH_STREAMING 15041 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base); 15042 if (comp != NULL) { 15043 if (ctxt->comp != NULL) 15044 xmlXPathFreeCompExpr(ctxt->comp); 15045 ctxt->comp = comp; 15046 if (ctxt->cur != NULL) 15047 while (*ctxt->cur != 0) ctxt->cur++; 15048 } else 15049 #endif 15050 { 15051 xmlXPathCompileExpr(ctxt, 1); 15052 if ((ctxt->error == XPATH_EXPRESSION_OK) && 15053 (ctxt->comp != NULL) && 15054 (ctxt->comp->nbStep > 1) && 15055 (ctxt->comp->last >= 0)) 15056 { 15057 xmlXPathOptimizeExpression(ctxt->comp, 15058 &ctxt->comp->steps[ctxt->comp->last]); 15059 } 15060 } 15061 CHECK_ERROR; 15062 xmlXPathRunEval(ctxt, 0); 15063 } 15064 15065 /** 15066 * xmlXPathEval: 15067 * @str: the XPath expression 15068 * @ctx: the XPath context 15069 * 15070 * Evaluate the XPath Location Path in the given context. 15071 * 15072 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 15073 * the caller has to free the object. 15074 */ 15075 xmlXPathObjectPtr 15076 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) { 15077 xmlXPathParserContextPtr ctxt; 15078 xmlXPathObjectPtr res, tmp, init = NULL; 15079 int stack = 0; 15080 15081 CHECK_CTXT(ctx) 15082 15083 xmlXPathInit(); 15084 15085 ctxt = xmlXPathNewParserContext(str, ctx); 15086 if (ctxt == NULL) 15087 return NULL; 15088 xmlXPathEvalExpr(ctxt); 15089 15090 if (ctxt->value == NULL) { 15091 xmlGenericError(xmlGenericErrorContext, 15092 "xmlXPathEval: evaluation failed\n"); 15093 res = NULL; 15094 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL) 15095 #ifdef XPATH_STREAMING 15096 && (ctxt->comp->stream == NULL) 15097 #endif 15098 ) { 15099 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR); 15100 res = NULL; 15101 } else { 15102 res = valuePop(ctxt); 15103 } 15104 15105 do { 15106 tmp = valuePop(ctxt); 15107 if (tmp != NULL) { 15108 if (tmp != init) 15109 stack++; 15110 xmlXPathReleaseObject(ctx, tmp); 15111 } 15112 } while (tmp != NULL); 15113 if ((stack != 0) && (res != NULL)) { 15114 xmlGenericError(xmlGenericErrorContext, 15115 "xmlXPathEval: %d object left on the stack\n", 15116 stack); 15117 } 15118 if (ctxt->error != XPATH_EXPRESSION_OK) { 15119 xmlXPathFreeObject(res); 15120 res = NULL; 15121 } 15122 15123 xmlXPathFreeParserContext(ctxt); 15124 return(res); 15125 } 15126 15127 /** 15128 * xmlXPathSetContextNode: 15129 * @node: the node to to use as the context node 15130 * @ctx: the XPath context 15131 * 15132 * Sets 'node' as the context node. The node must be in the same 15133 * document as that associated with the context. 15134 * 15135 * Returns -1 in case of error or 0 if successful 15136 */ 15137 int 15138 xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) { 15139 if ((node == NULL) || (ctx == NULL)) 15140 return(-1); 15141 15142 if (node->doc == ctx->doc) { 15143 ctx->node = node; 15144 return(0); 15145 } 15146 return(-1); 15147 } 15148 15149 /** 15150 * xmlXPathNodeEval: 15151 * @node: the node to to use as the context node 15152 * @str: the XPath expression 15153 * @ctx: the XPath context 15154 * 15155 * Evaluate the XPath Location Path in the given context. The node 'node' 15156 * is set as the context node. The context node is not restored. 15157 * 15158 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 15159 * the caller has to free the object. 15160 */ 15161 xmlXPathObjectPtr 15162 xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) { 15163 if (str == NULL) 15164 return(NULL); 15165 if (xmlXPathSetContextNode(node, ctx) < 0) 15166 return(NULL); 15167 return(xmlXPathEval(str, ctx)); 15168 } 15169 15170 /** 15171 * xmlXPathEvalExpression: 15172 * @str: the XPath expression 15173 * @ctxt: the XPath context 15174 * 15175 * Evaluate the XPath expression in the given context. 15176 * 15177 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 15178 * the caller has to free the object. 15179 */ 15180 xmlXPathObjectPtr 15181 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) { 15182 xmlXPathParserContextPtr pctxt; 15183 xmlXPathObjectPtr res, tmp; 15184 int stack = 0; 15185 15186 CHECK_CTXT(ctxt) 15187 15188 xmlXPathInit(); 15189 15190 pctxt = xmlXPathNewParserContext(str, ctxt); 15191 if (pctxt == NULL) 15192 return NULL; 15193 xmlXPathEvalExpr(pctxt); 15194 15195 if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) { 15196 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR); 15197 res = NULL; 15198 } else { 15199 res = valuePop(pctxt); 15200 } 15201 do { 15202 tmp = valuePop(pctxt); 15203 if (tmp != NULL) { 15204 xmlXPathReleaseObject(ctxt, tmp); 15205 stack++; 15206 } 15207 } while (tmp != NULL); 15208 if ((stack != 0) && (res != NULL)) { 15209 xmlGenericError(xmlGenericErrorContext, 15210 "xmlXPathEvalExpression: %d object left on the stack\n", 15211 stack); 15212 } 15213 xmlXPathFreeParserContext(pctxt); 15214 return(res); 15215 } 15216 15217 /************************************************************************ 15218 * * 15219 * Extra functions not pertaining to the XPath spec * 15220 * * 15221 ************************************************************************/ 15222 /** 15223 * xmlXPathEscapeUriFunction: 15224 * @ctxt: the XPath Parser context 15225 * @nargs: the number of arguments 15226 * 15227 * Implement the escape-uri() XPath function 15228 * string escape-uri(string $str, bool $escape-reserved) 15229 * 15230 * This function applies the URI escaping rules defined in section 2 of [RFC 15231 * 2396] to the string supplied as $uri-part, which typically represents all 15232 * or part of a URI. The effect of the function is to replace any special 15233 * character in the string by an escape sequence of the form %xx%yy..., 15234 * where xxyy... is the hexadecimal representation of the octets used to 15235 * represent the character in UTF-8. 15236 * 15237 * The set of characters that are escaped depends on the setting of the 15238 * boolean argument $escape-reserved. 15239 * 15240 * If $escape-reserved is true, all characters are escaped other than lower 15241 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters 15242 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!" 15243 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only 15244 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and 15245 * A-F). 15246 * 15247 * If $escape-reserved is false, the behavior differs in that characters 15248 * referred to in [RFC 2396] as reserved characters are not escaped. These 15249 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",". 15250 * 15251 * [RFC 2396] does not define whether escaped URIs should use lower case or 15252 * upper case for hexadecimal digits. To ensure that escaped URIs can be 15253 * compared using string comparison functions, this function must always use 15254 * the upper-case letters A-F. 15255 * 15256 * Generally, $escape-reserved should be set to true when escaping a string 15257 * that is to form a single part of a URI, and to false when escaping an 15258 * entire URI or URI reference. 15259 * 15260 * In the case of non-ascii characters, the string is encoded according to 15261 * utf-8 and then converted according to RFC 2396. 15262 * 15263 * Examples 15264 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true()) 15265 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean" 15266 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false()) 15267 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean" 15268 * 15269 */ 15270 static void 15271 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) { 15272 xmlXPathObjectPtr str; 15273 int escape_reserved; 15274 xmlBufPtr target; 15275 xmlChar *cptr; 15276 xmlChar escape[4]; 15277 15278 CHECK_ARITY(2); 15279 15280 escape_reserved = xmlXPathPopBoolean(ctxt); 15281 15282 CAST_TO_STRING; 15283 str = valuePop(ctxt); 15284 15285 target = xmlBufCreate(); 15286 15287 escape[0] = '%'; 15288 escape[3] = 0; 15289 15290 if (target) { 15291 for (cptr = str->stringval; *cptr; cptr++) { 15292 if ((*cptr >= 'A' && *cptr <= 'Z') || 15293 (*cptr >= 'a' && *cptr <= 'z') || 15294 (*cptr >= '0' && *cptr <= '9') || 15295 *cptr == '-' || *cptr == '_' || *cptr == '.' || 15296 *cptr == '!' || *cptr == '~' || *cptr == '*' || 15297 *cptr == '\''|| *cptr == '(' || *cptr == ')' || 15298 (*cptr == '%' && 15299 ((cptr[1] >= 'A' && cptr[1] <= 'F') || 15300 (cptr[1] >= 'a' && cptr[1] <= 'f') || 15301 (cptr[1] >= '0' && cptr[1] <= '9')) && 15302 ((cptr[2] >= 'A' && cptr[2] <= 'F') || 15303 (cptr[2] >= 'a' && cptr[2] <= 'f') || 15304 (cptr[2] >= '0' && cptr[2] <= '9'))) || 15305 (!escape_reserved && 15306 (*cptr == ';' || *cptr == '/' || *cptr == '?' || 15307 *cptr == ':' || *cptr == '@' || *cptr == '&' || 15308 *cptr == '=' || *cptr == '+' || *cptr == '$' || 15309 *cptr == ','))) { 15310 xmlBufAdd(target, cptr, 1); 15311 } else { 15312 if ((*cptr >> 4) < 10) 15313 escape[1] = '0' + (*cptr >> 4); 15314 else 15315 escape[1] = 'A' - 10 + (*cptr >> 4); 15316 if ((*cptr & 0xF) < 10) 15317 escape[2] = '0' + (*cptr & 0xF); 15318 else 15319 escape[2] = 'A' - 10 + (*cptr & 0xF); 15320 15321 xmlBufAdd(target, &escape[0], 3); 15322 } 15323 } 15324 } 15325 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 15326 xmlBufContent(target))); 15327 xmlBufFree(target); 15328 xmlXPathReleaseObject(ctxt->context, str); 15329 } 15330 15331 /** 15332 * xmlXPathRegisterAllFunctions: 15333 * @ctxt: the XPath context 15334 * 15335 * Registers all default XPath functions in this context 15336 */ 15337 void 15338 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt) 15339 { 15340 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean", 15341 xmlXPathBooleanFunction); 15342 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling", 15343 xmlXPathCeilingFunction); 15344 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count", 15345 xmlXPathCountFunction); 15346 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat", 15347 xmlXPathConcatFunction); 15348 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains", 15349 xmlXPathContainsFunction); 15350 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id", 15351 xmlXPathIdFunction); 15352 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false", 15353 xmlXPathFalseFunction); 15354 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor", 15355 xmlXPathFloorFunction); 15356 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last", 15357 xmlXPathLastFunction); 15358 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang", 15359 xmlXPathLangFunction); 15360 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name", 15361 xmlXPathLocalNameFunction); 15362 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not", 15363 xmlXPathNotFunction); 15364 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name", 15365 xmlXPathNameFunction); 15366 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri", 15367 xmlXPathNamespaceURIFunction); 15368 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space", 15369 xmlXPathNormalizeFunction); 15370 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number", 15371 xmlXPathNumberFunction); 15372 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position", 15373 xmlXPathPositionFunction); 15374 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round", 15375 xmlXPathRoundFunction); 15376 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string", 15377 xmlXPathStringFunction); 15378 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length", 15379 xmlXPathStringLengthFunction); 15380 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with", 15381 xmlXPathStartsWithFunction); 15382 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring", 15383 xmlXPathSubstringFunction); 15384 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before", 15385 xmlXPathSubstringBeforeFunction); 15386 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after", 15387 xmlXPathSubstringAfterFunction); 15388 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum", 15389 xmlXPathSumFunction); 15390 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true", 15391 xmlXPathTrueFunction); 15392 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate", 15393 xmlXPathTranslateFunction); 15394 15395 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri", 15396 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions", 15397 xmlXPathEscapeUriFunction); 15398 } 15399 15400 #endif /* LIBXML_XPATH_ENABLED */ 15401 #define bottom_xpath 15402 #include "elfgcchack.h" 15403