1 /* 2 * xpath.c: XML Path Language implementation 3 * XPath is a language for addressing parts of an XML document, 4 * designed to be used by both XSLT and XPointer 5 * 6 * Reference: W3C Recommendation 16 November 1999 7 * http://www.w3.org/TR/1999/REC-xpath-19991116 8 * Public reference: 9 * http://www.w3.org/TR/xpath 10 * 11 * See Copyright for the status of this software 12 * 13 * Author: daniel (at) veillard.com 14 * 15 */ 16 17 /* To avoid EBCDIC trouble when parsing on zOS */ 18 #if defined(__MVS__) 19 #pragma convert("ISO8859-1") 20 #endif 21 22 #define IN_LIBXML 23 #include "libxml.h" 24 25 #include <limits.h> 26 #include <string.h> 27 #include <stddef.h> 28 29 #ifdef HAVE_SYS_TYPES_H 30 #include <sys/types.h> 31 #endif 32 #ifdef HAVE_MATH_H 33 #include <math.h> 34 #endif 35 #ifdef HAVE_FLOAT_H 36 #include <float.h> 37 #endif 38 #ifdef HAVE_CTYPE_H 39 #include <ctype.h> 40 #endif 41 #ifdef HAVE_SIGNAL_H 42 #include <signal.h> 43 #endif 44 45 #include <libxml/xmlmemory.h> 46 #include <libxml/tree.h> 47 #include <libxml/valid.h> 48 #include <libxml/xpath.h> 49 #include <libxml/xpathInternals.h> 50 #include <libxml/parserInternals.h> 51 #include <libxml/hash.h> 52 #ifdef LIBXML_XPTR_ENABLED 53 #include <libxml/xpointer.h> 54 #endif 55 #ifdef LIBXML_DEBUG_ENABLED 56 #include <libxml/debugXML.h> 57 #endif 58 #include <libxml/xmlerror.h> 59 #include <libxml/threads.h> 60 #include <libxml/globals.h> 61 #ifdef LIBXML_PATTERN_ENABLED 62 #include <libxml/pattern.h> 63 #endif 64 65 #include "buf.h" 66 67 #ifdef LIBXML_PATTERN_ENABLED 68 #define XPATH_STREAMING 69 #endif 70 71 #define TODO \ 72 xmlGenericError(xmlGenericErrorContext, \ 73 "Unimplemented block at %s:%d\n", \ 74 __FILE__, __LINE__); 75 76 /** 77 * WITH_TIM_SORT: 78 * 79 * Use the Timsort algorithm provided in timsort.h to sort 80 * nodeset as this is a great improvement over the old Shell sort 81 * used in xmlXPathNodeSetSort() 82 */ 83 #define WITH_TIM_SORT 84 85 /* 86 * XP_OPTIMIZED_NON_ELEM_COMPARISON: 87 * If defined, this will use xmlXPathCmpNodesExt() instead of 88 * xmlXPathCmpNodes(). The new function is optimized comparison of 89 * non-element nodes; actually it will speed up comparison only if 90 * xmlXPathOrderDocElems() was called in order to index the elements of 91 * a tree in document order; Libxslt does such an indexing, thus it will 92 * benefit from this optimization. 93 */ 94 #define XP_OPTIMIZED_NON_ELEM_COMPARISON 95 96 /* 97 * XP_OPTIMIZED_FILTER_FIRST: 98 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]" 99 * in a way, that it stop evaluation at the first node. 100 */ 101 #define XP_OPTIMIZED_FILTER_FIRST 102 103 /* 104 * XP_DEBUG_OBJ_USAGE: 105 * Internal flag to enable tracking of how much XPath objects have been 106 * created. 107 */ 108 /* #define XP_DEBUG_OBJ_USAGE */ 109 110 /* 111 * XPATH_MAX_STEPS: 112 * when compiling an XPath expression we arbitrary limit the maximum 113 * number of step operation in the compiled expression. 1000000 is 114 * an insanely large value which should never be reached under normal 115 * circumstances 116 */ 117 #define XPATH_MAX_STEPS 1000000 118 119 /* 120 * XPATH_MAX_STACK_DEPTH: 121 * when evaluating an XPath expression we arbitrary limit the maximum 122 * number of object allowed to be pushed on the stack. 1000000 is 123 * an insanely large value which should never be reached under normal 124 * circumstances 125 */ 126 #define XPATH_MAX_STACK_DEPTH 1000000 127 128 /* 129 * XPATH_MAX_NODESET_LENGTH: 130 * when evaluating an XPath expression nodesets are created and we 131 * arbitrary limit the maximum length of those node set. 10000000 is 132 * an insanely large value which should never be reached under normal 133 * circumstances, one would first need to construct an in memory tree 134 * with more than 10 millions nodes. 135 */ 136 #define XPATH_MAX_NODESET_LENGTH 10000000 137 138 /* 139 * TODO: 140 * There are a few spots where some tests are done which depend upon ascii 141 * data. These should be enhanced for full UTF8 support (see particularly 142 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT) 143 */ 144 145 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 146 /** 147 * xmlXPathCmpNodesExt: 148 * @node1: the first node 149 * @node2: the second node 150 * 151 * Compare two nodes w.r.t document order. 152 * This one is optimized for handling of non-element nodes. 153 * 154 * Returns -2 in case of error 1 if first point < second point, 0 if 155 * it's the same node, -1 otherwise 156 */ 157 static int 158 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) { 159 int depth1, depth2; 160 int misc = 0, precedence1 = 0, precedence2 = 0; 161 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL; 162 xmlNodePtr cur, root; 163 ptrdiff_t l1, l2; 164 165 if ((node1 == NULL) || (node2 == NULL)) 166 return(-2); 167 168 if (node1 == node2) 169 return(0); 170 171 /* 172 * a couple of optimizations which will avoid computations in most cases 173 */ 174 switch (node1->type) { 175 case XML_ELEMENT_NODE: 176 if (node2->type == XML_ELEMENT_NODE) { 177 if ((0 > (ptrdiff_t) node1->content) && 178 (0 > (ptrdiff_t) node2->content) && 179 (node1->doc == node2->doc)) 180 { 181 l1 = -((ptrdiff_t) node1->content); 182 l2 = -((ptrdiff_t) node2->content); 183 if (l1 < l2) 184 return(1); 185 if (l1 > l2) 186 return(-1); 187 } else 188 goto turtle_comparison; 189 } 190 break; 191 case XML_ATTRIBUTE_NODE: 192 precedence1 = 1; /* element is owner */ 193 miscNode1 = node1; 194 node1 = node1->parent; 195 misc = 1; 196 break; 197 case XML_TEXT_NODE: 198 case XML_CDATA_SECTION_NODE: 199 case XML_COMMENT_NODE: 200 case XML_PI_NODE: { 201 miscNode1 = node1; 202 /* 203 * Find nearest element node. 204 */ 205 if (node1->prev != NULL) { 206 do { 207 node1 = node1->prev; 208 if (node1->type == XML_ELEMENT_NODE) { 209 precedence1 = 3; /* element in prev-sibl axis */ 210 break; 211 } 212 if (node1->prev == NULL) { 213 precedence1 = 2; /* element is parent */ 214 /* 215 * URGENT TODO: Are there any cases, where the 216 * parent of such a node is not an element node? 217 */ 218 node1 = node1->parent; 219 break; 220 } 221 } while (1); 222 } else { 223 precedence1 = 2; /* element is parent */ 224 node1 = node1->parent; 225 } 226 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) || 227 (0 <= (ptrdiff_t) node1->content)) { 228 /* 229 * Fallback for whatever case. 230 */ 231 node1 = miscNode1; 232 precedence1 = 0; 233 } else 234 misc = 1; 235 } 236 break; 237 case XML_NAMESPACE_DECL: 238 /* 239 * TODO: why do we return 1 for namespace nodes? 240 */ 241 return(1); 242 default: 243 break; 244 } 245 switch (node2->type) { 246 case XML_ELEMENT_NODE: 247 break; 248 case XML_ATTRIBUTE_NODE: 249 precedence2 = 1; /* element is owner */ 250 miscNode2 = node2; 251 node2 = node2->parent; 252 misc = 1; 253 break; 254 case XML_TEXT_NODE: 255 case XML_CDATA_SECTION_NODE: 256 case XML_COMMENT_NODE: 257 case XML_PI_NODE: { 258 miscNode2 = node2; 259 if (node2->prev != NULL) { 260 do { 261 node2 = node2->prev; 262 if (node2->type == XML_ELEMENT_NODE) { 263 precedence2 = 3; /* element in prev-sibl axis */ 264 break; 265 } 266 if (node2->prev == NULL) { 267 precedence2 = 2; /* element is parent */ 268 node2 = node2->parent; 269 break; 270 } 271 } while (1); 272 } else { 273 precedence2 = 2; /* element is parent */ 274 node2 = node2->parent; 275 } 276 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) || 277 (0 <= (ptrdiff_t) node2->content)) 278 { 279 node2 = miscNode2; 280 precedence2 = 0; 281 } else 282 misc = 1; 283 } 284 break; 285 case XML_NAMESPACE_DECL: 286 return(1); 287 default: 288 break; 289 } 290 if (misc) { 291 if (node1 == node2) { 292 if (precedence1 == precedence2) { 293 /* 294 * The ugly case; but normally there aren't many 295 * adjacent non-element nodes around. 296 */ 297 cur = miscNode2->prev; 298 while (cur != NULL) { 299 if (cur == miscNode1) 300 return(1); 301 if (cur->type == XML_ELEMENT_NODE) 302 return(-1); 303 cur = cur->prev; 304 } 305 return (-1); 306 } else { 307 /* 308 * Evaluate based on higher precedence wrt to the element. 309 * TODO: This assumes attributes are sorted before content. 310 * Is this 100% correct? 311 */ 312 if (precedence1 < precedence2) 313 return(1); 314 else 315 return(-1); 316 } 317 } 318 /* 319 * Special case: One of the helper-elements is contained by the other. 320 * <foo> 321 * <node2> 322 * <node1>Text-1(precedence1 == 2)</node1> 323 * </node2> 324 * Text-6(precedence2 == 3) 325 * </foo> 326 */ 327 if ((precedence2 == 3) && (precedence1 > 1)) { 328 cur = node1->parent; 329 while (cur) { 330 if (cur == node2) 331 return(1); 332 cur = cur->parent; 333 } 334 } 335 if ((precedence1 == 3) && (precedence2 > 1)) { 336 cur = node2->parent; 337 while (cur) { 338 if (cur == node1) 339 return(-1); 340 cur = cur->parent; 341 } 342 } 343 } 344 345 /* 346 * Speedup using document order if availble. 347 */ 348 if ((node1->type == XML_ELEMENT_NODE) && 349 (node2->type == XML_ELEMENT_NODE) && 350 (0 > (ptrdiff_t) node1->content) && 351 (0 > (ptrdiff_t) node2->content) && 352 (node1->doc == node2->doc)) { 353 354 l1 = -((ptrdiff_t) node1->content); 355 l2 = -((ptrdiff_t) node2->content); 356 if (l1 < l2) 357 return(1); 358 if (l1 > l2) 359 return(-1); 360 } 361 362 turtle_comparison: 363 364 if (node1 == node2->prev) 365 return(1); 366 if (node1 == node2->next) 367 return(-1); 368 /* 369 * compute depth to root 370 */ 371 for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) { 372 if (cur->parent == node1) 373 return(1); 374 depth2++; 375 } 376 root = cur; 377 for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) { 378 if (cur->parent == node2) 379 return(-1); 380 depth1++; 381 } 382 /* 383 * Distinct document (or distinct entities :-( ) case. 384 */ 385 if (root != cur) { 386 return(-2); 387 } 388 /* 389 * get the nearest common ancestor. 390 */ 391 while (depth1 > depth2) { 392 depth1--; 393 node1 = node1->parent; 394 } 395 while (depth2 > depth1) { 396 depth2--; 397 node2 = node2->parent; 398 } 399 while (node1->parent != node2->parent) { 400 node1 = node1->parent; 401 node2 = node2->parent; 402 /* should not happen but just in case ... */ 403 if ((node1 == NULL) || (node2 == NULL)) 404 return(-2); 405 } 406 /* 407 * Find who's first. 408 */ 409 if (node1 == node2->prev) 410 return(1); 411 if (node1 == node2->next) 412 return(-1); 413 /* 414 * Speedup using document order if availble. 415 */ 416 if ((node1->type == XML_ELEMENT_NODE) && 417 (node2->type == XML_ELEMENT_NODE) && 418 (0 > (ptrdiff_t) node1->content) && 419 (0 > (ptrdiff_t) node2->content) && 420 (node1->doc == node2->doc)) { 421 422 l1 = -((ptrdiff_t) node1->content); 423 l2 = -((ptrdiff_t) node2->content); 424 if (l1 < l2) 425 return(1); 426 if (l1 > l2) 427 return(-1); 428 } 429 430 for (cur = node1->next;cur != NULL;cur = cur->next) 431 if (cur == node2) 432 return(1); 433 return(-1); /* assume there is no sibling list corruption */ 434 } 435 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */ 436 437 /* 438 * Wrapper for the Timsort argorithm from timsort.h 439 */ 440 #ifdef WITH_TIM_SORT 441 #define SORT_NAME libxml_domnode 442 #define SORT_TYPE xmlNodePtr 443 /** 444 * wrap_cmp: 445 * @x: a node 446 * @y: another node 447 * 448 * Comparison function for the Timsort implementation 449 * 450 * Returns -2 in case of error -1 if first point < second point, 0 if 451 * it's the same node, +1 otherwise 452 */ 453 static 454 int wrap_cmp( xmlNodePtr x, xmlNodePtr y ); 455 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 456 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y ) 457 { 458 int res = xmlXPathCmpNodesExt(x, y); 459 return res == -2 ? res : -res; 460 } 461 #else 462 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y ) 463 { 464 int res = xmlXPathCmpNodes(x, y); 465 return res == -2 ? res : -res; 466 } 467 #endif 468 #define SORT_CMP(x, y) (wrap_cmp(x, y)) 469 #include "timsort.h" 470 #endif /* WITH_TIM_SORT */ 471 472 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) 473 474 /************************************************************************ 475 * * 476 * Floating point stuff * 477 * * 478 ************************************************************************/ 479 480 #ifndef INFINITY 481 #define INFINITY (DBL_MAX * DBL_MAX) 482 #endif 483 484 #ifndef NAN 485 #define NAN (INFINITY / INFINITY) 486 #endif 487 488 double xmlXPathNAN; 489 double xmlXPathPINF; 490 double xmlXPathNINF; 491 492 /** 493 * xmlXPathInit: 494 * 495 * Initialize the XPath environment 496 */ 497 void 498 xmlXPathInit(void) { 499 xmlXPathNAN = NAN; 500 xmlXPathPINF = INFINITY; 501 xmlXPathNINF = -INFINITY; 502 } 503 504 /** 505 * xmlXPathIsNaN: 506 * @val: a double value 507 * 508 * Returns 1 if the value is a NaN, 0 otherwise 509 */ 510 int 511 xmlXPathIsNaN(double val) { 512 #ifdef isnan 513 return isnan(val); 514 #else 515 return !(val == val); 516 #endif 517 } 518 519 /** 520 * xmlXPathIsInf: 521 * @val: a double value 522 * 523 * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise 524 */ 525 int 526 xmlXPathIsInf(double val) { 527 #ifdef isinf 528 return isinf(val) ? (val > 0 ? 1 : -1) : 0; 529 #else 530 if (val >= INFINITY) 531 return 1; 532 if (val <= -INFINITY) 533 return -1; 534 return 0; 535 #endif 536 } 537 538 #endif /* SCHEMAS or XPATH */ 539 540 #ifdef LIBXML_XPATH_ENABLED 541 542 /* 543 * TODO: when compatibility allows remove all "fake node libxslt" strings 544 * the test should just be name[0] = ' ' 545 */ 546 #ifdef DEBUG_XPATH_EXPRESSION 547 #define DEBUG_STEP 548 #define DEBUG_EXPR 549 #define DEBUG_EVAL_COUNTS 550 #endif 551 552 static xmlNs xmlXPathXMLNamespaceStruct = { 553 NULL, 554 XML_NAMESPACE_DECL, 555 XML_XML_NAMESPACE, 556 BAD_CAST "xml", 557 NULL, 558 NULL 559 }; 560 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct; 561 #ifndef LIBXML_THREAD_ENABLED 562 /* 563 * Optimizer is disabled only when threaded apps are detected while 564 * the library ain't compiled for thread safety. 565 */ 566 static int xmlXPathDisableOptimizer = 0; 567 #endif 568 569 /************************************************************************ 570 * * 571 * Error handling routines * 572 * * 573 ************************************************************************/ 574 575 /** 576 * XP_ERRORNULL: 577 * @X: the error code 578 * 579 * Macro to raise an XPath error and return NULL. 580 */ 581 #define XP_ERRORNULL(X) \ 582 { xmlXPathErr(ctxt, X); return(NULL); } 583 584 /* 585 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError 586 */ 587 static const char *xmlXPathErrorMessages[] = { 588 "Ok\n", 589 "Number encoding\n", 590 "Unfinished literal\n", 591 "Start of literal\n", 592 "Expected $ for variable reference\n", 593 "Undefined variable\n", 594 "Invalid predicate\n", 595 "Invalid expression\n", 596 "Missing closing curly brace\n", 597 "Unregistered function\n", 598 "Invalid operand\n", 599 "Invalid type\n", 600 "Invalid number of arguments\n", 601 "Invalid context size\n", 602 "Invalid context position\n", 603 "Memory allocation error\n", 604 "Syntax error\n", 605 "Resource error\n", 606 "Sub resource error\n", 607 "Undefined namespace prefix\n", 608 "Encoding error\n", 609 "Char out of XML range\n", 610 "Invalid or incomplete context\n", 611 "Stack usage error\n", 612 "Forbidden variable\n", 613 "?? Unknown error ??\n" /* Must be last in the list! */ 614 }; 615 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \ 616 sizeof(xmlXPathErrorMessages[0])) - 1) 617 /** 618 * xmlXPathErrMemory: 619 * @ctxt: an XPath context 620 * @extra: extra informations 621 * 622 * Handle a redefinition of attribute error 623 */ 624 static void 625 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra) 626 { 627 if (ctxt != NULL) { 628 if (extra) { 629 xmlChar buf[200]; 630 631 xmlStrPrintf(buf, 200, 632 "Memory allocation failed : %s\n", 633 extra); 634 ctxt->lastError.message = (char *) xmlStrdup(buf); 635 } else { 636 ctxt->lastError.message = (char *) 637 xmlStrdup(BAD_CAST "Memory allocation failed\n"); 638 } 639 ctxt->lastError.domain = XML_FROM_XPATH; 640 ctxt->lastError.code = XML_ERR_NO_MEMORY; 641 if (ctxt->error != NULL) 642 ctxt->error(ctxt->userData, &ctxt->lastError); 643 } else { 644 if (extra) 645 __xmlRaiseError(NULL, NULL, NULL, 646 NULL, NULL, XML_FROM_XPATH, 647 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, 648 extra, NULL, NULL, 0, 0, 649 "Memory allocation failed : %s\n", extra); 650 else 651 __xmlRaiseError(NULL, NULL, NULL, 652 NULL, NULL, XML_FROM_XPATH, 653 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, 654 NULL, NULL, NULL, 0, 0, 655 "Memory allocation failed\n"); 656 } 657 } 658 659 /** 660 * xmlXPathPErrMemory: 661 * @ctxt: an XPath parser context 662 * @extra: extra informations 663 * 664 * Handle a redefinition of attribute error 665 */ 666 static void 667 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra) 668 { 669 if (ctxt == NULL) 670 xmlXPathErrMemory(NULL, extra); 671 else { 672 ctxt->error = XPATH_MEMORY_ERROR; 673 xmlXPathErrMemory(ctxt->context, extra); 674 } 675 } 676 677 /** 678 * xmlXPathErr: 679 * @ctxt: a XPath parser context 680 * @error: the error code 681 * 682 * Handle an XPath error 683 */ 684 void 685 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error) 686 { 687 if ((error < 0) || (error > MAXERRNO)) 688 error = MAXERRNO; 689 if (ctxt == NULL) { 690 __xmlRaiseError(NULL, NULL, NULL, 691 NULL, NULL, XML_FROM_XPATH, 692 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, 693 XML_ERR_ERROR, NULL, 0, 694 NULL, NULL, NULL, 0, 0, 695 "%s", xmlXPathErrorMessages[error]); 696 return; 697 } 698 ctxt->error = error; 699 if (ctxt->context == 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 (const char *) ctxt->base, NULL, NULL, 705 ctxt->cur - ctxt->base, 0, 706 "%s", xmlXPathErrorMessages[error]); 707 return; 708 } 709 710 /* cleanup current last error */ 711 xmlResetError(&ctxt->context->lastError); 712 713 ctxt->context->lastError.domain = XML_FROM_XPATH; 714 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK - 715 XPATH_EXPRESSION_OK; 716 ctxt->context->lastError.level = XML_ERR_ERROR; 717 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base); 718 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base; 719 ctxt->context->lastError.node = ctxt->context->debugNode; 720 if (ctxt->context->error != NULL) { 721 ctxt->context->error(ctxt->context->userData, 722 &ctxt->context->lastError); 723 } else { 724 __xmlRaiseError(NULL, NULL, NULL, 725 NULL, ctxt->context->debugNode, XML_FROM_XPATH, 726 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, 727 XML_ERR_ERROR, NULL, 0, 728 (const char *) ctxt->base, NULL, NULL, 729 ctxt->cur - ctxt->base, 0, 730 "%s", xmlXPathErrorMessages[error]); 731 } 732 733 } 734 735 /** 736 * xmlXPatherror: 737 * @ctxt: the XPath Parser context 738 * @file: the file name 739 * @line: the line number 740 * @no: the error number 741 * 742 * Formats an error message. 743 */ 744 void 745 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED, 746 int line ATTRIBUTE_UNUSED, int no) { 747 xmlXPathErr(ctxt, no); 748 } 749 750 /************************************************************************ 751 * * 752 * Utilities * 753 * * 754 ************************************************************************/ 755 756 /** 757 * xsltPointerList: 758 * 759 * Pointer-list for various purposes. 760 */ 761 typedef struct _xmlPointerList xmlPointerList; 762 typedef xmlPointerList *xmlPointerListPtr; 763 struct _xmlPointerList { 764 void **items; 765 int number; 766 int size; 767 }; 768 /* 769 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt 770 * and here, we should make the functions public. 771 */ 772 static int 773 xmlPointerListAddSize(xmlPointerListPtr list, 774 void *item, 775 int initialSize) 776 { 777 if (list->items == NULL) { 778 if (initialSize <= 0) 779 initialSize = 1; 780 list->items = (void **) xmlMalloc(initialSize * sizeof(void *)); 781 if (list->items == NULL) { 782 xmlXPathErrMemory(NULL, 783 "xmlPointerListCreate: allocating item\n"); 784 return(-1); 785 } 786 list->number = 0; 787 list->size = initialSize; 788 } else if (list->size <= list->number) { 789 if (list->size > 50000000) { 790 xmlXPathErrMemory(NULL, 791 "xmlPointerListAddSize: re-allocating item\n"); 792 return(-1); 793 } 794 list->size *= 2; 795 list->items = (void **) xmlRealloc(list->items, 796 list->size * sizeof(void *)); 797 if (list->items == NULL) { 798 xmlXPathErrMemory(NULL, 799 "xmlPointerListAddSize: re-allocating item\n"); 800 list->size = 0; 801 return(-1); 802 } 803 } 804 list->items[list->number++] = item; 805 return(0); 806 } 807 808 /** 809 * xsltPointerListCreate: 810 * 811 * Creates an xsltPointerList structure. 812 * 813 * Returns a xsltPointerList structure or NULL in case of an error. 814 */ 815 static xmlPointerListPtr 816 xmlPointerListCreate(int initialSize) 817 { 818 xmlPointerListPtr ret; 819 820 ret = xmlMalloc(sizeof(xmlPointerList)); 821 if (ret == NULL) { 822 xmlXPathErrMemory(NULL, 823 "xmlPointerListCreate: allocating item\n"); 824 return (NULL); 825 } 826 memset(ret, 0, sizeof(xmlPointerList)); 827 if (initialSize > 0) { 828 xmlPointerListAddSize(ret, NULL, initialSize); 829 ret->number = 0; 830 } 831 return (ret); 832 } 833 834 /** 835 * xsltPointerListFree: 836 * 837 * Frees the xsltPointerList structure. This does not free 838 * the content of the list. 839 */ 840 static void 841 xmlPointerListFree(xmlPointerListPtr list) 842 { 843 if (list == NULL) 844 return; 845 if (list->items != NULL) 846 xmlFree(list->items); 847 xmlFree(list); 848 } 849 850 /************************************************************************ 851 * * 852 * Parser Types * 853 * * 854 ************************************************************************/ 855 856 /* 857 * Types are private: 858 */ 859 860 typedef enum { 861 XPATH_OP_END=0, 862 XPATH_OP_AND, 863 XPATH_OP_OR, 864 XPATH_OP_EQUAL, 865 XPATH_OP_CMP, 866 XPATH_OP_PLUS, 867 XPATH_OP_MULT, 868 XPATH_OP_UNION, 869 XPATH_OP_ROOT, 870 XPATH_OP_NODE, 871 XPATH_OP_COLLECT, 872 XPATH_OP_VALUE, /* 11 */ 873 XPATH_OP_VARIABLE, 874 XPATH_OP_FUNCTION, 875 XPATH_OP_ARG, 876 XPATH_OP_PREDICATE, 877 XPATH_OP_FILTER, /* 16 */ 878 XPATH_OP_SORT /* 17 */ 879 #ifdef LIBXML_XPTR_ENABLED 880 ,XPATH_OP_RANGETO 881 #endif 882 } xmlXPathOp; 883 884 typedef enum { 885 AXIS_ANCESTOR = 1, 886 AXIS_ANCESTOR_OR_SELF, 887 AXIS_ATTRIBUTE, 888 AXIS_CHILD, 889 AXIS_DESCENDANT, 890 AXIS_DESCENDANT_OR_SELF, 891 AXIS_FOLLOWING, 892 AXIS_FOLLOWING_SIBLING, 893 AXIS_NAMESPACE, 894 AXIS_PARENT, 895 AXIS_PRECEDING, 896 AXIS_PRECEDING_SIBLING, 897 AXIS_SELF 898 } xmlXPathAxisVal; 899 900 typedef enum { 901 NODE_TEST_NONE = 0, 902 NODE_TEST_TYPE = 1, 903 NODE_TEST_PI = 2, 904 NODE_TEST_ALL = 3, 905 NODE_TEST_NS = 4, 906 NODE_TEST_NAME = 5 907 } xmlXPathTestVal; 908 909 typedef enum { 910 NODE_TYPE_NODE = 0, 911 NODE_TYPE_COMMENT = XML_COMMENT_NODE, 912 NODE_TYPE_TEXT = XML_TEXT_NODE, 913 NODE_TYPE_PI = XML_PI_NODE 914 } xmlXPathTypeVal; 915 916 typedef struct _xmlXPathStepOp xmlXPathStepOp; 917 typedef xmlXPathStepOp *xmlXPathStepOpPtr; 918 struct _xmlXPathStepOp { 919 xmlXPathOp op; /* The identifier of the operation */ 920 int ch1; /* First child */ 921 int ch2; /* Second child */ 922 int value; 923 int value2; 924 int value3; 925 void *value4; 926 void *value5; 927 xmlXPathFunction cache; 928 void *cacheURI; 929 }; 930 931 struct _xmlXPathCompExpr { 932 int nbStep; /* Number of steps in this expression */ 933 int maxStep; /* Maximum number of steps allocated */ 934 xmlXPathStepOp *steps; /* ops for computation of this expression */ 935 int last; /* index of last step in expression */ 936 xmlChar *expr; /* the expression being computed */ 937 xmlDictPtr dict; /* the dictionary to use if any */ 938 #ifdef DEBUG_EVAL_COUNTS 939 int nb; 940 xmlChar *string; 941 #endif 942 #ifdef XPATH_STREAMING 943 xmlPatternPtr stream; 944 #endif 945 }; 946 947 /************************************************************************ 948 * * 949 * Forward declarations * 950 * * 951 ************************************************************************/ 952 static void 953 xmlXPathFreeValueTree(xmlNodeSetPtr obj); 954 static void 955 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj); 956 static int 957 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt, 958 xmlXPathStepOpPtr op, xmlNodePtr *first); 959 static int 960 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt, 961 xmlXPathStepOpPtr op, 962 int isPredicate); 963 static void 964 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name); 965 966 /************************************************************************ 967 * * 968 * Parser Type functions * 969 * * 970 ************************************************************************/ 971 972 /** 973 * xmlXPathNewCompExpr: 974 * 975 * Create a new Xpath component 976 * 977 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error 978 */ 979 static xmlXPathCompExprPtr 980 xmlXPathNewCompExpr(void) { 981 xmlXPathCompExprPtr cur; 982 983 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr)); 984 if (cur == NULL) { 985 xmlXPathErrMemory(NULL, "allocating component\n"); 986 return(NULL); 987 } 988 memset(cur, 0, sizeof(xmlXPathCompExpr)); 989 cur->maxStep = 10; 990 cur->nbStep = 0; 991 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep * 992 sizeof(xmlXPathStepOp)); 993 if (cur->steps == NULL) { 994 xmlXPathErrMemory(NULL, "allocating steps\n"); 995 xmlFree(cur); 996 return(NULL); 997 } 998 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp)); 999 cur->last = -1; 1000 #ifdef DEBUG_EVAL_COUNTS 1001 cur->nb = 0; 1002 #endif 1003 return(cur); 1004 } 1005 1006 /** 1007 * xmlXPathFreeCompExpr: 1008 * @comp: an XPATH comp 1009 * 1010 * Free up the memory allocated by @comp 1011 */ 1012 void 1013 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp) 1014 { 1015 xmlXPathStepOpPtr op; 1016 int i; 1017 1018 if (comp == NULL) 1019 return; 1020 if (comp->dict == NULL) { 1021 for (i = 0; i < comp->nbStep; i++) { 1022 op = &comp->steps[i]; 1023 if (op->value4 != NULL) { 1024 if (op->op == XPATH_OP_VALUE) 1025 xmlXPathFreeObject(op->value4); 1026 else 1027 xmlFree(op->value4); 1028 } 1029 if (op->value5 != NULL) 1030 xmlFree(op->value5); 1031 } 1032 } else { 1033 for (i = 0; i < comp->nbStep; i++) { 1034 op = &comp->steps[i]; 1035 if (op->value4 != NULL) { 1036 if (op->op == XPATH_OP_VALUE) 1037 xmlXPathFreeObject(op->value4); 1038 } 1039 } 1040 xmlDictFree(comp->dict); 1041 } 1042 if (comp->steps != NULL) { 1043 xmlFree(comp->steps); 1044 } 1045 #ifdef DEBUG_EVAL_COUNTS 1046 if (comp->string != NULL) { 1047 xmlFree(comp->string); 1048 } 1049 #endif 1050 #ifdef XPATH_STREAMING 1051 if (comp->stream != NULL) { 1052 xmlFreePatternList(comp->stream); 1053 } 1054 #endif 1055 if (comp->expr != NULL) { 1056 xmlFree(comp->expr); 1057 } 1058 1059 xmlFree(comp); 1060 } 1061 1062 /** 1063 * xmlXPathCompExprAdd: 1064 * @comp: the compiled expression 1065 * @ch1: first child index 1066 * @ch2: second child index 1067 * @op: an op 1068 * @value: the first int value 1069 * @value2: the second int value 1070 * @value3: the third int value 1071 * @value4: the first string value 1072 * @value5: the second string value 1073 * 1074 * Add a step to an XPath Compiled Expression 1075 * 1076 * Returns -1 in case of failure, the index otherwise 1077 */ 1078 static int 1079 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2, 1080 xmlXPathOp op, int value, 1081 int value2, int value3, void *value4, void *value5) { 1082 if (comp->nbStep >= comp->maxStep) { 1083 xmlXPathStepOp *real; 1084 1085 if (comp->maxStep >= XPATH_MAX_STEPS) { 1086 xmlXPathErrMemory(NULL, "adding step\n"); 1087 return(-1); 1088 } 1089 comp->maxStep *= 2; 1090 real = (xmlXPathStepOp *) xmlRealloc(comp->steps, 1091 comp->maxStep * sizeof(xmlXPathStepOp)); 1092 if (real == NULL) { 1093 comp->maxStep /= 2; 1094 xmlXPathErrMemory(NULL, "adding step\n"); 1095 return(-1); 1096 } 1097 comp->steps = real; 1098 } 1099 comp->last = comp->nbStep; 1100 comp->steps[comp->nbStep].ch1 = ch1; 1101 comp->steps[comp->nbStep].ch2 = ch2; 1102 comp->steps[comp->nbStep].op = op; 1103 comp->steps[comp->nbStep].value = value; 1104 comp->steps[comp->nbStep].value2 = value2; 1105 comp->steps[comp->nbStep].value3 = value3; 1106 if ((comp->dict != NULL) && 1107 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) || 1108 (op == XPATH_OP_COLLECT))) { 1109 if (value4 != NULL) { 1110 comp->steps[comp->nbStep].value4 = (xmlChar *) 1111 (void *)xmlDictLookup(comp->dict, value4, -1); 1112 xmlFree(value4); 1113 } else 1114 comp->steps[comp->nbStep].value4 = NULL; 1115 if (value5 != NULL) { 1116 comp->steps[comp->nbStep].value5 = (xmlChar *) 1117 (void *)xmlDictLookup(comp->dict, value5, -1); 1118 xmlFree(value5); 1119 } else 1120 comp->steps[comp->nbStep].value5 = NULL; 1121 } else { 1122 comp->steps[comp->nbStep].value4 = value4; 1123 comp->steps[comp->nbStep].value5 = value5; 1124 } 1125 comp->steps[comp->nbStep].cache = NULL; 1126 return(comp->nbStep++); 1127 } 1128 1129 /** 1130 * xmlXPathCompSwap: 1131 * @comp: the compiled expression 1132 * @op: operation index 1133 * 1134 * Swaps 2 operations in the compiled expression 1135 */ 1136 static void 1137 xmlXPathCompSwap(xmlXPathStepOpPtr op) { 1138 int tmp; 1139 1140 #ifndef LIBXML_THREAD_ENABLED 1141 /* 1142 * Since this manipulates possibly shared variables, this is 1143 * disabled if one detects that the library is used in a multithreaded 1144 * application 1145 */ 1146 if (xmlXPathDisableOptimizer) 1147 return; 1148 #endif 1149 1150 tmp = op->ch1; 1151 op->ch1 = op->ch2; 1152 op->ch2 = tmp; 1153 } 1154 1155 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \ 1156 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \ 1157 (op), (val), (val2), (val3), (val4), (val5)) 1158 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \ 1159 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \ 1160 (op), (val), (val2), (val3), (val4), (val5)) 1161 1162 #define PUSH_LEAVE_EXPR(op, val, val2) \ 1163 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL) 1164 1165 #define PUSH_UNARY_EXPR(op, ch, val, val2) \ 1166 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL) 1167 1168 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \ 1169 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \ 1170 (val), (val2), 0 ,NULL ,NULL) 1171 1172 /************************************************************************ 1173 * * 1174 * XPath object cache structures * 1175 * * 1176 ************************************************************************/ 1177 1178 /* #define XP_DEFAULT_CACHE_ON */ 1179 1180 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL)) 1181 1182 typedef struct _xmlXPathContextCache xmlXPathContextCache; 1183 typedef xmlXPathContextCache *xmlXPathContextCachePtr; 1184 struct _xmlXPathContextCache { 1185 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */ 1186 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */ 1187 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */ 1188 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */ 1189 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */ 1190 int maxNodeset; 1191 int maxString; 1192 int maxBoolean; 1193 int maxNumber; 1194 int maxMisc; 1195 #ifdef XP_DEBUG_OBJ_USAGE 1196 int dbgCachedAll; 1197 int dbgCachedNodeset; 1198 int dbgCachedString; 1199 int dbgCachedBool; 1200 int dbgCachedNumber; 1201 int dbgCachedPoint; 1202 int dbgCachedRange; 1203 int dbgCachedLocset; 1204 int dbgCachedUsers; 1205 int dbgCachedXSLTTree; 1206 int dbgCachedUndefined; 1207 1208 1209 int dbgReusedAll; 1210 int dbgReusedNodeset; 1211 int dbgReusedString; 1212 int dbgReusedBool; 1213 int dbgReusedNumber; 1214 int dbgReusedPoint; 1215 int dbgReusedRange; 1216 int dbgReusedLocset; 1217 int dbgReusedUsers; 1218 int dbgReusedXSLTTree; 1219 int dbgReusedUndefined; 1220 1221 #endif 1222 }; 1223 1224 /************************************************************************ 1225 * * 1226 * Debugging related functions * 1227 * * 1228 ************************************************************************/ 1229 1230 #define STRANGE \ 1231 xmlGenericError(xmlGenericErrorContext, \ 1232 "Internal error at %s:%d\n", \ 1233 __FILE__, __LINE__); 1234 1235 #ifdef LIBXML_DEBUG_ENABLED 1236 static void 1237 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) { 1238 int i; 1239 char shift[100]; 1240 1241 for (i = 0;((i < depth) && (i < 25));i++) 1242 shift[2 * i] = shift[2 * i + 1] = ' '; 1243 shift[2 * i] = shift[2 * i + 1] = 0; 1244 if (cur == NULL) { 1245 fprintf(output, "%s", shift); 1246 fprintf(output, "Node is NULL !\n"); 1247 return; 1248 1249 } 1250 1251 if ((cur->type == XML_DOCUMENT_NODE) || 1252 (cur->type == XML_HTML_DOCUMENT_NODE)) { 1253 fprintf(output, "%s", shift); 1254 fprintf(output, " /\n"); 1255 } else if (cur->type == XML_ATTRIBUTE_NODE) 1256 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth); 1257 else 1258 xmlDebugDumpOneNode(output, cur, depth); 1259 } 1260 static void 1261 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) { 1262 xmlNodePtr tmp; 1263 int i; 1264 char shift[100]; 1265 1266 for (i = 0;((i < depth) && (i < 25));i++) 1267 shift[2 * i] = shift[2 * i + 1] = ' '; 1268 shift[2 * i] = shift[2 * i + 1] = 0; 1269 if (cur == NULL) { 1270 fprintf(output, "%s", shift); 1271 fprintf(output, "Node is NULL !\n"); 1272 return; 1273 1274 } 1275 1276 while (cur != NULL) { 1277 tmp = cur; 1278 cur = cur->next; 1279 xmlDebugDumpOneNode(output, tmp, depth); 1280 } 1281 } 1282 1283 static void 1284 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) { 1285 int i; 1286 char shift[100]; 1287 1288 for (i = 0;((i < depth) && (i < 25));i++) 1289 shift[2 * i] = shift[2 * i + 1] = ' '; 1290 shift[2 * i] = shift[2 * i + 1] = 0; 1291 1292 if (cur == NULL) { 1293 fprintf(output, "%s", shift); 1294 fprintf(output, "NodeSet is NULL !\n"); 1295 return; 1296 1297 } 1298 1299 if (cur != NULL) { 1300 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr); 1301 for (i = 0;i < cur->nodeNr;i++) { 1302 fprintf(output, "%s", shift); 1303 fprintf(output, "%d", i + 1); 1304 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1); 1305 } 1306 } 1307 } 1308 1309 static void 1310 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) { 1311 int i; 1312 char shift[100]; 1313 1314 for (i = 0;((i < depth) && (i < 25));i++) 1315 shift[2 * i] = shift[2 * i + 1] = ' '; 1316 shift[2 * i] = shift[2 * i + 1] = 0; 1317 1318 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) { 1319 fprintf(output, "%s", shift); 1320 fprintf(output, "Value Tree is NULL !\n"); 1321 return; 1322 1323 } 1324 1325 fprintf(output, "%s", shift); 1326 fprintf(output, "%d", i + 1); 1327 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1); 1328 } 1329 #if defined(LIBXML_XPTR_ENABLED) 1330 static void 1331 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) { 1332 int i; 1333 char shift[100]; 1334 1335 for (i = 0;((i < depth) && (i < 25));i++) 1336 shift[2 * i] = shift[2 * i + 1] = ' '; 1337 shift[2 * i] = shift[2 * i + 1] = 0; 1338 1339 if (cur == NULL) { 1340 fprintf(output, "%s", shift); 1341 fprintf(output, "LocationSet is NULL !\n"); 1342 return; 1343 1344 } 1345 1346 for (i = 0;i < cur->locNr;i++) { 1347 fprintf(output, "%s", shift); 1348 fprintf(output, "%d : ", i + 1); 1349 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1); 1350 } 1351 } 1352 #endif /* LIBXML_XPTR_ENABLED */ 1353 1354 /** 1355 * xmlXPathDebugDumpObject: 1356 * @output: the FILE * to dump the output 1357 * @cur: the object to inspect 1358 * @depth: indentation level 1359 * 1360 * Dump the content of the object for debugging purposes 1361 */ 1362 void 1363 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) { 1364 int i; 1365 char shift[100]; 1366 1367 if (output == NULL) return; 1368 1369 for (i = 0;((i < depth) && (i < 25));i++) 1370 shift[2 * i] = shift[2 * i + 1] = ' '; 1371 shift[2 * i] = shift[2 * i + 1] = 0; 1372 1373 1374 fprintf(output, "%s", shift); 1375 1376 if (cur == NULL) { 1377 fprintf(output, "Object is empty (NULL)\n"); 1378 return; 1379 } 1380 switch(cur->type) { 1381 case XPATH_UNDEFINED: 1382 fprintf(output, "Object is uninitialized\n"); 1383 break; 1384 case XPATH_NODESET: 1385 fprintf(output, "Object is a Node Set :\n"); 1386 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth); 1387 break; 1388 case XPATH_XSLT_TREE: 1389 fprintf(output, "Object is an XSLT value tree :\n"); 1390 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth); 1391 break; 1392 case XPATH_BOOLEAN: 1393 fprintf(output, "Object is a Boolean : "); 1394 if (cur->boolval) fprintf(output, "true\n"); 1395 else fprintf(output, "false\n"); 1396 break; 1397 case XPATH_NUMBER: 1398 switch (xmlXPathIsInf(cur->floatval)) { 1399 case 1: 1400 fprintf(output, "Object is a number : Infinity\n"); 1401 break; 1402 case -1: 1403 fprintf(output, "Object is a number : -Infinity\n"); 1404 break; 1405 default: 1406 if (xmlXPathIsNaN(cur->floatval)) { 1407 fprintf(output, "Object is a number : NaN\n"); 1408 } else if (cur->floatval == 0) { 1409 /* Omit sign for negative zero. */ 1410 fprintf(output, "Object is a number : 0\n"); 1411 } else { 1412 fprintf(output, "Object is a number : %0g\n", cur->floatval); 1413 } 1414 } 1415 break; 1416 case XPATH_STRING: 1417 fprintf(output, "Object is a string : "); 1418 xmlDebugDumpString(output, cur->stringval); 1419 fprintf(output, "\n"); 1420 break; 1421 case XPATH_POINT: 1422 fprintf(output, "Object is a point : index %d in node", cur->index); 1423 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1); 1424 fprintf(output, "\n"); 1425 break; 1426 case XPATH_RANGE: 1427 if ((cur->user2 == NULL) || 1428 ((cur->user2 == cur->user) && (cur->index == cur->index2))) { 1429 fprintf(output, "Object is a collapsed range :\n"); 1430 fprintf(output, "%s", shift); 1431 if (cur->index >= 0) 1432 fprintf(output, "index %d in ", cur->index); 1433 fprintf(output, "node\n"); 1434 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, 1435 depth + 1); 1436 } else { 1437 fprintf(output, "Object is a range :\n"); 1438 fprintf(output, "%s", shift); 1439 fprintf(output, "From "); 1440 if (cur->index >= 0) 1441 fprintf(output, "index %d in ", cur->index); 1442 fprintf(output, "node\n"); 1443 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, 1444 depth + 1); 1445 fprintf(output, "%s", shift); 1446 fprintf(output, "To "); 1447 if (cur->index2 >= 0) 1448 fprintf(output, "index %d in ", cur->index2); 1449 fprintf(output, "node\n"); 1450 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2, 1451 depth + 1); 1452 fprintf(output, "\n"); 1453 } 1454 break; 1455 case XPATH_LOCATIONSET: 1456 #if defined(LIBXML_XPTR_ENABLED) 1457 fprintf(output, "Object is a Location Set:\n"); 1458 xmlXPathDebugDumpLocationSet(output, 1459 (xmlLocationSetPtr) cur->user, depth); 1460 #endif 1461 break; 1462 case XPATH_USERS: 1463 fprintf(output, "Object is user defined\n"); 1464 break; 1465 } 1466 } 1467 1468 static void 1469 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp, 1470 xmlXPathStepOpPtr op, int depth) { 1471 int i; 1472 char shift[100]; 1473 1474 for (i = 0;((i < depth) && (i < 25));i++) 1475 shift[2 * i] = shift[2 * i + 1] = ' '; 1476 shift[2 * i] = shift[2 * i + 1] = 0; 1477 1478 fprintf(output, "%s", shift); 1479 if (op == NULL) { 1480 fprintf(output, "Step is NULL\n"); 1481 return; 1482 } 1483 switch (op->op) { 1484 case XPATH_OP_END: 1485 fprintf(output, "END"); break; 1486 case XPATH_OP_AND: 1487 fprintf(output, "AND"); break; 1488 case XPATH_OP_OR: 1489 fprintf(output, "OR"); break; 1490 case XPATH_OP_EQUAL: 1491 if (op->value) 1492 fprintf(output, "EQUAL ="); 1493 else 1494 fprintf(output, "EQUAL !="); 1495 break; 1496 case XPATH_OP_CMP: 1497 if (op->value) 1498 fprintf(output, "CMP <"); 1499 else 1500 fprintf(output, "CMP >"); 1501 if (!op->value2) 1502 fprintf(output, "="); 1503 break; 1504 case XPATH_OP_PLUS: 1505 if (op->value == 0) 1506 fprintf(output, "PLUS -"); 1507 else if (op->value == 1) 1508 fprintf(output, "PLUS +"); 1509 else if (op->value == 2) 1510 fprintf(output, "PLUS unary -"); 1511 else if (op->value == 3) 1512 fprintf(output, "PLUS unary - -"); 1513 break; 1514 case XPATH_OP_MULT: 1515 if (op->value == 0) 1516 fprintf(output, "MULT *"); 1517 else if (op->value == 1) 1518 fprintf(output, "MULT div"); 1519 else 1520 fprintf(output, "MULT mod"); 1521 break; 1522 case XPATH_OP_UNION: 1523 fprintf(output, "UNION"); break; 1524 case XPATH_OP_ROOT: 1525 fprintf(output, "ROOT"); break; 1526 case XPATH_OP_NODE: 1527 fprintf(output, "NODE"); break; 1528 case XPATH_OP_SORT: 1529 fprintf(output, "SORT"); break; 1530 case XPATH_OP_COLLECT: { 1531 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value; 1532 xmlXPathTestVal test = (xmlXPathTestVal)op->value2; 1533 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3; 1534 const xmlChar *prefix = op->value4; 1535 const xmlChar *name = op->value5; 1536 1537 fprintf(output, "COLLECT "); 1538 switch (axis) { 1539 case AXIS_ANCESTOR: 1540 fprintf(output, " 'ancestors' "); break; 1541 case AXIS_ANCESTOR_OR_SELF: 1542 fprintf(output, " 'ancestors-or-self' "); break; 1543 case AXIS_ATTRIBUTE: 1544 fprintf(output, " 'attributes' "); break; 1545 case AXIS_CHILD: 1546 fprintf(output, " 'child' "); break; 1547 case AXIS_DESCENDANT: 1548 fprintf(output, " 'descendant' "); break; 1549 case AXIS_DESCENDANT_OR_SELF: 1550 fprintf(output, " 'descendant-or-self' "); break; 1551 case AXIS_FOLLOWING: 1552 fprintf(output, " 'following' "); break; 1553 case AXIS_FOLLOWING_SIBLING: 1554 fprintf(output, " 'following-siblings' "); break; 1555 case AXIS_NAMESPACE: 1556 fprintf(output, " 'namespace' "); break; 1557 case AXIS_PARENT: 1558 fprintf(output, " 'parent' "); break; 1559 case AXIS_PRECEDING: 1560 fprintf(output, " 'preceding' "); break; 1561 case AXIS_PRECEDING_SIBLING: 1562 fprintf(output, " 'preceding-sibling' "); break; 1563 case AXIS_SELF: 1564 fprintf(output, " 'self' "); break; 1565 } 1566 switch (test) { 1567 case NODE_TEST_NONE: 1568 fprintf(output, "'none' "); break; 1569 case NODE_TEST_TYPE: 1570 fprintf(output, "'type' "); break; 1571 case NODE_TEST_PI: 1572 fprintf(output, "'PI' "); break; 1573 case NODE_TEST_ALL: 1574 fprintf(output, "'all' "); break; 1575 case NODE_TEST_NS: 1576 fprintf(output, "'namespace' "); break; 1577 case NODE_TEST_NAME: 1578 fprintf(output, "'name' "); break; 1579 } 1580 switch (type) { 1581 case NODE_TYPE_NODE: 1582 fprintf(output, "'node' "); break; 1583 case NODE_TYPE_COMMENT: 1584 fprintf(output, "'comment' "); break; 1585 case NODE_TYPE_TEXT: 1586 fprintf(output, "'text' "); break; 1587 case NODE_TYPE_PI: 1588 fprintf(output, "'PI' "); break; 1589 } 1590 if (prefix != NULL) 1591 fprintf(output, "%s:", prefix); 1592 if (name != NULL) 1593 fprintf(output, "%s", (const char *) name); 1594 break; 1595 1596 } 1597 case XPATH_OP_VALUE: { 1598 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4; 1599 1600 fprintf(output, "ELEM "); 1601 xmlXPathDebugDumpObject(output, object, 0); 1602 goto finish; 1603 } 1604 case XPATH_OP_VARIABLE: { 1605 const xmlChar *prefix = op->value5; 1606 const xmlChar *name = op->value4; 1607 1608 if (prefix != NULL) 1609 fprintf(output, "VARIABLE %s:%s", prefix, name); 1610 else 1611 fprintf(output, "VARIABLE %s", name); 1612 break; 1613 } 1614 case XPATH_OP_FUNCTION: { 1615 int nbargs = op->value; 1616 const xmlChar *prefix = op->value5; 1617 const xmlChar *name = op->value4; 1618 1619 if (prefix != NULL) 1620 fprintf(output, "FUNCTION %s:%s(%d args)", 1621 prefix, name, nbargs); 1622 else 1623 fprintf(output, "FUNCTION %s(%d args)", name, nbargs); 1624 break; 1625 } 1626 case XPATH_OP_ARG: fprintf(output, "ARG"); break; 1627 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break; 1628 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break; 1629 #ifdef LIBXML_XPTR_ENABLED 1630 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break; 1631 #endif 1632 default: 1633 fprintf(output, "UNKNOWN %d\n", op->op); return; 1634 } 1635 fprintf(output, "\n"); 1636 finish: 1637 if (op->ch1 >= 0) 1638 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1); 1639 if (op->ch2 >= 0) 1640 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1); 1641 } 1642 1643 /** 1644 * xmlXPathDebugDumpCompExpr: 1645 * @output: the FILE * for the output 1646 * @comp: the precompiled XPath expression 1647 * @depth: the indentation level. 1648 * 1649 * Dumps the tree of the compiled XPath expression. 1650 */ 1651 void 1652 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp, 1653 int depth) { 1654 int i; 1655 char shift[100]; 1656 1657 if ((output == NULL) || (comp == NULL)) return; 1658 1659 for (i = 0;((i < depth) && (i < 25));i++) 1660 shift[2 * i] = shift[2 * i + 1] = ' '; 1661 shift[2 * i] = shift[2 * i + 1] = 0; 1662 1663 fprintf(output, "%s", shift); 1664 1665 #ifdef XPATH_STREAMING 1666 if (comp->stream) { 1667 fprintf(output, "Streaming Expression\n"); 1668 } else 1669 #endif 1670 { 1671 fprintf(output, "Compiled Expression : %d elements\n", 1672 comp->nbStep); 1673 i = comp->last; 1674 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1); 1675 } 1676 } 1677 1678 #ifdef XP_DEBUG_OBJ_USAGE 1679 1680 /* 1681 * XPath object usage related debugging variables. 1682 */ 1683 static int xmlXPathDebugObjCounterUndefined = 0; 1684 static int xmlXPathDebugObjCounterNodeset = 0; 1685 static int xmlXPathDebugObjCounterBool = 0; 1686 static int xmlXPathDebugObjCounterNumber = 0; 1687 static int xmlXPathDebugObjCounterString = 0; 1688 static int xmlXPathDebugObjCounterPoint = 0; 1689 static int xmlXPathDebugObjCounterRange = 0; 1690 static int xmlXPathDebugObjCounterLocset = 0; 1691 static int xmlXPathDebugObjCounterUsers = 0; 1692 static int xmlXPathDebugObjCounterXSLTTree = 0; 1693 static int xmlXPathDebugObjCounterAll = 0; 1694 1695 static int xmlXPathDebugObjTotalUndefined = 0; 1696 static int xmlXPathDebugObjTotalNodeset = 0; 1697 static int xmlXPathDebugObjTotalBool = 0; 1698 static int xmlXPathDebugObjTotalNumber = 0; 1699 static int xmlXPathDebugObjTotalString = 0; 1700 static int xmlXPathDebugObjTotalPoint = 0; 1701 static int xmlXPathDebugObjTotalRange = 0; 1702 static int xmlXPathDebugObjTotalLocset = 0; 1703 static int xmlXPathDebugObjTotalUsers = 0; 1704 static int xmlXPathDebugObjTotalXSLTTree = 0; 1705 static int xmlXPathDebugObjTotalAll = 0; 1706 1707 static int xmlXPathDebugObjMaxUndefined = 0; 1708 static int xmlXPathDebugObjMaxNodeset = 0; 1709 static int xmlXPathDebugObjMaxBool = 0; 1710 static int xmlXPathDebugObjMaxNumber = 0; 1711 static int xmlXPathDebugObjMaxString = 0; 1712 static int xmlXPathDebugObjMaxPoint = 0; 1713 static int xmlXPathDebugObjMaxRange = 0; 1714 static int xmlXPathDebugObjMaxLocset = 0; 1715 static int xmlXPathDebugObjMaxUsers = 0; 1716 static int xmlXPathDebugObjMaxXSLTTree = 0; 1717 static int xmlXPathDebugObjMaxAll = 0; 1718 1719 /* REVISIT TODO: Make this static when committing */ 1720 static void 1721 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt) 1722 { 1723 if (ctxt != NULL) { 1724 if (ctxt->cache != NULL) { 1725 xmlXPathContextCachePtr cache = 1726 (xmlXPathContextCachePtr) ctxt->cache; 1727 1728 cache->dbgCachedAll = 0; 1729 cache->dbgCachedNodeset = 0; 1730 cache->dbgCachedString = 0; 1731 cache->dbgCachedBool = 0; 1732 cache->dbgCachedNumber = 0; 1733 cache->dbgCachedPoint = 0; 1734 cache->dbgCachedRange = 0; 1735 cache->dbgCachedLocset = 0; 1736 cache->dbgCachedUsers = 0; 1737 cache->dbgCachedXSLTTree = 0; 1738 cache->dbgCachedUndefined = 0; 1739 1740 cache->dbgReusedAll = 0; 1741 cache->dbgReusedNodeset = 0; 1742 cache->dbgReusedString = 0; 1743 cache->dbgReusedBool = 0; 1744 cache->dbgReusedNumber = 0; 1745 cache->dbgReusedPoint = 0; 1746 cache->dbgReusedRange = 0; 1747 cache->dbgReusedLocset = 0; 1748 cache->dbgReusedUsers = 0; 1749 cache->dbgReusedXSLTTree = 0; 1750 cache->dbgReusedUndefined = 0; 1751 } 1752 } 1753 1754 xmlXPathDebugObjCounterUndefined = 0; 1755 xmlXPathDebugObjCounterNodeset = 0; 1756 xmlXPathDebugObjCounterBool = 0; 1757 xmlXPathDebugObjCounterNumber = 0; 1758 xmlXPathDebugObjCounterString = 0; 1759 xmlXPathDebugObjCounterPoint = 0; 1760 xmlXPathDebugObjCounterRange = 0; 1761 xmlXPathDebugObjCounterLocset = 0; 1762 xmlXPathDebugObjCounterUsers = 0; 1763 xmlXPathDebugObjCounterXSLTTree = 0; 1764 xmlXPathDebugObjCounterAll = 0; 1765 1766 xmlXPathDebugObjTotalUndefined = 0; 1767 xmlXPathDebugObjTotalNodeset = 0; 1768 xmlXPathDebugObjTotalBool = 0; 1769 xmlXPathDebugObjTotalNumber = 0; 1770 xmlXPathDebugObjTotalString = 0; 1771 xmlXPathDebugObjTotalPoint = 0; 1772 xmlXPathDebugObjTotalRange = 0; 1773 xmlXPathDebugObjTotalLocset = 0; 1774 xmlXPathDebugObjTotalUsers = 0; 1775 xmlXPathDebugObjTotalXSLTTree = 0; 1776 xmlXPathDebugObjTotalAll = 0; 1777 1778 xmlXPathDebugObjMaxUndefined = 0; 1779 xmlXPathDebugObjMaxNodeset = 0; 1780 xmlXPathDebugObjMaxBool = 0; 1781 xmlXPathDebugObjMaxNumber = 0; 1782 xmlXPathDebugObjMaxString = 0; 1783 xmlXPathDebugObjMaxPoint = 0; 1784 xmlXPathDebugObjMaxRange = 0; 1785 xmlXPathDebugObjMaxLocset = 0; 1786 xmlXPathDebugObjMaxUsers = 0; 1787 xmlXPathDebugObjMaxXSLTTree = 0; 1788 xmlXPathDebugObjMaxAll = 0; 1789 1790 } 1791 1792 static void 1793 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt, 1794 xmlXPathObjectType objType) 1795 { 1796 int isCached = 0; 1797 1798 if (ctxt != NULL) { 1799 if (ctxt->cache != NULL) { 1800 xmlXPathContextCachePtr cache = 1801 (xmlXPathContextCachePtr) ctxt->cache; 1802 1803 isCached = 1; 1804 1805 cache->dbgReusedAll++; 1806 switch (objType) { 1807 case XPATH_UNDEFINED: 1808 cache->dbgReusedUndefined++; 1809 break; 1810 case XPATH_NODESET: 1811 cache->dbgReusedNodeset++; 1812 break; 1813 case XPATH_BOOLEAN: 1814 cache->dbgReusedBool++; 1815 break; 1816 case XPATH_NUMBER: 1817 cache->dbgReusedNumber++; 1818 break; 1819 case XPATH_STRING: 1820 cache->dbgReusedString++; 1821 break; 1822 case XPATH_POINT: 1823 cache->dbgReusedPoint++; 1824 break; 1825 case XPATH_RANGE: 1826 cache->dbgReusedRange++; 1827 break; 1828 case XPATH_LOCATIONSET: 1829 cache->dbgReusedLocset++; 1830 break; 1831 case XPATH_USERS: 1832 cache->dbgReusedUsers++; 1833 break; 1834 case XPATH_XSLT_TREE: 1835 cache->dbgReusedXSLTTree++; 1836 break; 1837 default: 1838 break; 1839 } 1840 } 1841 } 1842 1843 switch (objType) { 1844 case XPATH_UNDEFINED: 1845 if (! isCached) 1846 xmlXPathDebugObjTotalUndefined++; 1847 xmlXPathDebugObjCounterUndefined++; 1848 if (xmlXPathDebugObjCounterUndefined > 1849 xmlXPathDebugObjMaxUndefined) 1850 xmlXPathDebugObjMaxUndefined = 1851 xmlXPathDebugObjCounterUndefined; 1852 break; 1853 case XPATH_NODESET: 1854 if (! isCached) 1855 xmlXPathDebugObjTotalNodeset++; 1856 xmlXPathDebugObjCounterNodeset++; 1857 if (xmlXPathDebugObjCounterNodeset > 1858 xmlXPathDebugObjMaxNodeset) 1859 xmlXPathDebugObjMaxNodeset = 1860 xmlXPathDebugObjCounterNodeset; 1861 break; 1862 case XPATH_BOOLEAN: 1863 if (! isCached) 1864 xmlXPathDebugObjTotalBool++; 1865 xmlXPathDebugObjCounterBool++; 1866 if (xmlXPathDebugObjCounterBool > 1867 xmlXPathDebugObjMaxBool) 1868 xmlXPathDebugObjMaxBool = 1869 xmlXPathDebugObjCounterBool; 1870 break; 1871 case XPATH_NUMBER: 1872 if (! isCached) 1873 xmlXPathDebugObjTotalNumber++; 1874 xmlXPathDebugObjCounterNumber++; 1875 if (xmlXPathDebugObjCounterNumber > 1876 xmlXPathDebugObjMaxNumber) 1877 xmlXPathDebugObjMaxNumber = 1878 xmlXPathDebugObjCounterNumber; 1879 break; 1880 case XPATH_STRING: 1881 if (! isCached) 1882 xmlXPathDebugObjTotalString++; 1883 xmlXPathDebugObjCounterString++; 1884 if (xmlXPathDebugObjCounterString > 1885 xmlXPathDebugObjMaxString) 1886 xmlXPathDebugObjMaxString = 1887 xmlXPathDebugObjCounterString; 1888 break; 1889 case XPATH_POINT: 1890 if (! isCached) 1891 xmlXPathDebugObjTotalPoint++; 1892 xmlXPathDebugObjCounterPoint++; 1893 if (xmlXPathDebugObjCounterPoint > 1894 xmlXPathDebugObjMaxPoint) 1895 xmlXPathDebugObjMaxPoint = 1896 xmlXPathDebugObjCounterPoint; 1897 break; 1898 case XPATH_RANGE: 1899 if (! isCached) 1900 xmlXPathDebugObjTotalRange++; 1901 xmlXPathDebugObjCounterRange++; 1902 if (xmlXPathDebugObjCounterRange > 1903 xmlXPathDebugObjMaxRange) 1904 xmlXPathDebugObjMaxRange = 1905 xmlXPathDebugObjCounterRange; 1906 break; 1907 case XPATH_LOCATIONSET: 1908 if (! isCached) 1909 xmlXPathDebugObjTotalLocset++; 1910 xmlXPathDebugObjCounterLocset++; 1911 if (xmlXPathDebugObjCounterLocset > 1912 xmlXPathDebugObjMaxLocset) 1913 xmlXPathDebugObjMaxLocset = 1914 xmlXPathDebugObjCounterLocset; 1915 break; 1916 case XPATH_USERS: 1917 if (! isCached) 1918 xmlXPathDebugObjTotalUsers++; 1919 xmlXPathDebugObjCounterUsers++; 1920 if (xmlXPathDebugObjCounterUsers > 1921 xmlXPathDebugObjMaxUsers) 1922 xmlXPathDebugObjMaxUsers = 1923 xmlXPathDebugObjCounterUsers; 1924 break; 1925 case XPATH_XSLT_TREE: 1926 if (! isCached) 1927 xmlXPathDebugObjTotalXSLTTree++; 1928 xmlXPathDebugObjCounterXSLTTree++; 1929 if (xmlXPathDebugObjCounterXSLTTree > 1930 xmlXPathDebugObjMaxXSLTTree) 1931 xmlXPathDebugObjMaxXSLTTree = 1932 xmlXPathDebugObjCounterXSLTTree; 1933 break; 1934 default: 1935 break; 1936 } 1937 if (! isCached) 1938 xmlXPathDebugObjTotalAll++; 1939 xmlXPathDebugObjCounterAll++; 1940 if (xmlXPathDebugObjCounterAll > 1941 xmlXPathDebugObjMaxAll) 1942 xmlXPathDebugObjMaxAll = 1943 xmlXPathDebugObjCounterAll; 1944 } 1945 1946 static void 1947 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt, 1948 xmlXPathObjectType objType) 1949 { 1950 int isCached = 0; 1951 1952 if (ctxt != NULL) { 1953 if (ctxt->cache != NULL) { 1954 xmlXPathContextCachePtr cache = 1955 (xmlXPathContextCachePtr) ctxt->cache; 1956 1957 isCached = 1; 1958 1959 cache->dbgCachedAll++; 1960 switch (objType) { 1961 case XPATH_UNDEFINED: 1962 cache->dbgCachedUndefined++; 1963 break; 1964 case XPATH_NODESET: 1965 cache->dbgCachedNodeset++; 1966 break; 1967 case XPATH_BOOLEAN: 1968 cache->dbgCachedBool++; 1969 break; 1970 case XPATH_NUMBER: 1971 cache->dbgCachedNumber++; 1972 break; 1973 case XPATH_STRING: 1974 cache->dbgCachedString++; 1975 break; 1976 case XPATH_POINT: 1977 cache->dbgCachedPoint++; 1978 break; 1979 case XPATH_RANGE: 1980 cache->dbgCachedRange++; 1981 break; 1982 case XPATH_LOCATIONSET: 1983 cache->dbgCachedLocset++; 1984 break; 1985 case XPATH_USERS: 1986 cache->dbgCachedUsers++; 1987 break; 1988 case XPATH_XSLT_TREE: 1989 cache->dbgCachedXSLTTree++; 1990 break; 1991 default: 1992 break; 1993 } 1994 1995 } 1996 } 1997 switch (objType) { 1998 case XPATH_UNDEFINED: 1999 xmlXPathDebugObjCounterUndefined--; 2000 break; 2001 case XPATH_NODESET: 2002 xmlXPathDebugObjCounterNodeset--; 2003 break; 2004 case XPATH_BOOLEAN: 2005 xmlXPathDebugObjCounterBool--; 2006 break; 2007 case XPATH_NUMBER: 2008 xmlXPathDebugObjCounterNumber--; 2009 break; 2010 case XPATH_STRING: 2011 xmlXPathDebugObjCounterString--; 2012 break; 2013 case XPATH_POINT: 2014 xmlXPathDebugObjCounterPoint--; 2015 break; 2016 case XPATH_RANGE: 2017 xmlXPathDebugObjCounterRange--; 2018 break; 2019 case XPATH_LOCATIONSET: 2020 xmlXPathDebugObjCounterLocset--; 2021 break; 2022 case XPATH_USERS: 2023 xmlXPathDebugObjCounterUsers--; 2024 break; 2025 case XPATH_XSLT_TREE: 2026 xmlXPathDebugObjCounterXSLTTree--; 2027 break; 2028 default: 2029 break; 2030 } 2031 xmlXPathDebugObjCounterAll--; 2032 } 2033 2034 /* REVISIT TODO: Make this static when committing */ 2035 static void 2036 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt) 2037 { 2038 int reqAll, reqNodeset, reqString, reqBool, reqNumber, 2039 reqXSLTTree, reqUndefined; 2040 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0, 2041 caNumber = 0, caXSLTTree = 0, caUndefined = 0; 2042 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0, 2043 reNumber = 0, reXSLTTree = 0, reUndefined = 0; 2044 int leftObjs = xmlXPathDebugObjCounterAll; 2045 2046 reqAll = xmlXPathDebugObjTotalAll; 2047 reqNodeset = xmlXPathDebugObjTotalNodeset; 2048 reqString = xmlXPathDebugObjTotalString; 2049 reqBool = xmlXPathDebugObjTotalBool; 2050 reqNumber = xmlXPathDebugObjTotalNumber; 2051 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree; 2052 reqUndefined = xmlXPathDebugObjTotalUndefined; 2053 2054 printf("# XPath object usage:\n"); 2055 2056 if (ctxt != NULL) { 2057 if (ctxt->cache != NULL) { 2058 xmlXPathContextCachePtr cache = 2059 (xmlXPathContextCachePtr) ctxt->cache; 2060 2061 reAll = cache->dbgReusedAll; 2062 reqAll += reAll; 2063 reNodeset = cache->dbgReusedNodeset; 2064 reqNodeset += reNodeset; 2065 reString = cache->dbgReusedString; 2066 reqString += reString; 2067 reBool = cache->dbgReusedBool; 2068 reqBool += reBool; 2069 reNumber = cache->dbgReusedNumber; 2070 reqNumber += reNumber; 2071 reXSLTTree = cache->dbgReusedXSLTTree; 2072 reqXSLTTree += reXSLTTree; 2073 reUndefined = cache->dbgReusedUndefined; 2074 reqUndefined += reUndefined; 2075 2076 caAll = cache->dbgCachedAll; 2077 caBool = cache->dbgCachedBool; 2078 caNodeset = cache->dbgCachedNodeset; 2079 caString = cache->dbgCachedString; 2080 caNumber = cache->dbgCachedNumber; 2081 caXSLTTree = cache->dbgCachedXSLTTree; 2082 caUndefined = cache->dbgCachedUndefined; 2083 2084 if (cache->nodesetObjs) 2085 leftObjs -= cache->nodesetObjs->number; 2086 if (cache->stringObjs) 2087 leftObjs -= cache->stringObjs->number; 2088 if (cache->booleanObjs) 2089 leftObjs -= cache->booleanObjs->number; 2090 if (cache->numberObjs) 2091 leftObjs -= cache->numberObjs->number; 2092 if (cache->miscObjs) 2093 leftObjs -= cache->miscObjs->number; 2094 } 2095 } 2096 2097 printf("# all\n"); 2098 printf("# total : %d\n", reqAll); 2099 printf("# left : %d\n", leftObjs); 2100 printf("# created: %d\n", xmlXPathDebugObjTotalAll); 2101 printf("# reused : %d\n", reAll); 2102 printf("# max : %d\n", xmlXPathDebugObjMaxAll); 2103 2104 printf("# node-sets\n"); 2105 printf("# total : %d\n", reqNodeset); 2106 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset); 2107 printf("# reused : %d\n", reNodeset); 2108 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset); 2109 2110 printf("# strings\n"); 2111 printf("# total : %d\n", reqString); 2112 printf("# created: %d\n", xmlXPathDebugObjTotalString); 2113 printf("# reused : %d\n", reString); 2114 printf("# max : %d\n", xmlXPathDebugObjMaxString); 2115 2116 printf("# booleans\n"); 2117 printf("# total : %d\n", reqBool); 2118 printf("# created: %d\n", xmlXPathDebugObjTotalBool); 2119 printf("# reused : %d\n", reBool); 2120 printf("# max : %d\n", xmlXPathDebugObjMaxBool); 2121 2122 printf("# numbers\n"); 2123 printf("# total : %d\n", reqNumber); 2124 printf("# created: %d\n", xmlXPathDebugObjTotalNumber); 2125 printf("# reused : %d\n", reNumber); 2126 printf("# max : %d\n", xmlXPathDebugObjMaxNumber); 2127 2128 printf("# XSLT result tree fragments\n"); 2129 printf("# total : %d\n", reqXSLTTree); 2130 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree); 2131 printf("# reused : %d\n", reXSLTTree); 2132 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree); 2133 2134 printf("# undefined\n"); 2135 printf("# total : %d\n", reqUndefined); 2136 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined); 2137 printf("# reused : %d\n", reUndefined); 2138 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined); 2139 2140 } 2141 2142 #endif /* XP_DEBUG_OBJ_USAGE */ 2143 2144 #endif /* LIBXML_DEBUG_ENABLED */ 2145 2146 /************************************************************************ 2147 * * 2148 * XPath object caching * 2149 * * 2150 ************************************************************************/ 2151 2152 /** 2153 * xmlXPathNewCache: 2154 * 2155 * Create a new object cache 2156 * 2157 * Returns the xmlXPathCache just allocated. 2158 */ 2159 static xmlXPathContextCachePtr 2160 xmlXPathNewCache(void) 2161 { 2162 xmlXPathContextCachePtr ret; 2163 2164 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache)); 2165 if (ret == NULL) { 2166 xmlXPathErrMemory(NULL, "creating object cache\n"); 2167 return(NULL); 2168 } 2169 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache)); 2170 ret->maxNodeset = 100; 2171 ret->maxString = 100; 2172 ret->maxBoolean = 100; 2173 ret->maxNumber = 100; 2174 ret->maxMisc = 100; 2175 return(ret); 2176 } 2177 2178 static void 2179 xmlXPathCacheFreeObjectList(xmlPointerListPtr list) 2180 { 2181 int i; 2182 xmlXPathObjectPtr obj; 2183 2184 if (list == NULL) 2185 return; 2186 2187 for (i = 0; i < list->number; i++) { 2188 obj = list->items[i]; 2189 /* 2190 * Note that it is already assured that we don't need to 2191 * look out for namespace nodes in the node-set. 2192 */ 2193 if (obj->nodesetval != NULL) { 2194 if (obj->nodesetval->nodeTab != NULL) 2195 xmlFree(obj->nodesetval->nodeTab); 2196 xmlFree(obj->nodesetval); 2197 } 2198 xmlFree(obj); 2199 #ifdef XP_DEBUG_OBJ_USAGE 2200 xmlXPathDebugObjCounterAll--; 2201 #endif 2202 } 2203 xmlPointerListFree(list); 2204 } 2205 2206 static void 2207 xmlXPathFreeCache(xmlXPathContextCachePtr cache) 2208 { 2209 if (cache == NULL) 2210 return; 2211 if (cache->nodesetObjs) 2212 xmlXPathCacheFreeObjectList(cache->nodesetObjs); 2213 if (cache->stringObjs) 2214 xmlXPathCacheFreeObjectList(cache->stringObjs); 2215 if (cache->booleanObjs) 2216 xmlXPathCacheFreeObjectList(cache->booleanObjs); 2217 if (cache->numberObjs) 2218 xmlXPathCacheFreeObjectList(cache->numberObjs); 2219 if (cache->miscObjs) 2220 xmlXPathCacheFreeObjectList(cache->miscObjs); 2221 xmlFree(cache); 2222 } 2223 2224 /** 2225 * xmlXPathContextSetCache: 2226 * 2227 * @ctxt: the XPath context 2228 * @active: enables/disables (creates/frees) the cache 2229 * @value: a value with semantics dependant on @options 2230 * @options: options (currently only the value 0 is used) 2231 * 2232 * Creates/frees an object cache on the XPath context. 2233 * If activates XPath objects (xmlXPathObject) will be cached internally 2234 * to be reused. 2235 * @options: 2236 * 0: This will set the XPath object caching: 2237 * @value: 2238 * This will set the maximum number of XPath objects 2239 * to be cached per slot 2240 * There are 5 slots for: node-set, string, number, boolean, and 2241 * misc objects. Use <0 for the default number (100). 2242 * Other values for @options have currently no effect. 2243 * 2244 * Returns 0 if the setting succeeded, and -1 on API or internal errors. 2245 */ 2246 int 2247 xmlXPathContextSetCache(xmlXPathContextPtr ctxt, 2248 int active, 2249 int value, 2250 int options) 2251 { 2252 if (ctxt == NULL) 2253 return(-1); 2254 if (active) { 2255 xmlXPathContextCachePtr cache; 2256 2257 if (ctxt->cache == NULL) { 2258 ctxt->cache = xmlXPathNewCache(); 2259 if (ctxt->cache == NULL) 2260 return(-1); 2261 } 2262 cache = (xmlXPathContextCachePtr) ctxt->cache; 2263 if (options == 0) { 2264 if (value < 0) 2265 value = 100; 2266 cache->maxNodeset = value; 2267 cache->maxString = value; 2268 cache->maxNumber = value; 2269 cache->maxBoolean = value; 2270 cache->maxMisc = value; 2271 } 2272 } else if (ctxt->cache != NULL) { 2273 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache); 2274 ctxt->cache = NULL; 2275 } 2276 return(0); 2277 } 2278 2279 /** 2280 * xmlXPathCacheWrapNodeSet: 2281 * @ctxt: the XPath context 2282 * @val: the NodePtr value 2283 * 2284 * This is the cached version of xmlXPathWrapNodeSet(). 2285 * Wrap the Nodeset @val in a new xmlXPathObjectPtr 2286 * 2287 * Returns the created or reused object. 2288 */ 2289 static xmlXPathObjectPtr 2290 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val) 2291 { 2292 if ((ctxt != NULL) && (ctxt->cache != NULL)) { 2293 xmlXPathContextCachePtr cache = 2294 (xmlXPathContextCachePtr) ctxt->cache; 2295 2296 if ((cache->miscObjs != NULL) && 2297 (cache->miscObjs->number != 0)) 2298 { 2299 xmlXPathObjectPtr ret; 2300 2301 ret = (xmlXPathObjectPtr) 2302 cache->miscObjs->items[--cache->miscObjs->number]; 2303 ret->type = XPATH_NODESET; 2304 ret->nodesetval = val; 2305 #ifdef XP_DEBUG_OBJ_USAGE 2306 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 2307 #endif 2308 return(ret); 2309 } 2310 } 2311 2312 return(xmlXPathWrapNodeSet(val)); 2313 2314 } 2315 2316 /** 2317 * xmlXPathCacheWrapString: 2318 * @ctxt: the XPath context 2319 * @val: the xmlChar * value 2320 * 2321 * This is the cached version of xmlXPathWrapString(). 2322 * Wraps the @val string into an XPath object. 2323 * 2324 * Returns the created or reused object. 2325 */ 2326 static xmlXPathObjectPtr 2327 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val) 2328 { 2329 if ((ctxt != NULL) && (ctxt->cache != NULL)) { 2330 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2331 2332 if ((cache->stringObjs != NULL) && 2333 (cache->stringObjs->number != 0)) 2334 { 2335 2336 xmlXPathObjectPtr ret; 2337 2338 ret = (xmlXPathObjectPtr) 2339 cache->stringObjs->items[--cache->stringObjs->number]; 2340 ret->type = XPATH_STRING; 2341 ret->stringval = val; 2342 #ifdef XP_DEBUG_OBJ_USAGE 2343 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2344 #endif 2345 return(ret); 2346 } else if ((cache->miscObjs != NULL) && 2347 (cache->miscObjs->number != 0)) 2348 { 2349 xmlXPathObjectPtr ret; 2350 /* 2351 * Fallback to misc-cache. 2352 */ 2353 ret = (xmlXPathObjectPtr) 2354 cache->miscObjs->items[--cache->miscObjs->number]; 2355 2356 ret->type = XPATH_STRING; 2357 ret->stringval = val; 2358 #ifdef XP_DEBUG_OBJ_USAGE 2359 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2360 #endif 2361 return(ret); 2362 } 2363 } 2364 return(xmlXPathWrapString(val)); 2365 } 2366 2367 /** 2368 * xmlXPathCacheNewNodeSet: 2369 * @ctxt: the XPath context 2370 * @val: the NodePtr value 2371 * 2372 * This is the cached version of xmlXPathNewNodeSet(). 2373 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize 2374 * it with the single Node @val 2375 * 2376 * Returns the created or reused object. 2377 */ 2378 static xmlXPathObjectPtr 2379 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val) 2380 { 2381 if ((ctxt != NULL) && (ctxt->cache)) { 2382 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2383 2384 if ((cache->nodesetObjs != NULL) && 2385 (cache->nodesetObjs->number != 0)) 2386 { 2387 xmlXPathObjectPtr ret; 2388 /* 2389 * Use the nodset-cache. 2390 */ 2391 ret = (xmlXPathObjectPtr) 2392 cache->nodesetObjs->items[--cache->nodesetObjs->number]; 2393 ret->type = XPATH_NODESET; 2394 ret->boolval = 0; 2395 if (val) { 2396 if ((ret->nodesetval->nodeMax == 0) || 2397 (val->type == XML_NAMESPACE_DECL)) 2398 { 2399 xmlXPathNodeSetAddUnique(ret->nodesetval, val); 2400 } else { 2401 ret->nodesetval->nodeTab[0] = val; 2402 ret->nodesetval->nodeNr = 1; 2403 } 2404 } 2405 #ifdef XP_DEBUG_OBJ_USAGE 2406 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 2407 #endif 2408 return(ret); 2409 } else if ((cache->miscObjs != NULL) && 2410 (cache->miscObjs->number != 0)) 2411 { 2412 xmlXPathObjectPtr ret; 2413 /* 2414 * Fallback to misc-cache. 2415 */ 2416 2417 ret = (xmlXPathObjectPtr) 2418 cache->miscObjs->items[--cache->miscObjs->number]; 2419 2420 ret->type = XPATH_NODESET; 2421 ret->boolval = 0; 2422 ret->nodesetval = xmlXPathNodeSetCreate(val); 2423 if (ret->nodesetval == NULL) { 2424 ctxt->lastError.domain = XML_FROM_XPATH; 2425 ctxt->lastError.code = XML_ERR_NO_MEMORY; 2426 return(NULL); 2427 } 2428 #ifdef XP_DEBUG_OBJ_USAGE 2429 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 2430 #endif 2431 return(ret); 2432 } 2433 } 2434 return(xmlXPathNewNodeSet(val)); 2435 } 2436 2437 /** 2438 * xmlXPathCacheNewCString: 2439 * @ctxt: the XPath context 2440 * @val: the char * value 2441 * 2442 * This is the cached version of xmlXPathNewCString(). 2443 * Acquire an xmlXPathObjectPtr of type string and of value @val 2444 * 2445 * Returns the created or reused object. 2446 */ 2447 static xmlXPathObjectPtr 2448 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val) 2449 { 2450 if ((ctxt != NULL) && (ctxt->cache)) { 2451 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2452 2453 if ((cache->stringObjs != NULL) && 2454 (cache->stringObjs->number != 0)) 2455 { 2456 xmlXPathObjectPtr ret; 2457 2458 ret = (xmlXPathObjectPtr) 2459 cache->stringObjs->items[--cache->stringObjs->number]; 2460 2461 ret->type = XPATH_STRING; 2462 ret->stringval = xmlStrdup(BAD_CAST val); 2463 #ifdef XP_DEBUG_OBJ_USAGE 2464 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2465 #endif 2466 return(ret); 2467 } else if ((cache->miscObjs != NULL) && 2468 (cache->miscObjs->number != 0)) 2469 { 2470 xmlXPathObjectPtr ret; 2471 2472 ret = (xmlXPathObjectPtr) 2473 cache->miscObjs->items[--cache->miscObjs->number]; 2474 2475 ret->type = XPATH_STRING; 2476 ret->stringval = xmlStrdup(BAD_CAST val); 2477 #ifdef XP_DEBUG_OBJ_USAGE 2478 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2479 #endif 2480 return(ret); 2481 } 2482 } 2483 return(xmlXPathNewCString(val)); 2484 } 2485 2486 /** 2487 * xmlXPathCacheNewString: 2488 * @ctxt: the XPath context 2489 * @val: the xmlChar * value 2490 * 2491 * This is the cached version of xmlXPathNewString(). 2492 * Acquire an xmlXPathObjectPtr of type string and of value @val 2493 * 2494 * Returns the created or reused object. 2495 */ 2496 static xmlXPathObjectPtr 2497 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val) 2498 { 2499 if ((ctxt != NULL) && (ctxt->cache)) { 2500 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2501 2502 if ((cache->stringObjs != NULL) && 2503 (cache->stringObjs->number != 0)) 2504 { 2505 xmlXPathObjectPtr ret; 2506 2507 ret = (xmlXPathObjectPtr) 2508 cache->stringObjs->items[--cache->stringObjs->number]; 2509 ret->type = XPATH_STRING; 2510 if (val != NULL) 2511 ret->stringval = xmlStrdup(val); 2512 else 2513 ret->stringval = xmlStrdup((const xmlChar *)""); 2514 #ifdef XP_DEBUG_OBJ_USAGE 2515 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2516 #endif 2517 return(ret); 2518 } else if ((cache->miscObjs != NULL) && 2519 (cache->miscObjs->number != 0)) 2520 { 2521 xmlXPathObjectPtr ret; 2522 2523 ret = (xmlXPathObjectPtr) 2524 cache->miscObjs->items[--cache->miscObjs->number]; 2525 2526 ret->type = XPATH_STRING; 2527 if (val != NULL) 2528 ret->stringval = xmlStrdup(val); 2529 else 2530 ret->stringval = xmlStrdup((const xmlChar *)""); 2531 #ifdef XP_DEBUG_OBJ_USAGE 2532 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2533 #endif 2534 return(ret); 2535 } 2536 } 2537 return(xmlXPathNewString(val)); 2538 } 2539 2540 /** 2541 * xmlXPathCacheNewBoolean: 2542 * @ctxt: the XPath context 2543 * @val: the boolean value 2544 * 2545 * This is the cached version of xmlXPathNewBoolean(). 2546 * Acquires an xmlXPathObjectPtr of type boolean and of value @val 2547 * 2548 * Returns the created or reused object. 2549 */ 2550 static xmlXPathObjectPtr 2551 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val) 2552 { 2553 if ((ctxt != NULL) && (ctxt->cache)) { 2554 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2555 2556 if ((cache->booleanObjs != NULL) && 2557 (cache->booleanObjs->number != 0)) 2558 { 2559 xmlXPathObjectPtr ret; 2560 2561 ret = (xmlXPathObjectPtr) 2562 cache->booleanObjs->items[--cache->booleanObjs->number]; 2563 ret->type = XPATH_BOOLEAN; 2564 ret->boolval = (val != 0); 2565 #ifdef XP_DEBUG_OBJ_USAGE 2566 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN); 2567 #endif 2568 return(ret); 2569 } else if ((cache->miscObjs != NULL) && 2570 (cache->miscObjs->number != 0)) 2571 { 2572 xmlXPathObjectPtr ret; 2573 2574 ret = (xmlXPathObjectPtr) 2575 cache->miscObjs->items[--cache->miscObjs->number]; 2576 2577 ret->type = XPATH_BOOLEAN; 2578 ret->boolval = (val != 0); 2579 #ifdef XP_DEBUG_OBJ_USAGE 2580 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN); 2581 #endif 2582 return(ret); 2583 } 2584 } 2585 return(xmlXPathNewBoolean(val)); 2586 } 2587 2588 /** 2589 * xmlXPathCacheNewFloat: 2590 * @ctxt: the XPath context 2591 * @val: the double value 2592 * 2593 * This is the cached version of xmlXPathNewFloat(). 2594 * Acquires an xmlXPathObjectPtr of type double and of value @val 2595 * 2596 * Returns the created or reused object. 2597 */ 2598 static xmlXPathObjectPtr 2599 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val) 2600 { 2601 if ((ctxt != NULL) && (ctxt->cache)) { 2602 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2603 2604 if ((cache->numberObjs != NULL) && 2605 (cache->numberObjs->number != 0)) 2606 { 2607 xmlXPathObjectPtr ret; 2608 2609 ret = (xmlXPathObjectPtr) 2610 cache->numberObjs->items[--cache->numberObjs->number]; 2611 ret->type = XPATH_NUMBER; 2612 ret->floatval = val; 2613 #ifdef XP_DEBUG_OBJ_USAGE 2614 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER); 2615 #endif 2616 return(ret); 2617 } else if ((cache->miscObjs != NULL) && 2618 (cache->miscObjs->number != 0)) 2619 { 2620 xmlXPathObjectPtr ret; 2621 2622 ret = (xmlXPathObjectPtr) 2623 cache->miscObjs->items[--cache->miscObjs->number]; 2624 2625 ret->type = XPATH_NUMBER; 2626 ret->floatval = val; 2627 #ifdef XP_DEBUG_OBJ_USAGE 2628 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER); 2629 #endif 2630 return(ret); 2631 } 2632 } 2633 return(xmlXPathNewFloat(val)); 2634 } 2635 2636 /** 2637 * xmlXPathCacheConvertString: 2638 * @ctxt: the XPath context 2639 * @val: an XPath object 2640 * 2641 * This is the cached version of xmlXPathConvertString(). 2642 * Converts an existing object to its string() equivalent 2643 * 2644 * Returns a created or reused object, the old one is freed (cached) 2645 * (or the operation is done directly on @val) 2646 */ 2647 2648 static xmlXPathObjectPtr 2649 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 2650 xmlChar *res = NULL; 2651 2652 if (val == NULL) 2653 return(xmlXPathCacheNewCString(ctxt, "")); 2654 2655 switch (val->type) { 2656 case XPATH_UNDEFINED: 2657 #ifdef DEBUG_EXPR 2658 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n"); 2659 #endif 2660 break; 2661 case XPATH_NODESET: 2662 case XPATH_XSLT_TREE: 2663 res = xmlXPathCastNodeSetToString(val->nodesetval); 2664 break; 2665 case XPATH_STRING: 2666 return(val); 2667 case XPATH_BOOLEAN: 2668 res = xmlXPathCastBooleanToString(val->boolval); 2669 break; 2670 case XPATH_NUMBER: 2671 res = xmlXPathCastNumberToString(val->floatval); 2672 break; 2673 case XPATH_USERS: 2674 case XPATH_POINT: 2675 case XPATH_RANGE: 2676 case XPATH_LOCATIONSET: 2677 TODO; 2678 break; 2679 } 2680 xmlXPathReleaseObject(ctxt, val); 2681 if (res == NULL) 2682 return(xmlXPathCacheNewCString(ctxt, "")); 2683 return(xmlXPathCacheWrapString(ctxt, res)); 2684 } 2685 2686 /** 2687 * xmlXPathCacheObjectCopy: 2688 * @ctxt: the XPath context 2689 * @val: the original object 2690 * 2691 * This is the cached version of xmlXPathObjectCopy(). 2692 * Acquire a copy of a given object 2693 * 2694 * Returns a created or reused created object. 2695 */ 2696 static xmlXPathObjectPtr 2697 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) 2698 { 2699 if (val == NULL) 2700 return(NULL); 2701 2702 if (XP_HAS_CACHE(ctxt)) { 2703 switch (val->type) { 2704 case XPATH_NODESET: 2705 return(xmlXPathCacheWrapNodeSet(ctxt, 2706 xmlXPathNodeSetMerge(NULL, val->nodesetval))); 2707 case XPATH_STRING: 2708 return(xmlXPathCacheNewString(ctxt, val->stringval)); 2709 case XPATH_BOOLEAN: 2710 return(xmlXPathCacheNewBoolean(ctxt, val->boolval)); 2711 case XPATH_NUMBER: 2712 return(xmlXPathCacheNewFloat(ctxt, val->floatval)); 2713 default: 2714 break; 2715 } 2716 } 2717 return(xmlXPathObjectCopy(val)); 2718 } 2719 2720 /** 2721 * xmlXPathCacheConvertBoolean: 2722 * @ctxt: the XPath context 2723 * @val: an XPath object 2724 * 2725 * This is the cached version of xmlXPathConvertBoolean(). 2726 * Converts an existing object to its boolean() equivalent 2727 * 2728 * Returns a created or reused object, the old one is freed (or the operation 2729 * is done directly on @val) 2730 */ 2731 static xmlXPathObjectPtr 2732 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 2733 xmlXPathObjectPtr ret; 2734 2735 if (val == NULL) 2736 return(xmlXPathCacheNewBoolean(ctxt, 0)); 2737 if (val->type == XPATH_BOOLEAN) 2738 return(val); 2739 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val)); 2740 xmlXPathReleaseObject(ctxt, val); 2741 return(ret); 2742 } 2743 2744 /** 2745 * xmlXPathCacheConvertNumber: 2746 * @ctxt: the XPath context 2747 * @val: an XPath object 2748 * 2749 * This is the cached version of xmlXPathConvertNumber(). 2750 * Converts an existing object to its number() equivalent 2751 * 2752 * Returns a created or reused object, the old one is freed (or the operation 2753 * is done directly on @val) 2754 */ 2755 static xmlXPathObjectPtr 2756 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 2757 xmlXPathObjectPtr ret; 2758 2759 if (val == NULL) 2760 return(xmlXPathCacheNewFloat(ctxt, 0.0)); 2761 if (val->type == XPATH_NUMBER) 2762 return(val); 2763 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val)); 2764 xmlXPathReleaseObject(ctxt, val); 2765 return(ret); 2766 } 2767 2768 /************************************************************************ 2769 * * 2770 * Parser stacks related functions and macros * 2771 * * 2772 ************************************************************************/ 2773 2774 /** 2775 * xmlXPathSetFrame: 2776 * @ctxt: an XPath parser context 2777 * 2778 * Set the callee evaluation frame 2779 * 2780 * Returns the previous frame value to be restored once done 2781 */ 2782 static int 2783 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) { 2784 int ret; 2785 2786 if (ctxt == NULL) 2787 return(0); 2788 ret = ctxt->valueFrame; 2789 ctxt->valueFrame = ctxt->valueNr; 2790 return(ret); 2791 } 2792 2793 /** 2794 * xmlXPathPopFrame: 2795 * @ctxt: an XPath parser context 2796 * @frame: the previous frame value 2797 * 2798 * Remove the callee evaluation frame 2799 */ 2800 static void 2801 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) { 2802 if (ctxt == NULL) 2803 return; 2804 if (ctxt->valueNr < ctxt->valueFrame) { 2805 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR); 2806 } 2807 ctxt->valueFrame = frame; 2808 } 2809 2810 /** 2811 * valuePop: 2812 * @ctxt: an XPath evaluation context 2813 * 2814 * Pops the top XPath object from the value stack 2815 * 2816 * Returns the XPath object just removed 2817 */ 2818 xmlXPathObjectPtr 2819 valuePop(xmlXPathParserContextPtr ctxt) 2820 { 2821 xmlXPathObjectPtr ret; 2822 2823 if ((ctxt == NULL) || (ctxt->valueNr <= 0)) 2824 return (NULL); 2825 2826 if (ctxt->valueNr <= ctxt->valueFrame) { 2827 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR); 2828 return (NULL); 2829 } 2830 2831 ctxt->valueNr--; 2832 if (ctxt->valueNr > 0) 2833 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1]; 2834 else 2835 ctxt->value = NULL; 2836 ret = ctxt->valueTab[ctxt->valueNr]; 2837 ctxt->valueTab[ctxt->valueNr] = NULL; 2838 return (ret); 2839 } 2840 /** 2841 * valuePush: 2842 * @ctxt: an XPath evaluation context 2843 * @value: the XPath object 2844 * 2845 * Pushes a new XPath object on top of the value stack 2846 * 2847 * returns the number of items on the value stack 2848 */ 2849 int 2850 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value) 2851 { 2852 if ((ctxt == NULL) || (value == NULL)) return(-1); 2853 if (ctxt->valueNr >= ctxt->valueMax) { 2854 xmlXPathObjectPtr *tmp; 2855 2856 if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) { 2857 xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n"); 2858 ctxt->error = XPATH_MEMORY_ERROR; 2859 return (0); 2860 } 2861 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab, 2862 2 * ctxt->valueMax * 2863 sizeof(ctxt->valueTab[0])); 2864 if (tmp == NULL) { 2865 xmlXPathErrMemory(NULL, "pushing value\n"); 2866 ctxt->error = XPATH_MEMORY_ERROR; 2867 return (0); 2868 } 2869 ctxt->valueMax *= 2; 2870 ctxt->valueTab = tmp; 2871 } 2872 ctxt->valueTab[ctxt->valueNr] = value; 2873 ctxt->value = value; 2874 return (ctxt->valueNr++); 2875 } 2876 2877 /** 2878 * xmlXPathPopBoolean: 2879 * @ctxt: an XPath parser context 2880 * 2881 * Pops a boolean from the stack, handling conversion if needed. 2882 * Check error with #xmlXPathCheckError. 2883 * 2884 * Returns the boolean 2885 */ 2886 int 2887 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) { 2888 xmlXPathObjectPtr obj; 2889 int ret; 2890 2891 obj = valuePop(ctxt); 2892 if (obj == NULL) { 2893 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2894 return(0); 2895 } 2896 if (obj->type != XPATH_BOOLEAN) 2897 ret = xmlXPathCastToBoolean(obj); 2898 else 2899 ret = obj->boolval; 2900 xmlXPathReleaseObject(ctxt->context, obj); 2901 return(ret); 2902 } 2903 2904 /** 2905 * xmlXPathPopNumber: 2906 * @ctxt: an XPath parser context 2907 * 2908 * Pops a number from the stack, handling conversion if needed. 2909 * Check error with #xmlXPathCheckError. 2910 * 2911 * Returns the number 2912 */ 2913 double 2914 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) { 2915 xmlXPathObjectPtr obj; 2916 double ret; 2917 2918 obj = valuePop(ctxt); 2919 if (obj == NULL) { 2920 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2921 return(0); 2922 } 2923 if (obj->type != XPATH_NUMBER) 2924 ret = xmlXPathCastToNumber(obj); 2925 else 2926 ret = obj->floatval; 2927 xmlXPathReleaseObject(ctxt->context, obj); 2928 return(ret); 2929 } 2930 2931 /** 2932 * xmlXPathPopString: 2933 * @ctxt: an XPath parser context 2934 * 2935 * Pops a string from the stack, handling conversion if needed. 2936 * Check error with #xmlXPathCheckError. 2937 * 2938 * Returns the string 2939 */ 2940 xmlChar * 2941 xmlXPathPopString (xmlXPathParserContextPtr ctxt) { 2942 xmlXPathObjectPtr obj; 2943 xmlChar * ret; 2944 2945 obj = valuePop(ctxt); 2946 if (obj == NULL) { 2947 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2948 return(NULL); 2949 } 2950 ret = xmlXPathCastToString(obj); /* this does required strdup */ 2951 /* TODO: needs refactoring somewhere else */ 2952 if (obj->stringval == ret) 2953 obj->stringval = NULL; 2954 xmlXPathReleaseObject(ctxt->context, obj); 2955 return(ret); 2956 } 2957 2958 /** 2959 * xmlXPathPopNodeSet: 2960 * @ctxt: an XPath parser context 2961 * 2962 * Pops a node-set from the stack, handling conversion if needed. 2963 * Check error with #xmlXPathCheckError. 2964 * 2965 * Returns the node-set 2966 */ 2967 xmlNodeSetPtr 2968 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) { 2969 xmlXPathObjectPtr obj; 2970 xmlNodeSetPtr ret; 2971 2972 if (ctxt == NULL) return(NULL); 2973 if (ctxt->value == NULL) { 2974 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2975 return(NULL); 2976 } 2977 if (!xmlXPathStackIsNodeSet(ctxt)) { 2978 xmlXPathSetTypeError(ctxt); 2979 return(NULL); 2980 } 2981 obj = valuePop(ctxt); 2982 ret = obj->nodesetval; 2983 #if 0 2984 /* to fix memory leak of not clearing obj->user */ 2985 if (obj->boolval && obj->user != NULL) 2986 xmlFreeNodeList((xmlNodePtr) obj->user); 2987 #endif 2988 obj->nodesetval = NULL; 2989 xmlXPathReleaseObject(ctxt->context, obj); 2990 return(ret); 2991 } 2992 2993 /** 2994 * xmlXPathPopExternal: 2995 * @ctxt: an XPath parser context 2996 * 2997 * Pops an external object from the stack, handling conversion if needed. 2998 * Check error with #xmlXPathCheckError. 2999 * 3000 * Returns the object 3001 */ 3002 void * 3003 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) { 3004 xmlXPathObjectPtr obj; 3005 void * ret; 3006 3007 if ((ctxt == NULL) || (ctxt->value == NULL)) { 3008 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 3009 return(NULL); 3010 } 3011 if (ctxt->value->type != XPATH_USERS) { 3012 xmlXPathSetTypeError(ctxt); 3013 return(NULL); 3014 } 3015 obj = valuePop(ctxt); 3016 ret = obj->user; 3017 obj->user = NULL; 3018 xmlXPathReleaseObject(ctxt->context, obj); 3019 return(ret); 3020 } 3021 3022 /* 3023 * Macros for accessing the content. Those should be used only by the parser, 3024 * and not exported. 3025 * 3026 * Dirty macros, i.e. one need to make assumption on the context to use them 3027 * 3028 * CUR_PTR return the current pointer to the xmlChar to be parsed. 3029 * CUR returns the current xmlChar value, i.e. a 8 bit value 3030 * in ISO-Latin or UTF-8. 3031 * This should be used internally by the parser 3032 * only to compare to ASCII values otherwise it would break when 3033 * running with UTF-8 encoding. 3034 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only 3035 * to compare on ASCII based substring. 3036 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined 3037 * strings within the parser. 3038 * CURRENT Returns the current char value, with the full decoding of 3039 * UTF-8 if we are using this mode. It returns an int. 3040 * NEXT Skip to the next character, this does the proper decoding 3041 * in UTF-8 mode. It also pop-up unfinished entities on the fly. 3042 * It returns the pointer to the current xmlChar. 3043 */ 3044 3045 #define CUR (*ctxt->cur) 3046 #define SKIP(val) ctxt->cur += (val) 3047 #define NXT(val) ctxt->cur[(val)] 3048 #define CUR_PTR ctxt->cur 3049 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l) 3050 3051 #define COPY_BUF(l,b,i,v) \ 3052 if (l == 1) b[i++] = (xmlChar) v; \ 3053 else i += xmlCopyChar(l,&b[i],v) 3054 3055 #define NEXTL(l) ctxt->cur += l 3056 3057 #define SKIP_BLANKS \ 3058 while (IS_BLANK_CH(*(ctxt->cur))) NEXT 3059 3060 #define CURRENT (*ctxt->cur) 3061 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur) 3062 3063 3064 #ifndef DBL_DIG 3065 #define DBL_DIG 16 3066 #endif 3067 #ifndef DBL_EPSILON 3068 #define DBL_EPSILON 1E-9 3069 #endif 3070 3071 #define UPPER_DOUBLE 1E9 3072 #define LOWER_DOUBLE 1E-5 3073 #define LOWER_DOUBLE_EXP 5 3074 3075 #define INTEGER_DIGITS DBL_DIG 3076 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP)) 3077 #define EXPONENT_DIGITS (3 + 2) 3078 3079 /** 3080 * xmlXPathFormatNumber: 3081 * @number: number to format 3082 * @buffer: output buffer 3083 * @buffersize: size of output buffer 3084 * 3085 * Convert the number into a string representation. 3086 */ 3087 static void 3088 xmlXPathFormatNumber(double number, char buffer[], int buffersize) 3089 { 3090 switch (xmlXPathIsInf(number)) { 3091 case 1: 3092 if (buffersize > (int)sizeof("Infinity")) 3093 snprintf(buffer, buffersize, "Infinity"); 3094 break; 3095 case -1: 3096 if (buffersize > (int)sizeof("-Infinity")) 3097 snprintf(buffer, buffersize, "-Infinity"); 3098 break; 3099 default: 3100 if (xmlXPathIsNaN(number)) { 3101 if (buffersize > (int)sizeof("NaN")) 3102 snprintf(buffer, buffersize, "NaN"); 3103 } else if (number == 0) { 3104 /* Omit sign for negative zero. */ 3105 snprintf(buffer, buffersize, "0"); 3106 } else if ((number > INT_MIN) && (number < INT_MAX) && 3107 (number == (int) number)) { 3108 char work[30]; 3109 char *ptr, *cur; 3110 int value = (int) number; 3111 3112 ptr = &buffer[0]; 3113 if (value == 0) { 3114 *ptr++ = '0'; 3115 } else { 3116 snprintf(work, 29, "%d", value); 3117 cur = &work[0]; 3118 while ((*cur) && (ptr - buffer < buffersize)) { 3119 *ptr++ = *cur++; 3120 } 3121 } 3122 if (ptr - buffer < buffersize) { 3123 *ptr = 0; 3124 } else if (buffersize > 0) { 3125 ptr--; 3126 *ptr = 0; 3127 } 3128 } else { 3129 /* 3130 For the dimension of work, 3131 DBL_DIG is number of significant digits 3132 EXPONENT is only needed for "scientific notation" 3133 3 is sign, decimal point, and terminating zero 3134 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction 3135 Note that this dimension is slightly (a few characters) 3136 larger than actually necessary. 3137 */ 3138 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP]; 3139 int integer_place, fraction_place; 3140 char *ptr; 3141 char *after_fraction; 3142 double absolute_value; 3143 int size; 3144 3145 absolute_value = fabs(number); 3146 3147 /* 3148 * First choose format - scientific or regular floating point. 3149 * In either case, result is in work, and after_fraction points 3150 * just past the fractional part. 3151 */ 3152 if ( ((absolute_value > UPPER_DOUBLE) || 3153 (absolute_value < LOWER_DOUBLE)) && 3154 (absolute_value != 0.0) ) { 3155 /* Use scientific notation */ 3156 integer_place = DBL_DIG + EXPONENT_DIGITS + 1; 3157 fraction_place = DBL_DIG - 1; 3158 size = snprintf(work, sizeof(work),"%*.*e", 3159 integer_place, fraction_place, number); 3160 while ((size > 0) && (work[size] != 'e')) size--; 3161 3162 } 3163 else { 3164 /* Use regular notation */ 3165 if (absolute_value > 0.0) { 3166 integer_place = (int)log10(absolute_value); 3167 if (integer_place > 0) 3168 fraction_place = DBL_DIG - integer_place - 1; 3169 else 3170 fraction_place = DBL_DIG - integer_place; 3171 } else { 3172 fraction_place = 1; 3173 } 3174 size = snprintf(work, sizeof(work), "%0.*f", 3175 fraction_place, number); 3176 } 3177 3178 /* Remove leading spaces sometimes inserted by snprintf */ 3179 while (work[0] == ' ') { 3180 for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++); 3181 size--; 3182 } 3183 3184 /* Remove fractional trailing zeroes */ 3185 after_fraction = work + size; 3186 ptr = after_fraction; 3187 while (*(--ptr) == '0') 3188 ; 3189 if (*ptr != '.') 3190 ptr++; 3191 while ((*ptr++ = *after_fraction++) != 0); 3192 3193 /* Finally copy result back to caller */ 3194 size = strlen(work) + 1; 3195 if (size > buffersize) { 3196 work[buffersize - 1] = 0; 3197 size = buffersize; 3198 } 3199 memmove(buffer, work, size); 3200 } 3201 break; 3202 } 3203 } 3204 3205 3206 /************************************************************************ 3207 * * 3208 * Routines to handle NodeSets * 3209 * * 3210 ************************************************************************/ 3211 3212 /** 3213 * xmlXPathOrderDocElems: 3214 * @doc: an input document 3215 * 3216 * Call this routine to speed up XPath computation on static documents. 3217 * This stamps all the element nodes with the document order 3218 * Like for line information, the order is kept in the element->content 3219 * field, the value stored is actually - the node number (starting at -1) 3220 * to be able to differentiate from line numbers. 3221 * 3222 * Returns the number of elements found in the document or -1 in case 3223 * of error. 3224 */ 3225 long 3226 xmlXPathOrderDocElems(xmlDocPtr doc) { 3227 ptrdiff_t count = 0; 3228 xmlNodePtr cur; 3229 3230 if (doc == NULL) 3231 return(-1); 3232 cur = doc->children; 3233 while (cur != NULL) { 3234 if (cur->type == XML_ELEMENT_NODE) { 3235 cur->content = (void *) (-(++count)); 3236 if (cur->children != NULL) { 3237 cur = cur->children; 3238 continue; 3239 } 3240 } 3241 if (cur->next != NULL) { 3242 cur = cur->next; 3243 continue; 3244 } 3245 do { 3246 cur = cur->parent; 3247 if (cur == NULL) 3248 break; 3249 if (cur == (xmlNodePtr) doc) { 3250 cur = NULL; 3251 break; 3252 } 3253 if (cur->next != NULL) { 3254 cur = cur->next; 3255 break; 3256 } 3257 } while (cur != NULL); 3258 } 3259 return((long) count); 3260 } 3261 3262 /** 3263 * xmlXPathCmpNodes: 3264 * @node1: the first node 3265 * @node2: the second node 3266 * 3267 * Compare two nodes w.r.t document order 3268 * 3269 * Returns -2 in case of error 1 if first point < second point, 0 if 3270 * it's the same node, -1 otherwise 3271 */ 3272 int 3273 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) { 3274 int depth1, depth2; 3275 int attr1 = 0, attr2 = 0; 3276 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL; 3277 xmlNodePtr cur, root; 3278 3279 if ((node1 == NULL) || (node2 == NULL)) 3280 return(-2); 3281 /* 3282 * a couple of optimizations which will avoid computations in most cases 3283 */ 3284 if (node1 == node2) /* trivial case */ 3285 return(0); 3286 if (node1->type == XML_ATTRIBUTE_NODE) { 3287 attr1 = 1; 3288 attrNode1 = node1; 3289 node1 = node1->parent; 3290 } 3291 if (node2->type == XML_ATTRIBUTE_NODE) { 3292 attr2 = 1; 3293 attrNode2 = node2; 3294 node2 = node2->parent; 3295 } 3296 if (node1 == node2) { 3297 if (attr1 == attr2) { 3298 /* not required, but we keep attributes in order */ 3299 if (attr1 != 0) { 3300 cur = attrNode2->prev; 3301 while (cur != NULL) { 3302 if (cur == attrNode1) 3303 return (1); 3304 cur = cur->prev; 3305 } 3306 return (-1); 3307 } 3308 return(0); 3309 } 3310 if (attr2 == 1) 3311 return(1); 3312 return(-1); 3313 } 3314 if ((node1->type == XML_NAMESPACE_DECL) || 3315 (node2->type == XML_NAMESPACE_DECL)) 3316 return(1); 3317 if (node1 == node2->prev) 3318 return(1); 3319 if (node1 == node2->next) 3320 return(-1); 3321 3322 /* 3323 * Speedup using document order if availble. 3324 */ 3325 if ((node1->type == XML_ELEMENT_NODE) && 3326 (node2->type == XML_ELEMENT_NODE) && 3327 (0 > (ptrdiff_t) node1->content) && 3328 (0 > (ptrdiff_t) node2->content) && 3329 (node1->doc == node2->doc)) { 3330 ptrdiff_t l1, l2; 3331 3332 l1 = -((ptrdiff_t) node1->content); 3333 l2 = -((ptrdiff_t) node2->content); 3334 if (l1 < l2) 3335 return(1); 3336 if (l1 > l2) 3337 return(-1); 3338 } 3339 3340 /* 3341 * compute depth to root 3342 */ 3343 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) { 3344 if (cur->parent == node1) 3345 return(1); 3346 depth2++; 3347 } 3348 root = cur; 3349 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) { 3350 if (cur->parent == node2) 3351 return(-1); 3352 depth1++; 3353 } 3354 /* 3355 * Distinct document (or distinct entities :-( ) case. 3356 */ 3357 if (root != cur) { 3358 return(-2); 3359 } 3360 /* 3361 * get the nearest common ancestor. 3362 */ 3363 while (depth1 > depth2) { 3364 depth1--; 3365 node1 = node1->parent; 3366 } 3367 while (depth2 > depth1) { 3368 depth2--; 3369 node2 = node2->parent; 3370 } 3371 while (node1->parent != node2->parent) { 3372 node1 = node1->parent; 3373 node2 = node2->parent; 3374 /* should not happen but just in case ... */ 3375 if ((node1 == NULL) || (node2 == NULL)) 3376 return(-2); 3377 } 3378 /* 3379 * Find who's first. 3380 */ 3381 if (node1 == node2->prev) 3382 return(1); 3383 if (node1 == node2->next) 3384 return(-1); 3385 /* 3386 * Speedup using document order if availble. 3387 */ 3388 if ((node1->type == XML_ELEMENT_NODE) && 3389 (node2->type == XML_ELEMENT_NODE) && 3390 (0 > (ptrdiff_t) node1->content) && 3391 (0 > (ptrdiff_t) node2->content) && 3392 (node1->doc == node2->doc)) { 3393 ptrdiff_t l1, l2; 3394 3395 l1 = -((ptrdiff_t) node1->content); 3396 l2 = -((ptrdiff_t) node2->content); 3397 if (l1 < l2) 3398 return(1); 3399 if (l1 > l2) 3400 return(-1); 3401 } 3402 3403 for (cur = node1->next;cur != NULL;cur = cur->next) 3404 if (cur == node2) 3405 return(1); 3406 return(-1); /* assume there is no sibling list corruption */ 3407 } 3408 3409 /** 3410 * xmlXPathNodeSetSort: 3411 * @set: the node set 3412 * 3413 * Sort the node set in document order 3414 */ 3415 void 3416 xmlXPathNodeSetSort(xmlNodeSetPtr set) { 3417 #ifndef WITH_TIM_SORT 3418 int i, j, incr, len; 3419 xmlNodePtr tmp; 3420 #endif 3421 3422 if (set == NULL) 3423 return; 3424 3425 #ifndef WITH_TIM_SORT 3426 /* 3427 * Use the old Shell's sort implementation to sort the node-set 3428 * Timsort ought to be quite faster 3429 */ 3430 len = set->nodeNr; 3431 for (incr = len / 2; incr > 0; incr /= 2) { 3432 for (i = incr; i < len; i++) { 3433 j = i - incr; 3434 while (j >= 0) { 3435 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 3436 if (xmlXPathCmpNodesExt(set->nodeTab[j], 3437 set->nodeTab[j + incr]) == -1) 3438 #else 3439 if (xmlXPathCmpNodes(set->nodeTab[j], 3440 set->nodeTab[j + incr]) == -1) 3441 #endif 3442 { 3443 tmp = set->nodeTab[j]; 3444 set->nodeTab[j] = set->nodeTab[j + incr]; 3445 set->nodeTab[j + incr] = tmp; 3446 j -= incr; 3447 } else 3448 break; 3449 } 3450 } 3451 } 3452 #else /* WITH_TIM_SORT */ 3453 libxml_domnode_tim_sort(set->nodeTab, set->nodeNr); 3454 #endif /* WITH_TIM_SORT */ 3455 } 3456 3457 #define XML_NODESET_DEFAULT 10 3458 /** 3459 * xmlXPathNodeSetDupNs: 3460 * @node: the parent node of the namespace XPath node 3461 * @ns: the libxml namespace declaration node. 3462 * 3463 * Namespace node in libxml don't match the XPath semantic. In a node set 3464 * the namespace nodes are duplicated and the next pointer is set to the 3465 * parent node in the XPath semantic. 3466 * 3467 * Returns the newly created object. 3468 */ 3469 static xmlNodePtr 3470 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) { 3471 xmlNsPtr cur; 3472 3473 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) 3474 return(NULL); 3475 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) 3476 return((xmlNodePtr) ns); 3477 3478 /* 3479 * Allocate a new Namespace and fill the fields. 3480 */ 3481 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); 3482 if (cur == NULL) { 3483 xmlXPathErrMemory(NULL, "duplicating namespace\n"); 3484 return(NULL); 3485 } 3486 memset(cur, 0, sizeof(xmlNs)); 3487 cur->type = XML_NAMESPACE_DECL; 3488 if (ns->href != NULL) 3489 cur->href = xmlStrdup(ns->href); 3490 if (ns->prefix != NULL) 3491 cur->prefix = xmlStrdup(ns->prefix); 3492 cur->next = (xmlNsPtr) node; 3493 return((xmlNodePtr) cur); 3494 } 3495 3496 /** 3497 * xmlXPathNodeSetFreeNs: 3498 * @ns: the XPath namespace node found in a nodeset. 3499 * 3500 * Namespace nodes in libxml don't match the XPath semantic. In a node set 3501 * the namespace nodes are duplicated and the next pointer is set to the 3502 * parent node in the XPath semantic. Check if such a node needs to be freed 3503 */ 3504 void 3505 xmlXPathNodeSetFreeNs(xmlNsPtr ns) { 3506 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) 3507 return; 3508 3509 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) { 3510 if (ns->href != NULL) 3511 xmlFree((xmlChar *)ns->href); 3512 if (ns->prefix != NULL) 3513 xmlFree((xmlChar *)ns->prefix); 3514 xmlFree(ns); 3515 } 3516 } 3517 3518 /** 3519 * xmlXPathNodeSetCreate: 3520 * @val: an initial xmlNodePtr, or NULL 3521 * 3522 * Create a new xmlNodeSetPtr of type double and of value @val 3523 * 3524 * Returns the newly created object. 3525 */ 3526 xmlNodeSetPtr 3527 xmlXPathNodeSetCreate(xmlNodePtr val) { 3528 xmlNodeSetPtr ret; 3529 3530 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet)); 3531 if (ret == NULL) { 3532 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3533 return(NULL); 3534 } 3535 memset(ret, 0 , (size_t) sizeof(xmlNodeSet)); 3536 if (val != NULL) { 3537 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3538 sizeof(xmlNodePtr)); 3539 if (ret->nodeTab == NULL) { 3540 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3541 xmlFree(ret); 3542 return(NULL); 3543 } 3544 memset(ret->nodeTab, 0 , 3545 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3546 ret->nodeMax = XML_NODESET_DEFAULT; 3547 if (val->type == XML_NAMESPACE_DECL) { 3548 xmlNsPtr ns = (xmlNsPtr) val; 3549 3550 ret->nodeTab[ret->nodeNr++] = 3551 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3552 } else 3553 ret->nodeTab[ret->nodeNr++] = val; 3554 } 3555 return(ret); 3556 } 3557 3558 /** 3559 * xmlXPathNodeSetCreateSize: 3560 * @size: the initial size of the set 3561 * 3562 * Create a new xmlNodeSetPtr of type double and of value @val 3563 * 3564 * Returns the newly created object. 3565 */ 3566 static xmlNodeSetPtr 3567 xmlXPathNodeSetCreateSize(int size) { 3568 xmlNodeSetPtr ret; 3569 3570 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet)); 3571 if (ret == NULL) { 3572 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3573 return(NULL); 3574 } 3575 memset(ret, 0 , (size_t) sizeof(xmlNodeSet)); 3576 if (size < XML_NODESET_DEFAULT) 3577 size = XML_NODESET_DEFAULT; 3578 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr)); 3579 if (ret->nodeTab == NULL) { 3580 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3581 xmlFree(ret); 3582 return(NULL); 3583 } 3584 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr)); 3585 ret->nodeMax = size; 3586 return(ret); 3587 } 3588 3589 /** 3590 * xmlXPathNodeSetContains: 3591 * @cur: the node-set 3592 * @val: the node 3593 * 3594 * checks whether @cur contains @val 3595 * 3596 * Returns true (1) if @cur contains @val, false (0) otherwise 3597 */ 3598 int 3599 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) { 3600 int i; 3601 3602 if ((cur == NULL) || (val == NULL)) return(0); 3603 if (val->type == XML_NAMESPACE_DECL) { 3604 for (i = 0; i < cur->nodeNr; i++) { 3605 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) { 3606 xmlNsPtr ns1, ns2; 3607 3608 ns1 = (xmlNsPtr) val; 3609 ns2 = (xmlNsPtr) cur->nodeTab[i]; 3610 if (ns1 == ns2) 3611 return(1); 3612 if ((ns1->next != NULL) && (ns2->next == ns1->next) && 3613 (xmlStrEqual(ns1->prefix, ns2->prefix))) 3614 return(1); 3615 } 3616 } 3617 } else { 3618 for (i = 0; i < cur->nodeNr; i++) { 3619 if (cur->nodeTab[i] == val) 3620 return(1); 3621 } 3622 } 3623 return(0); 3624 } 3625 3626 /** 3627 * xmlXPathNodeSetAddNs: 3628 * @cur: the initial node set 3629 * @node: the hosting node 3630 * @ns: a the namespace node 3631 * 3632 * add a new namespace node to an existing NodeSet 3633 * 3634 * Returns 0 in case of success and -1 in case of error 3635 */ 3636 int 3637 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) { 3638 int i; 3639 3640 3641 if ((cur == NULL) || (ns == NULL) || (node == NULL) || 3642 (ns->type != XML_NAMESPACE_DECL) || 3643 (node->type != XML_ELEMENT_NODE)) 3644 return(-1); 3645 3646 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3647 /* 3648 * prevent duplicates 3649 */ 3650 for (i = 0;i < cur->nodeNr;i++) { 3651 if ((cur->nodeTab[i] != NULL) && 3652 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) && 3653 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) && 3654 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix))) 3655 return(0); 3656 } 3657 3658 /* 3659 * grow the nodeTab if needed 3660 */ 3661 if (cur->nodeMax == 0) { 3662 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3663 sizeof(xmlNodePtr)); 3664 if (cur->nodeTab == NULL) { 3665 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3666 return(-1); 3667 } 3668 memset(cur->nodeTab, 0 , 3669 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3670 cur->nodeMax = XML_NODESET_DEFAULT; 3671 } else if (cur->nodeNr == cur->nodeMax) { 3672 xmlNodePtr *temp; 3673 3674 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 3675 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n"); 3676 return(-1); 3677 } 3678 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 * 3679 sizeof(xmlNodePtr)); 3680 if (temp == NULL) { 3681 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3682 return(-1); 3683 } 3684 cur->nodeMax *= 2; 3685 cur->nodeTab = temp; 3686 } 3687 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns); 3688 return(0); 3689 } 3690 3691 /** 3692 * xmlXPathNodeSetAdd: 3693 * @cur: the initial node set 3694 * @val: a new xmlNodePtr 3695 * 3696 * add a new xmlNodePtr to an existing NodeSet 3697 * 3698 * Returns 0 in case of success, and -1 in case of error 3699 */ 3700 int 3701 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) { 3702 int i; 3703 3704 if ((cur == NULL) || (val == NULL)) return(-1); 3705 3706 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3707 /* 3708 * prevent duplicates 3709 */ 3710 for (i = 0;i < cur->nodeNr;i++) 3711 if (cur->nodeTab[i] == val) return(0); 3712 3713 /* 3714 * grow the nodeTab if needed 3715 */ 3716 if (cur->nodeMax == 0) { 3717 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3718 sizeof(xmlNodePtr)); 3719 if (cur->nodeTab == NULL) { 3720 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3721 return(-1); 3722 } 3723 memset(cur->nodeTab, 0 , 3724 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3725 cur->nodeMax = XML_NODESET_DEFAULT; 3726 } else if (cur->nodeNr == cur->nodeMax) { 3727 xmlNodePtr *temp; 3728 3729 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 3730 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n"); 3731 return(-1); 3732 } 3733 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 * 3734 sizeof(xmlNodePtr)); 3735 if (temp == NULL) { 3736 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3737 return(-1); 3738 } 3739 cur->nodeMax *= 2; 3740 cur->nodeTab = temp; 3741 } 3742 if (val->type == XML_NAMESPACE_DECL) { 3743 xmlNsPtr ns = (xmlNsPtr) val; 3744 3745 cur->nodeTab[cur->nodeNr++] = 3746 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3747 } else 3748 cur->nodeTab[cur->nodeNr++] = val; 3749 return(0); 3750 } 3751 3752 /** 3753 * xmlXPathNodeSetAddUnique: 3754 * @cur: the initial node set 3755 * @val: a new xmlNodePtr 3756 * 3757 * add a new xmlNodePtr to an existing NodeSet, optimized version 3758 * when we are sure the node is not already in the set. 3759 * 3760 * Returns 0 in case of success and -1 in case of failure 3761 */ 3762 int 3763 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) { 3764 if ((cur == NULL) || (val == NULL)) return(-1); 3765 3766 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3767 /* 3768 * grow the nodeTab if needed 3769 */ 3770 if (cur->nodeMax == 0) { 3771 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3772 sizeof(xmlNodePtr)); 3773 if (cur->nodeTab == NULL) { 3774 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3775 return(-1); 3776 } 3777 memset(cur->nodeTab, 0 , 3778 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3779 cur->nodeMax = XML_NODESET_DEFAULT; 3780 } else if (cur->nodeNr == cur->nodeMax) { 3781 xmlNodePtr *temp; 3782 3783 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 3784 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n"); 3785 return(-1); 3786 } 3787 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 * 3788 sizeof(xmlNodePtr)); 3789 if (temp == NULL) { 3790 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3791 return(-1); 3792 } 3793 cur->nodeTab = temp; 3794 cur->nodeMax *= 2; 3795 } 3796 if (val->type == XML_NAMESPACE_DECL) { 3797 xmlNsPtr ns = (xmlNsPtr) val; 3798 3799 cur->nodeTab[cur->nodeNr++] = 3800 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3801 } else 3802 cur->nodeTab[cur->nodeNr++] = val; 3803 return(0); 3804 } 3805 3806 /** 3807 * xmlXPathNodeSetMerge: 3808 * @val1: the first NodeSet or NULL 3809 * @val2: the second NodeSet 3810 * 3811 * Merges two nodesets, all nodes from @val2 are added to @val1 3812 * if @val1 is NULL, a new set is created and copied from @val2 3813 * 3814 * Returns @val1 once extended or NULL in case of error. 3815 */ 3816 xmlNodeSetPtr 3817 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) { 3818 int i, j, initNr, skip; 3819 xmlNodePtr n1, n2; 3820 3821 if (val2 == NULL) return(val1); 3822 if (val1 == NULL) { 3823 val1 = xmlXPathNodeSetCreate(NULL); 3824 if (val1 == NULL) 3825 return (NULL); 3826 #if 0 3827 /* 3828 * TODO: The optimization won't work in every case, since 3829 * those nasty namespace nodes need to be added with 3830 * xmlXPathNodeSetDupNs() to the set; thus a pure 3831 * memcpy is not possible. 3832 * If there was a flag on the nodesetval, indicating that 3833 * some temporary nodes are in, that would be helpfull. 3834 */ 3835 /* 3836 * Optimization: Create an equally sized node-set 3837 * and memcpy the content. 3838 */ 3839 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr); 3840 if (val1 == NULL) 3841 return(NULL); 3842 if (val2->nodeNr != 0) { 3843 if (val2->nodeNr == 1) 3844 *(val1->nodeTab) = *(val2->nodeTab); 3845 else { 3846 memcpy(val1->nodeTab, val2->nodeTab, 3847 val2->nodeNr * sizeof(xmlNodePtr)); 3848 } 3849 val1->nodeNr = val2->nodeNr; 3850 } 3851 return(val1); 3852 #endif 3853 } 3854 3855 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3856 initNr = val1->nodeNr; 3857 3858 for (i = 0;i < val2->nodeNr;i++) { 3859 n2 = val2->nodeTab[i]; 3860 /* 3861 * check against duplicates 3862 */ 3863 skip = 0; 3864 for (j = 0; j < initNr; j++) { 3865 n1 = val1->nodeTab[j]; 3866 if (n1 == n2) { 3867 skip = 1; 3868 break; 3869 } else if ((n1->type == XML_NAMESPACE_DECL) && 3870 (n2->type == XML_NAMESPACE_DECL)) { 3871 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) && 3872 (xmlStrEqual(((xmlNsPtr) n1)->prefix, 3873 ((xmlNsPtr) n2)->prefix))) 3874 { 3875 skip = 1; 3876 break; 3877 } 3878 } 3879 } 3880 if (skip) 3881 continue; 3882 3883 /* 3884 * grow the nodeTab if needed 3885 */ 3886 if (val1->nodeMax == 0) { 3887 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3888 sizeof(xmlNodePtr)); 3889 if (val1->nodeTab == NULL) { 3890 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3891 return(NULL); 3892 } 3893 memset(val1->nodeTab, 0 , 3894 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3895 val1->nodeMax = XML_NODESET_DEFAULT; 3896 } else if (val1->nodeNr == val1->nodeMax) { 3897 xmlNodePtr *temp; 3898 3899 if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 3900 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n"); 3901 return(NULL); 3902 } 3903 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 * 3904 sizeof(xmlNodePtr)); 3905 if (temp == NULL) { 3906 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3907 return(NULL); 3908 } 3909 val1->nodeTab = temp; 3910 val1->nodeMax *= 2; 3911 } 3912 if (n2->type == XML_NAMESPACE_DECL) { 3913 xmlNsPtr ns = (xmlNsPtr) n2; 3914 3915 val1->nodeTab[val1->nodeNr++] = 3916 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3917 } else 3918 val1->nodeTab[val1->nodeNr++] = n2; 3919 } 3920 3921 return(val1); 3922 } 3923 3924 3925 /** 3926 * xmlXPathNodeSetMergeAndClear: 3927 * @set1: the first NodeSet or NULL 3928 * @set2: the second NodeSet 3929 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes 3930 * 3931 * Merges two nodesets, all nodes from @set2 are added to @set1 3932 * if @set1 is NULL, a new set is created and copied from @set2. 3933 * Checks for duplicate nodes. Clears set2. 3934 * 3935 * Returns @set1 once extended or NULL in case of error. 3936 */ 3937 static xmlNodeSetPtr 3938 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2, 3939 int hasNullEntries) 3940 { 3941 if ((set1 == NULL) && (hasNullEntries == 0)) { 3942 /* 3943 * Note that doing a memcpy of the list, namespace nodes are 3944 * just assigned to set1, since set2 is cleared anyway. 3945 */ 3946 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr); 3947 if (set1 == NULL) 3948 return(NULL); 3949 if (set2->nodeNr != 0) { 3950 memcpy(set1->nodeTab, set2->nodeTab, 3951 set2->nodeNr * sizeof(xmlNodePtr)); 3952 set1->nodeNr = set2->nodeNr; 3953 } 3954 } else { 3955 int i, j, initNbSet1; 3956 xmlNodePtr n1, n2; 3957 3958 if (set1 == NULL) 3959 set1 = xmlXPathNodeSetCreate(NULL); 3960 if (set1 == NULL) 3961 return (NULL); 3962 3963 initNbSet1 = set1->nodeNr; 3964 for (i = 0;i < set2->nodeNr;i++) { 3965 n2 = set2->nodeTab[i]; 3966 /* 3967 * Skip NULLed entries. 3968 */ 3969 if (n2 == NULL) 3970 continue; 3971 /* 3972 * Skip duplicates. 3973 */ 3974 for (j = 0; j < initNbSet1; j++) { 3975 n1 = set1->nodeTab[j]; 3976 if (n1 == n2) { 3977 goto skip_node; 3978 } else if ((n1->type == XML_NAMESPACE_DECL) && 3979 (n2->type == XML_NAMESPACE_DECL)) 3980 { 3981 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) && 3982 (xmlStrEqual(((xmlNsPtr) n1)->prefix, 3983 ((xmlNsPtr) n2)->prefix))) 3984 { 3985 /* 3986 * Free the namespace node. 3987 */ 3988 set2->nodeTab[i] = NULL; 3989 xmlXPathNodeSetFreeNs((xmlNsPtr) n2); 3990 goto skip_node; 3991 } 3992 } 3993 } 3994 /* 3995 * grow the nodeTab if needed 3996 */ 3997 if (set1->nodeMax == 0) { 3998 set1->nodeTab = (xmlNodePtr *) xmlMalloc( 3999 XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); 4000 if (set1->nodeTab == NULL) { 4001 xmlXPathErrMemory(NULL, "merging nodeset\n"); 4002 return(NULL); 4003 } 4004 memset(set1->nodeTab, 0, 4005 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 4006 set1->nodeMax = XML_NODESET_DEFAULT; 4007 } else if (set1->nodeNr >= set1->nodeMax) { 4008 xmlNodePtr *temp; 4009 4010 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 4011 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n"); 4012 return(NULL); 4013 } 4014 temp = (xmlNodePtr *) xmlRealloc( 4015 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr)); 4016 if (temp == NULL) { 4017 xmlXPathErrMemory(NULL, "merging nodeset\n"); 4018 return(NULL); 4019 } 4020 set1->nodeTab = temp; 4021 set1->nodeMax *= 2; 4022 } 4023 set1->nodeTab[set1->nodeNr++] = n2; 4024 skip_node: 4025 {} 4026 } 4027 } 4028 set2->nodeNr = 0; 4029 return(set1); 4030 } 4031 4032 /** 4033 * xmlXPathNodeSetMergeAndClearNoDupls: 4034 * @set1: the first NodeSet or NULL 4035 * @set2: the second NodeSet 4036 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes 4037 * 4038 * Merges two nodesets, all nodes from @set2 are added to @set1 4039 * if @set1 is NULL, a new set is created and copied from @set2. 4040 * Doesn't chack for duplicate nodes. Clears set2. 4041 * 4042 * Returns @set1 once extended or NULL in case of error. 4043 */ 4044 static xmlNodeSetPtr 4045 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2, 4046 int hasNullEntries) 4047 { 4048 if (set2 == NULL) 4049 return(set1); 4050 if ((set1 == NULL) && (hasNullEntries == 0)) { 4051 /* 4052 * Note that doing a memcpy of the list, namespace nodes are 4053 * just assigned to set1, since set2 is cleared anyway. 4054 */ 4055 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr); 4056 if (set1 == NULL) 4057 return(NULL); 4058 if (set2->nodeNr != 0) { 4059 memcpy(set1->nodeTab, set2->nodeTab, 4060 set2->nodeNr * sizeof(xmlNodePtr)); 4061 set1->nodeNr = set2->nodeNr; 4062 } 4063 } else { 4064 int i; 4065 xmlNodePtr n2; 4066 4067 if (set1 == NULL) 4068 set1 = xmlXPathNodeSetCreate(NULL); 4069 if (set1 == NULL) 4070 return (NULL); 4071 4072 for (i = 0;i < set2->nodeNr;i++) { 4073 n2 = set2->nodeTab[i]; 4074 /* 4075 * Skip NULLed entries. 4076 */ 4077 if (n2 == NULL) 4078 continue; 4079 if (set1->nodeMax == 0) { 4080 set1->nodeTab = (xmlNodePtr *) xmlMalloc( 4081 XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); 4082 if (set1->nodeTab == NULL) { 4083 xmlXPathErrMemory(NULL, "merging nodeset\n"); 4084 return(NULL); 4085 } 4086 memset(set1->nodeTab, 0, 4087 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 4088 set1->nodeMax = XML_NODESET_DEFAULT; 4089 } else if (set1->nodeNr >= set1->nodeMax) { 4090 xmlNodePtr *temp; 4091 4092 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) { 4093 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n"); 4094 return(NULL); 4095 } 4096 temp = (xmlNodePtr *) xmlRealloc( 4097 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr)); 4098 if (temp == NULL) { 4099 xmlXPathErrMemory(NULL, "merging nodeset\n"); 4100 return(NULL); 4101 } 4102 set1->nodeTab = temp; 4103 set1->nodeMax *= 2; 4104 } 4105 set1->nodeTab[set1->nodeNr++] = n2; 4106 } 4107 } 4108 set2->nodeNr = 0; 4109 return(set1); 4110 } 4111 4112 /** 4113 * xmlXPathNodeSetDel: 4114 * @cur: the initial node set 4115 * @val: an xmlNodePtr 4116 * 4117 * Removes an xmlNodePtr from an existing NodeSet 4118 */ 4119 void 4120 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) { 4121 int i; 4122 4123 if (cur == NULL) return; 4124 if (val == NULL) return; 4125 4126 /* 4127 * find node in nodeTab 4128 */ 4129 for (i = 0;i < cur->nodeNr;i++) 4130 if (cur->nodeTab[i] == val) break; 4131 4132 if (i >= cur->nodeNr) { /* not found */ 4133 #ifdef DEBUG 4134 xmlGenericError(xmlGenericErrorContext, 4135 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n", 4136 val->name); 4137 #endif 4138 return; 4139 } 4140 if ((cur->nodeTab[i] != NULL) && 4141 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL)) 4142 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]); 4143 cur->nodeNr--; 4144 for (;i < cur->nodeNr;i++) 4145 cur->nodeTab[i] = cur->nodeTab[i + 1]; 4146 cur->nodeTab[cur->nodeNr] = NULL; 4147 } 4148 4149 /** 4150 * xmlXPathNodeSetRemove: 4151 * @cur: the initial node set 4152 * @val: the index to remove 4153 * 4154 * Removes an entry from an existing NodeSet list. 4155 */ 4156 void 4157 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) { 4158 if (cur == NULL) return; 4159 if (val >= cur->nodeNr) return; 4160 if ((cur->nodeTab[val] != NULL) && 4161 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL)) 4162 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]); 4163 cur->nodeNr--; 4164 for (;val < cur->nodeNr;val++) 4165 cur->nodeTab[val] = cur->nodeTab[val + 1]; 4166 cur->nodeTab[cur->nodeNr] = NULL; 4167 } 4168 4169 /** 4170 * xmlXPathFreeNodeSet: 4171 * @obj: the xmlNodeSetPtr to free 4172 * 4173 * Free the NodeSet compound (not the actual nodes !). 4174 */ 4175 void 4176 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) { 4177 if (obj == NULL) return; 4178 if (obj->nodeTab != NULL) { 4179 int i; 4180 4181 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 4182 for (i = 0;i < obj->nodeNr;i++) 4183 if ((obj->nodeTab[i] != NULL) && 4184 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL)) 4185 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]); 4186 xmlFree(obj->nodeTab); 4187 } 4188 xmlFree(obj); 4189 } 4190 4191 /** 4192 * xmlXPathNodeSetClearFromPos: 4193 * @set: the node set to be cleared 4194 * @pos: the start position to clear from 4195 * 4196 * Clears the list from temporary XPath objects (e.g. namespace nodes 4197 * are feed) starting with the entry at @pos, but does *not* free the list 4198 * itself. Sets the length of the list to @pos. 4199 */ 4200 static void 4201 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes) 4202 { 4203 if ((set == NULL) || (pos >= set->nodeNr)) 4204 return; 4205 else if ((hasNsNodes)) { 4206 int i; 4207 xmlNodePtr node; 4208 4209 for (i = pos; i < set->nodeNr; i++) { 4210 node = set->nodeTab[i]; 4211 if ((node != NULL) && 4212 (node->type == XML_NAMESPACE_DECL)) 4213 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 4214 } 4215 } 4216 set->nodeNr = pos; 4217 } 4218 4219 /** 4220 * xmlXPathNodeSetClear: 4221 * @set: the node set to clear 4222 * 4223 * Clears the list from all temporary XPath objects (e.g. namespace nodes 4224 * are feed), but does *not* free the list itself. Sets the length of the 4225 * list to 0. 4226 */ 4227 static void 4228 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes) 4229 { 4230 xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes); 4231 } 4232 4233 /** 4234 * xmlXPathNodeSetKeepLast: 4235 * @set: the node set to be cleared 4236 * 4237 * Move the last node to the first position and clear temporary XPath objects 4238 * (e.g. namespace nodes) from all other nodes. Sets the length of the list 4239 * to 1. 4240 */ 4241 static void 4242 xmlXPathNodeSetKeepLast(xmlNodeSetPtr set) 4243 { 4244 int i; 4245 xmlNodePtr node; 4246 4247 if ((set == NULL) || (set->nodeNr <= 1)) 4248 return; 4249 for (i = 0; i < set->nodeNr - 1; i++) { 4250 node = set->nodeTab[i]; 4251 if ((node != NULL) && 4252 (node->type == XML_NAMESPACE_DECL)) 4253 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 4254 } 4255 set->nodeTab[0] = set->nodeTab[set->nodeNr-1]; 4256 set->nodeNr = 1; 4257 } 4258 4259 /** 4260 * xmlXPathFreeValueTree: 4261 * @obj: the xmlNodeSetPtr to free 4262 * 4263 * Free the NodeSet compound and the actual tree, this is different 4264 * from xmlXPathFreeNodeSet() 4265 */ 4266 static void 4267 xmlXPathFreeValueTree(xmlNodeSetPtr obj) { 4268 int i; 4269 4270 if (obj == NULL) return; 4271 4272 if (obj->nodeTab != NULL) { 4273 for (i = 0;i < obj->nodeNr;i++) { 4274 if (obj->nodeTab[i] != NULL) { 4275 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) { 4276 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]); 4277 } else { 4278 xmlFreeNodeList(obj->nodeTab[i]); 4279 } 4280 } 4281 } 4282 xmlFree(obj->nodeTab); 4283 } 4284 xmlFree(obj); 4285 } 4286 4287 #if defined(DEBUG) || defined(DEBUG_STEP) 4288 /** 4289 * xmlGenericErrorContextNodeSet: 4290 * @output: a FILE * for the output 4291 * @obj: the xmlNodeSetPtr to display 4292 * 4293 * Quick display of a NodeSet 4294 */ 4295 void 4296 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) { 4297 int i; 4298 4299 if (output == NULL) output = xmlGenericErrorContext; 4300 if (obj == NULL) { 4301 fprintf(output, "NodeSet == NULL !\n"); 4302 return; 4303 } 4304 if (obj->nodeNr == 0) { 4305 fprintf(output, "NodeSet is empty\n"); 4306 return; 4307 } 4308 if (obj->nodeTab == NULL) { 4309 fprintf(output, " nodeTab == NULL !\n"); 4310 return; 4311 } 4312 for (i = 0; i < obj->nodeNr; i++) { 4313 if (obj->nodeTab[i] == NULL) { 4314 fprintf(output, " NULL !\n"); 4315 return; 4316 } 4317 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) || 4318 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE)) 4319 fprintf(output, " /"); 4320 else if (obj->nodeTab[i]->name == NULL) 4321 fprintf(output, " noname!"); 4322 else fprintf(output, " %s", obj->nodeTab[i]->name); 4323 } 4324 fprintf(output, "\n"); 4325 } 4326 #endif 4327 4328 /** 4329 * xmlXPathNewNodeSet: 4330 * @val: the NodePtr value 4331 * 4332 * Create a new xmlXPathObjectPtr of type NodeSet and initialize 4333 * it with the single Node @val 4334 * 4335 * Returns the newly created object. 4336 */ 4337 xmlXPathObjectPtr 4338 xmlXPathNewNodeSet(xmlNodePtr val) { 4339 xmlXPathObjectPtr ret; 4340 4341 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4342 if (ret == NULL) { 4343 xmlXPathErrMemory(NULL, "creating nodeset\n"); 4344 return(NULL); 4345 } 4346 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4347 ret->type = XPATH_NODESET; 4348 ret->boolval = 0; 4349 ret->nodesetval = xmlXPathNodeSetCreate(val); 4350 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 4351 #ifdef XP_DEBUG_OBJ_USAGE 4352 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET); 4353 #endif 4354 return(ret); 4355 } 4356 4357 /** 4358 * xmlXPathNewValueTree: 4359 * @val: the NodePtr value 4360 * 4361 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize 4362 * it with the tree root @val 4363 * 4364 * Returns the newly created object. 4365 */ 4366 xmlXPathObjectPtr 4367 xmlXPathNewValueTree(xmlNodePtr val) { 4368 xmlXPathObjectPtr ret; 4369 4370 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4371 if (ret == NULL) { 4372 xmlXPathErrMemory(NULL, "creating result value tree\n"); 4373 return(NULL); 4374 } 4375 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4376 ret->type = XPATH_XSLT_TREE; 4377 ret->boolval = 1; 4378 ret->user = (void *) val; 4379 ret->nodesetval = xmlXPathNodeSetCreate(val); 4380 #ifdef XP_DEBUG_OBJ_USAGE 4381 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE); 4382 #endif 4383 return(ret); 4384 } 4385 4386 /** 4387 * xmlXPathNewNodeSetList: 4388 * @val: an existing NodeSet 4389 * 4390 * Create a new xmlXPathObjectPtr of type NodeSet and initialize 4391 * it with the Nodeset @val 4392 * 4393 * Returns the newly created object. 4394 */ 4395 xmlXPathObjectPtr 4396 xmlXPathNewNodeSetList(xmlNodeSetPtr val) 4397 { 4398 xmlXPathObjectPtr ret; 4399 int i; 4400 4401 if (val == NULL) 4402 ret = NULL; 4403 else if (val->nodeTab == NULL) 4404 ret = xmlXPathNewNodeSet(NULL); 4405 else { 4406 ret = xmlXPathNewNodeSet(val->nodeTab[0]); 4407 if (ret) { 4408 for (i = 1; i < val->nodeNr; ++i) { 4409 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]) 4410 < 0) break; 4411 } 4412 } 4413 } 4414 4415 return (ret); 4416 } 4417 4418 /** 4419 * xmlXPathWrapNodeSet: 4420 * @val: the NodePtr value 4421 * 4422 * Wrap the Nodeset @val in a new xmlXPathObjectPtr 4423 * 4424 * Returns the newly created object. 4425 */ 4426 xmlXPathObjectPtr 4427 xmlXPathWrapNodeSet(xmlNodeSetPtr val) { 4428 xmlXPathObjectPtr ret; 4429 4430 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4431 if (ret == NULL) { 4432 xmlXPathErrMemory(NULL, "creating node set object\n"); 4433 return(NULL); 4434 } 4435 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4436 ret->type = XPATH_NODESET; 4437 ret->nodesetval = val; 4438 #ifdef XP_DEBUG_OBJ_USAGE 4439 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET); 4440 #endif 4441 return(ret); 4442 } 4443 4444 /** 4445 * xmlXPathFreeNodeSetList: 4446 * @obj: an existing NodeSetList object 4447 * 4448 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in 4449 * the list contrary to xmlXPathFreeObject(). 4450 */ 4451 void 4452 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) { 4453 if (obj == NULL) return; 4454 #ifdef XP_DEBUG_OBJ_USAGE 4455 xmlXPathDebugObjUsageReleased(NULL, obj->type); 4456 #endif 4457 xmlFree(obj); 4458 } 4459 4460 /** 4461 * xmlXPathDifference: 4462 * @nodes1: a node-set 4463 * @nodes2: a node-set 4464 * 4465 * Implements the EXSLT - Sets difference() function: 4466 * node-set set:difference (node-set, node-set) 4467 * 4468 * Returns the difference between the two node sets, or nodes1 if 4469 * nodes2 is empty 4470 */ 4471 xmlNodeSetPtr 4472 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4473 xmlNodeSetPtr ret; 4474 int i, l1; 4475 xmlNodePtr cur; 4476 4477 if (xmlXPathNodeSetIsEmpty(nodes2)) 4478 return(nodes1); 4479 4480 ret = xmlXPathNodeSetCreate(NULL); 4481 if (xmlXPathNodeSetIsEmpty(nodes1)) 4482 return(ret); 4483 4484 l1 = xmlXPathNodeSetGetLength(nodes1); 4485 4486 for (i = 0; i < l1; i++) { 4487 cur = xmlXPathNodeSetItem(nodes1, i); 4488 if (!xmlXPathNodeSetContains(nodes2, cur)) { 4489 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) 4490 break; 4491 } 4492 } 4493 return(ret); 4494 } 4495 4496 /** 4497 * xmlXPathIntersection: 4498 * @nodes1: a node-set 4499 * @nodes2: a node-set 4500 * 4501 * Implements the EXSLT - Sets intersection() function: 4502 * node-set set:intersection (node-set, node-set) 4503 * 4504 * Returns a node set comprising the nodes that are within both the 4505 * node sets passed as arguments 4506 */ 4507 xmlNodeSetPtr 4508 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4509 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL); 4510 int i, l1; 4511 xmlNodePtr cur; 4512 4513 if (ret == NULL) 4514 return(ret); 4515 if (xmlXPathNodeSetIsEmpty(nodes1)) 4516 return(ret); 4517 if (xmlXPathNodeSetIsEmpty(nodes2)) 4518 return(ret); 4519 4520 l1 = xmlXPathNodeSetGetLength(nodes1); 4521 4522 for (i = 0; i < l1; i++) { 4523 cur = xmlXPathNodeSetItem(nodes1, i); 4524 if (xmlXPathNodeSetContains(nodes2, cur)) { 4525 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) 4526 break; 4527 } 4528 } 4529 return(ret); 4530 } 4531 4532 /** 4533 * xmlXPathDistinctSorted: 4534 * @nodes: a node-set, sorted by document order 4535 * 4536 * Implements the EXSLT - Sets distinct() function: 4537 * node-set set:distinct (node-set) 4538 * 4539 * Returns a subset of the nodes contained in @nodes, or @nodes if 4540 * it is empty 4541 */ 4542 xmlNodeSetPtr 4543 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) { 4544 xmlNodeSetPtr ret; 4545 xmlHashTablePtr hash; 4546 int i, l; 4547 xmlChar * strval; 4548 xmlNodePtr cur; 4549 4550 if (xmlXPathNodeSetIsEmpty(nodes)) 4551 return(nodes); 4552 4553 ret = xmlXPathNodeSetCreate(NULL); 4554 if (ret == NULL) 4555 return(ret); 4556 l = xmlXPathNodeSetGetLength(nodes); 4557 hash = xmlHashCreate (l); 4558 for (i = 0; i < l; i++) { 4559 cur = xmlXPathNodeSetItem(nodes, i); 4560 strval = xmlXPathCastNodeToString(cur); 4561 if (xmlHashLookup(hash, strval) == NULL) { 4562 xmlHashAddEntry(hash, strval, strval); 4563 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) 4564 break; 4565 } else { 4566 xmlFree(strval); 4567 } 4568 } 4569 xmlHashFree(hash, xmlHashDefaultDeallocator); 4570 return(ret); 4571 } 4572 4573 /** 4574 * xmlXPathDistinct: 4575 * @nodes: a node-set 4576 * 4577 * Implements the EXSLT - Sets distinct() function: 4578 * node-set set:distinct (node-set) 4579 * @nodes is sorted by document order, then #exslSetsDistinctSorted 4580 * is called with the sorted node-set 4581 * 4582 * Returns a subset of the nodes contained in @nodes, or @nodes if 4583 * it is empty 4584 */ 4585 xmlNodeSetPtr 4586 xmlXPathDistinct (xmlNodeSetPtr nodes) { 4587 if (xmlXPathNodeSetIsEmpty(nodes)) 4588 return(nodes); 4589 4590 xmlXPathNodeSetSort(nodes); 4591 return(xmlXPathDistinctSorted(nodes)); 4592 } 4593 4594 /** 4595 * xmlXPathHasSameNodes: 4596 * @nodes1: a node-set 4597 * @nodes2: a node-set 4598 * 4599 * Implements the EXSLT - Sets has-same-nodes function: 4600 * boolean set:has-same-node(node-set, node-set) 4601 * 4602 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0) 4603 * otherwise 4604 */ 4605 int 4606 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4607 int i, l; 4608 xmlNodePtr cur; 4609 4610 if (xmlXPathNodeSetIsEmpty(nodes1) || 4611 xmlXPathNodeSetIsEmpty(nodes2)) 4612 return(0); 4613 4614 l = xmlXPathNodeSetGetLength(nodes1); 4615 for (i = 0; i < l; i++) { 4616 cur = xmlXPathNodeSetItem(nodes1, i); 4617 if (xmlXPathNodeSetContains(nodes2, cur)) 4618 return(1); 4619 } 4620 return(0); 4621 } 4622 4623 /** 4624 * xmlXPathNodeLeadingSorted: 4625 * @nodes: a node-set, sorted by document order 4626 * @node: a node 4627 * 4628 * Implements the EXSLT - Sets leading() function: 4629 * node-set set:leading (node-set, node-set) 4630 * 4631 * Returns the nodes in @nodes that precede @node in document order, 4632 * @nodes if @node is NULL or an empty node-set if @nodes 4633 * doesn't contain @node 4634 */ 4635 xmlNodeSetPtr 4636 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { 4637 int i, l; 4638 xmlNodePtr cur; 4639 xmlNodeSetPtr ret; 4640 4641 if (node == NULL) 4642 return(nodes); 4643 4644 ret = xmlXPathNodeSetCreate(NULL); 4645 if (ret == NULL) 4646 return(ret); 4647 if (xmlXPathNodeSetIsEmpty(nodes) || 4648 (!xmlXPathNodeSetContains(nodes, node))) 4649 return(ret); 4650 4651 l = xmlXPathNodeSetGetLength(nodes); 4652 for (i = 0; i < l; i++) { 4653 cur = xmlXPathNodeSetItem(nodes, i); 4654 if (cur == node) 4655 break; 4656 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) 4657 break; 4658 } 4659 return(ret); 4660 } 4661 4662 /** 4663 * xmlXPathNodeLeading: 4664 * @nodes: a node-set 4665 * @node: a node 4666 * 4667 * Implements the EXSLT - Sets leading() function: 4668 * node-set set:leading (node-set, node-set) 4669 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted 4670 * is called. 4671 * 4672 * Returns the nodes in @nodes that precede @node in document order, 4673 * @nodes if @node is NULL or an empty node-set if @nodes 4674 * doesn't contain @node 4675 */ 4676 xmlNodeSetPtr 4677 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) { 4678 xmlXPathNodeSetSort(nodes); 4679 return(xmlXPathNodeLeadingSorted(nodes, node)); 4680 } 4681 4682 /** 4683 * xmlXPathLeadingSorted: 4684 * @nodes1: a node-set, sorted by document order 4685 * @nodes2: a node-set, sorted by document order 4686 * 4687 * Implements the EXSLT - Sets leading() function: 4688 * node-set set:leading (node-set, node-set) 4689 * 4690 * Returns the nodes in @nodes1 that precede the first node in @nodes2 4691 * in document order, @nodes1 if @nodes2 is NULL or empty or 4692 * an empty node-set if @nodes1 doesn't contain @nodes2 4693 */ 4694 xmlNodeSetPtr 4695 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4696 if (xmlXPathNodeSetIsEmpty(nodes2)) 4697 return(nodes1); 4698 return(xmlXPathNodeLeadingSorted(nodes1, 4699 xmlXPathNodeSetItem(nodes2, 1))); 4700 } 4701 4702 /** 4703 * xmlXPathLeading: 4704 * @nodes1: a node-set 4705 * @nodes2: a node-set 4706 * 4707 * Implements the EXSLT - Sets leading() function: 4708 * node-set set:leading (node-set, node-set) 4709 * @nodes1 and @nodes2 are sorted by document order, then 4710 * #exslSetsLeadingSorted is called. 4711 * 4712 * Returns the nodes in @nodes1 that precede the first node in @nodes2 4713 * in document order, @nodes1 if @nodes2 is NULL or empty or 4714 * an empty node-set if @nodes1 doesn't contain @nodes2 4715 */ 4716 xmlNodeSetPtr 4717 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4718 if (xmlXPathNodeSetIsEmpty(nodes2)) 4719 return(nodes1); 4720 if (xmlXPathNodeSetIsEmpty(nodes1)) 4721 return(xmlXPathNodeSetCreate(NULL)); 4722 xmlXPathNodeSetSort(nodes1); 4723 xmlXPathNodeSetSort(nodes2); 4724 return(xmlXPathNodeLeadingSorted(nodes1, 4725 xmlXPathNodeSetItem(nodes2, 1))); 4726 } 4727 4728 /** 4729 * xmlXPathNodeTrailingSorted: 4730 * @nodes: a node-set, sorted by document order 4731 * @node: a node 4732 * 4733 * Implements the EXSLT - Sets trailing() function: 4734 * node-set set:trailing (node-set, node-set) 4735 * 4736 * Returns the nodes in @nodes that follow @node in document order, 4737 * @nodes if @node is NULL or an empty node-set if @nodes 4738 * doesn't contain @node 4739 */ 4740 xmlNodeSetPtr 4741 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { 4742 int i, l; 4743 xmlNodePtr cur; 4744 xmlNodeSetPtr ret; 4745 4746 if (node == NULL) 4747 return(nodes); 4748 4749 ret = xmlXPathNodeSetCreate(NULL); 4750 if (ret == NULL) 4751 return(ret); 4752 if (xmlXPathNodeSetIsEmpty(nodes) || 4753 (!xmlXPathNodeSetContains(nodes, node))) 4754 return(ret); 4755 4756 l = xmlXPathNodeSetGetLength(nodes); 4757 for (i = l - 1; i >= 0; i--) { 4758 cur = xmlXPathNodeSetItem(nodes, i); 4759 if (cur == node) 4760 break; 4761 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) 4762 break; 4763 } 4764 xmlXPathNodeSetSort(ret); /* bug 413451 */ 4765 return(ret); 4766 } 4767 4768 /** 4769 * xmlXPathNodeTrailing: 4770 * @nodes: a node-set 4771 * @node: a node 4772 * 4773 * Implements the EXSLT - Sets trailing() function: 4774 * node-set set:trailing (node-set, node-set) 4775 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted 4776 * is called. 4777 * 4778 * Returns the nodes in @nodes that follow @node in document order, 4779 * @nodes if @node is NULL or an empty node-set if @nodes 4780 * doesn't contain @node 4781 */ 4782 xmlNodeSetPtr 4783 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) { 4784 xmlXPathNodeSetSort(nodes); 4785 return(xmlXPathNodeTrailingSorted(nodes, node)); 4786 } 4787 4788 /** 4789 * xmlXPathTrailingSorted: 4790 * @nodes1: a node-set, sorted by document order 4791 * @nodes2: a node-set, sorted by document order 4792 * 4793 * Implements the EXSLT - Sets trailing() function: 4794 * node-set set:trailing (node-set, node-set) 4795 * 4796 * Returns the nodes in @nodes1 that follow the first node in @nodes2 4797 * in document order, @nodes1 if @nodes2 is NULL or empty or 4798 * an empty node-set if @nodes1 doesn't contain @nodes2 4799 */ 4800 xmlNodeSetPtr 4801 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4802 if (xmlXPathNodeSetIsEmpty(nodes2)) 4803 return(nodes1); 4804 return(xmlXPathNodeTrailingSorted(nodes1, 4805 xmlXPathNodeSetItem(nodes2, 0))); 4806 } 4807 4808 /** 4809 * xmlXPathTrailing: 4810 * @nodes1: a node-set 4811 * @nodes2: a node-set 4812 * 4813 * Implements the EXSLT - Sets trailing() function: 4814 * node-set set:trailing (node-set, node-set) 4815 * @nodes1 and @nodes2 are sorted by document order, then 4816 * #xmlXPathTrailingSorted is called. 4817 * 4818 * Returns the nodes in @nodes1 that follow the first node in @nodes2 4819 * in document order, @nodes1 if @nodes2 is NULL or empty or 4820 * an empty node-set if @nodes1 doesn't contain @nodes2 4821 */ 4822 xmlNodeSetPtr 4823 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4824 if (xmlXPathNodeSetIsEmpty(nodes2)) 4825 return(nodes1); 4826 if (xmlXPathNodeSetIsEmpty(nodes1)) 4827 return(xmlXPathNodeSetCreate(NULL)); 4828 xmlXPathNodeSetSort(nodes1); 4829 xmlXPathNodeSetSort(nodes2); 4830 return(xmlXPathNodeTrailingSorted(nodes1, 4831 xmlXPathNodeSetItem(nodes2, 0))); 4832 } 4833 4834 /************************************************************************ 4835 * * 4836 * Routines to handle extra functions * 4837 * * 4838 ************************************************************************/ 4839 4840 /** 4841 * xmlXPathRegisterFunc: 4842 * @ctxt: the XPath context 4843 * @name: the function name 4844 * @f: the function implementation or NULL 4845 * 4846 * Register a new function. If @f is NULL it unregisters the function 4847 * 4848 * Returns 0 in case of success, -1 in case of error 4849 */ 4850 int 4851 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name, 4852 xmlXPathFunction f) { 4853 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f)); 4854 } 4855 4856 /** 4857 * xmlXPathRegisterFuncNS: 4858 * @ctxt: the XPath context 4859 * @name: the function name 4860 * @ns_uri: the function namespace URI 4861 * @f: the function implementation or NULL 4862 * 4863 * Register a new function. If @f is NULL it unregisters the function 4864 * 4865 * Returns 0 in case of success, -1 in case of error 4866 */ 4867 int 4868 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name, 4869 const xmlChar *ns_uri, xmlXPathFunction f) { 4870 if (ctxt == NULL) 4871 return(-1); 4872 if (name == NULL) 4873 return(-1); 4874 4875 if (ctxt->funcHash == NULL) 4876 ctxt->funcHash = xmlHashCreate(0); 4877 if (ctxt->funcHash == NULL) 4878 return(-1); 4879 if (f == NULL) 4880 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL)); 4881 XML_IGNORE_PEDANTIC_WARNINGS 4882 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f)); 4883 XML_POP_WARNINGS 4884 } 4885 4886 /** 4887 * xmlXPathRegisterFuncLookup: 4888 * @ctxt: the XPath context 4889 * @f: the lookup function 4890 * @funcCtxt: the lookup data 4891 * 4892 * Registers an external mechanism to do function lookup. 4893 */ 4894 void 4895 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt, 4896 xmlXPathFuncLookupFunc f, 4897 void *funcCtxt) { 4898 if (ctxt == NULL) 4899 return; 4900 ctxt->funcLookupFunc = f; 4901 ctxt->funcLookupData = funcCtxt; 4902 } 4903 4904 /** 4905 * xmlXPathFunctionLookup: 4906 * @ctxt: the XPath context 4907 * @name: the function name 4908 * 4909 * Search in the Function array of the context for the given 4910 * function. 4911 * 4912 * Returns the xmlXPathFunction or NULL if not found 4913 */ 4914 xmlXPathFunction 4915 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { 4916 if (ctxt == NULL) 4917 return (NULL); 4918 4919 if (ctxt->funcLookupFunc != NULL) { 4920 xmlXPathFunction ret; 4921 xmlXPathFuncLookupFunc f; 4922 4923 f = ctxt->funcLookupFunc; 4924 ret = f(ctxt->funcLookupData, name, NULL); 4925 if (ret != NULL) 4926 return(ret); 4927 } 4928 return(xmlXPathFunctionLookupNS(ctxt, name, NULL)); 4929 } 4930 4931 /** 4932 * xmlXPathFunctionLookupNS: 4933 * @ctxt: the XPath context 4934 * @name: the function name 4935 * @ns_uri: the function namespace URI 4936 * 4937 * Search in the Function array of the context for the given 4938 * function. 4939 * 4940 * Returns the xmlXPathFunction or NULL if not found 4941 */ 4942 xmlXPathFunction 4943 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name, 4944 const xmlChar *ns_uri) { 4945 xmlXPathFunction ret; 4946 4947 if (ctxt == NULL) 4948 return(NULL); 4949 if (name == NULL) 4950 return(NULL); 4951 4952 if (ctxt->funcLookupFunc != NULL) { 4953 xmlXPathFuncLookupFunc f; 4954 4955 f = ctxt->funcLookupFunc; 4956 ret = f(ctxt->funcLookupData, name, ns_uri); 4957 if (ret != NULL) 4958 return(ret); 4959 } 4960 4961 if (ctxt->funcHash == NULL) 4962 return(NULL); 4963 4964 XML_IGNORE_PEDANTIC_WARNINGS 4965 ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri); 4966 XML_POP_WARNINGS 4967 return(ret); 4968 } 4969 4970 /** 4971 * xmlXPathRegisteredFuncsCleanup: 4972 * @ctxt: the XPath context 4973 * 4974 * Cleanup the XPath context data associated to registered functions 4975 */ 4976 void 4977 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) { 4978 if (ctxt == NULL) 4979 return; 4980 4981 xmlHashFree(ctxt->funcHash, NULL); 4982 ctxt->funcHash = NULL; 4983 } 4984 4985 /************************************************************************ 4986 * * 4987 * Routines to handle Variables * 4988 * * 4989 ************************************************************************/ 4990 4991 /** 4992 * xmlXPathRegisterVariable: 4993 * @ctxt: the XPath context 4994 * @name: the variable name 4995 * @value: the variable value or NULL 4996 * 4997 * Register a new variable value. If @value is NULL it unregisters 4998 * the variable 4999 * 5000 * Returns 0 in case of success, -1 in case of error 5001 */ 5002 int 5003 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name, 5004 xmlXPathObjectPtr value) { 5005 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value)); 5006 } 5007 5008 /** 5009 * xmlXPathRegisterVariableNS: 5010 * @ctxt: the XPath context 5011 * @name: the variable name 5012 * @ns_uri: the variable namespace URI 5013 * @value: the variable value or NULL 5014 * 5015 * Register a new variable value. If @value is NULL it unregisters 5016 * the variable 5017 * 5018 * Returns 0 in case of success, -1 in case of error 5019 */ 5020 int 5021 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name, 5022 const xmlChar *ns_uri, 5023 xmlXPathObjectPtr value) { 5024 if (ctxt == NULL) 5025 return(-1); 5026 if (name == NULL) 5027 return(-1); 5028 5029 if (ctxt->varHash == NULL) 5030 ctxt->varHash = xmlHashCreate(0); 5031 if (ctxt->varHash == NULL) 5032 return(-1); 5033 if (value == NULL) 5034 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri, 5035 xmlXPathFreeObjectEntry)); 5036 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri, 5037 (void *) value, xmlXPathFreeObjectEntry)); 5038 } 5039 5040 /** 5041 * xmlXPathRegisterVariableLookup: 5042 * @ctxt: the XPath context 5043 * @f: the lookup function 5044 * @data: the lookup data 5045 * 5046 * register an external mechanism to do variable lookup 5047 */ 5048 void 5049 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt, 5050 xmlXPathVariableLookupFunc f, void *data) { 5051 if (ctxt == NULL) 5052 return; 5053 ctxt->varLookupFunc = f; 5054 ctxt->varLookupData = data; 5055 } 5056 5057 /** 5058 * xmlXPathVariableLookup: 5059 * @ctxt: the XPath context 5060 * @name: the variable name 5061 * 5062 * Search in the Variable array of the context for the given 5063 * variable value. 5064 * 5065 * Returns a copy of the value or NULL if not found 5066 */ 5067 xmlXPathObjectPtr 5068 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { 5069 if (ctxt == NULL) 5070 return(NULL); 5071 5072 if (ctxt->varLookupFunc != NULL) { 5073 xmlXPathObjectPtr ret; 5074 5075 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc) 5076 (ctxt->varLookupData, name, NULL); 5077 return(ret); 5078 } 5079 return(xmlXPathVariableLookupNS(ctxt, name, NULL)); 5080 } 5081 5082 /** 5083 * xmlXPathVariableLookupNS: 5084 * @ctxt: the XPath context 5085 * @name: the variable name 5086 * @ns_uri: the variable namespace URI 5087 * 5088 * Search in the Variable array of the context for the given 5089 * variable value. 5090 * 5091 * Returns the a copy of the value or NULL if not found 5092 */ 5093 xmlXPathObjectPtr 5094 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name, 5095 const xmlChar *ns_uri) { 5096 if (ctxt == NULL) 5097 return(NULL); 5098 5099 if (ctxt->varLookupFunc != NULL) { 5100 xmlXPathObjectPtr ret; 5101 5102 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc) 5103 (ctxt->varLookupData, name, ns_uri); 5104 if (ret != NULL) return(ret); 5105 } 5106 5107 if (ctxt->varHash == NULL) 5108 return(NULL); 5109 if (name == NULL) 5110 return(NULL); 5111 5112 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr) 5113 xmlHashLookup2(ctxt->varHash, name, ns_uri))); 5114 } 5115 5116 /** 5117 * xmlXPathRegisteredVariablesCleanup: 5118 * @ctxt: the XPath context 5119 * 5120 * Cleanup the XPath context data associated to registered variables 5121 */ 5122 void 5123 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) { 5124 if (ctxt == NULL) 5125 return; 5126 5127 xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry); 5128 ctxt->varHash = NULL; 5129 } 5130 5131 /** 5132 * xmlXPathRegisterNs: 5133 * @ctxt: the XPath context 5134 * @prefix: the namespace prefix cannot be NULL or empty string 5135 * @ns_uri: the namespace name 5136 * 5137 * Register a new namespace. If @ns_uri is NULL it unregisters 5138 * the namespace 5139 * 5140 * Returns 0 in case of success, -1 in case of error 5141 */ 5142 int 5143 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix, 5144 const xmlChar *ns_uri) { 5145 if (ctxt == NULL) 5146 return(-1); 5147 if (prefix == NULL) 5148 return(-1); 5149 if (prefix[0] == 0) 5150 return(-1); 5151 5152 if (ctxt->nsHash == NULL) 5153 ctxt->nsHash = xmlHashCreate(10); 5154 if (ctxt->nsHash == NULL) 5155 return(-1); 5156 if (ns_uri == NULL) 5157 return(xmlHashRemoveEntry(ctxt->nsHash, prefix, 5158 xmlHashDefaultDeallocator)); 5159 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri), 5160 xmlHashDefaultDeallocator)); 5161 } 5162 5163 /** 5164 * xmlXPathNsLookup: 5165 * @ctxt: the XPath context 5166 * @prefix: the namespace prefix value 5167 * 5168 * Search in the namespace declaration array of the context for the given 5169 * namespace name associated to the given prefix 5170 * 5171 * Returns the value or NULL if not found 5172 */ 5173 const xmlChar * 5174 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) { 5175 if (ctxt == NULL) 5176 return(NULL); 5177 if (prefix == NULL) 5178 return(NULL); 5179 5180 #ifdef XML_XML_NAMESPACE 5181 if (xmlStrEqual(prefix, (const xmlChar *) "xml")) 5182 return(XML_XML_NAMESPACE); 5183 #endif 5184 5185 if (ctxt->namespaces != NULL) { 5186 int i; 5187 5188 for (i = 0;i < ctxt->nsNr;i++) { 5189 if ((ctxt->namespaces[i] != NULL) && 5190 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix))) 5191 return(ctxt->namespaces[i]->href); 5192 } 5193 } 5194 5195 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix)); 5196 } 5197 5198 /** 5199 * xmlXPathRegisteredNsCleanup: 5200 * @ctxt: the XPath context 5201 * 5202 * Cleanup the XPath context data associated to registered variables 5203 */ 5204 void 5205 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) { 5206 if (ctxt == NULL) 5207 return; 5208 5209 xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator); 5210 ctxt->nsHash = NULL; 5211 } 5212 5213 /************************************************************************ 5214 * * 5215 * Routines to handle Values * 5216 * * 5217 ************************************************************************/ 5218 5219 /* Allocations are terrible, one needs to optimize all this !!! */ 5220 5221 /** 5222 * xmlXPathNewFloat: 5223 * @val: the double value 5224 * 5225 * Create a new xmlXPathObjectPtr of type double and of value @val 5226 * 5227 * Returns the newly created object. 5228 */ 5229 xmlXPathObjectPtr 5230 xmlXPathNewFloat(double val) { 5231 xmlXPathObjectPtr ret; 5232 5233 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5234 if (ret == NULL) { 5235 xmlXPathErrMemory(NULL, "creating float object\n"); 5236 return(NULL); 5237 } 5238 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5239 ret->type = XPATH_NUMBER; 5240 ret->floatval = val; 5241 #ifdef XP_DEBUG_OBJ_USAGE 5242 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER); 5243 #endif 5244 return(ret); 5245 } 5246 5247 /** 5248 * xmlXPathNewBoolean: 5249 * @val: the boolean value 5250 * 5251 * Create a new xmlXPathObjectPtr of type boolean and of value @val 5252 * 5253 * Returns the newly created object. 5254 */ 5255 xmlXPathObjectPtr 5256 xmlXPathNewBoolean(int val) { 5257 xmlXPathObjectPtr ret; 5258 5259 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5260 if (ret == NULL) { 5261 xmlXPathErrMemory(NULL, "creating boolean object\n"); 5262 return(NULL); 5263 } 5264 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5265 ret->type = XPATH_BOOLEAN; 5266 ret->boolval = (val != 0); 5267 #ifdef XP_DEBUG_OBJ_USAGE 5268 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN); 5269 #endif 5270 return(ret); 5271 } 5272 5273 /** 5274 * xmlXPathNewString: 5275 * @val: the xmlChar * value 5276 * 5277 * Create a new xmlXPathObjectPtr of type string and of value @val 5278 * 5279 * Returns the newly created object. 5280 */ 5281 xmlXPathObjectPtr 5282 xmlXPathNewString(const xmlChar *val) { 5283 xmlXPathObjectPtr ret; 5284 5285 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5286 if (ret == NULL) { 5287 xmlXPathErrMemory(NULL, "creating string object\n"); 5288 return(NULL); 5289 } 5290 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5291 ret->type = XPATH_STRING; 5292 if (val != NULL) 5293 ret->stringval = xmlStrdup(val); 5294 else 5295 ret->stringval = xmlStrdup((const xmlChar *)""); 5296 #ifdef XP_DEBUG_OBJ_USAGE 5297 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); 5298 #endif 5299 return(ret); 5300 } 5301 5302 /** 5303 * xmlXPathWrapString: 5304 * @val: the xmlChar * value 5305 * 5306 * Wraps the @val string into an XPath object. 5307 * 5308 * Returns the newly created object. 5309 */ 5310 xmlXPathObjectPtr 5311 xmlXPathWrapString (xmlChar *val) { 5312 xmlXPathObjectPtr ret; 5313 5314 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5315 if (ret == NULL) { 5316 xmlXPathErrMemory(NULL, "creating string object\n"); 5317 return(NULL); 5318 } 5319 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5320 ret->type = XPATH_STRING; 5321 ret->stringval = val; 5322 #ifdef XP_DEBUG_OBJ_USAGE 5323 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); 5324 #endif 5325 return(ret); 5326 } 5327 5328 /** 5329 * xmlXPathNewCString: 5330 * @val: the char * value 5331 * 5332 * Create a new xmlXPathObjectPtr of type string and of value @val 5333 * 5334 * Returns the newly created object. 5335 */ 5336 xmlXPathObjectPtr 5337 xmlXPathNewCString(const char *val) { 5338 xmlXPathObjectPtr ret; 5339 5340 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5341 if (ret == NULL) { 5342 xmlXPathErrMemory(NULL, "creating string object\n"); 5343 return(NULL); 5344 } 5345 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5346 ret->type = XPATH_STRING; 5347 ret->stringval = xmlStrdup(BAD_CAST val); 5348 #ifdef XP_DEBUG_OBJ_USAGE 5349 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); 5350 #endif 5351 return(ret); 5352 } 5353 5354 /** 5355 * xmlXPathWrapCString: 5356 * @val: the char * value 5357 * 5358 * Wraps a string into an XPath object. 5359 * 5360 * Returns the newly created object. 5361 */ 5362 xmlXPathObjectPtr 5363 xmlXPathWrapCString (char * val) { 5364 return(xmlXPathWrapString((xmlChar *)(val))); 5365 } 5366 5367 /** 5368 * xmlXPathWrapExternal: 5369 * @val: the user data 5370 * 5371 * Wraps the @val data into an XPath object. 5372 * 5373 * Returns the newly created object. 5374 */ 5375 xmlXPathObjectPtr 5376 xmlXPathWrapExternal (void *val) { 5377 xmlXPathObjectPtr ret; 5378 5379 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5380 if (ret == NULL) { 5381 xmlXPathErrMemory(NULL, "creating user object\n"); 5382 return(NULL); 5383 } 5384 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5385 ret->type = XPATH_USERS; 5386 ret->user = val; 5387 #ifdef XP_DEBUG_OBJ_USAGE 5388 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS); 5389 #endif 5390 return(ret); 5391 } 5392 5393 /** 5394 * xmlXPathObjectCopy: 5395 * @val: the original object 5396 * 5397 * allocate a new copy of a given object 5398 * 5399 * Returns the newly created object. 5400 */ 5401 xmlXPathObjectPtr 5402 xmlXPathObjectCopy(xmlXPathObjectPtr val) { 5403 xmlXPathObjectPtr ret; 5404 5405 if (val == NULL) 5406 return(NULL); 5407 5408 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5409 if (ret == NULL) { 5410 xmlXPathErrMemory(NULL, "copying object\n"); 5411 return(NULL); 5412 } 5413 memcpy(ret, val , (size_t) sizeof(xmlXPathObject)); 5414 #ifdef XP_DEBUG_OBJ_USAGE 5415 xmlXPathDebugObjUsageRequested(NULL, val->type); 5416 #endif 5417 switch (val->type) { 5418 case XPATH_BOOLEAN: 5419 case XPATH_NUMBER: 5420 case XPATH_POINT: 5421 case XPATH_RANGE: 5422 break; 5423 case XPATH_STRING: 5424 ret->stringval = xmlStrdup(val->stringval); 5425 break; 5426 case XPATH_XSLT_TREE: 5427 #if 0 5428 /* 5429 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that 5430 this previous handling is no longer correct, and can cause some serious 5431 problems (ref. bug 145547) 5432 */ 5433 if ((val->nodesetval != NULL) && 5434 (val->nodesetval->nodeTab != NULL)) { 5435 xmlNodePtr cur, tmp; 5436 xmlDocPtr top; 5437 5438 ret->boolval = 1; 5439 top = xmlNewDoc(NULL); 5440 top->name = (char *) 5441 xmlStrdup(val->nodesetval->nodeTab[0]->name); 5442 ret->user = top; 5443 if (top != NULL) { 5444 top->doc = top; 5445 cur = val->nodesetval->nodeTab[0]->children; 5446 while (cur != NULL) { 5447 tmp = xmlDocCopyNode(cur, top, 1); 5448 xmlAddChild((xmlNodePtr) top, tmp); 5449 cur = cur->next; 5450 } 5451 } 5452 5453 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top); 5454 } else 5455 ret->nodesetval = xmlXPathNodeSetCreate(NULL); 5456 /* Deallocate the copied tree value */ 5457 break; 5458 #endif 5459 case XPATH_NODESET: 5460 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval); 5461 /* Do not deallocate the copied tree value */ 5462 ret->boolval = 0; 5463 break; 5464 case XPATH_LOCATIONSET: 5465 #ifdef LIBXML_XPTR_ENABLED 5466 { 5467 xmlLocationSetPtr loc = val->user; 5468 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc); 5469 break; 5470 } 5471 #endif 5472 case XPATH_USERS: 5473 ret->user = val->user; 5474 break; 5475 case XPATH_UNDEFINED: 5476 xmlGenericError(xmlGenericErrorContext, 5477 "xmlXPathObjectCopy: unsupported type %d\n", 5478 val->type); 5479 break; 5480 } 5481 return(ret); 5482 } 5483 5484 /** 5485 * xmlXPathFreeObject: 5486 * @obj: the object to free 5487 * 5488 * Free up an xmlXPathObjectPtr object. 5489 */ 5490 void 5491 xmlXPathFreeObject(xmlXPathObjectPtr obj) { 5492 if (obj == NULL) return; 5493 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) { 5494 if (obj->boolval) { 5495 #if 0 5496 if (obj->user != NULL) { 5497 xmlXPathFreeNodeSet(obj->nodesetval); 5498 xmlFreeNodeList((xmlNodePtr) obj->user); 5499 } else 5500 #endif 5501 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */ 5502 if (obj->nodesetval != NULL) 5503 xmlXPathFreeValueTree(obj->nodesetval); 5504 } else { 5505 if (obj->nodesetval != NULL) 5506 xmlXPathFreeNodeSet(obj->nodesetval); 5507 } 5508 #ifdef LIBXML_XPTR_ENABLED 5509 } else if (obj->type == XPATH_LOCATIONSET) { 5510 if (obj->user != NULL) 5511 xmlXPtrFreeLocationSet(obj->user); 5512 #endif 5513 } else if (obj->type == XPATH_STRING) { 5514 if (obj->stringval != NULL) 5515 xmlFree(obj->stringval); 5516 } 5517 #ifdef XP_DEBUG_OBJ_USAGE 5518 xmlXPathDebugObjUsageReleased(NULL, obj->type); 5519 #endif 5520 xmlFree(obj); 5521 } 5522 5523 static void 5524 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) { 5525 xmlXPathFreeObject((xmlXPathObjectPtr) obj); 5526 } 5527 5528 /** 5529 * xmlXPathReleaseObject: 5530 * @obj: the xmlXPathObjectPtr to free or to cache 5531 * 5532 * Depending on the state of the cache this frees the given 5533 * XPath object or stores it in the cache. 5534 */ 5535 static void 5536 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj) 5537 { 5538 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \ 5539 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \ 5540 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj; 5541 5542 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n)) 5543 5544 if (obj == NULL) 5545 return; 5546 if ((ctxt == NULL) || (ctxt->cache == NULL)) { 5547 xmlXPathFreeObject(obj); 5548 } else { 5549 xmlXPathContextCachePtr cache = 5550 (xmlXPathContextCachePtr) ctxt->cache; 5551 5552 switch (obj->type) { 5553 case XPATH_NODESET: 5554 case XPATH_XSLT_TREE: 5555 if (obj->nodesetval != NULL) { 5556 if (obj->boolval) { 5557 /* 5558 * It looks like the @boolval is used for 5559 * evaluation if this an XSLT Result Tree Fragment. 5560 * TODO: Check if this assumption is correct. 5561 */ 5562 obj->type = XPATH_XSLT_TREE; /* just for debugging */ 5563 xmlXPathFreeValueTree(obj->nodesetval); 5564 obj->nodesetval = NULL; 5565 } else if ((obj->nodesetval->nodeMax <= 40) && 5566 (XP_CACHE_WANTS(cache->nodesetObjs, 5567 cache->maxNodeset))) 5568 { 5569 XP_CACHE_ADD(cache->nodesetObjs, obj); 5570 goto obj_cached; 5571 } else { 5572 xmlXPathFreeNodeSet(obj->nodesetval); 5573 obj->nodesetval = NULL; 5574 } 5575 } 5576 break; 5577 case XPATH_STRING: 5578 if (obj->stringval != NULL) 5579 xmlFree(obj->stringval); 5580 5581 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) { 5582 XP_CACHE_ADD(cache->stringObjs, obj); 5583 goto obj_cached; 5584 } 5585 break; 5586 case XPATH_BOOLEAN: 5587 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) { 5588 XP_CACHE_ADD(cache->booleanObjs, obj); 5589 goto obj_cached; 5590 } 5591 break; 5592 case XPATH_NUMBER: 5593 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) { 5594 XP_CACHE_ADD(cache->numberObjs, obj); 5595 goto obj_cached; 5596 } 5597 break; 5598 #ifdef LIBXML_XPTR_ENABLED 5599 case XPATH_LOCATIONSET: 5600 if (obj->user != NULL) { 5601 xmlXPtrFreeLocationSet(obj->user); 5602 } 5603 goto free_obj; 5604 #endif 5605 default: 5606 goto free_obj; 5607 } 5608 5609 /* 5610 * Fallback to adding to the misc-objects slot. 5611 */ 5612 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) { 5613 XP_CACHE_ADD(cache->miscObjs, obj); 5614 } else 5615 goto free_obj; 5616 5617 obj_cached: 5618 5619 #ifdef XP_DEBUG_OBJ_USAGE 5620 xmlXPathDebugObjUsageReleased(ctxt, obj->type); 5621 #endif 5622 5623 if (obj->nodesetval != NULL) { 5624 xmlNodeSetPtr tmpset = obj->nodesetval; 5625 5626 /* 5627 * TODO: Due to those nasty ns-nodes, we need to traverse 5628 * the list and free the ns-nodes. 5629 * URGENT TODO: Check if it's actually slowing things down. 5630 * Maybe we shouldn't try to preserve the list. 5631 */ 5632 if (tmpset->nodeNr > 1) { 5633 int i; 5634 xmlNodePtr node; 5635 5636 for (i = 0; i < tmpset->nodeNr; i++) { 5637 node = tmpset->nodeTab[i]; 5638 if ((node != NULL) && 5639 (node->type == XML_NAMESPACE_DECL)) 5640 { 5641 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 5642 } 5643 } 5644 } else if (tmpset->nodeNr == 1) { 5645 if ((tmpset->nodeTab[0] != NULL) && 5646 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL)) 5647 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]); 5648 } 5649 tmpset->nodeNr = 0; 5650 memset(obj, 0, sizeof(xmlXPathObject)); 5651 obj->nodesetval = tmpset; 5652 } else 5653 memset(obj, 0, sizeof(xmlXPathObject)); 5654 5655 return; 5656 5657 free_obj: 5658 /* 5659 * Cache is full; free the object. 5660 */ 5661 if (obj->nodesetval != NULL) 5662 xmlXPathFreeNodeSet(obj->nodesetval); 5663 #ifdef XP_DEBUG_OBJ_USAGE 5664 xmlXPathDebugObjUsageReleased(NULL, obj->type); 5665 #endif 5666 xmlFree(obj); 5667 } 5668 return; 5669 } 5670 5671 5672 /************************************************************************ 5673 * * 5674 * Type Casting Routines * 5675 * * 5676 ************************************************************************/ 5677 5678 /** 5679 * xmlXPathCastBooleanToString: 5680 * @val: a boolean 5681 * 5682 * Converts a boolean to its string value. 5683 * 5684 * Returns a newly allocated string. 5685 */ 5686 xmlChar * 5687 xmlXPathCastBooleanToString (int val) { 5688 xmlChar *ret; 5689 if (val) 5690 ret = xmlStrdup((const xmlChar *) "true"); 5691 else 5692 ret = xmlStrdup((const xmlChar *) "false"); 5693 return(ret); 5694 } 5695 5696 /** 5697 * xmlXPathCastNumberToString: 5698 * @val: a number 5699 * 5700 * Converts a number to its string value. 5701 * 5702 * Returns a newly allocated string. 5703 */ 5704 xmlChar * 5705 xmlXPathCastNumberToString (double val) { 5706 xmlChar *ret; 5707 switch (xmlXPathIsInf(val)) { 5708 case 1: 5709 ret = xmlStrdup((const xmlChar *) "Infinity"); 5710 break; 5711 case -1: 5712 ret = xmlStrdup((const xmlChar *) "-Infinity"); 5713 break; 5714 default: 5715 if (xmlXPathIsNaN(val)) { 5716 ret = xmlStrdup((const xmlChar *) "NaN"); 5717 } else if (val == 0) { 5718 /* Omit sign for negative zero. */ 5719 ret = xmlStrdup((const xmlChar *) "0"); 5720 } else { 5721 /* could be improved */ 5722 char buf[100]; 5723 xmlXPathFormatNumber(val, buf, 99); 5724 buf[99] = 0; 5725 ret = xmlStrdup((const xmlChar *) buf); 5726 } 5727 } 5728 return(ret); 5729 } 5730 5731 /** 5732 * xmlXPathCastNodeToString: 5733 * @node: a node 5734 * 5735 * Converts a node to its string value. 5736 * 5737 * Returns a newly allocated string. 5738 */ 5739 xmlChar * 5740 xmlXPathCastNodeToString (xmlNodePtr node) { 5741 xmlChar *ret; 5742 if ((ret = xmlNodeGetContent(node)) == NULL) 5743 ret = xmlStrdup((const xmlChar *) ""); 5744 return(ret); 5745 } 5746 5747 /** 5748 * xmlXPathCastNodeSetToString: 5749 * @ns: a node-set 5750 * 5751 * Converts a node-set to its string value. 5752 * 5753 * Returns a newly allocated string. 5754 */ 5755 xmlChar * 5756 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) { 5757 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL)) 5758 return(xmlStrdup((const xmlChar *) "")); 5759 5760 if (ns->nodeNr > 1) 5761 xmlXPathNodeSetSort(ns); 5762 return(xmlXPathCastNodeToString(ns->nodeTab[0])); 5763 } 5764 5765 /** 5766 * xmlXPathCastToString: 5767 * @val: an XPath object 5768 * 5769 * Converts an existing object to its string() equivalent 5770 * 5771 * Returns the allocated string value of the object, NULL in case of error. 5772 * It's up to the caller to free the string memory with xmlFree(). 5773 */ 5774 xmlChar * 5775 xmlXPathCastToString(xmlXPathObjectPtr val) { 5776 xmlChar *ret = NULL; 5777 5778 if (val == NULL) 5779 return(xmlStrdup((const xmlChar *) "")); 5780 switch (val->type) { 5781 case XPATH_UNDEFINED: 5782 #ifdef DEBUG_EXPR 5783 xmlGenericError(xmlGenericErrorContext, "String: undefined\n"); 5784 #endif 5785 ret = xmlStrdup((const xmlChar *) ""); 5786 break; 5787 case XPATH_NODESET: 5788 case XPATH_XSLT_TREE: 5789 ret = xmlXPathCastNodeSetToString(val->nodesetval); 5790 break; 5791 case XPATH_STRING: 5792 return(xmlStrdup(val->stringval)); 5793 case XPATH_BOOLEAN: 5794 ret = xmlXPathCastBooleanToString(val->boolval); 5795 break; 5796 case XPATH_NUMBER: { 5797 ret = xmlXPathCastNumberToString(val->floatval); 5798 break; 5799 } 5800 case XPATH_USERS: 5801 case XPATH_POINT: 5802 case XPATH_RANGE: 5803 case XPATH_LOCATIONSET: 5804 TODO 5805 ret = xmlStrdup((const xmlChar *) ""); 5806 break; 5807 } 5808 return(ret); 5809 } 5810 5811 /** 5812 * xmlXPathConvertString: 5813 * @val: an XPath object 5814 * 5815 * Converts an existing object to its string() equivalent 5816 * 5817 * Returns the new object, the old one is freed (or the operation 5818 * is done directly on @val) 5819 */ 5820 xmlXPathObjectPtr 5821 xmlXPathConvertString(xmlXPathObjectPtr val) { 5822 xmlChar *res = NULL; 5823 5824 if (val == NULL) 5825 return(xmlXPathNewCString("")); 5826 5827 switch (val->type) { 5828 case XPATH_UNDEFINED: 5829 #ifdef DEBUG_EXPR 5830 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n"); 5831 #endif 5832 break; 5833 case XPATH_NODESET: 5834 case XPATH_XSLT_TREE: 5835 res = xmlXPathCastNodeSetToString(val->nodesetval); 5836 break; 5837 case XPATH_STRING: 5838 return(val); 5839 case XPATH_BOOLEAN: 5840 res = xmlXPathCastBooleanToString(val->boolval); 5841 break; 5842 case XPATH_NUMBER: 5843 res = xmlXPathCastNumberToString(val->floatval); 5844 break; 5845 case XPATH_USERS: 5846 case XPATH_POINT: 5847 case XPATH_RANGE: 5848 case XPATH_LOCATIONSET: 5849 TODO; 5850 break; 5851 } 5852 xmlXPathFreeObject(val); 5853 if (res == NULL) 5854 return(xmlXPathNewCString("")); 5855 return(xmlXPathWrapString(res)); 5856 } 5857 5858 /** 5859 * xmlXPathCastBooleanToNumber: 5860 * @val: a boolean 5861 * 5862 * Converts a boolean to its number value 5863 * 5864 * Returns the number value 5865 */ 5866 double 5867 xmlXPathCastBooleanToNumber(int val) { 5868 if (val) 5869 return(1.0); 5870 return(0.0); 5871 } 5872 5873 /** 5874 * xmlXPathCastStringToNumber: 5875 * @val: a string 5876 * 5877 * Converts a string to its number value 5878 * 5879 * Returns the number value 5880 */ 5881 double 5882 xmlXPathCastStringToNumber(const xmlChar * val) { 5883 return(xmlXPathStringEvalNumber(val)); 5884 } 5885 5886 /** 5887 * xmlXPathCastNodeToNumber: 5888 * @node: a node 5889 * 5890 * Converts a node to its number value 5891 * 5892 * Returns the number value 5893 */ 5894 double 5895 xmlXPathCastNodeToNumber (xmlNodePtr node) { 5896 xmlChar *strval; 5897 double ret; 5898 5899 if (node == NULL) 5900 return(NAN); 5901 strval = xmlXPathCastNodeToString(node); 5902 if (strval == NULL) 5903 return(NAN); 5904 ret = xmlXPathCastStringToNumber(strval); 5905 xmlFree(strval); 5906 5907 return(ret); 5908 } 5909 5910 /** 5911 * xmlXPathCastNodeSetToNumber: 5912 * @ns: a node-set 5913 * 5914 * Converts a node-set to its number value 5915 * 5916 * Returns the number value 5917 */ 5918 double 5919 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) { 5920 xmlChar *str; 5921 double ret; 5922 5923 if (ns == NULL) 5924 return(NAN); 5925 str = xmlXPathCastNodeSetToString(ns); 5926 ret = xmlXPathCastStringToNumber(str); 5927 xmlFree(str); 5928 return(ret); 5929 } 5930 5931 /** 5932 * xmlXPathCastToNumber: 5933 * @val: an XPath object 5934 * 5935 * Converts an XPath object to its number value 5936 * 5937 * Returns the number value 5938 */ 5939 double 5940 xmlXPathCastToNumber(xmlXPathObjectPtr val) { 5941 double ret = 0.0; 5942 5943 if (val == NULL) 5944 return(NAN); 5945 switch (val->type) { 5946 case XPATH_UNDEFINED: 5947 #ifdef DEGUB_EXPR 5948 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n"); 5949 #endif 5950 ret = NAN; 5951 break; 5952 case XPATH_NODESET: 5953 case XPATH_XSLT_TREE: 5954 ret = xmlXPathCastNodeSetToNumber(val->nodesetval); 5955 break; 5956 case XPATH_STRING: 5957 ret = xmlXPathCastStringToNumber(val->stringval); 5958 break; 5959 case XPATH_NUMBER: 5960 ret = val->floatval; 5961 break; 5962 case XPATH_BOOLEAN: 5963 ret = xmlXPathCastBooleanToNumber(val->boolval); 5964 break; 5965 case XPATH_USERS: 5966 case XPATH_POINT: 5967 case XPATH_RANGE: 5968 case XPATH_LOCATIONSET: 5969 TODO; 5970 ret = NAN; 5971 break; 5972 } 5973 return(ret); 5974 } 5975 5976 /** 5977 * xmlXPathConvertNumber: 5978 * @val: an XPath object 5979 * 5980 * Converts an existing object to its number() equivalent 5981 * 5982 * Returns the new object, the old one is freed (or the operation 5983 * is done directly on @val) 5984 */ 5985 xmlXPathObjectPtr 5986 xmlXPathConvertNumber(xmlXPathObjectPtr val) { 5987 xmlXPathObjectPtr ret; 5988 5989 if (val == NULL) 5990 return(xmlXPathNewFloat(0.0)); 5991 if (val->type == XPATH_NUMBER) 5992 return(val); 5993 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val)); 5994 xmlXPathFreeObject(val); 5995 return(ret); 5996 } 5997 5998 /** 5999 * xmlXPathCastNumberToBoolean: 6000 * @val: a number 6001 * 6002 * Converts a number to its boolean value 6003 * 6004 * Returns the boolean value 6005 */ 6006 int 6007 xmlXPathCastNumberToBoolean (double val) { 6008 if (xmlXPathIsNaN(val) || (val == 0.0)) 6009 return(0); 6010 return(1); 6011 } 6012 6013 /** 6014 * xmlXPathCastStringToBoolean: 6015 * @val: a string 6016 * 6017 * Converts a string to its boolean value 6018 * 6019 * Returns the boolean value 6020 */ 6021 int 6022 xmlXPathCastStringToBoolean (const xmlChar *val) { 6023 if ((val == NULL) || (xmlStrlen(val) == 0)) 6024 return(0); 6025 return(1); 6026 } 6027 6028 /** 6029 * xmlXPathCastNodeSetToBoolean: 6030 * @ns: a node-set 6031 * 6032 * Converts a node-set to its boolean value 6033 * 6034 * Returns the boolean value 6035 */ 6036 int 6037 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) { 6038 if ((ns == NULL) || (ns->nodeNr == 0)) 6039 return(0); 6040 return(1); 6041 } 6042 6043 /** 6044 * xmlXPathCastToBoolean: 6045 * @val: an XPath object 6046 * 6047 * Converts an XPath object to its boolean value 6048 * 6049 * Returns the boolean value 6050 */ 6051 int 6052 xmlXPathCastToBoolean (xmlXPathObjectPtr val) { 6053 int ret = 0; 6054 6055 if (val == NULL) 6056 return(0); 6057 switch (val->type) { 6058 case XPATH_UNDEFINED: 6059 #ifdef DEBUG_EXPR 6060 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n"); 6061 #endif 6062 ret = 0; 6063 break; 6064 case XPATH_NODESET: 6065 case XPATH_XSLT_TREE: 6066 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval); 6067 break; 6068 case XPATH_STRING: 6069 ret = xmlXPathCastStringToBoolean(val->stringval); 6070 break; 6071 case XPATH_NUMBER: 6072 ret = xmlXPathCastNumberToBoolean(val->floatval); 6073 break; 6074 case XPATH_BOOLEAN: 6075 ret = val->boolval; 6076 break; 6077 case XPATH_USERS: 6078 case XPATH_POINT: 6079 case XPATH_RANGE: 6080 case XPATH_LOCATIONSET: 6081 TODO; 6082 ret = 0; 6083 break; 6084 } 6085 return(ret); 6086 } 6087 6088 6089 /** 6090 * xmlXPathConvertBoolean: 6091 * @val: an XPath object 6092 * 6093 * Converts an existing object to its boolean() equivalent 6094 * 6095 * Returns the new object, the old one is freed (or the operation 6096 * is done directly on @val) 6097 */ 6098 xmlXPathObjectPtr 6099 xmlXPathConvertBoolean(xmlXPathObjectPtr val) { 6100 xmlXPathObjectPtr ret; 6101 6102 if (val == NULL) 6103 return(xmlXPathNewBoolean(0)); 6104 if (val->type == XPATH_BOOLEAN) 6105 return(val); 6106 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val)); 6107 xmlXPathFreeObject(val); 6108 return(ret); 6109 } 6110 6111 /************************************************************************ 6112 * * 6113 * Routines to handle XPath contexts * 6114 * * 6115 ************************************************************************/ 6116 6117 /** 6118 * xmlXPathNewContext: 6119 * @doc: the XML document 6120 * 6121 * Create a new xmlXPathContext 6122 * 6123 * Returns the xmlXPathContext just allocated. The caller will need to free it. 6124 */ 6125 xmlXPathContextPtr 6126 xmlXPathNewContext(xmlDocPtr doc) { 6127 xmlXPathContextPtr ret; 6128 6129 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext)); 6130 if (ret == NULL) { 6131 xmlXPathErrMemory(NULL, "creating context\n"); 6132 return(NULL); 6133 } 6134 memset(ret, 0 , (size_t) sizeof(xmlXPathContext)); 6135 ret->doc = doc; 6136 ret->node = NULL; 6137 6138 ret->varHash = NULL; 6139 6140 ret->nb_types = 0; 6141 ret->max_types = 0; 6142 ret->types = NULL; 6143 6144 ret->funcHash = xmlHashCreate(0); 6145 6146 ret->nb_axis = 0; 6147 ret->max_axis = 0; 6148 ret->axis = NULL; 6149 6150 ret->nsHash = NULL; 6151 ret->user = NULL; 6152 6153 ret->contextSize = -1; 6154 ret->proximityPosition = -1; 6155 6156 #ifdef XP_DEFAULT_CACHE_ON 6157 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) { 6158 xmlXPathFreeContext(ret); 6159 return(NULL); 6160 } 6161 #endif 6162 6163 xmlXPathRegisterAllFunctions(ret); 6164 6165 return(ret); 6166 } 6167 6168 /** 6169 * xmlXPathFreeContext: 6170 * @ctxt: the context to free 6171 * 6172 * Free up an xmlXPathContext 6173 */ 6174 void 6175 xmlXPathFreeContext(xmlXPathContextPtr ctxt) { 6176 if (ctxt == NULL) return; 6177 6178 if (ctxt->cache != NULL) 6179 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache); 6180 xmlXPathRegisteredNsCleanup(ctxt); 6181 xmlXPathRegisteredFuncsCleanup(ctxt); 6182 xmlXPathRegisteredVariablesCleanup(ctxt); 6183 xmlResetError(&ctxt->lastError); 6184 xmlFree(ctxt); 6185 } 6186 6187 /************************************************************************ 6188 * * 6189 * Routines to handle XPath parser contexts * 6190 * * 6191 ************************************************************************/ 6192 6193 #define CHECK_CTXT(ctxt) \ 6194 if (ctxt == NULL) { \ 6195 __xmlRaiseError(NULL, NULL, NULL, \ 6196 NULL, NULL, XML_FROM_XPATH, \ 6197 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \ 6198 __FILE__, __LINE__, \ 6199 NULL, NULL, NULL, 0, 0, \ 6200 "NULL context pointer\n"); \ 6201 return(NULL); \ 6202 } \ 6203 6204 #define CHECK_CTXT_NEG(ctxt) \ 6205 if (ctxt == NULL) { \ 6206 __xmlRaiseError(NULL, NULL, NULL, \ 6207 NULL, NULL, XML_FROM_XPATH, \ 6208 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \ 6209 __FILE__, __LINE__, \ 6210 NULL, NULL, NULL, 0, 0, \ 6211 "NULL context pointer\n"); \ 6212 return(-1); \ 6213 } \ 6214 6215 6216 #define CHECK_CONTEXT(ctxt) \ 6217 if ((ctxt == NULL) || (ctxt->doc == NULL) || \ 6218 (ctxt->doc->children == NULL)) { \ 6219 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \ 6220 return(NULL); \ 6221 } 6222 6223 6224 /** 6225 * xmlXPathNewParserContext: 6226 * @str: the XPath expression 6227 * @ctxt: the XPath context 6228 * 6229 * Create a new xmlXPathParserContext 6230 * 6231 * Returns the xmlXPathParserContext just allocated. 6232 */ 6233 xmlXPathParserContextPtr 6234 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) { 6235 xmlXPathParserContextPtr ret; 6236 6237 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext)); 6238 if (ret == NULL) { 6239 xmlXPathErrMemory(ctxt, "creating parser context\n"); 6240 return(NULL); 6241 } 6242 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext)); 6243 ret->cur = ret->base = str; 6244 ret->context = ctxt; 6245 6246 ret->comp = xmlXPathNewCompExpr(); 6247 if (ret->comp == NULL) { 6248 xmlFree(ret->valueTab); 6249 xmlFree(ret); 6250 return(NULL); 6251 } 6252 if ((ctxt != NULL) && (ctxt->dict != NULL)) { 6253 ret->comp->dict = ctxt->dict; 6254 xmlDictReference(ret->comp->dict); 6255 } 6256 6257 return(ret); 6258 } 6259 6260 /** 6261 * xmlXPathCompParserContext: 6262 * @comp: the XPath compiled expression 6263 * @ctxt: the XPath context 6264 * 6265 * Create a new xmlXPathParserContext when processing a compiled expression 6266 * 6267 * Returns the xmlXPathParserContext just allocated. 6268 */ 6269 static xmlXPathParserContextPtr 6270 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) { 6271 xmlXPathParserContextPtr ret; 6272 6273 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext)); 6274 if (ret == NULL) { 6275 xmlXPathErrMemory(ctxt, "creating evaluation context\n"); 6276 return(NULL); 6277 } 6278 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext)); 6279 6280 /* Allocate the value stack */ 6281 ret->valueTab = (xmlXPathObjectPtr *) 6282 xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); 6283 if (ret->valueTab == NULL) { 6284 xmlFree(ret); 6285 xmlXPathErrMemory(ctxt, "creating evaluation context\n"); 6286 return(NULL); 6287 } 6288 ret->valueNr = 0; 6289 ret->valueMax = 10; 6290 ret->value = NULL; 6291 ret->valueFrame = 0; 6292 6293 ret->context = ctxt; 6294 ret->comp = comp; 6295 6296 return(ret); 6297 } 6298 6299 /** 6300 * xmlXPathFreeParserContext: 6301 * @ctxt: the context to free 6302 * 6303 * Free up an xmlXPathParserContext 6304 */ 6305 void 6306 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) { 6307 int i; 6308 6309 if (ctxt->valueTab != NULL) { 6310 for (i = 0; i < ctxt->valueNr; i++) { 6311 if (ctxt->context) 6312 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]); 6313 else 6314 xmlXPathFreeObject(ctxt->valueTab[i]); 6315 } 6316 xmlFree(ctxt->valueTab); 6317 } 6318 if (ctxt->comp != NULL) { 6319 #ifdef XPATH_STREAMING 6320 if (ctxt->comp->stream != NULL) { 6321 xmlFreePatternList(ctxt->comp->stream); 6322 ctxt->comp->stream = NULL; 6323 } 6324 #endif 6325 xmlXPathFreeCompExpr(ctxt->comp); 6326 } 6327 xmlFree(ctxt); 6328 } 6329 6330 /************************************************************************ 6331 * * 6332 * The implicit core function library * 6333 * * 6334 ************************************************************************/ 6335 6336 /** 6337 * xmlXPathNodeValHash: 6338 * @node: a node pointer 6339 * 6340 * Function computing the beginning of the string value of the node, 6341 * used to speed up comparisons 6342 * 6343 * Returns an int usable as a hash 6344 */ 6345 static unsigned int 6346 xmlXPathNodeValHash(xmlNodePtr node) { 6347 int len = 2; 6348 const xmlChar * string = NULL; 6349 xmlNodePtr tmp = NULL; 6350 unsigned int ret = 0; 6351 6352 if (node == NULL) 6353 return(0); 6354 6355 if (node->type == XML_DOCUMENT_NODE) { 6356 tmp = xmlDocGetRootElement((xmlDocPtr) node); 6357 if (tmp == NULL) 6358 node = node->children; 6359 else 6360 node = tmp; 6361 6362 if (node == NULL) 6363 return(0); 6364 } 6365 6366 switch (node->type) { 6367 case XML_COMMENT_NODE: 6368 case XML_PI_NODE: 6369 case XML_CDATA_SECTION_NODE: 6370 case XML_TEXT_NODE: 6371 string = node->content; 6372 if (string == NULL) 6373 return(0); 6374 if (string[0] == 0) 6375 return(0); 6376 return(((unsigned int) string[0]) + 6377 (((unsigned int) string[1]) << 8)); 6378 case XML_NAMESPACE_DECL: 6379 string = ((xmlNsPtr)node)->href; 6380 if (string == NULL) 6381 return(0); 6382 if (string[0] == 0) 6383 return(0); 6384 return(((unsigned int) string[0]) + 6385 (((unsigned int) string[1]) << 8)); 6386 case XML_ATTRIBUTE_NODE: 6387 tmp = ((xmlAttrPtr) node)->children; 6388 break; 6389 case XML_ELEMENT_NODE: 6390 tmp = node->children; 6391 break; 6392 default: 6393 return(0); 6394 } 6395 while (tmp != NULL) { 6396 switch (tmp->type) { 6397 case XML_CDATA_SECTION_NODE: 6398 case XML_TEXT_NODE: 6399 string = tmp->content; 6400 break; 6401 default: 6402 string = NULL; 6403 break; 6404 } 6405 if ((string != NULL) && (string[0] != 0)) { 6406 if (len == 1) { 6407 return(ret + (((unsigned int) string[0]) << 8)); 6408 } 6409 if (string[1] == 0) { 6410 len = 1; 6411 ret = (unsigned int) string[0]; 6412 } else { 6413 return(((unsigned int) string[0]) + 6414 (((unsigned int) string[1]) << 8)); 6415 } 6416 } 6417 /* 6418 * Skip to next node 6419 */ 6420 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) { 6421 if (tmp->children->type != XML_ENTITY_DECL) { 6422 tmp = tmp->children; 6423 continue; 6424 } 6425 } 6426 if (tmp == node) 6427 break; 6428 6429 if (tmp->next != NULL) { 6430 tmp = tmp->next; 6431 continue; 6432 } 6433 6434 do { 6435 tmp = tmp->parent; 6436 if (tmp == NULL) 6437 break; 6438 if (tmp == node) { 6439 tmp = NULL; 6440 break; 6441 } 6442 if (tmp->next != NULL) { 6443 tmp = tmp->next; 6444 break; 6445 } 6446 } while (tmp != NULL); 6447 } 6448 return(ret); 6449 } 6450 6451 /** 6452 * xmlXPathStringHash: 6453 * @string: a string 6454 * 6455 * Function computing the beginning of the string value of the node, 6456 * used to speed up comparisons 6457 * 6458 * Returns an int usable as a hash 6459 */ 6460 static unsigned int 6461 xmlXPathStringHash(const xmlChar * string) { 6462 if (string == NULL) 6463 return((unsigned int) 0); 6464 if (string[0] == 0) 6465 return(0); 6466 return(((unsigned int) string[0]) + 6467 (((unsigned int) string[1]) << 8)); 6468 } 6469 6470 /** 6471 * xmlXPathCompareNodeSetFloat: 6472 * @ctxt: the XPath Parser context 6473 * @inf: less than (1) or greater than (0) 6474 * @strict: is the comparison strict 6475 * @arg: the node set 6476 * @f: the value 6477 * 6478 * Implement the compare operation between a nodeset and a number 6479 * @ns < @val (1, 1, ... 6480 * @ns <= @val (1, 0, ... 6481 * @ns > @val (0, 1, ... 6482 * @ns >= @val (0, 0, ... 6483 * 6484 * If one object to be compared is a node-set and the other is a number, 6485 * then the comparison will be true if and only if there is a node in the 6486 * node-set such that the result of performing the comparison on the number 6487 * to be compared and on the result of converting the string-value of that 6488 * node to a number using the number function is true. 6489 * 6490 * Returns 0 or 1 depending on the results of the test. 6491 */ 6492 static int 6493 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict, 6494 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) { 6495 int i, ret = 0; 6496 xmlNodeSetPtr ns; 6497 xmlChar *str2; 6498 6499 if ((f == NULL) || (arg == NULL) || 6500 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) { 6501 xmlXPathReleaseObject(ctxt->context, arg); 6502 xmlXPathReleaseObject(ctxt->context, f); 6503 return(0); 6504 } 6505 ns = arg->nodesetval; 6506 if (ns != NULL) { 6507 for (i = 0;i < ns->nodeNr;i++) { 6508 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 6509 if (str2 != NULL) { 6510 valuePush(ctxt, 6511 xmlXPathCacheNewString(ctxt->context, str2)); 6512 xmlFree(str2); 6513 xmlXPathNumberFunction(ctxt, 1); 6514 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f)); 6515 ret = xmlXPathCompareValues(ctxt, inf, strict); 6516 if (ret) 6517 break; 6518 } 6519 } 6520 } 6521 xmlXPathReleaseObject(ctxt->context, arg); 6522 xmlXPathReleaseObject(ctxt->context, f); 6523 return(ret); 6524 } 6525 6526 /** 6527 * xmlXPathCompareNodeSetString: 6528 * @ctxt: the XPath Parser context 6529 * @inf: less than (1) or greater than (0) 6530 * @strict: is the comparison strict 6531 * @arg: the node set 6532 * @s: the value 6533 * 6534 * Implement the compare operation between a nodeset and a string 6535 * @ns < @val (1, 1, ... 6536 * @ns <= @val (1, 0, ... 6537 * @ns > @val (0, 1, ... 6538 * @ns >= @val (0, 0, ... 6539 * 6540 * If one object to be compared is a node-set and the other is a string, 6541 * then the comparison will be true if and only if there is a node in 6542 * the node-set such that the result of performing the comparison on the 6543 * string-value of the node and the other string is true. 6544 * 6545 * Returns 0 or 1 depending on the results of the test. 6546 */ 6547 static int 6548 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict, 6549 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) { 6550 int i, ret = 0; 6551 xmlNodeSetPtr ns; 6552 xmlChar *str2; 6553 6554 if ((s == NULL) || (arg == NULL) || 6555 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) { 6556 xmlXPathReleaseObject(ctxt->context, arg); 6557 xmlXPathReleaseObject(ctxt->context, s); 6558 return(0); 6559 } 6560 ns = arg->nodesetval; 6561 if (ns != NULL) { 6562 for (i = 0;i < ns->nodeNr;i++) { 6563 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 6564 if (str2 != NULL) { 6565 valuePush(ctxt, 6566 xmlXPathCacheNewString(ctxt->context, str2)); 6567 xmlFree(str2); 6568 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s)); 6569 ret = xmlXPathCompareValues(ctxt, inf, strict); 6570 if (ret) 6571 break; 6572 } 6573 } 6574 } 6575 xmlXPathReleaseObject(ctxt->context, arg); 6576 xmlXPathReleaseObject(ctxt->context, s); 6577 return(ret); 6578 } 6579 6580 /** 6581 * xmlXPathCompareNodeSets: 6582 * @inf: less than (1) or greater than (0) 6583 * @strict: is the comparison strict 6584 * @arg1: the first node set object 6585 * @arg2: the second node set object 6586 * 6587 * Implement the compare operation on nodesets: 6588 * 6589 * If both objects to be compared are node-sets, then the comparison 6590 * will be true if and only if there is a node in the first node-set 6591 * and a node in the second node-set such that the result of performing 6592 * the comparison on the string-values of the two nodes is true. 6593 * .... 6594 * When neither object to be compared is a node-set and the operator 6595 * is <=, <, >= or >, then the objects are compared by converting both 6596 * objects to numbers and comparing the numbers according to IEEE 754. 6597 * .... 6598 * The number function converts its argument to a number as follows: 6599 * - a string that consists of optional whitespace followed by an 6600 * optional minus sign followed by a Number followed by whitespace 6601 * is converted to the IEEE 754 number that is nearest (according 6602 * to the IEEE 754 round-to-nearest rule) to the mathematical value 6603 * represented by the string; any other string is converted to NaN 6604 * 6605 * Conclusion all nodes need to be converted first to their string value 6606 * and then the comparison must be done when possible 6607 */ 6608 static int 6609 xmlXPathCompareNodeSets(int inf, int strict, 6610 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) { 6611 int i, j, init = 0; 6612 double val1; 6613 double *values2; 6614 int ret = 0; 6615 xmlNodeSetPtr ns1; 6616 xmlNodeSetPtr ns2; 6617 6618 if ((arg1 == NULL) || 6619 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) { 6620 xmlXPathFreeObject(arg2); 6621 return(0); 6622 } 6623 if ((arg2 == NULL) || 6624 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) { 6625 xmlXPathFreeObject(arg1); 6626 xmlXPathFreeObject(arg2); 6627 return(0); 6628 } 6629 6630 ns1 = arg1->nodesetval; 6631 ns2 = arg2->nodesetval; 6632 6633 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) { 6634 xmlXPathFreeObject(arg1); 6635 xmlXPathFreeObject(arg2); 6636 return(0); 6637 } 6638 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) { 6639 xmlXPathFreeObject(arg1); 6640 xmlXPathFreeObject(arg2); 6641 return(0); 6642 } 6643 6644 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double)); 6645 if (values2 == NULL) { 6646 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6647 xmlXPathFreeObject(arg1); 6648 xmlXPathFreeObject(arg2); 6649 return(0); 6650 } 6651 for (i = 0;i < ns1->nodeNr;i++) { 6652 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]); 6653 if (xmlXPathIsNaN(val1)) 6654 continue; 6655 for (j = 0;j < ns2->nodeNr;j++) { 6656 if (init == 0) { 6657 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]); 6658 } 6659 if (xmlXPathIsNaN(values2[j])) 6660 continue; 6661 if (inf && strict) 6662 ret = (val1 < values2[j]); 6663 else if (inf && !strict) 6664 ret = (val1 <= values2[j]); 6665 else if (!inf && strict) 6666 ret = (val1 > values2[j]); 6667 else if (!inf && !strict) 6668 ret = (val1 >= values2[j]); 6669 if (ret) 6670 break; 6671 } 6672 if (ret) 6673 break; 6674 init = 1; 6675 } 6676 xmlFree(values2); 6677 xmlXPathFreeObject(arg1); 6678 xmlXPathFreeObject(arg2); 6679 return(ret); 6680 } 6681 6682 /** 6683 * xmlXPathCompareNodeSetValue: 6684 * @ctxt: the XPath Parser context 6685 * @inf: less than (1) or greater than (0) 6686 * @strict: is the comparison strict 6687 * @arg: the node set 6688 * @val: the value 6689 * 6690 * Implement the compare operation between a nodeset and a value 6691 * @ns < @val (1, 1, ... 6692 * @ns <= @val (1, 0, ... 6693 * @ns > @val (0, 1, ... 6694 * @ns >= @val (0, 0, ... 6695 * 6696 * If one object to be compared is a node-set and the other is a boolean, 6697 * then the comparison will be true if and only if the result of performing 6698 * the comparison on the boolean and on the result of converting 6699 * the node-set to a boolean using the boolean function is true. 6700 * 6701 * Returns 0 or 1 depending on the results of the test. 6702 */ 6703 static int 6704 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict, 6705 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) { 6706 if ((val == NULL) || (arg == NULL) || 6707 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 6708 return(0); 6709 6710 switch(val->type) { 6711 case XPATH_NUMBER: 6712 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val)); 6713 case XPATH_NODESET: 6714 case XPATH_XSLT_TREE: 6715 return(xmlXPathCompareNodeSets(inf, strict, arg, val)); 6716 case XPATH_STRING: 6717 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val)); 6718 case XPATH_BOOLEAN: 6719 valuePush(ctxt, arg); 6720 xmlXPathBooleanFunction(ctxt, 1); 6721 valuePush(ctxt, val); 6722 return(xmlXPathCompareValues(ctxt, inf, strict)); 6723 default: 6724 xmlGenericError(xmlGenericErrorContext, 6725 "xmlXPathCompareNodeSetValue: Can't compare node set " 6726 "and object of type %d\n", 6727 val->type); 6728 xmlXPathReleaseObject(ctxt->context, arg); 6729 xmlXPathReleaseObject(ctxt->context, val); 6730 XP_ERROR0(XPATH_INVALID_TYPE); 6731 } 6732 return(0); 6733 } 6734 6735 /** 6736 * xmlXPathEqualNodeSetString: 6737 * @arg: the nodeset object argument 6738 * @str: the string to compare to. 6739 * @neq: flag to show whether for '=' (0) or '!=' (1) 6740 * 6741 * Implement the equal operation on XPath objects content: @arg1 == @arg2 6742 * If one object to be compared is a node-set and the other is a string, 6743 * then the comparison will be true if and only if there is a node in 6744 * the node-set such that the result of performing the comparison on the 6745 * string-value of the node and the other string is true. 6746 * 6747 * Returns 0 or 1 depending on the results of the test. 6748 */ 6749 static int 6750 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq) 6751 { 6752 int i; 6753 xmlNodeSetPtr ns; 6754 xmlChar *str2; 6755 unsigned int hash; 6756 6757 if ((str == NULL) || (arg == NULL) || 6758 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 6759 return (0); 6760 ns = arg->nodesetval; 6761 /* 6762 * A NULL nodeset compared with a string is always false 6763 * (since there is no node equal, and no node not equal) 6764 */ 6765 if ((ns == NULL) || (ns->nodeNr <= 0) ) 6766 return (0); 6767 hash = xmlXPathStringHash(str); 6768 for (i = 0; i < ns->nodeNr; i++) { 6769 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) { 6770 str2 = xmlNodeGetContent(ns->nodeTab[i]); 6771 if ((str2 != NULL) && (xmlStrEqual(str, str2))) { 6772 xmlFree(str2); 6773 if (neq) 6774 continue; 6775 return (1); 6776 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) { 6777 if (neq) 6778 continue; 6779 return (1); 6780 } else if (neq) { 6781 if (str2 != NULL) 6782 xmlFree(str2); 6783 return (1); 6784 } 6785 if (str2 != NULL) 6786 xmlFree(str2); 6787 } else if (neq) 6788 return (1); 6789 } 6790 return (0); 6791 } 6792 6793 /** 6794 * xmlXPathEqualNodeSetFloat: 6795 * @arg: the nodeset object argument 6796 * @f: the float to compare to 6797 * @neq: flag to show whether to compare '=' (0) or '!=' (1) 6798 * 6799 * Implement the equal operation on XPath objects content: @arg1 == @arg2 6800 * If one object to be compared is a node-set and the other is a number, 6801 * then the comparison will be true if and only if there is a node in 6802 * the node-set such that the result of performing the comparison on the 6803 * number to be compared and on the result of converting the string-value 6804 * of that node to a number using the number function is true. 6805 * 6806 * Returns 0 or 1 depending on the results of the test. 6807 */ 6808 static int 6809 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt, 6810 xmlXPathObjectPtr arg, double f, int neq) { 6811 int i, ret=0; 6812 xmlNodeSetPtr ns; 6813 xmlChar *str2; 6814 xmlXPathObjectPtr val; 6815 double v; 6816 6817 if ((arg == NULL) || 6818 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 6819 return(0); 6820 6821 ns = arg->nodesetval; 6822 if (ns != NULL) { 6823 for (i=0;i<ns->nodeNr;i++) { 6824 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 6825 if (str2 != NULL) { 6826 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2)); 6827 xmlFree(str2); 6828 xmlXPathNumberFunction(ctxt, 1); 6829 val = valuePop(ctxt); 6830 v = val->floatval; 6831 xmlXPathReleaseObject(ctxt->context, val); 6832 if (!xmlXPathIsNaN(v)) { 6833 if ((!neq) && (v==f)) { 6834 ret = 1; 6835 break; 6836 } else if ((neq) && (v!=f)) { 6837 ret = 1; 6838 break; 6839 } 6840 } else { /* NaN is unequal to any value */ 6841 if (neq) 6842 ret = 1; 6843 } 6844 } 6845 } 6846 } 6847 6848 return(ret); 6849 } 6850 6851 6852 /** 6853 * xmlXPathEqualNodeSets: 6854 * @arg1: first nodeset object argument 6855 * @arg2: second nodeset object argument 6856 * @neq: flag to show whether to test '=' (0) or '!=' (1) 6857 * 6858 * Implement the equal / not equal operation on XPath nodesets: 6859 * @arg1 == @arg2 or @arg1 != @arg2 6860 * If both objects to be compared are node-sets, then the comparison 6861 * will be true if and only if there is a node in the first node-set and 6862 * a node in the second node-set such that the result of performing the 6863 * comparison on the string-values of the two nodes is true. 6864 * 6865 * (needless to say, this is a costly operation) 6866 * 6867 * Returns 0 or 1 depending on the results of the test. 6868 */ 6869 static int 6870 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) { 6871 int i, j; 6872 unsigned int *hashs1; 6873 unsigned int *hashs2; 6874 xmlChar **values1; 6875 xmlChar **values2; 6876 int ret = 0; 6877 xmlNodeSetPtr ns1; 6878 xmlNodeSetPtr ns2; 6879 6880 if ((arg1 == NULL) || 6881 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) 6882 return(0); 6883 if ((arg2 == NULL) || 6884 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) 6885 return(0); 6886 6887 ns1 = arg1->nodesetval; 6888 ns2 = arg2->nodesetval; 6889 6890 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) 6891 return(0); 6892 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) 6893 return(0); 6894 6895 /* 6896 * for equal, check if there is a node pertaining to both sets 6897 */ 6898 if (neq == 0) 6899 for (i = 0;i < ns1->nodeNr;i++) 6900 for (j = 0;j < ns2->nodeNr;j++) 6901 if (ns1->nodeTab[i] == ns2->nodeTab[j]) 6902 return(1); 6903 6904 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *)); 6905 if (values1 == NULL) { 6906 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6907 return(0); 6908 } 6909 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int)); 6910 if (hashs1 == NULL) { 6911 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6912 xmlFree(values1); 6913 return(0); 6914 } 6915 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *)); 6916 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *)); 6917 if (values2 == NULL) { 6918 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6919 xmlFree(hashs1); 6920 xmlFree(values1); 6921 return(0); 6922 } 6923 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int)); 6924 if (hashs2 == NULL) { 6925 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6926 xmlFree(hashs1); 6927 xmlFree(values1); 6928 xmlFree(values2); 6929 return(0); 6930 } 6931 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *)); 6932 for (i = 0;i < ns1->nodeNr;i++) { 6933 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]); 6934 for (j = 0;j < ns2->nodeNr;j++) { 6935 if (i == 0) 6936 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]); 6937 if (hashs1[i] != hashs2[j]) { 6938 if (neq) { 6939 ret = 1; 6940 break; 6941 } 6942 } 6943 else { 6944 if (values1[i] == NULL) 6945 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]); 6946 if (values2[j] == NULL) 6947 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]); 6948 ret = xmlStrEqual(values1[i], values2[j]) ^ neq; 6949 if (ret) 6950 break; 6951 } 6952 } 6953 if (ret) 6954 break; 6955 } 6956 for (i = 0;i < ns1->nodeNr;i++) 6957 if (values1[i] != NULL) 6958 xmlFree(values1[i]); 6959 for (j = 0;j < ns2->nodeNr;j++) 6960 if (values2[j] != NULL) 6961 xmlFree(values2[j]); 6962 xmlFree(values1); 6963 xmlFree(values2); 6964 xmlFree(hashs1); 6965 xmlFree(hashs2); 6966 return(ret); 6967 } 6968 6969 static int 6970 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt, 6971 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) { 6972 int ret = 0; 6973 /* 6974 *At this point we are assured neither arg1 nor arg2 6975 *is a nodeset, so we can just pick the appropriate routine. 6976 */ 6977 switch (arg1->type) { 6978 case XPATH_UNDEFINED: 6979 #ifdef DEBUG_EXPR 6980 xmlGenericError(xmlGenericErrorContext, 6981 "Equal: undefined\n"); 6982 #endif 6983 break; 6984 case XPATH_BOOLEAN: 6985 switch (arg2->type) { 6986 case XPATH_UNDEFINED: 6987 #ifdef DEBUG_EXPR 6988 xmlGenericError(xmlGenericErrorContext, 6989 "Equal: undefined\n"); 6990 #endif 6991 break; 6992 case XPATH_BOOLEAN: 6993 #ifdef DEBUG_EXPR 6994 xmlGenericError(xmlGenericErrorContext, 6995 "Equal: %d boolean %d \n", 6996 arg1->boolval, arg2->boolval); 6997 #endif 6998 ret = (arg1->boolval == arg2->boolval); 6999 break; 7000 case XPATH_NUMBER: 7001 ret = (arg1->boolval == 7002 xmlXPathCastNumberToBoolean(arg2->floatval)); 7003 break; 7004 case XPATH_STRING: 7005 if ((arg2->stringval == NULL) || 7006 (arg2->stringval[0] == 0)) ret = 0; 7007 else 7008 ret = 1; 7009 ret = (arg1->boolval == ret); 7010 break; 7011 case XPATH_USERS: 7012 case XPATH_POINT: 7013 case XPATH_RANGE: 7014 case XPATH_LOCATIONSET: 7015 TODO 7016 break; 7017 case XPATH_NODESET: 7018 case XPATH_XSLT_TREE: 7019 break; 7020 } 7021 break; 7022 case XPATH_NUMBER: 7023 switch (arg2->type) { 7024 case XPATH_UNDEFINED: 7025 #ifdef DEBUG_EXPR 7026 xmlGenericError(xmlGenericErrorContext, 7027 "Equal: undefined\n"); 7028 #endif 7029 break; 7030 case XPATH_BOOLEAN: 7031 ret = (arg2->boolval== 7032 xmlXPathCastNumberToBoolean(arg1->floatval)); 7033 break; 7034 case XPATH_STRING: 7035 valuePush(ctxt, arg2); 7036 xmlXPathNumberFunction(ctxt, 1); 7037 arg2 = valuePop(ctxt); 7038 /* Falls through. */ 7039 case XPATH_NUMBER: 7040 /* Hand check NaN and Infinity equalities */ 7041 if (xmlXPathIsNaN(arg1->floatval) || 7042 xmlXPathIsNaN(arg2->floatval)) { 7043 ret = 0; 7044 } else if (xmlXPathIsInf(arg1->floatval) == 1) { 7045 if (xmlXPathIsInf(arg2->floatval) == 1) 7046 ret = 1; 7047 else 7048 ret = 0; 7049 } else if (xmlXPathIsInf(arg1->floatval) == -1) { 7050 if (xmlXPathIsInf(arg2->floatval) == -1) 7051 ret = 1; 7052 else 7053 ret = 0; 7054 } else if (xmlXPathIsInf(arg2->floatval) == 1) { 7055 if (xmlXPathIsInf(arg1->floatval) == 1) 7056 ret = 1; 7057 else 7058 ret = 0; 7059 } else if (xmlXPathIsInf(arg2->floatval) == -1) { 7060 if (xmlXPathIsInf(arg1->floatval) == -1) 7061 ret = 1; 7062 else 7063 ret = 0; 7064 } else { 7065 ret = (arg1->floatval == arg2->floatval); 7066 } 7067 break; 7068 case XPATH_USERS: 7069 case XPATH_POINT: 7070 case XPATH_RANGE: 7071 case XPATH_LOCATIONSET: 7072 TODO 7073 break; 7074 case XPATH_NODESET: 7075 case XPATH_XSLT_TREE: 7076 break; 7077 } 7078 break; 7079 case XPATH_STRING: 7080 switch (arg2->type) { 7081 case XPATH_UNDEFINED: 7082 #ifdef DEBUG_EXPR 7083 xmlGenericError(xmlGenericErrorContext, 7084 "Equal: undefined\n"); 7085 #endif 7086 break; 7087 case XPATH_BOOLEAN: 7088 if ((arg1->stringval == NULL) || 7089 (arg1->stringval[0] == 0)) ret = 0; 7090 else 7091 ret = 1; 7092 ret = (arg2->boolval == ret); 7093 break; 7094 case XPATH_STRING: 7095 ret = xmlStrEqual(arg1->stringval, arg2->stringval); 7096 break; 7097 case XPATH_NUMBER: 7098 valuePush(ctxt, arg1); 7099 xmlXPathNumberFunction(ctxt, 1); 7100 arg1 = valuePop(ctxt); 7101 /* Hand check NaN and Infinity equalities */ 7102 if (xmlXPathIsNaN(arg1->floatval) || 7103 xmlXPathIsNaN(arg2->floatval)) { 7104 ret = 0; 7105 } else if (xmlXPathIsInf(arg1->floatval) == 1) { 7106 if (xmlXPathIsInf(arg2->floatval) == 1) 7107 ret = 1; 7108 else 7109 ret = 0; 7110 } else if (xmlXPathIsInf(arg1->floatval) == -1) { 7111 if (xmlXPathIsInf(arg2->floatval) == -1) 7112 ret = 1; 7113 else 7114 ret = 0; 7115 } else if (xmlXPathIsInf(arg2->floatval) == 1) { 7116 if (xmlXPathIsInf(arg1->floatval) == 1) 7117 ret = 1; 7118 else 7119 ret = 0; 7120 } else if (xmlXPathIsInf(arg2->floatval) == -1) { 7121 if (xmlXPathIsInf(arg1->floatval) == -1) 7122 ret = 1; 7123 else 7124 ret = 0; 7125 } else { 7126 ret = (arg1->floatval == arg2->floatval); 7127 } 7128 break; 7129 case XPATH_USERS: 7130 case XPATH_POINT: 7131 case XPATH_RANGE: 7132 case XPATH_LOCATIONSET: 7133 TODO 7134 break; 7135 case XPATH_NODESET: 7136 case XPATH_XSLT_TREE: 7137 break; 7138 } 7139 break; 7140 case XPATH_USERS: 7141 case XPATH_POINT: 7142 case XPATH_RANGE: 7143 case XPATH_LOCATIONSET: 7144 TODO 7145 break; 7146 case XPATH_NODESET: 7147 case XPATH_XSLT_TREE: 7148 break; 7149 } 7150 xmlXPathReleaseObject(ctxt->context, arg1); 7151 xmlXPathReleaseObject(ctxt->context, arg2); 7152 return(ret); 7153 } 7154 7155 /** 7156 * xmlXPathEqualValues: 7157 * @ctxt: the XPath Parser context 7158 * 7159 * Implement the equal operation on XPath objects content: @arg1 == @arg2 7160 * 7161 * Returns 0 or 1 depending on the results of the test. 7162 */ 7163 int 7164 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) { 7165 xmlXPathObjectPtr arg1, arg2, argtmp; 7166 int ret = 0; 7167 7168 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); 7169 arg2 = valuePop(ctxt); 7170 arg1 = valuePop(ctxt); 7171 if ((arg1 == NULL) || (arg2 == NULL)) { 7172 if (arg1 != NULL) 7173 xmlXPathReleaseObject(ctxt->context, arg1); 7174 else 7175 xmlXPathReleaseObject(ctxt->context, arg2); 7176 XP_ERROR0(XPATH_INVALID_OPERAND); 7177 } 7178 7179 if (arg1 == arg2) { 7180 #ifdef DEBUG_EXPR 7181 xmlGenericError(xmlGenericErrorContext, 7182 "Equal: by pointer\n"); 7183 #endif 7184 xmlXPathFreeObject(arg1); 7185 return(1); 7186 } 7187 7188 /* 7189 *If either argument is a nodeset, it's a 'special case' 7190 */ 7191 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 7192 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7193 /* 7194 *Hack it to assure arg1 is the nodeset 7195 */ 7196 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) { 7197 argtmp = arg2; 7198 arg2 = arg1; 7199 arg1 = argtmp; 7200 } 7201 switch (arg2->type) { 7202 case XPATH_UNDEFINED: 7203 #ifdef DEBUG_EXPR 7204 xmlGenericError(xmlGenericErrorContext, 7205 "Equal: undefined\n"); 7206 #endif 7207 break; 7208 case XPATH_NODESET: 7209 case XPATH_XSLT_TREE: 7210 ret = xmlXPathEqualNodeSets(arg1, arg2, 0); 7211 break; 7212 case XPATH_BOOLEAN: 7213 if ((arg1->nodesetval == NULL) || 7214 (arg1->nodesetval->nodeNr == 0)) ret = 0; 7215 else 7216 ret = 1; 7217 ret = (ret == arg2->boolval); 7218 break; 7219 case XPATH_NUMBER: 7220 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0); 7221 break; 7222 case XPATH_STRING: 7223 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0); 7224 break; 7225 case XPATH_USERS: 7226 case XPATH_POINT: 7227 case XPATH_RANGE: 7228 case XPATH_LOCATIONSET: 7229 TODO 7230 break; 7231 } 7232 xmlXPathReleaseObject(ctxt->context, arg1); 7233 xmlXPathReleaseObject(ctxt->context, arg2); 7234 return(ret); 7235 } 7236 7237 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2)); 7238 } 7239 7240 /** 7241 * xmlXPathNotEqualValues: 7242 * @ctxt: the XPath Parser context 7243 * 7244 * Implement the equal operation on XPath objects content: @arg1 == @arg2 7245 * 7246 * Returns 0 or 1 depending on the results of the test. 7247 */ 7248 int 7249 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) { 7250 xmlXPathObjectPtr arg1, arg2, argtmp; 7251 int ret = 0; 7252 7253 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); 7254 arg2 = valuePop(ctxt); 7255 arg1 = valuePop(ctxt); 7256 if ((arg1 == NULL) || (arg2 == NULL)) { 7257 if (arg1 != NULL) 7258 xmlXPathReleaseObject(ctxt->context, arg1); 7259 else 7260 xmlXPathReleaseObject(ctxt->context, arg2); 7261 XP_ERROR0(XPATH_INVALID_OPERAND); 7262 } 7263 7264 if (arg1 == arg2) { 7265 #ifdef DEBUG_EXPR 7266 xmlGenericError(xmlGenericErrorContext, 7267 "NotEqual: by pointer\n"); 7268 #endif 7269 xmlXPathReleaseObject(ctxt->context, arg1); 7270 return(0); 7271 } 7272 7273 /* 7274 *If either argument is a nodeset, it's a 'special case' 7275 */ 7276 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 7277 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7278 /* 7279 *Hack it to assure arg1 is the nodeset 7280 */ 7281 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) { 7282 argtmp = arg2; 7283 arg2 = arg1; 7284 arg1 = argtmp; 7285 } 7286 switch (arg2->type) { 7287 case XPATH_UNDEFINED: 7288 #ifdef DEBUG_EXPR 7289 xmlGenericError(xmlGenericErrorContext, 7290 "NotEqual: undefined\n"); 7291 #endif 7292 break; 7293 case XPATH_NODESET: 7294 case XPATH_XSLT_TREE: 7295 ret = xmlXPathEqualNodeSets(arg1, arg2, 1); 7296 break; 7297 case XPATH_BOOLEAN: 7298 if ((arg1->nodesetval == NULL) || 7299 (arg1->nodesetval->nodeNr == 0)) ret = 0; 7300 else 7301 ret = 1; 7302 ret = (ret != arg2->boolval); 7303 break; 7304 case XPATH_NUMBER: 7305 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1); 7306 break; 7307 case XPATH_STRING: 7308 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1); 7309 break; 7310 case XPATH_USERS: 7311 case XPATH_POINT: 7312 case XPATH_RANGE: 7313 case XPATH_LOCATIONSET: 7314 TODO 7315 break; 7316 } 7317 xmlXPathReleaseObject(ctxt->context, arg1); 7318 xmlXPathReleaseObject(ctxt->context, arg2); 7319 return(ret); 7320 } 7321 7322 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2)); 7323 } 7324 7325 /** 7326 * xmlXPathCompareValues: 7327 * @ctxt: the XPath Parser context 7328 * @inf: less than (1) or greater than (0) 7329 * @strict: is the comparison strict 7330 * 7331 * Implement the compare operation on XPath objects: 7332 * @arg1 < @arg2 (1, 1, ... 7333 * @arg1 <= @arg2 (1, 0, ... 7334 * @arg1 > @arg2 (0, 1, ... 7335 * @arg1 >= @arg2 (0, 0, ... 7336 * 7337 * When neither object to be compared is a node-set and the operator is 7338 * <=, <, >=, >, then the objects are compared by converted both objects 7339 * to numbers and comparing the numbers according to IEEE 754. The < 7340 * comparison will be true if and only if the first number is less than the 7341 * second number. The <= comparison will be true if and only if the first 7342 * number is less than or equal to the second number. The > comparison 7343 * will be true if and only if the first number is greater than the second 7344 * number. The >= comparison will be true if and only if the first number 7345 * is greater than or equal to the second number. 7346 * 7347 * Returns 1 if the comparison succeeded, 0 if it failed 7348 */ 7349 int 7350 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) { 7351 int ret = 0, arg1i = 0, arg2i = 0; 7352 xmlXPathObjectPtr arg1, arg2; 7353 7354 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); 7355 arg2 = valuePop(ctxt); 7356 arg1 = valuePop(ctxt); 7357 if ((arg1 == NULL) || (arg2 == NULL)) { 7358 if (arg1 != NULL) 7359 xmlXPathReleaseObject(ctxt->context, arg1); 7360 else 7361 xmlXPathReleaseObject(ctxt->context, arg2); 7362 XP_ERROR0(XPATH_INVALID_OPERAND); 7363 } 7364 7365 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 7366 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7367 /* 7368 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments 7369 * are not freed from within this routine; they will be freed from the 7370 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue 7371 */ 7372 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) && 7373 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){ 7374 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2); 7375 } else { 7376 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7377 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict, 7378 arg1, arg2); 7379 } else { 7380 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict, 7381 arg2, arg1); 7382 } 7383 } 7384 return(ret); 7385 } 7386 7387 if (arg1->type != XPATH_NUMBER) { 7388 valuePush(ctxt, arg1); 7389 xmlXPathNumberFunction(ctxt, 1); 7390 arg1 = valuePop(ctxt); 7391 } 7392 if (arg1->type != XPATH_NUMBER) { 7393 xmlXPathFreeObject(arg1); 7394 xmlXPathFreeObject(arg2); 7395 XP_ERROR0(XPATH_INVALID_OPERAND); 7396 } 7397 if (arg2->type != XPATH_NUMBER) { 7398 valuePush(ctxt, arg2); 7399 xmlXPathNumberFunction(ctxt, 1); 7400 arg2 = valuePop(ctxt); 7401 } 7402 if (arg2->type != XPATH_NUMBER) { 7403 xmlXPathReleaseObject(ctxt->context, arg1); 7404 xmlXPathReleaseObject(ctxt->context, arg2); 7405 XP_ERROR0(XPATH_INVALID_OPERAND); 7406 } 7407 /* 7408 * Add tests for infinity and nan 7409 * => feedback on 3.4 for Inf and NaN 7410 */ 7411 /* Hand check NaN and Infinity comparisons */ 7412 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) { 7413 ret=0; 7414 } else { 7415 arg1i=xmlXPathIsInf(arg1->floatval); 7416 arg2i=xmlXPathIsInf(arg2->floatval); 7417 if (inf && strict) { 7418 if ((arg1i == -1 && arg2i != -1) || 7419 (arg2i == 1 && arg1i != 1)) { 7420 ret = 1; 7421 } else if (arg1i == 0 && arg2i == 0) { 7422 ret = (arg1->floatval < arg2->floatval); 7423 } else { 7424 ret = 0; 7425 } 7426 } 7427 else if (inf && !strict) { 7428 if (arg1i == -1 || arg2i == 1) { 7429 ret = 1; 7430 } else if (arg1i == 0 && arg2i == 0) { 7431 ret = (arg1->floatval <= arg2->floatval); 7432 } else { 7433 ret = 0; 7434 } 7435 } 7436 else if (!inf && strict) { 7437 if ((arg1i == 1 && arg2i != 1) || 7438 (arg2i == -1 && arg1i != -1)) { 7439 ret = 1; 7440 } else if (arg1i == 0 && arg2i == 0) { 7441 ret = (arg1->floatval > arg2->floatval); 7442 } else { 7443 ret = 0; 7444 } 7445 } 7446 else if (!inf && !strict) { 7447 if (arg1i == 1 || arg2i == -1) { 7448 ret = 1; 7449 } else if (arg1i == 0 && arg2i == 0) { 7450 ret = (arg1->floatval >= arg2->floatval); 7451 } else { 7452 ret = 0; 7453 } 7454 } 7455 } 7456 xmlXPathReleaseObject(ctxt->context, arg1); 7457 xmlXPathReleaseObject(ctxt->context, arg2); 7458 return(ret); 7459 } 7460 7461 /** 7462 * xmlXPathValueFlipSign: 7463 * @ctxt: the XPath Parser context 7464 * 7465 * Implement the unary - operation on an XPath object 7466 * The numeric operators convert their operands to numbers as if 7467 * by calling the number function. 7468 */ 7469 void 7470 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) { 7471 if ((ctxt == NULL) || (ctxt->context == NULL)) return; 7472 CAST_TO_NUMBER; 7473 CHECK_TYPE(XPATH_NUMBER); 7474 ctxt->value->floatval = -ctxt->value->floatval; 7475 } 7476 7477 /** 7478 * xmlXPathAddValues: 7479 * @ctxt: the XPath Parser context 7480 * 7481 * Implement the add operation on XPath objects: 7482 * The numeric operators convert their operands to numbers as if 7483 * by calling the number function. 7484 */ 7485 void 7486 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) { 7487 xmlXPathObjectPtr arg; 7488 double val; 7489 7490 arg = valuePop(ctxt); 7491 if (arg == NULL) 7492 XP_ERROR(XPATH_INVALID_OPERAND); 7493 val = xmlXPathCastToNumber(arg); 7494 xmlXPathReleaseObject(ctxt->context, arg); 7495 CAST_TO_NUMBER; 7496 CHECK_TYPE(XPATH_NUMBER); 7497 ctxt->value->floatval += val; 7498 } 7499 7500 /** 7501 * xmlXPathSubValues: 7502 * @ctxt: the XPath Parser context 7503 * 7504 * Implement the subtraction operation on XPath objects: 7505 * The numeric operators convert their operands to numbers as if 7506 * by calling the number function. 7507 */ 7508 void 7509 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) { 7510 xmlXPathObjectPtr arg; 7511 double val; 7512 7513 arg = valuePop(ctxt); 7514 if (arg == NULL) 7515 XP_ERROR(XPATH_INVALID_OPERAND); 7516 val = xmlXPathCastToNumber(arg); 7517 xmlXPathReleaseObject(ctxt->context, arg); 7518 CAST_TO_NUMBER; 7519 CHECK_TYPE(XPATH_NUMBER); 7520 ctxt->value->floatval -= val; 7521 } 7522 7523 /** 7524 * xmlXPathMultValues: 7525 * @ctxt: the XPath Parser context 7526 * 7527 * Implement the multiply operation on XPath objects: 7528 * The numeric operators convert their operands to numbers as if 7529 * by calling the number function. 7530 */ 7531 void 7532 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) { 7533 xmlXPathObjectPtr arg; 7534 double val; 7535 7536 arg = valuePop(ctxt); 7537 if (arg == NULL) 7538 XP_ERROR(XPATH_INVALID_OPERAND); 7539 val = xmlXPathCastToNumber(arg); 7540 xmlXPathReleaseObject(ctxt->context, arg); 7541 CAST_TO_NUMBER; 7542 CHECK_TYPE(XPATH_NUMBER); 7543 ctxt->value->floatval *= val; 7544 } 7545 7546 /** 7547 * xmlXPathDivValues: 7548 * @ctxt: the XPath Parser context 7549 * 7550 * Implement the div operation on XPath objects @arg1 / @arg2: 7551 * The numeric operators convert their operands to numbers as if 7552 * by calling the number function. 7553 */ 7554 void 7555 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) { 7556 xmlXPathObjectPtr arg; 7557 double val; 7558 7559 arg = valuePop(ctxt); 7560 if (arg == NULL) 7561 XP_ERROR(XPATH_INVALID_OPERAND); 7562 val = xmlXPathCastToNumber(arg); 7563 xmlXPathReleaseObject(ctxt->context, arg); 7564 CAST_TO_NUMBER; 7565 CHECK_TYPE(XPATH_NUMBER); 7566 ctxt->value->floatval /= val; 7567 } 7568 7569 /** 7570 * xmlXPathModValues: 7571 * @ctxt: the XPath Parser context 7572 * 7573 * Implement the mod operation on XPath objects: @arg1 / @arg2 7574 * The numeric operators convert their operands to numbers as if 7575 * by calling the number function. 7576 */ 7577 void 7578 xmlXPathModValues(xmlXPathParserContextPtr ctxt) { 7579 xmlXPathObjectPtr arg; 7580 double arg1, arg2; 7581 7582 arg = valuePop(ctxt); 7583 if (arg == NULL) 7584 XP_ERROR(XPATH_INVALID_OPERAND); 7585 arg2 = xmlXPathCastToNumber(arg); 7586 xmlXPathReleaseObject(ctxt->context, arg); 7587 CAST_TO_NUMBER; 7588 CHECK_TYPE(XPATH_NUMBER); 7589 arg1 = ctxt->value->floatval; 7590 if (arg2 == 0) 7591 ctxt->value->floatval = NAN; 7592 else { 7593 ctxt->value->floatval = fmod(arg1, arg2); 7594 } 7595 } 7596 7597 /************************************************************************ 7598 * * 7599 * The traversal functions * 7600 * * 7601 ************************************************************************/ 7602 7603 /* 7604 * A traversal function enumerates nodes along an axis. 7605 * Initially it must be called with NULL, and it indicates 7606 * termination on the axis by returning NULL. 7607 */ 7608 typedef xmlNodePtr (*xmlXPathTraversalFunction) 7609 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur); 7610 7611 /* 7612 * xmlXPathTraversalFunctionExt: 7613 * A traversal function enumerates nodes along an axis. 7614 * Initially it must be called with NULL, and it indicates 7615 * termination on the axis by returning NULL. 7616 * The context node of the traversal is specified via @contextNode. 7617 */ 7618 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt) 7619 (xmlNodePtr cur, xmlNodePtr contextNode); 7620 7621 /* 7622 * xmlXPathNodeSetMergeFunction: 7623 * Used for merging node sets in xmlXPathCollectAndTest(). 7624 */ 7625 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction) 7626 (xmlNodeSetPtr, xmlNodeSetPtr, int); 7627 7628 7629 /** 7630 * xmlXPathNextSelf: 7631 * @ctxt: the XPath Parser context 7632 * @cur: the current node in the traversal 7633 * 7634 * Traversal function for the "self" direction 7635 * The self axis contains just the context node itself 7636 * 7637 * Returns the next element following that axis 7638 */ 7639 xmlNodePtr 7640 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7641 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7642 if (cur == NULL) 7643 return(ctxt->context->node); 7644 return(NULL); 7645 } 7646 7647 /** 7648 * xmlXPathNextChild: 7649 * @ctxt: the XPath Parser context 7650 * @cur: the current node in the traversal 7651 * 7652 * Traversal function for the "child" direction 7653 * The child axis contains the children of the context node in document order. 7654 * 7655 * Returns the next element following that axis 7656 */ 7657 xmlNodePtr 7658 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7659 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7660 if (cur == NULL) { 7661 if (ctxt->context->node == NULL) return(NULL); 7662 switch (ctxt->context->node->type) { 7663 case XML_ELEMENT_NODE: 7664 case XML_TEXT_NODE: 7665 case XML_CDATA_SECTION_NODE: 7666 case XML_ENTITY_REF_NODE: 7667 case XML_ENTITY_NODE: 7668 case XML_PI_NODE: 7669 case XML_COMMENT_NODE: 7670 case XML_NOTATION_NODE: 7671 case XML_DTD_NODE: 7672 return(ctxt->context->node->children); 7673 case XML_DOCUMENT_NODE: 7674 case XML_DOCUMENT_TYPE_NODE: 7675 case XML_DOCUMENT_FRAG_NODE: 7676 case XML_HTML_DOCUMENT_NODE: 7677 #ifdef LIBXML_DOCB_ENABLED 7678 case XML_DOCB_DOCUMENT_NODE: 7679 #endif 7680 return(((xmlDocPtr) ctxt->context->node)->children); 7681 case XML_ELEMENT_DECL: 7682 case XML_ATTRIBUTE_DECL: 7683 case XML_ENTITY_DECL: 7684 case XML_ATTRIBUTE_NODE: 7685 case XML_NAMESPACE_DECL: 7686 case XML_XINCLUDE_START: 7687 case XML_XINCLUDE_END: 7688 return(NULL); 7689 } 7690 return(NULL); 7691 } 7692 if ((cur->type == XML_DOCUMENT_NODE) || 7693 (cur->type == XML_HTML_DOCUMENT_NODE)) 7694 return(NULL); 7695 return(cur->next); 7696 } 7697 7698 /** 7699 * xmlXPathNextChildElement: 7700 * @ctxt: the XPath Parser context 7701 * @cur: the current node in the traversal 7702 * 7703 * Traversal function for the "child" direction and nodes of type element. 7704 * The child axis contains the children of the context node in document order. 7705 * 7706 * Returns the next element following that axis 7707 */ 7708 static xmlNodePtr 7709 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7710 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7711 if (cur == NULL) { 7712 cur = ctxt->context->node; 7713 if (cur == NULL) return(NULL); 7714 /* 7715 * Get the first element child. 7716 */ 7717 switch (cur->type) { 7718 case XML_ELEMENT_NODE: 7719 case XML_DOCUMENT_FRAG_NODE: 7720 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */ 7721 case XML_ENTITY_NODE: 7722 cur = cur->children; 7723 if (cur != NULL) { 7724 if (cur->type == XML_ELEMENT_NODE) 7725 return(cur); 7726 do { 7727 cur = cur->next; 7728 } while ((cur != NULL) && 7729 (cur->type != XML_ELEMENT_NODE)); 7730 return(cur); 7731 } 7732 return(NULL); 7733 case XML_DOCUMENT_NODE: 7734 case XML_HTML_DOCUMENT_NODE: 7735 #ifdef LIBXML_DOCB_ENABLED 7736 case XML_DOCB_DOCUMENT_NODE: 7737 #endif 7738 return(xmlDocGetRootElement((xmlDocPtr) cur)); 7739 default: 7740 return(NULL); 7741 } 7742 return(NULL); 7743 } 7744 /* 7745 * Get the next sibling element node. 7746 */ 7747 switch (cur->type) { 7748 case XML_ELEMENT_NODE: 7749 case XML_TEXT_NODE: 7750 case XML_ENTITY_REF_NODE: 7751 case XML_ENTITY_NODE: 7752 case XML_CDATA_SECTION_NODE: 7753 case XML_PI_NODE: 7754 case XML_COMMENT_NODE: 7755 case XML_XINCLUDE_END: 7756 break; 7757 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */ 7758 default: 7759 return(NULL); 7760 } 7761 if (cur->next != NULL) { 7762 if (cur->next->type == XML_ELEMENT_NODE) 7763 return(cur->next); 7764 cur = cur->next; 7765 do { 7766 cur = cur->next; 7767 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE)); 7768 return(cur); 7769 } 7770 return(NULL); 7771 } 7772 7773 #if 0 7774 /** 7775 * xmlXPathNextDescendantOrSelfElemParent: 7776 * @ctxt: the XPath Parser context 7777 * @cur: the current node in the traversal 7778 * 7779 * Traversal function for the "descendant-or-self" axis. 7780 * Additionally it returns only nodes which can be parents of 7781 * element nodes. 7782 * 7783 * 7784 * Returns the next element following that axis 7785 */ 7786 static xmlNodePtr 7787 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur, 7788 xmlNodePtr contextNode) 7789 { 7790 if (cur == NULL) { 7791 if (contextNode == NULL) 7792 return(NULL); 7793 switch (contextNode->type) { 7794 case XML_ELEMENT_NODE: 7795 case XML_XINCLUDE_START: 7796 case XML_DOCUMENT_FRAG_NODE: 7797 case XML_DOCUMENT_NODE: 7798 #ifdef LIBXML_DOCB_ENABLED 7799 case XML_DOCB_DOCUMENT_NODE: 7800 #endif 7801 case XML_HTML_DOCUMENT_NODE: 7802 return(contextNode); 7803 default: 7804 return(NULL); 7805 } 7806 return(NULL); 7807 } else { 7808 xmlNodePtr start = cur; 7809 7810 while (cur != NULL) { 7811 switch (cur->type) { 7812 case XML_ELEMENT_NODE: 7813 /* TODO: OK to have XInclude here? */ 7814 case XML_XINCLUDE_START: 7815 case XML_DOCUMENT_FRAG_NODE: 7816 if (cur != start) 7817 return(cur); 7818 if (cur->children != NULL) { 7819 cur = cur->children; 7820 continue; 7821 } 7822 break; 7823 /* Not sure if we need those here. */ 7824 case XML_DOCUMENT_NODE: 7825 #ifdef LIBXML_DOCB_ENABLED 7826 case XML_DOCB_DOCUMENT_NODE: 7827 #endif 7828 case XML_HTML_DOCUMENT_NODE: 7829 if (cur != start) 7830 return(cur); 7831 return(xmlDocGetRootElement((xmlDocPtr) cur)); 7832 default: 7833 break; 7834 } 7835 7836 next_sibling: 7837 if ((cur == NULL) || (cur == contextNode)) 7838 return(NULL); 7839 if (cur->next != NULL) { 7840 cur = cur->next; 7841 } else { 7842 cur = cur->parent; 7843 goto next_sibling; 7844 } 7845 } 7846 } 7847 return(NULL); 7848 } 7849 #endif 7850 7851 /** 7852 * xmlXPathNextDescendant: 7853 * @ctxt: the XPath Parser context 7854 * @cur: the current node in the traversal 7855 * 7856 * Traversal function for the "descendant" direction 7857 * the descendant axis contains the descendants of the context node in document 7858 * order; a descendant is a child or a child of a child and so on. 7859 * 7860 * Returns the next element following that axis 7861 */ 7862 xmlNodePtr 7863 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7864 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7865 if (cur == NULL) { 7866 if (ctxt->context->node == NULL) 7867 return(NULL); 7868 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 7869 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 7870 return(NULL); 7871 7872 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc) 7873 return(ctxt->context->doc->children); 7874 return(ctxt->context->node->children); 7875 } 7876 7877 if (cur->type == XML_NAMESPACE_DECL) 7878 return(NULL); 7879 if (cur->children != NULL) { 7880 /* 7881 * Do not descend on entities declarations 7882 */ 7883 if (cur->children->type != XML_ENTITY_DECL) { 7884 cur = cur->children; 7885 /* 7886 * Skip DTDs 7887 */ 7888 if (cur->type != XML_DTD_NODE) 7889 return(cur); 7890 } 7891 } 7892 7893 if (cur == ctxt->context->node) return(NULL); 7894 7895 while (cur->next != NULL) { 7896 cur = cur->next; 7897 if ((cur->type != XML_ENTITY_DECL) && 7898 (cur->type != XML_DTD_NODE)) 7899 return(cur); 7900 } 7901 7902 do { 7903 cur = cur->parent; 7904 if (cur == NULL) break; 7905 if (cur == ctxt->context->node) return(NULL); 7906 if (cur->next != NULL) { 7907 cur = cur->next; 7908 return(cur); 7909 } 7910 } while (cur != NULL); 7911 return(cur); 7912 } 7913 7914 /** 7915 * xmlXPathNextDescendantOrSelf: 7916 * @ctxt: the XPath Parser context 7917 * @cur: the current node in the traversal 7918 * 7919 * Traversal function for the "descendant-or-self" direction 7920 * the descendant-or-self axis contains the context node and the descendants 7921 * of the context node in document order; thus the context node is the first 7922 * node on the axis, and the first child of the context node is the second node 7923 * on the axis 7924 * 7925 * Returns the next element following that axis 7926 */ 7927 xmlNodePtr 7928 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7929 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7930 if (cur == NULL) 7931 return(ctxt->context->node); 7932 7933 if (ctxt->context->node == NULL) 7934 return(NULL); 7935 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 7936 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 7937 return(NULL); 7938 7939 return(xmlXPathNextDescendant(ctxt, cur)); 7940 } 7941 7942 /** 7943 * xmlXPathNextParent: 7944 * @ctxt: the XPath Parser context 7945 * @cur: the current node in the traversal 7946 * 7947 * Traversal function for the "parent" direction 7948 * The parent axis contains the parent of the context node, if there is one. 7949 * 7950 * Returns the next element following that axis 7951 */ 7952 xmlNodePtr 7953 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7954 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7955 /* 7956 * the parent of an attribute or namespace node is the element 7957 * to which the attribute or namespace node is attached 7958 * Namespace handling !!! 7959 */ 7960 if (cur == NULL) { 7961 if (ctxt->context->node == NULL) return(NULL); 7962 switch (ctxt->context->node->type) { 7963 case XML_ELEMENT_NODE: 7964 case XML_TEXT_NODE: 7965 case XML_CDATA_SECTION_NODE: 7966 case XML_ENTITY_REF_NODE: 7967 case XML_ENTITY_NODE: 7968 case XML_PI_NODE: 7969 case XML_COMMENT_NODE: 7970 case XML_NOTATION_NODE: 7971 case XML_DTD_NODE: 7972 case XML_ELEMENT_DECL: 7973 case XML_ATTRIBUTE_DECL: 7974 case XML_XINCLUDE_START: 7975 case XML_XINCLUDE_END: 7976 case XML_ENTITY_DECL: 7977 if (ctxt->context->node->parent == NULL) 7978 return((xmlNodePtr) ctxt->context->doc); 7979 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) && 7980 ((ctxt->context->node->parent->name[0] == ' ') || 7981 (xmlStrEqual(ctxt->context->node->parent->name, 7982 BAD_CAST "fake node libxslt")))) 7983 return(NULL); 7984 return(ctxt->context->node->parent); 7985 case XML_ATTRIBUTE_NODE: { 7986 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node; 7987 7988 return(att->parent); 7989 } 7990 case XML_DOCUMENT_NODE: 7991 case XML_DOCUMENT_TYPE_NODE: 7992 case XML_DOCUMENT_FRAG_NODE: 7993 case XML_HTML_DOCUMENT_NODE: 7994 #ifdef LIBXML_DOCB_ENABLED 7995 case XML_DOCB_DOCUMENT_NODE: 7996 #endif 7997 return(NULL); 7998 case XML_NAMESPACE_DECL: { 7999 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; 8000 8001 if ((ns->next != NULL) && 8002 (ns->next->type != XML_NAMESPACE_DECL)) 8003 return((xmlNodePtr) ns->next); 8004 return(NULL); 8005 } 8006 } 8007 } 8008 return(NULL); 8009 } 8010 8011 /** 8012 * xmlXPathNextAncestor: 8013 * @ctxt: the XPath Parser context 8014 * @cur: the current node in the traversal 8015 * 8016 * Traversal function for the "ancestor" direction 8017 * the ancestor axis contains the ancestors of the context node; the ancestors 8018 * of the context node consist of the parent of context node and the parent's 8019 * parent and so on; the nodes are ordered in reverse document order; thus the 8020 * parent is the first node on the axis, and the parent's parent is the second 8021 * node on the axis 8022 * 8023 * Returns the next element following that axis 8024 */ 8025 xmlNodePtr 8026 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8027 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8028 /* 8029 * the parent of an attribute or namespace node is the element 8030 * to which the attribute or namespace node is attached 8031 * !!!!!!!!!!!!! 8032 */ 8033 if (cur == NULL) { 8034 if (ctxt->context->node == NULL) return(NULL); 8035 switch (ctxt->context->node->type) { 8036 case XML_ELEMENT_NODE: 8037 case XML_TEXT_NODE: 8038 case XML_CDATA_SECTION_NODE: 8039 case XML_ENTITY_REF_NODE: 8040 case XML_ENTITY_NODE: 8041 case XML_PI_NODE: 8042 case XML_COMMENT_NODE: 8043 case XML_DTD_NODE: 8044 case XML_ELEMENT_DECL: 8045 case XML_ATTRIBUTE_DECL: 8046 case XML_ENTITY_DECL: 8047 case XML_NOTATION_NODE: 8048 case XML_XINCLUDE_START: 8049 case XML_XINCLUDE_END: 8050 if (ctxt->context->node->parent == NULL) 8051 return((xmlNodePtr) ctxt->context->doc); 8052 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) && 8053 ((ctxt->context->node->parent->name[0] == ' ') || 8054 (xmlStrEqual(ctxt->context->node->parent->name, 8055 BAD_CAST "fake node libxslt")))) 8056 return(NULL); 8057 return(ctxt->context->node->parent); 8058 case XML_ATTRIBUTE_NODE: { 8059 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node; 8060 8061 return(tmp->parent); 8062 } 8063 case XML_DOCUMENT_NODE: 8064 case XML_DOCUMENT_TYPE_NODE: 8065 case XML_DOCUMENT_FRAG_NODE: 8066 case XML_HTML_DOCUMENT_NODE: 8067 #ifdef LIBXML_DOCB_ENABLED 8068 case XML_DOCB_DOCUMENT_NODE: 8069 #endif 8070 return(NULL); 8071 case XML_NAMESPACE_DECL: { 8072 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; 8073 8074 if ((ns->next != NULL) && 8075 (ns->next->type != XML_NAMESPACE_DECL)) 8076 return((xmlNodePtr) ns->next); 8077 /* Bad, how did that namespace end up here ? */ 8078 return(NULL); 8079 } 8080 } 8081 return(NULL); 8082 } 8083 if (cur == ctxt->context->doc->children) 8084 return((xmlNodePtr) ctxt->context->doc); 8085 if (cur == (xmlNodePtr) ctxt->context->doc) 8086 return(NULL); 8087 switch (cur->type) { 8088 case XML_ELEMENT_NODE: 8089 case XML_TEXT_NODE: 8090 case XML_CDATA_SECTION_NODE: 8091 case XML_ENTITY_REF_NODE: 8092 case XML_ENTITY_NODE: 8093 case XML_PI_NODE: 8094 case XML_COMMENT_NODE: 8095 case XML_NOTATION_NODE: 8096 case XML_DTD_NODE: 8097 case XML_ELEMENT_DECL: 8098 case XML_ATTRIBUTE_DECL: 8099 case XML_ENTITY_DECL: 8100 case XML_XINCLUDE_START: 8101 case XML_XINCLUDE_END: 8102 if (cur->parent == NULL) 8103 return(NULL); 8104 if ((cur->parent->type == XML_ELEMENT_NODE) && 8105 ((cur->parent->name[0] == ' ') || 8106 (xmlStrEqual(cur->parent->name, 8107 BAD_CAST "fake node libxslt")))) 8108 return(NULL); 8109 return(cur->parent); 8110 case XML_ATTRIBUTE_NODE: { 8111 xmlAttrPtr att = (xmlAttrPtr) cur; 8112 8113 return(att->parent); 8114 } 8115 case XML_NAMESPACE_DECL: { 8116 xmlNsPtr ns = (xmlNsPtr) cur; 8117 8118 if ((ns->next != NULL) && 8119 (ns->next->type != XML_NAMESPACE_DECL)) 8120 return((xmlNodePtr) ns->next); 8121 /* Bad, how did that namespace end up here ? */ 8122 return(NULL); 8123 } 8124 case XML_DOCUMENT_NODE: 8125 case XML_DOCUMENT_TYPE_NODE: 8126 case XML_DOCUMENT_FRAG_NODE: 8127 case XML_HTML_DOCUMENT_NODE: 8128 #ifdef LIBXML_DOCB_ENABLED 8129 case XML_DOCB_DOCUMENT_NODE: 8130 #endif 8131 return(NULL); 8132 } 8133 return(NULL); 8134 } 8135 8136 /** 8137 * xmlXPathNextAncestorOrSelf: 8138 * @ctxt: the XPath Parser context 8139 * @cur: the current node in the traversal 8140 * 8141 * Traversal function for the "ancestor-or-self" direction 8142 * he ancestor-or-self axis contains the context node and ancestors of 8143 * the context node in reverse document order; thus the context node is 8144 * the first node on the axis, and the context node's parent the second; 8145 * parent here is defined the same as with the parent axis. 8146 * 8147 * Returns the next element following that axis 8148 */ 8149 xmlNodePtr 8150 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8151 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8152 if (cur == NULL) 8153 return(ctxt->context->node); 8154 return(xmlXPathNextAncestor(ctxt, cur)); 8155 } 8156 8157 /** 8158 * xmlXPathNextFollowingSibling: 8159 * @ctxt: the XPath Parser context 8160 * @cur: the current node in the traversal 8161 * 8162 * Traversal function for the "following-sibling" direction 8163 * The following-sibling axis contains the following siblings of the context 8164 * node in document order. 8165 * 8166 * Returns the next element following that axis 8167 */ 8168 xmlNodePtr 8169 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8170 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8171 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 8172 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 8173 return(NULL); 8174 if (cur == (xmlNodePtr) ctxt->context->doc) 8175 return(NULL); 8176 if (cur == NULL) 8177 return(ctxt->context->node->next); 8178 return(cur->next); 8179 } 8180 8181 /** 8182 * xmlXPathNextPrecedingSibling: 8183 * @ctxt: the XPath Parser context 8184 * @cur: the current node in the traversal 8185 * 8186 * Traversal function for the "preceding-sibling" direction 8187 * The preceding-sibling axis contains the preceding siblings of the context 8188 * node in reverse document order; the first preceding sibling is first on the 8189 * axis; the sibling preceding that node is the second on the axis and so on. 8190 * 8191 * Returns the next element following that axis 8192 */ 8193 xmlNodePtr 8194 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8195 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8196 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 8197 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 8198 return(NULL); 8199 if (cur == (xmlNodePtr) ctxt->context->doc) 8200 return(NULL); 8201 if (cur == NULL) 8202 return(ctxt->context->node->prev); 8203 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) { 8204 cur = cur->prev; 8205 if (cur == NULL) 8206 return(ctxt->context->node->prev); 8207 } 8208 return(cur->prev); 8209 } 8210 8211 /** 8212 * xmlXPathNextFollowing: 8213 * @ctxt: the XPath Parser context 8214 * @cur: the current node in the traversal 8215 * 8216 * Traversal function for the "following" direction 8217 * The following axis contains all nodes in the same document as the context 8218 * node that are after the context node in document order, excluding any 8219 * descendants and excluding attribute nodes and namespace nodes; the nodes 8220 * are ordered in document order 8221 * 8222 * Returns the next element following that axis 8223 */ 8224 xmlNodePtr 8225 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8226 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8227 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) && 8228 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL)) 8229 return(cur->children); 8230 8231 if (cur == NULL) { 8232 cur = ctxt->context->node; 8233 if (cur->type == XML_ATTRIBUTE_NODE) { 8234 cur = cur->parent; 8235 } else if (cur->type == XML_NAMESPACE_DECL) { 8236 xmlNsPtr ns = (xmlNsPtr) cur; 8237 8238 if ((ns->next == NULL) || 8239 (ns->next->type == XML_NAMESPACE_DECL)) 8240 return (NULL); 8241 cur = (xmlNodePtr) ns->next; 8242 } 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_ATTRIBUTE_NODE) { 8304 cur = cur->parent; 8305 } else if (cur->type == XML_NAMESPACE_DECL) { 8306 xmlNsPtr ns = (xmlNsPtr) cur; 8307 8308 if ((ns->next == NULL) || 8309 (ns->next->type == XML_NAMESPACE_DECL)) 8310 return (NULL); 8311 cur = (xmlNodePtr) ns->next; 8312 } 8313 } 8314 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) 8315 return (NULL); 8316 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) 8317 cur = cur->prev; 8318 do { 8319 if (cur->prev != NULL) { 8320 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ; 8321 return (cur); 8322 } 8323 8324 cur = cur->parent; 8325 if (cur == NULL) 8326 return (NULL); 8327 if (cur == ctxt->context->doc->children) 8328 return (NULL); 8329 } while (xmlXPathIsAncestor(cur, ctxt->context->node)); 8330 return (cur); 8331 } 8332 8333 /** 8334 * xmlXPathNextPrecedingInternal: 8335 * @ctxt: the XPath Parser context 8336 * @cur: the current node in the traversal 8337 * 8338 * Traversal function for the "preceding" direction 8339 * the preceding axis contains all nodes in the same document as the context 8340 * node that are before the context node in document order, excluding any 8341 * ancestors and excluding attribute nodes and namespace nodes; the nodes are 8342 * ordered in reverse document order 8343 * This is a faster implementation but internal only since it requires a 8344 * state kept in the parser context: ctxt->ancestor. 8345 * 8346 * Returns the next element following that axis 8347 */ 8348 static xmlNodePtr 8349 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt, 8350 xmlNodePtr cur) 8351 { 8352 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8353 if (cur == NULL) { 8354 cur = ctxt->context->node; 8355 if (cur == NULL) 8356 return (NULL); 8357 if (cur->type == XML_ATTRIBUTE_NODE) { 8358 cur = cur->parent; 8359 } else if (cur->type == XML_NAMESPACE_DECL) { 8360 xmlNsPtr ns = (xmlNsPtr) cur; 8361 8362 if ((ns->next == NULL) || 8363 (ns->next->type == XML_NAMESPACE_DECL)) 8364 return (NULL); 8365 cur = (xmlNodePtr) ns->next; 8366 } 8367 ctxt->ancestor = cur->parent; 8368 } 8369 if (cur->type == XML_NAMESPACE_DECL) 8370 return(NULL); 8371 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) 8372 cur = cur->prev; 8373 while (cur->prev == NULL) { 8374 cur = cur->parent; 8375 if (cur == NULL) 8376 return (NULL); 8377 if (cur == ctxt->context->doc->children) 8378 return (NULL); 8379 if (cur != ctxt->ancestor) 8380 return (cur); 8381 ctxt->ancestor = cur->parent; 8382 } 8383 cur = cur->prev; 8384 while (cur->last != NULL) 8385 cur = cur->last; 8386 return (cur); 8387 } 8388 8389 /** 8390 * xmlXPathNextNamespace: 8391 * @ctxt: the XPath Parser context 8392 * @cur: the current attribute in the traversal 8393 * 8394 * Traversal function for the "namespace" direction 8395 * the namespace axis contains the namespace nodes of the context node; 8396 * the order of nodes on this axis is implementation-defined; the axis will 8397 * be empty unless the context node is an element 8398 * 8399 * We keep the XML namespace node at the end of the list. 8400 * 8401 * Returns the next element following that axis 8402 */ 8403 xmlNodePtr 8404 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8405 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8406 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL); 8407 if (cur == NULL) { 8408 if (ctxt->context->tmpNsList != NULL) 8409 xmlFree(ctxt->context->tmpNsList); 8410 ctxt->context->tmpNsList = 8411 xmlGetNsList(ctxt->context->doc, ctxt->context->node); 8412 ctxt->context->tmpNsNr = 0; 8413 if (ctxt->context->tmpNsList != NULL) { 8414 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) { 8415 ctxt->context->tmpNsNr++; 8416 } 8417 } 8418 return((xmlNodePtr) xmlXPathXMLNamespace); 8419 } 8420 if (ctxt->context->tmpNsNr > 0) { 8421 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr]; 8422 } else { 8423 if (ctxt->context->tmpNsList != NULL) 8424 xmlFree(ctxt->context->tmpNsList); 8425 ctxt->context->tmpNsList = NULL; 8426 return(NULL); 8427 } 8428 } 8429 8430 /** 8431 * xmlXPathNextAttribute: 8432 * @ctxt: the XPath Parser context 8433 * @cur: the current attribute in the traversal 8434 * 8435 * Traversal function for the "attribute" direction 8436 * TODO: support DTD inherited default attributes 8437 * 8438 * Returns the next element following that axis 8439 */ 8440 xmlNodePtr 8441 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8442 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8443 if (ctxt->context->node == NULL) 8444 return(NULL); 8445 if (ctxt->context->node->type != XML_ELEMENT_NODE) 8446 return(NULL); 8447 if (cur == NULL) { 8448 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc) 8449 return(NULL); 8450 return((xmlNodePtr)ctxt->context->node->properties); 8451 } 8452 return((xmlNodePtr)cur->next); 8453 } 8454 8455 /************************************************************************ 8456 * * 8457 * NodeTest Functions * 8458 * * 8459 ************************************************************************/ 8460 8461 #define IS_FUNCTION 200 8462 8463 8464 /************************************************************************ 8465 * * 8466 * Implicit tree core function library * 8467 * * 8468 ************************************************************************/ 8469 8470 /** 8471 * xmlXPathRoot: 8472 * @ctxt: the XPath Parser context 8473 * 8474 * Initialize the context to the root of the document 8475 */ 8476 void 8477 xmlXPathRoot(xmlXPathParserContextPtr ctxt) { 8478 if ((ctxt == NULL) || (ctxt->context == NULL)) 8479 return; 8480 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8481 (xmlNodePtr) ctxt->context->doc)); 8482 } 8483 8484 /************************************************************************ 8485 * * 8486 * The explicit core function library * 8487 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib * 8488 * * 8489 ************************************************************************/ 8490 8491 8492 /** 8493 * xmlXPathLastFunction: 8494 * @ctxt: the XPath Parser context 8495 * @nargs: the number of arguments 8496 * 8497 * Implement the last() XPath function 8498 * number last() 8499 * The last function returns the number of nodes in the context node list. 8500 */ 8501 void 8502 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8503 CHECK_ARITY(0); 8504 if (ctxt->context->contextSize >= 0) { 8505 valuePush(ctxt, 8506 xmlXPathCacheNewFloat(ctxt->context, 8507 (double) ctxt->context->contextSize)); 8508 #ifdef DEBUG_EXPR 8509 xmlGenericError(xmlGenericErrorContext, 8510 "last() : %d\n", ctxt->context->contextSize); 8511 #endif 8512 } else { 8513 XP_ERROR(XPATH_INVALID_CTXT_SIZE); 8514 } 8515 } 8516 8517 /** 8518 * xmlXPathPositionFunction: 8519 * @ctxt: the XPath Parser context 8520 * @nargs: the number of arguments 8521 * 8522 * Implement the position() XPath function 8523 * number position() 8524 * The position function returns the position of the context node in the 8525 * context node list. The first position is 1, and so the last position 8526 * will be equal to last(). 8527 */ 8528 void 8529 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8530 CHECK_ARITY(0); 8531 if (ctxt->context->proximityPosition >= 0) { 8532 valuePush(ctxt, 8533 xmlXPathCacheNewFloat(ctxt->context, 8534 (double) ctxt->context->proximityPosition)); 8535 #ifdef DEBUG_EXPR 8536 xmlGenericError(xmlGenericErrorContext, "position() : %d\n", 8537 ctxt->context->proximityPosition); 8538 #endif 8539 } else { 8540 XP_ERROR(XPATH_INVALID_CTXT_POSITION); 8541 } 8542 } 8543 8544 /** 8545 * xmlXPathCountFunction: 8546 * @ctxt: the XPath Parser context 8547 * @nargs: the number of arguments 8548 * 8549 * Implement the count() XPath function 8550 * number count(node-set) 8551 */ 8552 void 8553 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8554 xmlXPathObjectPtr cur; 8555 8556 CHECK_ARITY(1); 8557 if ((ctxt->value == NULL) || 8558 ((ctxt->value->type != XPATH_NODESET) && 8559 (ctxt->value->type != XPATH_XSLT_TREE))) 8560 XP_ERROR(XPATH_INVALID_TYPE); 8561 cur = valuePop(ctxt); 8562 8563 if ((cur == NULL) || (cur->nodesetval == NULL)) 8564 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0)); 8565 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) { 8566 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 8567 (double) cur->nodesetval->nodeNr)); 8568 } else { 8569 if ((cur->nodesetval->nodeNr != 1) || 8570 (cur->nodesetval->nodeTab == NULL)) { 8571 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0)); 8572 } else { 8573 xmlNodePtr tmp; 8574 int i = 0; 8575 8576 tmp = cur->nodesetval->nodeTab[0]; 8577 if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) { 8578 tmp = tmp->children; 8579 while (tmp != NULL) { 8580 tmp = tmp->next; 8581 i++; 8582 } 8583 } 8584 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i)); 8585 } 8586 } 8587 xmlXPathReleaseObject(ctxt->context, cur); 8588 } 8589 8590 /** 8591 * xmlXPathGetElementsByIds: 8592 * @doc: the document 8593 * @ids: a whitespace separated list of IDs 8594 * 8595 * Selects elements by their unique ID. 8596 * 8597 * Returns a node-set of selected elements. 8598 */ 8599 static xmlNodeSetPtr 8600 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) { 8601 xmlNodeSetPtr ret; 8602 const xmlChar *cur = ids; 8603 xmlChar *ID; 8604 xmlAttrPtr attr; 8605 xmlNodePtr elem = NULL; 8606 8607 if (ids == NULL) return(NULL); 8608 8609 ret = xmlXPathNodeSetCreate(NULL); 8610 if (ret == NULL) 8611 return(ret); 8612 8613 while (IS_BLANK_CH(*cur)) cur++; 8614 while (*cur != 0) { 8615 while ((!IS_BLANK_CH(*cur)) && (*cur != 0)) 8616 cur++; 8617 8618 ID = xmlStrndup(ids, cur - ids); 8619 if (ID != NULL) { 8620 /* 8621 * We used to check the fact that the value passed 8622 * was an NCName, but this generated much troubles for 8623 * me and Aleksey Sanin, people blatantly violated that 8624 * constaint, like Visa3D spec. 8625 * if (xmlValidateNCName(ID, 1) == 0) 8626 */ 8627 attr = xmlGetID(doc, ID); 8628 if (attr != NULL) { 8629 if (attr->type == XML_ATTRIBUTE_NODE) 8630 elem = attr->parent; 8631 else if (attr->type == XML_ELEMENT_NODE) 8632 elem = (xmlNodePtr) attr; 8633 else 8634 elem = NULL; 8635 if (elem != NULL) 8636 xmlXPathNodeSetAdd(ret, elem); 8637 } 8638 xmlFree(ID); 8639 } 8640 8641 while (IS_BLANK_CH(*cur)) cur++; 8642 ids = cur; 8643 } 8644 return(ret); 8645 } 8646 8647 /** 8648 * xmlXPathIdFunction: 8649 * @ctxt: the XPath Parser context 8650 * @nargs: the number of arguments 8651 * 8652 * Implement the id() XPath function 8653 * node-set id(object) 8654 * The id function selects elements by their unique ID 8655 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set, 8656 * then the result is the union of the result of applying id to the 8657 * string value of each of the nodes in the argument node-set. When the 8658 * argument to id is of any other type, the argument is converted to a 8659 * string as if by a call to the string function; the string is split 8660 * into a whitespace-separated list of tokens (whitespace is any sequence 8661 * of characters matching the production S); the result is a node-set 8662 * containing the elements in the same document as the context node that 8663 * have a unique ID equal to any of the tokens in the list. 8664 */ 8665 void 8666 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8667 xmlChar *tokens; 8668 xmlNodeSetPtr ret; 8669 xmlXPathObjectPtr obj; 8670 8671 CHECK_ARITY(1); 8672 obj = valuePop(ctxt); 8673 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 8674 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) { 8675 xmlNodeSetPtr ns; 8676 int i; 8677 8678 ret = xmlXPathNodeSetCreate(NULL); 8679 /* 8680 * FIXME -- in an out-of-memory condition this will behave badly. 8681 * The solution is not clear -- we already popped an item from 8682 * ctxt, so the object is in a corrupt state. 8683 */ 8684 8685 if (obj->nodesetval != NULL) { 8686 for (i = 0; i < obj->nodesetval->nodeNr; i++) { 8687 tokens = 8688 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]); 8689 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens); 8690 ret = xmlXPathNodeSetMerge(ret, ns); 8691 xmlXPathFreeNodeSet(ns); 8692 if (tokens != NULL) 8693 xmlFree(tokens); 8694 } 8695 } 8696 xmlXPathReleaseObject(ctxt->context, obj); 8697 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret)); 8698 return; 8699 } 8700 obj = xmlXPathCacheConvertString(ctxt->context, obj); 8701 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval); 8702 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret)); 8703 xmlXPathReleaseObject(ctxt->context, obj); 8704 return; 8705 } 8706 8707 /** 8708 * xmlXPathLocalNameFunction: 8709 * @ctxt: the XPath Parser context 8710 * @nargs: the number of arguments 8711 * 8712 * Implement the local-name() XPath function 8713 * string local-name(node-set?) 8714 * The local-name function returns a string containing the local part 8715 * of the name of the node in the argument node-set that is first in 8716 * document order. If the node-set is empty or the first node has no 8717 * name, an empty string is returned. If the argument is omitted it 8718 * defaults to the context node. 8719 */ 8720 void 8721 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8722 xmlXPathObjectPtr cur; 8723 8724 if (ctxt == NULL) return; 8725 8726 if (nargs == 0) { 8727 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8728 ctxt->context->node)); 8729 nargs = 1; 8730 } 8731 8732 CHECK_ARITY(1); 8733 if ((ctxt->value == NULL) || 8734 ((ctxt->value->type != XPATH_NODESET) && 8735 (ctxt->value->type != XPATH_XSLT_TREE))) 8736 XP_ERROR(XPATH_INVALID_TYPE); 8737 cur = valuePop(ctxt); 8738 8739 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 8740 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8741 } else { 8742 int i = 0; /* Should be first in document order !!!!! */ 8743 switch (cur->nodesetval->nodeTab[i]->type) { 8744 case XML_ELEMENT_NODE: 8745 case XML_ATTRIBUTE_NODE: 8746 case XML_PI_NODE: 8747 if (cur->nodesetval->nodeTab[i]->name[0] == ' ') 8748 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8749 else 8750 valuePush(ctxt, 8751 xmlXPathCacheNewString(ctxt->context, 8752 cur->nodesetval->nodeTab[i]->name)); 8753 break; 8754 case XML_NAMESPACE_DECL: 8755 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 8756 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix)); 8757 break; 8758 default: 8759 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8760 } 8761 } 8762 xmlXPathReleaseObject(ctxt->context, cur); 8763 } 8764 8765 /** 8766 * xmlXPathNamespaceURIFunction: 8767 * @ctxt: the XPath Parser context 8768 * @nargs: the number of arguments 8769 * 8770 * Implement the namespace-uri() XPath function 8771 * string namespace-uri(node-set?) 8772 * The namespace-uri function returns a string containing the 8773 * namespace URI of the expanded name of the node in the argument 8774 * node-set that is first in document order. If the node-set is empty, 8775 * the first node has no name, or the expanded name has no namespace 8776 * URI, an empty string is returned. If the argument is omitted it 8777 * defaults to the context node. 8778 */ 8779 void 8780 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8781 xmlXPathObjectPtr cur; 8782 8783 if (ctxt == NULL) return; 8784 8785 if (nargs == 0) { 8786 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8787 ctxt->context->node)); 8788 nargs = 1; 8789 } 8790 CHECK_ARITY(1); 8791 if ((ctxt->value == NULL) || 8792 ((ctxt->value->type != XPATH_NODESET) && 8793 (ctxt->value->type != XPATH_XSLT_TREE))) 8794 XP_ERROR(XPATH_INVALID_TYPE); 8795 cur = valuePop(ctxt); 8796 8797 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 8798 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8799 } else { 8800 int i = 0; /* Should be first in document order !!!!! */ 8801 switch (cur->nodesetval->nodeTab[i]->type) { 8802 case XML_ELEMENT_NODE: 8803 case XML_ATTRIBUTE_NODE: 8804 if (cur->nodesetval->nodeTab[i]->ns == NULL) 8805 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8806 else 8807 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 8808 cur->nodesetval->nodeTab[i]->ns->href)); 8809 break; 8810 default: 8811 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8812 } 8813 } 8814 xmlXPathReleaseObject(ctxt->context, cur); 8815 } 8816 8817 /** 8818 * xmlXPathNameFunction: 8819 * @ctxt: the XPath Parser context 8820 * @nargs: the number of arguments 8821 * 8822 * Implement the name() XPath function 8823 * string name(node-set?) 8824 * The name function returns a string containing a QName representing 8825 * the name of the node in the argument node-set that is first in document 8826 * order. The QName must represent the name with respect to the namespace 8827 * declarations in effect on the node whose name is being represented. 8828 * Typically, this will be the form in which the name occurred in the XML 8829 * source. This need not be the case if there are namespace declarations 8830 * in effect on the node that associate multiple prefixes with the same 8831 * namespace. However, an implementation may include information about 8832 * the original prefix in its representation of nodes; in this case, an 8833 * implementation can ensure that the returned string is always the same 8834 * as the QName used in the XML source. If the argument it omitted it 8835 * defaults to the context node. 8836 * Libxml keep the original prefix so the "real qualified name" used is 8837 * returned. 8838 */ 8839 static void 8840 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) 8841 { 8842 xmlXPathObjectPtr cur; 8843 8844 if (nargs == 0) { 8845 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8846 ctxt->context->node)); 8847 nargs = 1; 8848 } 8849 8850 CHECK_ARITY(1); 8851 if ((ctxt->value == NULL) || 8852 ((ctxt->value->type != XPATH_NODESET) && 8853 (ctxt->value->type != XPATH_XSLT_TREE))) 8854 XP_ERROR(XPATH_INVALID_TYPE); 8855 cur = valuePop(ctxt); 8856 8857 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 8858 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8859 } else { 8860 int i = 0; /* Should be first in document order !!!!! */ 8861 8862 switch (cur->nodesetval->nodeTab[i]->type) { 8863 case XML_ELEMENT_NODE: 8864 case XML_ATTRIBUTE_NODE: 8865 if (cur->nodesetval->nodeTab[i]->name[0] == ' ') 8866 valuePush(ctxt, 8867 xmlXPathCacheNewCString(ctxt->context, "")); 8868 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) || 8869 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) { 8870 valuePush(ctxt, 8871 xmlXPathCacheNewString(ctxt->context, 8872 cur->nodesetval->nodeTab[i]->name)); 8873 } else { 8874 xmlChar *fullname; 8875 8876 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name, 8877 cur->nodesetval->nodeTab[i]->ns->prefix, 8878 NULL, 0); 8879 if (fullname == cur->nodesetval->nodeTab[i]->name) 8880 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name); 8881 if (fullname == NULL) { 8882 XP_ERROR(XPATH_MEMORY_ERROR); 8883 } 8884 valuePush(ctxt, xmlXPathCacheWrapString( 8885 ctxt->context, fullname)); 8886 } 8887 break; 8888 default: 8889 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8890 cur->nodesetval->nodeTab[i])); 8891 xmlXPathLocalNameFunction(ctxt, 1); 8892 } 8893 } 8894 xmlXPathReleaseObject(ctxt->context, cur); 8895 } 8896 8897 8898 /** 8899 * xmlXPathStringFunction: 8900 * @ctxt: the XPath Parser context 8901 * @nargs: the number of arguments 8902 * 8903 * Implement the string() XPath function 8904 * string string(object?) 8905 * The string function converts an object to a string as follows: 8906 * - A node-set is converted to a string by returning the value of 8907 * the node in the node-set that is first in document order. 8908 * If the node-set is empty, an empty string is returned. 8909 * - A number is converted to a string as follows 8910 * + NaN is converted to the string NaN 8911 * + positive zero is converted to the string 0 8912 * + negative zero is converted to the string 0 8913 * + positive infinity is converted to the string Infinity 8914 * + negative infinity is converted to the string -Infinity 8915 * + if the number is an integer, the number is represented in 8916 * decimal form as a Number with no decimal point and no leading 8917 * zeros, preceded by a minus sign (-) if the number is negative 8918 * + otherwise, the number is represented in decimal form as a 8919 * Number including a decimal point with at least one digit 8920 * before the decimal point and at least one digit after the 8921 * decimal point, preceded by a minus sign (-) if the number 8922 * is negative; there must be no leading zeros before the decimal 8923 * point apart possibly from the one required digit immediately 8924 * before the decimal point; beyond the one required digit 8925 * after the decimal point there must be as many, but only as 8926 * many, more digits as are needed to uniquely distinguish the 8927 * number from all other IEEE 754 numeric values. 8928 * - The boolean false value is converted to the string false. 8929 * The boolean true value is converted to the string true. 8930 * 8931 * If the argument is omitted, it defaults to a node-set with the 8932 * context node as its only member. 8933 */ 8934 void 8935 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8936 xmlXPathObjectPtr cur; 8937 8938 if (ctxt == NULL) return; 8939 if (nargs == 0) { 8940 valuePush(ctxt, 8941 xmlXPathCacheWrapString(ctxt->context, 8942 xmlXPathCastNodeToString(ctxt->context->node))); 8943 return; 8944 } 8945 8946 CHECK_ARITY(1); 8947 cur = valuePop(ctxt); 8948 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 8949 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur)); 8950 } 8951 8952 /** 8953 * xmlXPathStringLengthFunction: 8954 * @ctxt: the XPath Parser context 8955 * @nargs: the number of arguments 8956 * 8957 * Implement the string-length() XPath function 8958 * number string-length(string?) 8959 * The string-length returns the number of characters in the string 8960 * (see [3.6 Strings]). If the argument is omitted, it defaults to 8961 * the context node converted to a string, in other words the value 8962 * of the context node. 8963 */ 8964 void 8965 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8966 xmlXPathObjectPtr cur; 8967 8968 if (nargs == 0) { 8969 if ((ctxt == NULL) || (ctxt->context == NULL)) 8970 return; 8971 if (ctxt->context->node == NULL) { 8972 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0)); 8973 } else { 8974 xmlChar *content; 8975 8976 content = xmlXPathCastNodeToString(ctxt->context->node); 8977 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 8978 xmlUTF8Strlen(content))); 8979 xmlFree(content); 8980 } 8981 return; 8982 } 8983 CHECK_ARITY(1); 8984 CAST_TO_STRING; 8985 CHECK_TYPE(XPATH_STRING); 8986 cur = valuePop(ctxt); 8987 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 8988 xmlUTF8Strlen(cur->stringval))); 8989 xmlXPathReleaseObject(ctxt->context, cur); 8990 } 8991 8992 /** 8993 * xmlXPathConcatFunction: 8994 * @ctxt: the XPath Parser context 8995 * @nargs: the number of arguments 8996 * 8997 * Implement the concat() XPath function 8998 * string concat(string, string, string*) 8999 * The concat function returns the concatenation of its arguments. 9000 */ 9001 void 9002 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9003 xmlXPathObjectPtr cur, newobj; 9004 xmlChar *tmp; 9005 9006 if (ctxt == NULL) return; 9007 if (nargs < 2) { 9008 CHECK_ARITY(2); 9009 } 9010 9011 CAST_TO_STRING; 9012 cur = valuePop(ctxt); 9013 if ((cur == NULL) || (cur->type != XPATH_STRING)) { 9014 xmlXPathReleaseObject(ctxt->context, cur); 9015 return; 9016 } 9017 nargs--; 9018 9019 while (nargs > 0) { 9020 CAST_TO_STRING; 9021 newobj = valuePop(ctxt); 9022 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) { 9023 xmlXPathReleaseObject(ctxt->context, newobj); 9024 xmlXPathReleaseObject(ctxt->context, cur); 9025 XP_ERROR(XPATH_INVALID_TYPE); 9026 } 9027 tmp = xmlStrcat(newobj->stringval, cur->stringval); 9028 newobj->stringval = cur->stringval; 9029 cur->stringval = tmp; 9030 xmlXPathReleaseObject(ctxt->context, newobj); 9031 nargs--; 9032 } 9033 valuePush(ctxt, cur); 9034 } 9035 9036 /** 9037 * xmlXPathContainsFunction: 9038 * @ctxt: the XPath Parser context 9039 * @nargs: the number of arguments 9040 * 9041 * Implement the contains() XPath function 9042 * boolean contains(string, string) 9043 * The contains function returns true if the first argument string 9044 * contains the second argument string, and otherwise returns false. 9045 */ 9046 void 9047 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9048 xmlXPathObjectPtr hay, needle; 9049 9050 CHECK_ARITY(2); 9051 CAST_TO_STRING; 9052 CHECK_TYPE(XPATH_STRING); 9053 needle = valuePop(ctxt); 9054 CAST_TO_STRING; 9055 hay = valuePop(ctxt); 9056 9057 if ((hay == NULL) || (hay->type != XPATH_STRING)) { 9058 xmlXPathReleaseObject(ctxt->context, hay); 9059 xmlXPathReleaseObject(ctxt->context, needle); 9060 XP_ERROR(XPATH_INVALID_TYPE); 9061 } 9062 if (xmlStrstr(hay->stringval, needle->stringval)) 9063 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); 9064 else 9065 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); 9066 xmlXPathReleaseObject(ctxt->context, hay); 9067 xmlXPathReleaseObject(ctxt->context, needle); 9068 } 9069 9070 /** 9071 * xmlXPathStartsWithFunction: 9072 * @ctxt: the XPath Parser context 9073 * @nargs: the number of arguments 9074 * 9075 * Implement the starts-with() XPath function 9076 * boolean starts-with(string, string) 9077 * The starts-with function returns true if the first argument string 9078 * starts with the second argument string, and otherwise returns false. 9079 */ 9080 void 9081 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9082 xmlXPathObjectPtr hay, needle; 9083 int n; 9084 9085 CHECK_ARITY(2); 9086 CAST_TO_STRING; 9087 CHECK_TYPE(XPATH_STRING); 9088 needle = valuePop(ctxt); 9089 CAST_TO_STRING; 9090 hay = valuePop(ctxt); 9091 9092 if ((hay == NULL) || (hay->type != XPATH_STRING)) { 9093 xmlXPathReleaseObject(ctxt->context, hay); 9094 xmlXPathReleaseObject(ctxt->context, needle); 9095 XP_ERROR(XPATH_INVALID_TYPE); 9096 } 9097 n = xmlStrlen(needle->stringval); 9098 if (xmlStrncmp(hay->stringval, needle->stringval, n)) 9099 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); 9100 else 9101 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); 9102 xmlXPathReleaseObject(ctxt->context, hay); 9103 xmlXPathReleaseObject(ctxt->context, needle); 9104 } 9105 9106 /** 9107 * xmlXPathSubstringFunction: 9108 * @ctxt: the XPath Parser context 9109 * @nargs: the number of arguments 9110 * 9111 * Implement the substring() XPath function 9112 * string substring(string, number, number?) 9113 * The substring function returns the substring of the first argument 9114 * starting at the position specified in the second argument with 9115 * length specified in the third argument. For example, 9116 * substring("12345",2,3) returns "234". If the third argument is not 9117 * specified, it returns the substring starting at the position specified 9118 * in the second argument and continuing to the end of the string. For 9119 * example, substring("12345",2) returns "2345". More precisely, each 9120 * character in the string (see [3.6 Strings]) is considered to have a 9121 * numeric position: the position of the first character is 1, the position 9122 * of the second character is 2 and so on. The returned substring contains 9123 * those characters for which the position of the character is greater than 9124 * or equal to the second argument and, if the third argument is specified, 9125 * less than the sum of the second and third arguments; the comparisons 9126 * and addition used for the above follow the standard IEEE 754 rules. Thus: 9127 * - substring("12345", 1.5, 2.6) returns "234" 9128 * - substring("12345", 0, 3) returns "12" 9129 * - substring("12345", 0 div 0, 3) returns "" 9130 * - substring("12345", 1, 0 div 0) returns "" 9131 * - substring("12345", -42, 1 div 0) returns "12345" 9132 * - substring("12345", -1 div 0, 1 div 0) returns "" 9133 */ 9134 void 9135 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9136 xmlXPathObjectPtr str, start, len; 9137 double le=0, in; 9138 int i, l, m; 9139 xmlChar *ret; 9140 9141 if (nargs < 2) { 9142 CHECK_ARITY(2); 9143 } 9144 if (nargs > 3) { 9145 CHECK_ARITY(3); 9146 } 9147 /* 9148 * take care of possible last (position) argument 9149 */ 9150 if (nargs == 3) { 9151 CAST_TO_NUMBER; 9152 CHECK_TYPE(XPATH_NUMBER); 9153 len = valuePop(ctxt); 9154 le = len->floatval; 9155 xmlXPathReleaseObject(ctxt->context, len); 9156 } 9157 9158 CAST_TO_NUMBER; 9159 CHECK_TYPE(XPATH_NUMBER); 9160 start = valuePop(ctxt); 9161 in = start->floatval; 9162 xmlXPathReleaseObject(ctxt->context, start); 9163 CAST_TO_STRING; 9164 CHECK_TYPE(XPATH_STRING); 9165 str = valuePop(ctxt); 9166 m = xmlUTF8Strlen((const unsigned char *)str->stringval); 9167 9168 /* 9169 * If last pos not present, calculate last position 9170 */ 9171 if (nargs != 3) { 9172 le = (double)m; 9173 if (in < 1.0) 9174 in = 1.0; 9175 } 9176 9177 /* Need to check for the special cases where either 9178 * the index is NaN, the length is NaN, or both 9179 * arguments are infinity (relying on Inf + -Inf = NaN) 9180 */ 9181 if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) { 9182 /* 9183 * To meet the requirements of the spec, the arguments 9184 * must be converted to integer format before 9185 * initial index calculations are done 9186 * 9187 * First we go to integer form, rounding up 9188 * and checking for special cases 9189 */ 9190 i = (int) in; 9191 if (((double)i)+0.5 <= in) i++; 9192 9193 if (xmlXPathIsInf(le) == 1) { 9194 l = m; 9195 if (i < 1) 9196 i = 1; 9197 } 9198 else if (xmlXPathIsInf(le) == -1 || le < 0.0) 9199 l = 0; 9200 else { 9201 l = (int) le; 9202 if (((double)l)+0.5 <= le) l++; 9203 } 9204 9205 /* Now we normalize inidices */ 9206 i -= 1; 9207 l += i; 9208 if (i < 0) 9209 i = 0; 9210 if (l > m) 9211 l = m; 9212 9213 /* number of chars to copy */ 9214 l -= i; 9215 9216 ret = xmlUTF8Strsub(str->stringval, i, l); 9217 } 9218 else { 9219 ret = NULL; 9220 } 9221 if (ret == NULL) 9222 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 9223 else { 9224 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret)); 9225 xmlFree(ret); 9226 } 9227 xmlXPathReleaseObject(ctxt->context, str); 9228 } 9229 9230 /** 9231 * xmlXPathSubstringBeforeFunction: 9232 * @ctxt: the XPath Parser context 9233 * @nargs: the number of arguments 9234 * 9235 * Implement the substring-before() XPath function 9236 * string substring-before(string, string) 9237 * The substring-before function returns the substring of the first 9238 * argument string that precedes the first occurrence of the second 9239 * argument string in the first argument string, or the empty string 9240 * if the first argument string does not contain the second argument 9241 * string. For example, substring-before("1999/04/01","/") returns 1999. 9242 */ 9243 void 9244 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9245 xmlXPathObjectPtr str; 9246 xmlXPathObjectPtr find; 9247 xmlBufPtr target; 9248 const xmlChar *point; 9249 int offset; 9250 9251 CHECK_ARITY(2); 9252 CAST_TO_STRING; 9253 find = valuePop(ctxt); 9254 CAST_TO_STRING; 9255 str = valuePop(ctxt); 9256 9257 target = xmlBufCreate(); 9258 if (target) { 9259 point = xmlStrstr(str->stringval, find->stringval); 9260 if (point) { 9261 offset = (int)(point - str->stringval); 9262 xmlBufAdd(target, str->stringval, offset); 9263 } 9264 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9265 xmlBufContent(target))); 9266 xmlBufFree(target); 9267 } 9268 xmlXPathReleaseObject(ctxt->context, str); 9269 xmlXPathReleaseObject(ctxt->context, find); 9270 } 9271 9272 /** 9273 * xmlXPathSubstringAfterFunction: 9274 * @ctxt: the XPath Parser context 9275 * @nargs: the number of arguments 9276 * 9277 * Implement the substring-after() XPath function 9278 * string substring-after(string, string) 9279 * The substring-after function returns the substring of the first 9280 * argument string that follows the first occurrence of the second 9281 * argument string in the first argument string, or the empty stringi 9282 * if the first argument string does not contain the second argument 9283 * string. For example, substring-after("1999/04/01","/") returns 04/01, 9284 * and substring-after("1999/04/01","19") returns 99/04/01. 9285 */ 9286 void 9287 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9288 xmlXPathObjectPtr str; 9289 xmlXPathObjectPtr find; 9290 xmlBufPtr target; 9291 const xmlChar *point; 9292 int offset; 9293 9294 CHECK_ARITY(2); 9295 CAST_TO_STRING; 9296 find = valuePop(ctxt); 9297 CAST_TO_STRING; 9298 str = valuePop(ctxt); 9299 9300 target = xmlBufCreate(); 9301 if (target) { 9302 point = xmlStrstr(str->stringval, find->stringval); 9303 if (point) { 9304 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval); 9305 xmlBufAdd(target, &str->stringval[offset], 9306 xmlStrlen(str->stringval) - offset); 9307 } 9308 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9309 xmlBufContent(target))); 9310 xmlBufFree(target); 9311 } 9312 xmlXPathReleaseObject(ctxt->context, str); 9313 xmlXPathReleaseObject(ctxt->context, find); 9314 } 9315 9316 /** 9317 * xmlXPathNormalizeFunction: 9318 * @ctxt: the XPath Parser context 9319 * @nargs: the number of arguments 9320 * 9321 * Implement the normalize-space() XPath function 9322 * string normalize-space(string?) 9323 * The normalize-space function returns the argument string with white 9324 * space normalized by stripping leading and trailing whitespace 9325 * and replacing sequences of whitespace characters by a single 9326 * space. Whitespace characters are the same allowed by the S production 9327 * in XML. If the argument is omitted, it defaults to the context 9328 * node converted to a string, in other words the value of the context node. 9329 */ 9330 void 9331 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9332 xmlXPathObjectPtr obj = NULL; 9333 xmlChar *source = NULL; 9334 xmlBufPtr target; 9335 xmlChar blank; 9336 9337 if (ctxt == NULL) return; 9338 if (nargs == 0) { 9339 /* Use current context node */ 9340 valuePush(ctxt, 9341 xmlXPathCacheWrapString(ctxt->context, 9342 xmlXPathCastNodeToString(ctxt->context->node))); 9343 nargs = 1; 9344 } 9345 9346 CHECK_ARITY(1); 9347 CAST_TO_STRING; 9348 CHECK_TYPE(XPATH_STRING); 9349 obj = valuePop(ctxt); 9350 source = obj->stringval; 9351 9352 target = xmlBufCreate(); 9353 if (target && source) { 9354 9355 /* Skip leading whitespaces */ 9356 while (IS_BLANK_CH(*source)) 9357 source++; 9358 9359 /* Collapse intermediate whitespaces, and skip trailing whitespaces */ 9360 blank = 0; 9361 while (*source) { 9362 if (IS_BLANK_CH(*source)) { 9363 blank = 0x20; 9364 } else { 9365 if (blank) { 9366 xmlBufAdd(target, &blank, 1); 9367 blank = 0; 9368 } 9369 xmlBufAdd(target, source, 1); 9370 } 9371 source++; 9372 } 9373 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9374 xmlBufContent(target))); 9375 xmlBufFree(target); 9376 } 9377 xmlXPathReleaseObject(ctxt->context, obj); 9378 } 9379 9380 /** 9381 * xmlXPathTranslateFunction: 9382 * @ctxt: the XPath Parser context 9383 * @nargs: the number of arguments 9384 * 9385 * Implement the translate() XPath function 9386 * string translate(string, string, string) 9387 * The translate function returns the first argument string with 9388 * occurrences of characters in the second argument string replaced 9389 * by the character at the corresponding position in the third argument 9390 * string. For example, translate("bar","abc","ABC") returns the string 9391 * BAr. If there is a character in the second argument string with no 9392 * character at a corresponding position in the third argument string 9393 * (because the second argument string is longer than the third argument 9394 * string), then occurrences of that character in the first argument 9395 * string are removed. For example, translate("--aaa--","abc-","ABC") 9396 * returns "AAA". If a character occurs more than once in second 9397 * argument string, then the first occurrence determines the replacement 9398 * character. If the third argument string is longer than the second 9399 * argument string, then excess characters are ignored. 9400 */ 9401 void 9402 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9403 xmlXPathObjectPtr str; 9404 xmlXPathObjectPtr from; 9405 xmlXPathObjectPtr to; 9406 xmlBufPtr target; 9407 int offset, max; 9408 xmlChar ch; 9409 const xmlChar *point; 9410 xmlChar *cptr; 9411 9412 CHECK_ARITY(3); 9413 9414 CAST_TO_STRING; 9415 to = valuePop(ctxt); 9416 CAST_TO_STRING; 9417 from = valuePop(ctxt); 9418 CAST_TO_STRING; 9419 str = valuePop(ctxt); 9420 9421 target = xmlBufCreate(); 9422 if (target) { 9423 max = xmlUTF8Strlen(to->stringval); 9424 for (cptr = str->stringval; (ch=*cptr); ) { 9425 offset = xmlUTF8Strloc(from->stringval, cptr); 9426 if (offset >= 0) { 9427 if (offset < max) { 9428 point = xmlUTF8Strpos(to->stringval, offset); 9429 if (point) 9430 xmlBufAdd(target, point, xmlUTF8Strsize(point, 1)); 9431 } 9432 } else 9433 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1)); 9434 9435 /* Step to next character in input */ 9436 cptr++; 9437 if ( ch & 0x80 ) { 9438 /* if not simple ascii, verify proper format */ 9439 if ( (ch & 0xc0) != 0xc0 ) { 9440 xmlGenericError(xmlGenericErrorContext, 9441 "xmlXPathTranslateFunction: Invalid UTF8 string\n"); 9442 /* not asserting an XPath error is probably better */ 9443 break; 9444 } 9445 /* then skip over remaining bytes for this char */ 9446 while ( (ch <<= 1) & 0x80 ) 9447 if ( (*cptr++ & 0xc0) != 0x80 ) { 9448 xmlGenericError(xmlGenericErrorContext, 9449 "xmlXPathTranslateFunction: Invalid UTF8 string\n"); 9450 /* not asserting an XPath error is probably better */ 9451 break; 9452 } 9453 if (ch & 0x80) /* must have had error encountered */ 9454 break; 9455 } 9456 } 9457 } 9458 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9459 xmlBufContent(target))); 9460 xmlBufFree(target); 9461 xmlXPathReleaseObject(ctxt->context, str); 9462 xmlXPathReleaseObject(ctxt->context, from); 9463 xmlXPathReleaseObject(ctxt->context, to); 9464 } 9465 9466 /** 9467 * xmlXPathBooleanFunction: 9468 * @ctxt: the XPath Parser context 9469 * @nargs: the number of arguments 9470 * 9471 * Implement the boolean() XPath function 9472 * boolean boolean(object) 9473 * The boolean function converts its argument to a boolean as follows: 9474 * - a number is true if and only if it is neither positive or 9475 * negative zero nor NaN 9476 * - a node-set is true if and only if it is non-empty 9477 * - a string is true if and only if its length is non-zero 9478 */ 9479 void 9480 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9481 xmlXPathObjectPtr cur; 9482 9483 CHECK_ARITY(1); 9484 cur = valuePop(ctxt); 9485 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 9486 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur); 9487 valuePush(ctxt, cur); 9488 } 9489 9490 /** 9491 * xmlXPathNotFunction: 9492 * @ctxt: the XPath Parser context 9493 * @nargs: the number of arguments 9494 * 9495 * Implement the not() XPath function 9496 * boolean not(boolean) 9497 * The not function returns true if its argument is false, 9498 * and false otherwise. 9499 */ 9500 void 9501 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9502 CHECK_ARITY(1); 9503 CAST_TO_BOOLEAN; 9504 CHECK_TYPE(XPATH_BOOLEAN); 9505 ctxt->value->boolval = ! ctxt->value->boolval; 9506 } 9507 9508 /** 9509 * xmlXPathTrueFunction: 9510 * @ctxt: the XPath Parser context 9511 * @nargs: the number of arguments 9512 * 9513 * Implement the true() XPath function 9514 * boolean true() 9515 */ 9516 void 9517 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9518 CHECK_ARITY(0); 9519 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); 9520 } 9521 9522 /** 9523 * xmlXPathFalseFunction: 9524 * @ctxt: the XPath Parser context 9525 * @nargs: the number of arguments 9526 * 9527 * Implement the false() XPath function 9528 * boolean false() 9529 */ 9530 void 9531 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9532 CHECK_ARITY(0); 9533 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); 9534 } 9535 9536 /** 9537 * xmlXPathLangFunction: 9538 * @ctxt: the XPath Parser context 9539 * @nargs: the number of arguments 9540 * 9541 * Implement the lang() XPath function 9542 * boolean lang(string) 9543 * The lang function returns true or false depending on whether the 9544 * language of the context node as specified by xml:lang attributes 9545 * is the same as or is a sublanguage of the language specified by 9546 * the argument string. The language of the context node is determined 9547 * by the value of the xml:lang attribute on the context node, or, if 9548 * the context node has no xml:lang attribute, by the value of the 9549 * xml:lang attribute on the nearest ancestor of the context node that 9550 * has an xml:lang attribute. If there is no such attribute, then lang 9551 * returns false. If there is such an attribute, then lang returns 9552 * true if the attribute value is equal to the argument ignoring case, 9553 * or if there is some suffix starting with - such that the attribute 9554 * value is equal to the argument ignoring that suffix of the attribute 9555 * value and ignoring case. 9556 */ 9557 void 9558 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9559 xmlXPathObjectPtr val = NULL; 9560 const xmlChar *theLang = NULL; 9561 const xmlChar *lang; 9562 int ret = 0; 9563 int i; 9564 9565 CHECK_ARITY(1); 9566 CAST_TO_STRING; 9567 CHECK_TYPE(XPATH_STRING); 9568 val = valuePop(ctxt); 9569 lang = val->stringval; 9570 theLang = xmlNodeGetLang(ctxt->context->node); 9571 if ((theLang != NULL) && (lang != NULL)) { 9572 for (i = 0;lang[i] != 0;i++) 9573 if (toupper(lang[i]) != toupper(theLang[i])) 9574 goto not_equal; 9575 if ((theLang[i] == 0) || (theLang[i] == '-')) 9576 ret = 1; 9577 } 9578 not_equal: 9579 if (theLang != NULL) 9580 xmlFree((void *)theLang); 9581 9582 xmlXPathReleaseObject(ctxt->context, val); 9583 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret)); 9584 } 9585 9586 /** 9587 * xmlXPathNumberFunction: 9588 * @ctxt: the XPath Parser context 9589 * @nargs: the number of arguments 9590 * 9591 * Implement the number() XPath function 9592 * number number(object?) 9593 */ 9594 void 9595 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9596 xmlXPathObjectPtr cur; 9597 double res; 9598 9599 if (ctxt == NULL) return; 9600 if (nargs == 0) { 9601 if (ctxt->context->node == NULL) { 9602 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0)); 9603 } else { 9604 xmlChar* content = xmlNodeGetContent(ctxt->context->node); 9605 9606 res = xmlXPathStringEvalNumber(content); 9607 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res)); 9608 xmlFree(content); 9609 } 9610 return; 9611 } 9612 9613 CHECK_ARITY(1); 9614 cur = valuePop(ctxt); 9615 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur)); 9616 } 9617 9618 /** 9619 * xmlXPathSumFunction: 9620 * @ctxt: the XPath Parser context 9621 * @nargs: the number of arguments 9622 * 9623 * Implement the sum() XPath function 9624 * number sum(node-set) 9625 * The sum function returns the sum of the values of the nodes in 9626 * the argument node-set. 9627 */ 9628 void 9629 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9630 xmlXPathObjectPtr cur; 9631 int i; 9632 double res = 0.0; 9633 9634 CHECK_ARITY(1); 9635 if ((ctxt->value == NULL) || 9636 ((ctxt->value->type != XPATH_NODESET) && 9637 (ctxt->value->type != XPATH_XSLT_TREE))) 9638 XP_ERROR(XPATH_INVALID_TYPE); 9639 cur = valuePop(ctxt); 9640 9641 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) { 9642 for (i = 0; i < cur->nodesetval->nodeNr; i++) { 9643 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]); 9644 } 9645 } 9646 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res)); 9647 xmlXPathReleaseObject(ctxt->context, cur); 9648 } 9649 9650 /** 9651 * xmlXPathFloorFunction: 9652 * @ctxt: the XPath Parser context 9653 * @nargs: the number of arguments 9654 * 9655 * Implement the floor() XPath function 9656 * number floor(number) 9657 * The floor function returns the largest (closest to positive infinity) 9658 * number that is not greater than the argument and that is an integer. 9659 */ 9660 void 9661 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9662 CHECK_ARITY(1); 9663 CAST_TO_NUMBER; 9664 CHECK_TYPE(XPATH_NUMBER); 9665 9666 ctxt->value->floatval = floor(ctxt->value->floatval); 9667 } 9668 9669 /** 9670 * xmlXPathCeilingFunction: 9671 * @ctxt: the XPath Parser context 9672 * @nargs: the number of arguments 9673 * 9674 * Implement the ceiling() XPath function 9675 * number ceiling(number) 9676 * The ceiling function returns the smallest (closest to negative infinity) 9677 * number that is not less than the argument and that is an integer. 9678 */ 9679 void 9680 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9681 CHECK_ARITY(1); 9682 CAST_TO_NUMBER; 9683 CHECK_TYPE(XPATH_NUMBER); 9684 9685 ctxt->value->floatval = ceil(ctxt->value->floatval); 9686 } 9687 9688 /** 9689 * xmlXPathRoundFunction: 9690 * @ctxt: the XPath Parser context 9691 * @nargs: the number of arguments 9692 * 9693 * Implement the round() XPath function 9694 * number round(number) 9695 * The round function returns the number that is closest to the 9696 * argument and that is an integer. If there are two such numbers, 9697 * then the one that is closest to positive infinity is returned. 9698 */ 9699 void 9700 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9701 double f; 9702 9703 CHECK_ARITY(1); 9704 CAST_TO_NUMBER; 9705 CHECK_TYPE(XPATH_NUMBER); 9706 9707 f = ctxt->value->floatval; 9708 9709 if ((f >= -0.5) && (f < 0.5)) { 9710 /* Handles negative zero. */ 9711 ctxt->value->floatval *= 0.0; 9712 } 9713 else { 9714 double rounded = floor(f); 9715 if (f - rounded >= 0.5) 9716 rounded += 1.0; 9717 ctxt->value->floatval = rounded; 9718 } 9719 } 9720 9721 /************************************************************************ 9722 * * 9723 * The Parser * 9724 * * 9725 ************************************************************************/ 9726 9727 /* 9728 * a few forward declarations since we use a recursive call based 9729 * implementation. 9730 */ 9731 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort); 9732 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter); 9733 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt); 9734 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt); 9735 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, 9736 int qualified); 9737 9738 /** 9739 * xmlXPathCurrentChar: 9740 * @ctxt: the XPath parser context 9741 * @cur: pointer to the beginning of the char 9742 * @len: pointer to the length of the char read 9743 * 9744 * The current char value, if using UTF-8 this may actually span multiple 9745 * bytes in the input buffer. 9746 * 9747 * Returns the current char value and its length 9748 */ 9749 9750 static int 9751 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) { 9752 unsigned char c; 9753 unsigned int val; 9754 const xmlChar *cur; 9755 9756 if (ctxt == NULL) 9757 return(0); 9758 cur = ctxt->cur; 9759 9760 /* 9761 * We are supposed to handle UTF8, check it's valid 9762 * From rfc2044: encoding of the Unicode values on UTF-8: 9763 * 9764 * UCS-4 range (hex.) UTF-8 octet sequence (binary) 9765 * 0000 0000-0000 007F 0xxxxxxx 9766 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx 9767 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx 9768 * 9769 * Check for the 0x110000 limit too 9770 */ 9771 c = *cur; 9772 if (c & 0x80) { 9773 if ((cur[1] & 0xc0) != 0x80) 9774 goto encoding_error; 9775 if ((c & 0xe0) == 0xe0) { 9776 9777 if ((cur[2] & 0xc0) != 0x80) 9778 goto encoding_error; 9779 if ((c & 0xf0) == 0xf0) { 9780 if (((c & 0xf8) != 0xf0) || 9781 ((cur[3] & 0xc0) != 0x80)) 9782 goto encoding_error; 9783 /* 4-byte code */ 9784 *len = 4; 9785 val = (cur[0] & 0x7) << 18; 9786 val |= (cur[1] & 0x3f) << 12; 9787 val |= (cur[2] & 0x3f) << 6; 9788 val |= cur[3] & 0x3f; 9789 } else { 9790 /* 3-byte code */ 9791 *len = 3; 9792 val = (cur[0] & 0xf) << 12; 9793 val |= (cur[1] & 0x3f) << 6; 9794 val |= cur[2] & 0x3f; 9795 } 9796 } else { 9797 /* 2-byte code */ 9798 *len = 2; 9799 val = (cur[0] & 0x1f) << 6; 9800 val |= cur[1] & 0x3f; 9801 } 9802 if (!IS_CHAR(val)) { 9803 XP_ERROR0(XPATH_INVALID_CHAR_ERROR); 9804 } 9805 return(val); 9806 } else { 9807 /* 1-byte code */ 9808 *len = 1; 9809 return((int) *cur); 9810 } 9811 encoding_error: 9812 /* 9813 * If we detect an UTF8 error that probably means that the 9814 * input encoding didn't get properly advertised in the 9815 * declaration header. Report the error and switch the encoding 9816 * to ISO-Latin-1 (if you don't like this policy, just declare the 9817 * encoding !) 9818 */ 9819 *len = 0; 9820 XP_ERROR0(XPATH_ENCODING_ERROR); 9821 } 9822 9823 /** 9824 * xmlXPathParseNCName: 9825 * @ctxt: the XPath Parser context 9826 * 9827 * parse an XML namespace non qualified name. 9828 * 9829 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)* 9830 * 9831 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' | 9832 * CombiningChar | Extender 9833 * 9834 * Returns the namespace name or NULL 9835 */ 9836 9837 xmlChar * 9838 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) { 9839 const xmlChar *in; 9840 xmlChar *ret; 9841 int count = 0; 9842 9843 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL); 9844 /* 9845 * Accelerator for simple ASCII names 9846 */ 9847 in = ctxt->cur; 9848 if (((*in >= 0x61) && (*in <= 0x7A)) || 9849 ((*in >= 0x41) && (*in <= 0x5A)) || 9850 (*in == '_')) { 9851 in++; 9852 while (((*in >= 0x61) && (*in <= 0x7A)) || 9853 ((*in >= 0x41) && (*in <= 0x5A)) || 9854 ((*in >= 0x30) && (*in <= 0x39)) || 9855 (*in == '_') || (*in == '.') || 9856 (*in == '-')) 9857 in++; 9858 if ((*in == ' ') || (*in == '>') || (*in == '/') || 9859 (*in == '[') || (*in == ']') || (*in == ':') || 9860 (*in == '@') || (*in == '*')) { 9861 count = in - ctxt->cur; 9862 if (count == 0) 9863 return(NULL); 9864 ret = xmlStrndup(ctxt->cur, count); 9865 ctxt->cur = in; 9866 return(ret); 9867 } 9868 } 9869 return(xmlXPathParseNameComplex(ctxt, 0)); 9870 } 9871 9872 9873 /** 9874 * xmlXPathParseQName: 9875 * @ctxt: the XPath Parser context 9876 * @prefix: a xmlChar ** 9877 * 9878 * parse an XML qualified name 9879 * 9880 * [NS 5] QName ::= (Prefix ':')? LocalPart 9881 * 9882 * [NS 6] Prefix ::= NCName 9883 * 9884 * [NS 7] LocalPart ::= NCName 9885 * 9886 * Returns the function returns the local part, and prefix is updated 9887 * to get the Prefix if any. 9888 */ 9889 9890 static xmlChar * 9891 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) { 9892 xmlChar *ret = NULL; 9893 9894 *prefix = NULL; 9895 ret = xmlXPathParseNCName(ctxt); 9896 if (ret && CUR == ':') { 9897 *prefix = ret; 9898 NEXT; 9899 ret = xmlXPathParseNCName(ctxt); 9900 } 9901 return(ret); 9902 } 9903 9904 /** 9905 * xmlXPathParseName: 9906 * @ctxt: the XPath Parser context 9907 * 9908 * parse an XML name 9909 * 9910 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | 9911 * CombiningChar | Extender 9912 * 9913 * [5] Name ::= (Letter | '_' | ':') (NameChar)* 9914 * 9915 * Returns the namespace name or NULL 9916 */ 9917 9918 xmlChar * 9919 xmlXPathParseName(xmlXPathParserContextPtr ctxt) { 9920 const xmlChar *in; 9921 xmlChar *ret; 9922 size_t count = 0; 9923 9924 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL); 9925 /* 9926 * Accelerator for simple ASCII names 9927 */ 9928 in = ctxt->cur; 9929 if (((*in >= 0x61) && (*in <= 0x7A)) || 9930 ((*in >= 0x41) && (*in <= 0x5A)) || 9931 (*in == '_') || (*in == ':')) { 9932 in++; 9933 while (((*in >= 0x61) && (*in <= 0x7A)) || 9934 ((*in >= 0x41) && (*in <= 0x5A)) || 9935 ((*in >= 0x30) && (*in <= 0x39)) || 9936 (*in == '_') || (*in == '-') || 9937 (*in == ':') || (*in == '.')) 9938 in++; 9939 if ((*in > 0) && (*in < 0x80)) { 9940 count = in - ctxt->cur; 9941 if (count > XML_MAX_NAME_LENGTH) { 9942 ctxt->cur = in; 9943 XP_ERRORNULL(XPATH_EXPR_ERROR); 9944 } 9945 ret = xmlStrndup(ctxt->cur, count); 9946 ctxt->cur = in; 9947 return(ret); 9948 } 9949 } 9950 return(xmlXPathParseNameComplex(ctxt, 1)); 9951 } 9952 9953 static xmlChar * 9954 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) { 9955 xmlChar buf[XML_MAX_NAMELEN + 5]; 9956 int len = 0, l; 9957 int c; 9958 9959 /* 9960 * Handler for more complex cases 9961 */ 9962 c = CUR_CHAR(l); 9963 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */ 9964 (c == '[') || (c == ']') || (c == '@') || /* accelerators */ 9965 (c == '*') || /* accelerators */ 9966 (!IS_LETTER(c) && (c != '_') && 9967 ((!qualified) || (c != ':')))) { 9968 return(NULL); 9969 } 9970 9971 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */ 9972 ((IS_LETTER(c)) || (IS_DIGIT(c)) || 9973 (c == '.') || (c == '-') || 9974 (c == '_') || ((qualified) && (c == ':')) || 9975 (IS_COMBINING(c)) || 9976 (IS_EXTENDER(c)))) { 9977 COPY_BUF(l,buf,len,c); 9978 NEXTL(l); 9979 c = CUR_CHAR(l); 9980 if (len >= XML_MAX_NAMELEN) { 9981 /* 9982 * Okay someone managed to make a huge name, so he's ready to pay 9983 * for the processing speed. 9984 */ 9985 xmlChar *buffer; 9986 int max = len * 2; 9987 9988 if (len > XML_MAX_NAME_LENGTH) { 9989 XP_ERRORNULL(XPATH_EXPR_ERROR); 9990 } 9991 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar)); 9992 if (buffer == NULL) { 9993 XP_ERRORNULL(XPATH_MEMORY_ERROR); 9994 } 9995 memcpy(buffer, buf, len); 9996 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */ 9997 (c == '.') || (c == '-') || 9998 (c == '_') || ((qualified) && (c == ':')) || 9999 (IS_COMBINING(c)) || 10000 (IS_EXTENDER(c))) { 10001 if (len + 10 > max) { 10002 if (max > XML_MAX_NAME_LENGTH) { 10003 XP_ERRORNULL(XPATH_EXPR_ERROR); 10004 } 10005 max *= 2; 10006 buffer = (xmlChar *) xmlRealloc(buffer, 10007 max * sizeof(xmlChar)); 10008 if (buffer == NULL) { 10009 XP_ERRORNULL(XPATH_MEMORY_ERROR); 10010 } 10011 } 10012 COPY_BUF(l,buffer,len,c); 10013 NEXTL(l); 10014 c = CUR_CHAR(l); 10015 } 10016 buffer[len] = 0; 10017 return(buffer); 10018 } 10019 } 10020 if (len == 0) 10021 return(NULL); 10022 return(xmlStrndup(buf, len)); 10023 } 10024 10025 #define MAX_FRAC 20 10026 10027 /** 10028 * xmlXPathStringEvalNumber: 10029 * @str: A string to scan 10030 * 10031 * [30a] Float ::= Number ('e' Digits?)? 10032 * 10033 * [30] Number ::= Digits ('.' Digits?)? 10034 * | '.' Digits 10035 * [31] Digits ::= [0-9]+ 10036 * 10037 * Compile a Number in the string 10038 * In complement of the Number expression, this function also handles 10039 * negative values : '-' Number. 10040 * 10041 * Returns the double value. 10042 */ 10043 double 10044 xmlXPathStringEvalNumber(const xmlChar *str) { 10045 const xmlChar *cur = str; 10046 double ret; 10047 int ok = 0; 10048 int isneg = 0; 10049 int exponent = 0; 10050 int is_exponent_negative = 0; 10051 #ifdef __GNUC__ 10052 unsigned long tmp = 0; 10053 double temp; 10054 #endif 10055 if (cur == NULL) return(0); 10056 while (IS_BLANK_CH(*cur)) cur++; 10057 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) { 10058 return(NAN); 10059 } 10060 if (*cur == '-') { 10061 isneg = 1; 10062 cur++; 10063 } 10064 10065 #ifdef __GNUC__ 10066 /* 10067 * tmp/temp is a workaround against a gcc compiler bug 10068 * http://veillard.com/gcc.bug 10069 */ 10070 ret = 0; 10071 while ((*cur >= '0') && (*cur <= '9')) { 10072 ret = ret * 10; 10073 tmp = (*cur - '0'); 10074 ok = 1; 10075 cur++; 10076 temp = (double) tmp; 10077 ret = ret + temp; 10078 } 10079 #else 10080 ret = 0; 10081 while ((*cur >= '0') && (*cur <= '9')) { 10082 ret = ret * 10 + (*cur - '0'); 10083 ok = 1; 10084 cur++; 10085 } 10086 #endif 10087 10088 if (*cur == '.') { 10089 int v, frac = 0, max; 10090 double fraction = 0; 10091 10092 cur++; 10093 if (((*cur < '0') || (*cur > '9')) && (!ok)) { 10094 return(NAN); 10095 } 10096 while (*cur == '0') { 10097 frac = frac + 1; 10098 cur++; 10099 } 10100 max = frac + MAX_FRAC; 10101 while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) { 10102 v = (*cur - '0'); 10103 fraction = fraction * 10 + v; 10104 frac = frac + 1; 10105 cur++; 10106 } 10107 fraction /= pow(10.0, frac); 10108 ret = ret + fraction; 10109 while ((*cur >= '0') && (*cur <= '9')) 10110 cur++; 10111 } 10112 if ((*cur == 'e') || (*cur == 'E')) { 10113 cur++; 10114 if (*cur == '-') { 10115 is_exponent_negative = 1; 10116 cur++; 10117 } else if (*cur == '+') { 10118 cur++; 10119 } 10120 while ((*cur >= '0') && (*cur <= '9')) { 10121 if (exponent < 1000000) 10122 exponent = exponent * 10 + (*cur - '0'); 10123 cur++; 10124 } 10125 } 10126 while (IS_BLANK_CH(*cur)) cur++; 10127 if (*cur != 0) return(NAN); 10128 if (isneg) ret = -ret; 10129 if (is_exponent_negative) exponent = -exponent; 10130 ret *= pow(10.0, (double)exponent); 10131 return(ret); 10132 } 10133 10134 /** 10135 * xmlXPathCompNumber: 10136 * @ctxt: the XPath Parser context 10137 * 10138 * [30] Number ::= Digits ('.' Digits?)? 10139 * | '.' Digits 10140 * [31] Digits ::= [0-9]+ 10141 * 10142 * Compile a Number, then push it on the stack 10143 * 10144 */ 10145 static void 10146 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt) 10147 { 10148 double ret = 0.0; 10149 int ok = 0; 10150 int exponent = 0; 10151 int is_exponent_negative = 0; 10152 #ifdef __GNUC__ 10153 unsigned long tmp = 0; 10154 double temp; 10155 #endif 10156 10157 CHECK_ERROR; 10158 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) { 10159 XP_ERROR(XPATH_NUMBER_ERROR); 10160 } 10161 #ifdef __GNUC__ 10162 /* 10163 * tmp/temp is a workaround against a gcc compiler bug 10164 * http://veillard.com/gcc.bug 10165 */ 10166 ret = 0; 10167 while ((CUR >= '0') && (CUR <= '9')) { 10168 ret = ret * 10; 10169 tmp = (CUR - '0'); 10170 ok = 1; 10171 NEXT; 10172 temp = (double) tmp; 10173 ret = ret + temp; 10174 } 10175 #else 10176 ret = 0; 10177 while ((CUR >= '0') && (CUR <= '9')) { 10178 ret = ret * 10 + (CUR - '0'); 10179 ok = 1; 10180 NEXT; 10181 } 10182 #endif 10183 if (CUR == '.') { 10184 int v, frac = 0, max; 10185 double fraction = 0; 10186 10187 NEXT; 10188 if (((CUR < '0') || (CUR > '9')) && (!ok)) { 10189 XP_ERROR(XPATH_NUMBER_ERROR); 10190 } 10191 while (CUR == '0') { 10192 frac = frac + 1; 10193 NEXT; 10194 } 10195 max = frac + MAX_FRAC; 10196 while ((CUR >= '0') && (CUR <= '9') && (frac < max)) { 10197 v = (CUR - '0'); 10198 fraction = fraction * 10 + v; 10199 frac = frac + 1; 10200 NEXT; 10201 } 10202 fraction /= pow(10.0, frac); 10203 ret = ret + fraction; 10204 while ((CUR >= '0') && (CUR <= '9')) 10205 NEXT; 10206 } 10207 if ((CUR == 'e') || (CUR == 'E')) { 10208 NEXT; 10209 if (CUR == '-') { 10210 is_exponent_negative = 1; 10211 NEXT; 10212 } else if (CUR == '+') { 10213 NEXT; 10214 } 10215 while ((CUR >= '0') && (CUR <= '9')) { 10216 if (exponent < 1000000) 10217 exponent = exponent * 10 + (CUR - '0'); 10218 NEXT; 10219 } 10220 if (is_exponent_negative) 10221 exponent = -exponent; 10222 ret *= pow(10.0, (double) exponent); 10223 } 10224 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, 10225 xmlXPathCacheNewFloat(ctxt->context, ret), NULL); 10226 } 10227 10228 /** 10229 * xmlXPathParseLiteral: 10230 * @ctxt: the XPath Parser context 10231 * 10232 * Parse a Literal 10233 * 10234 * [29] Literal ::= '"' [^"]* '"' 10235 * | "'" [^']* "'" 10236 * 10237 * Returns the value found or NULL in case of error 10238 */ 10239 static xmlChar * 10240 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) { 10241 const xmlChar *q; 10242 xmlChar *ret = NULL; 10243 10244 if (CUR == '"') { 10245 NEXT; 10246 q = CUR_PTR; 10247 while ((IS_CHAR_CH(CUR)) && (CUR != '"')) 10248 NEXT; 10249 if (!IS_CHAR_CH(CUR)) { 10250 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR); 10251 } else { 10252 ret = xmlStrndup(q, CUR_PTR - q); 10253 NEXT; 10254 } 10255 } else if (CUR == '\'') { 10256 NEXT; 10257 q = CUR_PTR; 10258 while ((IS_CHAR_CH(CUR)) && (CUR != '\'')) 10259 NEXT; 10260 if (!IS_CHAR_CH(CUR)) { 10261 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR); 10262 } else { 10263 ret = xmlStrndup(q, CUR_PTR - q); 10264 NEXT; 10265 } 10266 } else { 10267 XP_ERRORNULL(XPATH_START_LITERAL_ERROR); 10268 } 10269 return(ret); 10270 } 10271 10272 /** 10273 * xmlXPathCompLiteral: 10274 * @ctxt: the XPath Parser context 10275 * 10276 * Parse a Literal and push it on the stack. 10277 * 10278 * [29] Literal ::= '"' [^"]* '"' 10279 * | "'" [^']* "'" 10280 * 10281 * TODO: xmlXPathCompLiteral memory allocation could be improved. 10282 */ 10283 static void 10284 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) { 10285 const xmlChar *q; 10286 xmlChar *ret = NULL; 10287 10288 if (CUR == '"') { 10289 NEXT; 10290 q = CUR_PTR; 10291 while ((IS_CHAR_CH(CUR)) && (CUR != '"')) 10292 NEXT; 10293 if (!IS_CHAR_CH(CUR)) { 10294 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR); 10295 } else { 10296 ret = xmlStrndup(q, CUR_PTR - q); 10297 NEXT; 10298 } 10299 } else if (CUR == '\'') { 10300 NEXT; 10301 q = CUR_PTR; 10302 while ((IS_CHAR_CH(CUR)) && (CUR != '\'')) 10303 NEXT; 10304 if (!IS_CHAR_CH(CUR)) { 10305 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR); 10306 } else { 10307 ret = xmlStrndup(q, CUR_PTR - q); 10308 NEXT; 10309 } 10310 } else { 10311 XP_ERROR(XPATH_START_LITERAL_ERROR); 10312 } 10313 if (ret == NULL) return; 10314 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, 10315 xmlXPathCacheNewString(ctxt->context, ret), NULL); 10316 xmlFree(ret); 10317 } 10318 10319 /** 10320 * xmlXPathCompVariableReference: 10321 * @ctxt: the XPath Parser context 10322 * 10323 * Parse a VariableReference, evaluate it and push it on the stack. 10324 * 10325 * The variable bindings consist of a mapping from variable names 10326 * to variable values. The value of a variable is an object, which can be 10327 * of any of the types that are possible for the value of an expression, 10328 * and may also be of additional types not specified here. 10329 * 10330 * Early evaluation is possible since: 10331 * The variable bindings [...] used to evaluate a subexpression are 10332 * always the same as those used to evaluate the containing expression. 10333 * 10334 * [36] VariableReference ::= '$' QName 10335 */ 10336 static void 10337 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) { 10338 xmlChar *name; 10339 xmlChar *prefix; 10340 10341 SKIP_BLANKS; 10342 if (CUR != '$') { 10343 XP_ERROR(XPATH_VARIABLE_REF_ERROR); 10344 } 10345 NEXT; 10346 name = xmlXPathParseQName(ctxt, &prefix); 10347 if (name == NULL) { 10348 xmlFree(prefix); 10349 XP_ERROR(XPATH_VARIABLE_REF_ERROR); 10350 } 10351 ctxt->comp->last = -1; 10352 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, 10353 name, prefix); 10354 SKIP_BLANKS; 10355 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) { 10356 XP_ERROR(XPATH_FORBID_VARIABLE_ERROR); 10357 } 10358 } 10359 10360 /** 10361 * xmlXPathIsNodeType: 10362 * @name: a name string 10363 * 10364 * Is the name given a NodeType one. 10365 * 10366 * [38] NodeType ::= 'comment' 10367 * | 'text' 10368 * | 'processing-instruction' 10369 * | 'node' 10370 * 10371 * Returns 1 if true 0 otherwise 10372 */ 10373 int 10374 xmlXPathIsNodeType(const xmlChar *name) { 10375 if (name == NULL) 10376 return(0); 10377 10378 if (xmlStrEqual(name, BAD_CAST "node")) 10379 return(1); 10380 if (xmlStrEqual(name, BAD_CAST "text")) 10381 return(1); 10382 if (xmlStrEqual(name, BAD_CAST "comment")) 10383 return(1); 10384 if (xmlStrEqual(name, BAD_CAST "processing-instruction")) 10385 return(1); 10386 return(0); 10387 } 10388 10389 /** 10390 * xmlXPathCompFunctionCall: 10391 * @ctxt: the XPath Parser context 10392 * 10393 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')' 10394 * [17] Argument ::= Expr 10395 * 10396 * Compile a function call, the evaluation of all arguments are 10397 * pushed on the stack 10398 */ 10399 static void 10400 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) { 10401 xmlChar *name; 10402 xmlChar *prefix; 10403 int nbargs = 0; 10404 int sort = 1; 10405 10406 name = xmlXPathParseQName(ctxt, &prefix); 10407 if (name == NULL) { 10408 xmlFree(prefix); 10409 XP_ERROR(XPATH_EXPR_ERROR); 10410 } 10411 SKIP_BLANKS; 10412 #ifdef DEBUG_EXPR 10413 if (prefix == NULL) 10414 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n", 10415 name); 10416 else 10417 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n", 10418 prefix, name); 10419 #endif 10420 10421 if (CUR != '(') { 10422 xmlFree(name); 10423 xmlFree(prefix); 10424 XP_ERROR(XPATH_EXPR_ERROR); 10425 } 10426 NEXT; 10427 SKIP_BLANKS; 10428 10429 /* 10430 * Optimization for count(): we don't need the node-set to be sorted. 10431 */ 10432 if ((prefix == NULL) && (name[0] == 'c') && 10433 xmlStrEqual(name, BAD_CAST "count")) 10434 { 10435 sort = 0; 10436 } 10437 ctxt->comp->last = -1; 10438 if (CUR != ')') { 10439 while (CUR != 0) { 10440 int op1 = ctxt->comp->last; 10441 ctxt->comp->last = -1; 10442 xmlXPathCompileExpr(ctxt, sort); 10443 if (ctxt->error != XPATH_EXPRESSION_OK) { 10444 xmlFree(name); 10445 xmlFree(prefix); 10446 return; 10447 } 10448 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0); 10449 nbargs++; 10450 if (CUR == ')') break; 10451 if (CUR != ',') { 10452 xmlFree(name); 10453 xmlFree(prefix); 10454 XP_ERROR(XPATH_EXPR_ERROR); 10455 } 10456 NEXT; 10457 SKIP_BLANKS; 10458 } 10459 } 10460 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, 10461 name, prefix); 10462 NEXT; 10463 SKIP_BLANKS; 10464 } 10465 10466 /** 10467 * xmlXPathCompPrimaryExpr: 10468 * @ctxt: the XPath Parser context 10469 * 10470 * [15] PrimaryExpr ::= VariableReference 10471 * | '(' Expr ')' 10472 * | Literal 10473 * | Number 10474 * | FunctionCall 10475 * 10476 * Compile a primary expression. 10477 */ 10478 static void 10479 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) { 10480 SKIP_BLANKS; 10481 if (CUR == '$') xmlXPathCompVariableReference(ctxt); 10482 else if (CUR == '(') { 10483 NEXT; 10484 SKIP_BLANKS; 10485 xmlXPathCompileExpr(ctxt, 1); 10486 CHECK_ERROR; 10487 if (CUR != ')') { 10488 XP_ERROR(XPATH_EXPR_ERROR); 10489 } 10490 NEXT; 10491 SKIP_BLANKS; 10492 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) { 10493 xmlXPathCompNumber(ctxt); 10494 } else if ((CUR == '\'') || (CUR == '"')) { 10495 xmlXPathCompLiteral(ctxt); 10496 } else { 10497 xmlXPathCompFunctionCall(ctxt); 10498 } 10499 SKIP_BLANKS; 10500 } 10501 10502 /** 10503 * xmlXPathCompFilterExpr: 10504 * @ctxt: the XPath Parser context 10505 * 10506 * [20] FilterExpr ::= PrimaryExpr 10507 * | FilterExpr Predicate 10508 * 10509 * Compile a filter expression. 10510 * Square brackets are used to filter expressions in the same way that 10511 * they are used in location paths. It is an error if the expression to 10512 * be filtered does not evaluate to a node-set. The context node list 10513 * used for evaluating the expression in square brackets is the node-set 10514 * to be filtered listed in document order. 10515 */ 10516 10517 static void 10518 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) { 10519 xmlXPathCompPrimaryExpr(ctxt); 10520 CHECK_ERROR; 10521 SKIP_BLANKS; 10522 10523 while (CUR == '[') { 10524 xmlXPathCompPredicate(ctxt, 1); 10525 SKIP_BLANKS; 10526 } 10527 10528 10529 } 10530 10531 /** 10532 * xmlXPathScanName: 10533 * @ctxt: the XPath Parser context 10534 * 10535 * Trickery: parse an XML name but without consuming the input flow 10536 * Needed to avoid insanity in the parser state. 10537 * 10538 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | 10539 * CombiningChar | Extender 10540 * 10541 * [5] Name ::= (Letter | '_' | ':') (NameChar)* 10542 * 10543 * [6] Names ::= Name (S Name)* 10544 * 10545 * Returns the Name parsed or NULL 10546 */ 10547 10548 static xmlChar * 10549 xmlXPathScanName(xmlXPathParserContextPtr ctxt) { 10550 int len = 0, l; 10551 int c; 10552 const xmlChar *cur; 10553 xmlChar *ret; 10554 10555 cur = ctxt->cur; 10556 10557 c = CUR_CHAR(l); 10558 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */ 10559 (!IS_LETTER(c) && (c != '_') && 10560 (c != ':'))) { 10561 return(NULL); 10562 } 10563 10564 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */ 10565 ((IS_LETTER(c)) || (IS_DIGIT(c)) || 10566 (c == '.') || (c == '-') || 10567 (c == '_') || (c == ':') || 10568 (IS_COMBINING(c)) || 10569 (IS_EXTENDER(c)))) { 10570 len += l; 10571 NEXTL(l); 10572 c = CUR_CHAR(l); 10573 } 10574 ret = xmlStrndup(cur, ctxt->cur - cur); 10575 ctxt->cur = cur; 10576 return(ret); 10577 } 10578 10579 /** 10580 * xmlXPathCompPathExpr: 10581 * @ctxt: the XPath Parser context 10582 * 10583 * [19] PathExpr ::= LocationPath 10584 * | FilterExpr 10585 * | FilterExpr '/' RelativeLocationPath 10586 * | FilterExpr '//' RelativeLocationPath 10587 * 10588 * Compile a path expression. 10589 * The / operator and // operators combine an arbitrary expression 10590 * and a relative location path. It is an error if the expression 10591 * does not evaluate to a node-set. 10592 * The / operator does composition in the same way as when / is 10593 * used in a location path. As in location paths, // is short for 10594 * /descendant-or-self::node()/. 10595 */ 10596 10597 static void 10598 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) { 10599 int lc = 1; /* Should we branch to LocationPath ? */ 10600 xmlChar *name = NULL; /* we may have to preparse a name to find out */ 10601 10602 SKIP_BLANKS; 10603 if ((CUR == '$') || (CUR == '(') || 10604 (IS_ASCII_DIGIT(CUR)) || 10605 (CUR == '\'') || (CUR == '"') || 10606 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) { 10607 lc = 0; 10608 } else if (CUR == '*') { 10609 /* relative or absolute location path */ 10610 lc = 1; 10611 } else if (CUR == '/') { 10612 /* relative or absolute location path */ 10613 lc = 1; 10614 } else if (CUR == '@') { 10615 /* relative abbreviated attribute location path */ 10616 lc = 1; 10617 } else if (CUR == '.') { 10618 /* relative abbreviated attribute location path */ 10619 lc = 1; 10620 } else { 10621 /* 10622 * Problem is finding if we have a name here whether it's: 10623 * - a nodetype 10624 * - a function call in which case it's followed by '(' 10625 * - an axis in which case it's followed by ':' 10626 * - a element name 10627 * We do an a priori analysis here rather than having to 10628 * maintain parsed token content through the recursive function 10629 * calls. This looks uglier but makes the code easier to 10630 * read/write/debug. 10631 */ 10632 SKIP_BLANKS; 10633 name = xmlXPathScanName(ctxt); 10634 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) { 10635 #ifdef DEBUG_STEP 10636 xmlGenericError(xmlGenericErrorContext, 10637 "PathExpr: Axis\n"); 10638 #endif 10639 lc = 1; 10640 xmlFree(name); 10641 } else if (name != NULL) { 10642 int len =xmlStrlen(name); 10643 10644 10645 while (NXT(len) != 0) { 10646 if (NXT(len) == '/') { 10647 /* element name */ 10648 #ifdef DEBUG_STEP 10649 xmlGenericError(xmlGenericErrorContext, 10650 "PathExpr: AbbrRelLocation\n"); 10651 #endif 10652 lc = 1; 10653 break; 10654 } else if (IS_BLANK_CH(NXT(len))) { 10655 /* ignore blanks */ 10656 ; 10657 } else if (NXT(len) == ':') { 10658 #ifdef DEBUG_STEP 10659 xmlGenericError(xmlGenericErrorContext, 10660 "PathExpr: AbbrRelLocation\n"); 10661 #endif 10662 lc = 1; 10663 break; 10664 } else if ((NXT(len) == '(')) { 10665 /* Node Type or Function */ 10666 if (xmlXPathIsNodeType(name)) { 10667 #ifdef DEBUG_STEP 10668 xmlGenericError(xmlGenericErrorContext, 10669 "PathExpr: Type search\n"); 10670 #endif 10671 lc = 1; 10672 #ifdef LIBXML_XPTR_ENABLED 10673 } else if (ctxt->xptr && 10674 xmlStrEqual(name, BAD_CAST "range-to")) { 10675 lc = 1; 10676 #endif 10677 } else { 10678 #ifdef DEBUG_STEP 10679 xmlGenericError(xmlGenericErrorContext, 10680 "PathExpr: function call\n"); 10681 #endif 10682 lc = 0; 10683 } 10684 break; 10685 } else if ((NXT(len) == '[')) { 10686 /* element name */ 10687 #ifdef DEBUG_STEP 10688 xmlGenericError(xmlGenericErrorContext, 10689 "PathExpr: AbbrRelLocation\n"); 10690 #endif 10691 lc = 1; 10692 break; 10693 } else if ((NXT(len) == '<') || (NXT(len) == '>') || 10694 (NXT(len) == '=')) { 10695 lc = 1; 10696 break; 10697 } else { 10698 lc = 1; 10699 break; 10700 } 10701 len++; 10702 } 10703 if (NXT(len) == 0) { 10704 #ifdef DEBUG_STEP 10705 xmlGenericError(xmlGenericErrorContext, 10706 "PathExpr: AbbrRelLocation\n"); 10707 #endif 10708 /* element name */ 10709 lc = 1; 10710 } 10711 xmlFree(name); 10712 } else { 10713 /* make sure all cases are covered explicitly */ 10714 XP_ERROR(XPATH_EXPR_ERROR); 10715 } 10716 } 10717 10718 if (lc) { 10719 if (CUR == '/') { 10720 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0); 10721 } else { 10722 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0); 10723 } 10724 xmlXPathCompLocationPath(ctxt); 10725 } else { 10726 xmlXPathCompFilterExpr(ctxt); 10727 CHECK_ERROR; 10728 if ((CUR == '/') && (NXT(1) == '/')) { 10729 SKIP(2); 10730 SKIP_BLANKS; 10731 10732 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 10733 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 10734 10735 xmlXPathCompRelativeLocationPath(ctxt); 10736 } else if (CUR == '/') { 10737 xmlXPathCompRelativeLocationPath(ctxt); 10738 } 10739 } 10740 SKIP_BLANKS; 10741 } 10742 10743 /** 10744 * xmlXPathCompUnionExpr: 10745 * @ctxt: the XPath Parser context 10746 * 10747 * [18] UnionExpr ::= PathExpr 10748 * | UnionExpr '|' PathExpr 10749 * 10750 * Compile an union expression. 10751 */ 10752 10753 static void 10754 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) { 10755 xmlXPathCompPathExpr(ctxt); 10756 CHECK_ERROR; 10757 SKIP_BLANKS; 10758 while (CUR == '|') { 10759 int op1 = ctxt->comp->last; 10760 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0); 10761 10762 NEXT; 10763 SKIP_BLANKS; 10764 xmlXPathCompPathExpr(ctxt); 10765 10766 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0); 10767 10768 SKIP_BLANKS; 10769 } 10770 } 10771 10772 /** 10773 * xmlXPathCompUnaryExpr: 10774 * @ctxt: the XPath Parser context 10775 * 10776 * [27] UnaryExpr ::= UnionExpr 10777 * | '-' UnaryExpr 10778 * 10779 * Compile an unary expression. 10780 */ 10781 10782 static void 10783 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) { 10784 int minus = 0; 10785 int found = 0; 10786 10787 SKIP_BLANKS; 10788 while (CUR == '-') { 10789 minus = 1 - minus; 10790 found = 1; 10791 NEXT; 10792 SKIP_BLANKS; 10793 } 10794 10795 xmlXPathCompUnionExpr(ctxt); 10796 CHECK_ERROR; 10797 if (found) { 10798 if (minus) 10799 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0); 10800 else 10801 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0); 10802 } 10803 } 10804 10805 /** 10806 * xmlXPathCompMultiplicativeExpr: 10807 * @ctxt: the XPath Parser context 10808 * 10809 * [26] MultiplicativeExpr ::= UnaryExpr 10810 * | MultiplicativeExpr MultiplyOperator UnaryExpr 10811 * | MultiplicativeExpr 'div' UnaryExpr 10812 * | MultiplicativeExpr 'mod' UnaryExpr 10813 * [34] MultiplyOperator ::= '*' 10814 * 10815 * Compile an Additive expression. 10816 */ 10817 10818 static void 10819 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) { 10820 xmlXPathCompUnaryExpr(ctxt); 10821 CHECK_ERROR; 10822 SKIP_BLANKS; 10823 while ((CUR == '*') || 10824 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) || 10825 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) { 10826 int op = -1; 10827 int op1 = ctxt->comp->last; 10828 10829 if (CUR == '*') { 10830 op = 0; 10831 NEXT; 10832 } else if (CUR == 'd') { 10833 op = 1; 10834 SKIP(3); 10835 } else if (CUR == 'm') { 10836 op = 2; 10837 SKIP(3); 10838 } 10839 SKIP_BLANKS; 10840 xmlXPathCompUnaryExpr(ctxt); 10841 CHECK_ERROR; 10842 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0); 10843 SKIP_BLANKS; 10844 } 10845 } 10846 10847 /** 10848 * xmlXPathCompAdditiveExpr: 10849 * @ctxt: the XPath Parser context 10850 * 10851 * [25] AdditiveExpr ::= MultiplicativeExpr 10852 * | AdditiveExpr '+' MultiplicativeExpr 10853 * | AdditiveExpr '-' MultiplicativeExpr 10854 * 10855 * Compile an Additive expression. 10856 */ 10857 10858 static void 10859 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) { 10860 10861 xmlXPathCompMultiplicativeExpr(ctxt); 10862 CHECK_ERROR; 10863 SKIP_BLANKS; 10864 while ((CUR == '+') || (CUR == '-')) { 10865 int plus; 10866 int op1 = ctxt->comp->last; 10867 10868 if (CUR == '+') plus = 1; 10869 else plus = 0; 10870 NEXT; 10871 SKIP_BLANKS; 10872 xmlXPathCompMultiplicativeExpr(ctxt); 10873 CHECK_ERROR; 10874 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0); 10875 SKIP_BLANKS; 10876 } 10877 } 10878 10879 /** 10880 * xmlXPathCompRelationalExpr: 10881 * @ctxt: the XPath Parser context 10882 * 10883 * [24] RelationalExpr ::= AdditiveExpr 10884 * | RelationalExpr '<' AdditiveExpr 10885 * | RelationalExpr '>' AdditiveExpr 10886 * | RelationalExpr '<=' AdditiveExpr 10887 * | RelationalExpr '>=' AdditiveExpr 10888 * 10889 * A <= B > C is allowed ? Answer from James, yes with 10890 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr 10891 * which is basically what got implemented. 10892 * 10893 * Compile a Relational expression, then push the result 10894 * on the stack 10895 */ 10896 10897 static void 10898 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) { 10899 xmlXPathCompAdditiveExpr(ctxt); 10900 CHECK_ERROR; 10901 SKIP_BLANKS; 10902 while ((CUR == '<') || 10903 (CUR == '>') || 10904 ((CUR == '<') && (NXT(1) == '=')) || 10905 ((CUR == '>') && (NXT(1) == '='))) { 10906 int inf, strict; 10907 int op1 = ctxt->comp->last; 10908 10909 if (CUR == '<') inf = 1; 10910 else inf = 0; 10911 if (NXT(1) == '=') strict = 0; 10912 else strict = 1; 10913 NEXT; 10914 if (!strict) NEXT; 10915 SKIP_BLANKS; 10916 xmlXPathCompAdditiveExpr(ctxt); 10917 CHECK_ERROR; 10918 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict); 10919 SKIP_BLANKS; 10920 } 10921 } 10922 10923 /** 10924 * xmlXPathCompEqualityExpr: 10925 * @ctxt: the XPath Parser context 10926 * 10927 * [23] EqualityExpr ::= RelationalExpr 10928 * | EqualityExpr '=' RelationalExpr 10929 * | EqualityExpr '!=' RelationalExpr 10930 * 10931 * A != B != C is allowed ? Answer from James, yes with 10932 * (RelationalExpr = RelationalExpr) = RelationalExpr 10933 * (RelationalExpr != RelationalExpr) != RelationalExpr 10934 * which is basically what got implemented. 10935 * 10936 * Compile an Equality expression. 10937 * 10938 */ 10939 static void 10940 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) { 10941 xmlXPathCompRelationalExpr(ctxt); 10942 CHECK_ERROR; 10943 SKIP_BLANKS; 10944 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) { 10945 int eq; 10946 int op1 = ctxt->comp->last; 10947 10948 if (CUR == '=') eq = 1; 10949 else eq = 0; 10950 NEXT; 10951 if (!eq) NEXT; 10952 SKIP_BLANKS; 10953 xmlXPathCompRelationalExpr(ctxt); 10954 CHECK_ERROR; 10955 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0); 10956 SKIP_BLANKS; 10957 } 10958 } 10959 10960 /** 10961 * xmlXPathCompAndExpr: 10962 * @ctxt: the XPath Parser context 10963 * 10964 * [22] AndExpr ::= EqualityExpr 10965 * | AndExpr 'and' EqualityExpr 10966 * 10967 * Compile an AND expression. 10968 * 10969 */ 10970 static void 10971 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) { 10972 xmlXPathCompEqualityExpr(ctxt); 10973 CHECK_ERROR; 10974 SKIP_BLANKS; 10975 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) { 10976 int op1 = ctxt->comp->last; 10977 SKIP(3); 10978 SKIP_BLANKS; 10979 xmlXPathCompEqualityExpr(ctxt); 10980 CHECK_ERROR; 10981 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0); 10982 SKIP_BLANKS; 10983 } 10984 } 10985 10986 /** 10987 * xmlXPathCompileExpr: 10988 * @ctxt: the XPath Parser context 10989 * 10990 * [14] Expr ::= OrExpr 10991 * [21] OrExpr ::= AndExpr 10992 * | OrExpr 'or' AndExpr 10993 * 10994 * Parse and compile an expression 10995 */ 10996 static void 10997 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) { 10998 xmlXPathCompAndExpr(ctxt); 10999 CHECK_ERROR; 11000 SKIP_BLANKS; 11001 while ((CUR == 'o') && (NXT(1) == 'r')) { 11002 int op1 = ctxt->comp->last; 11003 SKIP(2); 11004 SKIP_BLANKS; 11005 xmlXPathCompAndExpr(ctxt); 11006 CHECK_ERROR; 11007 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0); 11008 SKIP_BLANKS; 11009 } 11010 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) { 11011 /* more ops could be optimized too */ 11012 /* 11013 * This is the main place to eliminate sorting for 11014 * operations which don't require a sorted node-set. 11015 * E.g. count(). 11016 */ 11017 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0); 11018 } 11019 } 11020 11021 /** 11022 * xmlXPathCompPredicate: 11023 * @ctxt: the XPath Parser context 11024 * @filter: act as a filter 11025 * 11026 * [8] Predicate ::= '[' PredicateExpr ']' 11027 * [9] PredicateExpr ::= Expr 11028 * 11029 * Compile a predicate expression 11030 */ 11031 static void 11032 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) { 11033 int op1 = ctxt->comp->last; 11034 11035 SKIP_BLANKS; 11036 if (CUR != '[') { 11037 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); 11038 } 11039 NEXT; 11040 SKIP_BLANKS; 11041 11042 ctxt->comp->last = -1; 11043 /* 11044 * This call to xmlXPathCompileExpr() will deactivate sorting 11045 * of the predicate result. 11046 * TODO: Sorting is still activated for filters, since I'm not 11047 * sure if needed. Normally sorting should not be needed, since 11048 * a filter can only diminish the number of items in a sequence, 11049 * but won't change its order; so if the initial sequence is sorted, 11050 * subsequent sorting is not needed. 11051 */ 11052 if (! filter) 11053 xmlXPathCompileExpr(ctxt, 0); 11054 else 11055 xmlXPathCompileExpr(ctxt, 1); 11056 CHECK_ERROR; 11057 11058 if (CUR != ']') { 11059 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); 11060 } 11061 11062 if (filter) 11063 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0); 11064 else 11065 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0); 11066 11067 NEXT; 11068 SKIP_BLANKS; 11069 } 11070 11071 /** 11072 * xmlXPathCompNodeTest: 11073 * @ctxt: the XPath Parser context 11074 * @test: pointer to a xmlXPathTestVal 11075 * @type: pointer to a xmlXPathTypeVal 11076 * @prefix: placeholder for a possible name prefix 11077 * 11078 * [7] NodeTest ::= NameTest 11079 * | NodeType '(' ')' 11080 * | 'processing-instruction' '(' Literal ')' 11081 * 11082 * [37] NameTest ::= '*' 11083 * | NCName ':' '*' 11084 * | QName 11085 * [38] NodeType ::= 'comment' 11086 * | 'text' 11087 * | 'processing-instruction' 11088 * | 'node' 11089 * 11090 * Returns the name found and updates @test, @type and @prefix appropriately 11091 */ 11092 static xmlChar * 11093 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test, 11094 xmlXPathTypeVal *type, const xmlChar **prefix, 11095 xmlChar *name) { 11096 int blanks; 11097 11098 if ((test == NULL) || (type == NULL) || (prefix == NULL)) { 11099 STRANGE; 11100 return(NULL); 11101 } 11102 *type = (xmlXPathTypeVal) 0; 11103 *test = (xmlXPathTestVal) 0; 11104 *prefix = NULL; 11105 SKIP_BLANKS; 11106 11107 if ((name == NULL) && (CUR == '*')) { 11108 /* 11109 * All elements 11110 */ 11111 NEXT; 11112 *test = NODE_TEST_ALL; 11113 return(NULL); 11114 } 11115 11116 if (name == NULL) 11117 name = xmlXPathParseNCName(ctxt); 11118 if (name == NULL) { 11119 XP_ERRORNULL(XPATH_EXPR_ERROR); 11120 } 11121 11122 blanks = IS_BLANK_CH(CUR); 11123 SKIP_BLANKS; 11124 if (CUR == '(') { 11125 NEXT; 11126 /* 11127 * NodeType or PI search 11128 */ 11129 if (xmlStrEqual(name, BAD_CAST "comment")) 11130 *type = NODE_TYPE_COMMENT; 11131 else if (xmlStrEqual(name, BAD_CAST "node")) 11132 *type = NODE_TYPE_NODE; 11133 else if (xmlStrEqual(name, BAD_CAST "processing-instruction")) 11134 *type = NODE_TYPE_PI; 11135 else if (xmlStrEqual(name, BAD_CAST "text")) 11136 *type = NODE_TYPE_TEXT; 11137 else { 11138 if (name != NULL) 11139 xmlFree(name); 11140 XP_ERRORNULL(XPATH_EXPR_ERROR); 11141 } 11142 11143 *test = NODE_TEST_TYPE; 11144 11145 SKIP_BLANKS; 11146 if (*type == NODE_TYPE_PI) { 11147 /* 11148 * Specific case: search a PI by name. 11149 */ 11150 if (name != NULL) 11151 xmlFree(name); 11152 name = NULL; 11153 if (CUR != ')') { 11154 name = xmlXPathParseLiteral(ctxt); 11155 CHECK_ERROR NULL; 11156 *test = NODE_TEST_PI; 11157 SKIP_BLANKS; 11158 } 11159 } 11160 if (CUR != ')') { 11161 if (name != NULL) 11162 xmlFree(name); 11163 XP_ERRORNULL(XPATH_UNCLOSED_ERROR); 11164 } 11165 NEXT; 11166 return(name); 11167 } 11168 *test = NODE_TEST_NAME; 11169 if ((!blanks) && (CUR == ':')) { 11170 NEXT; 11171 11172 /* 11173 * Since currently the parser context don't have a 11174 * namespace list associated: 11175 * The namespace name for this prefix can be computed 11176 * only at evaluation time. The compilation is done 11177 * outside of any context. 11178 */ 11179 #if 0 11180 *prefix = xmlXPathNsLookup(ctxt->context, name); 11181 if (name != NULL) 11182 xmlFree(name); 11183 if (*prefix == NULL) { 11184 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); 11185 } 11186 #else 11187 *prefix = name; 11188 #endif 11189 11190 if (CUR == '*') { 11191 /* 11192 * All elements 11193 */ 11194 NEXT; 11195 *test = NODE_TEST_ALL; 11196 return(NULL); 11197 } 11198 11199 name = xmlXPathParseNCName(ctxt); 11200 if (name == NULL) { 11201 XP_ERRORNULL(XPATH_EXPR_ERROR); 11202 } 11203 } 11204 return(name); 11205 } 11206 11207 /** 11208 * xmlXPathIsAxisName: 11209 * @name: a preparsed name token 11210 * 11211 * [6] AxisName ::= 'ancestor' 11212 * | 'ancestor-or-self' 11213 * | 'attribute' 11214 * | 'child' 11215 * | 'descendant' 11216 * | 'descendant-or-self' 11217 * | 'following' 11218 * | 'following-sibling' 11219 * | 'namespace' 11220 * | 'parent' 11221 * | 'preceding' 11222 * | 'preceding-sibling' 11223 * | 'self' 11224 * 11225 * Returns the axis or 0 11226 */ 11227 static xmlXPathAxisVal 11228 xmlXPathIsAxisName(const xmlChar *name) { 11229 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0; 11230 switch (name[0]) { 11231 case 'a': 11232 if (xmlStrEqual(name, BAD_CAST "ancestor")) 11233 ret = AXIS_ANCESTOR; 11234 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self")) 11235 ret = AXIS_ANCESTOR_OR_SELF; 11236 if (xmlStrEqual(name, BAD_CAST "attribute")) 11237 ret = AXIS_ATTRIBUTE; 11238 break; 11239 case 'c': 11240 if (xmlStrEqual(name, BAD_CAST "child")) 11241 ret = AXIS_CHILD; 11242 break; 11243 case 'd': 11244 if (xmlStrEqual(name, BAD_CAST "descendant")) 11245 ret = AXIS_DESCENDANT; 11246 if (xmlStrEqual(name, BAD_CAST "descendant-or-self")) 11247 ret = AXIS_DESCENDANT_OR_SELF; 11248 break; 11249 case 'f': 11250 if (xmlStrEqual(name, BAD_CAST "following")) 11251 ret = AXIS_FOLLOWING; 11252 if (xmlStrEqual(name, BAD_CAST "following-sibling")) 11253 ret = AXIS_FOLLOWING_SIBLING; 11254 break; 11255 case 'n': 11256 if (xmlStrEqual(name, BAD_CAST "namespace")) 11257 ret = AXIS_NAMESPACE; 11258 break; 11259 case 'p': 11260 if (xmlStrEqual(name, BAD_CAST "parent")) 11261 ret = AXIS_PARENT; 11262 if (xmlStrEqual(name, BAD_CAST "preceding")) 11263 ret = AXIS_PRECEDING; 11264 if (xmlStrEqual(name, BAD_CAST "preceding-sibling")) 11265 ret = AXIS_PRECEDING_SIBLING; 11266 break; 11267 case 's': 11268 if (xmlStrEqual(name, BAD_CAST "self")) 11269 ret = AXIS_SELF; 11270 break; 11271 } 11272 return(ret); 11273 } 11274 11275 /** 11276 * xmlXPathCompStep: 11277 * @ctxt: the XPath Parser context 11278 * 11279 * [4] Step ::= AxisSpecifier NodeTest Predicate* 11280 * | AbbreviatedStep 11281 * 11282 * [12] AbbreviatedStep ::= '.' | '..' 11283 * 11284 * [5] AxisSpecifier ::= AxisName '::' 11285 * | AbbreviatedAxisSpecifier 11286 * 11287 * [13] AbbreviatedAxisSpecifier ::= '@'? 11288 * 11289 * Modified for XPtr range support as: 11290 * 11291 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate* 11292 * | AbbreviatedStep 11293 * | 'range-to' '(' Expr ')' Predicate* 11294 * 11295 * Compile one step in a Location Path 11296 * A location step of . is short for self::node(). This is 11297 * particularly useful in conjunction with //. For example, the 11298 * location path .//para is short for 11299 * self::node()/descendant-or-self::node()/child::para 11300 * and so will select all para descendant elements of the context 11301 * node. 11302 * Similarly, a location step of .. is short for parent::node(). 11303 * For example, ../title is short for parent::node()/child::title 11304 * and so will select the title children of the parent of the context 11305 * node. 11306 */ 11307 static void 11308 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) { 11309 #ifdef LIBXML_XPTR_ENABLED 11310 int rangeto = 0; 11311 int op2 = -1; 11312 #endif 11313 11314 SKIP_BLANKS; 11315 if ((CUR == '.') && (NXT(1) == '.')) { 11316 SKIP(2); 11317 SKIP_BLANKS; 11318 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT, 11319 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11320 } else if (CUR == '.') { 11321 NEXT; 11322 SKIP_BLANKS; 11323 } else { 11324 xmlChar *name = NULL; 11325 const xmlChar *prefix = NULL; 11326 xmlXPathTestVal test = (xmlXPathTestVal) 0; 11327 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0; 11328 xmlXPathTypeVal type = (xmlXPathTypeVal) 0; 11329 int op1; 11330 11331 /* 11332 * The modification needed for XPointer change to the production 11333 */ 11334 #ifdef LIBXML_XPTR_ENABLED 11335 if (ctxt->xptr) { 11336 name = xmlXPathParseNCName(ctxt); 11337 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) { 11338 op2 = ctxt->comp->last; 11339 xmlFree(name); 11340 SKIP_BLANKS; 11341 if (CUR != '(') { 11342 XP_ERROR(XPATH_EXPR_ERROR); 11343 } 11344 NEXT; 11345 SKIP_BLANKS; 11346 11347 xmlXPathCompileExpr(ctxt, 1); 11348 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */ 11349 CHECK_ERROR; 11350 11351 SKIP_BLANKS; 11352 if (CUR != ')') { 11353 XP_ERROR(XPATH_EXPR_ERROR); 11354 } 11355 NEXT; 11356 rangeto = 1; 11357 goto eval_predicates; 11358 } 11359 } 11360 #endif 11361 if (CUR == '*') { 11362 axis = AXIS_CHILD; 11363 } else { 11364 if (name == NULL) 11365 name = xmlXPathParseNCName(ctxt); 11366 if (name != NULL) { 11367 axis = xmlXPathIsAxisName(name); 11368 if (axis != 0) { 11369 SKIP_BLANKS; 11370 if ((CUR == ':') && (NXT(1) == ':')) { 11371 SKIP(2); 11372 xmlFree(name); 11373 name = NULL; 11374 } else { 11375 /* an element name can conflict with an axis one :-\ */ 11376 axis = AXIS_CHILD; 11377 } 11378 } else { 11379 axis = AXIS_CHILD; 11380 } 11381 } else if (CUR == '@') { 11382 NEXT; 11383 axis = AXIS_ATTRIBUTE; 11384 } else { 11385 axis = AXIS_CHILD; 11386 } 11387 } 11388 11389 if (ctxt->error != XPATH_EXPRESSION_OK) { 11390 xmlFree(name); 11391 return; 11392 } 11393 11394 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name); 11395 if (test == 0) 11396 return; 11397 11398 if ((prefix != NULL) && (ctxt->context != NULL) && 11399 (ctxt->context->flags & XML_XPATH_CHECKNS)) { 11400 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) { 11401 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR); 11402 } 11403 } 11404 #ifdef DEBUG_STEP 11405 xmlGenericError(xmlGenericErrorContext, 11406 "Basis : computing new set\n"); 11407 #endif 11408 11409 #ifdef DEBUG_STEP 11410 xmlGenericError(xmlGenericErrorContext, "Basis : "); 11411 if (ctxt->value == NULL) 11412 xmlGenericError(xmlGenericErrorContext, "no value\n"); 11413 else if (ctxt->value->nodesetval == NULL) 11414 xmlGenericError(xmlGenericErrorContext, "Empty\n"); 11415 else 11416 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval); 11417 #endif 11418 11419 #ifdef LIBXML_XPTR_ENABLED 11420 eval_predicates: 11421 #endif 11422 op1 = ctxt->comp->last; 11423 ctxt->comp->last = -1; 11424 11425 SKIP_BLANKS; 11426 while (CUR == '[') { 11427 xmlXPathCompPredicate(ctxt, 0); 11428 } 11429 11430 #ifdef LIBXML_XPTR_ENABLED 11431 if (rangeto) { 11432 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0); 11433 } else 11434 #endif 11435 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis, 11436 test, type, (void *)prefix, (void *)name); 11437 11438 } 11439 #ifdef DEBUG_STEP 11440 xmlGenericError(xmlGenericErrorContext, "Step : "); 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(xmlGenericErrorContext, 11447 ctxt->value->nodesetval); 11448 #endif 11449 } 11450 11451 /** 11452 * xmlXPathCompRelativeLocationPath: 11453 * @ctxt: the XPath Parser context 11454 * 11455 * [3] RelativeLocationPath ::= Step 11456 * | RelativeLocationPath '/' Step 11457 * | AbbreviatedRelativeLocationPath 11458 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step 11459 * 11460 * Compile a relative location path. 11461 */ 11462 static void 11463 xmlXPathCompRelativeLocationPath 11464 (xmlXPathParserContextPtr ctxt) { 11465 SKIP_BLANKS; 11466 if ((CUR == '/') && (NXT(1) == '/')) { 11467 SKIP(2); 11468 SKIP_BLANKS; 11469 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 11470 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11471 } else if (CUR == '/') { 11472 NEXT; 11473 SKIP_BLANKS; 11474 } 11475 xmlXPathCompStep(ctxt); 11476 CHECK_ERROR; 11477 SKIP_BLANKS; 11478 while (CUR == '/') { 11479 if ((CUR == '/') && (NXT(1) == '/')) { 11480 SKIP(2); 11481 SKIP_BLANKS; 11482 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 11483 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11484 xmlXPathCompStep(ctxt); 11485 } else if (CUR == '/') { 11486 NEXT; 11487 SKIP_BLANKS; 11488 xmlXPathCompStep(ctxt); 11489 } 11490 SKIP_BLANKS; 11491 } 11492 } 11493 11494 /** 11495 * xmlXPathCompLocationPath: 11496 * @ctxt: the XPath Parser context 11497 * 11498 * [1] LocationPath ::= RelativeLocationPath 11499 * | AbsoluteLocationPath 11500 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath? 11501 * | AbbreviatedAbsoluteLocationPath 11502 * [10] AbbreviatedAbsoluteLocationPath ::= 11503 * '//' RelativeLocationPath 11504 * 11505 * Compile a location path 11506 * 11507 * // is short for /descendant-or-self::node()/. For example, 11508 * //para is short for /descendant-or-self::node()/child::para and 11509 * so will select any para element in the document (even a para element 11510 * that is a document element will be selected by //para since the 11511 * document element node is a child of the root node); div//para is 11512 * short for div/descendant-or-self::node()/child::para and so will 11513 * select all para descendants of div children. 11514 */ 11515 static void 11516 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) { 11517 SKIP_BLANKS; 11518 if (CUR != '/') { 11519 xmlXPathCompRelativeLocationPath(ctxt); 11520 } else { 11521 while (CUR == '/') { 11522 if ((CUR == '/') && (NXT(1) == '/')) { 11523 SKIP(2); 11524 SKIP_BLANKS; 11525 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 11526 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11527 xmlXPathCompRelativeLocationPath(ctxt); 11528 } else if (CUR == '/') { 11529 NEXT; 11530 SKIP_BLANKS; 11531 if ((CUR != 0 ) && 11532 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') || 11533 (CUR == '@') || (CUR == '*'))) 11534 xmlXPathCompRelativeLocationPath(ctxt); 11535 } 11536 CHECK_ERROR; 11537 } 11538 } 11539 } 11540 11541 /************************************************************************ 11542 * * 11543 * XPath precompiled expression evaluation * 11544 * * 11545 ************************************************************************/ 11546 11547 static int 11548 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op); 11549 11550 #ifdef DEBUG_STEP 11551 static void 11552 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op, 11553 int nbNodes) 11554 { 11555 xmlGenericError(xmlGenericErrorContext, "new step : "); 11556 switch (op->value) { 11557 case AXIS_ANCESTOR: 11558 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' "); 11559 break; 11560 case AXIS_ANCESTOR_OR_SELF: 11561 xmlGenericError(xmlGenericErrorContext, 11562 "axis 'ancestors-or-self' "); 11563 break; 11564 case AXIS_ATTRIBUTE: 11565 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' "); 11566 break; 11567 case AXIS_CHILD: 11568 xmlGenericError(xmlGenericErrorContext, "axis 'child' "); 11569 break; 11570 case AXIS_DESCENDANT: 11571 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' "); 11572 break; 11573 case AXIS_DESCENDANT_OR_SELF: 11574 xmlGenericError(xmlGenericErrorContext, 11575 "axis 'descendant-or-self' "); 11576 break; 11577 case AXIS_FOLLOWING: 11578 xmlGenericError(xmlGenericErrorContext, "axis 'following' "); 11579 break; 11580 case AXIS_FOLLOWING_SIBLING: 11581 xmlGenericError(xmlGenericErrorContext, 11582 "axis 'following-siblings' "); 11583 break; 11584 case AXIS_NAMESPACE: 11585 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' "); 11586 break; 11587 case AXIS_PARENT: 11588 xmlGenericError(xmlGenericErrorContext, "axis 'parent' "); 11589 break; 11590 case AXIS_PRECEDING: 11591 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' "); 11592 break; 11593 case AXIS_PRECEDING_SIBLING: 11594 xmlGenericError(xmlGenericErrorContext, 11595 "axis 'preceding-sibling' "); 11596 break; 11597 case AXIS_SELF: 11598 xmlGenericError(xmlGenericErrorContext, "axis 'self' "); 11599 break; 11600 } 11601 xmlGenericError(xmlGenericErrorContext, 11602 " context contains %d nodes\n", nbNodes); 11603 switch (op->value2) { 11604 case NODE_TEST_NONE: 11605 xmlGenericError(xmlGenericErrorContext, 11606 " searching for none !!!\n"); 11607 break; 11608 case NODE_TEST_TYPE: 11609 xmlGenericError(xmlGenericErrorContext, 11610 " searching for type %d\n", op->value3); 11611 break; 11612 case NODE_TEST_PI: 11613 xmlGenericError(xmlGenericErrorContext, 11614 " searching for PI !!!\n"); 11615 break; 11616 case NODE_TEST_ALL: 11617 xmlGenericError(xmlGenericErrorContext, 11618 " searching for *\n"); 11619 break; 11620 case NODE_TEST_NS: 11621 xmlGenericError(xmlGenericErrorContext, 11622 " searching for namespace %s\n", 11623 op->value5); 11624 break; 11625 case NODE_TEST_NAME: 11626 xmlGenericError(xmlGenericErrorContext, 11627 " searching for name %s\n", op->value5); 11628 if (op->value4) 11629 xmlGenericError(xmlGenericErrorContext, 11630 " with namespace %s\n", op->value4); 11631 break; 11632 } 11633 xmlGenericError(xmlGenericErrorContext, "Testing : "); 11634 } 11635 #endif /* DEBUG_STEP */ 11636 11637 static int 11638 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt, 11639 xmlXPathStepOpPtr op, 11640 xmlNodeSetPtr set, 11641 int contextSize, 11642 int hasNsNodes) 11643 { 11644 if (op->ch1 != -1) { 11645 xmlXPathCompExprPtr comp = ctxt->comp; 11646 /* 11647 * Process inner predicates first. 11648 */ 11649 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) { 11650 /* 11651 * TODO: raise an internal error. 11652 */ 11653 } 11654 contextSize = xmlXPathCompOpEvalPredicate(ctxt, 11655 &comp->steps[op->ch1], set, contextSize, hasNsNodes); 11656 CHECK_ERROR0; 11657 if (contextSize <= 0) 11658 return(0); 11659 } 11660 if (op->ch2 != -1) { 11661 xmlXPathContextPtr xpctxt = ctxt->context; 11662 xmlNodePtr contextNode, oldContextNode; 11663 xmlDocPtr oldContextDoc; 11664 int oldcs, oldpp; 11665 int i, res, contextPos = 0, newContextSize; 11666 xmlXPathStepOpPtr exprOp; 11667 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL; 11668 11669 #ifdef LIBXML_XPTR_ENABLED 11670 /* 11671 * URGENT TODO: Check the following: 11672 * We don't expect location sets if evaluating prediates, right? 11673 * Only filters should expect location sets, right? 11674 */ 11675 #endif 11676 /* 11677 * SPEC XPath 1.0: 11678 * "For each node in the node-set to be filtered, the 11679 * PredicateExpr is evaluated with that node as the 11680 * context node, with the number of nodes in the 11681 * node-set as the context size, and with the proximity 11682 * position of the node in the node-set with respect to 11683 * the axis as the context position;" 11684 * @oldset is the node-set" to be filtered. 11685 * 11686 * SPEC XPath 1.0: 11687 * "only predicates change the context position and 11688 * context size (see [2.4 Predicates])." 11689 * Example: 11690 * node-set context pos 11691 * nA 1 11692 * nB 2 11693 * nC 3 11694 * After applying predicate [position() > 1] : 11695 * node-set context pos 11696 * nB 1 11697 * nC 2 11698 */ 11699 oldContextNode = xpctxt->node; 11700 oldContextDoc = xpctxt->doc; 11701 oldcs = xpctxt->contextSize; 11702 oldpp = xpctxt->proximityPosition; 11703 /* 11704 * Get the expression of this predicate. 11705 */ 11706 exprOp = &ctxt->comp->steps[op->ch2]; 11707 newContextSize = 0; 11708 for (i = 0; i < set->nodeNr; i++) { 11709 if (set->nodeTab[i] == NULL) 11710 continue; 11711 11712 contextNode = set->nodeTab[i]; 11713 xpctxt->node = contextNode; 11714 xpctxt->contextSize = contextSize; 11715 xpctxt->proximityPosition = ++contextPos; 11716 11717 /* 11718 * Also set the xpath document in case things like 11719 * key() are evaluated in the predicate. 11720 */ 11721 if ((contextNode->type != XML_NAMESPACE_DECL) && 11722 (contextNode->doc != NULL)) 11723 xpctxt->doc = contextNode->doc; 11724 /* 11725 * Evaluate the predicate expression with 1 context node 11726 * at a time; this node is packaged into a node set; this 11727 * node set is handed over to the evaluation mechanism. 11728 */ 11729 if (contextObj == NULL) 11730 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode); 11731 else { 11732 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval, 11733 contextNode) < 0) { 11734 ctxt->error = XPATH_MEMORY_ERROR; 11735 goto evaluation_exit; 11736 } 11737 } 11738 11739 valuePush(ctxt, contextObj); 11740 11741 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1); 11742 11743 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) { 11744 xmlXPathNodeSetClear(set, hasNsNodes); 11745 newContextSize = 0; 11746 goto evaluation_exit; 11747 } 11748 11749 if (res != 0) { 11750 newContextSize++; 11751 } else { 11752 /* 11753 * Remove the entry from the initial node set. 11754 */ 11755 set->nodeTab[i] = NULL; 11756 if (contextNode->type == XML_NAMESPACE_DECL) 11757 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode); 11758 } 11759 if (ctxt->value == contextObj) { 11760 /* 11761 * Don't free the temporary XPath object holding the 11762 * context node, in order to avoid massive recreation 11763 * inside this loop. 11764 */ 11765 valuePop(ctxt); 11766 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes); 11767 } else { 11768 /* 11769 * TODO: The object was lost in the evaluation machinery. 11770 * Can this happen? Maybe in internal-error cases. 11771 */ 11772 contextObj = NULL; 11773 } 11774 } 11775 11776 if (contextObj != NULL) { 11777 if (ctxt->value == contextObj) 11778 valuePop(ctxt); 11779 xmlXPathReleaseObject(xpctxt, contextObj); 11780 } 11781 evaluation_exit: 11782 if (exprRes != NULL) 11783 xmlXPathReleaseObject(ctxt->context, exprRes); 11784 /* 11785 * Reset/invalidate the context. 11786 */ 11787 xpctxt->node = oldContextNode; 11788 xpctxt->doc = oldContextDoc; 11789 xpctxt->contextSize = oldcs; 11790 xpctxt->proximityPosition = oldpp; 11791 return(newContextSize); 11792 } 11793 return(contextSize); 11794 } 11795 11796 static int 11797 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt, 11798 xmlXPathStepOpPtr op, 11799 xmlNodeSetPtr set, 11800 int contextSize, 11801 int minPos, 11802 int maxPos, 11803 int hasNsNodes) 11804 { 11805 if (op->ch1 != -1) { 11806 xmlXPathCompExprPtr comp = ctxt->comp; 11807 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) { 11808 /* 11809 * TODO: raise an internal error. 11810 */ 11811 } 11812 contextSize = xmlXPathCompOpEvalPredicate(ctxt, 11813 &comp->steps[op->ch1], set, contextSize, hasNsNodes); 11814 CHECK_ERROR0; 11815 if (contextSize <= 0) 11816 return(0); 11817 } 11818 /* 11819 * Check if the node set contains a sufficient number of nodes for 11820 * the requested range. 11821 */ 11822 if (contextSize < minPos) { 11823 xmlXPathNodeSetClear(set, hasNsNodes); 11824 return(0); 11825 } 11826 if (op->ch2 == -1) { 11827 /* 11828 * TODO: Can this ever happen? 11829 */ 11830 return (contextSize); 11831 } else { 11832 xmlDocPtr oldContextDoc; 11833 int oldcs, oldpp; 11834 int i, pos = 0, newContextSize = 0, contextPos = 0, res; 11835 xmlXPathStepOpPtr exprOp; 11836 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL; 11837 xmlNodePtr oldContextNode, contextNode = NULL; 11838 xmlXPathContextPtr xpctxt = ctxt->context; 11839 int frame; 11840 11841 #ifdef LIBXML_XPTR_ENABLED 11842 /* 11843 * URGENT TODO: Check the following: 11844 * We don't expect location sets if evaluating prediates, right? 11845 * Only filters should expect location sets, right? 11846 */ 11847 #endif /* LIBXML_XPTR_ENABLED */ 11848 11849 /* 11850 * Save old context. 11851 */ 11852 oldContextNode = xpctxt->node; 11853 oldContextDoc = xpctxt->doc; 11854 oldcs = xpctxt->contextSize; 11855 oldpp = xpctxt->proximityPosition; 11856 /* 11857 * Get the expression of this predicate. 11858 */ 11859 exprOp = &ctxt->comp->steps[op->ch2]; 11860 for (i = 0; i < set->nodeNr; i++) { 11861 xmlXPathObjectPtr tmp; 11862 11863 if (set->nodeTab[i] == NULL) 11864 continue; 11865 11866 contextNode = set->nodeTab[i]; 11867 xpctxt->node = contextNode; 11868 xpctxt->contextSize = contextSize; 11869 xpctxt->proximityPosition = ++contextPos; 11870 11871 /* 11872 * Initialize the new set. 11873 * Also set the xpath document in case things like 11874 * key() evaluation are attempted on the predicate 11875 */ 11876 if ((contextNode->type != XML_NAMESPACE_DECL) && 11877 (contextNode->doc != NULL)) 11878 xpctxt->doc = contextNode->doc; 11879 /* 11880 * Evaluate the predicate expression with 1 context node 11881 * at a time; this node is packaged into a node set; this 11882 * node set is handed over to the evaluation mechanism. 11883 */ 11884 if (contextObj == NULL) 11885 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode); 11886 else { 11887 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval, 11888 contextNode) < 0) { 11889 ctxt->error = XPATH_MEMORY_ERROR; 11890 goto evaluation_exit; 11891 } 11892 } 11893 11894 valuePush(ctxt, contextObj); 11895 frame = xmlXPathSetFrame(ctxt); 11896 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1); 11897 xmlXPathPopFrame(ctxt, frame); 11898 tmp = valuePop(ctxt); 11899 11900 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) { 11901 while (tmp != contextObj) { 11902 /* 11903 * Free up the result 11904 * then pop off contextObj, which will be freed later 11905 */ 11906 xmlXPathReleaseObject(xpctxt, tmp); 11907 tmp = valuePop(ctxt); 11908 } 11909 goto evaluation_error; 11910 } 11911 /* push the result back onto the stack */ 11912 valuePush(ctxt, tmp); 11913 11914 if (res) 11915 pos++; 11916 11917 if (res && (pos >= minPos) && (pos <= maxPos)) { 11918 /* 11919 * Fits in the requested range. 11920 */ 11921 newContextSize++; 11922 if (minPos == maxPos) { 11923 /* 11924 * Only 1 node was requested. 11925 */ 11926 if (contextNode->type == XML_NAMESPACE_DECL) { 11927 /* 11928 * As always: take care of those nasty 11929 * namespace nodes. 11930 */ 11931 set->nodeTab[i] = NULL; 11932 } 11933 xmlXPathNodeSetClear(set, hasNsNodes); 11934 set->nodeNr = 1; 11935 set->nodeTab[0] = contextNode; 11936 goto evaluation_exit; 11937 } 11938 if (pos == maxPos) { 11939 /* 11940 * We are done. 11941 */ 11942 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes); 11943 goto evaluation_exit; 11944 } 11945 } else { 11946 /* 11947 * Remove the entry from the initial node set. 11948 */ 11949 set->nodeTab[i] = NULL; 11950 if (contextNode->type == XML_NAMESPACE_DECL) 11951 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode); 11952 } 11953 if (exprRes != NULL) { 11954 xmlXPathReleaseObject(ctxt->context, exprRes); 11955 exprRes = NULL; 11956 } 11957 if (ctxt->value == contextObj) { 11958 /* 11959 * Don't free the temporary XPath object holding the 11960 * context node, in order to avoid massive recreation 11961 * inside this loop. 11962 */ 11963 valuePop(ctxt); 11964 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes); 11965 } else { 11966 /* 11967 * The object was lost in the evaluation machinery. 11968 * Can this happen? Maybe in case of internal-errors. 11969 */ 11970 contextObj = NULL; 11971 } 11972 } 11973 goto evaluation_exit; 11974 11975 evaluation_error: 11976 xmlXPathNodeSetClear(set, hasNsNodes); 11977 newContextSize = 0; 11978 11979 evaluation_exit: 11980 if (contextObj != NULL) { 11981 if (ctxt->value == contextObj) 11982 valuePop(ctxt); 11983 xmlXPathReleaseObject(xpctxt, contextObj); 11984 } 11985 if (exprRes != NULL) 11986 xmlXPathReleaseObject(ctxt->context, exprRes); 11987 /* 11988 * Reset/invalidate the context. 11989 */ 11990 xpctxt->node = oldContextNode; 11991 xpctxt->doc = oldContextDoc; 11992 xpctxt->contextSize = oldcs; 11993 xpctxt->proximityPosition = oldpp; 11994 return(newContextSize); 11995 } 11996 return(contextSize); 11997 } 11998 11999 static int 12000 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt, 12001 xmlXPathStepOpPtr op, 12002 int *maxPos) 12003 { 12004 12005 xmlXPathStepOpPtr exprOp; 12006 12007 /* 12008 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet! 12009 */ 12010 12011 /* 12012 * If not -1, then ch1 will point to: 12013 * 1) For predicates (XPATH_OP_PREDICATE): 12014 * - an inner predicate operator 12015 * 2) For filters (XPATH_OP_FILTER): 12016 * - an inner filter operater OR 12017 * - an expression selecting the node set. 12018 * E.g. "key('a', 'b')" or "(//foo | //bar)". 12019 */ 12020 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER)) 12021 return(0); 12022 12023 if (op->ch2 != -1) { 12024 exprOp = &ctxt->comp->steps[op->ch2]; 12025 } else 12026 return(0); 12027 12028 if ((exprOp != NULL) && 12029 (exprOp->op == XPATH_OP_VALUE) && 12030 (exprOp->value4 != NULL) && 12031 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER)) 12032 { 12033 double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval; 12034 12035 /* 12036 * We have a "[n]" predicate here. 12037 * TODO: Unfortunately this simplistic test here is not 12038 * able to detect a position() predicate in compound 12039 * expressions like "[@attr = 'a" and position() = 1], 12040 * and even not the usage of position() in 12041 * "[position() = 1]"; thus - obviously - a position-range, 12042 * like it "[position() < 5]", is also not detected. 12043 * Maybe we could rewrite the AST to ease the optimization. 12044 */ 12045 12046 if ((floatval > INT_MIN) && (floatval < INT_MAX)) { 12047 *maxPos = (int) floatval; 12048 if (floatval == (double) *maxPos) 12049 return(1); 12050 } 12051 } 12052 return(0); 12053 } 12054 12055 static int 12056 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, 12057 xmlXPathStepOpPtr op, 12058 xmlNodePtr * first, xmlNodePtr * last, 12059 int toBool) 12060 { 12061 12062 #define XP_TEST_HIT \ 12063 if (hasAxisRange != 0) { \ 12064 if (++pos == maxPos) { \ 12065 if (addNode(seq, cur) < 0) \ 12066 ctxt->error = XPATH_MEMORY_ERROR; \ 12067 goto axis_range_end; } \ 12068 } else { \ 12069 if (addNode(seq, cur) < 0) \ 12070 ctxt->error = XPATH_MEMORY_ERROR; \ 12071 if (breakOnFirstHit) goto first_hit; } 12072 12073 #define XP_TEST_HIT_NS \ 12074 if (hasAxisRange != 0) { \ 12075 if (++pos == maxPos) { \ 12076 hasNsNodes = 1; \ 12077 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \ 12078 ctxt->error = XPATH_MEMORY_ERROR; \ 12079 goto axis_range_end; } \ 12080 } else { \ 12081 hasNsNodes = 1; \ 12082 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \ 12083 ctxt->error = XPATH_MEMORY_ERROR; \ 12084 if (breakOnFirstHit) goto first_hit; } 12085 12086 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value; 12087 xmlXPathTestVal test = (xmlXPathTestVal) op->value2; 12088 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3; 12089 const xmlChar *prefix = op->value4; 12090 const xmlChar *name = op->value5; 12091 const xmlChar *URI = NULL; 12092 12093 #ifdef DEBUG_STEP 12094 int nbMatches = 0, prevMatches = 0; 12095 #endif 12096 int total = 0, hasNsNodes = 0; 12097 /* The popped object holding the context nodes */ 12098 xmlXPathObjectPtr obj; 12099 /* The set of context nodes for the node tests */ 12100 xmlNodeSetPtr contextSeq; 12101 int contextIdx; 12102 xmlNodePtr contextNode; 12103 /* The final resulting node set wrt to all context nodes */ 12104 xmlNodeSetPtr outSeq; 12105 /* 12106 * The temporary resulting node set wrt 1 context node. 12107 * Used to feed predicate evaluation. 12108 */ 12109 xmlNodeSetPtr seq; 12110 xmlNodePtr cur; 12111 /* First predicate operator */ 12112 xmlXPathStepOpPtr predOp; 12113 int maxPos; /* The requested position() (when a "[n]" predicate) */ 12114 int hasPredicateRange, hasAxisRange, pos, size, newSize; 12115 int breakOnFirstHit; 12116 12117 xmlXPathTraversalFunction next = NULL; 12118 int (*addNode) (xmlNodeSetPtr, xmlNodePtr); 12119 xmlXPathNodeSetMergeFunction mergeAndClear; 12120 xmlNodePtr oldContextNode; 12121 xmlXPathContextPtr xpctxt = ctxt->context; 12122 12123 12124 CHECK_TYPE0(XPATH_NODESET); 12125 obj = valuePop(ctxt); 12126 /* 12127 * Setup namespaces. 12128 */ 12129 if (prefix != NULL) { 12130 URI = xmlXPathNsLookup(xpctxt, prefix); 12131 if (URI == NULL) { 12132 xmlXPathReleaseObject(xpctxt, obj); 12133 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); 12134 } 12135 } 12136 /* 12137 * Setup axis. 12138 * 12139 * MAYBE FUTURE TODO: merging optimizations: 12140 * - If the nodes to be traversed wrt to the initial nodes and 12141 * the current axis cannot overlap, then we could avoid searching 12142 * for duplicates during the merge. 12143 * But the question is how/when to evaluate if they cannot overlap. 12144 * Example: if we know that for two initial nodes, the one is 12145 * not in the ancestor-or-self axis of the other, then we could safely 12146 * avoid a duplicate-aware merge, if the axis to be traversed is e.g. 12147 * the descendant-or-self axis. 12148 */ 12149 mergeAndClear = xmlXPathNodeSetMergeAndClear; 12150 switch (axis) { 12151 case AXIS_ANCESTOR: 12152 first = NULL; 12153 next = xmlXPathNextAncestor; 12154 break; 12155 case AXIS_ANCESTOR_OR_SELF: 12156 first = NULL; 12157 next = xmlXPathNextAncestorOrSelf; 12158 break; 12159 case AXIS_ATTRIBUTE: 12160 first = NULL; 12161 last = NULL; 12162 next = xmlXPathNextAttribute; 12163 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12164 break; 12165 case AXIS_CHILD: 12166 last = NULL; 12167 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) && 12168 (type == NODE_TYPE_NODE)) 12169 { 12170 /* 12171 * Optimization if an element node type is 'element'. 12172 */ 12173 next = xmlXPathNextChildElement; 12174 } else 12175 next = xmlXPathNextChild; 12176 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12177 break; 12178 case AXIS_DESCENDANT: 12179 last = NULL; 12180 next = xmlXPathNextDescendant; 12181 break; 12182 case AXIS_DESCENDANT_OR_SELF: 12183 last = NULL; 12184 next = xmlXPathNextDescendantOrSelf; 12185 break; 12186 case AXIS_FOLLOWING: 12187 last = NULL; 12188 next = xmlXPathNextFollowing; 12189 break; 12190 case AXIS_FOLLOWING_SIBLING: 12191 last = NULL; 12192 next = xmlXPathNextFollowingSibling; 12193 break; 12194 case AXIS_NAMESPACE: 12195 first = NULL; 12196 last = NULL; 12197 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; 12198 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12199 break; 12200 case AXIS_PARENT: 12201 first = NULL; 12202 next = xmlXPathNextParent; 12203 break; 12204 case AXIS_PRECEDING: 12205 first = NULL; 12206 next = xmlXPathNextPrecedingInternal; 12207 break; 12208 case AXIS_PRECEDING_SIBLING: 12209 first = NULL; 12210 next = xmlXPathNextPrecedingSibling; 12211 break; 12212 case AXIS_SELF: 12213 first = NULL; 12214 last = NULL; 12215 next = xmlXPathNextSelf; 12216 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12217 break; 12218 } 12219 12220 #ifdef DEBUG_STEP 12221 xmlXPathDebugDumpStepAxis(op, 12222 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0); 12223 #endif 12224 12225 if (next == NULL) { 12226 xmlXPathReleaseObject(xpctxt, obj); 12227 return(0); 12228 } 12229 contextSeq = obj->nodesetval; 12230 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) { 12231 xmlXPathReleaseObject(xpctxt, obj); 12232 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL)); 12233 return(0); 12234 } 12235 /* 12236 * Predicate optimization --------------------------------------------- 12237 * If this step has a last predicate, which contains a position(), 12238 * then we'll optimize (although not exactly "position()", but only 12239 * the short-hand form, i.e., "[n]". 12240 * 12241 * Example - expression "/foo[parent::bar][1]": 12242 * 12243 * COLLECT 'child' 'name' 'node' foo -- op (we are here) 12244 * ROOT -- op->ch1 12245 * PREDICATE -- op->ch2 (predOp) 12246 * PREDICATE -- predOp->ch1 = [parent::bar] 12247 * SORT 12248 * COLLECT 'parent' 'name' 'node' bar 12249 * NODE 12250 * ELEM Object is a number : 1 -- predOp->ch2 = [1] 12251 * 12252 */ 12253 maxPos = 0; 12254 predOp = NULL; 12255 hasPredicateRange = 0; 12256 hasAxisRange = 0; 12257 if (op->ch2 != -1) { 12258 /* 12259 * There's at least one predicate. 16 == XPATH_OP_PREDICATE 12260 */ 12261 predOp = &ctxt->comp->steps[op->ch2]; 12262 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) { 12263 if (predOp->ch1 != -1) { 12264 /* 12265 * Use the next inner predicate operator. 12266 */ 12267 predOp = &ctxt->comp->steps[predOp->ch1]; 12268 hasPredicateRange = 1; 12269 } else { 12270 /* 12271 * There's no other predicate than the [n] predicate. 12272 */ 12273 predOp = NULL; 12274 hasAxisRange = 1; 12275 } 12276 } 12277 } 12278 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0; 12279 /* 12280 * Axis traversal ----------------------------------------------------- 12281 */ 12282 /* 12283 * 2.3 Node Tests 12284 * - For the attribute axis, the principal node type is attribute. 12285 * - For the namespace axis, the principal node type is namespace. 12286 * - For other axes, the principal node type is element. 12287 * 12288 * A node test * is true for any node of the 12289 * principal node type. For example, child::* will 12290 * select all element children of the context node 12291 */ 12292 oldContextNode = xpctxt->node; 12293 addNode = xmlXPathNodeSetAddUnique; 12294 outSeq = NULL; 12295 seq = NULL; 12296 contextNode = NULL; 12297 contextIdx = 0; 12298 12299 12300 while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) && 12301 (ctxt->error == XPATH_EXPRESSION_OK)) { 12302 xpctxt->node = contextSeq->nodeTab[contextIdx++]; 12303 12304 if (seq == NULL) { 12305 seq = xmlXPathNodeSetCreate(NULL); 12306 if (seq == NULL) { 12307 total = 0; 12308 goto error; 12309 } 12310 } 12311 /* 12312 * Traverse the axis and test the nodes. 12313 */ 12314 pos = 0; 12315 cur = NULL; 12316 hasNsNodes = 0; 12317 do { 12318 cur = next(ctxt, cur); 12319 if (cur == NULL) 12320 break; 12321 12322 /* 12323 * QUESTION TODO: What does the "first" and "last" stuff do? 12324 */ 12325 if ((first != NULL) && (*first != NULL)) { 12326 if (*first == cur) 12327 break; 12328 if (((total % 256) == 0) && 12329 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 12330 (xmlXPathCmpNodesExt(*first, cur) >= 0)) 12331 #else 12332 (xmlXPathCmpNodes(*first, cur) >= 0)) 12333 #endif 12334 { 12335 break; 12336 } 12337 } 12338 if ((last != NULL) && (*last != NULL)) { 12339 if (*last == cur) 12340 break; 12341 if (((total % 256) == 0) && 12342 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 12343 (xmlXPathCmpNodesExt(cur, *last) >= 0)) 12344 #else 12345 (xmlXPathCmpNodes(cur, *last) >= 0)) 12346 #endif 12347 { 12348 break; 12349 } 12350 } 12351 12352 total++; 12353 12354 #ifdef DEBUG_STEP 12355 xmlGenericError(xmlGenericErrorContext, " %s", cur->name); 12356 #endif 12357 12358 switch (test) { 12359 case NODE_TEST_NONE: 12360 total = 0; 12361 STRANGE 12362 goto error; 12363 case NODE_TEST_TYPE: 12364 if (type == NODE_TYPE_NODE) { 12365 switch (cur->type) { 12366 case XML_DOCUMENT_NODE: 12367 case XML_HTML_DOCUMENT_NODE: 12368 #ifdef LIBXML_DOCB_ENABLED 12369 case XML_DOCB_DOCUMENT_NODE: 12370 #endif 12371 case XML_ELEMENT_NODE: 12372 case XML_ATTRIBUTE_NODE: 12373 case XML_PI_NODE: 12374 case XML_COMMENT_NODE: 12375 case XML_CDATA_SECTION_NODE: 12376 case XML_TEXT_NODE: 12377 XP_TEST_HIT 12378 break; 12379 case XML_NAMESPACE_DECL: { 12380 if (axis == AXIS_NAMESPACE) { 12381 XP_TEST_HIT_NS 12382 } else { 12383 hasNsNodes = 1; 12384 XP_TEST_HIT 12385 } 12386 break; 12387 } 12388 default: 12389 break; 12390 } 12391 } else if (cur->type == (xmlElementType) type) { 12392 if (cur->type == XML_NAMESPACE_DECL) 12393 XP_TEST_HIT_NS 12394 else 12395 XP_TEST_HIT 12396 } else if ((type == NODE_TYPE_TEXT) && 12397 (cur->type == XML_CDATA_SECTION_NODE)) 12398 { 12399 XP_TEST_HIT 12400 } 12401 break; 12402 case NODE_TEST_PI: 12403 if ((cur->type == XML_PI_NODE) && 12404 ((name == NULL) || xmlStrEqual(name, cur->name))) 12405 { 12406 XP_TEST_HIT 12407 } 12408 break; 12409 case NODE_TEST_ALL: 12410 if (axis == AXIS_ATTRIBUTE) { 12411 if (cur->type == XML_ATTRIBUTE_NODE) 12412 { 12413 if (prefix == NULL) 12414 { 12415 XP_TEST_HIT 12416 } else if ((cur->ns != NULL) && 12417 (xmlStrEqual(URI, cur->ns->href))) 12418 { 12419 XP_TEST_HIT 12420 } 12421 } 12422 } else if (axis == AXIS_NAMESPACE) { 12423 if (cur->type == XML_NAMESPACE_DECL) 12424 { 12425 XP_TEST_HIT_NS 12426 } 12427 } else { 12428 if (cur->type == XML_ELEMENT_NODE) { 12429 if (prefix == NULL) 12430 { 12431 XP_TEST_HIT 12432 12433 } else if ((cur->ns != NULL) && 12434 (xmlStrEqual(URI, cur->ns->href))) 12435 { 12436 XP_TEST_HIT 12437 } 12438 } 12439 } 12440 break; 12441 case NODE_TEST_NS:{ 12442 TODO; 12443 break; 12444 } 12445 case NODE_TEST_NAME: 12446 if (axis == AXIS_ATTRIBUTE) { 12447 if (cur->type != XML_ATTRIBUTE_NODE) 12448 break; 12449 } else if (axis == AXIS_NAMESPACE) { 12450 if (cur->type != XML_NAMESPACE_DECL) 12451 break; 12452 } else { 12453 if (cur->type != XML_ELEMENT_NODE) 12454 break; 12455 } 12456 switch (cur->type) { 12457 case XML_ELEMENT_NODE: 12458 if (xmlStrEqual(name, cur->name)) { 12459 if (prefix == NULL) { 12460 if (cur->ns == NULL) 12461 { 12462 XP_TEST_HIT 12463 } 12464 } else { 12465 if ((cur->ns != NULL) && 12466 (xmlStrEqual(URI, cur->ns->href))) 12467 { 12468 XP_TEST_HIT 12469 } 12470 } 12471 } 12472 break; 12473 case XML_ATTRIBUTE_NODE:{ 12474 xmlAttrPtr attr = (xmlAttrPtr) cur; 12475 12476 if (xmlStrEqual(name, attr->name)) { 12477 if (prefix == NULL) { 12478 if ((attr->ns == NULL) || 12479 (attr->ns->prefix == NULL)) 12480 { 12481 XP_TEST_HIT 12482 } 12483 } else { 12484 if ((attr->ns != NULL) && 12485 (xmlStrEqual(URI, 12486 attr->ns->href))) 12487 { 12488 XP_TEST_HIT 12489 } 12490 } 12491 } 12492 break; 12493 } 12494 case XML_NAMESPACE_DECL: 12495 if (cur->type == XML_NAMESPACE_DECL) { 12496 xmlNsPtr ns = (xmlNsPtr) cur; 12497 12498 if ((ns->prefix != NULL) && (name != NULL) 12499 && (xmlStrEqual(ns->prefix, name))) 12500 { 12501 XP_TEST_HIT_NS 12502 } 12503 } 12504 break; 12505 default: 12506 break; 12507 } 12508 break; 12509 } /* switch(test) */ 12510 } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK)); 12511 12512 goto apply_predicates; 12513 12514 axis_range_end: /* ----------------------------------------------------- */ 12515 /* 12516 * We have a "/foo[n]", and position() = n was reached. 12517 * Note that we can have as well "/foo/::parent::foo[1]", so 12518 * a duplicate-aware merge is still needed. 12519 * Merge with the result. 12520 */ 12521 if (outSeq == NULL) { 12522 outSeq = seq; 12523 seq = NULL; 12524 } else 12525 outSeq = mergeAndClear(outSeq, seq, 0); 12526 /* 12527 * Break if only a true/false result was requested. 12528 */ 12529 if (toBool) 12530 break; 12531 continue; 12532 12533 first_hit: /* ---------------------------------------------------------- */ 12534 /* 12535 * Break if only a true/false result was requested and 12536 * no predicates existed and a node test succeeded. 12537 */ 12538 if (outSeq == NULL) { 12539 outSeq = seq; 12540 seq = NULL; 12541 } else 12542 outSeq = mergeAndClear(outSeq, seq, 0); 12543 break; 12544 12545 #ifdef DEBUG_STEP 12546 if (seq != NULL) 12547 nbMatches += seq->nodeNr; 12548 #endif 12549 12550 apply_predicates: /* --------------------------------------------------- */ 12551 if (ctxt->error != XPATH_EXPRESSION_OK) 12552 goto error; 12553 12554 /* 12555 * Apply predicates. 12556 */ 12557 if ((predOp != NULL) && (seq->nodeNr > 0)) { 12558 /* 12559 * E.g. when we have a "/foo[some expression][n]". 12560 */ 12561 /* 12562 * QUESTION TODO: The old predicate evaluation took into 12563 * account location-sets. 12564 * (E.g. ctxt->value->type == XPATH_LOCATIONSET) 12565 * Do we expect such a set here? 12566 * All what I learned now from the evaluation semantics 12567 * does not indicate that a location-set will be processed 12568 * here, so this looks OK. 12569 */ 12570 /* 12571 * Iterate over all predicates, starting with the outermost 12572 * predicate. 12573 * TODO: Problem: we cannot execute the inner predicates first 12574 * since we cannot go back *up* the operator tree! 12575 * Options we have: 12576 * 1) Use of recursive functions (like is it currently done 12577 * via xmlXPathCompOpEval()) 12578 * 2) Add a predicate evaluation information stack to the 12579 * context struct 12580 * 3) Change the way the operators are linked; we need a 12581 * "parent" field on xmlXPathStepOp 12582 * 12583 * For the moment, I'll try to solve this with a recursive 12584 * function: xmlXPathCompOpEvalPredicate(). 12585 */ 12586 size = seq->nodeNr; 12587 if (hasPredicateRange != 0) 12588 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt, 12589 predOp, seq, size, maxPos, maxPos, hasNsNodes); 12590 else 12591 newSize = xmlXPathCompOpEvalPredicate(ctxt, 12592 predOp, seq, size, hasNsNodes); 12593 12594 if (ctxt->error != XPATH_EXPRESSION_OK) { 12595 total = 0; 12596 goto error; 12597 } 12598 /* 12599 * Add the filtered set of nodes to the result node set. 12600 */ 12601 if (newSize == 0) { 12602 /* 12603 * The predicates filtered all nodes out. 12604 */ 12605 xmlXPathNodeSetClear(seq, hasNsNodes); 12606 } else if (seq->nodeNr > 0) { 12607 /* 12608 * Add to result set. 12609 */ 12610 if (outSeq == NULL) { 12611 if (size != newSize) { 12612 /* 12613 * We need to merge and clear here, since 12614 * the sequence will contained NULLed entries. 12615 */ 12616 outSeq = mergeAndClear(NULL, seq, 1); 12617 } else { 12618 outSeq = seq; 12619 seq = NULL; 12620 } 12621 } else 12622 outSeq = mergeAndClear(outSeq, seq, 12623 (size != newSize) ? 1: 0); 12624 /* 12625 * Break if only a true/false result was requested. 12626 */ 12627 if (toBool) 12628 break; 12629 } 12630 } else if (seq->nodeNr > 0) { 12631 /* 12632 * Add to result set. 12633 */ 12634 if (outSeq == NULL) { 12635 outSeq = seq; 12636 seq = NULL; 12637 } else { 12638 outSeq = mergeAndClear(outSeq, seq, 0); 12639 } 12640 } 12641 } 12642 12643 error: 12644 if ((obj->boolval) && (obj->user != NULL)) { 12645 /* 12646 * QUESTION TODO: What does this do and why? 12647 * TODO: Do we have to do this also for the "error" 12648 * cleanup further down? 12649 */ 12650 ctxt->value->boolval = 1; 12651 ctxt->value->user = obj->user; 12652 obj->user = NULL; 12653 obj->boolval = 0; 12654 } 12655 xmlXPathReleaseObject(xpctxt, obj); 12656 12657 /* 12658 * Ensure we return at least an emtpy set. 12659 */ 12660 if (outSeq == NULL) { 12661 if ((seq != NULL) && (seq->nodeNr == 0)) 12662 outSeq = seq; 12663 else 12664 outSeq = xmlXPathNodeSetCreate(NULL); 12665 /* XXX what if xmlXPathNodeSetCreate returned NULL here? */ 12666 } 12667 if ((seq != NULL) && (seq != outSeq)) { 12668 xmlXPathFreeNodeSet(seq); 12669 } 12670 /* 12671 * Hand over the result. Better to push the set also in 12672 * case of errors. 12673 */ 12674 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq)); 12675 /* 12676 * Reset the context node. 12677 */ 12678 xpctxt->node = oldContextNode; 12679 /* 12680 * When traversing the namespace axis in "toBool" mode, it's 12681 * possible that tmpNsList wasn't freed. 12682 */ 12683 if (xpctxt->tmpNsList != NULL) { 12684 xmlFree(xpctxt->tmpNsList); 12685 xpctxt->tmpNsList = NULL; 12686 } 12687 12688 #ifdef DEBUG_STEP 12689 xmlGenericError(xmlGenericErrorContext, 12690 "\nExamined %d nodes, found %d nodes at that step\n", 12691 total, nbMatches); 12692 #endif 12693 12694 return(total); 12695 } 12696 12697 static int 12698 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt, 12699 xmlXPathStepOpPtr op, xmlNodePtr * first); 12700 12701 /** 12702 * xmlXPathCompOpEvalFirst: 12703 * @ctxt: the XPath parser context with the compiled expression 12704 * @op: an XPath compiled operation 12705 * @first: the first elem found so far 12706 * 12707 * Evaluate the Precompiled XPath operation searching only the first 12708 * element in document order 12709 * 12710 * Returns the number of examined objects. 12711 */ 12712 static int 12713 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt, 12714 xmlXPathStepOpPtr op, xmlNodePtr * first) 12715 { 12716 int total = 0, cur; 12717 xmlXPathCompExprPtr comp; 12718 xmlXPathObjectPtr arg1, arg2; 12719 12720 CHECK_ERROR0; 12721 comp = ctxt->comp; 12722 switch (op->op) { 12723 case XPATH_OP_END: 12724 return (0); 12725 case XPATH_OP_UNION: 12726 total = 12727 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1], 12728 first); 12729 CHECK_ERROR0; 12730 if ((ctxt->value != NULL) 12731 && (ctxt->value->type == XPATH_NODESET) 12732 && (ctxt->value->nodesetval != NULL) 12733 && (ctxt->value->nodesetval->nodeNr >= 1)) { 12734 /* 12735 * limit tree traversing to first node in the result 12736 */ 12737 /* 12738 * OPTIMIZE TODO: This implicitely sorts 12739 * the result, even if not needed. E.g. if the argument 12740 * of the count() function, no sorting is needed. 12741 * OPTIMIZE TODO: How do we know if the node-list wasn't 12742 * aready sorted? 12743 */ 12744 if (ctxt->value->nodesetval->nodeNr > 1) 12745 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12746 *first = ctxt->value->nodesetval->nodeTab[0]; 12747 } 12748 cur = 12749 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2], 12750 first); 12751 CHECK_ERROR0; 12752 12753 arg2 = valuePop(ctxt); 12754 arg1 = valuePop(ctxt); 12755 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) || 12756 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) { 12757 xmlXPathReleaseObject(ctxt->context, arg1); 12758 xmlXPathReleaseObject(ctxt->context, arg2); 12759 XP_ERROR0(XPATH_INVALID_TYPE); 12760 } 12761 12762 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 12763 arg2->nodesetval); 12764 valuePush(ctxt, arg1); 12765 xmlXPathReleaseObject(ctxt->context, arg2); 12766 /* optimizer */ 12767 if (total > cur) 12768 xmlXPathCompSwap(op); 12769 return (total + cur); 12770 case XPATH_OP_ROOT: 12771 xmlXPathRoot(ctxt); 12772 return (0); 12773 case XPATH_OP_NODE: 12774 if (op->ch1 != -1) 12775 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12776 CHECK_ERROR0; 12777 if (op->ch2 != -1) 12778 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12779 CHECK_ERROR0; 12780 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 12781 ctxt->context->node)); 12782 return (total); 12783 case XPATH_OP_COLLECT:{ 12784 if (op->ch1 == -1) 12785 return (total); 12786 12787 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12788 CHECK_ERROR0; 12789 12790 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0); 12791 return (total); 12792 } 12793 case XPATH_OP_VALUE: 12794 valuePush(ctxt, 12795 xmlXPathCacheObjectCopy(ctxt->context, 12796 (xmlXPathObjectPtr) op->value4)); 12797 return (0); 12798 case XPATH_OP_SORT: 12799 if (op->ch1 != -1) 12800 total += 12801 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1], 12802 first); 12803 CHECK_ERROR0; 12804 if ((ctxt->value != NULL) 12805 && (ctxt->value->type == XPATH_NODESET) 12806 && (ctxt->value->nodesetval != NULL) 12807 && (ctxt->value->nodesetval->nodeNr > 1)) 12808 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12809 return (total); 12810 #ifdef XP_OPTIMIZED_FILTER_FIRST 12811 case XPATH_OP_FILTER: 12812 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first); 12813 return (total); 12814 #endif 12815 default: 12816 return (xmlXPathCompOpEval(ctxt, op)); 12817 } 12818 } 12819 12820 /** 12821 * xmlXPathCompOpEvalLast: 12822 * @ctxt: the XPath parser context with the compiled expression 12823 * @op: an XPath compiled operation 12824 * @last: the last elem found so far 12825 * 12826 * Evaluate the Precompiled XPath operation searching only the last 12827 * element in document order 12828 * 12829 * Returns the number of nodes traversed 12830 */ 12831 static int 12832 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op, 12833 xmlNodePtr * last) 12834 { 12835 int total = 0, cur; 12836 xmlXPathCompExprPtr comp; 12837 xmlXPathObjectPtr arg1, arg2; 12838 12839 CHECK_ERROR0; 12840 comp = ctxt->comp; 12841 switch (op->op) { 12842 case XPATH_OP_END: 12843 return (0); 12844 case XPATH_OP_UNION: 12845 total = 12846 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last); 12847 CHECK_ERROR0; 12848 if ((ctxt->value != NULL) 12849 && (ctxt->value->type == XPATH_NODESET) 12850 && (ctxt->value->nodesetval != NULL) 12851 && (ctxt->value->nodesetval->nodeNr >= 1)) { 12852 /* 12853 * limit tree traversing to first node in the result 12854 */ 12855 if (ctxt->value->nodesetval->nodeNr > 1) 12856 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12857 *last = 12858 ctxt->value->nodesetval->nodeTab[ctxt->value-> 12859 nodesetval->nodeNr - 12860 1]; 12861 } 12862 cur = 12863 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last); 12864 CHECK_ERROR0; 12865 if ((ctxt->value != NULL) 12866 && (ctxt->value->type == XPATH_NODESET) 12867 && (ctxt->value->nodesetval != NULL) 12868 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */ 12869 } 12870 12871 arg2 = valuePop(ctxt); 12872 arg1 = valuePop(ctxt); 12873 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) || 12874 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) { 12875 xmlXPathReleaseObject(ctxt->context, arg1); 12876 xmlXPathReleaseObject(ctxt->context, arg2); 12877 XP_ERROR0(XPATH_INVALID_TYPE); 12878 } 12879 12880 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 12881 arg2->nodesetval); 12882 valuePush(ctxt, arg1); 12883 xmlXPathReleaseObject(ctxt->context, arg2); 12884 /* optimizer */ 12885 if (total > cur) 12886 xmlXPathCompSwap(op); 12887 return (total + cur); 12888 case XPATH_OP_ROOT: 12889 xmlXPathRoot(ctxt); 12890 return (0); 12891 case XPATH_OP_NODE: 12892 if (op->ch1 != -1) 12893 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12894 CHECK_ERROR0; 12895 if (op->ch2 != -1) 12896 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12897 CHECK_ERROR0; 12898 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 12899 ctxt->context->node)); 12900 return (total); 12901 case XPATH_OP_COLLECT:{ 12902 if (op->ch1 == -1) 12903 return (0); 12904 12905 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12906 CHECK_ERROR0; 12907 12908 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0); 12909 return (total); 12910 } 12911 case XPATH_OP_VALUE: 12912 valuePush(ctxt, 12913 xmlXPathCacheObjectCopy(ctxt->context, 12914 (xmlXPathObjectPtr) op->value4)); 12915 return (0); 12916 case XPATH_OP_SORT: 12917 if (op->ch1 != -1) 12918 total += 12919 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], 12920 last); 12921 CHECK_ERROR0; 12922 if ((ctxt->value != NULL) 12923 && (ctxt->value->type == XPATH_NODESET) 12924 && (ctxt->value->nodesetval != NULL) 12925 && (ctxt->value->nodesetval->nodeNr > 1)) 12926 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12927 return (total); 12928 default: 12929 return (xmlXPathCompOpEval(ctxt, op)); 12930 } 12931 } 12932 12933 #ifdef XP_OPTIMIZED_FILTER_FIRST 12934 static int 12935 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt, 12936 xmlXPathStepOpPtr op, xmlNodePtr * first) 12937 { 12938 int total = 0; 12939 xmlXPathCompExprPtr comp; 12940 xmlXPathObjectPtr res; 12941 xmlXPathObjectPtr obj; 12942 xmlNodeSetPtr oldset; 12943 xmlNodePtr oldnode; 12944 xmlDocPtr oldDoc; 12945 int oldcs, oldpp; 12946 int i; 12947 12948 CHECK_ERROR0; 12949 comp = ctxt->comp; 12950 /* 12951 * Optimization for ()[last()] selection i.e. the last elem 12952 */ 12953 if ((op->ch1 != -1) && (op->ch2 != -1) && 12954 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 12955 (comp->steps[op->ch2].op == XPATH_OP_SORT)) { 12956 int f = comp->steps[op->ch2].ch1; 12957 12958 if ((f != -1) && 12959 (comp->steps[f].op == XPATH_OP_FUNCTION) && 12960 (comp->steps[f].value5 == NULL) && 12961 (comp->steps[f].value == 0) && 12962 (comp->steps[f].value4 != NULL) && 12963 (xmlStrEqual 12964 (comp->steps[f].value4, BAD_CAST "last"))) { 12965 xmlNodePtr last = NULL; 12966 12967 total += 12968 xmlXPathCompOpEvalLast(ctxt, 12969 &comp->steps[op->ch1], 12970 &last); 12971 CHECK_ERROR0; 12972 /* 12973 * The nodeset should be in document order, 12974 * Keep only the last value 12975 */ 12976 if ((ctxt->value != NULL) && 12977 (ctxt->value->type == XPATH_NODESET) && 12978 (ctxt->value->nodesetval != NULL) && 12979 (ctxt->value->nodesetval->nodeTab != NULL) && 12980 (ctxt->value->nodesetval->nodeNr > 1)) { 12981 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval); 12982 *first = *(ctxt->value->nodesetval->nodeTab); 12983 } 12984 return (total); 12985 } 12986 } 12987 12988 if (op->ch1 != -1) 12989 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12990 CHECK_ERROR0; 12991 if (op->ch2 == -1) 12992 return (total); 12993 if (ctxt->value == NULL) 12994 return (total); 12995 12996 #ifdef LIBXML_XPTR_ENABLED 12997 /* 12998 * Hum are we filtering the result of an XPointer expression 12999 */ 13000 if (ctxt->value->type == XPATH_LOCATIONSET) { 13001 xmlXPathObjectPtr tmp = NULL; 13002 xmlLocationSetPtr newlocset = NULL; 13003 xmlLocationSetPtr oldlocset; 13004 13005 /* 13006 * Extract the old locset, and then evaluate the result of the 13007 * expression for all the element in the locset. use it to grow 13008 * up a new locset. 13009 */ 13010 CHECK_TYPE0(XPATH_LOCATIONSET); 13011 13012 if ((ctxt->value->user == NULL) || 13013 (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0)) 13014 return (total); 13015 13016 obj = valuePop(ctxt); 13017 oldlocset = obj->user; 13018 oldnode = ctxt->context->node; 13019 oldcs = ctxt->context->contextSize; 13020 oldpp = ctxt->context->proximityPosition; 13021 13022 newlocset = xmlXPtrLocationSetCreate(NULL); 13023 13024 for (i = 0; i < oldlocset->locNr; i++) { 13025 /* 13026 * Run the evaluation with a node list made of a 13027 * single item in the nodelocset. 13028 */ 13029 ctxt->context->node = oldlocset->locTab[i]->user; 13030 ctxt->context->contextSize = oldlocset->locNr; 13031 ctxt->context->proximityPosition = i + 1; 13032 if (tmp == NULL) { 13033 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13034 ctxt->context->node); 13035 } else { 13036 if (xmlXPathNodeSetAddUnique(tmp->nodesetval, 13037 ctxt->context->node) < 0) { 13038 ctxt->error = XPATH_MEMORY_ERROR; 13039 } 13040 } 13041 valuePush(ctxt, tmp); 13042 if (op->ch2 != -1) 13043 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13044 if (ctxt->error != XPATH_EXPRESSION_OK) { 13045 xmlXPtrFreeLocationSet(newlocset); 13046 goto xptr_error; 13047 } 13048 /* 13049 * The result of the evaluation need to be tested to 13050 * decided whether the filter succeeded or not 13051 */ 13052 res = valuePop(ctxt); 13053 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 13054 xmlXPtrLocationSetAdd(newlocset, 13055 xmlXPathCacheObjectCopy(ctxt->context, 13056 oldlocset->locTab[i])); 13057 } 13058 /* 13059 * Cleanup 13060 */ 13061 if (res != NULL) { 13062 xmlXPathReleaseObject(ctxt->context, res); 13063 } 13064 if (ctxt->value == tmp) { 13065 valuePop(ctxt); 13066 xmlXPathNodeSetClear(tmp->nodesetval, 1); 13067 /* 13068 * REVISIT TODO: Don't create a temporary nodeset 13069 * for everly iteration. 13070 */ 13071 /* OLD: xmlXPathFreeObject(res); */ 13072 } else 13073 tmp = NULL; 13074 /* 13075 * Only put the first node in the result, then leave. 13076 */ 13077 if (newlocset->locNr > 0) { 13078 *first = (xmlNodePtr) oldlocset->locTab[i]->user; 13079 break; 13080 } 13081 } 13082 if (tmp != NULL) { 13083 xmlXPathReleaseObject(ctxt->context, tmp); 13084 } 13085 /* 13086 * The result is used as the new evaluation locset. 13087 */ 13088 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset)); 13089 xptr_error: 13090 xmlXPathReleaseObject(ctxt->context, obj); 13091 ctxt->context->node = oldnode; 13092 ctxt->context->contextSize = oldcs; 13093 ctxt->context->proximityPosition = oldpp; 13094 return (total); 13095 } 13096 #endif /* LIBXML_XPTR_ENABLED */ 13097 13098 /* 13099 * Extract the old set, and then evaluate the result of the 13100 * expression for all the element in the set. use it to grow 13101 * up a new set. 13102 */ 13103 CHECK_TYPE0(XPATH_NODESET); 13104 13105 if ((ctxt->value->nodesetval != NULL) && 13106 (ctxt->value->nodesetval->nodeNr != 0)) { 13107 xmlNodeSetPtr newset; 13108 xmlXPathObjectPtr tmp = NULL; 13109 13110 obj = valuePop(ctxt); 13111 oldset = obj->nodesetval; 13112 oldnode = ctxt->context->node; 13113 oldDoc = ctxt->context->doc; 13114 oldcs = ctxt->context->contextSize; 13115 oldpp = ctxt->context->proximityPosition; 13116 13117 /* 13118 * Initialize the new set. 13119 * Also set the xpath document in case things like 13120 * key() evaluation are attempted on the predicate 13121 */ 13122 newset = xmlXPathNodeSetCreate(NULL); 13123 /* XXX what if xmlXPathNodeSetCreate returned NULL? */ 13124 13125 for (i = 0; i < oldset->nodeNr; i++) { 13126 /* 13127 * Run the evaluation with a node list made of 13128 * a single item in the nodeset. 13129 */ 13130 ctxt->context->node = oldset->nodeTab[i]; 13131 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) && 13132 (oldset->nodeTab[i]->doc != NULL)) 13133 ctxt->context->doc = oldset->nodeTab[i]->doc; 13134 if (tmp == NULL) { 13135 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13136 ctxt->context->node); 13137 } else { 13138 if (xmlXPathNodeSetAddUnique(tmp->nodesetval, 13139 ctxt->context->node) < 0) { 13140 ctxt->error = XPATH_MEMORY_ERROR; 13141 } 13142 } 13143 valuePush(ctxt, tmp); 13144 ctxt->context->contextSize = oldset->nodeNr; 13145 ctxt->context->proximityPosition = i + 1; 13146 if (op->ch2 != -1) 13147 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13148 if (ctxt->error != XPATH_EXPRESSION_OK) { 13149 xmlXPathFreeNodeSet(newset); 13150 goto error; 13151 } 13152 /* 13153 * The result of the evaluation needs to be tested to 13154 * decide whether the filter succeeded or not 13155 */ 13156 res = valuePop(ctxt); 13157 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 13158 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0) 13159 ctxt->error = XPATH_MEMORY_ERROR; 13160 } 13161 /* 13162 * Cleanup 13163 */ 13164 if (res != NULL) { 13165 xmlXPathReleaseObject(ctxt->context, res); 13166 } 13167 if (ctxt->value == tmp) { 13168 valuePop(ctxt); 13169 /* 13170 * Don't free the temporary nodeset 13171 * in order to avoid massive recreation inside this 13172 * loop. 13173 */ 13174 xmlXPathNodeSetClear(tmp->nodesetval, 1); 13175 } else 13176 tmp = NULL; 13177 /* 13178 * Only put the first node in the result, then leave. 13179 */ 13180 if (newset->nodeNr > 0) { 13181 *first = *(newset->nodeTab); 13182 break; 13183 } 13184 } 13185 if (tmp != NULL) { 13186 xmlXPathReleaseObject(ctxt->context, tmp); 13187 } 13188 /* 13189 * The result is used as the new evaluation set. 13190 */ 13191 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset)); 13192 error: 13193 xmlXPathReleaseObject(ctxt->context, obj); 13194 ctxt->context->node = oldnode; 13195 ctxt->context->doc = oldDoc; 13196 ctxt->context->contextSize = oldcs; 13197 ctxt->context->proximityPosition = oldpp; 13198 } 13199 return(total); 13200 } 13201 #endif /* XP_OPTIMIZED_FILTER_FIRST */ 13202 13203 /** 13204 * xmlXPathCompOpEval: 13205 * @ctxt: the XPath parser context with the compiled expression 13206 * @op: an XPath compiled operation 13207 * 13208 * Evaluate the Precompiled XPath operation 13209 * Returns the number of nodes traversed 13210 */ 13211 static int 13212 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) 13213 { 13214 int total = 0; 13215 int equal, ret; 13216 xmlXPathCompExprPtr comp; 13217 xmlXPathObjectPtr arg1, arg2; 13218 13219 CHECK_ERROR0; 13220 comp = ctxt->comp; 13221 switch (op->op) { 13222 case XPATH_OP_END: 13223 return (0); 13224 case XPATH_OP_AND: 13225 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13226 CHECK_ERROR0; 13227 xmlXPathBooleanFunction(ctxt, 1); 13228 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0)) 13229 return (total); 13230 arg2 = valuePop(ctxt); 13231 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13232 if (ctxt->error) { 13233 xmlXPathFreeObject(arg2); 13234 return(0); 13235 } 13236 xmlXPathBooleanFunction(ctxt, 1); 13237 if (ctxt->value != NULL) 13238 ctxt->value->boolval &= arg2->boolval; 13239 xmlXPathReleaseObject(ctxt->context, arg2); 13240 return (total); 13241 case XPATH_OP_OR: 13242 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13243 CHECK_ERROR0; 13244 xmlXPathBooleanFunction(ctxt, 1); 13245 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1)) 13246 return (total); 13247 arg2 = valuePop(ctxt); 13248 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13249 if (ctxt->error) { 13250 xmlXPathFreeObject(arg2); 13251 return(0); 13252 } 13253 xmlXPathBooleanFunction(ctxt, 1); 13254 if (ctxt->value != NULL) 13255 ctxt->value->boolval |= arg2->boolval; 13256 xmlXPathReleaseObject(ctxt->context, arg2); 13257 return (total); 13258 case XPATH_OP_EQUAL: 13259 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13260 CHECK_ERROR0; 13261 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13262 CHECK_ERROR0; 13263 if (op->value) 13264 equal = xmlXPathEqualValues(ctxt); 13265 else 13266 equal = xmlXPathNotEqualValues(ctxt); 13267 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal)); 13268 return (total); 13269 case XPATH_OP_CMP: 13270 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13271 CHECK_ERROR0; 13272 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13273 CHECK_ERROR0; 13274 ret = xmlXPathCompareValues(ctxt, op->value, op->value2); 13275 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret)); 13276 return (total); 13277 case XPATH_OP_PLUS: 13278 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13279 CHECK_ERROR0; 13280 if (op->ch2 != -1) { 13281 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13282 } 13283 CHECK_ERROR0; 13284 if (op->value == 0) 13285 xmlXPathSubValues(ctxt); 13286 else if (op->value == 1) 13287 xmlXPathAddValues(ctxt); 13288 else if (op->value == 2) 13289 xmlXPathValueFlipSign(ctxt); 13290 else if (op->value == 3) { 13291 CAST_TO_NUMBER; 13292 CHECK_TYPE0(XPATH_NUMBER); 13293 } 13294 return (total); 13295 case XPATH_OP_MULT: 13296 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13297 CHECK_ERROR0; 13298 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13299 CHECK_ERROR0; 13300 if (op->value == 0) 13301 xmlXPathMultValues(ctxt); 13302 else if (op->value == 1) 13303 xmlXPathDivValues(ctxt); 13304 else if (op->value == 2) 13305 xmlXPathModValues(ctxt); 13306 return (total); 13307 case XPATH_OP_UNION: 13308 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13309 CHECK_ERROR0; 13310 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13311 CHECK_ERROR0; 13312 13313 arg2 = valuePop(ctxt); 13314 arg1 = valuePop(ctxt); 13315 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) || 13316 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) { 13317 xmlXPathReleaseObject(ctxt->context, arg1); 13318 xmlXPathReleaseObject(ctxt->context, arg2); 13319 XP_ERROR0(XPATH_INVALID_TYPE); 13320 } 13321 13322 if ((arg1->nodesetval == NULL) || 13323 ((arg2->nodesetval != NULL) && 13324 (arg2->nodesetval->nodeNr != 0))) 13325 { 13326 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 13327 arg2->nodesetval); 13328 } 13329 13330 valuePush(ctxt, arg1); 13331 xmlXPathReleaseObject(ctxt->context, arg2); 13332 return (total); 13333 case XPATH_OP_ROOT: 13334 xmlXPathRoot(ctxt); 13335 return (total); 13336 case XPATH_OP_NODE: 13337 if (op->ch1 != -1) 13338 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13339 CHECK_ERROR0; 13340 if (op->ch2 != -1) 13341 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13342 CHECK_ERROR0; 13343 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 13344 ctxt->context->node)); 13345 return (total); 13346 case XPATH_OP_COLLECT:{ 13347 if (op->ch1 == -1) 13348 return (total); 13349 13350 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13351 CHECK_ERROR0; 13352 13353 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0); 13354 return (total); 13355 } 13356 case XPATH_OP_VALUE: 13357 valuePush(ctxt, 13358 xmlXPathCacheObjectCopy(ctxt->context, 13359 (xmlXPathObjectPtr) op->value4)); 13360 return (total); 13361 case XPATH_OP_VARIABLE:{ 13362 xmlXPathObjectPtr val; 13363 13364 if (op->ch1 != -1) 13365 total += 13366 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13367 if (op->value5 == NULL) { 13368 val = xmlXPathVariableLookup(ctxt->context, op->value4); 13369 if (val == NULL) 13370 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR); 13371 valuePush(ctxt, val); 13372 } else { 13373 const xmlChar *URI; 13374 13375 URI = xmlXPathNsLookup(ctxt->context, op->value5); 13376 if (URI == NULL) { 13377 xmlGenericError(xmlGenericErrorContext, 13378 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n", 13379 (char *) op->value4, (char *)op->value5); 13380 ctxt->error = XPATH_UNDEF_PREFIX_ERROR; 13381 return (total); 13382 } 13383 val = xmlXPathVariableLookupNS(ctxt->context, 13384 op->value4, URI); 13385 if (val == NULL) 13386 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR); 13387 valuePush(ctxt, val); 13388 } 13389 return (total); 13390 } 13391 case XPATH_OP_FUNCTION:{ 13392 xmlXPathFunction func; 13393 const xmlChar *oldFunc, *oldFuncURI; 13394 int i; 13395 int frame; 13396 13397 frame = xmlXPathSetFrame(ctxt); 13398 if (op->ch1 != -1) { 13399 total += 13400 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13401 if (ctxt->error != XPATH_EXPRESSION_OK) { 13402 xmlXPathPopFrame(ctxt, frame); 13403 return (total); 13404 } 13405 } 13406 if (ctxt->valueNr < ctxt->valueFrame + op->value) { 13407 xmlGenericError(xmlGenericErrorContext, 13408 "xmlXPathCompOpEval: parameter error\n"); 13409 ctxt->error = XPATH_INVALID_OPERAND; 13410 xmlXPathPopFrame(ctxt, frame); 13411 return (total); 13412 } 13413 for (i = 0; i < op->value; i++) { 13414 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) { 13415 xmlGenericError(xmlGenericErrorContext, 13416 "xmlXPathCompOpEval: parameter error\n"); 13417 ctxt->error = XPATH_INVALID_OPERAND; 13418 xmlXPathPopFrame(ctxt, frame); 13419 return (total); 13420 } 13421 } 13422 if (op->cache != NULL) 13423 func = op->cache; 13424 else { 13425 const xmlChar *URI = NULL; 13426 13427 if (op->value5 == NULL) 13428 func = 13429 xmlXPathFunctionLookup(ctxt->context, 13430 op->value4); 13431 else { 13432 URI = xmlXPathNsLookup(ctxt->context, op->value5); 13433 if (URI == NULL) { 13434 xmlGenericError(xmlGenericErrorContext, 13435 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n", 13436 (char *)op->value4, (char *)op->value5); 13437 xmlXPathPopFrame(ctxt, frame); 13438 ctxt->error = XPATH_UNDEF_PREFIX_ERROR; 13439 return (total); 13440 } 13441 func = xmlXPathFunctionLookupNS(ctxt->context, 13442 op->value4, URI); 13443 } 13444 if (func == NULL) { 13445 xmlGenericError(xmlGenericErrorContext, 13446 "xmlXPathCompOpEval: function %s not found\n", 13447 (char *)op->value4); 13448 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR); 13449 } 13450 op->cache = func; 13451 op->cacheURI = (void *) URI; 13452 } 13453 oldFunc = ctxt->context->function; 13454 oldFuncURI = ctxt->context->functionURI; 13455 ctxt->context->function = op->value4; 13456 ctxt->context->functionURI = op->cacheURI; 13457 func(ctxt, op->value); 13458 ctxt->context->function = oldFunc; 13459 ctxt->context->functionURI = oldFuncURI; 13460 xmlXPathPopFrame(ctxt, frame); 13461 return (total); 13462 } 13463 case XPATH_OP_ARG: 13464 if (op->ch1 != -1) { 13465 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13466 CHECK_ERROR0; 13467 } 13468 if (op->ch2 != -1) { 13469 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13470 CHECK_ERROR0; 13471 } 13472 return (total); 13473 case XPATH_OP_PREDICATE: 13474 case XPATH_OP_FILTER:{ 13475 xmlXPathObjectPtr res; 13476 xmlXPathObjectPtr obj, tmp; 13477 xmlNodeSetPtr newset = NULL; 13478 xmlNodeSetPtr oldset; 13479 xmlNodePtr oldnode; 13480 xmlDocPtr oldDoc; 13481 int oldcs, oldpp; 13482 int i; 13483 13484 /* 13485 * Optimization for ()[1] selection i.e. the first elem 13486 */ 13487 if ((op->ch1 != -1) && (op->ch2 != -1) && 13488 #ifdef XP_OPTIMIZED_FILTER_FIRST 13489 /* 13490 * FILTER TODO: Can we assume that the inner processing 13491 * will result in an ordered list if we have an 13492 * XPATH_OP_FILTER? 13493 * What about an additional field or flag on 13494 * xmlXPathObject like @sorted ? This way we wouln'd need 13495 * to assume anything, so it would be more robust and 13496 * easier to optimize. 13497 */ 13498 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */ 13499 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */ 13500 #else 13501 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 13502 #endif 13503 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */ 13504 xmlXPathObjectPtr val; 13505 13506 val = comp->steps[op->ch2].value4; 13507 if ((val != NULL) && (val->type == XPATH_NUMBER) && 13508 (val->floatval == 1.0)) { 13509 xmlNodePtr first = NULL; 13510 13511 total += 13512 xmlXPathCompOpEvalFirst(ctxt, 13513 &comp->steps[op->ch1], 13514 &first); 13515 CHECK_ERROR0; 13516 /* 13517 * The nodeset should be in document order, 13518 * Keep only the first value 13519 */ 13520 if ((ctxt->value != NULL) && 13521 (ctxt->value->type == XPATH_NODESET) && 13522 (ctxt->value->nodesetval != NULL) && 13523 (ctxt->value->nodesetval->nodeNr > 1)) 13524 xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval, 13525 1, 1); 13526 return (total); 13527 } 13528 } 13529 /* 13530 * Optimization for ()[last()] selection i.e. the last elem 13531 */ 13532 if ((op->ch1 != -1) && (op->ch2 != -1) && 13533 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 13534 (comp->steps[op->ch2].op == XPATH_OP_SORT)) { 13535 int f = comp->steps[op->ch2].ch1; 13536 13537 if ((f != -1) && 13538 (comp->steps[f].op == XPATH_OP_FUNCTION) && 13539 (comp->steps[f].value5 == NULL) && 13540 (comp->steps[f].value == 0) && 13541 (comp->steps[f].value4 != NULL) && 13542 (xmlStrEqual 13543 (comp->steps[f].value4, BAD_CAST "last"))) { 13544 xmlNodePtr last = NULL; 13545 13546 total += 13547 xmlXPathCompOpEvalLast(ctxt, 13548 &comp->steps[op->ch1], 13549 &last); 13550 CHECK_ERROR0; 13551 /* 13552 * The nodeset should be in document order, 13553 * Keep only the last value 13554 */ 13555 if ((ctxt->value != NULL) && 13556 (ctxt->value->type == XPATH_NODESET) && 13557 (ctxt->value->nodesetval != NULL) && 13558 (ctxt->value->nodesetval->nodeTab != NULL) && 13559 (ctxt->value->nodesetval->nodeNr > 1)) 13560 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval); 13561 return (total); 13562 } 13563 } 13564 /* 13565 * Process inner predicates first. 13566 * Example "index[parent::book][1]": 13567 * ... 13568 * PREDICATE <-- we are here "[1]" 13569 * PREDICATE <-- process "[parent::book]" first 13570 * SORT 13571 * COLLECT 'parent' 'name' 'node' book 13572 * NODE 13573 * ELEM Object is a number : 1 13574 */ 13575 if (op->ch1 != -1) 13576 total += 13577 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13578 CHECK_ERROR0; 13579 if (op->ch2 == -1) 13580 return (total); 13581 if (ctxt->value == NULL) 13582 return (total); 13583 13584 #ifdef LIBXML_XPTR_ENABLED 13585 /* 13586 * Hum are we filtering the result of an XPointer expression 13587 */ 13588 if (ctxt->value->type == XPATH_LOCATIONSET) { 13589 xmlLocationSetPtr newlocset = NULL; 13590 xmlLocationSetPtr oldlocset; 13591 13592 /* 13593 * Extract the old locset, and then evaluate the result of the 13594 * expression for all the element in the locset. use it to grow 13595 * up a new locset. 13596 */ 13597 CHECK_TYPE0(XPATH_LOCATIONSET); 13598 13599 if ((ctxt->value->user == NULL) || 13600 (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0)) 13601 return (total); 13602 13603 obj = valuePop(ctxt); 13604 oldlocset = obj->user; 13605 oldnode = ctxt->context->node; 13606 oldcs = ctxt->context->contextSize; 13607 oldpp = ctxt->context->proximityPosition; 13608 13609 newlocset = xmlXPtrLocationSetCreate(NULL); 13610 13611 for (i = 0; i < oldlocset->locNr; i++) { 13612 /* 13613 * Run the evaluation with a node list made of a 13614 * single item in the nodelocset. 13615 */ 13616 ctxt->context->node = oldlocset->locTab[i]->user; 13617 ctxt->context->contextSize = oldlocset->locNr; 13618 ctxt->context->proximityPosition = i + 1; 13619 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13620 ctxt->context->node); 13621 valuePush(ctxt, tmp); 13622 13623 if (op->ch2 != -1) 13624 total += 13625 xmlXPathCompOpEval(ctxt, 13626 &comp->steps[op->ch2]); 13627 if (ctxt->error != XPATH_EXPRESSION_OK) { 13628 xmlXPtrFreeLocationSet(newlocset); 13629 goto filter_xptr_error; 13630 } 13631 13632 /* 13633 * The result of the evaluation need to be tested to 13634 * decided whether the filter succeeded or not 13635 */ 13636 res = valuePop(ctxt); 13637 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 13638 xmlXPtrLocationSetAdd(newlocset, 13639 xmlXPathObjectCopy 13640 (oldlocset->locTab[i])); 13641 } 13642 13643 /* 13644 * Cleanup 13645 */ 13646 if (res != NULL) { 13647 xmlXPathReleaseObject(ctxt->context, res); 13648 } 13649 if (ctxt->value == tmp) { 13650 res = valuePop(ctxt); 13651 xmlXPathReleaseObject(ctxt->context, res); 13652 } 13653 } 13654 13655 /* 13656 * The result is used as the new evaluation locset. 13657 */ 13658 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset)); 13659 filter_xptr_error: 13660 xmlXPathReleaseObject(ctxt->context, obj); 13661 ctxt->context->node = oldnode; 13662 ctxt->context->contextSize = oldcs; 13663 ctxt->context->proximityPosition = oldpp; 13664 return (total); 13665 } 13666 #endif /* LIBXML_XPTR_ENABLED */ 13667 13668 /* 13669 * Extract the old set, and then evaluate the result of the 13670 * expression for all the element in the set. use it to grow 13671 * up a new set. 13672 */ 13673 CHECK_TYPE0(XPATH_NODESET); 13674 13675 if ((ctxt->value->nodesetval != NULL) && 13676 (ctxt->value->nodesetval->nodeNr != 0)) { 13677 obj = valuePop(ctxt); 13678 oldset = obj->nodesetval; 13679 oldnode = ctxt->context->node; 13680 oldDoc = ctxt->context->doc; 13681 oldcs = ctxt->context->contextSize; 13682 oldpp = ctxt->context->proximityPosition; 13683 tmp = NULL; 13684 /* 13685 * Initialize the new set. 13686 * Also set the xpath document in case things like 13687 * key() evaluation are attempted on the predicate 13688 */ 13689 newset = xmlXPathNodeSetCreate(NULL); 13690 /* 13691 * SPEC XPath 1.0: 13692 * "For each node in the node-set to be filtered, the 13693 * PredicateExpr is evaluated with that node as the 13694 * context node, with the number of nodes in the 13695 * node-set as the context size, and with the proximity 13696 * position of the node in the node-set with respect to 13697 * the axis as the context position;" 13698 * @oldset is the node-set" to be filtered. 13699 * 13700 * SPEC XPath 1.0: 13701 * "only predicates change the context position and 13702 * context size (see [2.4 Predicates])." 13703 * Example: 13704 * node-set context pos 13705 * nA 1 13706 * nB 2 13707 * nC 3 13708 * After applying predicate [position() > 1] : 13709 * node-set context pos 13710 * nB 1 13711 * nC 2 13712 * 13713 * removed the first node in the node-set, then 13714 * the context position of the 13715 */ 13716 for (i = 0; i < oldset->nodeNr; i++) { 13717 /* 13718 * Run the evaluation with a node list made of 13719 * a single item in the nodeset. 13720 */ 13721 ctxt->context->node = oldset->nodeTab[i]; 13722 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) && 13723 (oldset->nodeTab[i]->doc != NULL)) 13724 ctxt->context->doc = oldset->nodeTab[i]->doc; 13725 if (tmp == NULL) { 13726 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13727 ctxt->context->node); 13728 } else { 13729 if (xmlXPathNodeSetAddUnique(tmp->nodesetval, 13730 ctxt->context->node) < 0) { 13731 ctxt->error = XPATH_MEMORY_ERROR; 13732 } 13733 } 13734 valuePush(ctxt, tmp); 13735 ctxt->context->contextSize = oldset->nodeNr; 13736 ctxt->context->proximityPosition = i + 1; 13737 /* 13738 * Evaluate the predicate against the context node. 13739 * Can/should we optimize position() predicates 13740 * here (e.g. "[1]")? 13741 */ 13742 if (op->ch2 != -1) 13743 total += 13744 xmlXPathCompOpEval(ctxt, 13745 &comp->steps[op->ch2]); 13746 if (ctxt->error != XPATH_EXPRESSION_OK) { 13747 xmlXPathFreeNodeSet(newset); 13748 goto filter_error; 13749 } 13750 13751 /* 13752 * The result of the evaluation needs to be tested to 13753 * decide whether the filter succeeded or not 13754 */ 13755 /* 13756 * OPTIMIZE TODO: Can we use 13757 * xmlXPathNodeSetAdd*Unique()* instead? 13758 */ 13759 res = valuePop(ctxt); 13760 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 13761 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) 13762 < 0) 13763 ctxt->error = XPATH_MEMORY_ERROR; 13764 } 13765 13766 /* 13767 * Cleanup 13768 */ 13769 if (res != NULL) { 13770 xmlXPathReleaseObject(ctxt->context, res); 13771 } 13772 if (ctxt->value == tmp) { 13773 valuePop(ctxt); 13774 xmlXPathNodeSetClear(tmp->nodesetval, 1); 13775 /* 13776 * Don't free the temporary nodeset 13777 * in order to avoid massive recreation inside this 13778 * loop. 13779 */ 13780 } else 13781 tmp = NULL; 13782 } 13783 if (tmp != NULL) 13784 xmlXPathReleaseObject(ctxt->context, tmp); 13785 /* 13786 * The result is used as the new evaluation set. 13787 */ 13788 valuePush(ctxt, 13789 xmlXPathCacheWrapNodeSet(ctxt->context, newset)); 13790 filter_error: 13791 xmlXPathReleaseObject(ctxt->context, obj); 13792 ctxt->context->node = oldnode; 13793 ctxt->context->doc = oldDoc; 13794 ctxt->context->contextSize = oldcs; 13795 ctxt->context->proximityPosition = oldpp; 13796 } 13797 return (total); 13798 } 13799 case XPATH_OP_SORT: 13800 if (op->ch1 != -1) 13801 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13802 CHECK_ERROR0; 13803 if ((ctxt->value != NULL) && 13804 (ctxt->value->type == XPATH_NODESET) && 13805 (ctxt->value->nodesetval != NULL) && 13806 (ctxt->value->nodesetval->nodeNr > 1)) 13807 { 13808 xmlXPathNodeSetSort(ctxt->value->nodesetval); 13809 } 13810 return (total); 13811 #ifdef LIBXML_XPTR_ENABLED 13812 case XPATH_OP_RANGETO:{ 13813 xmlXPathObjectPtr range; 13814 xmlXPathObjectPtr res, obj; 13815 xmlXPathObjectPtr tmp; 13816 xmlLocationSetPtr newlocset = NULL; 13817 xmlLocationSetPtr oldlocset; 13818 xmlNodeSetPtr oldset; 13819 xmlNodePtr oldnode = ctxt->context->node; 13820 int oldcs = ctxt->context->contextSize; 13821 int oldpp = ctxt->context->proximityPosition; 13822 int i, j; 13823 13824 if (op->ch1 != -1) { 13825 total += 13826 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13827 CHECK_ERROR0; 13828 } 13829 if (ctxt->value == NULL) { 13830 XP_ERROR0(XPATH_INVALID_OPERAND); 13831 } 13832 if (op->ch2 == -1) 13833 return (total); 13834 13835 if (ctxt->value->type == XPATH_LOCATIONSET) { 13836 /* 13837 * Extract the old locset, and then evaluate the result of the 13838 * expression for all the element in the locset. use it to grow 13839 * up a new locset. 13840 */ 13841 CHECK_TYPE0(XPATH_LOCATIONSET); 13842 13843 if ((ctxt->value->user == NULL) || 13844 (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0)) 13845 return (total); 13846 13847 obj = valuePop(ctxt); 13848 oldlocset = obj->user; 13849 13850 newlocset = xmlXPtrLocationSetCreate(NULL); 13851 13852 for (i = 0; i < oldlocset->locNr; i++) { 13853 /* 13854 * Run the evaluation with a node list made of a 13855 * single item in the nodelocset. 13856 */ 13857 ctxt->context->node = oldlocset->locTab[i]->user; 13858 ctxt->context->contextSize = oldlocset->locNr; 13859 ctxt->context->proximityPosition = i + 1; 13860 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13861 ctxt->context->node); 13862 valuePush(ctxt, tmp); 13863 13864 if (op->ch2 != -1) 13865 total += 13866 xmlXPathCompOpEval(ctxt, 13867 &comp->steps[op->ch2]); 13868 if (ctxt->error != XPATH_EXPRESSION_OK) { 13869 xmlXPtrFreeLocationSet(newlocset); 13870 goto rangeto_error; 13871 } 13872 13873 res = valuePop(ctxt); 13874 if (res->type == XPATH_LOCATIONSET) { 13875 xmlLocationSetPtr rloc = 13876 (xmlLocationSetPtr)res->user; 13877 for (j=0; j<rloc->locNr; j++) { 13878 range = xmlXPtrNewRange( 13879 oldlocset->locTab[i]->user, 13880 oldlocset->locTab[i]->index, 13881 rloc->locTab[j]->user2, 13882 rloc->locTab[j]->index2); 13883 if (range != NULL) { 13884 xmlXPtrLocationSetAdd(newlocset, range); 13885 } 13886 } 13887 } else { 13888 range = xmlXPtrNewRangeNodeObject( 13889 (xmlNodePtr)oldlocset->locTab[i]->user, res); 13890 if (range != NULL) { 13891 xmlXPtrLocationSetAdd(newlocset,range); 13892 } 13893 } 13894 13895 /* 13896 * Cleanup 13897 */ 13898 if (res != NULL) { 13899 xmlXPathReleaseObject(ctxt->context, res); 13900 } 13901 if (ctxt->value == tmp) { 13902 res = valuePop(ctxt); 13903 xmlXPathReleaseObject(ctxt->context, res); 13904 } 13905 } 13906 } else { /* Not a location set */ 13907 CHECK_TYPE0(XPATH_NODESET); 13908 obj = valuePop(ctxt); 13909 oldset = obj->nodesetval; 13910 13911 newlocset = xmlXPtrLocationSetCreate(NULL); 13912 13913 if (oldset != NULL) { 13914 for (i = 0; i < oldset->nodeNr; i++) { 13915 /* 13916 * Run the evaluation with a node list made of a single item 13917 * in the nodeset. 13918 */ 13919 ctxt->context->node = oldset->nodeTab[i]; 13920 /* 13921 * OPTIMIZE TODO: Avoid recreation for every iteration. 13922 */ 13923 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13924 ctxt->context->node); 13925 valuePush(ctxt, tmp); 13926 13927 if (op->ch2 != -1) 13928 total += 13929 xmlXPathCompOpEval(ctxt, 13930 &comp->steps[op->ch2]); 13931 if (ctxt->error != XPATH_EXPRESSION_OK) { 13932 xmlXPtrFreeLocationSet(newlocset); 13933 goto rangeto_error; 13934 } 13935 13936 res = valuePop(ctxt); 13937 range = 13938 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i], 13939 res); 13940 if (range != NULL) { 13941 xmlXPtrLocationSetAdd(newlocset, range); 13942 } 13943 13944 /* 13945 * Cleanup 13946 */ 13947 if (res != NULL) { 13948 xmlXPathReleaseObject(ctxt->context, res); 13949 } 13950 if (ctxt->value == tmp) { 13951 res = valuePop(ctxt); 13952 xmlXPathReleaseObject(ctxt->context, res); 13953 } 13954 } 13955 } 13956 } 13957 13958 /* 13959 * The result is used as the new evaluation set. 13960 */ 13961 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset)); 13962 rangeto_error: 13963 xmlXPathReleaseObject(ctxt->context, obj); 13964 ctxt->context->node = oldnode; 13965 ctxt->context->contextSize = oldcs; 13966 ctxt->context->proximityPosition = oldpp; 13967 return (total); 13968 } 13969 #endif /* LIBXML_XPTR_ENABLED */ 13970 } 13971 xmlGenericError(xmlGenericErrorContext, 13972 "XPath: unknown precompiled operation %d\n", op->op); 13973 ctxt->error = XPATH_INVALID_OPERAND; 13974 return (total); 13975 } 13976 13977 /** 13978 * xmlXPathCompOpEvalToBoolean: 13979 * @ctxt: the XPath parser context 13980 * 13981 * Evaluates if the expression evaluates to true. 13982 * 13983 * Returns 1 if true, 0 if false and -1 on API or internal errors. 13984 */ 13985 static int 13986 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt, 13987 xmlXPathStepOpPtr op, 13988 int isPredicate) 13989 { 13990 xmlXPathObjectPtr resObj = NULL; 13991 13992 start: 13993 /* comp = ctxt->comp; */ 13994 switch (op->op) { 13995 case XPATH_OP_END: 13996 return (0); 13997 case XPATH_OP_VALUE: 13998 resObj = (xmlXPathObjectPtr) op->value4; 13999 if (isPredicate) 14000 return(xmlXPathEvaluatePredicateResult(ctxt, resObj)); 14001 return(xmlXPathCastToBoolean(resObj)); 14002 case XPATH_OP_SORT: 14003 /* 14004 * We don't need sorting for boolean results. Skip this one. 14005 */ 14006 if (op->ch1 != -1) { 14007 op = &ctxt->comp->steps[op->ch1]; 14008 goto start; 14009 } 14010 return(0); 14011 case XPATH_OP_COLLECT: 14012 if (op->ch1 == -1) 14013 return(0); 14014 14015 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]); 14016 if (ctxt->error != XPATH_EXPRESSION_OK) 14017 return(-1); 14018 14019 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1); 14020 if (ctxt->error != XPATH_EXPRESSION_OK) 14021 return(-1); 14022 14023 resObj = valuePop(ctxt); 14024 if (resObj == NULL) 14025 return(-1); 14026 break; 14027 default: 14028 /* 14029 * Fallback to call xmlXPathCompOpEval(). 14030 */ 14031 xmlXPathCompOpEval(ctxt, op); 14032 if (ctxt->error != XPATH_EXPRESSION_OK) 14033 return(-1); 14034 14035 resObj = valuePop(ctxt); 14036 if (resObj == NULL) 14037 return(-1); 14038 break; 14039 } 14040 14041 if (resObj) { 14042 int res; 14043 14044 if (resObj->type == XPATH_BOOLEAN) { 14045 res = resObj->boolval; 14046 } else if (isPredicate) { 14047 /* 14048 * For predicates a result of type "number" is handled 14049 * differently: 14050 * SPEC XPath 1.0: 14051 * "If the result is a number, the result will be converted 14052 * to true if the number is equal to the context position 14053 * and will be converted to false otherwise;" 14054 */ 14055 res = xmlXPathEvaluatePredicateResult(ctxt, resObj); 14056 } else { 14057 res = xmlXPathCastToBoolean(resObj); 14058 } 14059 xmlXPathReleaseObject(ctxt->context, resObj); 14060 return(res); 14061 } 14062 14063 return(0); 14064 } 14065 14066 #ifdef XPATH_STREAMING 14067 /** 14068 * xmlXPathRunStreamEval: 14069 * @ctxt: the XPath parser context with the compiled expression 14070 * 14071 * Evaluate the Precompiled Streamable XPath expression in the given context. 14072 */ 14073 static int 14074 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp, 14075 xmlXPathObjectPtr *resultSeq, int toBool) 14076 { 14077 int max_depth, min_depth; 14078 int from_root; 14079 int ret, depth; 14080 int eval_all_nodes; 14081 xmlNodePtr cur = NULL, limit = NULL; 14082 xmlStreamCtxtPtr patstream = NULL; 14083 14084 int nb_nodes = 0; 14085 14086 if ((ctxt == NULL) || (comp == NULL)) 14087 return(-1); 14088 max_depth = xmlPatternMaxDepth(comp); 14089 if (max_depth == -1) 14090 return(-1); 14091 if (max_depth == -2) 14092 max_depth = 10000; 14093 min_depth = xmlPatternMinDepth(comp); 14094 if (min_depth == -1) 14095 return(-1); 14096 from_root = xmlPatternFromRoot(comp); 14097 if (from_root < 0) 14098 return(-1); 14099 #if 0 14100 printf("stream eval: depth %d from root %d\n", max_depth, from_root); 14101 #endif 14102 14103 if (! toBool) { 14104 if (resultSeq == NULL) 14105 return(-1); 14106 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL); 14107 if (*resultSeq == NULL) 14108 return(-1); 14109 } 14110 14111 /* 14112 * handle the special cases of "/" amd "." being matched 14113 */ 14114 if (min_depth == 0) { 14115 if (from_root) { 14116 /* Select "/" */ 14117 if (toBool) 14118 return(1); 14119 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, 14120 (xmlNodePtr) ctxt->doc); 14121 } else { 14122 /* Select "self::node()" */ 14123 if (toBool) 14124 return(1); 14125 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node); 14126 } 14127 } 14128 if (max_depth == 0) { 14129 return(0); 14130 } 14131 14132 if (from_root) { 14133 cur = (xmlNodePtr)ctxt->doc; 14134 } else if (ctxt->node != NULL) { 14135 switch (ctxt->node->type) { 14136 case XML_ELEMENT_NODE: 14137 case XML_DOCUMENT_NODE: 14138 case XML_DOCUMENT_FRAG_NODE: 14139 case XML_HTML_DOCUMENT_NODE: 14140 #ifdef LIBXML_DOCB_ENABLED 14141 case XML_DOCB_DOCUMENT_NODE: 14142 #endif 14143 cur = ctxt->node; 14144 break; 14145 case XML_ATTRIBUTE_NODE: 14146 case XML_TEXT_NODE: 14147 case XML_CDATA_SECTION_NODE: 14148 case XML_ENTITY_REF_NODE: 14149 case XML_ENTITY_NODE: 14150 case XML_PI_NODE: 14151 case XML_COMMENT_NODE: 14152 case XML_NOTATION_NODE: 14153 case XML_DTD_NODE: 14154 case XML_DOCUMENT_TYPE_NODE: 14155 case XML_ELEMENT_DECL: 14156 case XML_ATTRIBUTE_DECL: 14157 case XML_ENTITY_DECL: 14158 case XML_NAMESPACE_DECL: 14159 case XML_XINCLUDE_START: 14160 case XML_XINCLUDE_END: 14161 break; 14162 } 14163 limit = cur; 14164 } 14165 if (cur == NULL) { 14166 return(0); 14167 } 14168 14169 patstream = xmlPatternGetStreamCtxt(comp); 14170 if (patstream == NULL) { 14171 /* 14172 * QUESTION TODO: Is this an error? 14173 */ 14174 return(0); 14175 } 14176 14177 eval_all_nodes = xmlStreamWantsAnyNode(patstream); 14178 14179 if (from_root) { 14180 ret = xmlStreamPush(patstream, NULL, NULL); 14181 if (ret < 0) { 14182 } else if (ret == 1) { 14183 if (toBool) 14184 goto return_1; 14185 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur); 14186 } 14187 } 14188 depth = 0; 14189 goto scan_children; 14190 next_node: 14191 do { 14192 nb_nodes++; 14193 14194 switch (cur->type) { 14195 case XML_ELEMENT_NODE: 14196 case XML_TEXT_NODE: 14197 case XML_CDATA_SECTION_NODE: 14198 case XML_COMMENT_NODE: 14199 case XML_PI_NODE: 14200 if (cur->type == XML_ELEMENT_NODE) { 14201 ret = xmlStreamPush(patstream, cur->name, 14202 (cur->ns ? cur->ns->href : NULL)); 14203 } else if (eval_all_nodes) 14204 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type); 14205 else 14206 break; 14207 14208 if (ret < 0) { 14209 /* NOP. */ 14210 } else if (ret == 1) { 14211 if (toBool) 14212 goto return_1; 14213 if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur) 14214 < 0) { 14215 ctxt->lastError.domain = XML_FROM_XPATH; 14216 ctxt->lastError.code = XML_ERR_NO_MEMORY; 14217 } 14218 } 14219 if ((cur->children == NULL) || (depth >= max_depth)) { 14220 ret = xmlStreamPop(patstream); 14221 while (cur->next != NULL) { 14222 cur = cur->next; 14223 if ((cur->type != XML_ENTITY_DECL) && 14224 (cur->type != XML_DTD_NODE)) 14225 goto next_node; 14226 } 14227 } 14228 default: 14229 break; 14230 } 14231 14232 scan_children: 14233 if (cur->type == XML_NAMESPACE_DECL) break; 14234 if ((cur->children != NULL) && (depth < max_depth)) { 14235 /* 14236 * Do not descend on entities declarations 14237 */ 14238 if (cur->children->type != XML_ENTITY_DECL) { 14239 cur = cur->children; 14240 depth++; 14241 /* 14242 * Skip DTDs 14243 */ 14244 if (cur->type != XML_DTD_NODE) 14245 continue; 14246 } 14247 } 14248 14249 if (cur == limit) 14250 break; 14251 14252 while (cur->next != NULL) { 14253 cur = cur->next; 14254 if ((cur->type != XML_ENTITY_DECL) && 14255 (cur->type != XML_DTD_NODE)) 14256 goto next_node; 14257 } 14258 14259 do { 14260 cur = cur->parent; 14261 depth--; 14262 if ((cur == NULL) || (cur == limit)) 14263 goto done; 14264 if (cur->type == XML_ELEMENT_NODE) { 14265 ret = xmlStreamPop(patstream); 14266 } else if ((eval_all_nodes) && 14267 ((cur->type == XML_TEXT_NODE) || 14268 (cur->type == XML_CDATA_SECTION_NODE) || 14269 (cur->type == XML_COMMENT_NODE) || 14270 (cur->type == XML_PI_NODE))) 14271 { 14272 ret = xmlStreamPop(patstream); 14273 } 14274 if (cur->next != NULL) { 14275 cur = cur->next; 14276 break; 14277 } 14278 } while (cur != NULL); 14279 14280 } while ((cur != NULL) && (depth >= 0)); 14281 14282 done: 14283 14284 #if 0 14285 printf("stream eval: checked %d nodes selected %d\n", 14286 nb_nodes, retObj->nodesetval->nodeNr); 14287 #endif 14288 14289 if (patstream) 14290 xmlFreeStreamCtxt(patstream); 14291 return(0); 14292 14293 return_1: 14294 if (patstream) 14295 xmlFreeStreamCtxt(patstream); 14296 return(1); 14297 } 14298 #endif /* XPATH_STREAMING */ 14299 14300 /** 14301 * xmlXPathRunEval: 14302 * @ctxt: the XPath parser context with the compiled expression 14303 * @toBool: evaluate to a boolean result 14304 * 14305 * Evaluate the Precompiled XPath expression in the given context. 14306 */ 14307 static int 14308 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool) 14309 { 14310 xmlXPathCompExprPtr comp; 14311 14312 if ((ctxt == NULL) || (ctxt->comp == NULL)) 14313 return(-1); 14314 14315 if (ctxt->valueTab == NULL) { 14316 /* Allocate the value stack */ 14317 ctxt->valueTab = (xmlXPathObjectPtr *) 14318 xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); 14319 if (ctxt->valueTab == NULL) { 14320 xmlXPathPErrMemory(ctxt, "creating evaluation context\n"); 14321 xmlFree(ctxt); 14322 } 14323 ctxt->valueNr = 0; 14324 ctxt->valueMax = 10; 14325 ctxt->value = NULL; 14326 ctxt->valueFrame = 0; 14327 } 14328 #ifdef XPATH_STREAMING 14329 if (ctxt->comp->stream) { 14330 int res; 14331 14332 if (toBool) { 14333 /* 14334 * Evaluation to boolean result. 14335 */ 14336 res = xmlXPathRunStreamEval(ctxt->context, 14337 ctxt->comp->stream, NULL, 1); 14338 if (res != -1) 14339 return(res); 14340 } else { 14341 xmlXPathObjectPtr resObj = NULL; 14342 14343 /* 14344 * Evaluation to a sequence. 14345 */ 14346 res = xmlXPathRunStreamEval(ctxt->context, 14347 ctxt->comp->stream, &resObj, 0); 14348 14349 if ((res != -1) && (resObj != NULL)) { 14350 valuePush(ctxt, resObj); 14351 return(0); 14352 } 14353 if (resObj != NULL) 14354 xmlXPathReleaseObject(ctxt->context, resObj); 14355 } 14356 /* 14357 * QUESTION TODO: This falls back to normal XPath evaluation 14358 * if res == -1. Is this intended? 14359 */ 14360 } 14361 #endif 14362 comp = ctxt->comp; 14363 if (comp->last < 0) { 14364 xmlGenericError(xmlGenericErrorContext, 14365 "xmlXPathRunEval: last is less than zero\n"); 14366 return(-1); 14367 } 14368 if (toBool) 14369 return(xmlXPathCompOpEvalToBoolean(ctxt, 14370 &comp->steps[comp->last], 0)); 14371 else 14372 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]); 14373 14374 return(0); 14375 } 14376 14377 /************************************************************************ 14378 * * 14379 * Public interfaces * 14380 * * 14381 ************************************************************************/ 14382 14383 /** 14384 * xmlXPathEvalPredicate: 14385 * @ctxt: the XPath context 14386 * @res: the Predicate Expression evaluation result 14387 * 14388 * Evaluate a predicate result for the current node. 14389 * A PredicateExpr is evaluated by evaluating the Expr and converting 14390 * the result to a boolean. If the result is a number, the result will 14391 * be converted to true if the number is equal to the position of the 14392 * context node in the context node list (as returned by the position 14393 * function) and will be converted to false otherwise; if the result 14394 * is not a number, then the result will be converted as if by a call 14395 * to the boolean function. 14396 * 14397 * Returns 1 if predicate is true, 0 otherwise 14398 */ 14399 int 14400 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) { 14401 if ((ctxt == NULL) || (res == NULL)) return(0); 14402 switch (res->type) { 14403 case XPATH_BOOLEAN: 14404 return(res->boolval); 14405 case XPATH_NUMBER: 14406 return(res->floatval == ctxt->proximityPosition); 14407 case XPATH_NODESET: 14408 case XPATH_XSLT_TREE: 14409 if (res->nodesetval == NULL) 14410 return(0); 14411 return(res->nodesetval->nodeNr != 0); 14412 case XPATH_STRING: 14413 return((res->stringval != NULL) && 14414 (xmlStrlen(res->stringval) != 0)); 14415 default: 14416 STRANGE 14417 } 14418 return(0); 14419 } 14420 14421 /** 14422 * xmlXPathEvaluatePredicateResult: 14423 * @ctxt: the XPath Parser context 14424 * @res: the Predicate Expression evaluation result 14425 * 14426 * Evaluate a predicate result for the current node. 14427 * A PredicateExpr is evaluated by evaluating the Expr and converting 14428 * the result to a boolean. If the result is a number, the result will 14429 * be converted to true if the number is equal to the position of the 14430 * context node in the context node list (as returned by the position 14431 * function) and will be converted to false otherwise; if the result 14432 * is not a number, then the result will be converted as if by a call 14433 * to the boolean function. 14434 * 14435 * Returns 1 if predicate is true, 0 otherwise 14436 */ 14437 int 14438 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt, 14439 xmlXPathObjectPtr res) { 14440 if ((ctxt == NULL) || (res == NULL)) return(0); 14441 switch (res->type) { 14442 case XPATH_BOOLEAN: 14443 return(res->boolval); 14444 case XPATH_NUMBER: 14445 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200)) 14446 return((res->floatval == ctxt->context->proximityPosition) && 14447 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/ 14448 #else 14449 return(res->floatval == ctxt->context->proximityPosition); 14450 #endif 14451 case XPATH_NODESET: 14452 case XPATH_XSLT_TREE: 14453 if (res->nodesetval == NULL) 14454 return(0); 14455 return(res->nodesetval->nodeNr != 0); 14456 case XPATH_STRING: 14457 return((res->stringval != NULL) && (res->stringval[0] != 0)); 14458 #ifdef LIBXML_XPTR_ENABLED 14459 case XPATH_LOCATIONSET:{ 14460 xmlLocationSetPtr ptr = res->user; 14461 if (ptr == NULL) 14462 return(0); 14463 return (ptr->locNr != 0); 14464 } 14465 #endif 14466 default: 14467 STRANGE 14468 } 14469 return(0); 14470 } 14471 14472 #ifdef XPATH_STREAMING 14473 /** 14474 * xmlXPathTryStreamCompile: 14475 * @ctxt: an XPath context 14476 * @str: the XPath expression 14477 * 14478 * Try to compile the XPath expression as a streamable subset. 14479 * 14480 * Returns the compiled expression or NULL if failed to compile. 14481 */ 14482 static xmlXPathCompExprPtr 14483 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { 14484 /* 14485 * Optimization: use streaming patterns when the XPath expression can 14486 * be compiled to a stream lookup 14487 */ 14488 xmlPatternPtr stream; 14489 xmlXPathCompExprPtr comp; 14490 xmlDictPtr dict = NULL; 14491 const xmlChar **namespaces = NULL; 14492 xmlNsPtr ns; 14493 int i, j; 14494 14495 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) && 14496 (!xmlStrchr(str, '@'))) { 14497 const xmlChar *tmp; 14498 14499 /* 14500 * We don't try to handle expressions using the verbose axis 14501 * specifiers ("::"), just the simplied form at this point. 14502 * Additionally, if there is no list of namespaces available and 14503 * there's a ":" in the expression, indicating a prefixed QName, 14504 * then we won't try to compile either. xmlPatterncompile() needs 14505 * to have a list of namespaces at compilation time in order to 14506 * compile prefixed name tests. 14507 */ 14508 tmp = xmlStrchr(str, ':'); 14509 if ((tmp != NULL) && 14510 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':'))) 14511 return(NULL); 14512 14513 if (ctxt != NULL) { 14514 dict = ctxt->dict; 14515 if (ctxt->nsNr > 0) { 14516 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*)); 14517 if (namespaces == NULL) { 14518 xmlXPathErrMemory(ctxt, "allocating namespaces array\n"); 14519 return(NULL); 14520 } 14521 for (i = 0, j = 0; (j < ctxt->nsNr); j++) { 14522 ns = ctxt->namespaces[j]; 14523 namespaces[i++] = ns->href; 14524 namespaces[i++] = ns->prefix; 14525 } 14526 namespaces[i++] = NULL; 14527 namespaces[i] = NULL; 14528 } 14529 } 14530 14531 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, 14532 &namespaces[0]); 14533 if (namespaces != NULL) { 14534 xmlFree((xmlChar **)namespaces); 14535 } 14536 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) { 14537 comp = xmlXPathNewCompExpr(); 14538 if (comp == NULL) { 14539 xmlXPathErrMemory(ctxt, "allocating streamable expression\n"); 14540 return(NULL); 14541 } 14542 comp->stream = stream; 14543 comp->dict = dict; 14544 if (comp->dict) 14545 xmlDictReference(comp->dict); 14546 return(comp); 14547 } 14548 xmlFreePattern(stream); 14549 } 14550 return(NULL); 14551 } 14552 #endif /* XPATH_STREAMING */ 14553 14554 static void 14555 xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op) 14556 { 14557 /* 14558 * Try to rewrite "descendant-or-self::node()/foo" to an optimized 14559 * internal representation. 14560 */ 14561 14562 if ((op->op == XPATH_OP_COLLECT /* 11 */) && 14563 (op->ch1 != -1) && 14564 (op->ch2 == -1 /* no predicate */)) 14565 { 14566 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1]; 14567 14568 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) && 14569 ((xmlXPathAxisVal) prevop->value == 14570 AXIS_DESCENDANT_OR_SELF) && 14571 (prevop->ch2 == -1) && 14572 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) && 14573 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE)) 14574 { 14575 /* 14576 * This is a "descendant-or-self::node()" without predicates. 14577 * Try to eliminate it. 14578 */ 14579 14580 switch ((xmlXPathAxisVal) op->value) { 14581 case AXIS_CHILD: 14582 case AXIS_DESCENDANT: 14583 /* 14584 * Convert "descendant-or-self::node()/child::" or 14585 * "descendant-or-self::node()/descendant::" to 14586 * "descendant::" 14587 */ 14588 op->ch1 = prevop->ch1; 14589 op->value = AXIS_DESCENDANT; 14590 break; 14591 case AXIS_SELF: 14592 case AXIS_DESCENDANT_OR_SELF: 14593 /* 14594 * Convert "descendant-or-self::node()/self::" or 14595 * "descendant-or-self::node()/descendant-or-self::" to 14596 * to "descendant-or-self::" 14597 */ 14598 op->ch1 = prevop->ch1; 14599 op->value = AXIS_DESCENDANT_OR_SELF; 14600 break; 14601 default: 14602 break; 14603 } 14604 } 14605 } 14606 14607 /* OP_VALUE has invalid ch1. */ 14608 if (op->op == XPATH_OP_VALUE) 14609 return; 14610 14611 /* Recurse */ 14612 if (op->ch1 != -1) 14613 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]); 14614 if (op->ch2 != -1) 14615 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]); 14616 } 14617 14618 /** 14619 * xmlXPathCtxtCompile: 14620 * @ctxt: an XPath context 14621 * @str: the XPath expression 14622 * 14623 * Compile an XPath expression 14624 * 14625 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL. 14626 * the caller has to free the object. 14627 */ 14628 xmlXPathCompExprPtr 14629 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { 14630 xmlXPathParserContextPtr pctxt; 14631 xmlXPathCompExprPtr comp; 14632 14633 #ifdef XPATH_STREAMING 14634 comp = xmlXPathTryStreamCompile(ctxt, str); 14635 if (comp != NULL) 14636 return(comp); 14637 #endif 14638 14639 xmlXPathInit(); 14640 14641 pctxt = xmlXPathNewParserContext(str, ctxt); 14642 if (pctxt == NULL) 14643 return NULL; 14644 xmlXPathCompileExpr(pctxt, 1); 14645 14646 if( pctxt->error != XPATH_EXPRESSION_OK ) 14647 { 14648 xmlXPathFreeParserContext(pctxt); 14649 return(NULL); 14650 } 14651 14652 if (*pctxt->cur != 0) { 14653 /* 14654 * aleksey: in some cases this line prints *second* error message 14655 * (see bug #78858) and probably this should be fixed. 14656 * However, we are not sure that all error messages are printed 14657 * out in other places. It's not critical so we leave it as-is for now 14658 */ 14659 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR); 14660 comp = NULL; 14661 } else { 14662 comp = pctxt->comp; 14663 pctxt->comp = NULL; 14664 } 14665 xmlXPathFreeParserContext(pctxt); 14666 14667 if (comp != NULL) { 14668 comp->expr = xmlStrdup(str); 14669 #ifdef DEBUG_EVAL_COUNTS 14670 comp->string = xmlStrdup(str); 14671 comp->nb = 0; 14672 #endif 14673 if ((comp->nbStep > 1) && (comp->last >= 0)) { 14674 xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]); 14675 } 14676 } 14677 return(comp); 14678 } 14679 14680 /** 14681 * xmlXPathCompile: 14682 * @str: the XPath expression 14683 * 14684 * Compile an XPath expression 14685 * 14686 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL. 14687 * the caller has to free the object. 14688 */ 14689 xmlXPathCompExprPtr 14690 xmlXPathCompile(const xmlChar *str) { 14691 return(xmlXPathCtxtCompile(NULL, str)); 14692 } 14693 14694 /** 14695 * xmlXPathCompiledEvalInternal: 14696 * @comp: the compiled XPath expression 14697 * @ctxt: the XPath context 14698 * @resObj: the resulting XPath object or NULL 14699 * @toBool: 1 if only a boolean result is requested 14700 * 14701 * Evaluate the Precompiled XPath expression in the given context. 14702 * The caller has to free @resObj. 14703 * 14704 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14705 * the caller has to free the object. 14706 */ 14707 static int 14708 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp, 14709 xmlXPathContextPtr ctxt, 14710 xmlXPathObjectPtr *resObjPtr, 14711 int toBool) 14712 { 14713 xmlXPathParserContextPtr pctxt; 14714 xmlXPathObjectPtr resObj; 14715 #ifndef LIBXML_THREAD_ENABLED 14716 static int reentance = 0; 14717 #endif 14718 int res; 14719 14720 CHECK_CTXT_NEG(ctxt) 14721 14722 if (comp == NULL) 14723 return(-1); 14724 xmlXPathInit(); 14725 14726 #ifndef LIBXML_THREAD_ENABLED 14727 reentance++; 14728 if (reentance > 1) 14729 xmlXPathDisableOptimizer = 1; 14730 #endif 14731 14732 #ifdef DEBUG_EVAL_COUNTS 14733 comp->nb++; 14734 if ((comp->string != NULL) && (comp->nb > 100)) { 14735 fprintf(stderr, "100 x %s\n", comp->string); 14736 comp->nb = 0; 14737 } 14738 #endif 14739 pctxt = xmlXPathCompParserContext(comp, ctxt); 14740 res = xmlXPathRunEval(pctxt, toBool); 14741 14742 if (pctxt->error != XPATH_EXPRESSION_OK) { 14743 resObj = NULL; 14744 } else { 14745 resObj = valuePop(pctxt); 14746 if (resObj == NULL) { 14747 if (!toBool) 14748 xmlGenericError(xmlGenericErrorContext, 14749 "xmlXPathCompiledEval: No result on the stack.\n"); 14750 } else if (pctxt->valueNr > 0) { 14751 xmlGenericError(xmlGenericErrorContext, 14752 "xmlXPathCompiledEval: %d object(s) left on the stack.\n", 14753 pctxt->valueNr); 14754 } 14755 } 14756 14757 if (resObjPtr) 14758 *resObjPtr = resObj; 14759 else 14760 xmlXPathReleaseObject(ctxt, resObj); 14761 14762 pctxt->comp = NULL; 14763 xmlXPathFreeParserContext(pctxt); 14764 #ifndef LIBXML_THREAD_ENABLED 14765 reentance--; 14766 #endif 14767 14768 return(res); 14769 } 14770 14771 /** 14772 * xmlXPathCompiledEval: 14773 * @comp: the compiled XPath expression 14774 * @ctx: the XPath context 14775 * 14776 * Evaluate the Precompiled XPath expression in the given context. 14777 * 14778 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14779 * the caller has to free the object. 14780 */ 14781 xmlXPathObjectPtr 14782 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) 14783 { 14784 xmlXPathObjectPtr res = NULL; 14785 14786 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0); 14787 return(res); 14788 } 14789 14790 /** 14791 * xmlXPathCompiledEvalToBoolean: 14792 * @comp: the compiled XPath expression 14793 * @ctxt: the XPath context 14794 * 14795 * Applies the XPath boolean() function on the result of the given 14796 * compiled expression. 14797 * 14798 * Returns 1 if the expression evaluated to true, 0 if to false and 14799 * -1 in API and internal errors. 14800 */ 14801 int 14802 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp, 14803 xmlXPathContextPtr ctxt) 14804 { 14805 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1)); 14806 } 14807 14808 /** 14809 * xmlXPathEvalExpr: 14810 * @ctxt: the XPath Parser context 14811 * 14812 * Parse and evaluate an XPath expression in the given context, 14813 * then push the result on the context stack 14814 */ 14815 void 14816 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) { 14817 #ifdef XPATH_STREAMING 14818 xmlXPathCompExprPtr comp; 14819 #endif 14820 14821 if (ctxt == NULL) return; 14822 14823 #ifdef XPATH_STREAMING 14824 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base); 14825 if (comp != NULL) { 14826 if (ctxt->comp != NULL) 14827 xmlXPathFreeCompExpr(ctxt->comp); 14828 ctxt->comp = comp; 14829 } else 14830 #endif 14831 { 14832 xmlXPathCompileExpr(ctxt, 1); 14833 CHECK_ERROR; 14834 14835 /* Check for trailing characters. */ 14836 if (*ctxt->cur != 0) 14837 XP_ERROR(XPATH_EXPR_ERROR); 14838 14839 if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) 14840 xmlXPathOptimizeExpression(ctxt->comp, 14841 &ctxt->comp->steps[ctxt->comp->last]); 14842 } 14843 14844 xmlXPathRunEval(ctxt, 0); 14845 } 14846 14847 /** 14848 * xmlXPathEval: 14849 * @str: the XPath expression 14850 * @ctx: the XPath context 14851 * 14852 * Evaluate the XPath Location Path in the given context. 14853 * 14854 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14855 * the caller has to free the object. 14856 */ 14857 xmlXPathObjectPtr 14858 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) { 14859 xmlXPathParserContextPtr ctxt; 14860 xmlXPathObjectPtr res; 14861 14862 CHECK_CTXT(ctx) 14863 14864 xmlXPathInit(); 14865 14866 ctxt = xmlXPathNewParserContext(str, ctx); 14867 if (ctxt == NULL) 14868 return NULL; 14869 xmlXPathEvalExpr(ctxt); 14870 14871 if (ctxt->error != XPATH_EXPRESSION_OK) { 14872 res = NULL; 14873 } else { 14874 res = valuePop(ctxt); 14875 if (res == NULL) { 14876 xmlGenericError(xmlGenericErrorContext, 14877 "xmlXPathCompiledEval: No result on the stack.\n"); 14878 } else if (ctxt->valueNr > 0) { 14879 xmlGenericError(xmlGenericErrorContext, 14880 "xmlXPathCompiledEval: %d object(s) left on the stack.\n", 14881 ctxt->valueNr); 14882 } 14883 } 14884 14885 xmlXPathFreeParserContext(ctxt); 14886 return(res); 14887 } 14888 14889 /** 14890 * xmlXPathSetContextNode: 14891 * @node: the node to to use as the context node 14892 * @ctx: the XPath context 14893 * 14894 * Sets 'node' as the context node. The node must be in the same 14895 * document as that associated with the context. 14896 * 14897 * Returns -1 in case of error or 0 if successful 14898 */ 14899 int 14900 xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) { 14901 if ((node == NULL) || (ctx == NULL)) 14902 return(-1); 14903 14904 if (node->doc == ctx->doc) { 14905 ctx->node = node; 14906 return(0); 14907 } 14908 return(-1); 14909 } 14910 14911 /** 14912 * xmlXPathNodeEval: 14913 * @node: the node to to use as the context node 14914 * @str: the XPath expression 14915 * @ctx: the XPath context 14916 * 14917 * Evaluate the XPath Location Path in the given context. The node 'node' 14918 * is set as the context node. The context node is not restored. 14919 * 14920 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14921 * the caller has to free the object. 14922 */ 14923 xmlXPathObjectPtr 14924 xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) { 14925 if (str == NULL) 14926 return(NULL); 14927 if (xmlXPathSetContextNode(node, ctx) < 0) 14928 return(NULL); 14929 return(xmlXPathEval(str, ctx)); 14930 } 14931 14932 /** 14933 * xmlXPathEvalExpression: 14934 * @str: the XPath expression 14935 * @ctxt: the XPath context 14936 * 14937 * Alias for xmlXPathEval(). 14938 * 14939 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14940 * the caller has to free the object. 14941 */ 14942 xmlXPathObjectPtr 14943 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) { 14944 return(xmlXPathEval(str, ctxt)); 14945 } 14946 14947 /************************************************************************ 14948 * * 14949 * Extra functions not pertaining to the XPath spec * 14950 * * 14951 ************************************************************************/ 14952 /** 14953 * xmlXPathEscapeUriFunction: 14954 * @ctxt: the XPath Parser context 14955 * @nargs: the number of arguments 14956 * 14957 * Implement the escape-uri() XPath function 14958 * string escape-uri(string $str, bool $escape-reserved) 14959 * 14960 * This function applies the URI escaping rules defined in section 2 of [RFC 14961 * 2396] to the string supplied as $uri-part, which typically represents all 14962 * or part of a URI. The effect of the function is to replace any special 14963 * character in the string by an escape sequence of the form %xx%yy..., 14964 * where xxyy... is the hexadecimal representation of the octets used to 14965 * represent the character in UTF-8. 14966 * 14967 * The set of characters that are escaped depends on the setting of the 14968 * boolean argument $escape-reserved. 14969 * 14970 * If $escape-reserved is true, all characters are escaped other than lower 14971 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters 14972 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!" 14973 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only 14974 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and 14975 * A-F). 14976 * 14977 * If $escape-reserved is false, the behavior differs in that characters 14978 * referred to in [RFC 2396] as reserved characters are not escaped. These 14979 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",". 14980 * 14981 * [RFC 2396] does not define whether escaped URIs should use lower case or 14982 * upper case for hexadecimal digits. To ensure that escaped URIs can be 14983 * compared using string comparison functions, this function must always use 14984 * the upper-case letters A-F. 14985 * 14986 * Generally, $escape-reserved should be set to true when escaping a string 14987 * that is to form a single part of a URI, and to false when escaping an 14988 * entire URI or URI reference. 14989 * 14990 * In the case of non-ascii characters, the string is encoded according to 14991 * utf-8 and then converted according to RFC 2396. 14992 * 14993 * Examples 14994 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true()) 14995 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean" 14996 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false()) 14997 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean" 14998 * 14999 */ 15000 static void 15001 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) { 15002 xmlXPathObjectPtr str; 15003 int escape_reserved; 15004 xmlBufPtr target; 15005 xmlChar *cptr; 15006 xmlChar escape[4]; 15007 15008 CHECK_ARITY(2); 15009 15010 escape_reserved = xmlXPathPopBoolean(ctxt); 15011 15012 CAST_TO_STRING; 15013 str = valuePop(ctxt); 15014 15015 target = xmlBufCreate(); 15016 15017 escape[0] = '%'; 15018 escape[3] = 0; 15019 15020 if (target) { 15021 for (cptr = str->stringval; *cptr; cptr++) { 15022 if ((*cptr >= 'A' && *cptr <= 'Z') || 15023 (*cptr >= 'a' && *cptr <= 'z') || 15024 (*cptr >= '0' && *cptr <= '9') || 15025 *cptr == '-' || *cptr == '_' || *cptr == '.' || 15026 *cptr == '!' || *cptr == '~' || *cptr == '*' || 15027 *cptr == '\''|| *cptr == '(' || *cptr == ')' || 15028 (*cptr == '%' && 15029 ((cptr[1] >= 'A' && cptr[1] <= 'F') || 15030 (cptr[1] >= 'a' && cptr[1] <= 'f') || 15031 (cptr[1] >= '0' && cptr[1] <= '9')) && 15032 ((cptr[2] >= 'A' && cptr[2] <= 'F') || 15033 (cptr[2] >= 'a' && cptr[2] <= 'f') || 15034 (cptr[2] >= '0' && cptr[2] <= '9'))) || 15035 (!escape_reserved && 15036 (*cptr == ';' || *cptr == '/' || *cptr == '?' || 15037 *cptr == ':' || *cptr == '@' || *cptr == '&' || 15038 *cptr == '=' || *cptr == '+' || *cptr == '$' || 15039 *cptr == ','))) { 15040 xmlBufAdd(target, cptr, 1); 15041 } else { 15042 if ((*cptr >> 4) < 10) 15043 escape[1] = '0' + (*cptr >> 4); 15044 else 15045 escape[1] = 'A' - 10 + (*cptr >> 4); 15046 if ((*cptr & 0xF) < 10) 15047 escape[2] = '0' + (*cptr & 0xF); 15048 else 15049 escape[2] = 'A' - 10 + (*cptr & 0xF); 15050 15051 xmlBufAdd(target, &escape[0], 3); 15052 } 15053 } 15054 } 15055 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 15056 xmlBufContent(target))); 15057 xmlBufFree(target); 15058 xmlXPathReleaseObject(ctxt->context, str); 15059 } 15060 15061 /** 15062 * xmlXPathRegisterAllFunctions: 15063 * @ctxt: the XPath context 15064 * 15065 * Registers all default XPath functions in this context 15066 */ 15067 void 15068 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt) 15069 { 15070 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean", 15071 xmlXPathBooleanFunction); 15072 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling", 15073 xmlXPathCeilingFunction); 15074 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count", 15075 xmlXPathCountFunction); 15076 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat", 15077 xmlXPathConcatFunction); 15078 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains", 15079 xmlXPathContainsFunction); 15080 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id", 15081 xmlXPathIdFunction); 15082 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false", 15083 xmlXPathFalseFunction); 15084 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor", 15085 xmlXPathFloorFunction); 15086 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last", 15087 xmlXPathLastFunction); 15088 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang", 15089 xmlXPathLangFunction); 15090 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name", 15091 xmlXPathLocalNameFunction); 15092 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not", 15093 xmlXPathNotFunction); 15094 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name", 15095 xmlXPathNameFunction); 15096 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri", 15097 xmlXPathNamespaceURIFunction); 15098 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space", 15099 xmlXPathNormalizeFunction); 15100 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number", 15101 xmlXPathNumberFunction); 15102 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position", 15103 xmlXPathPositionFunction); 15104 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round", 15105 xmlXPathRoundFunction); 15106 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string", 15107 xmlXPathStringFunction); 15108 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length", 15109 xmlXPathStringLengthFunction); 15110 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with", 15111 xmlXPathStartsWithFunction); 15112 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring", 15113 xmlXPathSubstringFunction); 15114 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before", 15115 xmlXPathSubstringBeforeFunction); 15116 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after", 15117 xmlXPathSubstringAfterFunction); 15118 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum", 15119 xmlXPathSumFunction); 15120 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true", 15121 xmlXPathTrueFunction); 15122 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate", 15123 xmlXPathTranslateFunction); 15124 15125 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri", 15126 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions", 15127 xmlXPathEscapeUriFunction); 15128 } 15129 15130 #endif /* LIBXML_XPATH_ENABLED */ 15131 #define bottom_xpath 15132 #include "elfgcchack.h" 15133