1 /* 2 * xpath.c: XML Path Language implementation 3 * XPath is a language for addressing parts of an XML document, 4 * designed to be used by both XSLT and XPointer 5 *f 6 * Reference: W3C Recommendation 16 November 1999 7 * http://www.w3.org/TR/1999/REC-xpath-19991116 8 * Public reference: 9 * http://www.w3.org/TR/xpath 10 * 11 * See Copyright for the status of this software 12 * 13 * Author: daniel (at) veillard.com 14 * 15 */ 16 17 #define IN_LIBXML 18 #include "libxml.h" 19 20 #include <string.h> 21 22 #ifdef HAVE_SYS_TYPES_H 23 #include <sys/types.h> 24 #endif 25 #ifdef HAVE_MATH_H 26 #include <math.h> 27 #endif 28 #ifdef HAVE_FLOAT_H 29 #include <float.h> 30 #endif 31 #ifdef HAVE_CTYPE_H 32 #include <ctype.h> 33 #endif 34 #ifdef HAVE_SIGNAL_H 35 #include <signal.h> 36 #endif 37 38 #include <libxml/xmlmemory.h> 39 #include <libxml/tree.h> 40 #include <libxml/valid.h> 41 #include <libxml/xpath.h> 42 #include <libxml/xpathInternals.h> 43 #include <libxml/parserInternals.h> 44 #include <libxml/hash.h> 45 #ifdef LIBXML_XPTR_ENABLED 46 #include <libxml/xpointer.h> 47 #endif 48 #ifdef LIBXML_DEBUG_ENABLED 49 #include <libxml/debugXML.h> 50 #endif 51 #include <libxml/xmlerror.h> 52 #include <libxml/threads.h> 53 #include <libxml/globals.h> 54 #ifdef LIBXML_PATTERN_ENABLED 55 #include <libxml/pattern.h> 56 #endif 57 58 #ifdef LIBXML_PATTERN_ENABLED 59 #define XPATH_STREAMING 60 #endif 61 62 #define TODO \ 63 xmlGenericError(xmlGenericErrorContext, \ 64 "Unimplemented block at %s:%d\n", \ 65 __FILE__, __LINE__); 66 67 /* 68 * XP_OPTIMIZED_NON_ELEM_COMPARISON: 69 * If defined, this will use xmlXPathCmpNodesExt() instead of 70 * xmlXPathCmpNodes(). The new function is optimized comparison of 71 * non-element nodes; actually it will speed up comparison only if 72 * xmlXPathOrderDocElems() was called in order to index the elements of 73 * a tree in document order; Libxslt does such an indexing, thus it will 74 * benefit from this optimization. 75 */ 76 #define XP_OPTIMIZED_NON_ELEM_COMPARISON 77 78 /* 79 * XP_OPTIMIZED_FILTER_FIRST: 80 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]" 81 * in a way, that it stop evaluation at the first node. 82 */ 83 #define XP_OPTIMIZED_FILTER_FIRST 84 85 /* 86 * XP_DEBUG_OBJ_USAGE: 87 * Internal flag to enable tracking of how much XPath objects have been 88 * created. 89 */ 90 /* #define XP_DEBUG_OBJ_USAGE */ 91 92 /* 93 * TODO: 94 * There are a few spots where some tests are done which depend upon ascii 95 * data. These should be enhanced for full UTF8 support (see particularly 96 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT) 97 */ 98 99 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) 100 101 /************************************************************************ 102 * * 103 * Floating point stuff * 104 * * 105 ************************************************************************/ 106 107 #ifndef TRIO_REPLACE_STDIO 108 #define TRIO_PUBLIC static 109 #endif 110 #include "trionan.c" 111 112 /* 113 * The lack of portability of this section of the libc is annoying ! 114 */ 115 double xmlXPathNAN = 0; 116 double xmlXPathPINF = 1; 117 double xmlXPathNINF = -1; 118 static double xmlXPathNZERO = 0; /* not exported from headers */ 119 static int xmlXPathInitialized = 0; 120 121 /** 122 * xmlXPathInit: 123 * 124 * Initialize the XPath environment 125 */ 126 void 127 xmlXPathInit(void) { 128 if (xmlXPathInitialized) return; 129 130 xmlXPathPINF = trio_pinf(); 131 xmlXPathNINF = trio_ninf(); 132 xmlXPathNAN = trio_nan(); 133 xmlXPathNZERO = trio_nzero(); 134 135 xmlXPathInitialized = 1; 136 } 137 138 /** 139 * xmlXPathIsNaN: 140 * @val: a double value 141 * 142 * Provides a portable isnan() function to detect whether a double 143 * is a NotaNumber. Based on trio code 144 * http://sourceforge.net/projects/ctrio/ 145 * 146 * Returns 1 if the value is a NaN, 0 otherwise 147 */ 148 int 149 xmlXPathIsNaN(double val) { 150 return(trio_isnan(val)); 151 } 152 153 /** 154 * xmlXPathIsInf: 155 * @val: a double value 156 * 157 * Provides a portable isinf() function to detect whether a double 158 * is a +Infinite or -Infinite. Based on trio code 159 * http://sourceforge.net/projects/ctrio/ 160 * 161 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise 162 */ 163 int 164 xmlXPathIsInf(double val) { 165 return(trio_isinf(val)); 166 } 167 168 #endif /* SCHEMAS or XPATH */ 169 #ifdef LIBXML_XPATH_ENABLED 170 /** 171 * xmlXPathGetSign: 172 * @val: a double value 173 * 174 * Provides a portable function to detect the sign of a double 175 * Modified from trio code 176 * http://sourceforge.net/projects/ctrio/ 177 * 178 * Returns 1 if the value is Negative, 0 if positive 179 */ 180 static int 181 xmlXPathGetSign(double val) { 182 return(trio_signbit(val)); 183 } 184 185 186 /* 187 * TODO: when compatibility allows remove all "fake node libxslt" strings 188 * the test should just be name[0] = ' ' 189 */ 190 #ifdef DEBUG_XPATH_EXPRESSION 191 #define DEBUG_STEP 192 #define DEBUG_EXPR 193 #define DEBUG_EVAL_COUNTS 194 #endif 195 196 static xmlNs xmlXPathXMLNamespaceStruct = { 197 NULL, 198 XML_NAMESPACE_DECL, 199 XML_XML_NAMESPACE, 200 BAD_CAST "xml", 201 NULL, 202 NULL 203 }; 204 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct; 205 #ifndef LIBXML_THREAD_ENABLED 206 /* 207 * Optimizer is disabled only when threaded apps are detected while 208 * the library ain't compiled for thread safety. 209 */ 210 static int xmlXPathDisableOptimizer = 0; 211 #endif 212 213 /************************************************************************ 214 * * 215 * Error handling routines * 216 * * 217 ************************************************************************/ 218 219 /** 220 * XP_ERRORNULL: 221 * @X: the error code 222 * 223 * Macro to raise an XPath error and return NULL. 224 */ 225 #define XP_ERRORNULL(X) \ 226 { xmlXPathErr(ctxt, X); return(NULL); } 227 228 /* 229 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError 230 */ 231 static const char *xmlXPathErrorMessages[] = { 232 "Ok\n", 233 "Number encoding\n", 234 "Unfinished literal\n", 235 "Start of literal\n", 236 "Expected $ for variable reference\n", 237 "Undefined variable\n", 238 "Invalid predicate\n", 239 "Invalid expression\n", 240 "Missing closing curly brace\n", 241 "Unregistered function\n", 242 "Invalid operand\n", 243 "Invalid type\n", 244 "Invalid number of arguments\n", 245 "Invalid context size\n", 246 "Invalid context position\n", 247 "Memory allocation error\n", 248 "Syntax error\n", 249 "Resource error\n", 250 "Sub resource error\n", 251 "Undefined namespace prefix\n", 252 "Encoding error\n", 253 "Char out of XML range\n", 254 "Invalid or incomplete context\n", 255 "Stack usage errror\n", 256 "?? Unknown error ??\n" /* Must be last in the list! */ 257 }; 258 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \ 259 sizeof(xmlXPathErrorMessages[0])) - 1) 260 /** 261 * xmlXPathErrMemory: 262 * @ctxt: an XPath context 263 * @extra: extra informations 264 * 265 * Handle a redefinition of attribute error 266 */ 267 static void 268 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra) 269 { 270 if (ctxt != NULL) { 271 if (extra) { 272 xmlChar buf[200]; 273 274 xmlStrPrintf(buf, 200, 275 BAD_CAST "Memory allocation failed : %s\n", 276 extra); 277 ctxt->lastError.message = (char *) xmlStrdup(buf); 278 } else { 279 ctxt->lastError.message = (char *) 280 xmlStrdup(BAD_CAST "Memory allocation failed\n"); 281 } 282 ctxt->lastError.domain = XML_FROM_XPATH; 283 ctxt->lastError.code = XML_ERR_NO_MEMORY; 284 if (ctxt->error != NULL) 285 ctxt->error(ctxt->userData, &ctxt->lastError); 286 } else { 287 if (extra) 288 __xmlRaiseError(NULL, NULL, NULL, 289 NULL, NULL, XML_FROM_XPATH, 290 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, 291 extra, NULL, NULL, 0, 0, 292 "Memory allocation failed : %s\n", extra); 293 else 294 __xmlRaiseError(NULL, NULL, NULL, 295 NULL, NULL, XML_FROM_XPATH, 296 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, 297 NULL, NULL, NULL, 0, 0, 298 "Memory allocation failed\n"); 299 } 300 } 301 302 /** 303 * xmlXPathPErrMemory: 304 * @ctxt: an XPath parser context 305 * @extra: extra informations 306 * 307 * Handle a redefinition of attribute error 308 */ 309 static void 310 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra) 311 { 312 if (ctxt == NULL) 313 xmlXPathErrMemory(NULL, extra); 314 else { 315 ctxt->error = XPATH_MEMORY_ERROR; 316 xmlXPathErrMemory(ctxt->context, extra); 317 } 318 } 319 320 /** 321 * xmlXPathErr: 322 * @ctxt: a XPath parser context 323 * @error: the error code 324 * 325 * Handle an XPath error 326 */ 327 void 328 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error) 329 { 330 if ((error < 0) || (error > MAXERRNO)) 331 error = MAXERRNO; 332 if (ctxt == NULL) { 333 __xmlRaiseError(NULL, NULL, NULL, 334 NULL, NULL, XML_FROM_XPATH, 335 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, 336 XML_ERR_ERROR, NULL, 0, 337 NULL, NULL, NULL, 0, 0, 338 "%s", xmlXPathErrorMessages[error]); 339 return; 340 } 341 ctxt->error = error; 342 if (ctxt->context == NULL) { 343 __xmlRaiseError(NULL, NULL, NULL, 344 NULL, NULL, XML_FROM_XPATH, 345 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, 346 XML_ERR_ERROR, NULL, 0, 347 (const char *) ctxt->base, NULL, NULL, 348 ctxt->cur - ctxt->base, 0, 349 "%s", xmlXPathErrorMessages[error]); 350 return; 351 } 352 353 /* cleanup current last error */ 354 xmlResetError(&ctxt->context->lastError); 355 356 ctxt->context->lastError.domain = XML_FROM_XPATH; 357 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK - 358 XPATH_EXPRESSION_OK; 359 ctxt->context->lastError.level = XML_ERR_ERROR; 360 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base); 361 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base; 362 ctxt->context->lastError.node = ctxt->context->debugNode; 363 if (ctxt->context->error != NULL) { 364 ctxt->context->error(ctxt->context->userData, 365 &ctxt->context->lastError); 366 } else { 367 __xmlRaiseError(NULL, NULL, NULL, 368 NULL, ctxt->context->debugNode, XML_FROM_XPATH, 369 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, 370 XML_ERR_ERROR, NULL, 0, 371 (const char *) ctxt->base, NULL, NULL, 372 ctxt->cur - ctxt->base, 0, 373 "%s", xmlXPathErrorMessages[error]); 374 } 375 376 } 377 378 /** 379 * xmlXPatherror: 380 * @ctxt: the XPath Parser context 381 * @file: the file name 382 * @line: the line number 383 * @no: the error number 384 * 385 * Formats an error message. 386 */ 387 void 388 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED, 389 int line ATTRIBUTE_UNUSED, int no) { 390 xmlXPathErr(ctxt, no); 391 } 392 393 /************************************************************************ 394 * * 395 * Utilities * 396 * * 397 ************************************************************************/ 398 399 /** 400 * xsltPointerList: 401 * 402 * Pointer-list for various purposes. 403 */ 404 typedef struct _xmlPointerList xmlPointerList; 405 typedef xmlPointerList *xmlPointerListPtr; 406 struct _xmlPointerList { 407 void **items; 408 int number; 409 int size; 410 }; 411 /* 412 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt 413 * and here, we should make the functions public. 414 */ 415 static int 416 xmlPointerListAddSize(xmlPointerListPtr list, 417 void *item, 418 int initialSize) 419 { 420 if (list->items == NULL) { 421 if (initialSize <= 0) 422 initialSize = 1; 423 list->items = (void **) xmlMalloc( 424 initialSize * sizeof(void *)); 425 if (list->items == NULL) { 426 xmlXPathErrMemory(NULL, 427 "xmlPointerListCreate: allocating item\n"); 428 return(-1); 429 } 430 list->number = 0; 431 list->size = initialSize; 432 } else if (list->size <= list->number) { 433 list->size *= 2; 434 list->items = (void **) xmlRealloc(list->items, 435 list->size * sizeof(void *)); 436 if (list->items == NULL) { 437 xmlXPathErrMemory(NULL, 438 "xmlPointerListCreate: re-allocating item\n"); 439 list->size = 0; 440 return(-1); 441 } 442 } 443 list->items[list->number++] = item; 444 return(0); 445 } 446 447 /** 448 * xsltPointerListCreate: 449 * 450 * Creates an xsltPointerList structure. 451 * 452 * Returns a xsltPointerList structure or NULL in case of an error. 453 */ 454 static xmlPointerListPtr 455 xmlPointerListCreate(int initialSize) 456 { 457 xmlPointerListPtr ret; 458 459 ret = xmlMalloc(sizeof(xmlPointerList)); 460 if (ret == NULL) { 461 xmlXPathErrMemory(NULL, 462 "xmlPointerListCreate: allocating item\n"); 463 return (NULL); 464 } 465 memset(ret, 0, sizeof(xmlPointerList)); 466 if (initialSize > 0) { 467 xmlPointerListAddSize(ret, NULL, initialSize); 468 ret->number = 0; 469 } 470 return (ret); 471 } 472 473 /** 474 * xsltPointerListFree: 475 * 476 * Frees the xsltPointerList structure. This does not free 477 * the content of the list. 478 */ 479 static void 480 xmlPointerListFree(xmlPointerListPtr list) 481 { 482 if (list == NULL) 483 return; 484 if (list->items != NULL) 485 xmlFree(list->items); 486 xmlFree(list); 487 } 488 489 /************************************************************************ 490 * * 491 * Parser Types * 492 * * 493 ************************************************************************/ 494 495 /* 496 * Types are private: 497 */ 498 499 typedef enum { 500 XPATH_OP_END=0, 501 XPATH_OP_AND, 502 XPATH_OP_OR, 503 XPATH_OP_EQUAL, 504 XPATH_OP_CMP, 505 XPATH_OP_PLUS, 506 XPATH_OP_MULT, 507 XPATH_OP_UNION, 508 XPATH_OP_ROOT, 509 XPATH_OP_NODE, 510 XPATH_OP_RESET, /* 10 */ 511 XPATH_OP_COLLECT, 512 XPATH_OP_VALUE, /* 12 */ 513 XPATH_OP_VARIABLE, 514 XPATH_OP_FUNCTION, 515 XPATH_OP_ARG, 516 XPATH_OP_PREDICATE, 517 XPATH_OP_FILTER, /* 17 */ 518 XPATH_OP_SORT /* 18 */ 519 #ifdef LIBXML_XPTR_ENABLED 520 ,XPATH_OP_RANGETO 521 #endif 522 } xmlXPathOp; 523 524 typedef enum { 525 AXIS_ANCESTOR = 1, 526 AXIS_ANCESTOR_OR_SELF, 527 AXIS_ATTRIBUTE, 528 AXIS_CHILD, 529 AXIS_DESCENDANT, 530 AXIS_DESCENDANT_OR_SELF, 531 AXIS_FOLLOWING, 532 AXIS_FOLLOWING_SIBLING, 533 AXIS_NAMESPACE, 534 AXIS_PARENT, 535 AXIS_PRECEDING, 536 AXIS_PRECEDING_SIBLING, 537 AXIS_SELF 538 } xmlXPathAxisVal; 539 540 typedef enum { 541 NODE_TEST_NONE = 0, 542 NODE_TEST_TYPE = 1, 543 NODE_TEST_PI = 2, 544 NODE_TEST_ALL = 3, 545 NODE_TEST_NS = 4, 546 NODE_TEST_NAME = 5 547 } xmlXPathTestVal; 548 549 typedef enum { 550 NODE_TYPE_NODE = 0, 551 NODE_TYPE_COMMENT = XML_COMMENT_NODE, 552 NODE_TYPE_TEXT = XML_TEXT_NODE, 553 NODE_TYPE_PI = XML_PI_NODE 554 } xmlXPathTypeVal; 555 556 #define XP_REWRITE_DOS_CHILD_ELEM 1 557 558 typedef struct _xmlXPathStepOp xmlXPathStepOp; 559 typedef xmlXPathStepOp *xmlXPathStepOpPtr; 560 struct _xmlXPathStepOp { 561 xmlXPathOp op; /* The identifier of the operation */ 562 int ch1; /* First child */ 563 int ch2; /* Second child */ 564 int value; 565 int value2; 566 int value3; 567 void *value4; 568 void *value5; 569 void *cache; 570 void *cacheURI; 571 int rewriteType; 572 }; 573 574 struct _xmlXPathCompExpr { 575 int nbStep; /* Number of steps in this expression */ 576 int maxStep; /* Maximum number of steps allocated */ 577 xmlXPathStepOp *steps; /* ops for computation of this expression */ 578 int last; /* index of last step in expression */ 579 xmlChar *expr; /* the expression being computed */ 580 xmlDictPtr dict; /* the dictionnary to use if any */ 581 #ifdef DEBUG_EVAL_COUNTS 582 int nb; 583 xmlChar *string; 584 #endif 585 #ifdef XPATH_STREAMING 586 xmlPatternPtr stream; 587 #endif 588 }; 589 590 /************************************************************************ 591 * * 592 * Forward declarations * 593 * * 594 ************************************************************************/ 595 static void 596 xmlXPathFreeValueTree(xmlNodeSetPtr obj); 597 static void 598 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj); 599 static int 600 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt, 601 xmlXPathStepOpPtr op, xmlNodePtr *first); 602 static int 603 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt, 604 xmlXPathStepOpPtr op, 605 int isPredicate); 606 607 /************************************************************************ 608 * * 609 * Parser Type functions * 610 * * 611 ************************************************************************/ 612 613 /** 614 * xmlXPathNewCompExpr: 615 * 616 * Create a new Xpath component 617 * 618 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error 619 */ 620 static xmlXPathCompExprPtr 621 xmlXPathNewCompExpr(void) { 622 xmlXPathCompExprPtr cur; 623 624 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr)); 625 if (cur == NULL) { 626 xmlXPathErrMemory(NULL, "allocating component\n"); 627 return(NULL); 628 } 629 memset(cur, 0, sizeof(xmlXPathCompExpr)); 630 cur->maxStep = 10; 631 cur->nbStep = 0; 632 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep * 633 sizeof(xmlXPathStepOp)); 634 if (cur->steps == NULL) { 635 xmlXPathErrMemory(NULL, "allocating steps\n"); 636 xmlFree(cur); 637 return(NULL); 638 } 639 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp)); 640 cur->last = -1; 641 #ifdef DEBUG_EVAL_COUNTS 642 cur->nb = 0; 643 #endif 644 return(cur); 645 } 646 647 /** 648 * xmlXPathFreeCompExpr: 649 * @comp: an XPATH comp 650 * 651 * Free up the memory allocated by @comp 652 */ 653 void 654 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp) 655 { 656 xmlXPathStepOpPtr op; 657 int i; 658 659 if (comp == NULL) 660 return; 661 if (comp->dict == NULL) { 662 for (i = 0; i < comp->nbStep; i++) { 663 op = &comp->steps[i]; 664 if (op->value4 != NULL) { 665 if (op->op == XPATH_OP_VALUE) 666 xmlXPathFreeObject(op->value4); 667 else 668 xmlFree(op->value4); 669 } 670 if (op->value5 != NULL) 671 xmlFree(op->value5); 672 } 673 } else { 674 for (i = 0; i < comp->nbStep; i++) { 675 op = &comp->steps[i]; 676 if (op->value4 != NULL) { 677 if (op->op == XPATH_OP_VALUE) 678 xmlXPathFreeObject(op->value4); 679 } 680 } 681 xmlDictFree(comp->dict); 682 } 683 if (comp->steps != NULL) { 684 xmlFree(comp->steps); 685 } 686 #ifdef DEBUG_EVAL_COUNTS 687 if (comp->string != NULL) { 688 xmlFree(comp->string); 689 } 690 #endif 691 #ifdef XPATH_STREAMING 692 if (comp->stream != NULL) { 693 xmlFreePatternList(comp->stream); 694 } 695 #endif 696 if (comp->expr != NULL) { 697 xmlFree(comp->expr); 698 } 699 700 xmlFree(comp); 701 } 702 703 /** 704 * xmlXPathCompExprAdd: 705 * @comp: the compiled expression 706 * @ch1: first child index 707 * @ch2: second child index 708 * @op: an op 709 * @value: the first int value 710 * @value2: the second int value 711 * @value3: the third int value 712 * @value4: the first string value 713 * @value5: the second string value 714 * 715 * Add a step to an XPath Compiled Expression 716 * 717 * Returns -1 in case of failure, the index otherwise 718 */ 719 static int 720 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2, 721 xmlXPathOp op, int value, 722 int value2, int value3, void *value4, void *value5) { 723 if (comp->nbStep >= comp->maxStep) { 724 xmlXPathStepOp *real; 725 726 comp->maxStep *= 2; 727 real = (xmlXPathStepOp *) xmlRealloc(comp->steps, 728 comp->maxStep * sizeof(xmlXPathStepOp)); 729 if (real == NULL) { 730 comp->maxStep /= 2; 731 xmlXPathErrMemory(NULL, "adding step\n"); 732 return(-1); 733 } 734 comp->steps = real; 735 } 736 comp->last = comp->nbStep; 737 comp->steps[comp->nbStep].rewriteType = 0; 738 comp->steps[comp->nbStep].ch1 = ch1; 739 comp->steps[comp->nbStep].ch2 = ch2; 740 comp->steps[comp->nbStep].op = op; 741 comp->steps[comp->nbStep].value = value; 742 comp->steps[comp->nbStep].value2 = value2; 743 comp->steps[comp->nbStep].value3 = value3; 744 if ((comp->dict != NULL) && 745 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) || 746 (op == XPATH_OP_COLLECT))) { 747 if (value4 != NULL) { 748 comp->steps[comp->nbStep].value4 = (xmlChar *) 749 (void *)xmlDictLookup(comp->dict, value4, -1); 750 xmlFree(value4); 751 } else 752 comp->steps[comp->nbStep].value4 = NULL; 753 if (value5 != NULL) { 754 comp->steps[comp->nbStep].value5 = (xmlChar *) 755 (void *)xmlDictLookup(comp->dict, value5, -1); 756 xmlFree(value5); 757 } else 758 comp->steps[comp->nbStep].value5 = NULL; 759 } else { 760 comp->steps[comp->nbStep].value4 = value4; 761 comp->steps[comp->nbStep].value5 = value5; 762 } 763 comp->steps[comp->nbStep].cache = NULL; 764 return(comp->nbStep++); 765 } 766 767 /** 768 * xmlXPathCompSwap: 769 * @comp: the compiled expression 770 * @op: operation index 771 * 772 * Swaps 2 operations in the compiled expression 773 */ 774 static void 775 xmlXPathCompSwap(xmlXPathStepOpPtr op) { 776 int tmp; 777 778 #ifndef LIBXML_THREAD_ENABLED 779 /* 780 * Since this manipulates possibly shared variables, this is 781 * disabled if one detects that the library is used in a multithreaded 782 * application 783 */ 784 if (xmlXPathDisableOptimizer) 785 return; 786 #endif 787 788 tmp = op->ch1; 789 op->ch1 = op->ch2; 790 op->ch2 = tmp; 791 } 792 793 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \ 794 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \ 795 (op), (val), (val2), (val3), (val4), (val5)) 796 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \ 797 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \ 798 (op), (val), (val2), (val3), (val4), (val5)) 799 800 #define PUSH_LEAVE_EXPR(op, val, val2) \ 801 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL) 802 803 #define PUSH_UNARY_EXPR(op, ch, val, val2) \ 804 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL) 805 806 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \ 807 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \ 808 (val), (val2), 0 ,NULL ,NULL) 809 810 /************************************************************************ 811 * * 812 * XPath object cache structures * 813 * * 814 ************************************************************************/ 815 816 /* #define XP_DEFAULT_CACHE_ON */ 817 818 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL)) 819 820 typedef struct _xmlXPathContextCache xmlXPathContextCache; 821 typedef xmlXPathContextCache *xmlXPathContextCachePtr; 822 struct _xmlXPathContextCache { 823 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */ 824 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */ 825 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */ 826 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */ 827 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */ 828 int maxNodeset; 829 int maxString; 830 int maxBoolean; 831 int maxNumber; 832 int maxMisc; 833 #ifdef XP_DEBUG_OBJ_USAGE 834 int dbgCachedAll; 835 int dbgCachedNodeset; 836 int dbgCachedString; 837 int dbgCachedBool; 838 int dbgCachedNumber; 839 int dbgCachedPoint; 840 int dbgCachedRange; 841 int dbgCachedLocset; 842 int dbgCachedUsers; 843 int dbgCachedXSLTTree; 844 int dbgCachedUndefined; 845 846 847 int dbgReusedAll; 848 int dbgReusedNodeset; 849 int dbgReusedString; 850 int dbgReusedBool; 851 int dbgReusedNumber; 852 int dbgReusedPoint; 853 int dbgReusedRange; 854 int dbgReusedLocset; 855 int dbgReusedUsers; 856 int dbgReusedXSLTTree; 857 int dbgReusedUndefined; 858 859 #endif 860 }; 861 862 /************************************************************************ 863 * * 864 * Debugging related functions * 865 * * 866 ************************************************************************/ 867 868 #define STRANGE \ 869 xmlGenericError(xmlGenericErrorContext, \ 870 "Internal error at %s:%d\n", \ 871 __FILE__, __LINE__); 872 873 #ifdef LIBXML_DEBUG_ENABLED 874 static void 875 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) { 876 int i; 877 char shift[100]; 878 879 for (i = 0;((i < depth) && (i < 25));i++) 880 shift[2 * i] = shift[2 * i + 1] = ' '; 881 shift[2 * i] = shift[2 * i + 1] = 0; 882 if (cur == NULL) { 883 fprintf(output, "%s", shift); 884 fprintf(output, "Node is NULL !\n"); 885 return; 886 887 } 888 889 if ((cur->type == XML_DOCUMENT_NODE) || 890 (cur->type == XML_HTML_DOCUMENT_NODE)) { 891 fprintf(output, "%s", shift); 892 fprintf(output, " /\n"); 893 } else if (cur->type == XML_ATTRIBUTE_NODE) 894 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth); 895 else 896 xmlDebugDumpOneNode(output, cur, depth); 897 } 898 static void 899 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) { 900 xmlNodePtr tmp; 901 int i; 902 char shift[100]; 903 904 for (i = 0;((i < depth) && (i < 25));i++) 905 shift[2 * i] = shift[2 * i + 1] = ' '; 906 shift[2 * i] = shift[2 * i + 1] = 0; 907 if (cur == NULL) { 908 fprintf(output, "%s", shift); 909 fprintf(output, "Node is NULL !\n"); 910 return; 911 912 } 913 914 while (cur != NULL) { 915 tmp = cur; 916 cur = cur->next; 917 xmlDebugDumpOneNode(output, tmp, depth); 918 } 919 } 920 921 static void 922 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) { 923 int i; 924 char shift[100]; 925 926 for (i = 0;((i < depth) && (i < 25));i++) 927 shift[2 * i] = shift[2 * i + 1] = ' '; 928 shift[2 * i] = shift[2 * i + 1] = 0; 929 930 if (cur == NULL) { 931 fprintf(output, "%s", shift); 932 fprintf(output, "NodeSet is NULL !\n"); 933 return; 934 935 } 936 937 if (cur != NULL) { 938 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr); 939 for (i = 0;i < cur->nodeNr;i++) { 940 fprintf(output, "%s", shift); 941 fprintf(output, "%d", i + 1); 942 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1); 943 } 944 } 945 } 946 947 static void 948 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) { 949 int i; 950 char shift[100]; 951 952 for (i = 0;((i < depth) && (i < 25));i++) 953 shift[2 * i] = shift[2 * i + 1] = ' '; 954 shift[2 * i] = shift[2 * i + 1] = 0; 955 956 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) { 957 fprintf(output, "%s", shift); 958 fprintf(output, "Value Tree is NULL !\n"); 959 return; 960 961 } 962 963 fprintf(output, "%s", shift); 964 fprintf(output, "%d", i + 1); 965 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1); 966 } 967 #if defined(LIBXML_XPTR_ENABLED) 968 static void 969 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) { 970 int i; 971 char shift[100]; 972 973 for (i = 0;((i < depth) && (i < 25));i++) 974 shift[2 * i] = shift[2 * i + 1] = ' '; 975 shift[2 * i] = shift[2 * i + 1] = 0; 976 977 if (cur == NULL) { 978 fprintf(output, "%s", shift); 979 fprintf(output, "LocationSet is NULL !\n"); 980 return; 981 982 } 983 984 for (i = 0;i < cur->locNr;i++) { 985 fprintf(output, "%s", shift); 986 fprintf(output, "%d : ", i + 1); 987 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1); 988 } 989 } 990 #endif /* LIBXML_XPTR_ENABLED */ 991 992 /** 993 * xmlXPathDebugDumpObject: 994 * @output: the FILE * to dump the output 995 * @cur: the object to inspect 996 * @depth: indentation level 997 * 998 * Dump the content of the object for debugging purposes 999 */ 1000 void 1001 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) { 1002 int i; 1003 char shift[100]; 1004 1005 if (output == NULL) return; 1006 1007 for (i = 0;((i < depth) && (i < 25));i++) 1008 shift[2 * i] = shift[2 * i + 1] = ' '; 1009 shift[2 * i] = shift[2 * i + 1] = 0; 1010 1011 1012 fprintf(output, "%s", shift); 1013 1014 if (cur == NULL) { 1015 fprintf(output, "Object is empty (NULL)\n"); 1016 return; 1017 } 1018 switch(cur->type) { 1019 case XPATH_UNDEFINED: 1020 fprintf(output, "Object is uninitialized\n"); 1021 break; 1022 case XPATH_NODESET: 1023 fprintf(output, "Object is a Node Set :\n"); 1024 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth); 1025 break; 1026 case XPATH_XSLT_TREE: 1027 fprintf(output, "Object is an XSLT value tree :\n"); 1028 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth); 1029 break; 1030 case XPATH_BOOLEAN: 1031 fprintf(output, "Object is a Boolean : "); 1032 if (cur->boolval) fprintf(output, "true\n"); 1033 else fprintf(output, "false\n"); 1034 break; 1035 case XPATH_NUMBER: 1036 switch (xmlXPathIsInf(cur->floatval)) { 1037 case 1: 1038 fprintf(output, "Object is a number : Infinity\n"); 1039 break; 1040 case -1: 1041 fprintf(output, "Object is a number : -Infinity\n"); 1042 break; 1043 default: 1044 if (xmlXPathIsNaN(cur->floatval)) { 1045 fprintf(output, "Object is a number : NaN\n"); 1046 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) { 1047 fprintf(output, "Object is a number : 0\n"); 1048 } else { 1049 fprintf(output, "Object is a number : %0g\n", cur->floatval); 1050 } 1051 } 1052 break; 1053 case XPATH_STRING: 1054 fprintf(output, "Object is a string : "); 1055 xmlDebugDumpString(output, cur->stringval); 1056 fprintf(output, "\n"); 1057 break; 1058 case XPATH_POINT: 1059 fprintf(output, "Object is a point : index %d in node", cur->index); 1060 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1); 1061 fprintf(output, "\n"); 1062 break; 1063 case XPATH_RANGE: 1064 if ((cur->user2 == NULL) || 1065 ((cur->user2 == cur->user) && (cur->index == cur->index2))) { 1066 fprintf(output, "Object is a collapsed range :\n"); 1067 fprintf(output, "%s", shift); 1068 if (cur->index >= 0) 1069 fprintf(output, "index %d in ", cur->index); 1070 fprintf(output, "node\n"); 1071 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, 1072 depth + 1); 1073 } else { 1074 fprintf(output, "Object is a range :\n"); 1075 fprintf(output, "%s", shift); 1076 fprintf(output, "From "); 1077 if (cur->index >= 0) 1078 fprintf(output, "index %d in ", cur->index); 1079 fprintf(output, "node\n"); 1080 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, 1081 depth + 1); 1082 fprintf(output, "%s", shift); 1083 fprintf(output, "To "); 1084 if (cur->index2 >= 0) 1085 fprintf(output, "index %d in ", cur->index2); 1086 fprintf(output, "node\n"); 1087 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2, 1088 depth + 1); 1089 fprintf(output, "\n"); 1090 } 1091 break; 1092 case XPATH_LOCATIONSET: 1093 #if defined(LIBXML_XPTR_ENABLED) 1094 fprintf(output, "Object is a Location Set:\n"); 1095 xmlXPathDebugDumpLocationSet(output, 1096 (xmlLocationSetPtr) cur->user, depth); 1097 #endif 1098 break; 1099 case XPATH_USERS: 1100 fprintf(output, "Object is user defined\n"); 1101 break; 1102 } 1103 } 1104 1105 static void 1106 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp, 1107 xmlXPathStepOpPtr op, int depth) { 1108 int i; 1109 char shift[100]; 1110 1111 for (i = 0;((i < depth) && (i < 25));i++) 1112 shift[2 * i] = shift[2 * i + 1] = ' '; 1113 shift[2 * i] = shift[2 * i + 1] = 0; 1114 1115 fprintf(output, "%s", shift); 1116 if (op == NULL) { 1117 fprintf(output, "Step is NULL\n"); 1118 return; 1119 } 1120 switch (op->op) { 1121 case XPATH_OP_END: 1122 fprintf(output, "END"); break; 1123 case XPATH_OP_AND: 1124 fprintf(output, "AND"); break; 1125 case XPATH_OP_OR: 1126 fprintf(output, "OR"); break; 1127 case XPATH_OP_EQUAL: 1128 if (op->value) 1129 fprintf(output, "EQUAL ="); 1130 else 1131 fprintf(output, "EQUAL !="); 1132 break; 1133 case XPATH_OP_CMP: 1134 if (op->value) 1135 fprintf(output, "CMP <"); 1136 else 1137 fprintf(output, "CMP >"); 1138 if (!op->value2) 1139 fprintf(output, "="); 1140 break; 1141 case XPATH_OP_PLUS: 1142 if (op->value == 0) 1143 fprintf(output, "PLUS -"); 1144 else if (op->value == 1) 1145 fprintf(output, "PLUS +"); 1146 else if (op->value == 2) 1147 fprintf(output, "PLUS unary -"); 1148 else if (op->value == 3) 1149 fprintf(output, "PLUS unary - -"); 1150 break; 1151 case XPATH_OP_MULT: 1152 if (op->value == 0) 1153 fprintf(output, "MULT *"); 1154 else if (op->value == 1) 1155 fprintf(output, "MULT div"); 1156 else 1157 fprintf(output, "MULT mod"); 1158 break; 1159 case XPATH_OP_UNION: 1160 fprintf(output, "UNION"); break; 1161 case XPATH_OP_ROOT: 1162 fprintf(output, "ROOT"); break; 1163 case XPATH_OP_NODE: 1164 fprintf(output, "NODE"); break; 1165 case XPATH_OP_RESET: 1166 fprintf(output, "RESET"); break; 1167 case XPATH_OP_SORT: 1168 fprintf(output, "SORT"); break; 1169 case XPATH_OP_COLLECT: { 1170 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value; 1171 xmlXPathTestVal test = (xmlXPathTestVal)op->value2; 1172 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3; 1173 const xmlChar *prefix = op->value4; 1174 const xmlChar *name = op->value5; 1175 1176 fprintf(output, "COLLECT "); 1177 switch (axis) { 1178 case AXIS_ANCESTOR: 1179 fprintf(output, " 'ancestors' "); break; 1180 case AXIS_ANCESTOR_OR_SELF: 1181 fprintf(output, " 'ancestors-or-self' "); break; 1182 case AXIS_ATTRIBUTE: 1183 fprintf(output, " 'attributes' "); break; 1184 case AXIS_CHILD: 1185 fprintf(output, " 'child' "); break; 1186 case AXIS_DESCENDANT: 1187 fprintf(output, " 'descendant' "); break; 1188 case AXIS_DESCENDANT_OR_SELF: 1189 fprintf(output, " 'descendant-or-self' "); break; 1190 case AXIS_FOLLOWING: 1191 fprintf(output, " 'following' "); break; 1192 case AXIS_FOLLOWING_SIBLING: 1193 fprintf(output, " 'following-siblings' "); break; 1194 case AXIS_NAMESPACE: 1195 fprintf(output, " 'namespace' "); break; 1196 case AXIS_PARENT: 1197 fprintf(output, " 'parent' "); break; 1198 case AXIS_PRECEDING: 1199 fprintf(output, " 'preceding' "); break; 1200 case AXIS_PRECEDING_SIBLING: 1201 fprintf(output, " 'preceding-sibling' "); break; 1202 case AXIS_SELF: 1203 fprintf(output, " 'self' "); break; 1204 } 1205 switch (test) { 1206 case NODE_TEST_NONE: 1207 fprintf(output, "'none' "); break; 1208 case NODE_TEST_TYPE: 1209 fprintf(output, "'type' "); break; 1210 case NODE_TEST_PI: 1211 fprintf(output, "'PI' "); break; 1212 case NODE_TEST_ALL: 1213 fprintf(output, "'all' "); break; 1214 case NODE_TEST_NS: 1215 fprintf(output, "'namespace' "); break; 1216 case NODE_TEST_NAME: 1217 fprintf(output, "'name' "); break; 1218 } 1219 switch (type) { 1220 case NODE_TYPE_NODE: 1221 fprintf(output, "'node' "); break; 1222 case NODE_TYPE_COMMENT: 1223 fprintf(output, "'comment' "); break; 1224 case NODE_TYPE_TEXT: 1225 fprintf(output, "'text' "); break; 1226 case NODE_TYPE_PI: 1227 fprintf(output, "'PI' "); break; 1228 } 1229 if (prefix != NULL) 1230 fprintf(output, "%s:", prefix); 1231 if (name != NULL) 1232 fprintf(output, "%s", (const char *) name); 1233 break; 1234 1235 } 1236 case XPATH_OP_VALUE: { 1237 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4; 1238 1239 fprintf(output, "ELEM "); 1240 xmlXPathDebugDumpObject(output, object, 0); 1241 goto finish; 1242 } 1243 case XPATH_OP_VARIABLE: { 1244 const xmlChar *prefix = op->value5; 1245 const xmlChar *name = op->value4; 1246 1247 if (prefix != NULL) 1248 fprintf(output, "VARIABLE %s:%s", prefix, name); 1249 else 1250 fprintf(output, "VARIABLE %s", name); 1251 break; 1252 } 1253 case XPATH_OP_FUNCTION: { 1254 int nbargs = op->value; 1255 const xmlChar *prefix = op->value5; 1256 const xmlChar *name = op->value4; 1257 1258 if (prefix != NULL) 1259 fprintf(output, "FUNCTION %s:%s(%d args)", 1260 prefix, name, nbargs); 1261 else 1262 fprintf(output, "FUNCTION %s(%d args)", name, nbargs); 1263 break; 1264 } 1265 case XPATH_OP_ARG: fprintf(output, "ARG"); break; 1266 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break; 1267 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break; 1268 #ifdef LIBXML_XPTR_ENABLED 1269 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break; 1270 #endif 1271 default: 1272 fprintf(output, "UNKNOWN %d\n", op->op); return; 1273 } 1274 fprintf(output, "\n"); 1275 finish: 1276 if (op->ch1 >= 0) 1277 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1); 1278 if (op->ch2 >= 0) 1279 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1); 1280 } 1281 1282 /** 1283 * xmlXPathDebugDumpCompExpr: 1284 * @output: the FILE * for the output 1285 * @comp: the precompiled XPath expression 1286 * @depth: the indentation level. 1287 * 1288 * Dumps the tree of the compiled XPath expression. 1289 */ 1290 void 1291 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp, 1292 int depth) { 1293 int i; 1294 char shift[100]; 1295 1296 if ((output == NULL) || (comp == NULL)) return; 1297 1298 for (i = 0;((i < depth) && (i < 25));i++) 1299 shift[2 * i] = shift[2 * i + 1] = ' '; 1300 shift[2 * i] = shift[2 * i + 1] = 0; 1301 1302 fprintf(output, "%s", shift); 1303 1304 fprintf(output, "Compiled Expression : %d elements\n", 1305 comp->nbStep); 1306 i = comp->last; 1307 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1); 1308 } 1309 1310 #ifdef XP_DEBUG_OBJ_USAGE 1311 1312 /* 1313 * XPath object usage related debugging variables. 1314 */ 1315 static int xmlXPathDebugObjCounterUndefined = 0; 1316 static int xmlXPathDebugObjCounterNodeset = 0; 1317 static int xmlXPathDebugObjCounterBool = 0; 1318 static int xmlXPathDebugObjCounterNumber = 0; 1319 static int xmlXPathDebugObjCounterString = 0; 1320 static int xmlXPathDebugObjCounterPoint = 0; 1321 static int xmlXPathDebugObjCounterRange = 0; 1322 static int xmlXPathDebugObjCounterLocset = 0; 1323 static int xmlXPathDebugObjCounterUsers = 0; 1324 static int xmlXPathDebugObjCounterXSLTTree = 0; 1325 static int xmlXPathDebugObjCounterAll = 0; 1326 1327 static int xmlXPathDebugObjTotalUndefined = 0; 1328 static int xmlXPathDebugObjTotalNodeset = 0; 1329 static int xmlXPathDebugObjTotalBool = 0; 1330 static int xmlXPathDebugObjTotalNumber = 0; 1331 static int xmlXPathDebugObjTotalString = 0; 1332 static int xmlXPathDebugObjTotalPoint = 0; 1333 static int xmlXPathDebugObjTotalRange = 0; 1334 static int xmlXPathDebugObjTotalLocset = 0; 1335 static int xmlXPathDebugObjTotalUsers = 0; 1336 static int xmlXPathDebugObjTotalXSLTTree = 0; 1337 static int xmlXPathDebugObjTotalAll = 0; 1338 1339 static int xmlXPathDebugObjMaxUndefined = 0; 1340 static int xmlXPathDebugObjMaxNodeset = 0; 1341 static int xmlXPathDebugObjMaxBool = 0; 1342 static int xmlXPathDebugObjMaxNumber = 0; 1343 static int xmlXPathDebugObjMaxString = 0; 1344 static int xmlXPathDebugObjMaxPoint = 0; 1345 static int xmlXPathDebugObjMaxRange = 0; 1346 static int xmlXPathDebugObjMaxLocset = 0; 1347 static int xmlXPathDebugObjMaxUsers = 0; 1348 static int xmlXPathDebugObjMaxXSLTTree = 0; 1349 static int xmlXPathDebugObjMaxAll = 0; 1350 1351 /* REVISIT TODO: Make this static when committing */ 1352 static void 1353 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt) 1354 { 1355 if (ctxt != NULL) { 1356 if (ctxt->cache != NULL) { 1357 xmlXPathContextCachePtr cache = 1358 (xmlXPathContextCachePtr) ctxt->cache; 1359 1360 cache->dbgCachedAll = 0; 1361 cache->dbgCachedNodeset = 0; 1362 cache->dbgCachedString = 0; 1363 cache->dbgCachedBool = 0; 1364 cache->dbgCachedNumber = 0; 1365 cache->dbgCachedPoint = 0; 1366 cache->dbgCachedRange = 0; 1367 cache->dbgCachedLocset = 0; 1368 cache->dbgCachedUsers = 0; 1369 cache->dbgCachedXSLTTree = 0; 1370 cache->dbgCachedUndefined = 0; 1371 1372 cache->dbgReusedAll = 0; 1373 cache->dbgReusedNodeset = 0; 1374 cache->dbgReusedString = 0; 1375 cache->dbgReusedBool = 0; 1376 cache->dbgReusedNumber = 0; 1377 cache->dbgReusedPoint = 0; 1378 cache->dbgReusedRange = 0; 1379 cache->dbgReusedLocset = 0; 1380 cache->dbgReusedUsers = 0; 1381 cache->dbgReusedXSLTTree = 0; 1382 cache->dbgReusedUndefined = 0; 1383 } 1384 } 1385 1386 xmlXPathDebugObjCounterUndefined = 0; 1387 xmlXPathDebugObjCounterNodeset = 0; 1388 xmlXPathDebugObjCounterBool = 0; 1389 xmlXPathDebugObjCounterNumber = 0; 1390 xmlXPathDebugObjCounterString = 0; 1391 xmlXPathDebugObjCounterPoint = 0; 1392 xmlXPathDebugObjCounterRange = 0; 1393 xmlXPathDebugObjCounterLocset = 0; 1394 xmlXPathDebugObjCounterUsers = 0; 1395 xmlXPathDebugObjCounterXSLTTree = 0; 1396 xmlXPathDebugObjCounterAll = 0; 1397 1398 xmlXPathDebugObjTotalUndefined = 0; 1399 xmlXPathDebugObjTotalNodeset = 0; 1400 xmlXPathDebugObjTotalBool = 0; 1401 xmlXPathDebugObjTotalNumber = 0; 1402 xmlXPathDebugObjTotalString = 0; 1403 xmlXPathDebugObjTotalPoint = 0; 1404 xmlXPathDebugObjTotalRange = 0; 1405 xmlXPathDebugObjTotalLocset = 0; 1406 xmlXPathDebugObjTotalUsers = 0; 1407 xmlXPathDebugObjTotalXSLTTree = 0; 1408 xmlXPathDebugObjTotalAll = 0; 1409 1410 xmlXPathDebugObjMaxUndefined = 0; 1411 xmlXPathDebugObjMaxNodeset = 0; 1412 xmlXPathDebugObjMaxBool = 0; 1413 xmlXPathDebugObjMaxNumber = 0; 1414 xmlXPathDebugObjMaxString = 0; 1415 xmlXPathDebugObjMaxPoint = 0; 1416 xmlXPathDebugObjMaxRange = 0; 1417 xmlXPathDebugObjMaxLocset = 0; 1418 xmlXPathDebugObjMaxUsers = 0; 1419 xmlXPathDebugObjMaxXSLTTree = 0; 1420 xmlXPathDebugObjMaxAll = 0; 1421 1422 } 1423 1424 static void 1425 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt, 1426 xmlXPathObjectType objType) 1427 { 1428 int isCached = 0; 1429 1430 if (ctxt != NULL) { 1431 if (ctxt->cache != NULL) { 1432 xmlXPathContextCachePtr cache = 1433 (xmlXPathContextCachePtr) ctxt->cache; 1434 1435 isCached = 1; 1436 1437 cache->dbgReusedAll++; 1438 switch (objType) { 1439 case XPATH_UNDEFINED: 1440 cache->dbgReusedUndefined++; 1441 break; 1442 case XPATH_NODESET: 1443 cache->dbgReusedNodeset++; 1444 break; 1445 case XPATH_BOOLEAN: 1446 cache->dbgReusedBool++; 1447 break; 1448 case XPATH_NUMBER: 1449 cache->dbgReusedNumber++; 1450 break; 1451 case XPATH_STRING: 1452 cache->dbgReusedString++; 1453 break; 1454 case XPATH_POINT: 1455 cache->dbgReusedPoint++; 1456 break; 1457 case XPATH_RANGE: 1458 cache->dbgReusedRange++; 1459 break; 1460 case XPATH_LOCATIONSET: 1461 cache->dbgReusedLocset++; 1462 break; 1463 case XPATH_USERS: 1464 cache->dbgReusedUsers++; 1465 break; 1466 case XPATH_XSLT_TREE: 1467 cache->dbgReusedXSLTTree++; 1468 break; 1469 default: 1470 break; 1471 } 1472 } 1473 } 1474 1475 switch (objType) { 1476 case XPATH_UNDEFINED: 1477 if (! isCached) 1478 xmlXPathDebugObjTotalUndefined++; 1479 xmlXPathDebugObjCounterUndefined++; 1480 if (xmlXPathDebugObjCounterUndefined > 1481 xmlXPathDebugObjMaxUndefined) 1482 xmlXPathDebugObjMaxUndefined = 1483 xmlXPathDebugObjCounterUndefined; 1484 break; 1485 case XPATH_NODESET: 1486 if (! isCached) 1487 xmlXPathDebugObjTotalNodeset++; 1488 xmlXPathDebugObjCounterNodeset++; 1489 if (xmlXPathDebugObjCounterNodeset > 1490 xmlXPathDebugObjMaxNodeset) 1491 xmlXPathDebugObjMaxNodeset = 1492 xmlXPathDebugObjCounterNodeset; 1493 break; 1494 case XPATH_BOOLEAN: 1495 if (! isCached) 1496 xmlXPathDebugObjTotalBool++; 1497 xmlXPathDebugObjCounterBool++; 1498 if (xmlXPathDebugObjCounterBool > 1499 xmlXPathDebugObjMaxBool) 1500 xmlXPathDebugObjMaxBool = 1501 xmlXPathDebugObjCounterBool; 1502 break; 1503 case XPATH_NUMBER: 1504 if (! isCached) 1505 xmlXPathDebugObjTotalNumber++; 1506 xmlXPathDebugObjCounterNumber++; 1507 if (xmlXPathDebugObjCounterNumber > 1508 xmlXPathDebugObjMaxNumber) 1509 xmlXPathDebugObjMaxNumber = 1510 xmlXPathDebugObjCounterNumber; 1511 break; 1512 case XPATH_STRING: 1513 if (! isCached) 1514 xmlXPathDebugObjTotalString++; 1515 xmlXPathDebugObjCounterString++; 1516 if (xmlXPathDebugObjCounterString > 1517 xmlXPathDebugObjMaxString) 1518 xmlXPathDebugObjMaxString = 1519 xmlXPathDebugObjCounterString; 1520 break; 1521 case XPATH_POINT: 1522 if (! isCached) 1523 xmlXPathDebugObjTotalPoint++; 1524 xmlXPathDebugObjCounterPoint++; 1525 if (xmlXPathDebugObjCounterPoint > 1526 xmlXPathDebugObjMaxPoint) 1527 xmlXPathDebugObjMaxPoint = 1528 xmlXPathDebugObjCounterPoint; 1529 break; 1530 case XPATH_RANGE: 1531 if (! isCached) 1532 xmlXPathDebugObjTotalRange++; 1533 xmlXPathDebugObjCounterRange++; 1534 if (xmlXPathDebugObjCounterRange > 1535 xmlXPathDebugObjMaxRange) 1536 xmlXPathDebugObjMaxRange = 1537 xmlXPathDebugObjCounterRange; 1538 break; 1539 case XPATH_LOCATIONSET: 1540 if (! isCached) 1541 xmlXPathDebugObjTotalLocset++; 1542 xmlXPathDebugObjCounterLocset++; 1543 if (xmlXPathDebugObjCounterLocset > 1544 xmlXPathDebugObjMaxLocset) 1545 xmlXPathDebugObjMaxLocset = 1546 xmlXPathDebugObjCounterLocset; 1547 break; 1548 case XPATH_USERS: 1549 if (! isCached) 1550 xmlXPathDebugObjTotalUsers++; 1551 xmlXPathDebugObjCounterUsers++; 1552 if (xmlXPathDebugObjCounterUsers > 1553 xmlXPathDebugObjMaxUsers) 1554 xmlXPathDebugObjMaxUsers = 1555 xmlXPathDebugObjCounterUsers; 1556 break; 1557 case XPATH_XSLT_TREE: 1558 if (! isCached) 1559 xmlXPathDebugObjTotalXSLTTree++; 1560 xmlXPathDebugObjCounterXSLTTree++; 1561 if (xmlXPathDebugObjCounterXSLTTree > 1562 xmlXPathDebugObjMaxXSLTTree) 1563 xmlXPathDebugObjMaxXSLTTree = 1564 xmlXPathDebugObjCounterXSLTTree; 1565 break; 1566 default: 1567 break; 1568 } 1569 if (! isCached) 1570 xmlXPathDebugObjTotalAll++; 1571 xmlXPathDebugObjCounterAll++; 1572 if (xmlXPathDebugObjCounterAll > 1573 xmlXPathDebugObjMaxAll) 1574 xmlXPathDebugObjMaxAll = 1575 xmlXPathDebugObjCounterAll; 1576 } 1577 1578 static void 1579 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt, 1580 xmlXPathObjectType objType) 1581 { 1582 int isCached = 0; 1583 1584 if (ctxt != NULL) { 1585 if (ctxt->cache != NULL) { 1586 xmlXPathContextCachePtr cache = 1587 (xmlXPathContextCachePtr) ctxt->cache; 1588 1589 isCached = 1; 1590 1591 cache->dbgCachedAll++; 1592 switch (objType) { 1593 case XPATH_UNDEFINED: 1594 cache->dbgCachedUndefined++; 1595 break; 1596 case XPATH_NODESET: 1597 cache->dbgCachedNodeset++; 1598 break; 1599 case XPATH_BOOLEAN: 1600 cache->dbgCachedBool++; 1601 break; 1602 case XPATH_NUMBER: 1603 cache->dbgCachedNumber++; 1604 break; 1605 case XPATH_STRING: 1606 cache->dbgCachedString++; 1607 break; 1608 case XPATH_POINT: 1609 cache->dbgCachedPoint++; 1610 break; 1611 case XPATH_RANGE: 1612 cache->dbgCachedRange++; 1613 break; 1614 case XPATH_LOCATIONSET: 1615 cache->dbgCachedLocset++; 1616 break; 1617 case XPATH_USERS: 1618 cache->dbgCachedUsers++; 1619 break; 1620 case XPATH_XSLT_TREE: 1621 cache->dbgCachedXSLTTree++; 1622 break; 1623 default: 1624 break; 1625 } 1626 1627 } 1628 } 1629 switch (objType) { 1630 case XPATH_UNDEFINED: 1631 xmlXPathDebugObjCounterUndefined--; 1632 break; 1633 case XPATH_NODESET: 1634 xmlXPathDebugObjCounterNodeset--; 1635 break; 1636 case XPATH_BOOLEAN: 1637 xmlXPathDebugObjCounterBool--; 1638 break; 1639 case XPATH_NUMBER: 1640 xmlXPathDebugObjCounterNumber--; 1641 break; 1642 case XPATH_STRING: 1643 xmlXPathDebugObjCounterString--; 1644 break; 1645 case XPATH_POINT: 1646 xmlXPathDebugObjCounterPoint--; 1647 break; 1648 case XPATH_RANGE: 1649 xmlXPathDebugObjCounterRange--; 1650 break; 1651 case XPATH_LOCATIONSET: 1652 xmlXPathDebugObjCounterLocset--; 1653 break; 1654 case XPATH_USERS: 1655 xmlXPathDebugObjCounterUsers--; 1656 break; 1657 case XPATH_XSLT_TREE: 1658 xmlXPathDebugObjCounterXSLTTree--; 1659 break; 1660 default: 1661 break; 1662 } 1663 xmlXPathDebugObjCounterAll--; 1664 } 1665 1666 /* REVISIT TODO: Make this static when committing */ 1667 static void 1668 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt) 1669 { 1670 int reqAll, reqNodeset, reqString, reqBool, reqNumber, 1671 reqXSLTTree, reqUndefined; 1672 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0, 1673 caNumber = 0, caXSLTTree = 0, caUndefined = 0; 1674 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0, 1675 reNumber = 0, reXSLTTree = 0, reUndefined = 0; 1676 int leftObjs = xmlXPathDebugObjCounterAll; 1677 1678 reqAll = xmlXPathDebugObjTotalAll; 1679 reqNodeset = xmlXPathDebugObjTotalNodeset; 1680 reqString = xmlXPathDebugObjTotalString; 1681 reqBool = xmlXPathDebugObjTotalBool; 1682 reqNumber = xmlXPathDebugObjTotalNumber; 1683 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree; 1684 reqUndefined = xmlXPathDebugObjTotalUndefined; 1685 1686 printf("# XPath object usage:\n"); 1687 1688 if (ctxt != NULL) { 1689 if (ctxt->cache != NULL) { 1690 xmlXPathContextCachePtr cache = 1691 (xmlXPathContextCachePtr) ctxt->cache; 1692 1693 reAll = cache->dbgReusedAll; 1694 reqAll += reAll; 1695 reNodeset = cache->dbgReusedNodeset; 1696 reqNodeset += reNodeset; 1697 reString = cache->dbgReusedString; 1698 reqString += reString; 1699 reBool = cache->dbgReusedBool; 1700 reqBool += reBool; 1701 reNumber = cache->dbgReusedNumber; 1702 reqNumber += reNumber; 1703 reXSLTTree = cache->dbgReusedXSLTTree; 1704 reqXSLTTree += reXSLTTree; 1705 reUndefined = cache->dbgReusedUndefined; 1706 reqUndefined += reUndefined; 1707 1708 caAll = cache->dbgCachedAll; 1709 caBool = cache->dbgCachedBool; 1710 caNodeset = cache->dbgCachedNodeset; 1711 caString = cache->dbgCachedString; 1712 caNumber = cache->dbgCachedNumber; 1713 caXSLTTree = cache->dbgCachedXSLTTree; 1714 caUndefined = cache->dbgCachedUndefined; 1715 1716 if (cache->nodesetObjs) 1717 leftObjs -= cache->nodesetObjs->number; 1718 if (cache->stringObjs) 1719 leftObjs -= cache->stringObjs->number; 1720 if (cache->booleanObjs) 1721 leftObjs -= cache->booleanObjs->number; 1722 if (cache->numberObjs) 1723 leftObjs -= cache->numberObjs->number; 1724 if (cache->miscObjs) 1725 leftObjs -= cache->miscObjs->number; 1726 } 1727 } 1728 1729 printf("# all\n"); 1730 printf("# total : %d\n", reqAll); 1731 printf("# left : %d\n", leftObjs); 1732 printf("# created: %d\n", xmlXPathDebugObjTotalAll); 1733 printf("# reused : %d\n", reAll); 1734 printf("# max : %d\n", xmlXPathDebugObjMaxAll); 1735 1736 printf("# node-sets\n"); 1737 printf("# total : %d\n", reqNodeset); 1738 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset); 1739 printf("# reused : %d\n", reNodeset); 1740 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset); 1741 1742 printf("# strings\n"); 1743 printf("# total : %d\n", reqString); 1744 printf("# created: %d\n", xmlXPathDebugObjTotalString); 1745 printf("# reused : %d\n", reString); 1746 printf("# max : %d\n", xmlXPathDebugObjMaxString); 1747 1748 printf("# booleans\n"); 1749 printf("# total : %d\n", reqBool); 1750 printf("# created: %d\n", xmlXPathDebugObjTotalBool); 1751 printf("# reused : %d\n", reBool); 1752 printf("# max : %d\n", xmlXPathDebugObjMaxBool); 1753 1754 printf("# numbers\n"); 1755 printf("# total : %d\n", reqNumber); 1756 printf("# created: %d\n", xmlXPathDebugObjTotalNumber); 1757 printf("# reused : %d\n", reNumber); 1758 printf("# max : %d\n", xmlXPathDebugObjMaxNumber); 1759 1760 printf("# XSLT result tree fragments\n"); 1761 printf("# total : %d\n", reqXSLTTree); 1762 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree); 1763 printf("# reused : %d\n", reXSLTTree); 1764 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree); 1765 1766 printf("# undefined\n"); 1767 printf("# total : %d\n", reqUndefined); 1768 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined); 1769 printf("# reused : %d\n", reUndefined); 1770 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined); 1771 1772 } 1773 1774 #endif /* XP_DEBUG_OBJ_USAGE */ 1775 1776 #endif /* LIBXML_DEBUG_ENABLED */ 1777 1778 /************************************************************************ 1779 * * 1780 * XPath object caching * 1781 * * 1782 ************************************************************************/ 1783 1784 /** 1785 * xmlXPathNewCache: 1786 * 1787 * Create a new object cache 1788 * 1789 * Returns the xmlXPathCache just allocated. 1790 */ 1791 static xmlXPathContextCachePtr 1792 xmlXPathNewCache(void) 1793 { 1794 xmlXPathContextCachePtr ret; 1795 1796 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache)); 1797 if (ret == NULL) { 1798 xmlXPathErrMemory(NULL, "creating object cache\n"); 1799 return(NULL); 1800 } 1801 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache)); 1802 ret->maxNodeset = 100; 1803 ret->maxString = 100; 1804 ret->maxBoolean = 100; 1805 ret->maxNumber = 100; 1806 ret->maxMisc = 100; 1807 return(ret); 1808 } 1809 1810 static void 1811 xmlXPathCacheFreeObjectList(xmlPointerListPtr list) 1812 { 1813 int i; 1814 xmlXPathObjectPtr obj; 1815 1816 if (list == NULL) 1817 return; 1818 1819 for (i = 0; i < list->number; i++) { 1820 obj = list->items[i]; 1821 /* 1822 * Note that it is already assured that we don't need to 1823 * look out for namespace nodes in the node-set. 1824 */ 1825 if (obj->nodesetval != NULL) { 1826 if (obj->nodesetval->nodeTab != NULL) 1827 xmlFree(obj->nodesetval->nodeTab); 1828 xmlFree(obj->nodesetval); 1829 } 1830 xmlFree(obj); 1831 #ifdef XP_DEBUG_OBJ_USAGE 1832 xmlXPathDebugObjCounterAll--; 1833 #endif 1834 } 1835 xmlPointerListFree(list); 1836 } 1837 1838 static void 1839 xmlXPathFreeCache(xmlXPathContextCachePtr cache) 1840 { 1841 if (cache == NULL) 1842 return; 1843 if (cache->nodesetObjs) 1844 xmlXPathCacheFreeObjectList(cache->nodesetObjs); 1845 if (cache->stringObjs) 1846 xmlXPathCacheFreeObjectList(cache->stringObjs); 1847 if (cache->booleanObjs) 1848 xmlXPathCacheFreeObjectList(cache->booleanObjs); 1849 if (cache->numberObjs) 1850 xmlXPathCacheFreeObjectList(cache->numberObjs); 1851 if (cache->miscObjs) 1852 xmlXPathCacheFreeObjectList(cache->miscObjs); 1853 xmlFree(cache); 1854 } 1855 1856 /** 1857 * xmlXPathContextSetCache: 1858 * 1859 * @ctxt: the XPath context 1860 * @active: enables/disables (creates/frees) the cache 1861 * @value: a value with semantics dependant on @options 1862 * @options: options (currently only the value 0 is used) 1863 * 1864 * Creates/frees an object cache on the XPath context. 1865 * If activates XPath objects (xmlXPathObject) will be cached internally 1866 * to be reused. 1867 * @options: 1868 * 0: This will set the XPath object caching: 1869 * @value: 1870 * This will set the maximum number of XPath objects 1871 * to be cached per slot 1872 * There are 5 slots for: node-set, string, number, boolean, and 1873 * misc objects. Use <0 for the default number (100). 1874 * Other values for @options have currently no effect. 1875 * 1876 * Returns 0 if the setting succeeded, and -1 on API or internal errors. 1877 */ 1878 int 1879 xmlXPathContextSetCache(xmlXPathContextPtr ctxt, 1880 int active, 1881 int value, 1882 int options) 1883 { 1884 if (ctxt == NULL) 1885 return(-1); 1886 if (active) { 1887 xmlXPathContextCachePtr cache; 1888 1889 if (ctxt->cache == NULL) { 1890 ctxt->cache = xmlXPathNewCache(); 1891 if (ctxt->cache == NULL) 1892 return(-1); 1893 } 1894 cache = (xmlXPathContextCachePtr) ctxt->cache; 1895 if (options == 0) { 1896 if (value < 0) 1897 value = 100; 1898 cache->maxNodeset = value; 1899 cache->maxString = value; 1900 cache->maxNumber = value; 1901 cache->maxBoolean = value; 1902 cache->maxMisc = value; 1903 } 1904 } else if (ctxt->cache != NULL) { 1905 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache); 1906 ctxt->cache = NULL; 1907 } 1908 return(0); 1909 } 1910 1911 /** 1912 * xmlXPathCacheWrapNodeSet: 1913 * @ctxt: the XPath context 1914 * @val: the NodePtr value 1915 * 1916 * This is the cached version of xmlXPathWrapNodeSet(). 1917 * Wrap the Nodeset @val in a new xmlXPathObjectPtr 1918 * 1919 * Returns the created or reused object. 1920 */ 1921 static xmlXPathObjectPtr 1922 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val) 1923 { 1924 if ((ctxt != NULL) && (ctxt->cache != NULL)) { 1925 xmlXPathContextCachePtr cache = 1926 (xmlXPathContextCachePtr) ctxt->cache; 1927 1928 if ((cache->miscObjs != NULL) && 1929 (cache->miscObjs->number != 0)) 1930 { 1931 xmlXPathObjectPtr ret; 1932 1933 ret = (xmlXPathObjectPtr) 1934 cache->miscObjs->items[--cache->miscObjs->number]; 1935 ret->type = XPATH_NODESET; 1936 ret->nodesetval = val; 1937 #ifdef XP_DEBUG_OBJ_USAGE 1938 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 1939 #endif 1940 return(ret); 1941 } 1942 } 1943 1944 return(xmlXPathWrapNodeSet(val)); 1945 1946 } 1947 1948 /** 1949 * xmlXPathCacheWrapString: 1950 * @ctxt: the XPath context 1951 * @val: the xmlChar * value 1952 * 1953 * This is the cached version of xmlXPathWrapString(). 1954 * Wraps the @val string into an XPath object. 1955 * 1956 * Returns the created or reused object. 1957 */ 1958 static xmlXPathObjectPtr 1959 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val) 1960 { 1961 if ((ctxt != NULL) && (ctxt->cache != NULL)) { 1962 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 1963 1964 if ((cache->stringObjs != NULL) && 1965 (cache->stringObjs->number != 0)) 1966 { 1967 1968 xmlXPathObjectPtr ret; 1969 1970 ret = (xmlXPathObjectPtr) 1971 cache->stringObjs->items[--cache->stringObjs->number]; 1972 ret->type = XPATH_STRING; 1973 ret->stringval = val; 1974 #ifdef XP_DEBUG_OBJ_USAGE 1975 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 1976 #endif 1977 return(ret); 1978 } else if ((cache->miscObjs != NULL) && 1979 (cache->miscObjs->number != 0)) 1980 { 1981 xmlXPathObjectPtr ret; 1982 /* 1983 * Fallback to misc-cache. 1984 */ 1985 ret = (xmlXPathObjectPtr) 1986 cache->miscObjs->items[--cache->miscObjs->number]; 1987 1988 ret->type = XPATH_STRING; 1989 ret->stringval = val; 1990 #ifdef XP_DEBUG_OBJ_USAGE 1991 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 1992 #endif 1993 return(ret); 1994 } 1995 } 1996 return(xmlXPathWrapString(val)); 1997 } 1998 1999 /** 2000 * xmlXPathCacheNewNodeSet: 2001 * @ctxt: the XPath context 2002 * @val: the NodePtr value 2003 * 2004 * This is the cached version of xmlXPathNewNodeSet(). 2005 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize 2006 * it with the single Node @val 2007 * 2008 * Returns the created or reused object. 2009 */ 2010 static xmlXPathObjectPtr 2011 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val) 2012 { 2013 if ((ctxt != NULL) && (ctxt->cache)) { 2014 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2015 2016 if ((cache->nodesetObjs != NULL) && 2017 (cache->nodesetObjs->number != 0)) 2018 { 2019 xmlXPathObjectPtr ret; 2020 /* 2021 * Use the nodset-cache. 2022 */ 2023 ret = (xmlXPathObjectPtr) 2024 cache->nodesetObjs->items[--cache->nodesetObjs->number]; 2025 ret->type = XPATH_NODESET; 2026 ret->boolval = 0; 2027 if (val) { 2028 if ((ret->nodesetval->nodeMax == 0) || 2029 (val->type == XML_NAMESPACE_DECL)) 2030 { 2031 xmlXPathNodeSetAddUnique(ret->nodesetval, val); 2032 } else { 2033 ret->nodesetval->nodeTab[0] = val; 2034 ret->nodesetval->nodeNr = 1; 2035 } 2036 } 2037 #ifdef XP_DEBUG_OBJ_USAGE 2038 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 2039 #endif 2040 return(ret); 2041 } else if ((cache->miscObjs != NULL) && 2042 (cache->miscObjs->number != 0)) 2043 { 2044 xmlXPathObjectPtr ret; 2045 /* 2046 * Fallback to misc-cache. 2047 */ 2048 2049 ret = (xmlXPathObjectPtr) 2050 cache->miscObjs->items[--cache->miscObjs->number]; 2051 2052 ret->type = XPATH_NODESET; 2053 ret->boolval = 0; 2054 ret->nodesetval = xmlXPathNodeSetCreate(val); 2055 #ifdef XP_DEBUG_OBJ_USAGE 2056 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 2057 #endif 2058 return(ret); 2059 } 2060 } 2061 return(xmlXPathNewNodeSet(val)); 2062 } 2063 2064 /** 2065 * xmlXPathCacheNewCString: 2066 * @ctxt: the XPath context 2067 * @val: the char * value 2068 * 2069 * This is the cached version of xmlXPathNewCString(). 2070 * Acquire an xmlXPathObjectPtr of type string and of value @val 2071 * 2072 * Returns the created or reused object. 2073 */ 2074 static xmlXPathObjectPtr 2075 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val) 2076 { 2077 if ((ctxt != NULL) && (ctxt->cache)) { 2078 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2079 2080 if ((cache->stringObjs != NULL) && 2081 (cache->stringObjs->number != 0)) 2082 { 2083 xmlXPathObjectPtr ret; 2084 2085 ret = (xmlXPathObjectPtr) 2086 cache->stringObjs->items[--cache->stringObjs->number]; 2087 2088 ret->type = XPATH_STRING; 2089 ret->stringval = xmlStrdup(BAD_CAST val); 2090 #ifdef XP_DEBUG_OBJ_USAGE 2091 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2092 #endif 2093 return(ret); 2094 } else if ((cache->miscObjs != NULL) && 2095 (cache->miscObjs->number != 0)) 2096 { 2097 xmlXPathObjectPtr ret; 2098 2099 ret = (xmlXPathObjectPtr) 2100 cache->miscObjs->items[--cache->miscObjs->number]; 2101 2102 ret->type = XPATH_STRING; 2103 ret->stringval = xmlStrdup(BAD_CAST val); 2104 #ifdef XP_DEBUG_OBJ_USAGE 2105 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2106 #endif 2107 return(ret); 2108 } 2109 } 2110 return(xmlXPathNewCString(val)); 2111 } 2112 2113 /** 2114 * xmlXPathCacheNewString: 2115 * @ctxt: the XPath context 2116 * @val: the xmlChar * value 2117 * 2118 * This is the cached version of xmlXPathNewString(). 2119 * Acquire an xmlXPathObjectPtr of type string and of value @val 2120 * 2121 * Returns the created or reused object. 2122 */ 2123 static xmlXPathObjectPtr 2124 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val) 2125 { 2126 if ((ctxt != NULL) && (ctxt->cache)) { 2127 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2128 2129 if ((cache->stringObjs != NULL) && 2130 (cache->stringObjs->number != 0)) 2131 { 2132 xmlXPathObjectPtr ret; 2133 2134 ret = (xmlXPathObjectPtr) 2135 cache->stringObjs->items[--cache->stringObjs->number]; 2136 ret->type = XPATH_STRING; 2137 if (val != NULL) 2138 ret->stringval = xmlStrdup(val); 2139 else 2140 ret->stringval = xmlStrdup((const xmlChar *)""); 2141 #ifdef XP_DEBUG_OBJ_USAGE 2142 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2143 #endif 2144 return(ret); 2145 } else if ((cache->miscObjs != NULL) && 2146 (cache->miscObjs->number != 0)) 2147 { 2148 xmlXPathObjectPtr ret; 2149 2150 ret = (xmlXPathObjectPtr) 2151 cache->miscObjs->items[--cache->miscObjs->number]; 2152 2153 ret->type = XPATH_STRING; 2154 if (val != NULL) 2155 ret->stringval = xmlStrdup(val); 2156 else 2157 ret->stringval = xmlStrdup((const xmlChar *)""); 2158 #ifdef XP_DEBUG_OBJ_USAGE 2159 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2160 #endif 2161 return(ret); 2162 } 2163 } 2164 return(xmlXPathNewString(val)); 2165 } 2166 2167 /** 2168 * xmlXPathCacheNewBoolean: 2169 * @ctxt: the XPath context 2170 * @val: the boolean value 2171 * 2172 * This is the cached version of xmlXPathNewBoolean(). 2173 * Acquires an xmlXPathObjectPtr of type boolean and of value @val 2174 * 2175 * Returns the created or reused object. 2176 */ 2177 static xmlXPathObjectPtr 2178 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val) 2179 { 2180 if ((ctxt != NULL) && (ctxt->cache)) { 2181 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2182 2183 if ((cache->booleanObjs != NULL) && 2184 (cache->booleanObjs->number != 0)) 2185 { 2186 xmlXPathObjectPtr ret; 2187 2188 ret = (xmlXPathObjectPtr) 2189 cache->booleanObjs->items[--cache->booleanObjs->number]; 2190 ret->type = XPATH_BOOLEAN; 2191 ret->boolval = (val != 0); 2192 #ifdef XP_DEBUG_OBJ_USAGE 2193 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN); 2194 #endif 2195 return(ret); 2196 } else if ((cache->miscObjs != NULL) && 2197 (cache->miscObjs->number != 0)) 2198 { 2199 xmlXPathObjectPtr ret; 2200 2201 ret = (xmlXPathObjectPtr) 2202 cache->miscObjs->items[--cache->miscObjs->number]; 2203 2204 ret->type = XPATH_BOOLEAN; 2205 ret->boolval = (val != 0); 2206 #ifdef XP_DEBUG_OBJ_USAGE 2207 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN); 2208 #endif 2209 return(ret); 2210 } 2211 } 2212 return(xmlXPathNewBoolean(val)); 2213 } 2214 2215 /** 2216 * xmlXPathCacheNewFloat: 2217 * @ctxt: the XPath context 2218 * @val: the double value 2219 * 2220 * This is the cached version of xmlXPathNewFloat(). 2221 * Acquires an xmlXPathObjectPtr of type double and of value @val 2222 * 2223 * Returns the created or reused object. 2224 */ 2225 static xmlXPathObjectPtr 2226 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val) 2227 { 2228 if ((ctxt != NULL) && (ctxt->cache)) { 2229 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2230 2231 if ((cache->numberObjs != NULL) && 2232 (cache->numberObjs->number != 0)) 2233 { 2234 xmlXPathObjectPtr ret; 2235 2236 ret = (xmlXPathObjectPtr) 2237 cache->numberObjs->items[--cache->numberObjs->number]; 2238 ret->type = XPATH_NUMBER; 2239 ret->floatval = val; 2240 #ifdef XP_DEBUG_OBJ_USAGE 2241 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER); 2242 #endif 2243 return(ret); 2244 } else if ((cache->miscObjs != NULL) && 2245 (cache->miscObjs->number != 0)) 2246 { 2247 xmlXPathObjectPtr ret; 2248 2249 ret = (xmlXPathObjectPtr) 2250 cache->miscObjs->items[--cache->miscObjs->number]; 2251 2252 ret->type = XPATH_NUMBER; 2253 ret->floatval = val; 2254 #ifdef XP_DEBUG_OBJ_USAGE 2255 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER); 2256 #endif 2257 return(ret); 2258 } 2259 } 2260 return(xmlXPathNewFloat(val)); 2261 } 2262 2263 /** 2264 * xmlXPathCacheConvertString: 2265 * @ctxt: the XPath context 2266 * @val: an XPath object 2267 * 2268 * This is the cached version of xmlXPathConvertString(). 2269 * Converts an existing object to its string() equivalent 2270 * 2271 * Returns a created or reused object, the old one is freed (cached) 2272 * (or the operation is done directly on @val) 2273 */ 2274 2275 static xmlXPathObjectPtr 2276 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 2277 xmlChar *res = NULL; 2278 2279 if (val == NULL) 2280 return(xmlXPathCacheNewCString(ctxt, "")); 2281 2282 switch (val->type) { 2283 case XPATH_UNDEFINED: 2284 #ifdef DEBUG_EXPR 2285 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n"); 2286 #endif 2287 break; 2288 case XPATH_NODESET: 2289 case XPATH_XSLT_TREE: 2290 res = xmlXPathCastNodeSetToString(val->nodesetval); 2291 break; 2292 case XPATH_STRING: 2293 return(val); 2294 case XPATH_BOOLEAN: 2295 res = xmlXPathCastBooleanToString(val->boolval); 2296 break; 2297 case XPATH_NUMBER: 2298 res = xmlXPathCastNumberToString(val->floatval); 2299 break; 2300 case XPATH_USERS: 2301 case XPATH_POINT: 2302 case XPATH_RANGE: 2303 case XPATH_LOCATIONSET: 2304 TODO; 2305 break; 2306 } 2307 xmlXPathReleaseObject(ctxt, val); 2308 if (res == NULL) 2309 return(xmlXPathCacheNewCString(ctxt, "")); 2310 return(xmlXPathCacheWrapString(ctxt, res)); 2311 } 2312 2313 /** 2314 * xmlXPathCacheObjectCopy: 2315 * @ctxt: the XPath context 2316 * @val: the original object 2317 * 2318 * This is the cached version of xmlXPathObjectCopy(). 2319 * Acquire a copy of a given object 2320 * 2321 * Returns a created or reused created object. 2322 */ 2323 static xmlXPathObjectPtr 2324 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) 2325 { 2326 if (val == NULL) 2327 return(NULL); 2328 2329 if (XP_HAS_CACHE(ctxt)) { 2330 switch (val->type) { 2331 case XPATH_NODESET: 2332 return(xmlXPathCacheWrapNodeSet(ctxt, 2333 xmlXPathNodeSetMerge(NULL, val->nodesetval))); 2334 case XPATH_STRING: 2335 return(xmlXPathCacheNewString(ctxt, val->stringval)); 2336 case XPATH_BOOLEAN: 2337 return(xmlXPathCacheNewBoolean(ctxt, val->boolval)); 2338 case XPATH_NUMBER: 2339 return(xmlXPathCacheNewFloat(ctxt, val->floatval)); 2340 default: 2341 break; 2342 } 2343 } 2344 return(xmlXPathObjectCopy(val)); 2345 } 2346 2347 /** 2348 * xmlXPathCacheConvertBoolean: 2349 * @ctxt: the XPath context 2350 * @val: an XPath object 2351 * 2352 * This is the cached version of xmlXPathConvertBoolean(). 2353 * Converts an existing object to its boolean() equivalent 2354 * 2355 * Returns a created or reused object, the old one is freed (or the operation 2356 * is done directly on @val) 2357 */ 2358 static xmlXPathObjectPtr 2359 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 2360 xmlXPathObjectPtr ret; 2361 2362 if (val == NULL) 2363 return(xmlXPathCacheNewBoolean(ctxt, 0)); 2364 if (val->type == XPATH_BOOLEAN) 2365 return(val); 2366 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val)); 2367 xmlXPathReleaseObject(ctxt, val); 2368 return(ret); 2369 } 2370 2371 /** 2372 * xmlXPathCacheConvertNumber: 2373 * @ctxt: the XPath context 2374 * @val: an XPath object 2375 * 2376 * This is the cached version of xmlXPathConvertNumber(). 2377 * Converts an existing object to its number() equivalent 2378 * 2379 * Returns a created or reused object, the old one is freed (or the operation 2380 * is done directly on @val) 2381 */ 2382 static xmlXPathObjectPtr 2383 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 2384 xmlXPathObjectPtr ret; 2385 2386 if (val == NULL) 2387 return(xmlXPathCacheNewFloat(ctxt, 0.0)); 2388 if (val->type == XPATH_NUMBER) 2389 return(val); 2390 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val)); 2391 xmlXPathReleaseObject(ctxt, val); 2392 return(ret); 2393 } 2394 2395 /************************************************************************ 2396 * * 2397 * Parser stacks related functions and macros * 2398 * * 2399 ************************************************************************/ 2400 2401 /** 2402 * xmlXPathSetFrame: 2403 * @ctxt: an XPath parser context 2404 * 2405 * Set the callee evaluation frame 2406 * 2407 * Returns the previous frame value to be restored once done 2408 */ 2409 static int 2410 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) { 2411 int ret; 2412 2413 if (ctxt == NULL) 2414 return(0); 2415 ret = ctxt->valueFrame; 2416 ctxt->valueFrame = ctxt->valueNr; 2417 return(ret); 2418 } 2419 2420 /** 2421 * xmlXPathPopFrame: 2422 * @ctxt: an XPath parser context 2423 * @frame: the previous frame value 2424 * 2425 * Remove the callee evaluation frame 2426 */ 2427 static void 2428 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) { 2429 if (ctxt == NULL) 2430 return; 2431 if (ctxt->valueNr < ctxt->valueFrame) { 2432 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR); 2433 } 2434 ctxt->valueFrame = frame; 2435 } 2436 2437 /** 2438 * valuePop: 2439 * @ctxt: an XPath evaluation context 2440 * 2441 * Pops the top XPath object from the value stack 2442 * 2443 * Returns the XPath object just removed 2444 */ 2445 xmlXPathObjectPtr 2446 valuePop(xmlXPathParserContextPtr ctxt) 2447 { 2448 xmlXPathObjectPtr ret; 2449 2450 if ((ctxt == NULL) || (ctxt->valueNr <= 0)) 2451 return (NULL); 2452 2453 if (ctxt->valueNr <= ctxt->valueFrame) { 2454 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR); 2455 return (NULL); 2456 } 2457 2458 ctxt->valueNr--; 2459 if (ctxt->valueNr > 0) 2460 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1]; 2461 else 2462 ctxt->value = NULL; 2463 ret = ctxt->valueTab[ctxt->valueNr]; 2464 ctxt->valueTab[ctxt->valueNr] = NULL; 2465 return (ret); 2466 } 2467 /** 2468 * valuePush: 2469 * @ctxt: an XPath evaluation context 2470 * @value: the XPath object 2471 * 2472 * Pushes a new XPath object on top of the value stack 2473 * 2474 * returns the number of items on the value stack 2475 */ 2476 int 2477 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value) 2478 { 2479 if ((ctxt == NULL) || (value == NULL)) return(-1); 2480 if (ctxt->valueNr >= ctxt->valueMax) { 2481 xmlXPathObjectPtr *tmp; 2482 2483 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab, 2484 2 * ctxt->valueMax * 2485 sizeof(ctxt->valueTab[0])); 2486 if (tmp == NULL) { 2487 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); 2488 ctxt->error = XPATH_MEMORY_ERROR; 2489 return (0); 2490 } 2491 ctxt->valueMax *= 2; 2492 ctxt->valueTab = tmp; 2493 } 2494 ctxt->valueTab[ctxt->valueNr] = value; 2495 ctxt->value = value; 2496 return (ctxt->valueNr++); 2497 } 2498 2499 /** 2500 * xmlXPathPopBoolean: 2501 * @ctxt: an XPath parser context 2502 * 2503 * Pops a boolean from the stack, handling conversion if needed. 2504 * Check error with #xmlXPathCheckError. 2505 * 2506 * Returns the boolean 2507 */ 2508 int 2509 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) { 2510 xmlXPathObjectPtr obj; 2511 int ret; 2512 2513 obj = valuePop(ctxt); 2514 if (obj == NULL) { 2515 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2516 return(0); 2517 } 2518 if (obj->type != XPATH_BOOLEAN) 2519 ret = xmlXPathCastToBoolean(obj); 2520 else 2521 ret = obj->boolval; 2522 xmlXPathReleaseObject(ctxt->context, obj); 2523 return(ret); 2524 } 2525 2526 /** 2527 * xmlXPathPopNumber: 2528 * @ctxt: an XPath parser context 2529 * 2530 * Pops a number from the stack, handling conversion if needed. 2531 * Check error with #xmlXPathCheckError. 2532 * 2533 * Returns the number 2534 */ 2535 double 2536 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) { 2537 xmlXPathObjectPtr obj; 2538 double ret; 2539 2540 obj = valuePop(ctxt); 2541 if (obj == NULL) { 2542 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2543 return(0); 2544 } 2545 if (obj->type != XPATH_NUMBER) 2546 ret = xmlXPathCastToNumber(obj); 2547 else 2548 ret = obj->floatval; 2549 xmlXPathReleaseObject(ctxt->context, obj); 2550 return(ret); 2551 } 2552 2553 /** 2554 * xmlXPathPopString: 2555 * @ctxt: an XPath parser context 2556 * 2557 * Pops a string from the stack, handling conversion if needed. 2558 * Check error with #xmlXPathCheckError. 2559 * 2560 * Returns the string 2561 */ 2562 xmlChar * 2563 xmlXPathPopString (xmlXPathParserContextPtr ctxt) { 2564 xmlXPathObjectPtr obj; 2565 xmlChar * ret; 2566 2567 obj = valuePop(ctxt); 2568 if (obj == NULL) { 2569 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2570 return(NULL); 2571 } 2572 ret = xmlXPathCastToString(obj); /* this does required strdup */ 2573 /* TODO: needs refactoring somewhere else */ 2574 if (obj->stringval == ret) 2575 obj->stringval = NULL; 2576 xmlXPathReleaseObject(ctxt->context, obj); 2577 return(ret); 2578 } 2579 2580 /** 2581 * xmlXPathPopNodeSet: 2582 * @ctxt: an XPath parser context 2583 * 2584 * Pops a node-set from the stack, handling conversion if needed. 2585 * Check error with #xmlXPathCheckError. 2586 * 2587 * Returns the node-set 2588 */ 2589 xmlNodeSetPtr 2590 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) { 2591 xmlXPathObjectPtr obj; 2592 xmlNodeSetPtr ret; 2593 2594 if (ctxt == NULL) return(NULL); 2595 if (ctxt->value == NULL) { 2596 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2597 return(NULL); 2598 } 2599 if (!xmlXPathStackIsNodeSet(ctxt)) { 2600 xmlXPathSetTypeError(ctxt); 2601 return(NULL); 2602 } 2603 obj = valuePop(ctxt); 2604 ret = obj->nodesetval; 2605 #if 0 2606 /* to fix memory leak of not clearing obj->user */ 2607 if (obj->boolval && obj->user != NULL) 2608 xmlFreeNodeList((xmlNodePtr) obj->user); 2609 #endif 2610 obj->nodesetval = NULL; 2611 xmlXPathReleaseObject(ctxt->context, obj); 2612 return(ret); 2613 } 2614 2615 /** 2616 * xmlXPathPopExternal: 2617 * @ctxt: an XPath parser context 2618 * 2619 * Pops an external object from the stack, handling conversion if needed. 2620 * Check error with #xmlXPathCheckError. 2621 * 2622 * Returns the object 2623 */ 2624 void * 2625 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) { 2626 xmlXPathObjectPtr obj; 2627 void * ret; 2628 2629 if ((ctxt == NULL) || (ctxt->value == NULL)) { 2630 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2631 return(NULL); 2632 } 2633 if (ctxt->value->type != XPATH_USERS) { 2634 xmlXPathSetTypeError(ctxt); 2635 return(NULL); 2636 } 2637 obj = valuePop(ctxt); 2638 ret = obj->user; 2639 obj->user = NULL; 2640 xmlXPathReleaseObject(ctxt->context, obj); 2641 return(ret); 2642 } 2643 2644 /* 2645 * Macros for accessing the content. Those should be used only by the parser, 2646 * and not exported. 2647 * 2648 * Dirty macros, i.e. one need to make assumption on the context to use them 2649 * 2650 * CUR_PTR return the current pointer to the xmlChar to be parsed. 2651 * CUR returns the current xmlChar value, i.e. a 8 bit value 2652 * in ISO-Latin or UTF-8. 2653 * This should be used internally by the parser 2654 * only to compare to ASCII values otherwise it would break when 2655 * running with UTF-8 encoding. 2656 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only 2657 * to compare on ASCII based substring. 2658 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined 2659 * strings within the parser. 2660 * CURRENT Returns the current char value, with the full decoding of 2661 * UTF-8 if we are using this mode. It returns an int. 2662 * NEXT Skip to the next character, this does the proper decoding 2663 * in UTF-8 mode. It also pop-up unfinished entities on the fly. 2664 * It returns the pointer to the current xmlChar. 2665 */ 2666 2667 #define CUR (*ctxt->cur) 2668 #define SKIP(val) ctxt->cur += (val) 2669 #define NXT(val) ctxt->cur[(val)] 2670 #define CUR_PTR ctxt->cur 2671 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l) 2672 2673 #define COPY_BUF(l,b,i,v) \ 2674 if (l == 1) b[i++] = (xmlChar) v; \ 2675 else i += xmlCopyChar(l,&b[i],v) 2676 2677 #define NEXTL(l) ctxt->cur += l 2678 2679 #define SKIP_BLANKS \ 2680 while (IS_BLANK_CH(*(ctxt->cur))) NEXT 2681 2682 #define CURRENT (*ctxt->cur) 2683 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur) 2684 2685 2686 #ifndef DBL_DIG 2687 #define DBL_DIG 16 2688 #endif 2689 #ifndef DBL_EPSILON 2690 #define DBL_EPSILON 1E-9 2691 #endif 2692 2693 #define UPPER_DOUBLE 1E9 2694 #define LOWER_DOUBLE 1E-5 2695 #define LOWER_DOUBLE_EXP 5 2696 2697 #define INTEGER_DIGITS DBL_DIG 2698 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP)) 2699 #define EXPONENT_DIGITS (3 + 2) 2700 2701 /** 2702 * xmlXPathFormatNumber: 2703 * @number: number to format 2704 * @buffer: output buffer 2705 * @buffersize: size of output buffer 2706 * 2707 * Convert the number into a string representation. 2708 */ 2709 static void 2710 xmlXPathFormatNumber(double number, char buffer[], int buffersize) 2711 { 2712 switch (xmlXPathIsInf(number)) { 2713 case 1: 2714 if (buffersize > (int)sizeof("Infinity")) 2715 snprintf(buffer, buffersize, "Infinity"); 2716 break; 2717 case -1: 2718 if (buffersize > (int)sizeof("-Infinity")) 2719 snprintf(buffer, buffersize, "-Infinity"); 2720 break; 2721 default: 2722 if (xmlXPathIsNaN(number)) { 2723 if (buffersize > (int)sizeof("NaN")) 2724 snprintf(buffer, buffersize, "NaN"); 2725 } else if (number == 0 && xmlXPathGetSign(number) != 0) { 2726 snprintf(buffer, buffersize, "0"); 2727 } else if (number == ((int) number)) { 2728 char work[30]; 2729 char *ptr, *cur; 2730 int value = (int) number; 2731 2732 ptr = &buffer[0]; 2733 if (value == 0) { 2734 *ptr++ = '0'; 2735 } else { 2736 snprintf(work, 29, "%d", value); 2737 cur = &work[0]; 2738 while ((*cur) && (ptr - buffer < buffersize)) { 2739 *ptr++ = *cur++; 2740 } 2741 } 2742 if (ptr - buffer < buffersize) { 2743 *ptr = 0; 2744 } else if (buffersize > 0) { 2745 ptr--; 2746 *ptr = 0; 2747 } 2748 } else { 2749 /* 2750 For the dimension of work, 2751 DBL_DIG is number of significant digits 2752 EXPONENT is only needed for "scientific notation" 2753 3 is sign, decimal point, and terminating zero 2754 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction 2755 Note that this dimension is slightly (a few characters) 2756 larger than actually necessary. 2757 */ 2758 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP]; 2759 int integer_place, fraction_place; 2760 char *ptr; 2761 char *after_fraction; 2762 double absolute_value; 2763 int size; 2764 2765 absolute_value = fabs(number); 2766 2767 /* 2768 * First choose format - scientific or regular floating point. 2769 * In either case, result is in work, and after_fraction points 2770 * just past the fractional part. 2771 */ 2772 if ( ((absolute_value > UPPER_DOUBLE) || 2773 (absolute_value < LOWER_DOUBLE)) && 2774 (absolute_value != 0.0) ) { 2775 /* Use scientific notation */ 2776 integer_place = DBL_DIG + EXPONENT_DIGITS + 1; 2777 fraction_place = DBL_DIG - 1; 2778 size = snprintf(work, sizeof(work),"%*.*e", 2779 integer_place, fraction_place, number); 2780 while ((size > 0) && (work[size] != 'e')) size--; 2781 2782 } 2783 else { 2784 /* Use regular notation */ 2785 if (absolute_value > 0.0) { 2786 integer_place = (int)log10(absolute_value); 2787 if (integer_place > 0) 2788 fraction_place = DBL_DIG - integer_place - 1; 2789 else 2790 fraction_place = DBL_DIG - integer_place; 2791 } else { 2792 fraction_place = 1; 2793 } 2794 size = snprintf(work, sizeof(work), "%0.*f", 2795 fraction_place, number); 2796 } 2797 2798 /* Remove fractional trailing zeroes */ 2799 after_fraction = work + size; 2800 ptr = after_fraction; 2801 while (*(--ptr) == '0') 2802 ; 2803 if (*ptr != '.') 2804 ptr++; 2805 while ((*ptr++ = *after_fraction++) != 0); 2806 2807 /* Finally copy result back to caller */ 2808 size = strlen(work) + 1; 2809 if (size > buffersize && buffersize <= (int)sizeof(work)) { 2810 work[buffersize - 1] = 0; 2811 size = buffersize; 2812 } 2813 memmove(buffer, work, size); 2814 } 2815 break; 2816 } 2817 } 2818 2819 2820 /************************************************************************ 2821 * * 2822 * Routines to handle NodeSets * 2823 * * 2824 ************************************************************************/ 2825 2826 /** 2827 * xmlXPathOrderDocElems: 2828 * @doc: an input document 2829 * 2830 * Call this routine to speed up XPath computation on static documents. 2831 * This stamps all the element nodes with the document order 2832 * Like for line information, the order is kept in the element->content 2833 * field, the value stored is actually - the node number (starting at -1) 2834 * to be able to differentiate from line numbers. 2835 * 2836 * Returns the number of elements found in the document or -1 in case 2837 * of error. 2838 */ 2839 long 2840 xmlXPathOrderDocElems(xmlDocPtr doc) { 2841 long count = 0; 2842 xmlNodePtr cur; 2843 2844 if (doc == NULL) 2845 return(-1); 2846 cur = doc->children; 2847 while (cur != NULL) { 2848 if (cur->type == XML_ELEMENT_NODE) { 2849 cur->content = (void *) (-(++count)); 2850 if (cur->children != NULL) { 2851 cur = cur->children; 2852 continue; 2853 } 2854 } 2855 if (cur->next != NULL) { 2856 cur = cur->next; 2857 continue; 2858 } 2859 do { 2860 cur = cur->parent; 2861 if (cur == NULL) 2862 break; 2863 if (cur == (xmlNodePtr) doc) { 2864 cur = NULL; 2865 break; 2866 } 2867 if (cur->next != NULL) { 2868 cur = cur->next; 2869 break; 2870 } 2871 } while (cur != NULL); 2872 } 2873 return(count); 2874 } 2875 2876 /** 2877 * xmlXPathCmpNodes: 2878 * @node1: the first node 2879 * @node2: the second node 2880 * 2881 * Compare two nodes w.r.t document order 2882 * 2883 * Returns -2 in case of error 1 if first point < second point, 0 if 2884 * it's the same node, -1 otherwise 2885 */ 2886 int 2887 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) { 2888 int depth1, depth2; 2889 int attr1 = 0, attr2 = 0; 2890 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL; 2891 xmlNodePtr cur, root; 2892 2893 if ((node1 == NULL) || (node2 == NULL)) 2894 return(-2); 2895 /* 2896 * a couple of optimizations which will avoid computations in most cases 2897 */ 2898 if (node1 == node2) /* trivial case */ 2899 return(0); 2900 if (node1->type == XML_ATTRIBUTE_NODE) { 2901 attr1 = 1; 2902 attrNode1 = node1; 2903 node1 = node1->parent; 2904 } 2905 if (node2->type == XML_ATTRIBUTE_NODE) { 2906 attr2 = 1; 2907 attrNode2 = node2; 2908 node2 = node2->parent; 2909 } 2910 if (node1 == node2) { 2911 if (attr1 == attr2) { 2912 /* not required, but we keep attributes in order */ 2913 if (attr1 != 0) { 2914 cur = attrNode2->prev; 2915 while (cur != NULL) { 2916 if (cur == attrNode1) 2917 return (1); 2918 cur = cur->prev; 2919 } 2920 return (-1); 2921 } 2922 return(0); 2923 } 2924 if (attr2 == 1) 2925 return(1); 2926 return(-1); 2927 } 2928 if ((node1->type == XML_NAMESPACE_DECL) || 2929 (node2->type == XML_NAMESPACE_DECL)) 2930 return(1); 2931 if (node1 == node2->prev) 2932 return(1); 2933 if (node1 == node2->next) 2934 return(-1); 2935 2936 /* 2937 * Speedup using document order if availble. 2938 */ 2939 if ((node1->type == XML_ELEMENT_NODE) && 2940 (node2->type == XML_ELEMENT_NODE) && 2941 (0 > (long) node1->content) && 2942 (0 > (long) node2->content) && 2943 (node1->doc == node2->doc)) { 2944 long l1, l2; 2945 2946 l1 = -((long) node1->content); 2947 l2 = -((long) node2->content); 2948 if (l1 < l2) 2949 return(1); 2950 if (l1 > l2) 2951 return(-1); 2952 } 2953 2954 /* 2955 * compute depth to root 2956 */ 2957 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) { 2958 if (cur == node1) 2959 return(1); 2960 depth2++; 2961 } 2962 root = cur; 2963 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) { 2964 if (cur == node2) 2965 return(-1); 2966 depth1++; 2967 } 2968 /* 2969 * Distinct document (or distinct entities :-( ) case. 2970 */ 2971 if (root != cur) { 2972 return(-2); 2973 } 2974 /* 2975 * get the nearest common ancestor. 2976 */ 2977 while (depth1 > depth2) { 2978 depth1--; 2979 node1 = node1->parent; 2980 } 2981 while (depth2 > depth1) { 2982 depth2--; 2983 node2 = node2->parent; 2984 } 2985 while (node1->parent != node2->parent) { 2986 node1 = node1->parent; 2987 node2 = node2->parent; 2988 /* should not happen but just in case ... */ 2989 if ((node1 == NULL) || (node2 == NULL)) 2990 return(-2); 2991 } 2992 /* 2993 * Find who's first. 2994 */ 2995 if (node1 == node2->prev) 2996 return(1); 2997 if (node1 == node2->next) 2998 return(-1); 2999 /* 3000 * Speedup using document order if availble. 3001 */ 3002 if ((node1->type == XML_ELEMENT_NODE) && 3003 (node2->type == XML_ELEMENT_NODE) && 3004 (0 > (long) node1->content) && 3005 (0 > (long) node2->content) && 3006 (node1->doc == node2->doc)) { 3007 long l1, l2; 3008 3009 l1 = -((long) node1->content); 3010 l2 = -((long) node2->content); 3011 if (l1 < l2) 3012 return(1); 3013 if (l1 > l2) 3014 return(-1); 3015 } 3016 3017 for (cur = node1->next;cur != NULL;cur = cur->next) 3018 if (cur == node2) 3019 return(1); 3020 return(-1); /* assume there is no sibling list corruption */ 3021 } 3022 3023 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 3024 /** 3025 * xmlXPathCmpNodesExt: 3026 * @node1: the first node 3027 * @node2: the second node 3028 * 3029 * Compare two nodes w.r.t document order. 3030 * This one is optimized for handling of non-element nodes. 3031 * 3032 * Returns -2 in case of error 1 if first point < second point, 0 if 3033 * it's the same node, -1 otherwise 3034 */ 3035 static int 3036 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) { 3037 int depth1, depth2; 3038 int misc = 0, precedence1 = 0, precedence2 = 0; 3039 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL; 3040 xmlNodePtr cur, root; 3041 long l1, l2; 3042 3043 if ((node1 == NULL) || (node2 == NULL)) 3044 return(-2); 3045 3046 if (node1 == node2) 3047 return(0); 3048 3049 /* 3050 * a couple of optimizations which will avoid computations in most cases 3051 */ 3052 switch (node1->type) { 3053 case XML_ELEMENT_NODE: 3054 if (node2->type == XML_ELEMENT_NODE) { 3055 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */ 3056 (0 > (long) node2->content) && 3057 (node1->doc == node2->doc)) 3058 { 3059 l1 = -((long) node1->content); 3060 l2 = -((long) node2->content); 3061 if (l1 < l2) 3062 return(1); 3063 if (l1 > l2) 3064 return(-1); 3065 } else 3066 goto turtle_comparison; 3067 } 3068 break; 3069 case XML_ATTRIBUTE_NODE: 3070 precedence1 = 1; /* element is owner */ 3071 miscNode1 = node1; 3072 node1 = node1->parent; 3073 misc = 1; 3074 break; 3075 case XML_TEXT_NODE: 3076 case XML_CDATA_SECTION_NODE: 3077 case XML_COMMENT_NODE: 3078 case XML_PI_NODE: { 3079 miscNode1 = node1; 3080 /* 3081 * Find nearest element node. 3082 */ 3083 if (node1->prev != NULL) { 3084 do { 3085 node1 = node1->prev; 3086 if (node1->type == XML_ELEMENT_NODE) { 3087 precedence1 = 3; /* element in prev-sibl axis */ 3088 break; 3089 } 3090 if (node1->prev == NULL) { 3091 precedence1 = 2; /* element is parent */ 3092 /* 3093 * URGENT TODO: Are there any cases, where the 3094 * parent of such a node is not an element node? 3095 */ 3096 node1 = node1->parent; 3097 break; 3098 } 3099 } while (1); 3100 } else { 3101 precedence1 = 2; /* element is parent */ 3102 node1 = node1->parent; 3103 } 3104 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) || 3105 (0 <= (long) node1->content)) { 3106 /* 3107 * Fallback for whatever case. 3108 */ 3109 node1 = miscNode1; 3110 precedence1 = 0; 3111 } else 3112 misc = 1; 3113 } 3114 break; 3115 case XML_NAMESPACE_DECL: 3116 /* 3117 * TODO: why do we return 1 for namespace nodes? 3118 */ 3119 return(1); 3120 default: 3121 break; 3122 } 3123 switch (node2->type) { 3124 case XML_ELEMENT_NODE: 3125 break; 3126 case XML_ATTRIBUTE_NODE: 3127 precedence2 = 1; /* element is owner */ 3128 miscNode2 = node2; 3129 node2 = node2->parent; 3130 misc = 1; 3131 break; 3132 case XML_TEXT_NODE: 3133 case XML_CDATA_SECTION_NODE: 3134 case XML_COMMENT_NODE: 3135 case XML_PI_NODE: { 3136 miscNode2 = node2; 3137 if (node2->prev != NULL) { 3138 do { 3139 node2 = node2->prev; 3140 if (node2->type == XML_ELEMENT_NODE) { 3141 precedence2 = 3; /* element in prev-sibl axis */ 3142 break; 3143 } 3144 if (node2->prev == NULL) { 3145 precedence2 = 2; /* element is parent */ 3146 node2 = node2->parent; 3147 break; 3148 } 3149 } while (1); 3150 } else { 3151 precedence2 = 2; /* element is parent */ 3152 node2 = node2->parent; 3153 } 3154 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) || 3155 (0 <= (long) node1->content)) 3156 { 3157 node2 = miscNode2; 3158 precedence2 = 0; 3159 } else 3160 misc = 1; 3161 } 3162 break; 3163 case XML_NAMESPACE_DECL: 3164 return(1); 3165 default: 3166 break; 3167 } 3168 if (misc) { 3169 if (node1 == node2) { 3170 if (precedence1 == precedence2) { 3171 /* 3172 * The ugly case; but normally there aren't many 3173 * adjacent non-element nodes around. 3174 */ 3175 cur = miscNode2->prev; 3176 while (cur != NULL) { 3177 if (cur == miscNode1) 3178 return(1); 3179 if (cur->type == XML_ELEMENT_NODE) 3180 return(-1); 3181 cur = cur->prev; 3182 } 3183 return (-1); 3184 } else { 3185 /* 3186 * Evaluate based on higher precedence wrt to the element. 3187 * TODO: This assumes attributes are sorted before content. 3188 * Is this 100% correct? 3189 */ 3190 if (precedence1 < precedence2) 3191 return(1); 3192 else 3193 return(-1); 3194 } 3195 } 3196 /* 3197 * Special case: One of the helper-elements is contained by the other. 3198 * <foo> 3199 * <node2> 3200 * <node1>Text-1(precedence1 == 2)</node1> 3201 * </node2> 3202 * Text-6(precedence2 == 3) 3203 * </foo> 3204 */ 3205 if ((precedence2 == 3) && (precedence1 > 1)) { 3206 cur = node1->parent; 3207 while (cur) { 3208 if (cur == node2) 3209 return(1); 3210 cur = cur->parent; 3211 } 3212 } 3213 if ((precedence1 == 3) && (precedence2 > 1)) { 3214 cur = node2->parent; 3215 while (cur) { 3216 if (cur == node1) 3217 return(-1); 3218 cur = cur->parent; 3219 } 3220 } 3221 } 3222 3223 /* 3224 * Speedup using document order if availble. 3225 */ 3226 if ((node1->type == XML_ELEMENT_NODE) && 3227 (node2->type == XML_ELEMENT_NODE) && 3228 (0 > (long) node1->content) && 3229 (0 > (long) node2->content) && 3230 (node1->doc == node2->doc)) { 3231 3232 l1 = -((long) node1->content); 3233 l2 = -((long) node2->content); 3234 if (l1 < l2) 3235 return(1); 3236 if (l1 > l2) 3237 return(-1); 3238 } 3239 3240 turtle_comparison: 3241 3242 if (node1 == node2->prev) 3243 return(1); 3244 if (node1 == node2->next) 3245 return(-1); 3246 /* 3247 * compute depth to root 3248 */ 3249 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) { 3250 if (cur == node1) 3251 return(1); 3252 depth2++; 3253 } 3254 root = cur; 3255 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) { 3256 if (cur == node2) 3257 return(-1); 3258 depth1++; 3259 } 3260 /* 3261 * Distinct document (or distinct entities :-( ) case. 3262 */ 3263 if (root != cur) { 3264 return(-2); 3265 } 3266 /* 3267 * get the nearest common ancestor. 3268 */ 3269 while (depth1 > depth2) { 3270 depth1--; 3271 node1 = node1->parent; 3272 } 3273 while (depth2 > depth1) { 3274 depth2--; 3275 node2 = node2->parent; 3276 } 3277 while (node1->parent != node2->parent) { 3278 node1 = node1->parent; 3279 node2 = node2->parent; 3280 /* should not happen but just in case ... */ 3281 if ((node1 == NULL) || (node2 == NULL)) 3282 return(-2); 3283 } 3284 /* 3285 * Find who's first. 3286 */ 3287 if (node1 == node2->prev) 3288 return(1); 3289 if (node1 == node2->next) 3290 return(-1); 3291 /* 3292 * Speedup using document order if availble. 3293 */ 3294 if ((node1->type == XML_ELEMENT_NODE) && 3295 (node2->type == XML_ELEMENT_NODE) && 3296 (0 > (long) node1->content) && 3297 (0 > (long) node2->content) && 3298 (node1->doc == node2->doc)) { 3299 3300 l1 = -((long) node1->content); 3301 l2 = -((long) node2->content); 3302 if (l1 < l2) 3303 return(1); 3304 if (l1 > l2) 3305 return(-1); 3306 } 3307 3308 for (cur = node1->next;cur != NULL;cur = cur->next) 3309 if (cur == node2) 3310 return(1); 3311 return(-1); /* assume there is no sibling list corruption */ 3312 } 3313 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */ 3314 3315 /** 3316 * xmlXPathNodeSetSort: 3317 * @set: the node set 3318 * 3319 * Sort the node set in document order 3320 */ 3321 void 3322 xmlXPathNodeSetSort(xmlNodeSetPtr set) { 3323 int i, j, incr, len; 3324 xmlNodePtr tmp; 3325 3326 if (set == NULL) 3327 return; 3328 3329 /* Use Shell's sort to sort the node-set */ 3330 len = set->nodeNr; 3331 for (incr = len / 2; incr > 0; incr /= 2) { 3332 for (i = incr; i < len; i++) { 3333 j = i - incr; 3334 while (j >= 0) { 3335 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 3336 if (xmlXPathCmpNodesExt(set->nodeTab[j], 3337 set->nodeTab[j + incr]) == -1) 3338 #else 3339 if (xmlXPathCmpNodes(set->nodeTab[j], 3340 set->nodeTab[j + incr]) == -1) 3341 #endif 3342 { 3343 tmp = set->nodeTab[j]; 3344 set->nodeTab[j] = set->nodeTab[j + incr]; 3345 set->nodeTab[j + incr] = tmp; 3346 j -= incr; 3347 } else 3348 break; 3349 } 3350 } 3351 } 3352 } 3353 3354 #define XML_NODESET_DEFAULT 10 3355 /** 3356 * xmlXPathNodeSetDupNs: 3357 * @node: the parent node of the namespace XPath node 3358 * @ns: the libxml namespace declaration node. 3359 * 3360 * Namespace node in libxml don't match the XPath semantic. In a node set 3361 * the namespace nodes are duplicated and the next pointer is set to the 3362 * parent node in the XPath semantic. 3363 * 3364 * Returns the newly created object. 3365 */ 3366 static xmlNodePtr 3367 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) { 3368 xmlNsPtr cur; 3369 3370 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) 3371 return(NULL); 3372 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) 3373 return((xmlNodePtr) ns); 3374 3375 /* 3376 * Allocate a new Namespace and fill the fields. 3377 */ 3378 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); 3379 if (cur == NULL) { 3380 xmlXPathErrMemory(NULL, "duplicating namespace\n"); 3381 return(NULL); 3382 } 3383 memset(cur, 0, sizeof(xmlNs)); 3384 cur->type = XML_NAMESPACE_DECL; 3385 if (ns->href != NULL) 3386 cur->href = xmlStrdup(ns->href); 3387 if (ns->prefix != NULL) 3388 cur->prefix = xmlStrdup(ns->prefix); 3389 cur->next = (xmlNsPtr) node; 3390 return((xmlNodePtr) cur); 3391 } 3392 3393 /** 3394 * xmlXPathNodeSetFreeNs: 3395 * @ns: the XPath namespace node found in a nodeset. 3396 * 3397 * Namespace nodes in libxml don't match the XPath semantic. In a node set 3398 * the namespace nodes are duplicated and the next pointer is set to the 3399 * parent node in the XPath semantic. Check if such a node needs to be freed 3400 */ 3401 void 3402 xmlXPathNodeSetFreeNs(xmlNsPtr ns) { 3403 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) 3404 return; 3405 3406 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) { 3407 if (ns->href != NULL) 3408 xmlFree((xmlChar *)ns->href); 3409 if (ns->prefix != NULL) 3410 xmlFree((xmlChar *)ns->prefix); 3411 xmlFree(ns); 3412 } 3413 } 3414 3415 /** 3416 * xmlXPathNodeSetCreate: 3417 * @val: an initial xmlNodePtr, or NULL 3418 * 3419 * Create a new xmlNodeSetPtr of type double and of value @val 3420 * 3421 * Returns the newly created object. 3422 */ 3423 xmlNodeSetPtr 3424 xmlXPathNodeSetCreate(xmlNodePtr val) { 3425 xmlNodeSetPtr ret; 3426 3427 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet)); 3428 if (ret == NULL) { 3429 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3430 return(NULL); 3431 } 3432 memset(ret, 0 , (size_t) sizeof(xmlNodeSet)); 3433 if (val != NULL) { 3434 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3435 sizeof(xmlNodePtr)); 3436 if (ret->nodeTab == NULL) { 3437 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3438 xmlFree(ret); 3439 return(NULL); 3440 } 3441 memset(ret->nodeTab, 0 , 3442 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3443 ret->nodeMax = XML_NODESET_DEFAULT; 3444 if (val->type == XML_NAMESPACE_DECL) { 3445 xmlNsPtr ns = (xmlNsPtr) val; 3446 3447 ret->nodeTab[ret->nodeNr++] = 3448 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3449 } else 3450 ret->nodeTab[ret->nodeNr++] = val; 3451 } 3452 return(ret); 3453 } 3454 3455 /** 3456 * xmlXPathNodeSetCreateSize: 3457 * @size: the initial size of the set 3458 * 3459 * Create a new xmlNodeSetPtr of type double and of value @val 3460 * 3461 * Returns the newly created object. 3462 */ 3463 static xmlNodeSetPtr 3464 xmlXPathNodeSetCreateSize(int size) { 3465 xmlNodeSetPtr ret; 3466 3467 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet)); 3468 if (ret == NULL) { 3469 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3470 return(NULL); 3471 } 3472 memset(ret, 0 , (size_t) sizeof(xmlNodeSet)); 3473 if (size < XML_NODESET_DEFAULT) 3474 size = XML_NODESET_DEFAULT; 3475 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr)); 3476 if (ret->nodeTab == NULL) { 3477 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3478 xmlFree(ret); 3479 return(NULL); 3480 } 3481 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr)); 3482 ret->nodeMax = size; 3483 return(ret); 3484 } 3485 3486 /** 3487 * xmlXPathNodeSetContains: 3488 * @cur: the node-set 3489 * @val: the node 3490 * 3491 * checks whether @cur contains @val 3492 * 3493 * Returns true (1) if @cur contains @val, false (0) otherwise 3494 */ 3495 int 3496 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) { 3497 int i; 3498 3499 if ((cur == NULL) || (val == NULL)) return(0); 3500 if (val->type == XML_NAMESPACE_DECL) { 3501 for (i = 0; i < cur->nodeNr; i++) { 3502 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) { 3503 xmlNsPtr ns1, ns2; 3504 3505 ns1 = (xmlNsPtr) val; 3506 ns2 = (xmlNsPtr) cur->nodeTab[i]; 3507 if (ns1 == ns2) 3508 return(1); 3509 if ((ns1->next != NULL) && (ns2->next == ns1->next) && 3510 (xmlStrEqual(ns1->prefix, ns2->prefix))) 3511 return(1); 3512 } 3513 } 3514 } else { 3515 for (i = 0; i < cur->nodeNr; i++) { 3516 if (cur->nodeTab[i] == val) 3517 return(1); 3518 } 3519 } 3520 return(0); 3521 } 3522 3523 /** 3524 * xmlXPathNodeSetAddNs: 3525 * @cur: the initial node set 3526 * @node: the hosting node 3527 * @ns: a the namespace node 3528 * 3529 * add a new namespace node to an existing NodeSet 3530 */ 3531 void 3532 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) { 3533 int i; 3534 3535 3536 if ((cur == NULL) || (ns == NULL) || (node == NULL) || 3537 (ns->type != XML_NAMESPACE_DECL) || 3538 (node->type != XML_ELEMENT_NODE)) 3539 return; 3540 3541 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3542 /* 3543 * prevent duplicates 3544 */ 3545 for (i = 0;i < cur->nodeNr;i++) { 3546 if ((cur->nodeTab[i] != NULL) && 3547 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) && 3548 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) && 3549 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix))) 3550 return; 3551 } 3552 3553 /* 3554 * grow the nodeTab if needed 3555 */ 3556 if (cur->nodeMax == 0) { 3557 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3558 sizeof(xmlNodePtr)); 3559 if (cur->nodeTab == NULL) { 3560 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3561 return; 3562 } 3563 memset(cur->nodeTab, 0 , 3564 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3565 cur->nodeMax = XML_NODESET_DEFAULT; 3566 } else if (cur->nodeNr == cur->nodeMax) { 3567 xmlNodePtr *temp; 3568 3569 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 * 3570 sizeof(xmlNodePtr)); 3571 if (temp == NULL) { 3572 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3573 return; 3574 } 3575 cur->nodeMax *= 2; 3576 cur->nodeTab = temp; 3577 } 3578 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns); 3579 } 3580 3581 /** 3582 * xmlXPathNodeSetAdd: 3583 * @cur: the initial node set 3584 * @val: a new xmlNodePtr 3585 * 3586 * add a new xmlNodePtr to an existing NodeSet 3587 */ 3588 void 3589 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) { 3590 int i; 3591 3592 if ((cur == NULL) || (val == NULL)) return; 3593 3594 #if 0 3595 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' ')) 3596 return; /* an XSLT fake node */ 3597 #endif 3598 3599 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3600 /* 3601 * prevent duplcates 3602 */ 3603 for (i = 0;i < cur->nodeNr;i++) 3604 if (cur->nodeTab[i] == val) return; 3605 3606 /* 3607 * grow the nodeTab if needed 3608 */ 3609 if (cur->nodeMax == 0) { 3610 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3611 sizeof(xmlNodePtr)); 3612 if (cur->nodeTab == NULL) { 3613 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3614 return; 3615 } 3616 memset(cur->nodeTab, 0 , 3617 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3618 cur->nodeMax = XML_NODESET_DEFAULT; 3619 } else if (cur->nodeNr == cur->nodeMax) { 3620 xmlNodePtr *temp; 3621 3622 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 * 3623 sizeof(xmlNodePtr)); 3624 if (temp == NULL) { 3625 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3626 return; 3627 } 3628 cur->nodeMax *= 2; 3629 cur->nodeTab = temp; 3630 } 3631 if (val->type == XML_NAMESPACE_DECL) { 3632 xmlNsPtr ns = (xmlNsPtr) val; 3633 3634 cur->nodeTab[cur->nodeNr++] = 3635 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3636 } else 3637 cur->nodeTab[cur->nodeNr++] = val; 3638 } 3639 3640 /** 3641 * xmlXPathNodeSetAddUnique: 3642 * @cur: the initial node set 3643 * @val: a new xmlNodePtr 3644 * 3645 * add a new xmlNodePtr to an existing NodeSet, optimized version 3646 * when we are sure the node is not already in the set. 3647 */ 3648 void 3649 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) { 3650 if ((cur == NULL) || (val == NULL)) return; 3651 3652 #if 0 3653 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' ')) 3654 return; /* an XSLT fake node */ 3655 #endif 3656 3657 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 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; 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 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 * 3675 sizeof(xmlNodePtr)); 3676 if (temp == NULL) { 3677 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3678 return; 3679 } 3680 cur->nodeTab = temp; 3681 cur->nodeMax *= 2; 3682 } 3683 if (val->type == XML_NAMESPACE_DECL) { 3684 xmlNsPtr ns = (xmlNsPtr) val; 3685 3686 cur->nodeTab[cur->nodeNr++] = 3687 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3688 } else 3689 cur->nodeTab[cur->nodeNr++] = val; 3690 } 3691 3692 /** 3693 * xmlXPathNodeSetMerge: 3694 * @val1: the first NodeSet or NULL 3695 * @val2: the second NodeSet 3696 * 3697 * Merges two nodesets, all nodes from @val2 are added to @val1 3698 * if @val1 is NULL, a new set is created and copied from @val2 3699 * 3700 * Returns @val1 once extended or NULL in case of error. 3701 */ 3702 xmlNodeSetPtr 3703 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) { 3704 int i, j, initNr, skip; 3705 xmlNodePtr n1, n2; 3706 3707 if (val2 == NULL) return(val1); 3708 if (val1 == NULL) { 3709 val1 = xmlXPathNodeSetCreate(NULL); 3710 if (val1 == NULL) 3711 return (NULL); 3712 #if 0 3713 /* 3714 * TODO: The optimization won't work in every case, since 3715 * those nasty namespace nodes need to be added with 3716 * xmlXPathNodeSetDupNs() to the set; thus a pure 3717 * memcpy is not possible. 3718 * If there was a flag on the nodesetval, indicating that 3719 * some temporary nodes are in, that would be helpfull. 3720 */ 3721 /* 3722 * Optimization: Create an equally sized node-set 3723 * and memcpy the content. 3724 */ 3725 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr); 3726 if (val1 == NULL) 3727 return(NULL); 3728 if (val2->nodeNr != 0) { 3729 if (val2->nodeNr == 1) 3730 *(val1->nodeTab) = *(val2->nodeTab); 3731 else { 3732 memcpy(val1->nodeTab, val2->nodeTab, 3733 val2->nodeNr * sizeof(xmlNodePtr)); 3734 } 3735 val1->nodeNr = val2->nodeNr; 3736 } 3737 return(val1); 3738 #endif 3739 } 3740 3741 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3742 initNr = val1->nodeNr; 3743 3744 for (i = 0;i < val2->nodeNr;i++) { 3745 n2 = val2->nodeTab[i]; 3746 /* 3747 * check against duplicates 3748 */ 3749 skip = 0; 3750 for (j = 0; j < initNr; j++) { 3751 n1 = val1->nodeTab[j]; 3752 if (n1 == n2) { 3753 skip = 1; 3754 break; 3755 } else if ((n1->type == XML_NAMESPACE_DECL) && 3756 (n2->type == XML_NAMESPACE_DECL)) { 3757 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) && 3758 (xmlStrEqual(((xmlNsPtr) n1)->prefix, 3759 ((xmlNsPtr) n2)->prefix))) 3760 { 3761 skip = 1; 3762 break; 3763 } 3764 } 3765 } 3766 if (skip) 3767 continue; 3768 3769 /* 3770 * grow the nodeTab if needed 3771 */ 3772 if (val1->nodeMax == 0) { 3773 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3774 sizeof(xmlNodePtr)); 3775 if (val1->nodeTab == NULL) { 3776 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3777 return(NULL); 3778 } 3779 memset(val1->nodeTab, 0 , 3780 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3781 val1->nodeMax = XML_NODESET_DEFAULT; 3782 } else if (val1->nodeNr == val1->nodeMax) { 3783 xmlNodePtr *temp; 3784 3785 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 * 3786 sizeof(xmlNodePtr)); 3787 if (temp == NULL) { 3788 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3789 return(NULL); 3790 } 3791 val1->nodeTab = temp; 3792 val1->nodeMax *= 2; 3793 } 3794 if (n2->type == XML_NAMESPACE_DECL) { 3795 xmlNsPtr ns = (xmlNsPtr) n2; 3796 3797 val1->nodeTab[val1->nodeNr++] = 3798 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3799 } else 3800 val1->nodeTab[val1->nodeNr++] = n2; 3801 } 3802 3803 return(val1); 3804 } 3805 3806 #if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */ 3807 /** 3808 * xmlXPathNodeSetMergeUnique: 3809 * @val1: the first NodeSet or NULL 3810 * @val2: the second NodeSet 3811 * 3812 * Merges two nodesets, all nodes from @val2 are added to @val1 3813 * if @val1 is NULL, a new set is created and copied from @val2 3814 * 3815 * Returns @val1 once extended or NULL in case of error. 3816 */ 3817 static xmlNodeSetPtr 3818 xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) { 3819 int i; 3820 3821 if (val2 == NULL) return(val1); 3822 if (val1 == NULL) { 3823 val1 = xmlXPathNodeSetCreate(NULL); 3824 } 3825 if (val1 == NULL) 3826 return (NULL); 3827 3828 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3829 3830 for (i = 0;i < val2->nodeNr;i++) { 3831 /* 3832 * grow the nodeTab if needed 3833 */ 3834 if (val1->nodeMax == 0) { 3835 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3836 sizeof(xmlNodePtr)); 3837 if (val1->nodeTab == NULL) { 3838 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3839 return(NULL); 3840 } 3841 memset(val1->nodeTab, 0 , 3842 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3843 val1->nodeMax = XML_NODESET_DEFAULT; 3844 } else if (val1->nodeNr == val1->nodeMax) { 3845 xmlNodePtr *temp; 3846 3847 val1->nodeMax *= 2; 3848 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 3849 sizeof(xmlNodePtr)); 3850 if (temp == NULL) { 3851 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3852 return(NULL); 3853 } 3854 val1->nodeTab = temp; 3855 } 3856 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) { 3857 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i]; 3858 3859 val1->nodeTab[val1->nodeNr++] = 3860 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3861 } else 3862 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i]; 3863 } 3864 3865 return(val1); 3866 } 3867 #endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */ 3868 3869 /** 3870 * xmlXPathNodeSetMergeAndClear: 3871 * @set1: the first NodeSet or NULL 3872 * @set2: the second NodeSet 3873 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes 3874 * 3875 * Merges two nodesets, all nodes from @set2 are added to @set1 3876 * if @set1 is NULL, a new set is created and copied from @set2. 3877 * Checks for duplicate nodes. Clears set2. 3878 * 3879 * Returns @set1 once extended or NULL in case of error. 3880 */ 3881 static xmlNodeSetPtr 3882 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2, 3883 int hasNullEntries) 3884 { 3885 if ((set1 == NULL) && (hasNullEntries == 0)) { 3886 /* 3887 * Note that doing a memcpy of the list, namespace nodes are 3888 * just assigned to set1, since set2 is cleared anyway. 3889 */ 3890 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr); 3891 if (set1 == NULL) 3892 return(NULL); 3893 if (set2->nodeNr != 0) { 3894 memcpy(set1->nodeTab, set2->nodeTab, 3895 set2->nodeNr * sizeof(xmlNodePtr)); 3896 set1->nodeNr = set2->nodeNr; 3897 } 3898 } else { 3899 int i, j, initNbSet1; 3900 xmlNodePtr n1, n2; 3901 3902 if (set1 == NULL) 3903 set1 = xmlXPathNodeSetCreate(NULL); 3904 if (set1 == NULL) 3905 return (NULL); 3906 3907 initNbSet1 = set1->nodeNr; 3908 for (i = 0;i < set2->nodeNr;i++) { 3909 n2 = set2->nodeTab[i]; 3910 /* 3911 * Skip NULLed entries. 3912 */ 3913 if (n2 == NULL) 3914 continue; 3915 /* 3916 * Skip duplicates. 3917 */ 3918 for (j = 0; j < initNbSet1; j++) { 3919 n1 = set1->nodeTab[j]; 3920 if (n1 == n2) { 3921 goto skip_node; 3922 } else if ((n1->type == XML_NAMESPACE_DECL) && 3923 (n2->type == XML_NAMESPACE_DECL)) 3924 { 3925 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) && 3926 (xmlStrEqual(((xmlNsPtr) n1)->prefix, 3927 ((xmlNsPtr) n2)->prefix))) 3928 { 3929 /* 3930 * Free the namespace node. 3931 */ 3932 set2->nodeTab[i] = NULL; 3933 xmlXPathNodeSetFreeNs((xmlNsPtr) n2); 3934 goto skip_node; 3935 } 3936 } 3937 } 3938 /* 3939 * grow the nodeTab if needed 3940 */ 3941 if (set1->nodeMax == 0) { 3942 set1->nodeTab = (xmlNodePtr *) xmlMalloc( 3943 XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); 3944 if (set1->nodeTab == NULL) { 3945 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3946 return(NULL); 3947 } 3948 memset(set1->nodeTab, 0, 3949 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3950 set1->nodeMax = XML_NODESET_DEFAULT; 3951 } else if (set1->nodeNr >= set1->nodeMax) { 3952 xmlNodePtr *temp; 3953 3954 temp = (xmlNodePtr *) xmlRealloc( 3955 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr)); 3956 if (temp == NULL) { 3957 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3958 return(NULL); 3959 } 3960 set1->nodeTab = temp; 3961 set1->nodeMax *= 2; 3962 } 3963 if (n2->type == XML_NAMESPACE_DECL) { 3964 xmlNsPtr ns = (xmlNsPtr) n2; 3965 3966 set1->nodeTab[set1->nodeNr++] = 3967 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3968 } else 3969 set1->nodeTab[set1->nodeNr++] = n2; 3970 skip_node: 3971 {} 3972 } 3973 } 3974 set2->nodeNr = 0; 3975 return(set1); 3976 } 3977 3978 /** 3979 * xmlXPathNodeSetMergeAndClearNoDupls: 3980 * @set1: the first NodeSet or NULL 3981 * @set2: the second NodeSet 3982 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes 3983 * 3984 * Merges two nodesets, all nodes from @set2 are added to @set1 3985 * if @set1 is NULL, a new set is created and copied from @set2. 3986 * Doesn't chack for duplicate nodes. Clears set2. 3987 * 3988 * Returns @set1 once extended or NULL in case of error. 3989 */ 3990 static xmlNodeSetPtr 3991 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2, 3992 int hasNullEntries) 3993 { 3994 if (set2 == NULL) 3995 return(set1); 3996 if ((set1 == NULL) && (hasNullEntries == 0)) { 3997 /* 3998 * Note that doing a memcpy of the list, namespace nodes are 3999 * just assigned to set1, since set2 is cleared anyway. 4000 */ 4001 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr); 4002 if (set1 == NULL) 4003 return(NULL); 4004 if (set2->nodeNr != 0) { 4005 memcpy(set1->nodeTab, set2->nodeTab, 4006 set2->nodeNr * sizeof(xmlNodePtr)); 4007 set1->nodeNr = set2->nodeNr; 4008 } 4009 } else { 4010 int i; 4011 xmlNodePtr n2; 4012 4013 if (set1 == NULL) 4014 set1 = xmlXPathNodeSetCreate(NULL); 4015 if (set1 == NULL) 4016 return (NULL); 4017 4018 for (i = 0;i < set2->nodeNr;i++) { 4019 n2 = set2->nodeTab[i]; 4020 /* 4021 * Skip NULLed entries. 4022 */ 4023 if (n2 == NULL) 4024 continue; 4025 if (set1->nodeMax == 0) { 4026 set1->nodeTab = (xmlNodePtr *) xmlMalloc( 4027 XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); 4028 if (set1->nodeTab == NULL) { 4029 xmlXPathErrMemory(NULL, "merging nodeset\n"); 4030 return(NULL); 4031 } 4032 memset(set1->nodeTab, 0, 4033 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 4034 set1->nodeMax = XML_NODESET_DEFAULT; 4035 } else if (set1->nodeNr >= set1->nodeMax) { 4036 xmlNodePtr *temp; 4037 4038 temp = (xmlNodePtr *) xmlRealloc( 4039 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr)); 4040 if (temp == NULL) { 4041 xmlXPathErrMemory(NULL, "merging nodeset\n"); 4042 return(NULL); 4043 } 4044 set1->nodeTab = temp; 4045 set1->nodeMax *= 2; 4046 } 4047 set1->nodeTab[set1->nodeNr++] = n2; 4048 } 4049 } 4050 set2->nodeNr = 0; 4051 return(set1); 4052 } 4053 4054 /** 4055 * xmlXPathNodeSetDel: 4056 * @cur: the initial node set 4057 * @val: an xmlNodePtr 4058 * 4059 * Removes an xmlNodePtr from an existing NodeSet 4060 */ 4061 void 4062 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) { 4063 int i; 4064 4065 if (cur == NULL) return; 4066 if (val == NULL) return; 4067 4068 /* 4069 * find node in nodeTab 4070 */ 4071 for (i = 0;i < cur->nodeNr;i++) 4072 if (cur->nodeTab[i] == val) break; 4073 4074 if (i >= cur->nodeNr) { /* not found */ 4075 #ifdef DEBUG 4076 xmlGenericError(xmlGenericErrorContext, 4077 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n", 4078 val->name); 4079 #endif 4080 return; 4081 } 4082 if ((cur->nodeTab[i] != NULL) && 4083 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL)) 4084 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]); 4085 cur->nodeNr--; 4086 for (;i < cur->nodeNr;i++) 4087 cur->nodeTab[i] = cur->nodeTab[i + 1]; 4088 cur->nodeTab[cur->nodeNr] = NULL; 4089 } 4090 4091 /** 4092 * xmlXPathNodeSetRemove: 4093 * @cur: the initial node set 4094 * @val: the index to remove 4095 * 4096 * Removes an entry from an existing NodeSet list. 4097 */ 4098 void 4099 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) { 4100 if (cur == NULL) return; 4101 if (val >= cur->nodeNr) return; 4102 if ((cur->nodeTab[val] != NULL) && 4103 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL)) 4104 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]); 4105 cur->nodeNr--; 4106 for (;val < cur->nodeNr;val++) 4107 cur->nodeTab[val] = cur->nodeTab[val + 1]; 4108 cur->nodeTab[cur->nodeNr] = NULL; 4109 } 4110 4111 /** 4112 * xmlXPathFreeNodeSet: 4113 * @obj: the xmlNodeSetPtr to free 4114 * 4115 * Free the NodeSet compound (not the actual nodes !). 4116 */ 4117 void 4118 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) { 4119 if (obj == NULL) return; 4120 if (obj->nodeTab != NULL) { 4121 int i; 4122 4123 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 4124 for (i = 0;i < obj->nodeNr;i++) 4125 if ((obj->nodeTab[i] != NULL) && 4126 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL)) 4127 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]); 4128 xmlFree(obj->nodeTab); 4129 } 4130 xmlFree(obj); 4131 } 4132 4133 /** 4134 * xmlXPathNodeSetClear: 4135 * @set: the node set to clear 4136 * 4137 * Clears the list from all temporary XPath objects (e.g. namespace nodes 4138 * are feed), but does *not* free the list itself. Sets the length of the 4139 * list to 0. 4140 */ 4141 static void 4142 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes) 4143 { 4144 if ((set == NULL) || (set->nodeNr <= 0)) 4145 return; 4146 else if (hasNsNodes) { 4147 int i; 4148 xmlNodePtr node; 4149 4150 for (i = 0; i < set->nodeNr; i++) { 4151 node = set->nodeTab[i]; 4152 if ((node != NULL) && 4153 (node->type == XML_NAMESPACE_DECL)) 4154 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 4155 } 4156 } 4157 set->nodeNr = 0; 4158 } 4159 4160 /** 4161 * xmlXPathNodeSetClearFromPos: 4162 * @set: the node set to be cleared 4163 * @pos: the start position to clear from 4164 * 4165 * Clears the list from temporary XPath objects (e.g. namespace nodes 4166 * are feed) starting with the entry at @pos, but does *not* free the list 4167 * itself. Sets the length of the list to @pos. 4168 */ 4169 static void 4170 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes) 4171 { 4172 if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr)) 4173 return; 4174 else if ((hasNsNodes)) { 4175 int i; 4176 xmlNodePtr node; 4177 4178 for (i = pos; i < set->nodeNr; i++) { 4179 node = set->nodeTab[i]; 4180 if ((node != NULL) && 4181 (node->type == XML_NAMESPACE_DECL)) 4182 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 4183 } 4184 } 4185 set->nodeNr = pos; 4186 } 4187 4188 /** 4189 * xmlXPathFreeValueTree: 4190 * @obj: the xmlNodeSetPtr to free 4191 * 4192 * Free the NodeSet compound and the actual tree, this is different 4193 * from xmlXPathFreeNodeSet() 4194 */ 4195 static void 4196 xmlXPathFreeValueTree(xmlNodeSetPtr obj) { 4197 int i; 4198 4199 if (obj == NULL) return; 4200 4201 if (obj->nodeTab != NULL) { 4202 for (i = 0;i < obj->nodeNr;i++) { 4203 if (obj->nodeTab[i] != NULL) { 4204 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) { 4205 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]); 4206 } else { 4207 xmlFreeNodeList(obj->nodeTab[i]); 4208 } 4209 } 4210 } 4211 xmlFree(obj->nodeTab); 4212 } 4213 xmlFree(obj); 4214 } 4215 4216 #if defined(DEBUG) || defined(DEBUG_STEP) 4217 /** 4218 * xmlGenericErrorContextNodeSet: 4219 * @output: a FILE * for the output 4220 * @obj: the xmlNodeSetPtr to display 4221 * 4222 * Quick display of a NodeSet 4223 */ 4224 void 4225 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) { 4226 int i; 4227 4228 if (output == NULL) output = xmlGenericErrorContext; 4229 if (obj == NULL) { 4230 fprintf(output, "NodeSet == NULL !\n"); 4231 return; 4232 } 4233 if (obj->nodeNr == 0) { 4234 fprintf(output, "NodeSet is empty\n"); 4235 return; 4236 } 4237 if (obj->nodeTab == NULL) { 4238 fprintf(output, " nodeTab == NULL !\n"); 4239 return; 4240 } 4241 for (i = 0; i < obj->nodeNr; i++) { 4242 if (obj->nodeTab[i] == NULL) { 4243 fprintf(output, " NULL !\n"); 4244 return; 4245 } 4246 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) || 4247 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE)) 4248 fprintf(output, " /"); 4249 else if (obj->nodeTab[i]->name == NULL) 4250 fprintf(output, " noname!"); 4251 else fprintf(output, " %s", obj->nodeTab[i]->name); 4252 } 4253 fprintf(output, "\n"); 4254 } 4255 #endif 4256 4257 /** 4258 * xmlXPathNewNodeSet: 4259 * @val: the NodePtr value 4260 * 4261 * Create a new xmlXPathObjectPtr of type NodeSet and initialize 4262 * it with the single Node @val 4263 * 4264 * Returns the newly created object. 4265 */ 4266 xmlXPathObjectPtr 4267 xmlXPathNewNodeSet(xmlNodePtr val) { 4268 xmlXPathObjectPtr ret; 4269 4270 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4271 if (ret == NULL) { 4272 xmlXPathErrMemory(NULL, "creating nodeset\n"); 4273 return(NULL); 4274 } 4275 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4276 ret->type = XPATH_NODESET; 4277 ret->boolval = 0; 4278 ret->nodesetval = xmlXPathNodeSetCreate(val); 4279 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 4280 #ifdef XP_DEBUG_OBJ_USAGE 4281 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET); 4282 #endif 4283 return(ret); 4284 } 4285 4286 /** 4287 * xmlXPathNewValueTree: 4288 * @val: the NodePtr value 4289 * 4290 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize 4291 * it with the tree root @val 4292 * 4293 * Returns the newly created object. 4294 */ 4295 xmlXPathObjectPtr 4296 xmlXPathNewValueTree(xmlNodePtr val) { 4297 xmlXPathObjectPtr ret; 4298 4299 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4300 if (ret == NULL) { 4301 xmlXPathErrMemory(NULL, "creating result value tree\n"); 4302 return(NULL); 4303 } 4304 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4305 ret->type = XPATH_XSLT_TREE; 4306 ret->boolval = 1; 4307 ret->user = (void *) val; 4308 ret->nodesetval = xmlXPathNodeSetCreate(val); 4309 #ifdef XP_DEBUG_OBJ_USAGE 4310 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE); 4311 #endif 4312 return(ret); 4313 } 4314 4315 /** 4316 * xmlXPathNewNodeSetList: 4317 * @val: an existing NodeSet 4318 * 4319 * Create a new xmlXPathObjectPtr of type NodeSet and initialize 4320 * it with the Nodeset @val 4321 * 4322 * Returns the newly created object. 4323 */ 4324 xmlXPathObjectPtr 4325 xmlXPathNewNodeSetList(xmlNodeSetPtr val) 4326 { 4327 xmlXPathObjectPtr ret; 4328 int i; 4329 4330 if (val == NULL) 4331 ret = NULL; 4332 else if (val->nodeTab == NULL) 4333 ret = xmlXPathNewNodeSet(NULL); 4334 else { 4335 ret = xmlXPathNewNodeSet(val->nodeTab[0]); 4336 if (ret) 4337 for (i = 1; i < val->nodeNr; ++i) 4338 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]); 4339 } 4340 4341 return (ret); 4342 } 4343 4344 /** 4345 * xmlXPathWrapNodeSet: 4346 * @val: the NodePtr value 4347 * 4348 * Wrap the Nodeset @val in a new xmlXPathObjectPtr 4349 * 4350 * Returns the newly created object. 4351 */ 4352 xmlXPathObjectPtr 4353 xmlXPathWrapNodeSet(xmlNodeSetPtr val) { 4354 xmlXPathObjectPtr ret; 4355 4356 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4357 if (ret == NULL) { 4358 xmlXPathErrMemory(NULL, "creating node set object\n"); 4359 return(NULL); 4360 } 4361 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4362 ret->type = XPATH_NODESET; 4363 ret->nodesetval = val; 4364 #ifdef XP_DEBUG_OBJ_USAGE 4365 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET); 4366 #endif 4367 return(ret); 4368 } 4369 4370 /** 4371 * xmlXPathFreeNodeSetList: 4372 * @obj: an existing NodeSetList object 4373 * 4374 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in 4375 * the list contrary to xmlXPathFreeObject(). 4376 */ 4377 void 4378 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) { 4379 if (obj == NULL) return; 4380 #ifdef XP_DEBUG_OBJ_USAGE 4381 xmlXPathDebugObjUsageReleased(NULL, obj->type); 4382 #endif 4383 xmlFree(obj); 4384 } 4385 4386 /** 4387 * xmlXPathDifference: 4388 * @nodes1: a node-set 4389 * @nodes2: a node-set 4390 * 4391 * Implements the EXSLT - Sets difference() function: 4392 * node-set set:difference (node-set, node-set) 4393 * 4394 * Returns the difference between the two node sets, or nodes1 if 4395 * nodes2 is empty 4396 */ 4397 xmlNodeSetPtr 4398 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4399 xmlNodeSetPtr ret; 4400 int i, l1; 4401 xmlNodePtr cur; 4402 4403 if (xmlXPathNodeSetIsEmpty(nodes2)) 4404 return(nodes1); 4405 4406 ret = xmlXPathNodeSetCreate(NULL); 4407 if (xmlXPathNodeSetIsEmpty(nodes1)) 4408 return(ret); 4409 4410 l1 = xmlXPathNodeSetGetLength(nodes1); 4411 4412 for (i = 0; i < l1; i++) { 4413 cur = xmlXPathNodeSetItem(nodes1, i); 4414 if (!xmlXPathNodeSetContains(nodes2, cur)) 4415 xmlXPathNodeSetAddUnique(ret, cur); 4416 } 4417 return(ret); 4418 } 4419 4420 /** 4421 * xmlXPathIntersection: 4422 * @nodes1: a node-set 4423 * @nodes2: a node-set 4424 * 4425 * Implements the EXSLT - Sets intersection() function: 4426 * node-set set:intersection (node-set, node-set) 4427 * 4428 * Returns a node set comprising the nodes that are within both the 4429 * node sets passed as arguments 4430 */ 4431 xmlNodeSetPtr 4432 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4433 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL); 4434 int i, l1; 4435 xmlNodePtr cur; 4436 4437 if (ret == NULL) 4438 return(ret); 4439 if (xmlXPathNodeSetIsEmpty(nodes1)) 4440 return(ret); 4441 if (xmlXPathNodeSetIsEmpty(nodes2)) 4442 return(ret); 4443 4444 l1 = xmlXPathNodeSetGetLength(nodes1); 4445 4446 for (i = 0; i < l1; i++) { 4447 cur = xmlXPathNodeSetItem(nodes1, i); 4448 if (xmlXPathNodeSetContains(nodes2, cur)) 4449 xmlXPathNodeSetAddUnique(ret, cur); 4450 } 4451 return(ret); 4452 } 4453 4454 /** 4455 * xmlXPathDistinctSorted: 4456 * @nodes: a node-set, sorted by document order 4457 * 4458 * Implements the EXSLT - Sets distinct() function: 4459 * node-set set:distinct (node-set) 4460 * 4461 * Returns a subset of the nodes contained in @nodes, or @nodes if 4462 * it is empty 4463 */ 4464 xmlNodeSetPtr 4465 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) { 4466 xmlNodeSetPtr ret; 4467 xmlHashTablePtr hash; 4468 int i, l; 4469 xmlChar * strval; 4470 xmlNodePtr cur; 4471 4472 if (xmlXPathNodeSetIsEmpty(nodes)) 4473 return(nodes); 4474 4475 ret = xmlXPathNodeSetCreate(NULL); 4476 if (ret == NULL) 4477 return(ret); 4478 l = xmlXPathNodeSetGetLength(nodes); 4479 hash = xmlHashCreate (l); 4480 for (i = 0; i < l; i++) { 4481 cur = xmlXPathNodeSetItem(nodes, i); 4482 strval = xmlXPathCastNodeToString(cur); 4483 if (xmlHashLookup(hash, strval) == NULL) { 4484 xmlHashAddEntry(hash, strval, strval); 4485 xmlXPathNodeSetAddUnique(ret, cur); 4486 } else { 4487 xmlFree(strval); 4488 } 4489 } 4490 xmlHashFree(hash, (xmlHashDeallocator) xmlFree); 4491 return(ret); 4492 } 4493 4494 /** 4495 * xmlXPathDistinct: 4496 * @nodes: a node-set 4497 * 4498 * Implements the EXSLT - Sets distinct() function: 4499 * node-set set:distinct (node-set) 4500 * @nodes is sorted by document order, then #exslSetsDistinctSorted 4501 * is called with the sorted node-set 4502 * 4503 * Returns a subset of the nodes contained in @nodes, or @nodes if 4504 * it is empty 4505 */ 4506 xmlNodeSetPtr 4507 xmlXPathDistinct (xmlNodeSetPtr nodes) { 4508 if (xmlXPathNodeSetIsEmpty(nodes)) 4509 return(nodes); 4510 4511 xmlXPathNodeSetSort(nodes); 4512 return(xmlXPathDistinctSorted(nodes)); 4513 } 4514 4515 /** 4516 * xmlXPathHasSameNodes: 4517 * @nodes1: a node-set 4518 * @nodes2: a node-set 4519 * 4520 * Implements the EXSLT - Sets has-same-nodes function: 4521 * boolean set:has-same-node(node-set, node-set) 4522 * 4523 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0) 4524 * otherwise 4525 */ 4526 int 4527 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4528 int i, l; 4529 xmlNodePtr cur; 4530 4531 if (xmlXPathNodeSetIsEmpty(nodes1) || 4532 xmlXPathNodeSetIsEmpty(nodes2)) 4533 return(0); 4534 4535 l = xmlXPathNodeSetGetLength(nodes1); 4536 for (i = 0; i < l; i++) { 4537 cur = xmlXPathNodeSetItem(nodes1, i); 4538 if (xmlXPathNodeSetContains(nodes2, cur)) 4539 return(1); 4540 } 4541 return(0); 4542 } 4543 4544 /** 4545 * xmlXPathNodeLeadingSorted: 4546 * @nodes: a node-set, sorted by document order 4547 * @node: a node 4548 * 4549 * Implements the EXSLT - Sets leading() function: 4550 * node-set set:leading (node-set, node-set) 4551 * 4552 * Returns the nodes in @nodes that precede @node in document order, 4553 * @nodes if @node is NULL or an empty node-set if @nodes 4554 * doesn't contain @node 4555 */ 4556 xmlNodeSetPtr 4557 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { 4558 int i, l; 4559 xmlNodePtr cur; 4560 xmlNodeSetPtr ret; 4561 4562 if (node == NULL) 4563 return(nodes); 4564 4565 ret = xmlXPathNodeSetCreate(NULL); 4566 if (ret == NULL) 4567 return(ret); 4568 if (xmlXPathNodeSetIsEmpty(nodes) || 4569 (!xmlXPathNodeSetContains(nodes, node))) 4570 return(ret); 4571 4572 l = xmlXPathNodeSetGetLength(nodes); 4573 for (i = 0; i < l; i++) { 4574 cur = xmlXPathNodeSetItem(nodes, i); 4575 if (cur == node) 4576 break; 4577 xmlXPathNodeSetAddUnique(ret, cur); 4578 } 4579 return(ret); 4580 } 4581 4582 /** 4583 * xmlXPathNodeLeading: 4584 * @nodes: a node-set 4585 * @node: a node 4586 * 4587 * Implements the EXSLT - Sets leading() function: 4588 * node-set set:leading (node-set, node-set) 4589 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted 4590 * is called. 4591 * 4592 * Returns the nodes in @nodes that precede @node in document order, 4593 * @nodes if @node is NULL or an empty node-set if @nodes 4594 * doesn't contain @node 4595 */ 4596 xmlNodeSetPtr 4597 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) { 4598 xmlXPathNodeSetSort(nodes); 4599 return(xmlXPathNodeLeadingSorted(nodes, node)); 4600 } 4601 4602 /** 4603 * xmlXPathLeadingSorted: 4604 * @nodes1: a node-set, sorted by document order 4605 * @nodes2: a node-set, sorted by document order 4606 * 4607 * Implements the EXSLT - Sets leading() function: 4608 * node-set set:leading (node-set, node-set) 4609 * 4610 * Returns the nodes in @nodes1 that precede the first node in @nodes2 4611 * in document order, @nodes1 if @nodes2 is NULL or empty or 4612 * an empty node-set if @nodes1 doesn't contain @nodes2 4613 */ 4614 xmlNodeSetPtr 4615 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4616 if (xmlXPathNodeSetIsEmpty(nodes2)) 4617 return(nodes1); 4618 return(xmlXPathNodeLeadingSorted(nodes1, 4619 xmlXPathNodeSetItem(nodes2, 1))); 4620 } 4621 4622 /** 4623 * xmlXPathLeading: 4624 * @nodes1: a node-set 4625 * @nodes2: a node-set 4626 * 4627 * Implements the EXSLT - Sets leading() function: 4628 * node-set set:leading (node-set, node-set) 4629 * @nodes1 and @nodes2 are sorted by document order, then 4630 * #exslSetsLeadingSorted is called. 4631 * 4632 * Returns the nodes in @nodes1 that precede the first node in @nodes2 4633 * in document order, @nodes1 if @nodes2 is NULL or empty or 4634 * an empty node-set if @nodes1 doesn't contain @nodes2 4635 */ 4636 xmlNodeSetPtr 4637 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4638 if (xmlXPathNodeSetIsEmpty(nodes2)) 4639 return(nodes1); 4640 if (xmlXPathNodeSetIsEmpty(nodes1)) 4641 return(xmlXPathNodeSetCreate(NULL)); 4642 xmlXPathNodeSetSort(nodes1); 4643 xmlXPathNodeSetSort(nodes2); 4644 return(xmlXPathNodeLeadingSorted(nodes1, 4645 xmlXPathNodeSetItem(nodes2, 1))); 4646 } 4647 4648 /** 4649 * xmlXPathNodeTrailingSorted: 4650 * @nodes: a node-set, sorted by document order 4651 * @node: a node 4652 * 4653 * Implements the EXSLT - Sets trailing() function: 4654 * node-set set:trailing (node-set, node-set) 4655 * 4656 * Returns the nodes in @nodes that follow @node in document order, 4657 * @nodes if @node is NULL or an empty node-set if @nodes 4658 * doesn't contain @node 4659 */ 4660 xmlNodeSetPtr 4661 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { 4662 int i, l; 4663 xmlNodePtr cur; 4664 xmlNodeSetPtr ret; 4665 4666 if (node == NULL) 4667 return(nodes); 4668 4669 ret = xmlXPathNodeSetCreate(NULL); 4670 if (ret == NULL) 4671 return(ret); 4672 if (xmlXPathNodeSetIsEmpty(nodes) || 4673 (!xmlXPathNodeSetContains(nodes, node))) 4674 return(ret); 4675 4676 l = xmlXPathNodeSetGetLength(nodes); 4677 for (i = l - 1; i >= 0; i--) { 4678 cur = xmlXPathNodeSetItem(nodes, i); 4679 if (cur == node) 4680 break; 4681 xmlXPathNodeSetAddUnique(ret, cur); 4682 } 4683 xmlXPathNodeSetSort(ret); /* bug 413451 */ 4684 return(ret); 4685 } 4686 4687 /** 4688 * xmlXPathNodeTrailing: 4689 * @nodes: a node-set 4690 * @node: a node 4691 * 4692 * Implements the EXSLT - Sets trailing() function: 4693 * node-set set:trailing (node-set, node-set) 4694 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted 4695 * is called. 4696 * 4697 * Returns the nodes in @nodes that follow @node in document order, 4698 * @nodes if @node is NULL or an empty node-set if @nodes 4699 * doesn't contain @node 4700 */ 4701 xmlNodeSetPtr 4702 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) { 4703 xmlXPathNodeSetSort(nodes); 4704 return(xmlXPathNodeTrailingSorted(nodes, node)); 4705 } 4706 4707 /** 4708 * xmlXPathTrailingSorted: 4709 * @nodes1: a node-set, sorted by document order 4710 * @nodes2: a node-set, sorted by document order 4711 * 4712 * Implements the EXSLT - Sets trailing() function: 4713 * node-set set:trailing (node-set, node-set) 4714 * 4715 * Returns the nodes in @nodes1 that follow the first node in @nodes2 4716 * in document order, @nodes1 if @nodes2 is NULL or empty or 4717 * an empty node-set if @nodes1 doesn't contain @nodes2 4718 */ 4719 xmlNodeSetPtr 4720 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4721 if (xmlXPathNodeSetIsEmpty(nodes2)) 4722 return(nodes1); 4723 return(xmlXPathNodeTrailingSorted(nodes1, 4724 xmlXPathNodeSetItem(nodes2, 0))); 4725 } 4726 4727 /** 4728 * xmlXPathTrailing: 4729 * @nodes1: a node-set 4730 * @nodes2: a node-set 4731 * 4732 * Implements the EXSLT - Sets trailing() function: 4733 * node-set set:trailing (node-set, node-set) 4734 * @nodes1 and @nodes2 are sorted by document order, then 4735 * #xmlXPathTrailingSorted is called. 4736 * 4737 * Returns the nodes in @nodes1 that follow the first node in @nodes2 4738 * in document order, @nodes1 if @nodes2 is NULL or empty or 4739 * an empty node-set if @nodes1 doesn't contain @nodes2 4740 */ 4741 xmlNodeSetPtr 4742 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4743 if (xmlXPathNodeSetIsEmpty(nodes2)) 4744 return(nodes1); 4745 if (xmlXPathNodeSetIsEmpty(nodes1)) 4746 return(xmlXPathNodeSetCreate(NULL)); 4747 xmlXPathNodeSetSort(nodes1); 4748 xmlXPathNodeSetSort(nodes2); 4749 return(xmlXPathNodeTrailingSorted(nodes1, 4750 xmlXPathNodeSetItem(nodes2, 0))); 4751 } 4752 4753 /************************************************************************ 4754 * * 4755 * Routines to handle extra functions * 4756 * * 4757 ************************************************************************/ 4758 4759 /** 4760 * xmlXPathRegisterFunc: 4761 * @ctxt: the XPath context 4762 * @name: the function name 4763 * @f: the function implementation or NULL 4764 * 4765 * Register a new function. If @f is NULL it unregisters the function 4766 * 4767 * Returns 0 in case of success, -1 in case of error 4768 */ 4769 int 4770 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name, 4771 xmlXPathFunction f) { 4772 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f)); 4773 } 4774 4775 /** 4776 * xmlXPathRegisterFuncNS: 4777 * @ctxt: the XPath context 4778 * @name: the function name 4779 * @ns_uri: the function namespace URI 4780 * @f: the function implementation or NULL 4781 * 4782 * Register a new function. If @f is NULL it unregisters the function 4783 * 4784 * Returns 0 in case of success, -1 in case of error 4785 */ 4786 int 4787 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name, 4788 const xmlChar *ns_uri, xmlXPathFunction f) { 4789 if (ctxt == NULL) 4790 return(-1); 4791 if (name == NULL) 4792 return(-1); 4793 4794 if (ctxt->funcHash == NULL) 4795 ctxt->funcHash = xmlHashCreate(0); 4796 if (ctxt->funcHash == NULL) 4797 return(-1); 4798 if (f == NULL) 4799 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL)); 4800 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f))); 4801 } 4802 4803 /** 4804 * xmlXPathRegisterFuncLookup: 4805 * @ctxt: the XPath context 4806 * @f: the lookup function 4807 * @funcCtxt: the lookup data 4808 * 4809 * Registers an external mechanism to do function lookup. 4810 */ 4811 void 4812 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt, 4813 xmlXPathFuncLookupFunc f, 4814 void *funcCtxt) { 4815 if (ctxt == NULL) 4816 return; 4817 ctxt->funcLookupFunc = f; 4818 ctxt->funcLookupData = funcCtxt; 4819 } 4820 4821 /** 4822 * xmlXPathFunctionLookup: 4823 * @ctxt: the XPath context 4824 * @name: the function name 4825 * 4826 * Search in the Function array of the context for the given 4827 * function. 4828 * 4829 * Returns the xmlXPathFunction or NULL if not found 4830 */ 4831 xmlXPathFunction 4832 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { 4833 if (ctxt == NULL) 4834 return (NULL); 4835 4836 if (ctxt->funcLookupFunc != NULL) { 4837 xmlXPathFunction ret; 4838 xmlXPathFuncLookupFunc f; 4839 4840 f = ctxt->funcLookupFunc; 4841 ret = f(ctxt->funcLookupData, name, NULL); 4842 if (ret != NULL) 4843 return(ret); 4844 } 4845 return(xmlXPathFunctionLookupNS(ctxt, name, NULL)); 4846 } 4847 4848 /** 4849 * xmlXPathFunctionLookupNS: 4850 * @ctxt: the XPath context 4851 * @name: the function name 4852 * @ns_uri: the function namespace URI 4853 * 4854 * Search in the Function array of the context for the given 4855 * function. 4856 * 4857 * Returns the xmlXPathFunction or NULL if not found 4858 */ 4859 xmlXPathFunction 4860 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name, 4861 const xmlChar *ns_uri) { 4862 xmlXPathFunction ret; 4863 4864 if (ctxt == NULL) 4865 return(NULL); 4866 if (name == NULL) 4867 return(NULL); 4868 4869 if (ctxt->funcLookupFunc != NULL) { 4870 xmlXPathFuncLookupFunc f; 4871 4872 f = ctxt->funcLookupFunc; 4873 ret = f(ctxt->funcLookupData, name, ns_uri); 4874 if (ret != NULL) 4875 return(ret); 4876 } 4877 4878 if (ctxt->funcHash == NULL) 4879 return(NULL); 4880 4881 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri); 4882 return(ret); 4883 } 4884 4885 /** 4886 * xmlXPathRegisteredFuncsCleanup: 4887 * @ctxt: the XPath context 4888 * 4889 * Cleanup the XPath context data associated to registered functions 4890 */ 4891 void 4892 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) { 4893 if (ctxt == NULL) 4894 return; 4895 4896 xmlHashFree(ctxt->funcHash, NULL); 4897 ctxt->funcHash = NULL; 4898 } 4899 4900 /************************************************************************ 4901 * * 4902 * Routines to handle Variables * 4903 * * 4904 ************************************************************************/ 4905 4906 /** 4907 * xmlXPathRegisterVariable: 4908 * @ctxt: the XPath context 4909 * @name: the variable name 4910 * @value: the variable value or NULL 4911 * 4912 * Register a new variable value. If @value is NULL it unregisters 4913 * the variable 4914 * 4915 * Returns 0 in case of success, -1 in case of error 4916 */ 4917 int 4918 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name, 4919 xmlXPathObjectPtr value) { 4920 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value)); 4921 } 4922 4923 /** 4924 * xmlXPathRegisterVariableNS: 4925 * @ctxt: the XPath context 4926 * @name: the variable name 4927 * @ns_uri: the variable namespace URI 4928 * @value: the variable value or NULL 4929 * 4930 * Register a new variable value. If @value is NULL it unregisters 4931 * the variable 4932 * 4933 * Returns 0 in case of success, -1 in case of error 4934 */ 4935 int 4936 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name, 4937 const xmlChar *ns_uri, 4938 xmlXPathObjectPtr value) { 4939 if (ctxt == NULL) 4940 return(-1); 4941 if (name == NULL) 4942 return(-1); 4943 4944 if (ctxt->varHash == NULL) 4945 ctxt->varHash = xmlHashCreate(0); 4946 if (ctxt->varHash == NULL) 4947 return(-1); 4948 if (value == NULL) 4949 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri, 4950 (xmlHashDeallocator)xmlXPathFreeObject)); 4951 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri, 4952 (void *) value, 4953 (xmlHashDeallocator)xmlXPathFreeObject)); 4954 } 4955 4956 /** 4957 * xmlXPathRegisterVariableLookup: 4958 * @ctxt: the XPath context 4959 * @f: the lookup function 4960 * @data: the lookup data 4961 * 4962 * register an external mechanism to do variable lookup 4963 */ 4964 void 4965 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt, 4966 xmlXPathVariableLookupFunc f, void *data) { 4967 if (ctxt == NULL) 4968 return; 4969 ctxt->varLookupFunc = f; 4970 ctxt->varLookupData = data; 4971 } 4972 4973 /** 4974 * xmlXPathVariableLookup: 4975 * @ctxt: the XPath context 4976 * @name: the variable name 4977 * 4978 * Search in the Variable array of the context for the given 4979 * variable value. 4980 * 4981 * Returns a copy of the value or NULL if not found 4982 */ 4983 xmlXPathObjectPtr 4984 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { 4985 if (ctxt == NULL) 4986 return(NULL); 4987 4988 if (ctxt->varLookupFunc != NULL) { 4989 xmlXPathObjectPtr ret; 4990 4991 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc) 4992 (ctxt->varLookupData, name, NULL); 4993 return(ret); 4994 } 4995 return(xmlXPathVariableLookupNS(ctxt, name, NULL)); 4996 } 4997 4998 /** 4999 * xmlXPathVariableLookupNS: 5000 * @ctxt: the XPath context 5001 * @name: the variable name 5002 * @ns_uri: the variable namespace URI 5003 * 5004 * Search in the Variable array of the context for the given 5005 * variable value. 5006 * 5007 * Returns the a copy of the value or NULL if not found 5008 */ 5009 xmlXPathObjectPtr 5010 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name, 5011 const xmlChar *ns_uri) { 5012 if (ctxt == NULL) 5013 return(NULL); 5014 5015 if (ctxt->varLookupFunc != NULL) { 5016 xmlXPathObjectPtr ret; 5017 5018 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc) 5019 (ctxt->varLookupData, name, ns_uri); 5020 if (ret != NULL) return(ret); 5021 } 5022 5023 if (ctxt->varHash == NULL) 5024 return(NULL); 5025 if (name == NULL) 5026 return(NULL); 5027 5028 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr) 5029 xmlHashLookup2(ctxt->varHash, name, ns_uri))); 5030 } 5031 5032 /** 5033 * xmlXPathRegisteredVariablesCleanup: 5034 * @ctxt: the XPath context 5035 * 5036 * Cleanup the XPath context data associated to registered variables 5037 */ 5038 void 5039 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) { 5040 if (ctxt == NULL) 5041 return; 5042 5043 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject); 5044 ctxt->varHash = NULL; 5045 } 5046 5047 /** 5048 * xmlXPathRegisterNs: 5049 * @ctxt: the XPath context 5050 * @prefix: the namespace prefix cannot be NULL or empty string 5051 * @ns_uri: the namespace name 5052 * 5053 * Register a new namespace. If @ns_uri is NULL it unregisters 5054 * the namespace 5055 * 5056 * Returns 0 in case of success, -1 in case of error 5057 */ 5058 int 5059 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix, 5060 const xmlChar *ns_uri) { 5061 if (ctxt == NULL) 5062 return(-1); 5063 if (prefix == NULL) 5064 return(-1); 5065 if (prefix[0] == 0) 5066 return(-1); 5067 5068 if (ctxt->nsHash == NULL) 5069 ctxt->nsHash = xmlHashCreate(10); 5070 if (ctxt->nsHash == NULL) 5071 return(-1); 5072 if (ns_uri == NULL) 5073 return(xmlHashRemoveEntry(ctxt->nsHash, prefix, 5074 (xmlHashDeallocator)xmlFree)); 5075 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri), 5076 (xmlHashDeallocator)xmlFree)); 5077 } 5078 5079 /** 5080 * xmlXPathNsLookup: 5081 * @ctxt: the XPath context 5082 * @prefix: the namespace prefix value 5083 * 5084 * Search in the namespace declaration array of the context for the given 5085 * namespace name associated to the given prefix 5086 * 5087 * Returns the value or NULL if not found 5088 */ 5089 const xmlChar * 5090 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) { 5091 if (ctxt == NULL) 5092 return(NULL); 5093 if (prefix == NULL) 5094 return(NULL); 5095 5096 #ifdef XML_XML_NAMESPACE 5097 if (xmlStrEqual(prefix, (const xmlChar *) "xml")) 5098 return(XML_XML_NAMESPACE); 5099 #endif 5100 5101 if (ctxt->namespaces != NULL) { 5102 int i; 5103 5104 for (i = 0;i < ctxt->nsNr;i++) { 5105 if ((ctxt->namespaces[i] != NULL) && 5106 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix))) 5107 return(ctxt->namespaces[i]->href); 5108 } 5109 } 5110 5111 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix)); 5112 } 5113 5114 /** 5115 * xmlXPathRegisteredNsCleanup: 5116 * @ctxt: the XPath context 5117 * 5118 * Cleanup the XPath context data associated to registered variables 5119 */ 5120 void 5121 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) { 5122 if (ctxt == NULL) 5123 return; 5124 5125 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree); 5126 ctxt->nsHash = NULL; 5127 } 5128 5129 /************************************************************************ 5130 * * 5131 * Routines to handle Values * 5132 * * 5133 ************************************************************************/ 5134 5135 /* Allocations are terrible, one needs to optimize all this !!! */ 5136 5137 /** 5138 * xmlXPathNewFloat: 5139 * @val: the double value 5140 * 5141 * Create a new xmlXPathObjectPtr of type double and of value @val 5142 * 5143 * Returns the newly created object. 5144 */ 5145 xmlXPathObjectPtr 5146 xmlXPathNewFloat(double val) { 5147 xmlXPathObjectPtr ret; 5148 5149 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5150 if (ret == NULL) { 5151 xmlXPathErrMemory(NULL, "creating float object\n"); 5152 return(NULL); 5153 } 5154 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5155 ret->type = XPATH_NUMBER; 5156 ret->floatval = val; 5157 #ifdef XP_DEBUG_OBJ_USAGE 5158 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER); 5159 #endif 5160 return(ret); 5161 } 5162 5163 /** 5164 * xmlXPathNewBoolean: 5165 * @val: the boolean value 5166 * 5167 * Create a new xmlXPathObjectPtr of type boolean and of value @val 5168 * 5169 * Returns the newly created object. 5170 */ 5171 xmlXPathObjectPtr 5172 xmlXPathNewBoolean(int val) { 5173 xmlXPathObjectPtr ret; 5174 5175 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5176 if (ret == NULL) { 5177 xmlXPathErrMemory(NULL, "creating boolean object\n"); 5178 return(NULL); 5179 } 5180 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5181 ret->type = XPATH_BOOLEAN; 5182 ret->boolval = (val != 0); 5183 #ifdef XP_DEBUG_OBJ_USAGE 5184 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN); 5185 #endif 5186 return(ret); 5187 } 5188 5189 /** 5190 * xmlXPathNewString: 5191 * @val: the xmlChar * value 5192 * 5193 * Create a new xmlXPathObjectPtr of type string and of value @val 5194 * 5195 * Returns the newly created object. 5196 */ 5197 xmlXPathObjectPtr 5198 xmlXPathNewString(const xmlChar *val) { 5199 xmlXPathObjectPtr ret; 5200 5201 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5202 if (ret == NULL) { 5203 xmlXPathErrMemory(NULL, "creating string object\n"); 5204 return(NULL); 5205 } 5206 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5207 ret->type = XPATH_STRING; 5208 if (val != NULL) 5209 ret->stringval = xmlStrdup(val); 5210 else 5211 ret->stringval = xmlStrdup((const xmlChar *)""); 5212 #ifdef XP_DEBUG_OBJ_USAGE 5213 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); 5214 #endif 5215 return(ret); 5216 } 5217 5218 /** 5219 * xmlXPathWrapString: 5220 * @val: the xmlChar * value 5221 * 5222 * Wraps the @val string into an XPath object. 5223 * 5224 * Returns the newly created object. 5225 */ 5226 xmlXPathObjectPtr 5227 xmlXPathWrapString (xmlChar *val) { 5228 xmlXPathObjectPtr ret; 5229 5230 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5231 if (ret == NULL) { 5232 xmlXPathErrMemory(NULL, "creating string object\n"); 5233 return(NULL); 5234 } 5235 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5236 ret->type = XPATH_STRING; 5237 ret->stringval = val; 5238 #ifdef XP_DEBUG_OBJ_USAGE 5239 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); 5240 #endif 5241 return(ret); 5242 } 5243 5244 /** 5245 * xmlXPathNewCString: 5246 * @val: the char * value 5247 * 5248 * Create a new xmlXPathObjectPtr of type string and of value @val 5249 * 5250 * Returns the newly created object. 5251 */ 5252 xmlXPathObjectPtr 5253 xmlXPathNewCString(const char *val) { 5254 xmlXPathObjectPtr ret; 5255 5256 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5257 if (ret == NULL) { 5258 xmlXPathErrMemory(NULL, "creating string object\n"); 5259 return(NULL); 5260 } 5261 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5262 ret->type = XPATH_STRING; 5263 ret->stringval = xmlStrdup(BAD_CAST val); 5264 #ifdef XP_DEBUG_OBJ_USAGE 5265 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); 5266 #endif 5267 return(ret); 5268 } 5269 5270 /** 5271 * xmlXPathWrapCString: 5272 * @val: the char * value 5273 * 5274 * Wraps a string into an XPath object. 5275 * 5276 * Returns the newly created object. 5277 */ 5278 xmlXPathObjectPtr 5279 xmlXPathWrapCString (char * val) { 5280 return(xmlXPathWrapString((xmlChar *)(val))); 5281 } 5282 5283 /** 5284 * xmlXPathWrapExternal: 5285 * @val: the user data 5286 * 5287 * Wraps the @val data into an XPath object. 5288 * 5289 * Returns the newly created object. 5290 */ 5291 xmlXPathObjectPtr 5292 xmlXPathWrapExternal (void *val) { 5293 xmlXPathObjectPtr ret; 5294 5295 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5296 if (ret == NULL) { 5297 xmlXPathErrMemory(NULL, "creating user object\n"); 5298 return(NULL); 5299 } 5300 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5301 ret->type = XPATH_USERS; 5302 ret->user = val; 5303 #ifdef XP_DEBUG_OBJ_USAGE 5304 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS); 5305 #endif 5306 return(ret); 5307 } 5308 5309 /** 5310 * xmlXPathObjectCopy: 5311 * @val: the original object 5312 * 5313 * allocate a new copy of a given object 5314 * 5315 * Returns the newly created object. 5316 */ 5317 xmlXPathObjectPtr 5318 xmlXPathObjectCopy(xmlXPathObjectPtr val) { 5319 xmlXPathObjectPtr ret; 5320 5321 if (val == NULL) 5322 return(NULL); 5323 5324 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5325 if (ret == NULL) { 5326 xmlXPathErrMemory(NULL, "copying object\n"); 5327 return(NULL); 5328 } 5329 memcpy(ret, val , (size_t) sizeof(xmlXPathObject)); 5330 #ifdef XP_DEBUG_OBJ_USAGE 5331 xmlXPathDebugObjUsageRequested(NULL, val->type); 5332 #endif 5333 switch (val->type) { 5334 case XPATH_BOOLEAN: 5335 case XPATH_NUMBER: 5336 case XPATH_POINT: 5337 case XPATH_RANGE: 5338 break; 5339 case XPATH_STRING: 5340 ret->stringval = xmlStrdup(val->stringval); 5341 break; 5342 case XPATH_XSLT_TREE: 5343 #if 0 5344 /* 5345 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that 5346 this previous handling is no longer correct, and can cause some serious 5347 problems (ref. bug 145547) 5348 */ 5349 if ((val->nodesetval != NULL) && 5350 (val->nodesetval->nodeTab != NULL)) { 5351 xmlNodePtr cur, tmp; 5352 xmlDocPtr top; 5353 5354 ret->boolval = 1; 5355 top = xmlNewDoc(NULL); 5356 top->name = (char *) 5357 xmlStrdup(val->nodesetval->nodeTab[0]->name); 5358 ret->user = top; 5359 if (top != NULL) { 5360 top->doc = top; 5361 cur = val->nodesetval->nodeTab[0]->children; 5362 while (cur != NULL) { 5363 tmp = xmlDocCopyNode(cur, top, 1); 5364 xmlAddChild((xmlNodePtr) top, tmp); 5365 cur = cur->next; 5366 } 5367 } 5368 5369 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top); 5370 } else 5371 ret->nodesetval = xmlXPathNodeSetCreate(NULL); 5372 /* Deallocate the copied tree value */ 5373 break; 5374 #endif 5375 case XPATH_NODESET: 5376 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval); 5377 /* Do not deallocate the copied tree value */ 5378 ret->boolval = 0; 5379 break; 5380 case XPATH_LOCATIONSET: 5381 #ifdef LIBXML_XPTR_ENABLED 5382 { 5383 xmlLocationSetPtr loc = val->user; 5384 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc); 5385 break; 5386 } 5387 #endif 5388 case XPATH_USERS: 5389 ret->user = val->user; 5390 break; 5391 case XPATH_UNDEFINED: 5392 xmlGenericError(xmlGenericErrorContext, 5393 "xmlXPathObjectCopy: unsupported type %d\n", 5394 val->type); 5395 break; 5396 } 5397 return(ret); 5398 } 5399 5400 /** 5401 * xmlXPathFreeObject: 5402 * @obj: the object to free 5403 * 5404 * Free up an xmlXPathObjectPtr object. 5405 */ 5406 void 5407 xmlXPathFreeObject(xmlXPathObjectPtr obj) { 5408 if (obj == NULL) return; 5409 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) { 5410 if (obj->boolval) { 5411 #if 0 5412 if (obj->user != NULL) { 5413 xmlXPathFreeNodeSet(obj->nodesetval); 5414 xmlFreeNodeList((xmlNodePtr) obj->user); 5415 } else 5416 #endif 5417 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */ 5418 if (obj->nodesetval != NULL) 5419 xmlXPathFreeValueTree(obj->nodesetval); 5420 } else { 5421 if (obj->nodesetval != NULL) 5422 xmlXPathFreeNodeSet(obj->nodesetval); 5423 } 5424 #ifdef LIBXML_XPTR_ENABLED 5425 } else if (obj->type == XPATH_LOCATIONSET) { 5426 if (obj->user != NULL) 5427 xmlXPtrFreeLocationSet(obj->user); 5428 #endif 5429 } else if (obj->type == XPATH_STRING) { 5430 if (obj->stringval != NULL) 5431 xmlFree(obj->stringval); 5432 } 5433 #ifdef XP_DEBUG_OBJ_USAGE 5434 xmlXPathDebugObjUsageReleased(NULL, obj->type); 5435 #endif 5436 xmlFree(obj); 5437 } 5438 5439 /** 5440 * xmlXPathReleaseObject: 5441 * @obj: the xmlXPathObjectPtr to free or to cache 5442 * 5443 * Depending on the state of the cache this frees the given 5444 * XPath object or stores it in the cache. 5445 */ 5446 static void 5447 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj) 5448 { 5449 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \ 5450 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \ 5451 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj; 5452 5453 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n)) 5454 5455 if (obj == NULL) 5456 return; 5457 if ((ctxt == NULL) || (ctxt->cache == NULL)) { 5458 xmlXPathFreeObject(obj); 5459 } else { 5460 xmlXPathContextCachePtr cache = 5461 (xmlXPathContextCachePtr) ctxt->cache; 5462 5463 switch (obj->type) { 5464 case XPATH_NODESET: 5465 case XPATH_XSLT_TREE: 5466 if (obj->nodesetval != NULL) { 5467 if (obj->boolval) { 5468 /* 5469 * It looks like the @boolval is used for 5470 * evaluation if this an XSLT Result Tree Fragment. 5471 * TODO: Check if this assumption is correct. 5472 */ 5473 obj->type = XPATH_XSLT_TREE; /* just for debugging */ 5474 xmlXPathFreeValueTree(obj->nodesetval); 5475 obj->nodesetval = NULL; 5476 } else if ((obj->nodesetval->nodeMax <= 40) && 5477 (XP_CACHE_WANTS(cache->nodesetObjs, 5478 cache->maxNodeset))) 5479 { 5480 XP_CACHE_ADD(cache->nodesetObjs, obj); 5481 goto obj_cached; 5482 } else { 5483 xmlXPathFreeNodeSet(obj->nodesetval); 5484 obj->nodesetval = NULL; 5485 } 5486 } 5487 break; 5488 case XPATH_STRING: 5489 if (obj->stringval != NULL) 5490 xmlFree(obj->stringval); 5491 5492 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) { 5493 XP_CACHE_ADD(cache->stringObjs, obj); 5494 goto obj_cached; 5495 } 5496 break; 5497 case XPATH_BOOLEAN: 5498 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) { 5499 XP_CACHE_ADD(cache->booleanObjs, obj); 5500 goto obj_cached; 5501 } 5502 break; 5503 case XPATH_NUMBER: 5504 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) { 5505 XP_CACHE_ADD(cache->numberObjs, obj); 5506 goto obj_cached; 5507 } 5508 break; 5509 #ifdef LIBXML_XPTR_ENABLED 5510 case XPATH_LOCATIONSET: 5511 if (obj->user != NULL) { 5512 xmlXPtrFreeLocationSet(obj->user); 5513 } 5514 goto free_obj; 5515 #endif 5516 default: 5517 goto free_obj; 5518 } 5519 5520 /* 5521 * Fallback to adding to the misc-objects slot. 5522 */ 5523 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) { 5524 XP_CACHE_ADD(cache->miscObjs, obj); 5525 } else 5526 goto free_obj; 5527 5528 obj_cached: 5529 5530 #ifdef XP_DEBUG_OBJ_USAGE 5531 xmlXPathDebugObjUsageReleased(ctxt, obj->type); 5532 #endif 5533 5534 if (obj->nodesetval != NULL) { 5535 xmlNodeSetPtr tmpset = obj->nodesetval; 5536 5537 /* 5538 * TODO: Due to those nasty ns-nodes, we need to traverse 5539 * the list and free the ns-nodes. 5540 * URGENT TODO: Check if it's actually slowing things down. 5541 * Maybe we shouldn't try to preserve the list. 5542 */ 5543 if (tmpset->nodeNr > 1) { 5544 int i; 5545 xmlNodePtr node; 5546 5547 for (i = 0; i < tmpset->nodeNr; i++) { 5548 node = tmpset->nodeTab[i]; 5549 if ((node != NULL) && 5550 (node->type == XML_NAMESPACE_DECL)) 5551 { 5552 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 5553 } 5554 } 5555 } else if (tmpset->nodeNr == 1) { 5556 if ((tmpset->nodeTab[0] != NULL) && 5557 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL)) 5558 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]); 5559 } 5560 tmpset->nodeNr = 0; 5561 memset(obj, 0, sizeof(xmlXPathObject)); 5562 obj->nodesetval = tmpset; 5563 } else 5564 memset(obj, 0, sizeof(xmlXPathObject)); 5565 5566 return; 5567 5568 free_obj: 5569 /* 5570 * Cache is full; free the object. 5571 */ 5572 if (obj->nodesetval != NULL) 5573 xmlXPathFreeNodeSet(obj->nodesetval); 5574 #ifdef XP_DEBUG_OBJ_USAGE 5575 xmlXPathDebugObjUsageReleased(NULL, obj->type); 5576 #endif 5577 xmlFree(obj); 5578 } 5579 return; 5580 } 5581 5582 5583 /************************************************************************ 5584 * * 5585 * Type Casting Routines * 5586 * * 5587 ************************************************************************/ 5588 5589 /** 5590 * xmlXPathCastBooleanToString: 5591 * @val: a boolean 5592 * 5593 * Converts a boolean to its string value. 5594 * 5595 * Returns a newly allocated string. 5596 */ 5597 xmlChar * 5598 xmlXPathCastBooleanToString (int val) { 5599 xmlChar *ret; 5600 if (val) 5601 ret = xmlStrdup((const xmlChar *) "true"); 5602 else 5603 ret = xmlStrdup((const xmlChar *) "false"); 5604 return(ret); 5605 } 5606 5607 /** 5608 * xmlXPathCastNumberToString: 5609 * @val: a number 5610 * 5611 * Converts a number to its string value. 5612 * 5613 * Returns a newly allocated string. 5614 */ 5615 xmlChar * 5616 xmlXPathCastNumberToString (double val) { 5617 xmlChar *ret; 5618 switch (xmlXPathIsInf(val)) { 5619 case 1: 5620 ret = xmlStrdup((const xmlChar *) "Infinity"); 5621 break; 5622 case -1: 5623 ret = xmlStrdup((const xmlChar *) "-Infinity"); 5624 break; 5625 default: 5626 if (xmlXPathIsNaN(val)) { 5627 ret = xmlStrdup((const xmlChar *) "NaN"); 5628 } else if (val == 0 && xmlXPathGetSign(val) != 0) { 5629 ret = xmlStrdup((const xmlChar *) "0"); 5630 } else { 5631 /* could be improved */ 5632 char buf[100]; 5633 xmlXPathFormatNumber(val, buf, 99); 5634 buf[99] = 0; 5635 ret = xmlStrdup((const xmlChar *) buf); 5636 } 5637 } 5638 return(ret); 5639 } 5640 5641 /** 5642 * xmlXPathCastNodeToString: 5643 * @node: a node 5644 * 5645 * Converts a node to its string value. 5646 * 5647 * Returns a newly allocated string. 5648 */ 5649 xmlChar * 5650 xmlXPathCastNodeToString (xmlNodePtr node) { 5651 xmlChar *ret; 5652 if ((ret = xmlNodeGetContent(node)) == NULL) 5653 ret = xmlStrdup((const xmlChar *) ""); 5654 return(ret); 5655 } 5656 5657 /** 5658 * xmlXPathCastNodeSetToString: 5659 * @ns: a node-set 5660 * 5661 * Converts a node-set to its string value. 5662 * 5663 * Returns a newly allocated string. 5664 */ 5665 xmlChar * 5666 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) { 5667 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL)) 5668 return(xmlStrdup((const xmlChar *) "")); 5669 5670 if (ns->nodeNr > 1) 5671 xmlXPathNodeSetSort(ns); 5672 return(xmlXPathCastNodeToString(ns->nodeTab[0])); 5673 } 5674 5675 /** 5676 * xmlXPathCastToString: 5677 * @val: an XPath object 5678 * 5679 * Converts an existing object to its string() equivalent 5680 * 5681 * Returns the allocated string value of the object, NULL in case of error. 5682 * It's up to the caller to free the string memory with xmlFree(). 5683 */ 5684 xmlChar * 5685 xmlXPathCastToString(xmlXPathObjectPtr val) { 5686 xmlChar *ret = NULL; 5687 5688 if (val == NULL) 5689 return(xmlStrdup((const xmlChar *) "")); 5690 switch (val->type) { 5691 case XPATH_UNDEFINED: 5692 #ifdef DEBUG_EXPR 5693 xmlGenericError(xmlGenericErrorContext, "String: undefined\n"); 5694 #endif 5695 ret = xmlStrdup((const xmlChar *) ""); 5696 break; 5697 case XPATH_NODESET: 5698 case XPATH_XSLT_TREE: 5699 ret = xmlXPathCastNodeSetToString(val->nodesetval); 5700 break; 5701 case XPATH_STRING: 5702 return(xmlStrdup(val->stringval)); 5703 case XPATH_BOOLEAN: 5704 ret = xmlXPathCastBooleanToString(val->boolval); 5705 break; 5706 case XPATH_NUMBER: { 5707 ret = xmlXPathCastNumberToString(val->floatval); 5708 break; 5709 } 5710 case XPATH_USERS: 5711 case XPATH_POINT: 5712 case XPATH_RANGE: 5713 case XPATH_LOCATIONSET: 5714 TODO 5715 ret = xmlStrdup((const xmlChar *) ""); 5716 break; 5717 } 5718 return(ret); 5719 } 5720 5721 /** 5722 * xmlXPathConvertString: 5723 * @val: an XPath object 5724 * 5725 * Converts an existing object to its string() equivalent 5726 * 5727 * Returns the new object, the old one is freed (or the operation 5728 * is done directly on @val) 5729 */ 5730 xmlXPathObjectPtr 5731 xmlXPathConvertString(xmlXPathObjectPtr val) { 5732 xmlChar *res = NULL; 5733 5734 if (val == NULL) 5735 return(xmlXPathNewCString("")); 5736 5737 switch (val->type) { 5738 case XPATH_UNDEFINED: 5739 #ifdef DEBUG_EXPR 5740 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n"); 5741 #endif 5742 break; 5743 case XPATH_NODESET: 5744 case XPATH_XSLT_TREE: 5745 res = xmlXPathCastNodeSetToString(val->nodesetval); 5746 break; 5747 case XPATH_STRING: 5748 return(val); 5749 case XPATH_BOOLEAN: 5750 res = xmlXPathCastBooleanToString(val->boolval); 5751 break; 5752 case XPATH_NUMBER: 5753 res = xmlXPathCastNumberToString(val->floatval); 5754 break; 5755 case XPATH_USERS: 5756 case XPATH_POINT: 5757 case XPATH_RANGE: 5758 case XPATH_LOCATIONSET: 5759 TODO; 5760 break; 5761 } 5762 xmlXPathFreeObject(val); 5763 if (res == NULL) 5764 return(xmlXPathNewCString("")); 5765 return(xmlXPathWrapString(res)); 5766 } 5767 5768 /** 5769 * xmlXPathCastBooleanToNumber: 5770 * @val: a boolean 5771 * 5772 * Converts a boolean to its number value 5773 * 5774 * Returns the number value 5775 */ 5776 double 5777 xmlXPathCastBooleanToNumber(int val) { 5778 if (val) 5779 return(1.0); 5780 return(0.0); 5781 } 5782 5783 /** 5784 * xmlXPathCastStringToNumber: 5785 * @val: a string 5786 * 5787 * Converts a string to its number value 5788 * 5789 * Returns the number value 5790 */ 5791 double 5792 xmlXPathCastStringToNumber(const xmlChar * val) { 5793 return(xmlXPathStringEvalNumber(val)); 5794 } 5795 5796 /** 5797 * xmlXPathCastNodeToNumber: 5798 * @node: a node 5799 * 5800 * Converts a node to its number value 5801 * 5802 * Returns the number value 5803 */ 5804 double 5805 xmlXPathCastNodeToNumber (xmlNodePtr node) { 5806 xmlChar *strval; 5807 double ret; 5808 5809 if (node == NULL) 5810 return(xmlXPathNAN); 5811 strval = xmlXPathCastNodeToString(node); 5812 if (strval == NULL) 5813 return(xmlXPathNAN); 5814 ret = xmlXPathCastStringToNumber(strval); 5815 xmlFree(strval); 5816 5817 return(ret); 5818 } 5819 5820 /** 5821 * xmlXPathCastNodeSetToNumber: 5822 * @ns: a node-set 5823 * 5824 * Converts a node-set to its number value 5825 * 5826 * Returns the number value 5827 */ 5828 double 5829 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) { 5830 xmlChar *str; 5831 double ret; 5832 5833 if (ns == NULL) 5834 return(xmlXPathNAN); 5835 str = xmlXPathCastNodeSetToString(ns); 5836 ret = xmlXPathCastStringToNumber(str); 5837 xmlFree(str); 5838 return(ret); 5839 } 5840 5841 /** 5842 * xmlXPathCastToNumber: 5843 * @val: an XPath object 5844 * 5845 * Converts an XPath object to its number value 5846 * 5847 * Returns the number value 5848 */ 5849 double 5850 xmlXPathCastToNumber(xmlXPathObjectPtr val) { 5851 double ret = 0.0; 5852 5853 if (val == NULL) 5854 return(xmlXPathNAN); 5855 switch (val->type) { 5856 case XPATH_UNDEFINED: 5857 #ifdef DEGUB_EXPR 5858 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n"); 5859 #endif 5860 ret = xmlXPathNAN; 5861 break; 5862 case XPATH_NODESET: 5863 case XPATH_XSLT_TREE: 5864 ret = xmlXPathCastNodeSetToNumber(val->nodesetval); 5865 break; 5866 case XPATH_STRING: 5867 ret = xmlXPathCastStringToNumber(val->stringval); 5868 break; 5869 case XPATH_NUMBER: 5870 ret = val->floatval; 5871 break; 5872 case XPATH_BOOLEAN: 5873 ret = xmlXPathCastBooleanToNumber(val->boolval); 5874 break; 5875 case XPATH_USERS: 5876 case XPATH_POINT: 5877 case XPATH_RANGE: 5878 case XPATH_LOCATIONSET: 5879 TODO; 5880 ret = xmlXPathNAN; 5881 break; 5882 } 5883 return(ret); 5884 } 5885 5886 /** 5887 * xmlXPathConvertNumber: 5888 * @val: an XPath object 5889 * 5890 * Converts an existing object to its number() equivalent 5891 * 5892 * Returns the new object, the old one is freed (or the operation 5893 * is done directly on @val) 5894 */ 5895 xmlXPathObjectPtr 5896 xmlXPathConvertNumber(xmlXPathObjectPtr val) { 5897 xmlXPathObjectPtr ret; 5898 5899 if (val == NULL) 5900 return(xmlXPathNewFloat(0.0)); 5901 if (val->type == XPATH_NUMBER) 5902 return(val); 5903 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val)); 5904 xmlXPathFreeObject(val); 5905 return(ret); 5906 } 5907 5908 /** 5909 * xmlXPathCastNumberToBoolean: 5910 * @val: a number 5911 * 5912 * Converts a number to its boolean value 5913 * 5914 * Returns the boolean value 5915 */ 5916 int 5917 xmlXPathCastNumberToBoolean (double val) { 5918 if (xmlXPathIsNaN(val) || (val == 0.0)) 5919 return(0); 5920 return(1); 5921 } 5922 5923 /** 5924 * xmlXPathCastStringToBoolean: 5925 * @val: a string 5926 * 5927 * Converts a string to its boolean value 5928 * 5929 * Returns the boolean value 5930 */ 5931 int 5932 xmlXPathCastStringToBoolean (const xmlChar *val) { 5933 if ((val == NULL) || (xmlStrlen(val) == 0)) 5934 return(0); 5935 return(1); 5936 } 5937 5938 /** 5939 * xmlXPathCastNodeSetToBoolean: 5940 * @ns: a node-set 5941 * 5942 * Converts a node-set to its boolean value 5943 * 5944 * Returns the boolean value 5945 */ 5946 int 5947 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) { 5948 if ((ns == NULL) || (ns->nodeNr == 0)) 5949 return(0); 5950 return(1); 5951 } 5952 5953 /** 5954 * xmlXPathCastToBoolean: 5955 * @val: an XPath object 5956 * 5957 * Converts an XPath object to its boolean value 5958 * 5959 * Returns the boolean value 5960 */ 5961 int 5962 xmlXPathCastToBoolean (xmlXPathObjectPtr val) { 5963 int ret = 0; 5964 5965 if (val == NULL) 5966 return(0); 5967 switch (val->type) { 5968 case XPATH_UNDEFINED: 5969 #ifdef DEBUG_EXPR 5970 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n"); 5971 #endif 5972 ret = 0; 5973 break; 5974 case XPATH_NODESET: 5975 case XPATH_XSLT_TREE: 5976 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval); 5977 break; 5978 case XPATH_STRING: 5979 ret = xmlXPathCastStringToBoolean(val->stringval); 5980 break; 5981 case XPATH_NUMBER: 5982 ret = xmlXPathCastNumberToBoolean(val->floatval); 5983 break; 5984 case XPATH_BOOLEAN: 5985 ret = val->boolval; 5986 break; 5987 case XPATH_USERS: 5988 case XPATH_POINT: 5989 case XPATH_RANGE: 5990 case XPATH_LOCATIONSET: 5991 TODO; 5992 ret = 0; 5993 break; 5994 } 5995 return(ret); 5996 } 5997 5998 5999 /** 6000 * xmlXPathConvertBoolean: 6001 * @val: an XPath object 6002 * 6003 * Converts an existing object to its boolean() equivalent 6004 * 6005 * Returns the new object, the old one is freed (or the operation 6006 * is done directly on @val) 6007 */ 6008 xmlXPathObjectPtr 6009 xmlXPathConvertBoolean(xmlXPathObjectPtr val) { 6010 xmlXPathObjectPtr ret; 6011 6012 if (val == NULL) 6013 return(xmlXPathNewBoolean(0)); 6014 if (val->type == XPATH_BOOLEAN) 6015 return(val); 6016 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val)); 6017 xmlXPathFreeObject(val); 6018 return(ret); 6019 } 6020 6021 /************************************************************************ 6022 * * 6023 * Routines to handle XPath contexts * 6024 * * 6025 ************************************************************************/ 6026 6027 /** 6028 * xmlXPathNewContext: 6029 * @doc: the XML document 6030 * 6031 * Create a new xmlXPathContext 6032 * 6033 * Returns the xmlXPathContext just allocated. The caller will need to free it. 6034 */ 6035 xmlXPathContextPtr 6036 xmlXPathNewContext(xmlDocPtr doc) { 6037 xmlXPathContextPtr ret; 6038 6039 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext)); 6040 if (ret == NULL) { 6041 xmlXPathErrMemory(NULL, "creating context\n"); 6042 return(NULL); 6043 } 6044 memset(ret, 0 , (size_t) sizeof(xmlXPathContext)); 6045 ret->doc = doc; 6046 ret->node = NULL; 6047 6048 ret->varHash = NULL; 6049 6050 ret->nb_types = 0; 6051 ret->max_types = 0; 6052 ret->types = NULL; 6053 6054 ret->funcHash = xmlHashCreate(0); 6055 6056 ret->nb_axis = 0; 6057 ret->max_axis = 0; 6058 ret->axis = NULL; 6059 6060 ret->nsHash = NULL; 6061 ret->user = NULL; 6062 6063 ret->contextSize = -1; 6064 ret->proximityPosition = -1; 6065 6066 #ifdef XP_DEFAULT_CACHE_ON 6067 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) { 6068 xmlXPathFreeContext(ret); 6069 return(NULL); 6070 } 6071 #endif 6072 6073 xmlXPathRegisterAllFunctions(ret); 6074 6075 return(ret); 6076 } 6077 6078 /** 6079 * xmlXPathFreeContext: 6080 * @ctxt: the context to free 6081 * 6082 * Free up an xmlXPathContext 6083 */ 6084 void 6085 xmlXPathFreeContext(xmlXPathContextPtr ctxt) { 6086 if (ctxt == NULL) return; 6087 6088 if (ctxt->cache != NULL) 6089 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache); 6090 xmlXPathRegisteredNsCleanup(ctxt); 6091 xmlXPathRegisteredFuncsCleanup(ctxt); 6092 xmlXPathRegisteredVariablesCleanup(ctxt); 6093 xmlResetError(&ctxt->lastError); 6094 xmlFree(ctxt); 6095 } 6096 6097 /************************************************************************ 6098 * * 6099 * Routines to handle XPath parser contexts * 6100 * * 6101 ************************************************************************/ 6102 6103 #define CHECK_CTXT(ctxt) \ 6104 if (ctxt == NULL) { \ 6105 __xmlRaiseError(NULL, NULL, NULL, \ 6106 NULL, NULL, XML_FROM_XPATH, \ 6107 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \ 6108 __FILE__, __LINE__, \ 6109 NULL, NULL, NULL, 0, 0, \ 6110 "NULL context pointer\n"); \ 6111 return(NULL); \ 6112 } \ 6113 6114 #define CHECK_CTXT_NEG(ctxt) \ 6115 if (ctxt == NULL) { \ 6116 __xmlRaiseError(NULL, NULL, NULL, \ 6117 NULL, NULL, XML_FROM_XPATH, \ 6118 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \ 6119 __FILE__, __LINE__, \ 6120 NULL, NULL, NULL, 0, 0, \ 6121 "NULL context pointer\n"); \ 6122 return(-1); \ 6123 } \ 6124 6125 6126 #define CHECK_CONTEXT(ctxt) \ 6127 if ((ctxt == NULL) || (ctxt->doc == NULL) || \ 6128 (ctxt->doc->children == NULL)) { \ 6129 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \ 6130 return(NULL); \ 6131 } 6132 6133 6134 /** 6135 * xmlXPathNewParserContext: 6136 * @str: the XPath expression 6137 * @ctxt: the XPath context 6138 * 6139 * Create a new xmlXPathParserContext 6140 * 6141 * Returns the xmlXPathParserContext just allocated. 6142 */ 6143 xmlXPathParserContextPtr 6144 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) { 6145 xmlXPathParserContextPtr ret; 6146 6147 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext)); 6148 if (ret == NULL) { 6149 xmlXPathErrMemory(ctxt, "creating parser context\n"); 6150 return(NULL); 6151 } 6152 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext)); 6153 ret->cur = ret->base = str; 6154 ret->context = ctxt; 6155 6156 ret->comp = xmlXPathNewCompExpr(); 6157 if (ret->comp == NULL) { 6158 xmlFree(ret->valueTab); 6159 xmlFree(ret); 6160 return(NULL); 6161 } 6162 if ((ctxt != NULL) && (ctxt->dict != NULL)) { 6163 ret->comp->dict = ctxt->dict; 6164 xmlDictReference(ret->comp->dict); 6165 } 6166 6167 return(ret); 6168 } 6169 6170 /** 6171 * xmlXPathCompParserContext: 6172 * @comp: the XPath compiled expression 6173 * @ctxt: the XPath context 6174 * 6175 * Create a new xmlXPathParserContext when processing a compiled expression 6176 * 6177 * Returns the xmlXPathParserContext just allocated. 6178 */ 6179 static xmlXPathParserContextPtr 6180 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) { 6181 xmlXPathParserContextPtr ret; 6182 6183 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext)); 6184 if (ret == NULL) { 6185 xmlXPathErrMemory(ctxt, "creating evaluation context\n"); 6186 return(NULL); 6187 } 6188 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext)); 6189 6190 /* Allocate the value stack */ 6191 ret->valueTab = (xmlXPathObjectPtr *) 6192 xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); 6193 if (ret->valueTab == NULL) { 6194 xmlFree(ret); 6195 xmlXPathErrMemory(ctxt, "creating evaluation context\n"); 6196 return(NULL); 6197 } 6198 ret->valueNr = 0; 6199 ret->valueMax = 10; 6200 ret->value = NULL; 6201 ret->valueFrame = 0; 6202 6203 ret->context = ctxt; 6204 ret->comp = comp; 6205 6206 return(ret); 6207 } 6208 6209 /** 6210 * xmlXPathFreeParserContext: 6211 * @ctxt: the context to free 6212 * 6213 * Free up an xmlXPathParserContext 6214 */ 6215 void 6216 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) { 6217 if (ctxt->valueTab != NULL) { 6218 xmlFree(ctxt->valueTab); 6219 } 6220 if (ctxt->comp != NULL) { 6221 #ifdef XPATH_STREAMING 6222 if (ctxt->comp->stream != NULL) { 6223 xmlFreePatternList(ctxt->comp->stream); 6224 ctxt->comp->stream = NULL; 6225 } 6226 #endif 6227 xmlXPathFreeCompExpr(ctxt->comp); 6228 } 6229 xmlFree(ctxt); 6230 } 6231 6232 /************************************************************************ 6233 * * 6234 * The implicit core function library * 6235 * * 6236 ************************************************************************/ 6237 6238 /** 6239 * xmlXPathNodeValHash: 6240 * @node: a node pointer 6241 * 6242 * Function computing the beginning of the string value of the node, 6243 * used to speed up comparisons 6244 * 6245 * Returns an int usable as a hash 6246 */ 6247 static unsigned int 6248 xmlXPathNodeValHash(xmlNodePtr node) { 6249 int len = 2; 6250 const xmlChar * string = NULL; 6251 xmlNodePtr tmp = NULL; 6252 unsigned int ret = 0; 6253 6254 if (node == NULL) 6255 return(0); 6256 6257 if (node->type == XML_DOCUMENT_NODE) { 6258 tmp = xmlDocGetRootElement((xmlDocPtr) node); 6259 if (tmp == NULL) 6260 node = node->children; 6261 else 6262 node = tmp; 6263 6264 if (node == NULL) 6265 return(0); 6266 } 6267 6268 switch (node->type) { 6269 case XML_COMMENT_NODE: 6270 case XML_PI_NODE: 6271 case XML_CDATA_SECTION_NODE: 6272 case XML_TEXT_NODE: 6273 string = node->content; 6274 if (string == NULL) 6275 return(0); 6276 if (string[0] == 0) 6277 return(0); 6278 return(((unsigned int) string[0]) + 6279 (((unsigned int) string[1]) << 8)); 6280 case XML_NAMESPACE_DECL: 6281 string = ((xmlNsPtr)node)->href; 6282 if (string == NULL) 6283 return(0); 6284 if (string[0] == 0) 6285 return(0); 6286 return(((unsigned int) string[0]) + 6287 (((unsigned int) string[1]) << 8)); 6288 case XML_ATTRIBUTE_NODE: 6289 tmp = ((xmlAttrPtr) node)->children; 6290 break; 6291 case XML_ELEMENT_NODE: 6292 tmp = node->children; 6293 break; 6294 default: 6295 return(0); 6296 } 6297 while (tmp != NULL) { 6298 switch (tmp->type) { 6299 case XML_COMMENT_NODE: 6300 case XML_PI_NODE: 6301 case XML_CDATA_SECTION_NODE: 6302 case XML_TEXT_NODE: 6303 string = tmp->content; 6304 break; 6305 case XML_NAMESPACE_DECL: 6306 string = ((xmlNsPtr)tmp)->href; 6307 break; 6308 default: 6309 break; 6310 } 6311 if ((string != NULL) && (string[0] != 0)) { 6312 if (len == 1) { 6313 return(ret + (((unsigned int) string[0]) << 8)); 6314 } 6315 if (string[1] == 0) { 6316 len = 1; 6317 ret = (unsigned int) string[0]; 6318 } else { 6319 return(((unsigned int) string[0]) + 6320 (((unsigned int) string[1]) << 8)); 6321 } 6322 } 6323 /* 6324 * Skip to next node 6325 */ 6326 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) { 6327 if (tmp->children->type != XML_ENTITY_DECL) { 6328 tmp = tmp->children; 6329 continue; 6330 } 6331 } 6332 if (tmp == node) 6333 break; 6334 6335 if (tmp->next != NULL) { 6336 tmp = tmp->next; 6337 continue; 6338 } 6339 6340 do { 6341 tmp = tmp->parent; 6342 if (tmp == NULL) 6343 break; 6344 if (tmp == node) { 6345 tmp = NULL; 6346 break; 6347 } 6348 if (tmp->next != NULL) { 6349 tmp = tmp->next; 6350 break; 6351 } 6352 } while (tmp != NULL); 6353 } 6354 return(ret); 6355 } 6356 6357 /** 6358 * xmlXPathStringHash: 6359 * @string: a string 6360 * 6361 * Function computing the beginning of the string value of the node, 6362 * used to speed up comparisons 6363 * 6364 * Returns an int usable as a hash 6365 */ 6366 static unsigned int 6367 xmlXPathStringHash(const xmlChar * string) { 6368 if (string == NULL) 6369 return((unsigned int) 0); 6370 if (string[0] == 0) 6371 return(0); 6372 return(((unsigned int) string[0]) + 6373 (((unsigned int) string[1]) << 8)); 6374 } 6375 6376 /** 6377 * xmlXPathCompareNodeSetFloat: 6378 * @ctxt: the XPath Parser context 6379 * @inf: less than (1) or greater than (0) 6380 * @strict: is the comparison strict 6381 * @arg: the node set 6382 * @f: the value 6383 * 6384 * Implement the compare operation between a nodeset and a number 6385 * @ns < @val (1, 1, ... 6386 * @ns <= @val (1, 0, ... 6387 * @ns > @val (0, 1, ... 6388 * @ns >= @val (0, 0, ... 6389 * 6390 * If one object to be compared is a node-set and the other is a number, 6391 * then the comparison will be true if and only if there is a node in the 6392 * node-set such that the result of performing the comparison on the number 6393 * to be compared and on the result of converting the string-value of that 6394 * node to a number using the number function is true. 6395 * 6396 * Returns 0 or 1 depending on the results of the test. 6397 */ 6398 static int 6399 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict, 6400 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) { 6401 int i, ret = 0; 6402 xmlNodeSetPtr ns; 6403 xmlChar *str2; 6404 6405 if ((f == NULL) || (arg == NULL) || 6406 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) { 6407 xmlXPathReleaseObject(ctxt->context, arg); 6408 xmlXPathReleaseObject(ctxt->context, f); 6409 return(0); 6410 } 6411 ns = arg->nodesetval; 6412 if (ns != NULL) { 6413 for (i = 0;i < ns->nodeNr;i++) { 6414 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 6415 if (str2 != NULL) { 6416 valuePush(ctxt, 6417 xmlXPathCacheNewString(ctxt->context, str2)); 6418 xmlFree(str2); 6419 xmlXPathNumberFunction(ctxt, 1); 6420 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f)); 6421 ret = xmlXPathCompareValues(ctxt, inf, strict); 6422 if (ret) 6423 break; 6424 } 6425 } 6426 } 6427 xmlXPathReleaseObject(ctxt->context, arg); 6428 xmlXPathReleaseObject(ctxt->context, f); 6429 return(ret); 6430 } 6431 6432 /** 6433 * xmlXPathCompareNodeSetString: 6434 * @ctxt: the XPath Parser context 6435 * @inf: less than (1) or greater than (0) 6436 * @strict: is the comparison strict 6437 * @arg: the node set 6438 * @s: the value 6439 * 6440 * Implement the compare operation between a nodeset and a string 6441 * @ns < @val (1, 1, ... 6442 * @ns <= @val (1, 0, ... 6443 * @ns > @val (0, 1, ... 6444 * @ns >= @val (0, 0, ... 6445 * 6446 * If one object to be compared is a node-set and the other is a string, 6447 * then the comparison will be true if and only if there is a node in 6448 * the node-set such that the result of performing the comparison on the 6449 * string-value of the node and the other string is true. 6450 * 6451 * Returns 0 or 1 depending on the results of the test. 6452 */ 6453 static int 6454 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict, 6455 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) { 6456 int i, ret = 0; 6457 xmlNodeSetPtr ns; 6458 xmlChar *str2; 6459 6460 if ((s == NULL) || (arg == NULL) || 6461 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) { 6462 xmlXPathReleaseObject(ctxt->context, arg); 6463 xmlXPathReleaseObject(ctxt->context, s); 6464 return(0); 6465 } 6466 ns = arg->nodesetval; 6467 if (ns != NULL) { 6468 for (i = 0;i < ns->nodeNr;i++) { 6469 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 6470 if (str2 != NULL) { 6471 valuePush(ctxt, 6472 xmlXPathCacheNewString(ctxt->context, str2)); 6473 xmlFree(str2); 6474 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s)); 6475 ret = xmlXPathCompareValues(ctxt, inf, strict); 6476 if (ret) 6477 break; 6478 } 6479 } 6480 } 6481 xmlXPathReleaseObject(ctxt->context, arg); 6482 xmlXPathReleaseObject(ctxt->context, s); 6483 return(ret); 6484 } 6485 6486 /** 6487 * xmlXPathCompareNodeSets: 6488 * @inf: less than (1) or greater than (0) 6489 * @strict: is the comparison strict 6490 * @arg1: the first node set object 6491 * @arg2: the second node set object 6492 * 6493 * Implement the compare operation on nodesets: 6494 * 6495 * If both objects to be compared are node-sets, then the comparison 6496 * will be true if and only if there is a node in the first node-set 6497 * and a node in the second node-set such that the result of performing 6498 * the comparison on the string-values of the two nodes is true. 6499 * .... 6500 * When neither object to be compared is a node-set and the operator 6501 * is <=, <, >= or >, then the objects are compared by converting both 6502 * objects to numbers and comparing the numbers according to IEEE 754. 6503 * .... 6504 * The number function converts its argument to a number as follows: 6505 * - a string that consists of optional whitespace followed by an 6506 * optional minus sign followed by a Number followed by whitespace 6507 * is converted to the IEEE 754 number that is nearest (according 6508 * to the IEEE 754 round-to-nearest rule) to the mathematical value 6509 * represented by the string; any other string is converted to NaN 6510 * 6511 * Conclusion all nodes need to be converted first to their string value 6512 * and then the comparison must be done when possible 6513 */ 6514 static int 6515 xmlXPathCompareNodeSets(int inf, int strict, 6516 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) { 6517 int i, j, init = 0; 6518 double val1; 6519 double *values2; 6520 int ret = 0; 6521 xmlNodeSetPtr ns1; 6522 xmlNodeSetPtr ns2; 6523 6524 if ((arg1 == NULL) || 6525 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) { 6526 xmlXPathFreeObject(arg2); 6527 return(0); 6528 } 6529 if ((arg2 == NULL) || 6530 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) { 6531 xmlXPathFreeObject(arg1); 6532 xmlXPathFreeObject(arg2); 6533 return(0); 6534 } 6535 6536 ns1 = arg1->nodesetval; 6537 ns2 = arg2->nodesetval; 6538 6539 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) { 6540 xmlXPathFreeObject(arg1); 6541 xmlXPathFreeObject(arg2); 6542 return(0); 6543 } 6544 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) { 6545 xmlXPathFreeObject(arg1); 6546 xmlXPathFreeObject(arg2); 6547 return(0); 6548 } 6549 6550 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double)); 6551 if (values2 == NULL) { 6552 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6553 xmlXPathFreeObject(arg1); 6554 xmlXPathFreeObject(arg2); 6555 return(0); 6556 } 6557 for (i = 0;i < ns1->nodeNr;i++) { 6558 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]); 6559 if (xmlXPathIsNaN(val1)) 6560 continue; 6561 for (j = 0;j < ns2->nodeNr;j++) { 6562 if (init == 0) { 6563 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]); 6564 } 6565 if (xmlXPathIsNaN(values2[j])) 6566 continue; 6567 if (inf && strict) 6568 ret = (val1 < values2[j]); 6569 else if (inf && !strict) 6570 ret = (val1 <= values2[j]); 6571 else if (!inf && strict) 6572 ret = (val1 > values2[j]); 6573 else if (!inf && !strict) 6574 ret = (val1 >= values2[j]); 6575 if (ret) 6576 break; 6577 } 6578 if (ret) 6579 break; 6580 init = 1; 6581 } 6582 xmlFree(values2); 6583 xmlXPathFreeObject(arg1); 6584 xmlXPathFreeObject(arg2); 6585 return(ret); 6586 } 6587 6588 /** 6589 * xmlXPathCompareNodeSetValue: 6590 * @ctxt: the XPath Parser context 6591 * @inf: less than (1) or greater than (0) 6592 * @strict: is the comparison strict 6593 * @arg: the node set 6594 * @val: the value 6595 * 6596 * Implement the compare operation between a nodeset and a value 6597 * @ns < @val (1, 1, ... 6598 * @ns <= @val (1, 0, ... 6599 * @ns > @val (0, 1, ... 6600 * @ns >= @val (0, 0, ... 6601 * 6602 * If one object to be compared is a node-set and the other is a boolean, 6603 * then the comparison will be true if and only if the result of performing 6604 * the comparison on the boolean and on the result of converting 6605 * the node-set to a boolean using the boolean function is true. 6606 * 6607 * Returns 0 or 1 depending on the results of the test. 6608 */ 6609 static int 6610 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict, 6611 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) { 6612 if ((val == NULL) || (arg == NULL) || 6613 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 6614 return(0); 6615 6616 switch(val->type) { 6617 case XPATH_NUMBER: 6618 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val)); 6619 case XPATH_NODESET: 6620 case XPATH_XSLT_TREE: 6621 return(xmlXPathCompareNodeSets(inf, strict, arg, val)); 6622 case XPATH_STRING: 6623 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val)); 6624 case XPATH_BOOLEAN: 6625 valuePush(ctxt, arg); 6626 xmlXPathBooleanFunction(ctxt, 1); 6627 valuePush(ctxt, val); 6628 return(xmlXPathCompareValues(ctxt, inf, strict)); 6629 default: 6630 TODO 6631 } 6632 return(0); 6633 } 6634 6635 /** 6636 * xmlXPathEqualNodeSetString: 6637 * @arg: the nodeset object argument 6638 * @str: the string to compare to. 6639 * @neq: flag to show whether for '=' (0) or '!=' (1) 6640 * 6641 * Implement the equal operation on XPath objects content: @arg1 == @arg2 6642 * If one object to be compared is a node-set and the other is a string, 6643 * then the comparison will be true if and only if there is a node in 6644 * the node-set such that the result of performing the comparison on the 6645 * string-value of the node and the other string is true. 6646 * 6647 * Returns 0 or 1 depending on the results of the test. 6648 */ 6649 static int 6650 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq) 6651 { 6652 int i; 6653 xmlNodeSetPtr ns; 6654 xmlChar *str2; 6655 unsigned int hash; 6656 6657 if ((str == NULL) || (arg == NULL) || 6658 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 6659 return (0); 6660 ns = arg->nodesetval; 6661 /* 6662 * A NULL nodeset compared with a string is always false 6663 * (since there is no node equal, and no node not equal) 6664 */ 6665 if ((ns == NULL) || (ns->nodeNr <= 0) ) 6666 return (0); 6667 hash = xmlXPathStringHash(str); 6668 for (i = 0; i < ns->nodeNr; i++) { 6669 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) { 6670 str2 = xmlNodeGetContent(ns->nodeTab[i]); 6671 if ((str2 != NULL) && (xmlStrEqual(str, str2))) { 6672 xmlFree(str2); 6673 if (neq) 6674 continue; 6675 return (1); 6676 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) { 6677 if (neq) 6678 continue; 6679 return (1); 6680 } else if (neq) { 6681 if (str2 != NULL) 6682 xmlFree(str2); 6683 return (1); 6684 } 6685 if (str2 != NULL) 6686 xmlFree(str2); 6687 } else if (neq) 6688 return (1); 6689 } 6690 return (0); 6691 } 6692 6693 /** 6694 * xmlXPathEqualNodeSetFloat: 6695 * @arg: the nodeset object argument 6696 * @f: the float to compare to 6697 * @neq: flag to show whether to compare '=' (0) or '!=' (1) 6698 * 6699 * Implement the equal operation on XPath objects content: @arg1 == @arg2 6700 * If one object to be compared is a node-set and the other is a number, 6701 * then the comparison will be true if and only if there is a node in 6702 * the node-set such that the result of performing the comparison on the 6703 * number to be compared and on the result of converting the string-value 6704 * of that node to a number using the number function is true. 6705 * 6706 * Returns 0 or 1 depending on the results of the test. 6707 */ 6708 static int 6709 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt, 6710 xmlXPathObjectPtr arg, double f, int neq) { 6711 int i, ret=0; 6712 xmlNodeSetPtr ns; 6713 xmlChar *str2; 6714 xmlXPathObjectPtr val; 6715 double v; 6716 6717 if ((arg == NULL) || 6718 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 6719 return(0); 6720 6721 ns = arg->nodesetval; 6722 if (ns != NULL) { 6723 for (i=0;i<ns->nodeNr;i++) { 6724 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 6725 if (str2 != NULL) { 6726 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2)); 6727 xmlFree(str2); 6728 xmlXPathNumberFunction(ctxt, 1); 6729 val = valuePop(ctxt); 6730 v = val->floatval; 6731 xmlXPathReleaseObject(ctxt->context, val); 6732 if (!xmlXPathIsNaN(v)) { 6733 if ((!neq) && (v==f)) { 6734 ret = 1; 6735 break; 6736 } else if ((neq) && (v!=f)) { 6737 ret = 1; 6738 break; 6739 } 6740 } else { /* NaN is unequal to any value */ 6741 if (neq) 6742 ret = 1; 6743 } 6744 } 6745 } 6746 } 6747 6748 return(ret); 6749 } 6750 6751 6752 /** 6753 * xmlXPathEqualNodeSets: 6754 * @arg1: first nodeset object argument 6755 * @arg2: second nodeset object argument 6756 * @neq: flag to show whether to test '=' (0) or '!=' (1) 6757 * 6758 * Implement the equal / not equal operation on XPath nodesets: 6759 * @arg1 == @arg2 or @arg1 != @arg2 6760 * If both objects to be compared are node-sets, then the comparison 6761 * will be true if and only if there is a node in the first node-set and 6762 * a node in the second node-set such that the result of performing the 6763 * comparison on the string-values of the two nodes is true. 6764 * 6765 * (needless to say, this is a costly operation) 6766 * 6767 * Returns 0 or 1 depending on the results of the test. 6768 */ 6769 static int 6770 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) { 6771 int i, j; 6772 unsigned int *hashs1; 6773 unsigned int *hashs2; 6774 xmlChar **values1; 6775 xmlChar **values2; 6776 int ret = 0; 6777 xmlNodeSetPtr ns1; 6778 xmlNodeSetPtr ns2; 6779 6780 if ((arg1 == NULL) || 6781 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) 6782 return(0); 6783 if ((arg2 == NULL) || 6784 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) 6785 return(0); 6786 6787 ns1 = arg1->nodesetval; 6788 ns2 = arg2->nodesetval; 6789 6790 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) 6791 return(0); 6792 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) 6793 return(0); 6794 6795 /* 6796 * for equal, check if there is a node pertaining to both sets 6797 */ 6798 if (neq == 0) 6799 for (i = 0;i < ns1->nodeNr;i++) 6800 for (j = 0;j < ns2->nodeNr;j++) 6801 if (ns1->nodeTab[i] == ns2->nodeTab[j]) 6802 return(1); 6803 6804 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *)); 6805 if (values1 == NULL) { 6806 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6807 return(0); 6808 } 6809 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int)); 6810 if (hashs1 == NULL) { 6811 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6812 xmlFree(values1); 6813 return(0); 6814 } 6815 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *)); 6816 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *)); 6817 if (values2 == NULL) { 6818 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6819 xmlFree(hashs1); 6820 xmlFree(values1); 6821 return(0); 6822 } 6823 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int)); 6824 if (hashs2 == NULL) { 6825 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6826 xmlFree(hashs1); 6827 xmlFree(values1); 6828 xmlFree(values2); 6829 return(0); 6830 } 6831 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *)); 6832 for (i = 0;i < ns1->nodeNr;i++) { 6833 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]); 6834 for (j = 0;j < ns2->nodeNr;j++) { 6835 if (i == 0) 6836 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]); 6837 if (hashs1[i] != hashs2[j]) { 6838 if (neq) { 6839 ret = 1; 6840 break; 6841 } 6842 } 6843 else { 6844 if (values1[i] == NULL) 6845 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]); 6846 if (values2[j] == NULL) 6847 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]); 6848 ret = xmlStrEqual(values1[i], values2[j]) ^ neq; 6849 if (ret) 6850 break; 6851 } 6852 } 6853 if (ret) 6854 break; 6855 } 6856 for (i = 0;i < ns1->nodeNr;i++) 6857 if (values1[i] != NULL) 6858 xmlFree(values1[i]); 6859 for (j = 0;j < ns2->nodeNr;j++) 6860 if (values2[j] != NULL) 6861 xmlFree(values2[j]); 6862 xmlFree(values1); 6863 xmlFree(values2); 6864 xmlFree(hashs1); 6865 xmlFree(hashs2); 6866 return(ret); 6867 } 6868 6869 static int 6870 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt, 6871 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) { 6872 int ret = 0; 6873 /* 6874 *At this point we are assured neither arg1 nor arg2 6875 *is a nodeset, so we can just pick the appropriate routine. 6876 */ 6877 switch (arg1->type) { 6878 case XPATH_UNDEFINED: 6879 #ifdef DEBUG_EXPR 6880 xmlGenericError(xmlGenericErrorContext, 6881 "Equal: undefined\n"); 6882 #endif 6883 break; 6884 case XPATH_BOOLEAN: 6885 switch (arg2->type) { 6886 case XPATH_UNDEFINED: 6887 #ifdef DEBUG_EXPR 6888 xmlGenericError(xmlGenericErrorContext, 6889 "Equal: undefined\n"); 6890 #endif 6891 break; 6892 case XPATH_BOOLEAN: 6893 #ifdef DEBUG_EXPR 6894 xmlGenericError(xmlGenericErrorContext, 6895 "Equal: %d boolean %d \n", 6896 arg1->boolval, arg2->boolval); 6897 #endif 6898 ret = (arg1->boolval == arg2->boolval); 6899 break; 6900 case XPATH_NUMBER: 6901 ret = (arg1->boolval == 6902 xmlXPathCastNumberToBoolean(arg2->floatval)); 6903 break; 6904 case XPATH_STRING: 6905 if ((arg2->stringval == NULL) || 6906 (arg2->stringval[0] == 0)) ret = 0; 6907 else 6908 ret = 1; 6909 ret = (arg1->boolval == ret); 6910 break; 6911 case XPATH_USERS: 6912 case XPATH_POINT: 6913 case XPATH_RANGE: 6914 case XPATH_LOCATIONSET: 6915 TODO 6916 break; 6917 case XPATH_NODESET: 6918 case XPATH_XSLT_TREE: 6919 break; 6920 } 6921 break; 6922 case XPATH_NUMBER: 6923 switch (arg2->type) { 6924 case XPATH_UNDEFINED: 6925 #ifdef DEBUG_EXPR 6926 xmlGenericError(xmlGenericErrorContext, 6927 "Equal: undefined\n"); 6928 #endif 6929 break; 6930 case XPATH_BOOLEAN: 6931 ret = (arg2->boolval== 6932 xmlXPathCastNumberToBoolean(arg1->floatval)); 6933 break; 6934 case XPATH_STRING: 6935 valuePush(ctxt, arg2); 6936 xmlXPathNumberFunction(ctxt, 1); 6937 arg2 = valuePop(ctxt); 6938 /* no break on purpose */ 6939 case XPATH_NUMBER: 6940 /* Hand check NaN and Infinity equalities */ 6941 if (xmlXPathIsNaN(arg1->floatval) || 6942 xmlXPathIsNaN(arg2->floatval)) { 6943 ret = 0; 6944 } else if (xmlXPathIsInf(arg1->floatval) == 1) { 6945 if (xmlXPathIsInf(arg2->floatval) == 1) 6946 ret = 1; 6947 else 6948 ret = 0; 6949 } else if (xmlXPathIsInf(arg1->floatval) == -1) { 6950 if (xmlXPathIsInf(arg2->floatval) == -1) 6951 ret = 1; 6952 else 6953 ret = 0; 6954 } else if (xmlXPathIsInf(arg2->floatval) == 1) { 6955 if (xmlXPathIsInf(arg1->floatval) == 1) 6956 ret = 1; 6957 else 6958 ret = 0; 6959 } else if (xmlXPathIsInf(arg2->floatval) == -1) { 6960 if (xmlXPathIsInf(arg1->floatval) == -1) 6961 ret = 1; 6962 else 6963 ret = 0; 6964 } else { 6965 ret = (arg1->floatval == arg2->floatval); 6966 } 6967 break; 6968 case XPATH_USERS: 6969 case XPATH_POINT: 6970 case XPATH_RANGE: 6971 case XPATH_LOCATIONSET: 6972 TODO 6973 break; 6974 case XPATH_NODESET: 6975 case XPATH_XSLT_TREE: 6976 break; 6977 } 6978 break; 6979 case XPATH_STRING: 6980 switch (arg2->type) { 6981 case XPATH_UNDEFINED: 6982 #ifdef DEBUG_EXPR 6983 xmlGenericError(xmlGenericErrorContext, 6984 "Equal: undefined\n"); 6985 #endif 6986 break; 6987 case XPATH_BOOLEAN: 6988 if ((arg1->stringval == NULL) || 6989 (arg1->stringval[0] == 0)) ret = 0; 6990 else 6991 ret = 1; 6992 ret = (arg2->boolval == ret); 6993 break; 6994 case XPATH_STRING: 6995 ret = xmlStrEqual(arg1->stringval, arg2->stringval); 6996 break; 6997 case XPATH_NUMBER: 6998 valuePush(ctxt, arg1); 6999 xmlXPathNumberFunction(ctxt, 1); 7000 arg1 = valuePop(ctxt); 7001 /* Hand check NaN and Infinity equalities */ 7002 if (xmlXPathIsNaN(arg1->floatval) || 7003 xmlXPathIsNaN(arg2->floatval)) { 7004 ret = 0; 7005 } else if (xmlXPathIsInf(arg1->floatval) == 1) { 7006 if (xmlXPathIsInf(arg2->floatval) == 1) 7007 ret = 1; 7008 else 7009 ret = 0; 7010 } else if (xmlXPathIsInf(arg1->floatval) == -1) { 7011 if (xmlXPathIsInf(arg2->floatval) == -1) 7012 ret = 1; 7013 else 7014 ret = 0; 7015 } else if (xmlXPathIsInf(arg2->floatval) == 1) { 7016 if (xmlXPathIsInf(arg1->floatval) == 1) 7017 ret = 1; 7018 else 7019 ret = 0; 7020 } else if (xmlXPathIsInf(arg2->floatval) == -1) { 7021 if (xmlXPathIsInf(arg1->floatval) == -1) 7022 ret = 1; 7023 else 7024 ret = 0; 7025 } else { 7026 ret = (arg1->floatval == arg2->floatval); 7027 } 7028 break; 7029 case XPATH_USERS: 7030 case XPATH_POINT: 7031 case XPATH_RANGE: 7032 case XPATH_LOCATIONSET: 7033 TODO 7034 break; 7035 case XPATH_NODESET: 7036 case XPATH_XSLT_TREE: 7037 break; 7038 } 7039 break; 7040 case XPATH_USERS: 7041 case XPATH_POINT: 7042 case XPATH_RANGE: 7043 case XPATH_LOCATIONSET: 7044 TODO 7045 break; 7046 case XPATH_NODESET: 7047 case XPATH_XSLT_TREE: 7048 break; 7049 } 7050 xmlXPathReleaseObject(ctxt->context, arg1); 7051 xmlXPathReleaseObject(ctxt->context, arg2); 7052 return(ret); 7053 } 7054 7055 /** 7056 * xmlXPathEqualValues: 7057 * @ctxt: the XPath Parser context 7058 * 7059 * Implement the equal operation on XPath objects content: @arg1 == @arg2 7060 * 7061 * Returns 0 or 1 depending on the results of the test. 7062 */ 7063 int 7064 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) { 7065 xmlXPathObjectPtr arg1, arg2, argtmp; 7066 int ret = 0; 7067 7068 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); 7069 arg2 = valuePop(ctxt); 7070 arg1 = valuePop(ctxt); 7071 if ((arg1 == NULL) || (arg2 == NULL)) { 7072 if (arg1 != NULL) 7073 xmlXPathReleaseObject(ctxt->context, arg1); 7074 else 7075 xmlXPathReleaseObject(ctxt->context, arg2); 7076 XP_ERROR0(XPATH_INVALID_OPERAND); 7077 } 7078 7079 if (arg1 == arg2) { 7080 #ifdef DEBUG_EXPR 7081 xmlGenericError(xmlGenericErrorContext, 7082 "Equal: by pointer\n"); 7083 #endif 7084 xmlXPathFreeObject(arg1); 7085 return(1); 7086 } 7087 7088 /* 7089 *If either argument is a nodeset, it's a 'special case' 7090 */ 7091 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 7092 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7093 /* 7094 *Hack it to assure arg1 is the nodeset 7095 */ 7096 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) { 7097 argtmp = arg2; 7098 arg2 = arg1; 7099 arg1 = argtmp; 7100 } 7101 switch (arg2->type) { 7102 case XPATH_UNDEFINED: 7103 #ifdef DEBUG_EXPR 7104 xmlGenericError(xmlGenericErrorContext, 7105 "Equal: undefined\n"); 7106 #endif 7107 break; 7108 case XPATH_NODESET: 7109 case XPATH_XSLT_TREE: 7110 ret = xmlXPathEqualNodeSets(arg1, arg2, 0); 7111 break; 7112 case XPATH_BOOLEAN: 7113 if ((arg1->nodesetval == NULL) || 7114 (arg1->nodesetval->nodeNr == 0)) ret = 0; 7115 else 7116 ret = 1; 7117 ret = (ret == arg2->boolval); 7118 break; 7119 case XPATH_NUMBER: 7120 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0); 7121 break; 7122 case XPATH_STRING: 7123 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0); 7124 break; 7125 case XPATH_USERS: 7126 case XPATH_POINT: 7127 case XPATH_RANGE: 7128 case XPATH_LOCATIONSET: 7129 TODO 7130 break; 7131 } 7132 xmlXPathReleaseObject(ctxt->context, arg1); 7133 xmlXPathReleaseObject(ctxt->context, arg2); 7134 return(ret); 7135 } 7136 7137 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2)); 7138 } 7139 7140 /** 7141 * xmlXPathNotEqualValues: 7142 * @ctxt: the XPath Parser context 7143 * 7144 * Implement the equal operation on XPath objects content: @arg1 == @arg2 7145 * 7146 * Returns 0 or 1 depending on the results of the test. 7147 */ 7148 int 7149 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) { 7150 xmlXPathObjectPtr arg1, arg2, argtmp; 7151 int ret = 0; 7152 7153 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); 7154 arg2 = valuePop(ctxt); 7155 arg1 = valuePop(ctxt); 7156 if ((arg1 == NULL) || (arg2 == NULL)) { 7157 if (arg1 != NULL) 7158 xmlXPathReleaseObject(ctxt->context, arg1); 7159 else 7160 xmlXPathReleaseObject(ctxt->context, arg2); 7161 XP_ERROR0(XPATH_INVALID_OPERAND); 7162 } 7163 7164 if (arg1 == arg2) { 7165 #ifdef DEBUG_EXPR 7166 xmlGenericError(xmlGenericErrorContext, 7167 "NotEqual: by pointer\n"); 7168 #endif 7169 xmlXPathReleaseObject(ctxt->context, arg1); 7170 return(0); 7171 } 7172 7173 /* 7174 *If either argument is a nodeset, it's a 'special case' 7175 */ 7176 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 7177 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7178 /* 7179 *Hack it to assure arg1 is the nodeset 7180 */ 7181 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) { 7182 argtmp = arg2; 7183 arg2 = arg1; 7184 arg1 = argtmp; 7185 } 7186 switch (arg2->type) { 7187 case XPATH_UNDEFINED: 7188 #ifdef DEBUG_EXPR 7189 xmlGenericError(xmlGenericErrorContext, 7190 "NotEqual: undefined\n"); 7191 #endif 7192 break; 7193 case XPATH_NODESET: 7194 case XPATH_XSLT_TREE: 7195 ret = xmlXPathEqualNodeSets(arg1, arg2, 1); 7196 break; 7197 case XPATH_BOOLEAN: 7198 if ((arg1->nodesetval == NULL) || 7199 (arg1->nodesetval->nodeNr == 0)) ret = 0; 7200 else 7201 ret = 1; 7202 ret = (ret != arg2->boolval); 7203 break; 7204 case XPATH_NUMBER: 7205 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1); 7206 break; 7207 case XPATH_STRING: 7208 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1); 7209 break; 7210 case XPATH_USERS: 7211 case XPATH_POINT: 7212 case XPATH_RANGE: 7213 case XPATH_LOCATIONSET: 7214 TODO 7215 break; 7216 } 7217 xmlXPathReleaseObject(ctxt->context, arg1); 7218 xmlXPathReleaseObject(ctxt->context, arg2); 7219 return(ret); 7220 } 7221 7222 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2)); 7223 } 7224 7225 /** 7226 * xmlXPathCompareValues: 7227 * @ctxt: the XPath Parser context 7228 * @inf: less than (1) or greater than (0) 7229 * @strict: is the comparison strict 7230 * 7231 * Implement the compare operation on XPath objects: 7232 * @arg1 < @arg2 (1, 1, ... 7233 * @arg1 <= @arg2 (1, 0, ... 7234 * @arg1 > @arg2 (0, 1, ... 7235 * @arg1 >= @arg2 (0, 0, ... 7236 * 7237 * When neither object to be compared is a node-set and the operator is 7238 * <=, <, >=, >, then the objects are compared by converted both objects 7239 * to numbers and comparing the numbers according to IEEE 754. The < 7240 * comparison will be true if and only if the first number is less than the 7241 * second number. The <= comparison will be true if and only if the first 7242 * number is less than or equal to the second number. The > comparison 7243 * will be true if and only if the first number is greater than the second 7244 * number. The >= comparison will be true if and only if the first number 7245 * is greater than or equal to the second number. 7246 * 7247 * Returns 1 if the comparison succeeded, 0 if it failed 7248 */ 7249 int 7250 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) { 7251 int ret = 0, arg1i = 0, arg2i = 0; 7252 xmlXPathObjectPtr arg1, arg2; 7253 7254 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); 7255 arg2 = valuePop(ctxt); 7256 arg1 = valuePop(ctxt); 7257 if ((arg1 == NULL) || (arg2 == NULL)) { 7258 if (arg1 != NULL) 7259 xmlXPathReleaseObject(ctxt->context, arg1); 7260 else 7261 xmlXPathReleaseObject(ctxt->context, arg2); 7262 XP_ERROR0(XPATH_INVALID_OPERAND); 7263 } 7264 7265 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 7266 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7267 /* 7268 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments 7269 * are not freed from within this routine; they will be freed from the 7270 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue 7271 */ 7272 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) && 7273 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){ 7274 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2); 7275 } else { 7276 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7277 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict, 7278 arg1, arg2); 7279 } else { 7280 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict, 7281 arg2, arg1); 7282 } 7283 } 7284 return(ret); 7285 } 7286 7287 if (arg1->type != XPATH_NUMBER) { 7288 valuePush(ctxt, arg1); 7289 xmlXPathNumberFunction(ctxt, 1); 7290 arg1 = valuePop(ctxt); 7291 } 7292 if (arg1->type != XPATH_NUMBER) { 7293 xmlXPathFreeObject(arg1); 7294 xmlXPathFreeObject(arg2); 7295 XP_ERROR0(XPATH_INVALID_OPERAND); 7296 } 7297 if (arg2->type != XPATH_NUMBER) { 7298 valuePush(ctxt, arg2); 7299 xmlXPathNumberFunction(ctxt, 1); 7300 arg2 = valuePop(ctxt); 7301 } 7302 if (arg2->type != XPATH_NUMBER) { 7303 xmlXPathReleaseObject(ctxt->context, arg1); 7304 xmlXPathReleaseObject(ctxt->context, arg2); 7305 XP_ERROR0(XPATH_INVALID_OPERAND); 7306 } 7307 /* 7308 * Add tests for infinity and nan 7309 * => feedback on 3.4 for Inf and NaN 7310 */ 7311 /* Hand check NaN and Infinity comparisons */ 7312 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) { 7313 ret=0; 7314 } else { 7315 arg1i=xmlXPathIsInf(arg1->floatval); 7316 arg2i=xmlXPathIsInf(arg2->floatval); 7317 if (inf && strict) { 7318 if ((arg1i == -1 && arg2i != -1) || 7319 (arg2i == 1 && arg1i != 1)) { 7320 ret = 1; 7321 } else if (arg1i == 0 && arg2i == 0) { 7322 ret = (arg1->floatval < arg2->floatval); 7323 } else { 7324 ret = 0; 7325 } 7326 } 7327 else if (inf && !strict) { 7328 if (arg1i == -1 || arg2i == 1) { 7329 ret = 1; 7330 } else if (arg1i == 0 && arg2i == 0) { 7331 ret = (arg1->floatval <= arg2->floatval); 7332 } else { 7333 ret = 0; 7334 } 7335 } 7336 else if (!inf && strict) { 7337 if ((arg1i == 1 && arg2i != 1) || 7338 (arg2i == -1 && arg1i != -1)) { 7339 ret = 1; 7340 } else if (arg1i == 0 && arg2i == 0) { 7341 ret = (arg1->floatval > arg2->floatval); 7342 } else { 7343 ret = 0; 7344 } 7345 } 7346 else if (!inf && !strict) { 7347 if (arg1i == 1 || arg2i == -1) { 7348 ret = 1; 7349 } else if (arg1i == 0 && arg2i == 0) { 7350 ret = (arg1->floatval >= arg2->floatval); 7351 } else { 7352 ret = 0; 7353 } 7354 } 7355 } 7356 xmlXPathReleaseObject(ctxt->context, arg1); 7357 xmlXPathReleaseObject(ctxt->context, arg2); 7358 return(ret); 7359 } 7360 7361 /** 7362 * xmlXPathValueFlipSign: 7363 * @ctxt: the XPath Parser context 7364 * 7365 * Implement the unary - operation on an XPath object 7366 * The numeric operators convert their operands to numbers as if 7367 * by calling the number function. 7368 */ 7369 void 7370 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) { 7371 if ((ctxt == NULL) || (ctxt->context == NULL)) return; 7372 CAST_TO_NUMBER; 7373 CHECK_TYPE(XPATH_NUMBER); 7374 if (xmlXPathIsNaN(ctxt->value->floatval)) 7375 ctxt->value->floatval=xmlXPathNAN; 7376 else if (xmlXPathIsInf(ctxt->value->floatval) == 1) 7377 ctxt->value->floatval=xmlXPathNINF; 7378 else if (xmlXPathIsInf(ctxt->value->floatval) == -1) 7379 ctxt->value->floatval=xmlXPathPINF; 7380 else if (ctxt->value->floatval == 0) { 7381 if (xmlXPathGetSign(ctxt->value->floatval) == 0) 7382 ctxt->value->floatval = xmlXPathNZERO; 7383 else 7384 ctxt->value->floatval = 0; 7385 } 7386 else 7387 ctxt->value->floatval = - ctxt->value->floatval; 7388 } 7389 7390 /** 7391 * xmlXPathAddValues: 7392 * @ctxt: the XPath Parser context 7393 * 7394 * Implement the add operation on XPath objects: 7395 * The numeric operators convert their operands to numbers as if 7396 * by calling the number function. 7397 */ 7398 void 7399 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) { 7400 xmlXPathObjectPtr arg; 7401 double val; 7402 7403 arg = valuePop(ctxt); 7404 if (arg == NULL) 7405 XP_ERROR(XPATH_INVALID_OPERAND); 7406 val = xmlXPathCastToNumber(arg); 7407 xmlXPathReleaseObject(ctxt->context, arg); 7408 CAST_TO_NUMBER; 7409 CHECK_TYPE(XPATH_NUMBER); 7410 ctxt->value->floatval += val; 7411 } 7412 7413 /** 7414 * xmlXPathSubValues: 7415 * @ctxt: the XPath Parser context 7416 * 7417 * Implement the subtraction operation on XPath objects: 7418 * The numeric operators convert their operands to numbers as if 7419 * by calling the number function. 7420 */ 7421 void 7422 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) { 7423 xmlXPathObjectPtr arg; 7424 double val; 7425 7426 arg = valuePop(ctxt); 7427 if (arg == NULL) 7428 XP_ERROR(XPATH_INVALID_OPERAND); 7429 val = xmlXPathCastToNumber(arg); 7430 xmlXPathReleaseObject(ctxt->context, arg); 7431 CAST_TO_NUMBER; 7432 CHECK_TYPE(XPATH_NUMBER); 7433 ctxt->value->floatval -= val; 7434 } 7435 7436 /** 7437 * xmlXPathMultValues: 7438 * @ctxt: the XPath Parser context 7439 * 7440 * Implement the multiply operation on XPath objects: 7441 * The numeric operators convert their operands to numbers as if 7442 * by calling the number function. 7443 */ 7444 void 7445 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) { 7446 xmlXPathObjectPtr arg; 7447 double val; 7448 7449 arg = valuePop(ctxt); 7450 if (arg == NULL) 7451 XP_ERROR(XPATH_INVALID_OPERAND); 7452 val = xmlXPathCastToNumber(arg); 7453 xmlXPathReleaseObject(ctxt->context, arg); 7454 CAST_TO_NUMBER; 7455 CHECK_TYPE(XPATH_NUMBER); 7456 ctxt->value->floatval *= val; 7457 } 7458 7459 /** 7460 * xmlXPathDivValues: 7461 * @ctxt: the XPath Parser context 7462 * 7463 * Implement the div operation on XPath objects @arg1 / @arg2: 7464 * The numeric operators convert their operands to numbers as if 7465 * by calling the number function. 7466 */ 7467 void 7468 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) { 7469 xmlXPathObjectPtr arg; 7470 double val; 7471 7472 arg = valuePop(ctxt); 7473 if (arg == NULL) 7474 XP_ERROR(XPATH_INVALID_OPERAND); 7475 val = xmlXPathCastToNumber(arg); 7476 xmlXPathReleaseObject(ctxt->context, arg); 7477 CAST_TO_NUMBER; 7478 CHECK_TYPE(XPATH_NUMBER); 7479 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval)) 7480 ctxt->value->floatval = xmlXPathNAN; 7481 else if (val == 0 && xmlXPathGetSign(val) != 0) { 7482 if (ctxt->value->floatval == 0) 7483 ctxt->value->floatval = xmlXPathNAN; 7484 else if (ctxt->value->floatval > 0) 7485 ctxt->value->floatval = xmlXPathNINF; 7486 else if (ctxt->value->floatval < 0) 7487 ctxt->value->floatval = xmlXPathPINF; 7488 } 7489 else if (val == 0) { 7490 if (ctxt->value->floatval == 0) 7491 ctxt->value->floatval = xmlXPathNAN; 7492 else if (ctxt->value->floatval > 0) 7493 ctxt->value->floatval = xmlXPathPINF; 7494 else if (ctxt->value->floatval < 0) 7495 ctxt->value->floatval = xmlXPathNINF; 7496 } else 7497 ctxt->value->floatval /= val; 7498 } 7499 7500 /** 7501 * xmlXPathModValues: 7502 * @ctxt: the XPath Parser context 7503 * 7504 * Implement the mod operation on XPath objects: @arg1 / @arg2 7505 * The numeric operators convert their operands to numbers as if 7506 * by calling the number function. 7507 */ 7508 void 7509 xmlXPathModValues(xmlXPathParserContextPtr ctxt) { 7510 xmlXPathObjectPtr arg; 7511 double arg1, arg2; 7512 7513 arg = valuePop(ctxt); 7514 if (arg == NULL) 7515 XP_ERROR(XPATH_INVALID_OPERAND); 7516 arg2 = xmlXPathCastToNumber(arg); 7517 xmlXPathReleaseObject(ctxt->context, arg); 7518 CAST_TO_NUMBER; 7519 CHECK_TYPE(XPATH_NUMBER); 7520 arg1 = ctxt->value->floatval; 7521 if (arg2 == 0) 7522 ctxt->value->floatval = xmlXPathNAN; 7523 else { 7524 ctxt->value->floatval = fmod(arg1, arg2); 7525 } 7526 } 7527 7528 /************************************************************************ 7529 * * 7530 * The traversal functions * 7531 * * 7532 ************************************************************************/ 7533 7534 /* 7535 * A traversal function enumerates nodes along an axis. 7536 * Initially it must be called with NULL, and it indicates 7537 * termination on the axis by returning NULL. 7538 */ 7539 typedef xmlNodePtr (*xmlXPathTraversalFunction) 7540 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur); 7541 7542 /* 7543 * xmlXPathTraversalFunctionExt: 7544 * A traversal function enumerates nodes along an axis. 7545 * Initially it must be called with NULL, and it indicates 7546 * termination on the axis by returning NULL. 7547 * The context node of the traversal is specified via @contextNode. 7548 */ 7549 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt) 7550 (xmlNodePtr cur, xmlNodePtr contextNode); 7551 7552 /* 7553 * xmlXPathNodeSetMergeFunction: 7554 * Used for merging node sets in xmlXPathCollectAndTest(). 7555 */ 7556 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction) 7557 (xmlNodeSetPtr, xmlNodeSetPtr, int); 7558 7559 7560 /** 7561 * xmlXPathNextSelf: 7562 * @ctxt: the XPath Parser context 7563 * @cur: the current node in the traversal 7564 * 7565 * Traversal function for the "self" direction 7566 * The self axis contains just the context node itself 7567 * 7568 * Returns the next element following that axis 7569 */ 7570 xmlNodePtr 7571 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7572 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7573 if (cur == NULL) 7574 return(ctxt->context->node); 7575 return(NULL); 7576 } 7577 7578 /** 7579 * xmlXPathNextChild: 7580 * @ctxt: the XPath Parser context 7581 * @cur: the current node in the traversal 7582 * 7583 * Traversal function for the "child" direction 7584 * The child axis contains the children of the context node in document order. 7585 * 7586 * Returns the next element following that axis 7587 */ 7588 xmlNodePtr 7589 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7590 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7591 if (cur == NULL) { 7592 if (ctxt->context->node == NULL) return(NULL); 7593 switch (ctxt->context->node->type) { 7594 case XML_ELEMENT_NODE: 7595 case XML_TEXT_NODE: 7596 case XML_CDATA_SECTION_NODE: 7597 case XML_ENTITY_REF_NODE: 7598 case XML_ENTITY_NODE: 7599 case XML_PI_NODE: 7600 case XML_COMMENT_NODE: 7601 case XML_NOTATION_NODE: 7602 case XML_DTD_NODE: 7603 return(ctxt->context->node->children); 7604 case XML_DOCUMENT_NODE: 7605 case XML_DOCUMENT_TYPE_NODE: 7606 case XML_DOCUMENT_FRAG_NODE: 7607 case XML_HTML_DOCUMENT_NODE: 7608 #ifdef LIBXML_DOCB_ENABLED 7609 case XML_DOCB_DOCUMENT_NODE: 7610 #endif 7611 return(((xmlDocPtr) ctxt->context->node)->children); 7612 case XML_ELEMENT_DECL: 7613 case XML_ATTRIBUTE_DECL: 7614 case XML_ENTITY_DECL: 7615 case XML_ATTRIBUTE_NODE: 7616 case XML_NAMESPACE_DECL: 7617 case XML_XINCLUDE_START: 7618 case XML_XINCLUDE_END: 7619 return(NULL); 7620 } 7621 return(NULL); 7622 } 7623 if ((cur->type == XML_DOCUMENT_NODE) || 7624 (cur->type == XML_HTML_DOCUMENT_NODE)) 7625 return(NULL); 7626 return(cur->next); 7627 } 7628 7629 /** 7630 * xmlXPathNextChildElement: 7631 * @ctxt: the XPath Parser context 7632 * @cur: the current node in the traversal 7633 * 7634 * Traversal function for the "child" direction and nodes of type element. 7635 * The child axis contains the children of the context node in document order. 7636 * 7637 * Returns the next element following that axis 7638 */ 7639 static xmlNodePtr 7640 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7641 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7642 if (cur == NULL) { 7643 cur = ctxt->context->node; 7644 if (cur == NULL) return(NULL); 7645 /* 7646 * Get the first element child. 7647 */ 7648 switch (cur->type) { 7649 case XML_ELEMENT_NODE: 7650 case XML_DOCUMENT_FRAG_NODE: 7651 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */ 7652 case XML_ENTITY_NODE: 7653 cur = cur->children; 7654 if (cur != NULL) { 7655 if (cur->type == XML_ELEMENT_NODE) 7656 return(cur); 7657 do { 7658 cur = cur->next; 7659 } while ((cur != NULL) && 7660 (cur->type != XML_ELEMENT_NODE)); 7661 return(cur); 7662 } 7663 return(NULL); 7664 case XML_DOCUMENT_NODE: 7665 case XML_HTML_DOCUMENT_NODE: 7666 #ifdef LIBXML_DOCB_ENABLED 7667 case XML_DOCB_DOCUMENT_NODE: 7668 #endif 7669 return(xmlDocGetRootElement((xmlDocPtr) cur)); 7670 default: 7671 return(NULL); 7672 } 7673 return(NULL); 7674 } 7675 /* 7676 * Get the next sibling element node. 7677 */ 7678 switch (cur->type) { 7679 case XML_ELEMENT_NODE: 7680 case XML_TEXT_NODE: 7681 case XML_ENTITY_REF_NODE: 7682 case XML_ENTITY_NODE: 7683 case XML_CDATA_SECTION_NODE: 7684 case XML_PI_NODE: 7685 case XML_COMMENT_NODE: 7686 case XML_XINCLUDE_END: 7687 break; 7688 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */ 7689 default: 7690 return(NULL); 7691 } 7692 if (cur->next != NULL) { 7693 if (cur->next->type == XML_ELEMENT_NODE) 7694 return(cur->next); 7695 cur = cur->next; 7696 do { 7697 cur = cur->next; 7698 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE)); 7699 return(cur); 7700 } 7701 return(NULL); 7702 } 7703 7704 /** 7705 * xmlXPathNextDescendantOrSelfElemParent: 7706 * @ctxt: the XPath Parser context 7707 * @cur: the current node in the traversal 7708 * 7709 * Traversal function for the "descendant-or-self" axis. 7710 * Additionally it returns only nodes which can be parents of 7711 * element nodes. 7712 * 7713 * 7714 * Returns the next element following that axis 7715 */ 7716 static xmlNodePtr 7717 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur, 7718 xmlNodePtr contextNode) 7719 { 7720 if (cur == NULL) { 7721 if (contextNode == NULL) 7722 return(NULL); 7723 switch (contextNode->type) { 7724 case XML_ELEMENT_NODE: 7725 case XML_XINCLUDE_START: 7726 case XML_DOCUMENT_FRAG_NODE: 7727 case XML_DOCUMENT_NODE: 7728 #ifdef LIBXML_DOCB_ENABLED 7729 case XML_DOCB_DOCUMENT_NODE: 7730 #endif 7731 case XML_HTML_DOCUMENT_NODE: 7732 return(contextNode); 7733 default: 7734 return(NULL); 7735 } 7736 return(NULL); 7737 } else { 7738 xmlNodePtr start = cur; 7739 7740 while (cur != NULL) { 7741 switch (cur->type) { 7742 case XML_ELEMENT_NODE: 7743 /* TODO: OK to have XInclude here? */ 7744 case XML_XINCLUDE_START: 7745 case XML_DOCUMENT_FRAG_NODE: 7746 if (cur != start) 7747 return(cur); 7748 if (cur->children != NULL) { 7749 cur = cur->children; 7750 continue; 7751 } 7752 break; 7753 /* Not sure if we need those here. */ 7754 case XML_DOCUMENT_NODE: 7755 #ifdef LIBXML_DOCB_ENABLED 7756 case XML_DOCB_DOCUMENT_NODE: 7757 #endif 7758 case XML_HTML_DOCUMENT_NODE: 7759 if (cur != start) 7760 return(cur); 7761 return(xmlDocGetRootElement((xmlDocPtr) cur)); 7762 default: 7763 break; 7764 } 7765 7766 next_sibling: 7767 if ((cur == NULL) || (cur == contextNode)) 7768 return(NULL); 7769 if (cur->next != NULL) { 7770 cur = cur->next; 7771 } else { 7772 cur = cur->parent; 7773 goto next_sibling; 7774 } 7775 } 7776 } 7777 return(NULL); 7778 } 7779 7780 /** 7781 * xmlXPathNextDescendant: 7782 * @ctxt: the XPath Parser context 7783 * @cur: the current node in the traversal 7784 * 7785 * Traversal function for the "descendant" direction 7786 * the descendant axis contains the descendants of the context node in document 7787 * order; a descendant is a child or a child of a child and so on. 7788 * 7789 * Returns the next element following that axis 7790 */ 7791 xmlNodePtr 7792 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7793 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7794 if (cur == NULL) { 7795 if (ctxt->context->node == NULL) 7796 return(NULL); 7797 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 7798 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 7799 return(NULL); 7800 7801 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc) 7802 return(ctxt->context->doc->children); 7803 return(ctxt->context->node->children); 7804 } 7805 7806 if (cur->children != NULL) { 7807 /* 7808 * Do not descend on entities declarations 7809 */ 7810 if (cur->children->type != XML_ENTITY_DECL) { 7811 cur = cur->children; 7812 /* 7813 * Skip DTDs 7814 */ 7815 if (cur->type != XML_DTD_NODE) 7816 return(cur); 7817 } 7818 } 7819 7820 if (cur == ctxt->context->node) return(NULL); 7821 7822 while (cur->next != NULL) { 7823 cur = cur->next; 7824 if ((cur->type != XML_ENTITY_DECL) && 7825 (cur->type != XML_DTD_NODE)) 7826 return(cur); 7827 } 7828 7829 do { 7830 cur = cur->parent; 7831 if (cur == NULL) break; 7832 if (cur == ctxt->context->node) return(NULL); 7833 if (cur->next != NULL) { 7834 cur = cur->next; 7835 return(cur); 7836 } 7837 } while (cur != NULL); 7838 return(cur); 7839 } 7840 7841 /** 7842 * xmlXPathNextDescendantOrSelf: 7843 * @ctxt: the XPath Parser context 7844 * @cur: the current node in the traversal 7845 * 7846 * Traversal function for the "descendant-or-self" direction 7847 * the descendant-or-self axis contains the context node and the descendants 7848 * of the context node in document order; thus the context node is the first 7849 * node on the axis, and the first child of the context node is the second node 7850 * on the axis 7851 * 7852 * Returns the next element following that axis 7853 */ 7854 xmlNodePtr 7855 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7856 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7857 if (cur == NULL) { 7858 if (ctxt->context->node == NULL) 7859 return(NULL); 7860 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 7861 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 7862 return(NULL); 7863 return(ctxt->context->node); 7864 } 7865 7866 return(xmlXPathNextDescendant(ctxt, cur)); 7867 } 7868 7869 /** 7870 * xmlXPathNextParent: 7871 * @ctxt: the XPath Parser context 7872 * @cur: the current node in the traversal 7873 * 7874 * Traversal function for the "parent" direction 7875 * The parent axis contains the parent of the context node, if there is one. 7876 * 7877 * Returns the next element following that axis 7878 */ 7879 xmlNodePtr 7880 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7881 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7882 /* 7883 * the parent of an attribute or namespace node is the element 7884 * to which the attribute or namespace node is attached 7885 * Namespace handling !!! 7886 */ 7887 if (cur == NULL) { 7888 if (ctxt->context->node == NULL) return(NULL); 7889 switch (ctxt->context->node->type) { 7890 case XML_ELEMENT_NODE: 7891 case XML_TEXT_NODE: 7892 case XML_CDATA_SECTION_NODE: 7893 case XML_ENTITY_REF_NODE: 7894 case XML_ENTITY_NODE: 7895 case XML_PI_NODE: 7896 case XML_COMMENT_NODE: 7897 case XML_NOTATION_NODE: 7898 case XML_DTD_NODE: 7899 case XML_ELEMENT_DECL: 7900 case XML_ATTRIBUTE_DECL: 7901 case XML_XINCLUDE_START: 7902 case XML_XINCLUDE_END: 7903 case XML_ENTITY_DECL: 7904 if (ctxt->context->node->parent == NULL) 7905 return((xmlNodePtr) ctxt->context->doc); 7906 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) && 7907 ((ctxt->context->node->parent->name[0] == ' ') || 7908 (xmlStrEqual(ctxt->context->node->parent->name, 7909 BAD_CAST "fake node libxslt")))) 7910 return(NULL); 7911 return(ctxt->context->node->parent); 7912 case XML_ATTRIBUTE_NODE: { 7913 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node; 7914 7915 return(att->parent); 7916 } 7917 case XML_DOCUMENT_NODE: 7918 case XML_DOCUMENT_TYPE_NODE: 7919 case XML_DOCUMENT_FRAG_NODE: 7920 case XML_HTML_DOCUMENT_NODE: 7921 #ifdef LIBXML_DOCB_ENABLED 7922 case XML_DOCB_DOCUMENT_NODE: 7923 #endif 7924 return(NULL); 7925 case XML_NAMESPACE_DECL: { 7926 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; 7927 7928 if ((ns->next != NULL) && 7929 (ns->next->type != XML_NAMESPACE_DECL)) 7930 return((xmlNodePtr) ns->next); 7931 return(NULL); 7932 } 7933 } 7934 } 7935 return(NULL); 7936 } 7937 7938 /** 7939 * xmlXPathNextAncestor: 7940 * @ctxt: the XPath Parser context 7941 * @cur: the current node in the traversal 7942 * 7943 * Traversal function for the "ancestor" direction 7944 * the ancestor axis contains the ancestors of the context node; the ancestors 7945 * of the context node consist of the parent of context node and the parent's 7946 * parent and so on; the nodes are ordered in reverse document order; thus the 7947 * parent is the first node on the axis, and the parent's parent is the second 7948 * node on the axis 7949 * 7950 * Returns the next element following that axis 7951 */ 7952 xmlNodePtr 7953 xmlXPathNextAncestor(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 * !!!!!!!!!!!!! 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_DTD_NODE: 7971 case XML_ELEMENT_DECL: 7972 case XML_ATTRIBUTE_DECL: 7973 case XML_ENTITY_DECL: 7974 case XML_NOTATION_NODE: 7975 case XML_XINCLUDE_START: 7976 case XML_XINCLUDE_END: 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 tmp = (xmlAttrPtr) ctxt->context->node; 7987 7988 return(tmp->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 /* Bad, how did that namespace end up here ? */ 8005 return(NULL); 8006 } 8007 } 8008 return(NULL); 8009 } 8010 if (cur == ctxt->context->doc->children) 8011 return((xmlNodePtr) ctxt->context->doc); 8012 if (cur == (xmlNodePtr) ctxt->context->doc) 8013 return(NULL); 8014 switch (cur->type) { 8015 case XML_ELEMENT_NODE: 8016 case XML_TEXT_NODE: 8017 case XML_CDATA_SECTION_NODE: 8018 case XML_ENTITY_REF_NODE: 8019 case XML_ENTITY_NODE: 8020 case XML_PI_NODE: 8021 case XML_COMMENT_NODE: 8022 case XML_NOTATION_NODE: 8023 case XML_DTD_NODE: 8024 case XML_ELEMENT_DECL: 8025 case XML_ATTRIBUTE_DECL: 8026 case XML_ENTITY_DECL: 8027 case XML_XINCLUDE_START: 8028 case XML_XINCLUDE_END: 8029 if (cur->parent == NULL) 8030 return(NULL); 8031 if ((cur->parent->type == XML_ELEMENT_NODE) && 8032 ((cur->parent->name[0] == ' ') || 8033 (xmlStrEqual(cur->parent->name, 8034 BAD_CAST "fake node libxslt")))) 8035 return(NULL); 8036 return(cur->parent); 8037 case XML_ATTRIBUTE_NODE: { 8038 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node; 8039 8040 return(att->parent); 8041 } 8042 case XML_NAMESPACE_DECL: { 8043 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; 8044 8045 if ((ns->next != NULL) && 8046 (ns->next->type != XML_NAMESPACE_DECL)) 8047 return((xmlNodePtr) ns->next); 8048 /* Bad, how did that namespace end up here ? */ 8049 return(NULL); 8050 } 8051 case XML_DOCUMENT_NODE: 8052 case XML_DOCUMENT_TYPE_NODE: 8053 case XML_DOCUMENT_FRAG_NODE: 8054 case XML_HTML_DOCUMENT_NODE: 8055 #ifdef LIBXML_DOCB_ENABLED 8056 case XML_DOCB_DOCUMENT_NODE: 8057 #endif 8058 return(NULL); 8059 } 8060 return(NULL); 8061 } 8062 8063 /** 8064 * xmlXPathNextAncestorOrSelf: 8065 * @ctxt: the XPath Parser context 8066 * @cur: the current node in the traversal 8067 * 8068 * Traversal function for the "ancestor-or-self" direction 8069 * he ancestor-or-self axis contains the context node and ancestors of 8070 * the context node in reverse document order; thus the context node is 8071 * the first node on the axis, and the context node's parent the second; 8072 * parent here is defined the same as with the parent axis. 8073 * 8074 * Returns the next element following that axis 8075 */ 8076 xmlNodePtr 8077 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8078 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8079 if (cur == NULL) 8080 return(ctxt->context->node); 8081 return(xmlXPathNextAncestor(ctxt, cur)); 8082 } 8083 8084 /** 8085 * xmlXPathNextFollowingSibling: 8086 * @ctxt: the XPath Parser context 8087 * @cur: the current node in the traversal 8088 * 8089 * Traversal function for the "following-sibling" direction 8090 * The following-sibling axis contains the following siblings of the context 8091 * node in document order. 8092 * 8093 * Returns the next element following that axis 8094 */ 8095 xmlNodePtr 8096 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8097 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8098 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 8099 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 8100 return(NULL); 8101 if (cur == (xmlNodePtr) ctxt->context->doc) 8102 return(NULL); 8103 if (cur == NULL) 8104 return(ctxt->context->node->next); 8105 return(cur->next); 8106 } 8107 8108 /** 8109 * xmlXPathNextPrecedingSibling: 8110 * @ctxt: the XPath Parser context 8111 * @cur: the current node in the traversal 8112 * 8113 * Traversal function for the "preceding-sibling" direction 8114 * The preceding-sibling axis contains the preceding siblings of the context 8115 * node in reverse document order; the first preceding sibling is first on the 8116 * axis; the sibling preceding that node is the second on the axis and so on. 8117 * 8118 * Returns the next element following that axis 8119 */ 8120 xmlNodePtr 8121 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8122 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8123 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 8124 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 8125 return(NULL); 8126 if (cur == (xmlNodePtr) ctxt->context->doc) 8127 return(NULL); 8128 if (cur == NULL) 8129 return(ctxt->context->node->prev); 8130 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) { 8131 cur = cur->prev; 8132 if (cur == NULL) 8133 return(ctxt->context->node->prev); 8134 } 8135 return(cur->prev); 8136 } 8137 8138 /** 8139 * xmlXPathNextFollowing: 8140 * @ctxt: the XPath Parser context 8141 * @cur: the current node in the traversal 8142 * 8143 * Traversal function for the "following" direction 8144 * The following axis contains all nodes in the same document as the context 8145 * node that are after the context node in document order, excluding any 8146 * descendants and excluding attribute nodes and namespace nodes; the nodes 8147 * are ordered in document order 8148 * 8149 * Returns the next element following that axis 8150 */ 8151 xmlNodePtr 8152 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8153 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8154 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) && 8155 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL)) 8156 return(cur->children); 8157 8158 if (cur == NULL) { 8159 cur = ctxt->context->node; 8160 if (cur->type == XML_NAMESPACE_DECL) 8161 return(NULL); 8162 if (cur->type == XML_ATTRIBUTE_NODE) 8163 cur = cur->parent; 8164 } 8165 if (cur == NULL) return(NULL) ; /* ERROR */ 8166 if (cur->next != NULL) return(cur->next) ; 8167 do { 8168 cur = cur->parent; 8169 if (cur == NULL) break; 8170 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL); 8171 if (cur->next != NULL) return(cur->next); 8172 } while (cur != NULL); 8173 return(cur); 8174 } 8175 8176 /* 8177 * xmlXPathIsAncestor: 8178 * @ancestor: the ancestor node 8179 * @node: the current node 8180 * 8181 * Check that @ancestor is a @node's ancestor 8182 * 8183 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise. 8184 */ 8185 static int 8186 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) { 8187 if ((ancestor == NULL) || (node == NULL)) return(0); 8188 /* nodes need to be in the same document */ 8189 if (ancestor->doc != node->doc) return(0); 8190 /* avoid searching if ancestor or node is the root node */ 8191 if (ancestor == (xmlNodePtr) node->doc) return(1); 8192 if (node == (xmlNodePtr) ancestor->doc) return(0); 8193 while (node->parent != NULL) { 8194 if (node->parent == ancestor) 8195 return(1); 8196 node = node->parent; 8197 } 8198 return(0); 8199 } 8200 8201 /** 8202 * xmlXPathNextPreceding: 8203 * @ctxt: the XPath Parser context 8204 * @cur: the current node in the traversal 8205 * 8206 * Traversal function for the "preceding" direction 8207 * the preceding axis contains all nodes in the same document as the context 8208 * node that are before the context node in document order, excluding any 8209 * ancestors and excluding attribute nodes and namespace nodes; the nodes are 8210 * ordered in reverse document order 8211 * 8212 * Returns the next element following that axis 8213 */ 8214 xmlNodePtr 8215 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) 8216 { 8217 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8218 if (cur == NULL) { 8219 cur = ctxt->context->node; 8220 if (cur->type == XML_NAMESPACE_DECL) 8221 return(NULL); 8222 if (cur->type == XML_ATTRIBUTE_NODE) 8223 return(cur->parent); 8224 } 8225 if (cur == NULL) 8226 return (NULL); 8227 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) 8228 cur = cur->prev; 8229 do { 8230 if (cur->prev != NULL) { 8231 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ; 8232 return (cur); 8233 } 8234 8235 cur = cur->parent; 8236 if (cur == NULL) 8237 return (NULL); 8238 if (cur == ctxt->context->doc->children) 8239 return (NULL); 8240 } while (xmlXPathIsAncestor(cur, ctxt->context->node)); 8241 return (cur); 8242 } 8243 8244 /** 8245 * xmlXPathNextPrecedingInternal: 8246 * @ctxt: the XPath Parser context 8247 * @cur: the current node in the traversal 8248 * 8249 * Traversal function for the "preceding" direction 8250 * the preceding axis contains all nodes in the same document as the context 8251 * node that are before the context node in document order, excluding any 8252 * ancestors and excluding attribute nodes and namespace nodes; the nodes are 8253 * ordered in reverse document order 8254 * This is a faster implementation but internal only since it requires a 8255 * state kept in the parser context: ctxt->ancestor. 8256 * 8257 * Returns the next element following that axis 8258 */ 8259 static xmlNodePtr 8260 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt, 8261 xmlNodePtr cur) 8262 { 8263 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8264 if (cur == NULL) { 8265 cur = ctxt->context->node; 8266 if (cur == NULL) 8267 return (NULL); 8268 if (cur->type == XML_NAMESPACE_DECL) 8269 return (NULL); 8270 ctxt->ancestor = cur->parent; 8271 } 8272 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) 8273 cur = cur->prev; 8274 while (cur->prev == NULL) { 8275 cur = cur->parent; 8276 if (cur == NULL) 8277 return (NULL); 8278 if (cur == ctxt->context->doc->children) 8279 return (NULL); 8280 if (cur != ctxt->ancestor) 8281 return (cur); 8282 ctxt->ancestor = cur->parent; 8283 } 8284 cur = cur->prev; 8285 while (cur->last != NULL) 8286 cur = cur->last; 8287 return (cur); 8288 } 8289 8290 /** 8291 * xmlXPathNextNamespace: 8292 * @ctxt: the XPath Parser context 8293 * @cur: the current attribute in the traversal 8294 * 8295 * Traversal function for the "namespace" direction 8296 * the namespace axis contains the namespace nodes of the context node; 8297 * the order of nodes on this axis is implementation-defined; the axis will 8298 * be empty unless the context node is an element 8299 * 8300 * We keep the XML namespace node at the end of the list. 8301 * 8302 * Returns the next element following that axis 8303 */ 8304 xmlNodePtr 8305 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8306 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8307 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL); 8308 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) { 8309 if (ctxt->context->tmpNsList != NULL) 8310 xmlFree(ctxt->context->tmpNsList); 8311 ctxt->context->tmpNsList = 8312 xmlGetNsList(ctxt->context->doc, ctxt->context->node); 8313 ctxt->context->tmpNsNr = 0; 8314 if (ctxt->context->tmpNsList != NULL) { 8315 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) { 8316 ctxt->context->tmpNsNr++; 8317 } 8318 } 8319 return((xmlNodePtr) xmlXPathXMLNamespace); 8320 } 8321 if (ctxt->context->tmpNsNr > 0) { 8322 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr]; 8323 } else { 8324 if (ctxt->context->tmpNsList != NULL) 8325 xmlFree(ctxt->context->tmpNsList); 8326 ctxt->context->tmpNsList = NULL; 8327 return(NULL); 8328 } 8329 } 8330 8331 /** 8332 * xmlXPathNextAttribute: 8333 * @ctxt: the XPath Parser context 8334 * @cur: the current attribute in the traversal 8335 * 8336 * Traversal function for the "attribute" direction 8337 * TODO: support DTD inherited default attributes 8338 * 8339 * Returns the next element following that axis 8340 */ 8341 xmlNodePtr 8342 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8343 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8344 if (ctxt->context->node == NULL) 8345 return(NULL); 8346 if (ctxt->context->node->type != XML_ELEMENT_NODE) 8347 return(NULL); 8348 if (cur == NULL) { 8349 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc) 8350 return(NULL); 8351 return((xmlNodePtr)ctxt->context->node->properties); 8352 } 8353 return((xmlNodePtr)cur->next); 8354 } 8355 8356 /************************************************************************ 8357 * * 8358 * NodeTest Functions * 8359 * * 8360 ************************************************************************/ 8361 8362 #define IS_FUNCTION 200 8363 8364 8365 /************************************************************************ 8366 * * 8367 * Implicit tree core function library * 8368 * * 8369 ************************************************************************/ 8370 8371 /** 8372 * xmlXPathRoot: 8373 * @ctxt: the XPath Parser context 8374 * 8375 * Initialize the context to the root of the document 8376 */ 8377 void 8378 xmlXPathRoot(xmlXPathParserContextPtr ctxt) { 8379 if ((ctxt == NULL) || (ctxt->context == NULL)) 8380 return; 8381 ctxt->context->node = (xmlNodePtr) ctxt->context->doc; 8382 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8383 ctxt->context->node)); 8384 } 8385 8386 /************************************************************************ 8387 * * 8388 * The explicit core function library * 8389 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib * 8390 * * 8391 ************************************************************************/ 8392 8393 8394 /** 8395 * xmlXPathLastFunction: 8396 * @ctxt: the XPath Parser context 8397 * @nargs: the number of arguments 8398 * 8399 * Implement the last() XPath function 8400 * number last() 8401 * The last function returns the number of nodes in the context node list. 8402 */ 8403 void 8404 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8405 CHECK_ARITY(0); 8406 if (ctxt->context->contextSize >= 0) { 8407 valuePush(ctxt, 8408 xmlXPathCacheNewFloat(ctxt->context, 8409 (double) ctxt->context->contextSize)); 8410 #ifdef DEBUG_EXPR 8411 xmlGenericError(xmlGenericErrorContext, 8412 "last() : %d\n", ctxt->context->contextSize); 8413 #endif 8414 } else { 8415 XP_ERROR(XPATH_INVALID_CTXT_SIZE); 8416 } 8417 } 8418 8419 /** 8420 * xmlXPathPositionFunction: 8421 * @ctxt: the XPath Parser context 8422 * @nargs: the number of arguments 8423 * 8424 * Implement the position() XPath function 8425 * number position() 8426 * The position function returns the position of the context node in the 8427 * context node list. The first position is 1, and so the last position 8428 * will be equal to last(). 8429 */ 8430 void 8431 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8432 CHECK_ARITY(0); 8433 if (ctxt->context->proximityPosition >= 0) { 8434 valuePush(ctxt, 8435 xmlXPathCacheNewFloat(ctxt->context, 8436 (double) ctxt->context->proximityPosition)); 8437 #ifdef DEBUG_EXPR 8438 xmlGenericError(xmlGenericErrorContext, "position() : %d\n", 8439 ctxt->context->proximityPosition); 8440 #endif 8441 } else { 8442 XP_ERROR(XPATH_INVALID_CTXT_POSITION); 8443 } 8444 } 8445 8446 /** 8447 * xmlXPathCountFunction: 8448 * @ctxt: the XPath Parser context 8449 * @nargs: the number of arguments 8450 * 8451 * Implement the count() XPath function 8452 * number count(node-set) 8453 */ 8454 void 8455 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8456 xmlXPathObjectPtr cur; 8457 8458 CHECK_ARITY(1); 8459 if ((ctxt->value == NULL) || 8460 ((ctxt->value->type != XPATH_NODESET) && 8461 (ctxt->value->type != XPATH_XSLT_TREE))) 8462 XP_ERROR(XPATH_INVALID_TYPE); 8463 cur = valuePop(ctxt); 8464 8465 if ((cur == NULL) || (cur->nodesetval == NULL)) 8466 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0)); 8467 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) { 8468 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 8469 (double) cur->nodesetval->nodeNr)); 8470 } else { 8471 if ((cur->nodesetval->nodeNr != 1) || 8472 (cur->nodesetval->nodeTab == NULL)) { 8473 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0)); 8474 } else { 8475 xmlNodePtr tmp; 8476 int i = 0; 8477 8478 tmp = cur->nodesetval->nodeTab[0]; 8479 if (tmp != NULL) { 8480 tmp = tmp->children; 8481 while (tmp != NULL) { 8482 tmp = tmp->next; 8483 i++; 8484 } 8485 } 8486 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i)); 8487 } 8488 } 8489 xmlXPathReleaseObject(ctxt->context, cur); 8490 } 8491 8492 /** 8493 * xmlXPathGetElementsByIds: 8494 * @doc: the document 8495 * @ids: a whitespace separated list of IDs 8496 * 8497 * Selects elements by their unique ID. 8498 * 8499 * Returns a node-set of selected elements. 8500 */ 8501 static xmlNodeSetPtr 8502 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) { 8503 xmlNodeSetPtr ret; 8504 const xmlChar *cur = ids; 8505 xmlChar *ID; 8506 xmlAttrPtr attr; 8507 xmlNodePtr elem = NULL; 8508 8509 if (ids == NULL) return(NULL); 8510 8511 ret = xmlXPathNodeSetCreate(NULL); 8512 if (ret == NULL) 8513 return(ret); 8514 8515 while (IS_BLANK_CH(*cur)) cur++; 8516 while (*cur != 0) { 8517 while ((!IS_BLANK_CH(*cur)) && (*cur != 0)) 8518 cur++; 8519 8520 ID = xmlStrndup(ids, cur - ids); 8521 if (ID != NULL) { 8522 /* 8523 * We used to check the fact that the value passed 8524 * was an NCName, but this generated much troubles for 8525 * me and Aleksey Sanin, people blatantly violated that 8526 * constaint, like Visa3D spec. 8527 * if (xmlValidateNCName(ID, 1) == 0) 8528 */ 8529 attr = xmlGetID(doc, ID); 8530 if (attr != NULL) { 8531 if (attr->type == XML_ATTRIBUTE_NODE) 8532 elem = attr->parent; 8533 else if (attr->type == XML_ELEMENT_NODE) 8534 elem = (xmlNodePtr) attr; 8535 else 8536 elem = NULL; 8537 if (elem != NULL) 8538 xmlXPathNodeSetAdd(ret, elem); 8539 } 8540 xmlFree(ID); 8541 } 8542 8543 while (IS_BLANK_CH(*cur)) cur++; 8544 ids = cur; 8545 } 8546 return(ret); 8547 } 8548 8549 /** 8550 * xmlXPathIdFunction: 8551 * @ctxt: the XPath Parser context 8552 * @nargs: the number of arguments 8553 * 8554 * Implement the id() XPath function 8555 * node-set id(object) 8556 * The id function selects elements by their unique ID 8557 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set, 8558 * then the result is the union of the result of applying id to the 8559 * string value of each of the nodes in the argument node-set. When the 8560 * argument to id is of any other type, the argument is converted to a 8561 * string as if by a call to the string function; the string is split 8562 * into a whitespace-separated list of tokens (whitespace is any sequence 8563 * of characters matching the production S); the result is a node-set 8564 * containing the elements in the same document as the context node that 8565 * have a unique ID equal to any of the tokens in the list. 8566 */ 8567 void 8568 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8569 xmlChar *tokens; 8570 xmlNodeSetPtr ret; 8571 xmlXPathObjectPtr obj; 8572 8573 CHECK_ARITY(1); 8574 obj = valuePop(ctxt); 8575 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 8576 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) { 8577 xmlNodeSetPtr ns; 8578 int i; 8579 8580 ret = xmlXPathNodeSetCreate(NULL); 8581 /* 8582 * FIXME -- in an out-of-memory condition this will behave badly. 8583 * The solution is not clear -- we already popped an item from 8584 * ctxt, so the object is in a corrupt state. 8585 */ 8586 8587 if (obj->nodesetval != NULL) { 8588 for (i = 0; i < obj->nodesetval->nodeNr; i++) { 8589 tokens = 8590 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]); 8591 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens); 8592 ret = xmlXPathNodeSetMerge(ret, ns); 8593 xmlXPathFreeNodeSet(ns); 8594 if (tokens != NULL) 8595 xmlFree(tokens); 8596 } 8597 } 8598 xmlXPathReleaseObject(ctxt->context, obj); 8599 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret)); 8600 return; 8601 } 8602 obj = xmlXPathCacheConvertString(ctxt->context, obj); 8603 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval); 8604 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret)); 8605 xmlXPathReleaseObject(ctxt->context, obj); 8606 return; 8607 } 8608 8609 /** 8610 * xmlXPathLocalNameFunction: 8611 * @ctxt: the XPath Parser context 8612 * @nargs: the number of arguments 8613 * 8614 * Implement the local-name() XPath function 8615 * string local-name(node-set?) 8616 * The local-name function returns a string containing the local part 8617 * of the name of the node in the argument node-set that is first in 8618 * document order. If the node-set is empty or the first node has no 8619 * name, an empty string is returned. If the argument is omitted it 8620 * defaults to the context node. 8621 */ 8622 void 8623 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8624 xmlXPathObjectPtr cur; 8625 8626 if (ctxt == NULL) return; 8627 8628 if (nargs == 0) { 8629 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8630 ctxt->context->node)); 8631 nargs = 1; 8632 } 8633 8634 CHECK_ARITY(1); 8635 if ((ctxt->value == NULL) || 8636 ((ctxt->value->type != XPATH_NODESET) && 8637 (ctxt->value->type != XPATH_XSLT_TREE))) 8638 XP_ERROR(XPATH_INVALID_TYPE); 8639 cur = valuePop(ctxt); 8640 8641 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 8642 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8643 } else { 8644 int i = 0; /* Should be first in document order !!!!! */ 8645 switch (cur->nodesetval->nodeTab[i]->type) { 8646 case XML_ELEMENT_NODE: 8647 case XML_ATTRIBUTE_NODE: 8648 case XML_PI_NODE: 8649 if (cur->nodesetval->nodeTab[i]->name[0] == ' ') 8650 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8651 else 8652 valuePush(ctxt, 8653 xmlXPathCacheNewString(ctxt->context, 8654 cur->nodesetval->nodeTab[i]->name)); 8655 break; 8656 case XML_NAMESPACE_DECL: 8657 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 8658 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix)); 8659 break; 8660 default: 8661 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8662 } 8663 } 8664 xmlXPathReleaseObject(ctxt->context, cur); 8665 } 8666 8667 /** 8668 * xmlXPathNamespaceURIFunction: 8669 * @ctxt: the XPath Parser context 8670 * @nargs: the number of arguments 8671 * 8672 * Implement the namespace-uri() XPath function 8673 * string namespace-uri(node-set?) 8674 * The namespace-uri function returns a string containing the 8675 * namespace URI of the expanded name of the node in the argument 8676 * node-set that is first in document order. If the node-set is empty, 8677 * the first node has no name, or the expanded name has no namespace 8678 * URI, an empty string is returned. If the argument is omitted it 8679 * defaults to the context node. 8680 */ 8681 void 8682 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8683 xmlXPathObjectPtr cur; 8684 8685 if (ctxt == NULL) return; 8686 8687 if (nargs == 0) { 8688 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8689 ctxt->context->node)); 8690 nargs = 1; 8691 } 8692 CHECK_ARITY(1); 8693 if ((ctxt->value == NULL) || 8694 ((ctxt->value->type != XPATH_NODESET) && 8695 (ctxt->value->type != XPATH_XSLT_TREE))) 8696 XP_ERROR(XPATH_INVALID_TYPE); 8697 cur = valuePop(ctxt); 8698 8699 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 8700 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8701 } else { 8702 int i = 0; /* Should be first in document order !!!!! */ 8703 switch (cur->nodesetval->nodeTab[i]->type) { 8704 case XML_ELEMENT_NODE: 8705 case XML_ATTRIBUTE_NODE: 8706 if (cur->nodesetval->nodeTab[i]->ns == NULL) 8707 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8708 else 8709 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 8710 cur->nodesetval->nodeTab[i]->ns->href)); 8711 break; 8712 default: 8713 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8714 } 8715 } 8716 xmlXPathReleaseObject(ctxt->context, cur); 8717 } 8718 8719 /** 8720 * xmlXPathNameFunction: 8721 * @ctxt: the XPath Parser context 8722 * @nargs: the number of arguments 8723 * 8724 * Implement the name() XPath function 8725 * string name(node-set?) 8726 * The name function returns a string containing a QName representing 8727 * the name of the node in the argument node-set that is first in document 8728 * order. The QName must represent the name with respect to the namespace 8729 * declarations in effect on the node whose name is being represented. 8730 * Typically, this will be the form in which the name occurred in the XML 8731 * source. This need not be the case if there are namespace declarations 8732 * in effect on the node that associate multiple prefixes with the same 8733 * namespace. However, an implementation may include information about 8734 * the original prefix in its representation of nodes; in this case, an 8735 * implementation can ensure that the returned string is always the same 8736 * as the QName used in the XML source. If the argument it omitted it 8737 * defaults to the context node. 8738 * Libxml keep the original prefix so the "real qualified name" used is 8739 * returned. 8740 */ 8741 static void 8742 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) 8743 { 8744 xmlXPathObjectPtr cur; 8745 8746 if (nargs == 0) { 8747 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8748 ctxt->context->node)); 8749 nargs = 1; 8750 } 8751 8752 CHECK_ARITY(1); 8753 if ((ctxt->value == NULL) || 8754 ((ctxt->value->type != XPATH_NODESET) && 8755 (ctxt->value->type != XPATH_XSLT_TREE))) 8756 XP_ERROR(XPATH_INVALID_TYPE); 8757 cur = valuePop(ctxt); 8758 8759 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 8760 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8761 } else { 8762 int i = 0; /* Should be first in document order !!!!! */ 8763 8764 switch (cur->nodesetval->nodeTab[i]->type) { 8765 case XML_ELEMENT_NODE: 8766 case XML_ATTRIBUTE_NODE: 8767 if (cur->nodesetval->nodeTab[i]->name[0] == ' ') 8768 valuePush(ctxt, 8769 xmlXPathCacheNewCString(ctxt->context, "")); 8770 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) || 8771 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) { 8772 valuePush(ctxt, 8773 xmlXPathCacheNewString(ctxt->context, 8774 cur->nodesetval->nodeTab[i]->name)); 8775 } else { 8776 xmlChar *fullname; 8777 8778 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name, 8779 cur->nodesetval->nodeTab[i]->ns->prefix, 8780 NULL, 0); 8781 if (fullname == cur->nodesetval->nodeTab[i]->name) 8782 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name); 8783 if (fullname == NULL) { 8784 XP_ERROR(XPATH_MEMORY_ERROR); 8785 } 8786 valuePush(ctxt, xmlXPathCacheWrapString( 8787 ctxt->context, fullname)); 8788 } 8789 break; 8790 default: 8791 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8792 cur->nodesetval->nodeTab[i])); 8793 xmlXPathLocalNameFunction(ctxt, 1); 8794 } 8795 } 8796 xmlXPathReleaseObject(ctxt->context, cur); 8797 } 8798 8799 8800 /** 8801 * xmlXPathStringFunction: 8802 * @ctxt: the XPath Parser context 8803 * @nargs: the number of arguments 8804 * 8805 * Implement the string() XPath function 8806 * string string(object?) 8807 * The string function converts an object to a string as follows: 8808 * - A node-set is converted to a string by returning the value of 8809 * the node in the node-set that is first in document order. 8810 * If the node-set is empty, an empty string is returned. 8811 * - A number is converted to a string as follows 8812 * + NaN is converted to the string NaN 8813 * + positive zero is converted to the string 0 8814 * + negative zero is converted to the string 0 8815 * + positive infinity is converted to the string Infinity 8816 * + negative infinity is converted to the string -Infinity 8817 * + if the number is an integer, the number is represented in 8818 * decimal form as a Number with no decimal point and no leading 8819 * zeros, preceded by a minus sign (-) if the number is negative 8820 * + otherwise, the number is represented in decimal form as a 8821 * Number including a decimal point with at least one digit 8822 * before the decimal point and at least one digit after the 8823 * decimal point, preceded by a minus sign (-) if the number 8824 * is negative; there must be no leading zeros before the decimal 8825 * point apart possibly from the one required digit immediately 8826 * before the decimal point; beyond the one required digit 8827 * after the decimal point there must be as many, but only as 8828 * many, more digits as are needed to uniquely distinguish the 8829 * number from all other IEEE 754 numeric values. 8830 * - The boolean false value is converted to the string false. 8831 * The boolean true value is converted to the string true. 8832 * 8833 * If the argument is omitted, it defaults to a node-set with the 8834 * context node as its only member. 8835 */ 8836 void 8837 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8838 xmlXPathObjectPtr cur; 8839 8840 if (ctxt == NULL) return; 8841 if (nargs == 0) { 8842 valuePush(ctxt, 8843 xmlXPathCacheWrapString(ctxt->context, 8844 xmlXPathCastNodeToString(ctxt->context->node))); 8845 return; 8846 } 8847 8848 CHECK_ARITY(1); 8849 cur = valuePop(ctxt); 8850 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 8851 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur)); 8852 } 8853 8854 /** 8855 * xmlXPathStringLengthFunction: 8856 * @ctxt: the XPath Parser context 8857 * @nargs: the number of arguments 8858 * 8859 * Implement the string-length() XPath function 8860 * number string-length(string?) 8861 * The string-length returns the number of characters in the string 8862 * (see [3.6 Strings]). If the argument is omitted, it defaults to 8863 * the context node converted to a string, in other words the value 8864 * of the context node. 8865 */ 8866 void 8867 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8868 xmlXPathObjectPtr cur; 8869 8870 if (nargs == 0) { 8871 if ((ctxt == NULL) || (ctxt->context == NULL)) 8872 return; 8873 if (ctxt->context->node == NULL) { 8874 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0)); 8875 } else { 8876 xmlChar *content; 8877 8878 content = xmlXPathCastNodeToString(ctxt->context->node); 8879 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 8880 xmlUTF8Strlen(content))); 8881 xmlFree(content); 8882 } 8883 return; 8884 } 8885 CHECK_ARITY(1); 8886 CAST_TO_STRING; 8887 CHECK_TYPE(XPATH_STRING); 8888 cur = valuePop(ctxt); 8889 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 8890 xmlUTF8Strlen(cur->stringval))); 8891 xmlXPathReleaseObject(ctxt->context, cur); 8892 } 8893 8894 /** 8895 * xmlXPathConcatFunction: 8896 * @ctxt: the XPath Parser context 8897 * @nargs: the number of arguments 8898 * 8899 * Implement the concat() XPath function 8900 * string concat(string, string, string*) 8901 * The concat function returns the concatenation of its arguments. 8902 */ 8903 void 8904 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8905 xmlXPathObjectPtr cur, newobj; 8906 xmlChar *tmp; 8907 8908 if (ctxt == NULL) return; 8909 if (nargs < 2) { 8910 CHECK_ARITY(2); 8911 } 8912 8913 CAST_TO_STRING; 8914 cur = valuePop(ctxt); 8915 if ((cur == NULL) || (cur->type != XPATH_STRING)) { 8916 xmlXPathReleaseObject(ctxt->context, cur); 8917 return; 8918 } 8919 nargs--; 8920 8921 while (nargs > 0) { 8922 CAST_TO_STRING; 8923 newobj = valuePop(ctxt); 8924 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) { 8925 xmlXPathReleaseObject(ctxt->context, newobj); 8926 xmlXPathReleaseObject(ctxt->context, cur); 8927 XP_ERROR(XPATH_INVALID_TYPE); 8928 } 8929 tmp = xmlStrcat(newobj->stringval, cur->stringval); 8930 newobj->stringval = cur->stringval; 8931 cur->stringval = tmp; 8932 xmlXPathReleaseObject(ctxt->context, newobj); 8933 nargs--; 8934 } 8935 valuePush(ctxt, cur); 8936 } 8937 8938 /** 8939 * xmlXPathContainsFunction: 8940 * @ctxt: the XPath Parser context 8941 * @nargs: the number of arguments 8942 * 8943 * Implement the contains() XPath function 8944 * boolean contains(string, string) 8945 * The contains function returns true if the first argument string 8946 * contains the second argument string, and otherwise returns false. 8947 */ 8948 void 8949 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8950 xmlXPathObjectPtr hay, needle; 8951 8952 CHECK_ARITY(2); 8953 CAST_TO_STRING; 8954 CHECK_TYPE(XPATH_STRING); 8955 needle = valuePop(ctxt); 8956 CAST_TO_STRING; 8957 hay = valuePop(ctxt); 8958 8959 if ((hay == NULL) || (hay->type != XPATH_STRING)) { 8960 xmlXPathReleaseObject(ctxt->context, hay); 8961 xmlXPathReleaseObject(ctxt->context, needle); 8962 XP_ERROR(XPATH_INVALID_TYPE); 8963 } 8964 if (xmlStrstr(hay->stringval, needle->stringval)) 8965 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); 8966 else 8967 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); 8968 xmlXPathReleaseObject(ctxt->context, hay); 8969 xmlXPathReleaseObject(ctxt->context, needle); 8970 } 8971 8972 /** 8973 * xmlXPathStartsWithFunction: 8974 * @ctxt: the XPath Parser context 8975 * @nargs: the number of arguments 8976 * 8977 * Implement the starts-with() XPath function 8978 * boolean starts-with(string, string) 8979 * The starts-with function returns true if the first argument string 8980 * starts with the second argument string, and otherwise returns false. 8981 */ 8982 void 8983 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8984 xmlXPathObjectPtr hay, needle; 8985 int n; 8986 8987 CHECK_ARITY(2); 8988 CAST_TO_STRING; 8989 CHECK_TYPE(XPATH_STRING); 8990 needle = valuePop(ctxt); 8991 CAST_TO_STRING; 8992 hay = valuePop(ctxt); 8993 8994 if ((hay == NULL) || (hay->type != XPATH_STRING)) { 8995 xmlXPathReleaseObject(ctxt->context, hay); 8996 xmlXPathReleaseObject(ctxt->context, needle); 8997 XP_ERROR(XPATH_INVALID_TYPE); 8998 } 8999 n = xmlStrlen(needle->stringval); 9000 if (xmlStrncmp(hay->stringval, needle->stringval, n)) 9001 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); 9002 else 9003 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); 9004 xmlXPathReleaseObject(ctxt->context, hay); 9005 xmlXPathReleaseObject(ctxt->context, needle); 9006 } 9007 9008 /** 9009 * xmlXPathSubstringFunction: 9010 * @ctxt: the XPath Parser context 9011 * @nargs: the number of arguments 9012 * 9013 * Implement the substring() XPath function 9014 * string substring(string, number, number?) 9015 * The substring function returns the substring of the first argument 9016 * starting at the position specified in the second argument with 9017 * length specified in the third argument. For example, 9018 * substring("12345",2,3) returns "234". If the third argument is not 9019 * specified, it returns the substring starting at the position specified 9020 * in the second argument and continuing to the end of the string. For 9021 * example, substring("12345",2) returns "2345". More precisely, each 9022 * character in the string (see [3.6 Strings]) is considered to have a 9023 * numeric position: the position of the first character is 1, the position 9024 * of the second character is 2 and so on. The returned substring contains 9025 * those characters for which the position of the character is greater than 9026 * or equal to the second argument and, if the third argument is specified, 9027 * less than the sum of the second and third arguments; the comparisons 9028 * and addition used for the above follow the standard IEEE 754 rules. Thus: 9029 * - substring("12345", 1.5, 2.6) returns "234" 9030 * - substring("12345", 0, 3) returns "12" 9031 * - substring("12345", 0 div 0, 3) returns "" 9032 * - substring("12345", 1, 0 div 0) returns "" 9033 * - substring("12345", -42, 1 div 0) returns "12345" 9034 * - substring("12345", -1 div 0, 1 div 0) returns "" 9035 */ 9036 void 9037 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9038 xmlXPathObjectPtr str, start, len; 9039 double le=0, in; 9040 int i, l, m; 9041 xmlChar *ret; 9042 9043 if (nargs < 2) { 9044 CHECK_ARITY(2); 9045 } 9046 if (nargs > 3) { 9047 CHECK_ARITY(3); 9048 } 9049 /* 9050 * take care of possible last (position) argument 9051 */ 9052 if (nargs == 3) { 9053 CAST_TO_NUMBER; 9054 CHECK_TYPE(XPATH_NUMBER); 9055 len = valuePop(ctxt); 9056 le = len->floatval; 9057 xmlXPathReleaseObject(ctxt->context, len); 9058 } 9059 9060 CAST_TO_NUMBER; 9061 CHECK_TYPE(XPATH_NUMBER); 9062 start = valuePop(ctxt); 9063 in = start->floatval; 9064 xmlXPathReleaseObject(ctxt->context, start); 9065 CAST_TO_STRING; 9066 CHECK_TYPE(XPATH_STRING); 9067 str = valuePop(ctxt); 9068 m = xmlUTF8Strlen((const unsigned char *)str->stringval); 9069 9070 /* 9071 * If last pos not present, calculate last position 9072 */ 9073 if (nargs != 3) { 9074 le = (double)m; 9075 if (in < 1.0) 9076 in = 1.0; 9077 } 9078 9079 /* Need to check for the special cases where either 9080 * the index is NaN, the length is NaN, or both 9081 * arguments are infinity (relying on Inf + -Inf = NaN) 9082 */ 9083 if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) { 9084 /* 9085 * To meet the requirements of the spec, the arguments 9086 * must be converted to integer format before 9087 * initial index calculations are done 9088 * 9089 * First we go to integer form, rounding up 9090 * and checking for special cases 9091 */ 9092 i = (int) in; 9093 if (((double)i)+0.5 <= in) i++; 9094 9095 if (xmlXPathIsInf(le) == 1) { 9096 l = m; 9097 if (i < 1) 9098 i = 1; 9099 } 9100 else if (xmlXPathIsInf(le) == -1 || le < 0.0) 9101 l = 0; 9102 else { 9103 l = (int) le; 9104 if (((double)l)+0.5 <= le) l++; 9105 } 9106 9107 /* Now we normalize inidices */ 9108 i -= 1; 9109 l += i; 9110 if (i < 0) 9111 i = 0; 9112 if (l > m) 9113 l = m; 9114 9115 /* number of chars to copy */ 9116 l -= i; 9117 9118 ret = xmlUTF8Strsub(str->stringval, i, l); 9119 } 9120 else { 9121 ret = NULL; 9122 } 9123 if (ret == NULL) 9124 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 9125 else { 9126 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret)); 9127 xmlFree(ret); 9128 } 9129 xmlXPathReleaseObject(ctxt->context, str); 9130 } 9131 9132 /** 9133 * xmlXPathSubstringBeforeFunction: 9134 * @ctxt: the XPath Parser context 9135 * @nargs: the number of arguments 9136 * 9137 * Implement the substring-before() XPath function 9138 * string substring-before(string, string) 9139 * The substring-before function returns the substring of the first 9140 * argument string that precedes the first occurrence of the second 9141 * argument string in the first argument string, or the empty string 9142 * if the first argument string does not contain the second argument 9143 * string. For example, substring-before("1999/04/01","/") returns 1999. 9144 */ 9145 void 9146 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9147 xmlXPathObjectPtr str; 9148 xmlXPathObjectPtr find; 9149 xmlBufferPtr target; 9150 const xmlChar *point; 9151 int offset; 9152 9153 CHECK_ARITY(2); 9154 CAST_TO_STRING; 9155 find = valuePop(ctxt); 9156 CAST_TO_STRING; 9157 str = valuePop(ctxt); 9158 9159 target = xmlBufferCreate(); 9160 if (target) { 9161 point = xmlStrstr(str->stringval, find->stringval); 9162 if (point) { 9163 offset = (int)(point - str->stringval); 9164 xmlBufferAdd(target, str->stringval, offset); 9165 } 9166 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9167 xmlBufferContent(target))); 9168 xmlBufferFree(target); 9169 } 9170 xmlXPathReleaseObject(ctxt->context, str); 9171 xmlXPathReleaseObject(ctxt->context, find); 9172 } 9173 9174 /** 9175 * xmlXPathSubstringAfterFunction: 9176 * @ctxt: the XPath Parser context 9177 * @nargs: the number of arguments 9178 * 9179 * Implement the substring-after() XPath function 9180 * string substring-after(string, string) 9181 * The substring-after function returns the substring of the first 9182 * argument string that follows the first occurrence of the second 9183 * argument string in the first argument string, or the empty stringi 9184 * if the first argument string does not contain the second argument 9185 * string. For example, substring-after("1999/04/01","/") returns 04/01, 9186 * and substring-after("1999/04/01","19") returns 99/04/01. 9187 */ 9188 void 9189 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9190 xmlXPathObjectPtr str; 9191 xmlXPathObjectPtr find; 9192 xmlBufferPtr target; 9193 const xmlChar *point; 9194 int offset; 9195 9196 CHECK_ARITY(2); 9197 CAST_TO_STRING; 9198 find = valuePop(ctxt); 9199 CAST_TO_STRING; 9200 str = valuePop(ctxt); 9201 9202 target = xmlBufferCreate(); 9203 if (target) { 9204 point = xmlStrstr(str->stringval, find->stringval); 9205 if (point) { 9206 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval); 9207 xmlBufferAdd(target, &str->stringval[offset], 9208 xmlStrlen(str->stringval) - offset); 9209 } 9210 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9211 xmlBufferContent(target))); 9212 xmlBufferFree(target); 9213 } 9214 xmlXPathReleaseObject(ctxt->context, str); 9215 xmlXPathReleaseObject(ctxt->context, find); 9216 } 9217 9218 /** 9219 * xmlXPathNormalizeFunction: 9220 * @ctxt: the XPath Parser context 9221 * @nargs: the number of arguments 9222 * 9223 * Implement the normalize-space() XPath function 9224 * string normalize-space(string?) 9225 * The normalize-space function returns the argument string with white 9226 * space normalized by stripping leading and trailing whitespace 9227 * and replacing sequences of whitespace characters by a single 9228 * space. Whitespace characters are the same allowed by the S production 9229 * in XML. If the argument is omitted, it defaults to the context 9230 * node converted to a string, in other words the value of the context node. 9231 */ 9232 void 9233 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9234 xmlXPathObjectPtr obj = NULL; 9235 xmlChar *source = NULL; 9236 xmlBufferPtr target; 9237 xmlChar blank; 9238 9239 if (ctxt == NULL) return; 9240 if (nargs == 0) { 9241 /* Use current context node */ 9242 valuePush(ctxt, 9243 xmlXPathCacheWrapString(ctxt->context, 9244 xmlXPathCastNodeToString(ctxt->context->node))); 9245 nargs = 1; 9246 } 9247 9248 CHECK_ARITY(1); 9249 CAST_TO_STRING; 9250 CHECK_TYPE(XPATH_STRING); 9251 obj = valuePop(ctxt); 9252 source = obj->stringval; 9253 9254 target = xmlBufferCreate(); 9255 if (target && source) { 9256 9257 /* Skip leading whitespaces */ 9258 while (IS_BLANK_CH(*source)) 9259 source++; 9260 9261 /* Collapse intermediate whitespaces, and skip trailing whitespaces */ 9262 blank = 0; 9263 while (*source) { 9264 if (IS_BLANK_CH(*source)) { 9265 blank = 0x20; 9266 } else { 9267 if (blank) { 9268 xmlBufferAdd(target, &blank, 1); 9269 blank = 0; 9270 } 9271 xmlBufferAdd(target, source, 1); 9272 } 9273 source++; 9274 } 9275 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9276 xmlBufferContent(target))); 9277 xmlBufferFree(target); 9278 } 9279 xmlXPathReleaseObject(ctxt->context, obj); 9280 } 9281 9282 /** 9283 * xmlXPathTranslateFunction: 9284 * @ctxt: the XPath Parser context 9285 * @nargs: the number of arguments 9286 * 9287 * Implement the translate() XPath function 9288 * string translate(string, string, string) 9289 * The translate function returns the first argument string with 9290 * occurrences of characters in the second argument string replaced 9291 * by the character at the corresponding position in the third argument 9292 * string. For example, translate("bar","abc","ABC") returns the string 9293 * BAr. If there is a character in the second argument string with no 9294 * character at a corresponding position in the third argument string 9295 * (because the second argument string is longer than the third argument 9296 * string), then occurrences of that character in the first argument 9297 * string are removed. For example, translate("--aaa--","abc-","ABC") 9298 * returns "AAA". If a character occurs more than once in second 9299 * argument string, then the first occurrence determines the replacement 9300 * character. If the third argument string is longer than the second 9301 * argument string, then excess characters are ignored. 9302 */ 9303 void 9304 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9305 xmlXPathObjectPtr str; 9306 xmlXPathObjectPtr from; 9307 xmlXPathObjectPtr to; 9308 xmlBufferPtr target; 9309 int offset, max; 9310 xmlChar ch; 9311 const xmlChar *point; 9312 xmlChar *cptr; 9313 9314 CHECK_ARITY(3); 9315 9316 CAST_TO_STRING; 9317 to = valuePop(ctxt); 9318 CAST_TO_STRING; 9319 from = valuePop(ctxt); 9320 CAST_TO_STRING; 9321 str = valuePop(ctxt); 9322 9323 target = xmlBufferCreate(); 9324 if (target) { 9325 max = xmlUTF8Strlen(to->stringval); 9326 for (cptr = str->stringval; (ch=*cptr); ) { 9327 offset = xmlUTF8Strloc(from->stringval, cptr); 9328 if (offset >= 0) { 9329 if (offset < max) { 9330 point = xmlUTF8Strpos(to->stringval, offset); 9331 if (point) 9332 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1)); 9333 } 9334 } else 9335 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1)); 9336 9337 /* Step to next character in input */ 9338 cptr++; 9339 if ( ch & 0x80 ) { 9340 /* if not simple ascii, verify proper format */ 9341 if ( (ch & 0xc0) != 0xc0 ) { 9342 xmlGenericError(xmlGenericErrorContext, 9343 "xmlXPathTranslateFunction: Invalid UTF8 string\n"); 9344 /* not asserting an XPath error is probably better */ 9345 break; 9346 } 9347 /* then skip over remaining bytes for this char */ 9348 while ( (ch <<= 1) & 0x80 ) 9349 if ( (*cptr++ & 0xc0) != 0x80 ) { 9350 xmlGenericError(xmlGenericErrorContext, 9351 "xmlXPathTranslateFunction: Invalid UTF8 string\n"); 9352 /* not asserting an XPath error is probably better */ 9353 break; 9354 } 9355 if (ch & 0x80) /* must have had error encountered */ 9356 break; 9357 } 9358 } 9359 } 9360 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9361 xmlBufferContent(target))); 9362 xmlBufferFree(target); 9363 xmlXPathReleaseObject(ctxt->context, str); 9364 xmlXPathReleaseObject(ctxt->context, from); 9365 xmlXPathReleaseObject(ctxt->context, to); 9366 } 9367 9368 /** 9369 * xmlXPathBooleanFunction: 9370 * @ctxt: the XPath Parser context 9371 * @nargs: the number of arguments 9372 * 9373 * Implement the boolean() XPath function 9374 * boolean boolean(object) 9375 * The boolean function converts its argument to a boolean as follows: 9376 * - a number is true if and only if it is neither positive or 9377 * negative zero nor NaN 9378 * - a node-set is true if and only if it is non-empty 9379 * - a string is true if and only if its length is non-zero 9380 */ 9381 void 9382 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9383 xmlXPathObjectPtr cur; 9384 9385 CHECK_ARITY(1); 9386 cur = valuePop(ctxt); 9387 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 9388 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur); 9389 valuePush(ctxt, cur); 9390 } 9391 9392 /** 9393 * xmlXPathNotFunction: 9394 * @ctxt: the XPath Parser context 9395 * @nargs: the number of arguments 9396 * 9397 * Implement the not() XPath function 9398 * boolean not(boolean) 9399 * The not function returns true if its argument is false, 9400 * and false otherwise. 9401 */ 9402 void 9403 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9404 CHECK_ARITY(1); 9405 CAST_TO_BOOLEAN; 9406 CHECK_TYPE(XPATH_BOOLEAN); 9407 ctxt->value->boolval = ! ctxt->value->boolval; 9408 } 9409 9410 /** 9411 * xmlXPathTrueFunction: 9412 * @ctxt: the XPath Parser context 9413 * @nargs: the number of arguments 9414 * 9415 * Implement the true() XPath function 9416 * boolean true() 9417 */ 9418 void 9419 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9420 CHECK_ARITY(0); 9421 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); 9422 } 9423 9424 /** 9425 * xmlXPathFalseFunction: 9426 * @ctxt: the XPath Parser context 9427 * @nargs: the number of arguments 9428 * 9429 * Implement the false() XPath function 9430 * boolean false() 9431 */ 9432 void 9433 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9434 CHECK_ARITY(0); 9435 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); 9436 } 9437 9438 /** 9439 * xmlXPathLangFunction: 9440 * @ctxt: the XPath Parser context 9441 * @nargs: the number of arguments 9442 * 9443 * Implement the lang() XPath function 9444 * boolean lang(string) 9445 * The lang function returns true or false depending on whether the 9446 * language of the context node as specified by xml:lang attributes 9447 * is the same as or is a sublanguage of the language specified by 9448 * the argument string. The language of the context node is determined 9449 * by the value of the xml:lang attribute on the context node, or, if 9450 * the context node has no xml:lang attribute, by the value of the 9451 * xml:lang attribute on the nearest ancestor of the context node that 9452 * has an xml:lang attribute. If there is no such attribute, then lang 9453 * returns false. If there is such an attribute, then lang returns 9454 * true if the attribute value is equal to the argument ignoring case, 9455 * or if there is some suffix starting with - such that the attribute 9456 * value is equal to the argument ignoring that suffix of the attribute 9457 * value and ignoring case. 9458 */ 9459 void 9460 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9461 xmlXPathObjectPtr val = NULL; 9462 const xmlChar *theLang = NULL; 9463 const xmlChar *lang; 9464 int ret = 0; 9465 int i; 9466 9467 CHECK_ARITY(1); 9468 CAST_TO_STRING; 9469 CHECK_TYPE(XPATH_STRING); 9470 val = valuePop(ctxt); 9471 lang = val->stringval; 9472 theLang = xmlNodeGetLang(ctxt->context->node); 9473 if ((theLang != NULL) && (lang != NULL)) { 9474 for (i = 0;lang[i] != 0;i++) 9475 if (toupper(lang[i]) != toupper(theLang[i])) 9476 goto not_equal; 9477 if ((theLang[i] == 0) || (theLang[i] == '-')) 9478 ret = 1; 9479 } 9480 not_equal: 9481 if (theLang != NULL) 9482 xmlFree((void *)theLang); 9483 9484 xmlXPathReleaseObject(ctxt->context, val); 9485 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret)); 9486 } 9487 9488 /** 9489 * xmlXPathNumberFunction: 9490 * @ctxt: the XPath Parser context 9491 * @nargs: the number of arguments 9492 * 9493 * Implement the number() XPath function 9494 * number number(object?) 9495 */ 9496 void 9497 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9498 xmlXPathObjectPtr cur; 9499 double res; 9500 9501 if (ctxt == NULL) return; 9502 if (nargs == 0) { 9503 if (ctxt->context->node == NULL) { 9504 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0)); 9505 } else { 9506 xmlChar* content = xmlNodeGetContent(ctxt->context->node); 9507 9508 res = xmlXPathStringEvalNumber(content); 9509 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res)); 9510 xmlFree(content); 9511 } 9512 return; 9513 } 9514 9515 CHECK_ARITY(1); 9516 cur = valuePop(ctxt); 9517 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur)); 9518 } 9519 9520 /** 9521 * xmlXPathSumFunction: 9522 * @ctxt: the XPath Parser context 9523 * @nargs: the number of arguments 9524 * 9525 * Implement the sum() XPath function 9526 * number sum(node-set) 9527 * The sum function returns the sum of the values of the nodes in 9528 * the argument node-set. 9529 */ 9530 void 9531 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9532 xmlXPathObjectPtr cur; 9533 int i; 9534 double res = 0.0; 9535 9536 CHECK_ARITY(1); 9537 if ((ctxt->value == NULL) || 9538 ((ctxt->value->type != XPATH_NODESET) && 9539 (ctxt->value->type != XPATH_XSLT_TREE))) 9540 XP_ERROR(XPATH_INVALID_TYPE); 9541 cur = valuePop(ctxt); 9542 9543 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) { 9544 for (i = 0; i < cur->nodesetval->nodeNr; i++) { 9545 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]); 9546 } 9547 } 9548 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res)); 9549 xmlXPathReleaseObject(ctxt->context, cur); 9550 } 9551 9552 /* 9553 * To assure working code on multiple platforms, we want to only depend 9554 * upon the characteristic truncation of converting a floating point value 9555 * to an integer. Unfortunately, because of the different storage sizes 9556 * of our internal floating point value (double) and integer (int), we 9557 * can't directly convert (see bug 301162). This macro is a messy 9558 * 'workaround' 9559 */ 9560 #define XTRUNC(f, v) \ 9561 f = fmod((v), INT_MAX); \ 9562 f = (v) - (f) + (double)((int)(f)); 9563 9564 /** 9565 * xmlXPathFloorFunction: 9566 * @ctxt: the XPath Parser context 9567 * @nargs: the number of arguments 9568 * 9569 * Implement the floor() XPath function 9570 * number floor(number) 9571 * The floor function returns the largest (closest to positive infinity) 9572 * number that is not greater than the argument and that is an integer. 9573 */ 9574 void 9575 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9576 double f; 9577 9578 CHECK_ARITY(1); 9579 CAST_TO_NUMBER; 9580 CHECK_TYPE(XPATH_NUMBER); 9581 9582 XTRUNC(f, ctxt->value->floatval); 9583 if (f != ctxt->value->floatval) { 9584 if (ctxt->value->floatval > 0) 9585 ctxt->value->floatval = f; 9586 else 9587 ctxt->value->floatval = f - 1; 9588 } 9589 } 9590 9591 /** 9592 * xmlXPathCeilingFunction: 9593 * @ctxt: the XPath Parser context 9594 * @nargs: the number of arguments 9595 * 9596 * Implement the ceiling() XPath function 9597 * number ceiling(number) 9598 * The ceiling function returns the smallest (closest to negative infinity) 9599 * number that is not less than the argument and that is an integer. 9600 */ 9601 void 9602 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9603 double f; 9604 9605 CHECK_ARITY(1); 9606 CAST_TO_NUMBER; 9607 CHECK_TYPE(XPATH_NUMBER); 9608 9609 #if 0 9610 ctxt->value->floatval = ceil(ctxt->value->floatval); 9611 #else 9612 XTRUNC(f, ctxt->value->floatval); 9613 if (f != ctxt->value->floatval) { 9614 if (ctxt->value->floatval > 0) 9615 ctxt->value->floatval = f + 1; 9616 else { 9617 if (ctxt->value->floatval < 0 && f == 0) 9618 ctxt->value->floatval = xmlXPathNZERO; 9619 else 9620 ctxt->value->floatval = f; 9621 } 9622 9623 } 9624 #endif 9625 } 9626 9627 /** 9628 * xmlXPathRoundFunction: 9629 * @ctxt: the XPath Parser context 9630 * @nargs: the number of arguments 9631 * 9632 * Implement the round() XPath function 9633 * number round(number) 9634 * The round function returns the number that is closest to the 9635 * argument and that is an integer. If there are two such numbers, 9636 * then the one that is even is returned. 9637 */ 9638 void 9639 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9640 double f; 9641 9642 CHECK_ARITY(1); 9643 CAST_TO_NUMBER; 9644 CHECK_TYPE(XPATH_NUMBER); 9645 9646 if ((xmlXPathIsNaN(ctxt->value->floatval)) || 9647 (xmlXPathIsInf(ctxt->value->floatval) == 1) || 9648 (xmlXPathIsInf(ctxt->value->floatval) == -1) || 9649 (ctxt->value->floatval == 0.0)) 9650 return; 9651 9652 XTRUNC(f, ctxt->value->floatval); 9653 if (ctxt->value->floatval < 0) { 9654 if (ctxt->value->floatval < f - 0.5) 9655 ctxt->value->floatval = f - 1; 9656 else 9657 ctxt->value->floatval = f; 9658 if (ctxt->value->floatval == 0) 9659 ctxt->value->floatval = xmlXPathNZERO; 9660 } else { 9661 if (ctxt->value->floatval < f + 0.5) 9662 ctxt->value->floatval = f; 9663 else 9664 ctxt->value->floatval = f + 1; 9665 } 9666 } 9667 9668 /************************************************************************ 9669 * * 9670 * The Parser * 9671 * * 9672 ************************************************************************/ 9673 9674 /* 9675 * a few forward declarations since we use a recursive call based 9676 * implementation. 9677 */ 9678 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort); 9679 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter); 9680 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt); 9681 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt); 9682 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, 9683 int qualified); 9684 9685 /** 9686 * xmlXPathCurrentChar: 9687 * @ctxt: the XPath parser context 9688 * @cur: pointer to the beginning of the char 9689 * @len: pointer to the length of the char read 9690 * 9691 * The current char value, if using UTF-8 this may actually span multiple 9692 * bytes in the input buffer. 9693 * 9694 * Returns the current char value and its length 9695 */ 9696 9697 static int 9698 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) { 9699 unsigned char c; 9700 unsigned int val; 9701 const xmlChar *cur; 9702 9703 if (ctxt == NULL) 9704 return(0); 9705 cur = ctxt->cur; 9706 9707 /* 9708 * We are supposed to handle UTF8, check it's valid 9709 * From rfc2044: encoding of the Unicode values on UTF-8: 9710 * 9711 * UCS-4 range (hex.) UTF-8 octet sequence (binary) 9712 * 0000 0000-0000 007F 0xxxxxxx 9713 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx 9714 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx 9715 * 9716 * Check for the 0x110000 limit too 9717 */ 9718 c = *cur; 9719 if (c & 0x80) { 9720 if ((cur[1] & 0xc0) != 0x80) 9721 goto encoding_error; 9722 if ((c & 0xe0) == 0xe0) { 9723 9724 if ((cur[2] & 0xc0) != 0x80) 9725 goto encoding_error; 9726 if ((c & 0xf0) == 0xf0) { 9727 if (((c & 0xf8) != 0xf0) || 9728 ((cur[3] & 0xc0) != 0x80)) 9729 goto encoding_error; 9730 /* 4-byte code */ 9731 *len = 4; 9732 val = (cur[0] & 0x7) << 18; 9733 val |= (cur[1] & 0x3f) << 12; 9734 val |= (cur[2] & 0x3f) << 6; 9735 val |= cur[3] & 0x3f; 9736 } else { 9737 /* 3-byte code */ 9738 *len = 3; 9739 val = (cur[0] & 0xf) << 12; 9740 val |= (cur[1] & 0x3f) << 6; 9741 val |= cur[2] & 0x3f; 9742 } 9743 } else { 9744 /* 2-byte code */ 9745 *len = 2; 9746 val = (cur[0] & 0x1f) << 6; 9747 val |= cur[1] & 0x3f; 9748 } 9749 if (!IS_CHAR(val)) { 9750 XP_ERROR0(XPATH_INVALID_CHAR_ERROR); 9751 } 9752 return(val); 9753 } else { 9754 /* 1-byte code */ 9755 *len = 1; 9756 return((int) *cur); 9757 } 9758 encoding_error: 9759 /* 9760 * If we detect an UTF8 error that probably means that the 9761 * input encoding didn't get properly advertised in the 9762 * declaration header. Report the error and switch the encoding 9763 * to ISO-Latin-1 (if you don't like this policy, just declare the 9764 * encoding !) 9765 */ 9766 *len = 0; 9767 XP_ERROR0(XPATH_ENCODING_ERROR); 9768 } 9769 9770 /** 9771 * xmlXPathParseNCName: 9772 * @ctxt: the XPath Parser context 9773 * 9774 * parse an XML namespace non qualified name. 9775 * 9776 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)* 9777 * 9778 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' | 9779 * CombiningChar | Extender 9780 * 9781 * Returns the namespace name or NULL 9782 */ 9783 9784 xmlChar * 9785 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) { 9786 const xmlChar *in; 9787 xmlChar *ret; 9788 int count = 0; 9789 9790 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL); 9791 /* 9792 * Accelerator for simple ASCII names 9793 */ 9794 in = ctxt->cur; 9795 if (((*in >= 0x61) && (*in <= 0x7A)) || 9796 ((*in >= 0x41) && (*in <= 0x5A)) || 9797 (*in == '_')) { 9798 in++; 9799 while (((*in >= 0x61) && (*in <= 0x7A)) || 9800 ((*in >= 0x41) && (*in <= 0x5A)) || 9801 ((*in >= 0x30) && (*in <= 0x39)) || 9802 (*in == '_') || (*in == '.') || 9803 (*in == '-')) 9804 in++; 9805 if ((*in == ' ') || (*in == '>') || (*in == '/') || 9806 (*in == '[') || (*in == ']') || (*in == ':') || 9807 (*in == '@') || (*in == '*')) { 9808 count = in - ctxt->cur; 9809 if (count == 0) 9810 return(NULL); 9811 ret = xmlStrndup(ctxt->cur, count); 9812 ctxt->cur = in; 9813 return(ret); 9814 } 9815 } 9816 return(xmlXPathParseNameComplex(ctxt, 0)); 9817 } 9818 9819 9820 /** 9821 * xmlXPathParseQName: 9822 * @ctxt: the XPath Parser context 9823 * @prefix: a xmlChar ** 9824 * 9825 * parse an XML qualified name 9826 * 9827 * [NS 5] QName ::= (Prefix ':')? LocalPart 9828 * 9829 * [NS 6] Prefix ::= NCName 9830 * 9831 * [NS 7] LocalPart ::= NCName 9832 * 9833 * Returns the function returns the local part, and prefix is updated 9834 * to get the Prefix if any. 9835 */ 9836 9837 static xmlChar * 9838 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) { 9839 xmlChar *ret = NULL; 9840 9841 *prefix = NULL; 9842 ret = xmlXPathParseNCName(ctxt); 9843 if (ret && CUR == ':') { 9844 *prefix = ret; 9845 NEXT; 9846 ret = xmlXPathParseNCName(ctxt); 9847 } 9848 return(ret); 9849 } 9850 9851 /** 9852 * xmlXPathParseName: 9853 * @ctxt: the XPath Parser context 9854 * 9855 * parse an XML name 9856 * 9857 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | 9858 * CombiningChar | Extender 9859 * 9860 * [5] Name ::= (Letter | '_' | ':') (NameChar)* 9861 * 9862 * Returns the namespace name or NULL 9863 */ 9864 9865 xmlChar * 9866 xmlXPathParseName(xmlXPathParserContextPtr ctxt) { 9867 const xmlChar *in; 9868 xmlChar *ret; 9869 int count = 0; 9870 9871 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL); 9872 /* 9873 * Accelerator for simple ASCII names 9874 */ 9875 in = ctxt->cur; 9876 if (((*in >= 0x61) && (*in <= 0x7A)) || 9877 ((*in >= 0x41) && (*in <= 0x5A)) || 9878 (*in == '_') || (*in == ':')) { 9879 in++; 9880 while (((*in >= 0x61) && (*in <= 0x7A)) || 9881 ((*in >= 0x41) && (*in <= 0x5A)) || 9882 ((*in >= 0x30) && (*in <= 0x39)) || 9883 (*in == '_') || (*in == '-') || 9884 (*in == ':') || (*in == '.')) 9885 in++; 9886 if ((*in > 0) && (*in < 0x80)) { 9887 count = in - ctxt->cur; 9888 ret = xmlStrndup(ctxt->cur, count); 9889 ctxt->cur = in; 9890 return(ret); 9891 } 9892 } 9893 return(xmlXPathParseNameComplex(ctxt, 1)); 9894 } 9895 9896 static xmlChar * 9897 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) { 9898 xmlChar buf[XML_MAX_NAMELEN + 5]; 9899 int len = 0, l; 9900 int c; 9901 9902 /* 9903 * Handler for more complex cases 9904 */ 9905 c = CUR_CHAR(l); 9906 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */ 9907 (c == '[') || (c == ']') || (c == '@') || /* accelerators */ 9908 (c == '*') || /* accelerators */ 9909 (!IS_LETTER(c) && (c != '_') && 9910 ((qualified) && (c != ':')))) { 9911 return(NULL); 9912 } 9913 9914 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */ 9915 ((IS_LETTER(c)) || (IS_DIGIT(c)) || 9916 (c == '.') || (c == '-') || 9917 (c == '_') || ((qualified) && (c == ':')) || 9918 (IS_COMBINING(c)) || 9919 (IS_EXTENDER(c)))) { 9920 COPY_BUF(l,buf,len,c); 9921 NEXTL(l); 9922 c = CUR_CHAR(l); 9923 if (len >= XML_MAX_NAMELEN) { 9924 /* 9925 * Okay someone managed to make a huge name, so he's ready to pay 9926 * for the processing speed. 9927 */ 9928 xmlChar *buffer; 9929 int max = len * 2; 9930 9931 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar)); 9932 if (buffer == NULL) { 9933 XP_ERRORNULL(XPATH_MEMORY_ERROR); 9934 } 9935 memcpy(buffer, buf, len); 9936 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */ 9937 (c == '.') || (c == '-') || 9938 (c == '_') || ((qualified) && (c == ':')) || 9939 (IS_COMBINING(c)) || 9940 (IS_EXTENDER(c))) { 9941 if (len + 10 > max) { 9942 max *= 2; 9943 buffer = (xmlChar *) xmlRealloc(buffer, 9944 max * sizeof(xmlChar)); 9945 if (buffer == NULL) { 9946 XP_ERRORNULL(XPATH_MEMORY_ERROR); 9947 } 9948 } 9949 COPY_BUF(l,buffer,len,c); 9950 NEXTL(l); 9951 c = CUR_CHAR(l); 9952 } 9953 buffer[len] = 0; 9954 return(buffer); 9955 } 9956 } 9957 if (len == 0) 9958 return(NULL); 9959 return(xmlStrndup(buf, len)); 9960 } 9961 9962 #define MAX_FRAC 20 9963 9964 /* 9965 * These are used as divisors for the fractional part of a number. 9966 * Since the table includes 1.0 (representing '0' fractional digits), 9967 * it must be dimensioned at MAX_FRAC+1 (bug 133921) 9968 */ 9969 static double my_pow10[MAX_FRAC+1] = { 9970 1.0, 10.0, 100.0, 1000.0, 10000.0, 9971 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0, 9972 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0, 9973 100000000000000.0, 9974 1000000000000000.0, 10000000000000000.0, 100000000000000000.0, 9975 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0 9976 }; 9977 9978 /** 9979 * xmlXPathStringEvalNumber: 9980 * @str: A string to scan 9981 * 9982 * [30a] Float ::= Number ('e' Digits?)? 9983 * 9984 * [30] Number ::= Digits ('.' Digits?)? 9985 * | '.' Digits 9986 * [31] Digits ::= [0-9]+ 9987 * 9988 * Compile a Number in the string 9989 * In complement of the Number expression, this function also handles 9990 * negative values : '-' Number. 9991 * 9992 * Returns the double value. 9993 */ 9994 double 9995 xmlXPathStringEvalNumber(const xmlChar *str) { 9996 const xmlChar *cur = str; 9997 double ret; 9998 int ok = 0; 9999 int isneg = 0; 10000 int exponent = 0; 10001 int is_exponent_negative = 0; 10002 #ifdef __GNUC__ 10003 unsigned long tmp = 0; 10004 double temp; 10005 #endif 10006 if (cur == NULL) return(0); 10007 while (IS_BLANK_CH(*cur)) cur++; 10008 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) { 10009 return(xmlXPathNAN); 10010 } 10011 if (*cur == '-') { 10012 isneg = 1; 10013 cur++; 10014 } 10015 10016 #ifdef __GNUC__ 10017 /* 10018 * tmp/temp is a workaround against a gcc compiler bug 10019 * http://veillard.com/gcc.bug 10020 */ 10021 ret = 0; 10022 while ((*cur >= '0') && (*cur <= '9')) { 10023 ret = ret * 10; 10024 tmp = (*cur - '0'); 10025 ok = 1; 10026 cur++; 10027 temp = (double) tmp; 10028 ret = ret + temp; 10029 } 10030 #else 10031 ret = 0; 10032 while ((*cur >= '0') && (*cur <= '9')) { 10033 ret = ret * 10 + (*cur - '0'); 10034 ok = 1; 10035 cur++; 10036 } 10037 #endif 10038 10039 if (*cur == '.') { 10040 int v, frac = 0; 10041 double fraction = 0; 10042 10043 cur++; 10044 if (((*cur < '0') || (*cur > '9')) && (!ok)) { 10045 return(xmlXPathNAN); 10046 } 10047 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) { 10048 v = (*cur - '0'); 10049 fraction = fraction * 10 + v; 10050 frac = frac + 1; 10051 cur++; 10052 } 10053 fraction /= my_pow10[frac]; 10054 ret = ret + fraction; 10055 while ((*cur >= '0') && (*cur <= '9')) 10056 cur++; 10057 } 10058 if ((*cur == 'e') || (*cur == 'E')) { 10059 cur++; 10060 if (*cur == '-') { 10061 is_exponent_negative = 1; 10062 cur++; 10063 } else if (*cur == '+') { 10064 cur++; 10065 } 10066 while ((*cur >= '0') && (*cur <= '9')) { 10067 exponent = exponent * 10 + (*cur - '0'); 10068 cur++; 10069 } 10070 } 10071 while (IS_BLANK_CH(*cur)) cur++; 10072 if (*cur != 0) return(xmlXPathNAN); 10073 if (isneg) ret = -ret; 10074 if (is_exponent_negative) exponent = -exponent; 10075 ret *= pow(10.0, (double)exponent); 10076 return(ret); 10077 } 10078 10079 /** 10080 * xmlXPathCompNumber: 10081 * @ctxt: the XPath Parser context 10082 * 10083 * [30] Number ::= Digits ('.' Digits?)? 10084 * | '.' Digits 10085 * [31] Digits ::= [0-9]+ 10086 * 10087 * Compile a Number, then push it on the stack 10088 * 10089 */ 10090 static void 10091 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt) 10092 { 10093 double ret = 0.0; 10094 int ok = 0; 10095 int exponent = 0; 10096 int is_exponent_negative = 0; 10097 #ifdef __GNUC__ 10098 unsigned long tmp = 0; 10099 double temp; 10100 #endif 10101 10102 CHECK_ERROR; 10103 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) { 10104 XP_ERROR(XPATH_NUMBER_ERROR); 10105 } 10106 #ifdef __GNUC__ 10107 /* 10108 * tmp/temp is a workaround against a gcc compiler bug 10109 * http://veillard.com/gcc.bug 10110 */ 10111 ret = 0; 10112 while ((CUR >= '0') && (CUR <= '9')) { 10113 ret = ret * 10; 10114 tmp = (CUR - '0'); 10115 ok = 1; 10116 NEXT; 10117 temp = (double) tmp; 10118 ret = ret + temp; 10119 } 10120 #else 10121 ret = 0; 10122 while ((CUR >= '0') && (CUR <= '9')) { 10123 ret = ret * 10 + (CUR - '0'); 10124 ok = 1; 10125 NEXT; 10126 } 10127 #endif 10128 if (CUR == '.') { 10129 int v, frac = 0; 10130 double fraction = 0; 10131 10132 NEXT; 10133 if (((CUR < '0') || (CUR > '9')) && (!ok)) { 10134 XP_ERROR(XPATH_NUMBER_ERROR); 10135 } 10136 while ((CUR >= '0') && (CUR <= '9') && (frac < MAX_FRAC)) { 10137 v = (CUR - '0'); 10138 fraction = fraction * 10 + v; 10139 frac = frac + 1; 10140 NEXT; 10141 } 10142 fraction /= my_pow10[frac]; 10143 ret = ret + fraction; 10144 while ((CUR >= '0') && (CUR <= '9')) 10145 NEXT; 10146 } 10147 if ((CUR == 'e') || (CUR == 'E')) { 10148 NEXT; 10149 if (CUR == '-') { 10150 is_exponent_negative = 1; 10151 NEXT; 10152 } else if (CUR == '+') { 10153 NEXT; 10154 } 10155 while ((CUR >= '0') && (CUR <= '9')) { 10156 exponent = exponent * 10 + (CUR - '0'); 10157 NEXT; 10158 } 10159 if (is_exponent_negative) 10160 exponent = -exponent; 10161 ret *= pow(10.0, (double) exponent); 10162 } 10163 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, 10164 xmlXPathCacheNewFloat(ctxt->context, ret), NULL); 10165 } 10166 10167 /** 10168 * xmlXPathParseLiteral: 10169 * @ctxt: the XPath Parser context 10170 * 10171 * Parse a Literal 10172 * 10173 * [29] Literal ::= '"' [^"]* '"' 10174 * | "'" [^']* "'" 10175 * 10176 * Returns the value found or NULL in case of error 10177 */ 10178 static xmlChar * 10179 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) { 10180 const xmlChar *q; 10181 xmlChar *ret = NULL; 10182 10183 if (CUR == '"') { 10184 NEXT; 10185 q = CUR_PTR; 10186 while ((IS_CHAR_CH(CUR)) && (CUR != '"')) 10187 NEXT; 10188 if (!IS_CHAR_CH(CUR)) { 10189 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR); 10190 } else { 10191 ret = xmlStrndup(q, CUR_PTR - q); 10192 NEXT; 10193 } 10194 } else if (CUR == '\'') { 10195 NEXT; 10196 q = CUR_PTR; 10197 while ((IS_CHAR_CH(CUR)) && (CUR != '\'')) 10198 NEXT; 10199 if (!IS_CHAR_CH(CUR)) { 10200 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR); 10201 } else { 10202 ret = xmlStrndup(q, CUR_PTR - q); 10203 NEXT; 10204 } 10205 } else { 10206 XP_ERRORNULL(XPATH_START_LITERAL_ERROR); 10207 } 10208 return(ret); 10209 } 10210 10211 /** 10212 * xmlXPathCompLiteral: 10213 * @ctxt: the XPath Parser context 10214 * 10215 * Parse a Literal and push it on the stack. 10216 * 10217 * [29] Literal ::= '"' [^"]* '"' 10218 * | "'" [^']* "'" 10219 * 10220 * TODO: xmlXPathCompLiteral memory allocation could be improved. 10221 */ 10222 static void 10223 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) { 10224 const xmlChar *q; 10225 xmlChar *ret = NULL; 10226 10227 if (CUR == '"') { 10228 NEXT; 10229 q = CUR_PTR; 10230 while ((IS_CHAR_CH(CUR)) && (CUR != '"')) 10231 NEXT; 10232 if (!IS_CHAR_CH(CUR)) { 10233 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR); 10234 } else { 10235 ret = xmlStrndup(q, CUR_PTR - q); 10236 NEXT; 10237 } 10238 } else if (CUR == '\'') { 10239 NEXT; 10240 q = CUR_PTR; 10241 while ((IS_CHAR_CH(CUR)) && (CUR != '\'')) 10242 NEXT; 10243 if (!IS_CHAR_CH(CUR)) { 10244 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR); 10245 } else { 10246 ret = xmlStrndup(q, CUR_PTR - q); 10247 NEXT; 10248 } 10249 } else { 10250 XP_ERROR(XPATH_START_LITERAL_ERROR); 10251 } 10252 if (ret == NULL) return; 10253 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, 10254 xmlXPathCacheNewString(ctxt->context, ret), NULL); 10255 xmlFree(ret); 10256 } 10257 10258 /** 10259 * xmlXPathCompVariableReference: 10260 * @ctxt: the XPath Parser context 10261 * 10262 * Parse a VariableReference, evaluate it and push it on the stack. 10263 * 10264 * The variable bindings consist of a mapping from variable names 10265 * to variable values. The value of a variable is an object, which can be 10266 * of any of the types that are possible for the value of an expression, 10267 * and may also be of additional types not specified here. 10268 * 10269 * Early evaluation is possible since: 10270 * The variable bindings [...] used to evaluate a subexpression are 10271 * always the same as those used to evaluate the containing expression. 10272 * 10273 * [36] VariableReference ::= '$' QName 10274 */ 10275 static void 10276 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) { 10277 xmlChar *name; 10278 xmlChar *prefix; 10279 10280 SKIP_BLANKS; 10281 if (CUR != '$') { 10282 XP_ERROR(XPATH_VARIABLE_REF_ERROR); 10283 } 10284 NEXT; 10285 name = xmlXPathParseQName(ctxt, &prefix); 10286 if (name == NULL) { 10287 XP_ERROR(XPATH_VARIABLE_REF_ERROR); 10288 } 10289 ctxt->comp->last = -1; 10290 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, 10291 name, prefix); 10292 SKIP_BLANKS; 10293 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) { 10294 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR); 10295 } 10296 } 10297 10298 /** 10299 * xmlXPathIsNodeType: 10300 * @name: a name string 10301 * 10302 * Is the name given a NodeType one. 10303 * 10304 * [38] NodeType ::= 'comment' 10305 * | 'text' 10306 * | 'processing-instruction' 10307 * | 'node' 10308 * 10309 * Returns 1 if true 0 otherwise 10310 */ 10311 int 10312 xmlXPathIsNodeType(const xmlChar *name) { 10313 if (name == NULL) 10314 return(0); 10315 10316 if (xmlStrEqual(name, BAD_CAST "node")) 10317 return(1); 10318 if (xmlStrEqual(name, BAD_CAST "text")) 10319 return(1); 10320 if (xmlStrEqual(name, BAD_CAST "comment")) 10321 return(1); 10322 if (xmlStrEqual(name, BAD_CAST "processing-instruction")) 10323 return(1); 10324 return(0); 10325 } 10326 10327 /** 10328 * xmlXPathCompFunctionCall: 10329 * @ctxt: the XPath Parser context 10330 * 10331 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')' 10332 * [17] Argument ::= Expr 10333 * 10334 * Compile a function call, the evaluation of all arguments are 10335 * pushed on the stack 10336 */ 10337 static void 10338 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) { 10339 xmlChar *name; 10340 xmlChar *prefix; 10341 int nbargs = 0; 10342 int sort = 1; 10343 10344 name = xmlXPathParseQName(ctxt, &prefix); 10345 if (name == NULL) { 10346 xmlFree(prefix); 10347 XP_ERROR(XPATH_EXPR_ERROR); 10348 } 10349 SKIP_BLANKS; 10350 #ifdef DEBUG_EXPR 10351 if (prefix == NULL) 10352 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n", 10353 name); 10354 else 10355 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n", 10356 prefix, name); 10357 #endif 10358 10359 if (CUR != '(') { 10360 XP_ERROR(XPATH_EXPR_ERROR); 10361 } 10362 NEXT; 10363 SKIP_BLANKS; 10364 10365 /* 10366 * Optimization for count(): we don't need the node-set to be sorted. 10367 */ 10368 if ((prefix == NULL) && (name[0] == 'c') && 10369 xmlStrEqual(name, BAD_CAST "count")) 10370 { 10371 sort = 0; 10372 } 10373 ctxt->comp->last = -1; 10374 if (CUR != ')') { 10375 while (CUR != 0) { 10376 int op1 = ctxt->comp->last; 10377 ctxt->comp->last = -1; 10378 xmlXPathCompileExpr(ctxt, sort); 10379 if (ctxt->error != XPATH_EXPRESSION_OK) { 10380 xmlFree(name); 10381 xmlFree(prefix); 10382 return; 10383 } 10384 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0); 10385 nbargs++; 10386 if (CUR == ')') break; 10387 if (CUR != ',') { 10388 XP_ERROR(XPATH_EXPR_ERROR); 10389 } 10390 NEXT; 10391 SKIP_BLANKS; 10392 } 10393 } 10394 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, 10395 name, prefix); 10396 NEXT; 10397 SKIP_BLANKS; 10398 } 10399 10400 /** 10401 * xmlXPathCompPrimaryExpr: 10402 * @ctxt: the XPath Parser context 10403 * 10404 * [15] PrimaryExpr ::= VariableReference 10405 * | '(' Expr ')' 10406 * | Literal 10407 * | Number 10408 * | FunctionCall 10409 * 10410 * Compile a primary expression. 10411 */ 10412 static void 10413 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) { 10414 SKIP_BLANKS; 10415 if (CUR == '$') xmlXPathCompVariableReference(ctxt); 10416 else if (CUR == '(') { 10417 NEXT; 10418 SKIP_BLANKS; 10419 xmlXPathCompileExpr(ctxt, 1); 10420 CHECK_ERROR; 10421 if (CUR != ')') { 10422 XP_ERROR(XPATH_EXPR_ERROR); 10423 } 10424 NEXT; 10425 SKIP_BLANKS; 10426 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) { 10427 xmlXPathCompNumber(ctxt); 10428 } else if ((CUR == '\'') || (CUR == '"')) { 10429 xmlXPathCompLiteral(ctxt); 10430 } else { 10431 xmlXPathCompFunctionCall(ctxt); 10432 } 10433 SKIP_BLANKS; 10434 } 10435 10436 /** 10437 * xmlXPathCompFilterExpr: 10438 * @ctxt: the XPath Parser context 10439 * 10440 * [20] FilterExpr ::= PrimaryExpr 10441 * | FilterExpr Predicate 10442 * 10443 * Compile a filter expression. 10444 * Square brackets are used to filter expressions in the same way that 10445 * they are used in location paths. It is an error if the expression to 10446 * be filtered does not evaluate to a node-set. The context node list 10447 * used for evaluating the expression in square brackets is the node-set 10448 * to be filtered listed in document order. 10449 */ 10450 10451 static void 10452 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) { 10453 xmlXPathCompPrimaryExpr(ctxt); 10454 CHECK_ERROR; 10455 SKIP_BLANKS; 10456 10457 while (CUR == '[') { 10458 xmlXPathCompPredicate(ctxt, 1); 10459 SKIP_BLANKS; 10460 } 10461 10462 10463 } 10464 10465 /** 10466 * xmlXPathScanName: 10467 * @ctxt: the XPath Parser context 10468 * 10469 * Trickery: parse an XML name but without consuming the input flow 10470 * Needed to avoid insanity in the parser state. 10471 * 10472 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | 10473 * CombiningChar | Extender 10474 * 10475 * [5] Name ::= (Letter | '_' | ':') (NameChar)* 10476 * 10477 * [6] Names ::= Name (S Name)* 10478 * 10479 * Returns the Name parsed or NULL 10480 */ 10481 10482 static xmlChar * 10483 xmlXPathScanName(xmlXPathParserContextPtr ctxt) { 10484 int len = 0, l; 10485 int c; 10486 const xmlChar *cur; 10487 xmlChar *ret; 10488 10489 cur = ctxt->cur; 10490 10491 c = CUR_CHAR(l); 10492 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */ 10493 (!IS_LETTER(c) && (c != '_') && 10494 (c != ':'))) { 10495 return(NULL); 10496 } 10497 10498 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */ 10499 ((IS_LETTER(c)) || (IS_DIGIT(c)) || 10500 (c == '.') || (c == '-') || 10501 (c == '_') || (c == ':') || 10502 (IS_COMBINING(c)) || 10503 (IS_EXTENDER(c)))) { 10504 len += l; 10505 NEXTL(l); 10506 c = CUR_CHAR(l); 10507 } 10508 ret = xmlStrndup(cur, ctxt->cur - cur); 10509 ctxt->cur = cur; 10510 return(ret); 10511 } 10512 10513 /** 10514 * xmlXPathCompPathExpr: 10515 * @ctxt: the XPath Parser context 10516 * 10517 * [19] PathExpr ::= LocationPath 10518 * | FilterExpr 10519 * | FilterExpr '/' RelativeLocationPath 10520 * | FilterExpr '//' RelativeLocationPath 10521 * 10522 * Compile a path expression. 10523 * The / operator and // operators combine an arbitrary expression 10524 * and a relative location path. It is an error if the expression 10525 * does not evaluate to a node-set. 10526 * The / operator does composition in the same way as when / is 10527 * used in a location path. As in location paths, // is short for 10528 * /descendant-or-self::node()/. 10529 */ 10530 10531 static void 10532 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) { 10533 int lc = 1; /* Should we branch to LocationPath ? */ 10534 xmlChar *name = NULL; /* we may have to preparse a name to find out */ 10535 10536 SKIP_BLANKS; 10537 if ((CUR == '$') || (CUR == '(') || 10538 (IS_ASCII_DIGIT(CUR)) || 10539 (CUR == '\'') || (CUR == '"') || 10540 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) { 10541 lc = 0; 10542 } else if (CUR == '*') { 10543 /* relative or absolute location path */ 10544 lc = 1; 10545 } else if (CUR == '/') { 10546 /* relative or absolute location path */ 10547 lc = 1; 10548 } else if (CUR == '@') { 10549 /* relative abbreviated attribute location path */ 10550 lc = 1; 10551 } else if (CUR == '.') { 10552 /* relative abbreviated attribute location path */ 10553 lc = 1; 10554 } else { 10555 /* 10556 * Problem is finding if we have a name here whether it's: 10557 * - a nodetype 10558 * - a function call in which case it's followed by '(' 10559 * - an axis in which case it's followed by ':' 10560 * - a element name 10561 * We do an a priori analysis here rather than having to 10562 * maintain parsed token content through the recursive function 10563 * calls. This looks uglier but makes the code easier to 10564 * read/write/debug. 10565 */ 10566 SKIP_BLANKS; 10567 name = xmlXPathScanName(ctxt); 10568 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) { 10569 #ifdef DEBUG_STEP 10570 xmlGenericError(xmlGenericErrorContext, 10571 "PathExpr: Axis\n"); 10572 #endif 10573 lc = 1; 10574 xmlFree(name); 10575 } else if (name != NULL) { 10576 int len =xmlStrlen(name); 10577 10578 10579 while (NXT(len) != 0) { 10580 if (NXT(len) == '/') { 10581 /* element name */ 10582 #ifdef DEBUG_STEP 10583 xmlGenericError(xmlGenericErrorContext, 10584 "PathExpr: AbbrRelLocation\n"); 10585 #endif 10586 lc = 1; 10587 break; 10588 } else if (IS_BLANK_CH(NXT(len))) { 10589 /* ignore blanks */ 10590 ; 10591 } else if (NXT(len) == ':') { 10592 #ifdef DEBUG_STEP 10593 xmlGenericError(xmlGenericErrorContext, 10594 "PathExpr: AbbrRelLocation\n"); 10595 #endif 10596 lc = 1; 10597 break; 10598 } else if ((NXT(len) == '(')) { 10599 /* Note Type or Function */ 10600 if (xmlXPathIsNodeType(name)) { 10601 #ifdef DEBUG_STEP 10602 xmlGenericError(xmlGenericErrorContext, 10603 "PathExpr: Type search\n"); 10604 #endif 10605 lc = 1; 10606 } else { 10607 #ifdef DEBUG_STEP 10608 xmlGenericError(xmlGenericErrorContext, 10609 "PathExpr: function call\n"); 10610 #endif 10611 lc = 0; 10612 } 10613 break; 10614 } else if ((NXT(len) == '[')) { 10615 /* element name */ 10616 #ifdef DEBUG_STEP 10617 xmlGenericError(xmlGenericErrorContext, 10618 "PathExpr: AbbrRelLocation\n"); 10619 #endif 10620 lc = 1; 10621 break; 10622 } else if ((NXT(len) == '<') || (NXT(len) == '>') || 10623 (NXT(len) == '=')) { 10624 lc = 1; 10625 break; 10626 } else { 10627 lc = 1; 10628 break; 10629 } 10630 len++; 10631 } 10632 if (NXT(len) == 0) { 10633 #ifdef DEBUG_STEP 10634 xmlGenericError(xmlGenericErrorContext, 10635 "PathExpr: AbbrRelLocation\n"); 10636 #endif 10637 /* element name */ 10638 lc = 1; 10639 } 10640 xmlFree(name); 10641 } else { 10642 /* make sure all cases are covered explicitly */ 10643 XP_ERROR(XPATH_EXPR_ERROR); 10644 } 10645 } 10646 10647 if (lc) { 10648 if (CUR == '/') { 10649 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0); 10650 } else { 10651 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0); 10652 } 10653 xmlXPathCompLocationPath(ctxt); 10654 } else { 10655 xmlXPathCompFilterExpr(ctxt); 10656 CHECK_ERROR; 10657 if ((CUR == '/') && (NXT(1) == '/')) { 10658 SKIP(2); 10659 SKIP_BLANKS; 10660 10661 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 10662 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 10663 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0); 10664 10665 xmlXPathCompRelativeLocationPath(ctxt); 10666 } else if (CUR == '/') { 10667 xmlXPathCompRelativeLocationPath(ctxt); 10668 } 10669 } 10670 SKIP_BLANKS; 10671 } 10672 10673 /** 10674 * xmlXPathCompUnionExpr: 10675 * @ctxt: the XPath Parser context 10676 * 10677 * [18] UnionExpr ::= PathExpr 10678 * | UnionExpr '|' PathExpr 10679 * 10680 * Compile an union expression. 10681 */ 10682 10683 static void 10684 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) { 10685 xmlXPathCompPathExpr(ctxt); 10686 CHECK_ERROR; 10687 SKIP_BLANKS; 10688 while (CUR == '|') { 10689 int op1 = ctxt->comp->last; 10690 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0); 10691 10692 NEXT; 10693 SKIP_BLANKS; 10694 xmlXPathCompPathExpr(ctxt); 10695 10696 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0); 10697 10698 SKIP_BLANKS; 10699 } 10700 } 10701 10702 /** 10703 * xmlXPathCompUnaryExpr: 10704 * @ctxt: the XPath Parser context 10705 * 10706 * [27] UnaryExpr ::= UnionExpr 10707 * | '-' UnaryExpr 10708 * 10709 * Compile an unary expression. 10710 */ 10711 10712 static void 10713 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) { 10714 int minus = 0; 10715 int found = 0; 10716 10717 SKIP_BLANKS; 10718 while (CUR == '-') { 10719 minus = 1 - minus; 10720 found = 1; 10721 NEXT; 10722 SKIP_BLANKS; 10723 } 10724 10725 xmlXPathCompUnionExpr(ctxt); 10726 CHECK_ERROR; 10727 if (found) { 10728 if (minus) 10729 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0); 10730 else 10731 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0); 10732 } 10733 } 10734 10735 /** 10736 * xmlXPathCompMultiplicativeExpr: 10737 * @ctxt: the XPath Parser context 10738 * 10739 * [26] MultiplicativeExpr ::= UnaryExpr 10740 * | MultiplicativeExpr MultiplyOperator UnaryExpr 10741 * | MultiplicativeExpr 'div' UnaryExpr 10742 * | MultiplicativeExpr 'mod' UnaryExpr 10743 * [34] MultiplyOperator ::= '*' 10744 * 10745 * Compile an Additive expression. 10746 */ 10747 10748 static void 10749 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) { 10750 xmlXPathCompUnaryExpr(ctxt); 10751 CHECK_ERROR; 10752 SKIP_BLANKS; 10753 while ((CUR == '*') || 10754 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) || 10755 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) { 10756 int op = -1; 10757 int op1 = ctxt->comp->last; 10758 10759 if (CUR == '*') { 10760 op = 0; 10761 NEXT; 10762 } else if (CUR == 'd') { 10763 op = 1; 10764 SKIP(3); 10765 } else if (CUR == 'm') { 10766 op = 2; 10767 SKIP(3); 10768 } 10769 SKIP_BLANKS; 10770 xmlXPathCompUnaryExpr(ctxt); 10771 CHECK_ERROR; 10772 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0); 10773 SKIP_BLANKS; 10774 } 10775 } 10776 10777 /** 10778 * xmlXPathCompAdditiveExpr: 10779 * @ctxt: the XPath Parser context 10780 * 10781 * [25] AdditiveExpr ::= MultiplicativeExpr 10782 * | AdditiveExpr '+' MultiplicativeExpr 10783 * | AdditiveExpr '-' MultiplicativeExpr 10784 * 10785 * Compile an Additive expression. 10786 */ 10787 10788 static void 10789 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) { 10790 10791 xmlXPathCompMultiplicativeExpr(ctxt); 10792 CHECK_ERROR; 10793 SKIP_BLANKS; 10794 while ((CUR == '+') || (CUR == '-')) { 10795 int plus; 10796 int op1 = ctxt->comp->last; 10797 10798 if (CUR == '+') plus = 1; 10799 else plus = 0; 10800 NEXT; 10801 SKIP_BLANKS; 10802 xmlXPathCompMultiplicativeExpr(ctxt); 10803 CHECK_ERROR; 10804 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0); 10805 SKIP_BLANKS; 10806 } 10807 } 10808 10809 /** 10810 * xmlXPathCompRelationalExpr: 10811 * @ctxt: the XPath Parser context 10812 * 10813 * [24] RelationalExpr ::= AdditiveExpr 10814 * | RelationalExpr '<' AdditiveExpr 10815 * | RelationalExpr '>' AdditiveExpr 10816 * | RelationalExpr '<=' AdditiveExpr 10817 * | RelationalExpr '>=' AdditiveExpr 10818 * 10819 * A <= B > C is allowed ? Answer from James, yes with 10820 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr 10821 * which is basically what got implemented. 10822 * 10823 * Compile a Relational expression, then push the result 10824 * on the stack 10825 */ 10826 10827 static void 10828 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) { 10829 xmlXPathCompAdditiveExpr(ctxt); 10830 CHECK_ERROR; 10831 SKIP_BLANKS; 10832 while ((CUR == '<') || 10833 (CUR == '>') || 10834 ((CUR == '<') && (NXT(1) == '=')) || 10835 ((CUR == '>') && (NXT(1) == '='))) { 10836 int inf, strict; 10837 int op1 = ctxt->comp->last; 10838 10839 if (CUR == '<') inf = 1; 10840 else inf = 0; 10841 if (NXT(1) == '=') strict = 0; 10842 else strict = 1; 10843 NEXT; 10844 if (!strict) NEXT; 10845 SKIP_BLANKS; 10846 xmlXPathCompAdditiveExpr(ctxt); 10847 CHECK_ERROR; 10848 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict); 10849 SKIP_BLANKS; 10850 } 10851 } 10852 10853 /** 10854 * xmlXPathCompEqualityExpr: 10855 * @ctxt: the XPath Parser context 10856 * 10857 * [23] EqualityExpr ::= RelationalExpr 10858 * | EqualityExpr '=' RelationalExpr 10859 * | EqualityExpr '!=' RelationalExpr 10860 * 10861 * A != B != C is allowed ? Answer from James, yes with 10862 * (RelationalExpr = RelationalExpr) = RelationalExpr 10863 * (RelationalExpr != RelationalExpr) != RelationalExpr 10864 * which is basically what got implemented. 10865 * 10866 * Compile an Equality expression. 10867 * 10868 */ 10869 static void 10870 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) { 10871 xmlXPathCompRelationalExpr(ctxt); 10872 CHECK_ERROR; 10873 SKIP_BLANKS; 10874 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) { 10875 int eq; 10876 int op1 = ctxt->comp->last; 10877 10878 if (CUR == '=') eq = 1; 10879 else eq = 0; 10880 NEXT; 10881 if (!eq) NEXT; 10882 SKIP_BLANKS; 10883 xmlXPathCompRelationalExpr(ctxt); 10884 CHECK_ERROR; 10885 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0); 10886 SKIP_BLANKS; 10887 } 10888 } 10889 10890 /** 10891 * xmlXPathCompAndExpr: 10892 * @ctxt: the XPath Parser context 10893 * 10894 * [22] AndExpr ::= EqualityExpr 10895 * | AndExpr 'and' EqualityExpr 10896 * 10897 * Compile an AND expression. 10898 * 10899 */ 10900 static void 10901 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) { 10902 xmlXPathCompEqualityExpr(ctxt); 10903 CHECK_ERROR; 10904 SKIP_BLANKS; 10905 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) { 10906 int op1 = ctxt->comp->last; 10907 SKIP(3); 10908 SKIP_BLANKS; 10909 xmlXPathCompEqualityExpr(ctxt); 10910 CHECK_ERROR; 10911 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0); 10912 SKIP_BLANKS; 10913 } 10914 } 10915 10916 /** 10917 * xmlXPathCompileExpr: 10918 * @ctxt: the XPath Parser context 10919 * 10920 * [14] Expr ::= OrExpr 10921 * [21] OrExpr ::= AndExpr 10922 * | OrExpr 'or' AndExpr 10923 * 10924 * Parse and compile an expression 10925 */ 10926 static void 10927 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) { 10928 xmlXPathCompAndExpr(ctxt); 10929 CHECK_ERROR; 10930 SKIP_BLANKS; 10931 while ((CUR == 'o') && (NXT(1) == 'r')) { 10932 int op1 = ctxt->comp->last; 10933 SKIP(2); 10934 SKIP_BLANKS; 10935 xmlXPathCompAndExpr(ctxt); 10936 CHECK_ERROR; 10937 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0); 10938 SKIP_BLANKS; 10939 } 10940 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) { 10941 /* more ops could be optimized too */ 10942 /* 10943 * This is the main place to eliminate sorting for 10944 * operations which don't require a sorted node-set. 10945 * E.g. count(). 10946 */ 10947 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0); 10948 } 10949 } 10950 10951 /** 10952 * xmlXPathCompPredicate: 10953 * @ctxt: the XPath Parser context 10954 * @filter: act as a filter 10955 * 10956 * [8] Predicate ::= '[' PredicateExpr ']' 10957 * [9] PredicateExpr ::= Expr 10958 * 10959 * Compile a predicate expression 10960 */ 10961 static void 10962 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) { 10963 int op1 = ctxt->comp->last; 10964 10965 SKIP_BLANKS; 10966 if (CUR != '[') { 10967 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); 10968 } 10969 NEXT; 10970 SKIP_BLANKS; 10971 10972 ctxt->comp->last = -1; 10973 /* 10974 * This call to xmlXPathCompileExpr() will deactivate sorting 10975 * of the predicate result. 10976 * TODO: Sorting is still activated for filters, since I'm not 10977 * sure if needed. Normally sorting should not be needed, since 10978 * a filter can only diminish the number of items in a sequence, 10979 * but won't change its order; so if the initial sequence is sorted, 10980 * subsequent sorting is not needed. 10981 */ 10982 if (! filter) 10983 xmlXPathCompileExpr(ctxt, 0); 10984 else 10985 xmlXPathCompileExpr(ctxt, 1); 10986 CHECK_ERROR; 10987 10988 if (CUR != ']') { 10989 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); 10990 } 10991 10992 if (filter) 10993 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0); 10994 else 10995 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0); 10996 10997 NEXT; 10998 SKIP_BLANKS; 10999 } 11000 11001 /** 11002 * xmlXPathCompNodeTest: 11003 * @ctxt: the XPath Parser context 11004 * @test: pointer to a xmlXPathTestVal 11005 * @type: pointer to a xmlXPathTypeVal 11006 * @prefix: placeholder for a possible name prefix 11007 * 11008 * [7] NodeTest ::= NameTest 11009 * | NodeType '(' ')' 11010 * | 'processing-instruction' '(' Literal ')' 11011 * 11012 * [37] NameTest ::= '*' 11013 * | NCName ':' '*' 11014 * | QName 11015 * [38] NodeType ::= 'comment' 11016 * | 'text' 11017 * | 'processing-instruction' 11018 * | 'node' 11019 * 11020 * Returns the name found and updates @test, @type and @prefix appropriately 11021 */ 11022 static xmlChar * 11023 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test, 11024 xmlXPathTypeVal *type, const xmlChar **prefix, 11025 xmlChar *name) { 11026 int blanks; 11027 11028 if ((test == NULL) || (type == NULL) || (prefix == NULL)) { 11029 STRANGE; 11030 return(NULL); 11031 } 11032 *type = (xmlXPathTypeVal) 0; 11033 *test = (xmlXPathTestVal) 0; 11034 *prefix = NULL; 11035 SKIP_BLANKS; 11036 11037 if ((name == NULL) && (CUR == '*')) { 11038 /* 11039 * All elements 11040 */ 11041 NEXT; 11042 *test = NODE_TEST_ALL; 11043 return(NULL); 11044 } 11045 11046 if (name == NULL) 11047 name = xmlXPathParseNCName(ctxt); 11048 if (name == NULL) { 11049 XP_ERRORNULL(XPATH_EXPR_ERROR); 11050 } 11051 11052 blanks = IS_BLANK_CH(CUR); 11053 SKIP_BLANKS; 11054 if (CUR == '(') { 11055 NEXT; 11056 /* 11057 * NodeType or PI search 11058 */ 11059 if (xmlStrEqual(name, BAD_CAST "comment")) 11060 *type = NODE_TYPE_COMMENT; 11061 else if (xmlStrEqual(name, BAD_CAST "node")) 11062 *type = NODE_TYPE_NODE; 11063 else if (xmlStrEqual(name, BAD_CAST "processing-instruction")) 11064 *type = NODE_TYPE_PI; 11065 else if (xmlStrEqual(name, BAD_CAST "text")) 11066 *type = NODE_TYPE_TEXT; 11067 else { 11068 if (name != NULL) 11069 xmlFree(name); 11070 XP_ERRORNULL(XPATH_EXPR_ERROR); 11071 } 11072 11073 *test = NODE_TEST_TYPE; 11074 11075 SKIP_BLANKS; 11076 if (*type == NODE_TYPE_PI) { 11077 /* 11078 * Specific case: search a PI by name. 11079 */ 11080 if (name != NULL) 11081 xmlFree(name); 11082 name = NULL; 11083 if (CUR != ')') { 11084 name = xmlXPathParseLiteral(ctxt); 11085 CHECK_ERROR NULL; 11086 *test = NODE_TEST_PI; 11087 SKIP_BLANKS; 11088 } 11089 } 11090 if (CUR != ')') { 11091 if (name != NULL) 11092 xmlFree(name); 11093 XP_ERRORNULL(XPATH_UNCLOSED_ERROR); 11094 } 11095 NEXT; 11096 return(name); 11097 } 11098 *test = NODE_TEST_NAME; 11099 if ((!blanks) && (CUR == ':')) { 11100 NEXT; 11101 11102 /* 11103 * Since currently the parser context don't have a 11104 * namespace list associated: 11105 * The namespace name for this prefix can be computed 11106 * only at evaluation time. The compilation is done 11107 * outside of any context. 11108 */ 11109 #if 0 11110 *prefix = xmlXPathNsLookup(ctxt->context, name); 11111 if (name != NULL) 11112 xmlFree(name); 11113 if (*prefix == NULL) { 11114 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); 11115 } 11116 #else 11117 *prefix = name; 11118 #endif 11119 11120 if (CUR == '*') { 11121 /* 11122 * All elements 11123 */ 11124 NEXT; 11125 *test = NODE_TEST_ALL; 11126 return(NULL); 11127 } 11128 11129 name = xmlXPathParseNCName(ctxt); 11130 if (name == NULL) { 11131 XP_ERRORNULL(XPATH_EXPR_ERROR); 11132 } 11133 } 11134 return(name); 11135 } 11136 11137 /** 11138 * xmlXPathIsAxisName: 11139 * @name: a preparsed name token 11140 * 11141 * [6] AxisName ::= 'ancestor' 11142 * | 'ancestor-or-self' 11143 * | 'attribute' 11144 * | 'child' 11145 * | 'descendant' 11146 * | 'descendant-or-self' 11147 * | 'following' 11148 * | 'following-sibling' 11149 * | 'namespace' 11150 * | 'parent' 11151 * | 'preceding' 11152 * | 'preceding-sibling' 11153 * | 'self' 11154 * 11155 * Returns the axis or 0 11156 */ 11157 static xmlXPathAxisVal 11158 xmlXPathIsAxisName(const xmlChar *name) { 11159 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0; 11160 switch (name[0]) { 11161 case 'a': 11162 if (xmlStrEqual(name, BAD_CAST "ancestor")) 11163 ret = AXIS_ANCESTOR; 11164 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self")) 11165 ret = AXIS_ANCESTOR_OR_SELF; 11166 if (xmlStrEqual(name, BAD_CAST "attribute")) 11167 ret = AXIS_ATTRIBUTE; 11168 break; 11169 case 'c': 11170 if (xmlStrEqual(name, BAD_CAST "child")) 11171 ret = AXIS_CHILD; 11172 break; 11173 case 'd': 11174 if (xmlStrEqual(name, BAD_CAST "descendant")) 11175 ret = AXIS_DESCENDANT; 11176 if (xmlStrEqual(name, BAD_CAST "descendant-or-self")) 11177 ret = AXIS_DESCENDANT_OR_SELF; 11178 break; 11179 case 'f': 11180 if (xmlStrEqual(name, BAD_CAST "following")) 11181 ret = AXIS_FOLLOWING; 11182 if (xmlStrEqual(name, BAD_CAST "following-sibling")) 11183 ret = AXIS_FOLLOWING_SIBLING; 11184 break; 11185 case 'n': 11186 if (xmlStrEqual(name, BAD_CAST "namespace")) 11187 ret = AXIS_NAMESPACE; 11188 break; 11189 case 'p': 11190 if (xmlStrEqual(name, BAD_CAST "parent")) 11191 ret = AXIS_PARENT; 11192 if (xmlStrEqual(name, BAD_CAST "preceding")) 11193 ret = AXIS_PRECEDING; 11194 if (xmlStrEqual(name, BAD_CAST "preceding-sibling")) 11195 ret = AXIS_PRECEDING_SIBLING; 11196 break; 11197 case 's': 11198 if (xmlStrEqual(name, BAD_CAST "self")) 11199 ret = AXIS_SELF; 11200 break; 11201 } 11202 return(ret); 11203 } 11204 11205 /** 11206 * xmlXPathCompStep: 11207 * @ctxt: the XPath Parser context 11208 * 11209 * [4] Step ::= AxisSpecifier NodeTest Predicate* 11210 * | AbbreviatedStep 11211 * 11212 * [12] AbbreviatedStep ::= '.' | '..' 11213 * 11214 * [5] AxisSpecifier ::= AxisName '::' 11215 * | AbbreviatedAxisSpecifier 11216 * 11217 * [13] AbbreviatedAxisSpecifier ::= '@'? 11218 * 11219 * Modified for XPtr range support as: 11220 * 11221 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate* 11222 * | AbbreviatedStep 11223 * | 'range-to' '(' Expr ')' Predicate* 11224 * 11225 * Compile one step in a Location Path 11226 * A location step of . is short for self::node(). This is 11227 * particularly useful in conjunction with //. For example, the 11228 * location path .//para is short for 11229 * self::node()/descendant-or-self::node()/child::para 11230 * and so will select all para descendant elements of the context 11231 * node. 11232 * Similarly, a location step of .. is short for parent::node(). 11233 * For example, ../title is short for parent::node()/child::title 11234 * and so will select the title children of the parent of the context 11235 * node. 11236 */ 11237 static void 11238 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) { 11239 #ifdef LIBXML_XPTR_ENABLED 11240 int rangeto = 0; 11241 int op2 = -1; 11242 #endif 11243 11244 SKIP_BLANKS; 11245 if ((CUR == '.') && (NXT(1) == '.')) { 11246 SKIP(2); 11247 SKIP_BLANKS; 11248 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT, 11249 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11250 } else if (CUR == '.') { 11251 NEXT; 11252 SKIP_BLANKS; 11253 } else { 11254 xmlChar *name = NULL; 11255 const xmlChar *prefix = NULL; 11256 xmlXPathTestVal test = (xmlXPathTestVal) 0; 11257 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0; 11258 xmlXPathTypeVal type = (xmlXPathTypeVal) 0; 11259 int op1; 11260 11261 /* 11262 * The modification needed for XPointer change to the production 11263 */ 11264 #ifdef LIBXML_XPTR_ENABLED 11265 if (ctxt->xptr) { 11266 name = xmlXPathParseNCName(ctxt); 11267 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) { 11268 op2 = ctxt->comp->last; 11269 xmlFree(name); 11270 SKIP_BLANKS; 11271 if (CUR != '(') { 11272 XP_ERROR(XPATH_EXPR_ERROR); 11273 } 11274 NEXT; 11275 SKIP_BLANKS; 11276 11277 xmlXPathCompileExpr(ctxt, 1); 11278 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */ 11279 CHECK_ERROR; 11280 11281 SKIP_BLANKS; 11282 if (CUR != ')') { 11283 XP_ERROR(XPATH_EXPR_ERROR); 11284 } 11285 NEXT; 11286 rangeto = 1; 11287 goto eval_predicates; 11288 } 11289 } 11290 #endif 11291 if (CUR == '*') { 11292 axis = AXIS_CHILD; 11293 } else { 11294 if (name == NULL) 11295 name = xmlXPathParseNCName(ctxt); 11296 if (name != NULL) { 11297 axis = xmlXPathIsAxisName(name); 11298 if (axis != 0) { 11299 SKIP_BLANKS; 11300 if ((CUR == ':') && (NXT(1) == ':')) { 11301 SKIP(2); 11302 xmlFree(name); 11303 name = NULL; 11304 } else { 11305 /* an element name can conflict with an axis one :-\ */ 11306 axis = AXIS_CHILD; 11307 } 11308 } else { 11309 axis = AXIS_CHILD; 11310 } 11311 } else if (CUR == '@') { 11312 NEXT; 11313 axis = AXIS_ATTRIBUTE; 11314 } else { 11315 axis = AXIS_CHILD; 11316 } 11317 } 11318 11319 if (ctxt->error != XPATH_EXPRESSION_OK) { 11320 xmlFree(name); 11321 return; 11322 } 11323 11324 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name); 11325 if (test == 0) 11326 return; 11327 11328 if ((prefix != NULL) && (ctxt->context != NULL) && 11329 (ctxt->context->flags & XML_XPATH_CHECKNS)) { 11330 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) { 11331 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR); 11332 } 11333 } 11334 #ifdef DEBUG_STEP 11335 xmlGenericError(xmlGenericErrorContext, 11336 "Basis : computing new set\n"); 11337 #endif 11338 11339 #ifdef DEBUG_STEP 11340 xmlGenericError(xmlGenericErrorContext, "Basis : "); 11341 if (ctxt->value == NULL) 11342 xmlGenericError(xmlGenericErrorContext, "no value\n"); 11343 else if (ctxt->value->nodesetval == NULL) 11344 xmlGenericError(xmlGenericErrorContext, "Empty\n"); 11345 else 11346 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval); 11347 #endif 11348 11349 #ifdef LIBXML_XPTR_ENABLED 11350 eval_predicates: 11351 #endif 11352 op1 = ctxt->comp->last; 11353 ctxt->comp->last = -1; 11354 11355 SKIP_BLANKS; 11356 while (CUR == '[') { 11357 xmlXPathCompPredicate(ctxt, 0); 11358 } 11359 11360 #ifdef LIBXML_XPTR_ENABLED 11361 if (rangeto) { 11362 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0); 11363 } else 11364 #endif 11365 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis, 11366 test, type, (void *)prefix, (void *)name); 11367 11368 } 11369 #ifdef DEBUG_STEP 11370 xmlGenericError(xmlGenericErrorContext, "Step : "); 11371 if (ctxt->value == NULL) 11372 xmlGenericError(xmlGenericErrorContext, "no value\n"); 11373 else if (ctxt->value->nodesetval == NULL) 11374 xmlGenericError(xmlGenericErrorContext, "Empty\n"); 11375 else 11376 xmlGenericErrorContextNodeSet(xmlGenericErrorContext, 11377 ctxt->value->nodesetval); 11378 #endif 11379 } 11380 11381 /** 11382 * xmlXPathCompRelativeLocationPath: 11383 * @ctxt: the XPath Parser context 11384 * 11385 * [3] RelativeLocationPath ::= Step 11386 * | RelativeLocationPath '/' Step 11387 * | AbbreviatedRelativeLocationPath 11388 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step 11389 * 11390 * Compile a relative location path. 11391 */ 11392 static void 11393 xmlXPathCompRelativeLocationPath 11394 (xmlXPathParserContextPtr ctxt) { 11395 SKIP_BLANKS; 11396 if ((CUR == '/') && (NXT(1) == '/')) { 11397 SKIP(2); 11398 SKIP_BLANKS; 11399 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 11400 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11401 } else if (CUR == '/') { 11402 NEXT; 11403 SKIP_BLANKS; 11404 } 11405 xmlXPathCompStep(ctxt); 11406 CHECK_ERROR; 11407 SKIP_BLANKS; 11408 while (CUR == '/') { 11409 if ((CUR == '/') && (NXT(1) == '/')) { 11410 SKIP(2); 11411 SKIP_BLANKS; 11412 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 11413 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11414 xmlXPathCompStep(ctxt); 11415 } else if (CUR == '/') { 11416 NEXT; 11417 SKIP_BLANKS; 11418 xmlXPathCompStep(ctxt); 11419 } 11420 SKIP_BLANKS; 11421 } 11422 } 11423 11424 /** 11425 * xmlXPathCompLocationPath: 11426 * @ctxt: the XPath Parser context 11427 * 11428 * [1] LocationPath ::= RelativeLocationPath 11429 * | AbsoluteLocationPath 11430 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath? 11431 * | AbbreviatedAbsoluteLocationPath 11432 * [10] AbbreviatedAbsoluteLocationPath ::= 11433 * '//' RelativeLocationPath 11434 * 11435 * Compile a location path 11436 * 11437 * // is short for /descendant-or-self::node()/. For example, 11438 * //para is short for /descendant-or-self::node()/child::para and 11439 * so will select any para element in the document (even a para element 11440 * that is a document element will be selected by //para since the 11441 * document element node is a child of the root node); div//para is 11442 * short for div/descendant-or-self::node()/child::para and so will 11443 * select all para descendants of div children. 11444 */ 11445 static void 11446 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) { 11447 SKIP_BLANKS; 11448 if (CUR != '/') { 11449 xmlXPathCompRelativeLocationPath(ctxt); 11450 } else { 11451 while (CUR == '/') { 11452 if ((CUR == '/') && (NXT(1) == '/')) { 11453 SKIP(2); 11454 SKIP_BLANKS; 11455 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 11456 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11457 xmlXPathCompRelativeLocationPath(ctxt); 11458 } else if (CUR == '/') { 11459 NEXT; 11460 SKIP_BLANKS; 11461 if ((CUR != 0 ) && 11462 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') || 11463 (CUR == '@') || (CUR == '*'))) 11464 xmlXPathCompRelativeLocationPath(ctxt); 11465 } 11466 CHECK_ERROR; 11467 } 11468 } 11469 } 11470 11471 /************************************************************************ 11472 * * 11473 * XPath precompiled expression evaluation * 11474 * * 11475 ************************************************************************/ 11476 11477 static int 11478 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op); 11479 11480 #ifdef DEBUG_STEP 11481 static void 11482 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op, 11483 int nbNodes) 11484 { 11485 xmlGenericError(xmlGenericErrorContext, "new step : "); 11486 switch (op->value) { 11487 case AXIS_ANCESTOR: 11488 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' "); 11489 break; 11490 case AXIS_ANCESTOR_OR_SELF: 11491 xmlGenericError(xmlGenericErrorContext, 11492 "axis 'ancestors-or-self' "); 11493 break; 11494 case AXIS_ATTRIBUTE: 11495 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' "); 11496 break; 11497 case AXIS_CHILD: 11498 xmlGenericError(xmlGenericErrorContext, "axis 'child' "); 11499 break; 11500 case AXIS_DESCENDANT: 11501 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' "); 11502 break; 11503 case AXIS_DESCENDANT_OR_SELF: 11504 xmlGenericError(xmlGenericErrorContext, 11505 "axis 'descendant-or-self' "); 11506 break; 11507 case AXIS_FOLLOWING: 11508 xmlGenericError(xmlGenericErrorContext, "axis 'following' "); 11509 break; 11510 case AXIS_FOLLOWING_SIBLING: 11511 xmlGenericError(xmlGenericErrorContext, 11512 "axis 'following-siblings' "); 11513 break; 11514 case AXIS_NAMESPACE: 11515 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' "); 11516 break; 11517 case AXIS_PARENT: 11518 xmlGenericError(xmlGenericErrorContext, "axis 'parent' "); 11519 break; 11520 case AXIS_PRECEDING: 11521 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' "); 11522 break; 11523 case AXIS_PRECEDING_SIBLING: 11524 xmlGenericError(xmlGenericErrorContext, 11525 "axis 'preceding-sibling' "); 11526 break; 11527 case AXIS_SELF: 11528 xmlGenericError(xmlGenericErrorContext, "axis 'self' "); 11529 break; 11530 } 11531 xmlGenericError(xmlGenericErrorContext, 11532 " context contains %d nodes\n", nbNodes); 11533 switch (op->value2) { 11534 case NODE_TEST_NONE: 11535 xmlGenericError(xmlGenericErrorContext, 11536 " searching for none !!!\n"); 11537 break; 11538 case NODE_TEST_TYPE: 11539 xmlGenericError(xmlGenericErrorContext, 11540 " searching for type %d\n", op->value3); 11541 break; 11542 case NODE_TEST_PI: 11543 xmlGenericError(xmlGenericErrorContext, 11544 " searching for PI !!!\n"); 11545 break; 11546 case NODE_TEST_ALL: 11547 xmlGenericError(xmlGenericErrorContext, 11548 " searching for *\n"); 11549 break; 11550 case NODE_TEST_NS: 11551 xmlGenericError(xmlGenericErrorContext, 11552 " searching for namespace %s\n", 11553 op->value5); 11554 break; 11555 case NODE_TEST_NAME: 11556 xmlGenericError(xmlGenericErrorContext, 11557 " searching for name %s\n", op->value5); 11558 if (op->value4) 11559 xmlGenericError(xmlGenericErrorContext, 11560 " with namespace %s\n", op->value4); 11561 break; 11562 } 11563 xmlGenericError(xmlGenericErrorContext, "Testing : "); 11564 } 11565 #endif /* DEBUG_STEP */ 11566 11567 static int 11568 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt, 11569 xmlXPathStepOpPtr op, 11570 xmlNodeSetPtr set, 11571 int contextSize, 11572 int hasNsNodes) 11573 { 11574 if (op->ch1 != -1) { 11575 xmlXPathCompExprPtr comp = ctxt->comp; 11576 /* 11577 * Process inner predicates first. 11578 */ 11579 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) { 11580 /* 11581 * TODO: raise an internal error. 11582 */ 11583 } 11584 contextSize = xmlXPathCompOpEvalPredicate(ctxt, 11585 &comp->steps[op->ch1], set, contextSize, hasNsNodes); 11586 CHECK_ERROR0; 11587 if (contextSize <= 0) 11588 return(0); 11589 } 11590 if (op->ch2 != -1) { 11591 xmlXPathContextPtr xpctxt = ctxt->context; 11592 xmlNodePtr contextNode, oldContextNode; 11593 xmlDocPtr oldContextDoc; 11594 int i, res, contextPos = 0, newContextSize; 11595 xmlXPathStepOpPtr exprOp; 11596 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL; 11597 11598 #ifdef LIBXML_XPTR_ENABLED 11599 /* 11600 * URGENT TODO: Check the following: 11601 * We don't expect location sets if evaluating prediates, right? 11602 * Only filters should expect location sets, right? 11603 */ 11604 #endif 11605 /* 11606 * SPEC XPath 1.0: 11607 * "For each node in the node-set to be filtered, the 11608 * PredicateExpr is evaluated with that node as the 11609 * context node, with the number of nodes in the 11610 * node-set as the context size, and with the proximity 11611 * position of the node in the node-set with respect to 11612 * the axis as the context position;" 11613 * @oldset is the node-set" to be filtered. 11614 * 11615 * SPEC XPath 1.0: 11616 * "only predicates change the context position and 11617 * context size (see [2.4 Predicates])." 11618 * Example: 11619 * node-set context pos 11620 * nA 1 11621 * nB 2 11622 * nC 3 11623 * After applying predicate [position() > 1] : 11624 * node-set context pos 11625 * nB 1 11626 * nC 2 11627 */ 11628 oldContextNode = xpctxt->node; 11629 oldContextDoc = xpctxt->doc; 11630 /* 11631 * Get the expression of this predicate. 11632 */ 11633 exprOp = &ctxt->comp->steps[op->ch2]; 11634 newContextSize = 0; 11635 for (i = 0; i < set->nodeNr; i++) { 11636 if (set->nodeTab[i] == NULL) 11637 continue; 11638 11639 contextNode = set->nodeTab[i]; 11640 xpctxt->node = contextNode; 11641 xpctxt->contextSize = contextSize; 11642 xpctxt->proximityPosition = ++contextPos; 11643 11644 /* 11645 * Also set the xpath document in case things like 11646 * key() are evaluated in the predicate. 11647 */ 11648 if ((contextNode->type != XML_NAMESPACE_DECL) && 11649 (contextNode->doc != NULL)) 11650 xpctxt->doc = contextNode->doc; 11651 /* 11652 * Evaluate the predicate expression with 1 context node 11653 * at a time; this node is packaged into a node set; this 11654 * node set is handed over to the evaluation mechanism. 11655 */ 11656 if (contextObj == NULL) 11657 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode); 11658 else 11659 xmlXPathNodeSetAddUnique(contextObj->nodesetval, 11660 contextNode); 11661 11662 valuePush(ctxt, contextObj); 11663 11664 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1); 11665 11666 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) { 11667 xmlXPathNodeSetClear(set, hasNsNodes); 11668 newContextSize = 0; 11669 goto evaluation_exit; 11670 } 11671 11672 if (res != 0) { 11673 newContextSize++; 11674 } else { 11675 /* 11676 * Remove the entry from the initial node set. 11677 */ 11678 set->nodeTab[i] = NULL; 11679 if (contextNode->type == XML_NAMESPACE_DECL) 11680 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode); 11681 } 11682 if (ctxt->value == contextObj) { 11683 /* 11684 * Don't free the temporary XPath object holding the 11685 * context node, in order to avoid massive recreation 11686 * inside this loop. 11687 */ 11688 valuePop(ctxt); 11689 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes); 11690 } else { 11691 /* 11692 * TODO: The object was lost in the evaluation machinery. 11693 * Can this happen? Maybe in internal-error cases. 11694 */ 11695 contextObj = NULL; 11696 } 11697 } 11698 11699 if (contextObj != NULL) { 11700 if (ctxt->value == contextObj) 11701 valuePop(ctxt); 11702 xmlXPathReleaseObject(xpctxt, contextObj); 11703 } 11704 evaluation_exit: 11705 if (exprRes != NULL) 11706 xmlXPathReleaseObject(ctxt->context, exprRes); 11707 /* 11708 * Reset/invalidate the context. 11709 */ 11710 xpctxt->node = oldContextNode; 11711 xpctxt->doc = oldContextDoc; 11712 xpctxt->contextSize = -1; 11713 xpctxt->proximityPosition = -1; 11714 return(newContextSize); 11715 } 11716 return(contextSize); 11717 } 11718 11719 static int 11720 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt, 11721 xmlXPathStepOpPtr op, 11722 xmlNodeSetPtr set, 11723 int contextSize, 11724 int minPos, 11725 int maxPos, 11726 int hasNsNodes) 11727 { 11728 if (op->ch1 != -1) { 11729 xmlXPathCompExprPtr comp = ctxt->comp; 11730 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) { 11731 /* 11732 * TODO: raise an internal error. 11733 */ 11734 } 11735 contextSize = xmlXPathCompOpEvalPredicate(ctxt, 11736 &comp->steps[op->ch1], set, contextSize, hasNsNodes); 11737 CHECK_ERROR0; 11738 if (contextSize <= 0) 11739 return(0); 11740 } 11741 /* 11742 * Check if the node set contains a sufficient number of nodes for 11743 * the requested range. 11744 */ 11745 if (contextSize < minPos) { 11746 xmlXPathNodeSetClear(set, hasNsNodes); 11747 return(0); 11748 } 11749 if (op->ch2 == -1) { 11750 /* 11751 * TODO: Can this ever happen? 11752 */ 11753 return (contextSize); 11754 } else { 11755 xmlDocPtr oldContextDoc; 11756 int i, pos = 0, newContextSize = 0, contextPos = 0, res; 11757 xmlXPathStepOpPtr exprOp; 11758 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL; 11759 xmlNodePtr oldContextNode, contextNode = NULL; 11760 xmlXPathContextPtr xpctxt = ctxt->context; 11761 int frame; 11762 11763 #ifdef LIBXML_XPTR_ENABLED 11764 /* 11765 * URGENT TODO: Check the following: 11766 * We don't expect location sets if evaluating prediates, right? 11767 * Only filters should expect location sets, right? 11768 */ 11769 #endif /* LIBXML_XPTR_ENABLED */ 11770 11771 /* 11772 * Save old context. 11773 */ 11774 oldContextNode = xpctxt->node; 11775 oldContextDoc = xpctxt->doc; 11776 /* 11777 * Get the expression of this predicate. 11778 */ 11779 exprOp = &ctxt->comp->steps[op->ch2]; 11780 for (i = 0; i < set->nodeNr; i++) { 11781 xmlXPathObjectPtr tmp; 11782 11783 if (set->nodeTab[i] == NULL) 11784 continue; 11785 11786 contextNode = set->nodeTab[i]; 11787 xpctxt->node = contextNode; 11788 xpctxt->contextSize = contextSize; 11789 xpctxt->proximityPosition = ++contextPos; 11790 11791 /* 11792 * Initialize the new set. 11793 * Also set the xpath document in case things like 11794 * key() evaluation are attempted on the predicate 11795 */ 11796 if ((contextNode->type != XML_NAMESPACE_DECL) && 11797 (contextNode->doc != NULL)) 11798 xpctxt->doc = contextNode->doc; 11799 /* 11800 * Evaluate the predicate expression with 1 context node 11801 * at a time; this node is packaged into a node set; this 11802 * node set is handed over to the evaluation mechanism. 11803 */ 11804 if (contextObj == NULL) 11805 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode); 11806 else 11807 xmlXPathNodeSetAddUnique(contextObj->nodesetval, 11808 contextNode); 11809 11810 frame = xmlXPathSetFrame(ctxt); 11811 valuePush(ctxt, contextObj); 11812 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1); 11813 tmp = valuePop(ctxt); 11814 xmlXPathPopFrame(ctxt, frame); 11815 11816 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) { 11817 while (tmp != contextObj) { 11818 /* 11819 * Free up the result 11820 * then pop off contextObj, which will be freed later 11821 */ 11822 xmlXPathReleaseObject(xpctxt, tmp); 11823 tmp = valuePop(ctxt); 11824 } 11825 goto evaluation_error; 11826 } 11827 /* push the result back onto the stack */ 11828 valuePush(ctxt, tmp); 11829 11830 if (res) 11831 pos++; 11832 11833 if (res && (pos >= minPos) && (pos <= maxPos)) { 11834 /* 11835 * Fits in the requested range. 11836 */ 11837 newContextSize++; 11838 if (minPos == maxPos) { 11839 /* 11840 * Only 1 node was requested. 11841 */ 11842 if (contextNode->type == XML_NAMESPACE_DECL) { 11843 /* 11844 * As always: take care of those nasty 11845 * namespace nodes. 11846 */ 11847 set->nodeTab[i] = NULL; 11848 } 11849 xmlXPathNodeSetClear(set, hasNsNodes); 11850 set->nodeNr = 1; 11851 set->nodeTab[0] = contextNode; 11852 goto evaluation_exit; 11853 } 11854 if (pos == maxPos) { 11855 /* 11856 * We are done. 11857 */ 11858 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes); 11859 goto evaluation_exit; 11860 } 11861 } else { 11862 /* 11863 * Remove the entry from the initial node set. 11864 */ 11865 set->nodeTab[i] = NULL; 11866 if (contextNode->type == XML_NAMESPACE_DECL) 11867 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode); 11868 } 11869 if (exprRes != NULL) { 11870 xmlXPathReleaseObject(ctxt->context, exprRes); 11871 exprRes = NULL; 11872 } 11873 if (ctxt->value == contextObj) { 11874 /* 11875 * Don't free the temporary XPath object holding the 11876 * context node, in order to avoid massive recreation 11877 * inside this loop. 11878 */ 11879 valuePop(ctxt); 11880 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes); 11881 } else { 11882 /* 11883 * The object was lost in the evaluation machinery. 11884 * Can this happen? Maybe in case of internal-errors. 11885 */ 11886 contextObj = NULL; 11887 } 11888 } 11889 goto evaluation_exit; 11890 11891 evaluation_error: 11892 xmlXPathNodeSetClear(set, hasNsNodes); 11893 newContextSize = 0; 11894 11895 evaluation_exit: 11896 if (contextObj != NULL) { 11897 if (ctxt->value == contextObj) 11898 valuePop(ctxt); 11899 xmlXPathReleaseObject(xpctxt, contextObj); 11900 } 11901 if (exprRes != NULL) 11902 xmlXPathReleaseObject(ctxt->context, exprRes); 11903 /* 11904 * Reset/invalidate the context. 11905 */ 11906 xpctxt->node = oldContextNode; 11907 xpctxt->doc = oldContextDoc; 11908 xpctxt->contextSize = -1; 11909 xpctxt->proximityPosition = -1; 11910 return(newContextSize); 11911 } 11912 return(contextSize); 11913 } 11914 11915 static int 11916 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt, 11917 xmlXPathStepOpPtr op, 11918 int *maxPos) 11919 { 11920 11921 xmlXPathStepOpPtr exprOp; 11922 11923 /* 11924 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet! 11925 */ 11926 11927 /* 11928 * If not -1, then ch1 will point to: 11929 * 1) For predicates (XPATH_OP_PREDICATE): 11930 * - an inner predicate operator 11931 * 2) For filters (XPATH_OP_FILTER): 11932 * - an inner filter operater OR 11933 * - an expression selecting the node set. 11934 * E.g. "key('a', 'b')" or "(//foo | //bar)". 11935 */ 11936 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER)) 11937 return(0); 11938 11939 if (op->ch2 != -1) { 11940 exprOp = &ctxt->comp->steps[op->ch2]; 11941 } else 11942 return(0); 11943 11944 if ((exprOp != NULL) && 11945 (exprOp->op == XPATH_OP_VALUE) && 11946 (exprOp->value4 != NULL) && 11947 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER)) 11948 { 11949 /* 11950 * We have a "[n]" predicate here. 11951 * TODO: Unfortunately this simplistic test here is not 11952 * able to detect a position() predicate in compound 11953 * expressions like "[@attr = 'a" and position() = 1], 11954 * and even not the usage of position() in 11955 * "[position() = 1]"; thus - obviously - a position-range, 11956 * like it "[position() < 5]", is also not detected. 11957 * Maybe we could rewrite the AST to ease the optimization. 11958 */ 11959 *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval; 11960 11961 if (((xmlXPathObjectPtr) exprOp->value4)->floatval == 11962 (float) *maxPos) 11963 { 11964 return(1); 11965 } 11966 } 11967 return(0); 11968 } 11969 11970 static int 11971 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, 11972 xmlXPathStepOpPtr op, 11973 xmlNodePtr * first, xmlNodePtr * last, 11974 int toBool) 11975 { 11976 11977 #define XP_TEST_HIT \ 11978 if (hasAxisRange != 0) { \ 11979 if (++pos == maxPos) { \ 11980 addNode(seq, cur); \ 11981 goto axis_range_end; } \ 11982 } else { \ 11983 addNode(seq, cur); \ 11984 if (breakOnFirstHit) goto first_hit; } 11985 11986 #define XP_TEST_HIT_NS \ 11987 if (hasAxisRange != 0) { \ 11988 if (++pos == maxPos) { \ 11989 hasNsNodes = 1; \ 11990 xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \ 11991 goto axis_range_end; } \ 11992 } else { \ 11993 hasNsNodes = 1; \ 11994 xmlXPathNodeSetAddNs(seq, \ 11995 xpctxt->node, (xmlNsPtr) cur); \ 11996 if (breakOnFirstHit) goto first_hit; } 11997 11998 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value; 11999 xmlXPathTestVal test = (xmlXPathTestVal) op->value2; 12000 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3; 12001 const xmlChar *prefix = op->value4; 12002 const xmlChar *name = op->value5; 12003 const xmlChar *URI = NULL; 12004 12005 #ifdef DEBUG_STEP 12006 int nbMatches = 0, prevMatches = 0; 12007 #endif 12008 int total = 0, hasNsNodes = 0; 12009 /* The popped object holding the context nodes */ 12010 xmlXPathObjectPtr obj; 12011 /* The set of context nodes for the node tests */ 12012 xmlNodeSetPtr contextSeq; 12013 int contextIdx; 12014 xmlNodePtr contextNode; 12015 /* The context node for a compound traversal */ 12016 xmlNodePtr outerContextNode; 12017 /* The final resulting node set wrt to all context nodes */ 12018 xmlNodeSetPtr outSeq; 12019 /* 12020 * The temporary resulting node set wrt 1 context node. 12021 * Used to feed predicate evaluation. 12022 */ 12023 xmlNodeSetPtr seq; 12024 xmlNodePtr cur; 12025 /* First predicate operator */ 12026 xmlXPathStepOpPtr predOp; 12027 int maxPos; /* The requested position() (when a "[n]" predicate) */ 12028 int hasPredicateRange, hasAxisRange, pos, size, newSize; 12029 int breakOnFirstHit; 12030 12031 xmlXPathTraversalFunction next = NULL; 12032 /* compound axis traversal */ 12033 xmlXPathTraversalFunctionExt outerNext = NULL; 12034 void (*addNode) (xmlNodeSetPtr, xmlNodePtr); 12035 xmlXPathNodeSetMergeFunction mergeAndClear; 12036 xmlNodePtr oldContextNode; 12037 xmlXPathContextPtr xpctxt = ctxt->context; 12038 12039 12040 CHECK_TYPE0(XPATH_NODESET); 12041 obj = valuePop(ctxt); 12042 /* 12043 * Setup namespaces. 12044 */ 12045 if (prefix != NULL) { 12046 URI = xmlXPathNsLookup(xpctxt, prefix); 12047 if (URI == NULL) { 12048 xmlXPathReleaseObject(xpctxt, obj); 12049 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); 12050 } 12051 } 12052 /* 12053 * Setup axis. 12054 * 12055 * MAYBE FUTURE TODO: merging optimizations: 12056 * - If the nodes to be traversed wrt to the initial nodes and 12057 * the current axis cannot overlap, then we could avoid searching 12058 * for duplicates during the merge. 12059 * But the question is how/when to evaluate if they cannot overlap. 12060 * Example: if we know that for two initial nodes, the one is 12061 * not in the ancestor-or-self axis of the other, then we could safely 12062 * avoid a duplicate-aware merge, if the axis to be traversed is e.g. 12063 * the descendant-or-self axis. 12064 */ 12065 mergeAndClear = xmlXPathNodeSetMergeAndClear; 12066 switch (axis) { 12067 case AXIS_ANCESTOR: 12068 first = NULL; 12069 next = xmlXPathNextAncestor; 12070 break; 12071 case AXIS_ANCESTOR_OR_SELF: 12072 first = NULL; 12073 next = xmlXPathNextAncestorOrSelf; 12074 break; 12075 case AXIS_ATTRIBUTE: 12076 first = NULL; 12077 last = NULL; 12078 next = xmlXPathNextAttribute; 12079 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12080 break; 12081 case AXIS_CHILD: 12082 last = NULL; 12083 if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) { 12084 /* 12085 * This iterator will give us only nodes which can 12086 * hold element nodes. 12087 */ 12088 outerNext = xmlXPathNextDescendantOrSelfElemParent; 12089 } 12090 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) && 12091 (type == NODE_TYPE_NODE)) 12092 { 12093 /* 12094 * Optimization if an element node type is 'element'. 12095 */ 12096 next = xmlXPathNextChildElement; 12097 } else 12098 next = xmlXPathNextChild; 12099 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12100 break; 12101 case AXIS_DESCENDANT: 12102 last = NULL; 12103 next = xmlXPathNextDescendant; 12104 break; 12105 case AXIS_DESCENDANT_OR_SELF: 12106 last = NULL; 12107 next = xmlXPathNextDescendantOrSelf; 12108 break; 12109 case AXIS_FOLLOWING: 12110 last = NULL; 12111 next = xmlXPathNextFollowing; 12112 break; 12113 case AXIS_FOLLOWING_SIBLING: 12114 last = NULL; 12115 next = xmlXPathNextFollowingSibling; 12116 break; 12117 case AXIS_NAMESPACE: 12118 first = NULL; 12119 last = NULL; 12120 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; 12121 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12122 break; 12123 case AXIS_PARENT: 12124 first = NULL; 12125 next = xmlXPathNextParent; 12126 break; 12127 case AXIS_PRECEDING: 12128 first = NULL; 12129 next = xmlXPathNextPrecedingInternal; 12130 break; 12131 case AXIS_PRECEDING_SIBLING: 12132 first = NULL; 12133 next = xmlXPathNextPrecedingSibling; 12134 break; 12135 case AXIS_SELF: 12136 first = NULL; 12137 last = NULL; 12138 next = xmlXPathNextSelf; 12139 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12140 break; 12141 } 12142 12143 #ifdef DEBUG_STEP 12144 xmlXPathDebugDumpStepAxis(op, 12145 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0); 12146 #endif 12147 12148 if (next == NULL) { 12149 xmlXPathReleaseObject(xpctxt, obj); 12150 return(0); 12151 } 12152 contextSeq = obj->nodesetval; 12153 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) { 12154 xmlXPathReleaseObject(xpctxt, obj); 12155 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL)); 12156 return(0); 12157 } 12158 /* 12159 * Predicate optimization --------------------------------------------- 12160 * If this step has a last predicate, which contains a position(), 12161 * then we'll optimize (although not exactly "position()", but only 12162 * the short-hand form, i.e., "[n]". 12163 * 12164 * Example - expression "/foo[parent::bar][1]": 12165 * 12166 * COLLECT 'child' 'name' 'node' foo -- op (we are here) 12167 * ROOT -- op->ch1 12168 * PREDICATE -- op->ch2 (predOp) 12169 * PREDICATE -- predOp->ch1 = [parent::bar] 12170 * SORT 12171 * COLLECT 'parent' 'name' 'node' bar 12172 * NODE 12173 * ELEM Object is a number : 1 -- predOp->ch2 = [1] 12174 * 12175 */ 12176 maxPos = 0; 12177 predOp = NULL; 12178 hasPredicateRange = 0; 12179 hasAxisRange = 0; 12180 if (op->ch2 != -1) { 12181 /* 12182 * There's at least one predicate. 16 == XPATH_OP_PREDICATE 12183 */ 12184 predOp = &ctxt->comp->steps[op->ch2]; 12185 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) { 12186 if (predOp->ch1 != -1) { 12187 /* 12188 * Use the next inner predicate operator. 12189 */ 12190 predOp = &ctxt->comp->steps[predOp->ch1]; 12191 hasPredicateRange = 1; 12192 } else { 12193 /* 12194 * There's no other predicate than the [n] predicate. 12195 */ 12196 predOp = NULL; 12197 hasAxisRange = 1; 12198 } 12199 } 12200 } 12201 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0; 12202 /* 12203 * Axis traversal ----------------------------------------------------- 12204 */ 12205 /* 12206 * 2.3 Node Tests 12207 * - For the attribute axis, the principal node type is attribute. 12208 * - For the namespace axis, the principal node type is namespace. 12209 * - For other axes, the principal node type is element. 12210 * 12211 * A node test * is true for any node of the 12212 * principal node type. For example, child::* will 12213 * select all element children of the context node 12214 */ 12215 oldContextNode = xpctxt->node; 12216 addNode = xmlXPathNodeSetAddUnique; 12217 outSeq = NULL; 12218 seq = NULL; 12219 outerContextNode = NULL; 12220 contextNode = NULL; 12221 contextIdx = 0; 12222 12223 12224 while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) { 12225 if (outerNext != NULL) { 12226 /* 12227 * This is a compound traversal. 12228 */ 12229 if (contextNode == NULL) { 12230 /* 12231 * Set the context for the outer traversal. 12232 */ 12233 outerContextNode = contextSeq->nodeTab[contextIdx++]; 12234 contextNode = outerNext(NULL, outerContextNode); 12235 } else 12236 contextNode = outerNext(contextNode, outerContextNode); 12237 if (contextNode == NULL) 12238 continue; 12239 /* 12240 * Set the context for the main traversal. 12241 */ 12242 xpctxt->node = contextNode; 12243 } else 12244 xpctxt->node = contextSeq->nodeTab[contextIdx++]; 12245 12246 if (seq == NULL) { 12247 seq = xmlXPathNodeSetCreate(NULL); 12248 if (seq == NULL) { 12249 total = 0; 12250 goto error; 12251 } 12252 } 12253 /* 12254 * Traverse the axis and test the nodes. 12255 */ 12256 pos = 0; 12257 cur = NULL; 12258 hasNsNodes = 0; 12259 do { 12260 cur = next(ctxt, cur); 12261 if (cur == NULL) 12262 break; 12263 12264 /* 12265 * QUESTION TODO: What does the "first" and "last" stuff do? 12266 */ 12267 if ((first != NULL) && (*first != NULL)) { 12268 if (*first == cur) 12269 break; 12270 if (((total % 256) == 0) && 12271 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 12272 (xmlXPathCmpNodesExt(*first, cur) >= 0)) 12273 #else 12274 (xmlXPathCmpNodes(*first, cur) >= 0)) 12275 #endif 12276 { 12277 break; 12278 } 12279 } 12280 if ((last != NULL) && (*last != NULL)) { 12281 if (*last == cur) 12282 break; 12283 if (((total % 256) == 0) && 12284 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 12285 (xmlXPathCmpNodesExt(cur, *last) >= 0)) 12286 #else 12287 (xmlXPathCmpNodes(cur, *last) >= 0)) 12288 #endif 12289 { 12290 break; 12291 } 12292 } 12293 12294 total++; 12295 12296 #ifdef DEBUG_STEP 12297 xmlGenericError(xmlGenericErrorContext, " %s", cur->name); 12298 #endif 12299 12300 switch (test) { 12301 case NODE_TEST_NONE: 12302 total = 0; 12303 STRANGE 12304 goto error; 12305 case NODE_TEST_TYPE: 12306 /* 12307 * TODO: Don't we need to use 12308 * xmlXPathNodeSetAddNs() for namespace nodes here? 12309 * Surprisingly, some c14n tests fail, if we do this. 12310 */ 12311 if (type == NODE_TYPE_NODE) { 12312 switch (cur->type) { 12313 case XML_DOCUMENT_NODE: 12314 case XML_HTML_DOCUMENT_NODE: 12315 #ifdef LIBXML_DOCB_ENABLED 12316 case XML_DOCB_DOCUMENT_NODE: 12317 #endif 12318 case XML_ELEMENT_NODE: 12319 case XML_ATTRIBUTE_NODE: 12320 case XML_PI_NODE: 12321 case XML_COMMENT_NODE: 12322 case XML_CDATA_SECTION_NODE: 12323 case XML_TEXT_NODE: 12324 case XML_NAMESPACE_DECL: 12325 XP_TEST_HIT 12326 break; 12327 default: 12328 break; 12329 } 12330 } else if (cur->type == type) { 12331 if (type == XML_NAMESPACE_DECL) 12332 XP_TEST_HIT_NS 12333 else 12334 XP_TEST_HIT 12335 } else if ((type == NODE_TYPE_TEXT) && 12336 (cur->type == XML_CDATA_SECTION_NODE)) 12337 { 12338 XP_TEST_HIT 12339 } 12340 break; 12341 case NODE_TEST_PI: 12342 if ((cur->type == XML_PI_NODE) && 12343 ((name == NULL) || xmlStrEqual(name, cur->name))) 12344 { 12345 XP_TEST_HIT 12346 } 12347 break; 12348 case NODE_TEST_ALL: 12349 if (axis == AXIS_ATTRIBUTE) { 12350 if (cur->type == XML_ATTRIBUTE_NODE) 12351 { 12352 XP_TEST_HIT 12353 } 12354 } else if (axis == AXIS_NAMESPACE) { 12355 if (cur->type == XML_NAMESPACE_DECL) 12356 { 12357 XP_TEST_HIT_NS 12358 } 12359 } else { 12360 if (cur->type == XML_ELEMENT_NODE) { 12361 if (prefix == NULL) 12362 { 12363 XP_TEST_HIT 12364 12365 } else if ((cur->ns != NULL) && 12366 (xmlStrEqual(URI, cur->ns->href))) 12367 { 12368 XP_TEST_HIT 12369 } 12370 } 12371 } 12372 break; 12373 case NODE_TEST_NS:{ 12374 TODO; 12375 break; 12376 } 12377 case NODE_TEST_NAME: 12378 if (axis == AXIS_ATTRIBUTE) { 12379 if (cur->type != XML_ATTRIBUTE_NODE) 12380 break; 12381 } else if (axis == AXIS_NAMESPACE) { 12382 if (cur->type != XML_NAMESPACE_DECL) 12383 break; 12384 } else { 12385 if (cur->type != XML_ELEMENT_NODE) 12386 break; 12387 } 12388 switch (cur->type) { 12389 case XML_ELEMENT_NODE: 12390 if (xmlStrEqual(name, cur->name)) { 12391 if (prefix == NULL) { 12392 if (cur->ns == NULL) 12393 { 12394 XP_TEST_HIT 12395 } 12396 } else { 12397 if ((cur->ns != NULL) && 12398 (xmlStrEqual(URI, cur->ns->href))) 12399 { 12400 XP_TEST_HIT 12401 } 12402 } 12403 } 12404 break; 12405 case XML_ATTRIBUTE_NODE:{ 12406 xmlAttrPtr attr = (xmlAttrPtr) cur; 12407 12408 if (xmlStrEqual(name, attr->name)) { 12409 if (prefix == NULL) { 12410 if ((attr->ns == NULL) || 12411 (attr->ns->prefix == NULL)) 12412 { 12413 XP_TEST_HIT 12414 } 12415 } else { 12416 if ((attr->ns != NULL) && 12417 (xmlStrEqual(URI, 12418 attr->ns->href))) 12419 { 12420 XP_TEST_HIT 12421 } 12422 } 12423 } 12424 break; 12425 } 12426 case XML_NAMESPACE_DECL: 12427 if (cur->type == XML_NAMESPACE_DECL) { 12428 xmlNsPtr ns = (xmlNsPtr) cur; 12429 12430 if ((ns->prefix != NULL) && (name != NULL) 12431 && (xmlStrEqual(ns->prefix, name))) 12432 { 12433 XP_TEST_HIT_NS 12434 } 12435 } 12436 break; 12437 default: 12438 break; 12439 } 12440 break; 12441 } /* switch(test) */ 12442 } while (cur != NULL); 12443 12444 goto apply_predicates; 12445 12446 axis_range_end: /* ----------------------------------------------------- */ 12447 /* 12448 * We have a "/foo[n]", and position() = n was reached. 12449 * Note that we can have as well "/foo/::parent::foo[1]", so 12450 * a duplicate-aware merge is still needed. 12451 * Merge with the result. 12452 */ 12453 if (outSeq == NULL) { 12454 outSeq = seq; 12455 seq = NULL; 12456 } else 12457 outSeq = mergeAndClear(outSeq, seq, 0); 12458 /* 12459 * Break if only a true/false result was requested. 12460 */ 12461 if (toBool) 12462 break; 12463 continue; 12464 12465 first_hit: /* ---------------------------------------------------------- */ 12466 /* 12467 * Break if only a true/false result was requested and 12468 * no predicates existed and a node test succeeded. 12469 */ 12470 if (outSeq == NULL) { 12471 outSeq = seq; 12472 seq = NULL; 12473 } else 12474 outSeq = mergeAndClear(outSeq, seq, 0); 12475 break; 12476 12477 #ifdef DEBUG_STEP 12478 if (seq != NULL) 12479 nbMatches += seq->nodeNr; 12480 #endif 12481 12482 apply_predicates: /* --------------------------------------------------- */ 12483 /* 12484 * Apply predicates. 12485 */ 12486 if ((predOp != NULL) && (seq->nodeNr > 0)) { 12487 /* 12488 * E.g. when we have a "/foo[some expression][n]". 12489 */ 12490 /* 12491 * QUESTION TODO: The old predicate evaluation took into 12492 * account location-sets. 12493 * (E.g. ctxt->value->type == XPATH_LOCATIONSET) 12494 * Do we expect such a set here? 12495 * All what I learned now from the evaluation semantics 12496 * does not indicate that a location-set will be processed 12497 * here, so this looks OK. 12498 */ 12499 /* 12500 * Iterate over all predicates, starting with the outermost 12501 * predicate. 12502 * TODO: Problem: we cannot execute the inner predicates first 12503 * since we cannot go back *up* the operator tree! 12504 * Options we have: 12505 * 1) Use of recursive functions (like is it currently done 12506 * via xmlXPathCompOpEval()) 12507 * 2) Add a predicate evaluation information stack to the 12508 * context struct 12509 * 3) Change the way the operators are linked; we need a 12510 * "parent" field on xmlXPathStepOp 12511 * 12512 * For the moment, I'll try to solve this with a recursive 12513 * function: xmlXPathCompOpEvalPredicate(). 12514 */ 12515 size = seq->nodeNr; 12516 if (hasPredicateRange != 0) 12517 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt, 12518 predOp, seq, size, maxPos, maxPos, hasNsNodes); 12519 else 12520 newSize = xmlXPathCompOpEvalPredicate(ctxt, 12521 predOp, seq, size, hasNsNodes); 12522 12523 if (ctxt->error != XPATH_EXPRESSION_OK) { 12524 total = 0; 12525 goto error; 12526 } 12527 /* 12528 * Add the filtered set of nodes to the result node set. 12529 */ 12530 if (newSize == 0) { 12531 /* 12532 * The predicates filtered all nodes out. 12533 */ 12534 xmlXPathNodeSetClear(seq, hasNsNodes); 12535 } else if (seq->nodeNr > 0) { 12536 /* 12537 * Add to result set. 12538 */ 12539 if (outSeq == NULL) { 12540 if (size != newSize) { 12541 /* 12542 * We need to merge and clear here, since 12543 * the sequence will contained NULLed entries. 12544 */ 12545 outSeq = mergeAndClear(NULL, seq, 1); 12546 } else { 12547 outSeq = seq; 12548 seq = NULL; 12549 } 12550 } else 12551 outSeq = mergeAndClear(outSeq, seq, 12552 (size != newSize) ? 1: 0); 12553 /* 12554 * Break if only a true/false result was requested. 12555 */ 12556 if (toBool) 12557 break; 12558 } 12559 } else if (seq->nodeNr > 0) { 12560 /* 12561 * Add to result set. 12562 */ 12563 if (outSeq == NULL) { 12564 outSeq = seq; 12565 seq = NULL; 12566 } else { 12567 outSeq = mergeAndClear(outSeq, seq, 0); 12568 } 12569 } 12570 } 12571 12572 error: 12573 if ((obj->boolval) && (obj->user != NULL)) { 12574 /* 12575 * QUESTION TODO: What does this do and why? 12576 * TODO: Do we have to do this also for the "error" 12577 * cleanup further down? 12578 */ 12579 ctxt->value->boolval = 1; 12580 ctxt->value->user = obj->user; 12581 obj->user = NULL; 12582 obj->boolval = 0; 12583 } 12584 xmlXPathReleaseObject(xpctxt, obj); 12585 12586 /* 12587 * Ensure we return at least an emtpy set. 12588 */ 12589 if (outSeq == NULL) { 12590 if ((seq != NULL) && (seq->nodeNr == 0)) 12591 outSeq = seq; 12592 else 12593 outSeq = xmlXPathNodeSetCreate(NULL); 12594 /* XXX what if xmlXPathNodeSetCreate returned NULL here? */ 12595 } 12596 if ((seq != NULL) && (seq != outSeq)) { 12597 xmlXPathFreeNodeSet(seq); 12598 } 12599 /* 12600 * Hand over the result. Better to push the set also in 12601 * case of errors. 12602 */ 12603 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq)); 12604 /* 12605 * Reset the context node. 12606 */ 12607 xpctxt->node = oldContextNode; 12608 12609 #ifdef DEBUG_STEP 12610 xmlGenericError(xmlGenericErrorContext, 12611 "\nExamined %d nodes, found %d nodes at that step\n", 12612 total, nbMatches); 12613 #endif 12614 12615 return(total); 12616 } 12617 12618 static int 12619 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt, 12620 xmlXPathStepOpPtr op, xmlNodePtr * first); 12621 12622 /** 12623 * xmlXPathCompOpEvalFirst: 12624 * @ctxt: the XPath parser context with the compiled expression 12625 * @op: an XPath compiled operation 12626 * @first: the first elem found so far 12627 * 12628 * Evaluate the Precompiled XPath operation searching only the first 12629 * element in document order 12630 * 12631 * Returns the number of examined objects. 12632 */ 12633 static int 12634 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt, 12635 xmlXPathStepOpPtr op, xmlNodePtr * first) 12636 { 12637 int total = 0, cur; 12638 xmlXPathCompExprPtr comp; 12639 xmlXPathObjectPtr arg1, arg2; 12640 12641 CHECK_ERROR0; 12642 comp = ctxt->comp; 12643 switch (op->op) { 12644 case XPATH_OP_END: 12645 return (0); 12646 case XPATH_OP_UNION: 12647 total = 12648 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1], 12649 first); 12650 CHECK_ERROR0; 12651 if ((ctxt->value != NULL) 12652 && (ctxt->value->type == XPATH_NODESET) 12653 && (ctxt->value->nodesetval != NULL) 12654 && (ctxt->value->nodesetval->nodeNr >= 1)) { 12655 /* 12656 * limit tree traversing to first node in the result 12657 */ 12658 /* 12659 * OPTIMIZE TODO: This implicitely sorts 12660 * the result, even if not needed. E.g. if the argument 12661 * of the count() function, no sorting is needed. 12662 * OPTIMIZE TODO: How do we know if the node-list wasn't 12663 * aready sorted? 12664 */ 12665 if (ctxt->value->nodesetval->nodeNr > 1) 12666 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12667 *first = ctxt->value->nodesetval->nodeTab[0]; 12668 } 12669 cur = 12670 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2], 12671 first); 12672 CHECK_ERROR0; 12673 CHECK_TYPE0(XPATH_NODESET); 12674 arg2 = valuePop(ctxt); 12675 12676 CHECK_TYPE0(XPATH_NODESET); 12677 arg1 = valuePop(ctxt); 12678 12679 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 12680 arg2->nodesetval); 12681 valuePush(ctxt, arg1); 12682 xmlXPathReleaseObject(ctxt->context, arg2); 12683 /* optimizer */ 12684 if (total > cur) 12685 xmlXPathCompSwap(op); 12686 return (total + cur); 12687 case XPATH_OP_ROOT: 12688 xmlXPathRoot(ctxt); 12689 return (0); 12690 case XPATH_OP_NODE: 12691 if (op->ch1 != -1) 12692 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12693 CHECK_ERROR0; 12694 if (op->ch2 != -1) 12695 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12696 CHECK_ERROR0; 12697 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 12698 ctxt->context->node)); 12699 return (total); 12700 case XPATH_OP_RESET: 12701 if (op->ch1 != -1) 12702 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12703 CHECK_ERROR0; 12704 if (op->ch2 != -1) 12705 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12706 CHECK_ERROR0; 12707 ctxt->context->node = NULL; 12708 return (total); 12709 case XPATH_OP_COLLECT:{ 12710 if (op->ch1 == -1) 12711 return (total); 12712 12713 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12714 CHECK_ERROR0; 12715 12716 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0); 12717 return (total); 12718 } 12719 case XPATH_OP_VALUE: 12720 valuePush(ctxt, 12721 xmlXPathCacheObjectCopy(ctxt->context, 12722 (xmlXPathObjectPtr) op->value4)); 12723 return (0); 12724 case XPATH_OP_SORT: 12725 if (op->ch1 != -1) 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 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12735 return (total); 12736 #ifdef XP_OPTIMIZED_FILTER_FIRST 12737 case XPATH_OP_FILTER: 12738 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first); 12739 return (total); 12740 #endif 12741 default: 12742 return (xmlXPathCompOpEval(ctxt, op)); 12743 } 12744 } 12745 12746 /** 12747 * xmlXPathCompOpEvalLast: 12748 * @ctxt: the XPath parser context with the compiled expression 12749 * @op: an XPath compiled operation 12750 * @last: the last elem found so far 12751 * 12752 * Evaluate the Precompiled XPath operation searching only the last 12753 * element in document order 12754 * 12755 * Returns the number of nodes traversed 12756 */ 12757 static int 12758 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op, 12759 xmlNodePtr * last) 12760 { 12761 int total = 0, cur; 12762 xmlXPathCompExprPtr comp; 12763 xmlXPathObjectPtr arg1, arg2; 12764 xmlNodePtr bak; 12765 xmlDocPtr bakd; 12766 int pp; 12767 int cs; 12768 12769 CHECK_ERROR0; 12770 comp = ctxt->comp; 12771 switch (op->op) { 12772 case XPATH_OP_END: 12773 return (0); 12774 case XPATH_OP_UNION: 12775 bakd = ctxt->context->doc; 12776 bak = ctxt->context->node; 12777 pp = ctxt->context->proximityPosition; 12778 cs = ctxt->context->contextSize; 12779 total = 12780 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last); 12781 CHECK_ERROR0; 12782 if ((ctxt->value != NULL) 12783 && (ctxt->value->type == XPATH_NODESET) 12784 && (ctxt->value->nodesetval != NULL) 12785 && (ctxt->value->nodesetval->nodeNr >= 1)) { 12786 /* 12787 * limit tree traversing to first node in the result 12788 */ 12789 if (ctxt->value->nodesetval->nodeNr > 1) 12790 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12791 *last = 12792 ctxt->value->nodesetval->nodeTab[ctxt->value-> 12793 nodesetval->nodeNr - 12794 1]; 12795 } 12796 ctxt->context->doc = bakd; 12797 ctxt->context->node = bak; 12798 ctxt->context->proximityPosition = pp; 12799 ctxt->context->contextSize = cs; 12800 cur = 12801 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last); 12802 CHECK_ERROR0; 12803 if ((ctxt->value != NULL) 12804 && (ctxt->value->type == XPATH_NODESET) 12805 && (ctxt->value->nodesetval != NULL) 12806 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */ 12807 } 12808 CHECK_TYPE0(XPATH_NODESET); 12809 arg2 = valuePop(ctxt); 12810 12811 CHECK_TYPE0(XPATH_NODESET); 12812 arg1 = valuePop(ctxt); 12813 12814 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 12815 arg2->nodesetval); 12816 valuePush(ctxt, arg1); 12817 xmlXPathReleaseObject(ctxt->context, arg2); 12818 /* optimizer */ 12819 if (total > cur) 12820 xmlXPathCompSwap(op); 12821 return (total + cur); 12822 case XPATH_OP_ROOT: 12823 xmlXPathRoot(ctxt); 12824 return (0); 12825 case XPATH_OP_NODE: 12826 if (op->ch1 != -1) 12827 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12828 CHECK_ERROR0; 12829 if (op->ch2 != -1) 12830 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12831 CHECK_ERROR0; 12832 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 12833 ctxt->context->node)); 12834 return (total); 12835 case XPATH_OP_RESET: 12836 if (op->ch1 != -1) 12837 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12838 CHECK_ERROR0; 12839 if (op->ch2 != -1) 12840 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12841 CHECK_ERROR0; 12842 ctxt->context->node = NULL; 12843 return (total); 12844 case XPATH_OP_COLLECT:{ 12845 if (op->ch1 == -1) 12846 return (0); 12847 12848 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12849 CHECK_ERROR0; 12850 12851 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0); 12852 return (total); 12853 } 12854 case XPATH_OP_VALUE: 12855 valuePush(ctxt, 12856 xmlXPathCacheObjectCopy(ctxt->context, 12857 (xmlXPathObjectPtr) op->value4)); 12858 return (0); 12859 case XPATH_OP_SORT: 12860 if (op->ch1 != -1) 12861 total += 12862 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], 12863 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)) 12869 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12870 return (total); 12871 default: 12872 return (xmlXPathCompOpEval(ctxt, op)); 12873 } 12874 } 12875 12876 #ifdef XP_OPTIMIZED_FILTER_FIRST 12877 static int 12878 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt, 12879 xmlXPathStepOpPtr op, xmlNodePtr * first) 12880 { 12881 int total = 0; 12882 xmlXPathCompExprPtr comp; 12883 xmlXPathObjectPtr res; 12884 xmlXPathObjectPtr obj; 12885 xmlNodeSetPtr oldset; 12886 xmlNodePtr oldnode; 12887 xmlDocPtr oldDoc; 12888 int i; 12889 12890 CHECK_ERROR0; 12891 comp = ctxt->comp; 12892 /* 12893 * Optimization for ()[last()] selection i.e. the last elem 12894 */ 12895 if ((op->ch1 != -1) && (op->ch2 != -1) && 12896 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 12897 (comp->steps[op->ch2].op == XPATH_OP_SORT)) { 12898 int f = comp->steps[op->ch2].ch1; 12899 12900 if ((f != -1) && 12901 (comp->steps[f].op == XPATH_OP_FUNCTION) && 12902 (comp->steps[f].value5 == NULL) && 12903 (comp->steps[f].value == 0) && 12904 (comp->steps[f].value4 != NULL) && 12905 (xmlStrEqual 12906 (comp->steps[f].value4, BAD_CAST "last"))) { 12907 xmlNodePtr last = NULL; 12908 12909 total += 12910 xmlXPathCompOpEvalLast(ctxt, 12911 &comp->steps[op->ch1], 12912 &last); 12913 CHECK_ERROR0; 12914 /* 12915 * The nodeset should be in document order, 12916 * Keep only the last value 12917 */ 12918 if ((ctxt->value != NULL) && 12919 (ctxt->value->type == XPATH_NODESET) && 12920 (ctxt->value->nodesetval != NULL) && 12921 (ctxt->value->nodesetval->nodeTab != NULL) && 12922 (ctxt->value->nodesetval->nodeNr > 1)) { 12923 ctxt->value->nodesetval->nodeTab[0] = 12924 ctxt->value->nodesetval->nodeTab[ctxt-> 12925 value-> 12926 nodesetval-> 12927 nodeNr - 12928 1]; 12929 ctxt->value->nodesetval->nodeNr = 1; 12930 *first = *(ctxt->value->nodesetval->nodeTab); 12931 } 12932 return (total); 12933 } 12934 } 12935 12936 if (op->ch1 != -1) 12937 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12938 CHECK_ERROR0; 12939 if (op->ch2 == -1) 12940 return (total); 12941 if (ctxt->value == NULL) 12942 return (total); 12943 12944 #ifdef LIBXML_XPTR_ENABLED 12945 oldnode = ctxt->context->node; 12946 /* 12947 * Hum are we filtering the result of an XPointer expression 12948 */ 12949 if (ctxt->value->type == XPATH_LOCATIONSET) { 12950 xmlXPathObjectPtr tmp = NULL; 12951 xmlLocationSetPtr newlocset = NULL; 12952 xmlLocationSetPtr oldlocset; 12953 12954 /* 12955 * Extract the old locset, and then evaluate the result of the 12956 * expression for all the element in the locset. use it to grow 12957 * up a new locset. 12958 */ 12959 CHECK_TYPE0(XPATH_LOCATIONSET); 12960 obj = valuePop(ctxt); 12961 oldlocset = obj->user; 12962 ctxt->context->node = NULL; 12963 12964 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) { 12965 ctxt->context->contextSize = 0; 12966 ctxt->context->proximityPosition = 0; 12967 if (op->ch2 != -1) 12968 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12969 res = valuePop(ctxt); 12970 if (res != NULL) { 12971 xmlXPathReleaseObject(ctxt->context, res); 12972 } 12973 valuePush(ctxt, obj); 12974 CHECK_ERROR0; 12975 return (total); 12976 } 12977 newlocset = xmlXPtrLocationSetCreate(NULL); 12978 12979 for (i = 0; i < oldlocset->locNr; i++) { 12980 /* 12981 * Run the evaluation with a node list made of a 12982 * single item in the nodelocset. 12983 */ 12984 ctxt->context->node = oldlocset->locTab[i]->user; 12985 ctxt->context->contextSize = oldlocset->locNr; 12986 ctxt->context->proximityPosition = i + 1; 12987 if (tmp == NULL) { 12988 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 12989 ctxt->context->node); 12990 } else { 12991 xmlXPathNodeSetAddUnique(tmp->nodesetval, 12992 ctxt->context->node); 12993 } 12994 valuePush(ctxt, tmp); 12995 if (op->ch2 != -1) 12996 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12997 if (ctxt->error != XPATH_EXPRESSION_OK) { 12998 xmlXPathFreeObject(obj); 12999 return(0); 13000 } 13001 /* 13002 * The result of the evaluation need to be tested to 13003 * decided whether the filter succeeded or not 13004 */ 13005 res = valuePop(ctxt); 13006 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 13007 xmlXPtrLocationSetAdd(newlocset, 13008 xmlXPathCacheObjectCopy(ctxt->context, 13009 oldlocset->locTab[i])); 13010 } 13011 /* 13012 * Cleanup 13013 */ 13014 if (res != NULL) { 13015 xmlXPathReleaseObject(ctxt->context, res); 13016 } 13017 if (ctxt->value == tmp) { 13018 valuePop(ctxt); 13019 xmlXPathNodeSetClear(tmp->nodesetval, 1); 13020 /* 13021 * REVISIT TODO: Don't create a temporary nodeset 13022 * for everly iteration. 13023 */ 13024 /* OLD: xmlXPathFreeObject(res); */ 13025 } else 13026 tmp = NULL; 13027 ctxt->context->node = NULL; 13028 /* 13029 * Only put the first node in the result, then leave. 13030 */ 13031 if (newlocset->locNr > 0) { 13032 *first = (xmlNodePtr) oldlocset->locTab[i]->user; 13033 break; 13034 } 13035 } 13036 if (tmp != NULL) { 13037 xmlXPathReleaseObject(ctxt->context, tmp); 13038 } 13039 /* 13040 * The result is used as the new evaluation locset. 13041 */ 13042 xmlXPathReleaseObject(ctxt->context, obj); 13043 ctxt->context->node = NULL; 13044 ctxt->context->contextSize = -1; 13045 ctxt->context->proximityPosition = -1; 13046 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset)); 13047 ctxt->context->node = oldnode; 13048 return (total); 13049 } 13050 #endif /* LIBXML_XPTR_ENABLED */ 13051 13052 /* 13053 * Extract the old set, and then evaluate the result of the 13054 * expression for all the element in the set. use it to grow 13055 * up a new set. 13056 */ 13057 CHECK_TYPE0(XPATH_NODESET); 13058 obj = valuePop(ctxt); 13059 oldset = obj->nodesetval; 13060 13061 oldnode = ctxt->context->node; 13062 oldDoc = ctxt->context->doc; 13063 ctxt->context->node = NULL; 13064 13065 if ((oldset == NULL) || (oldset->nodeNr == 0)) { 13066 ctxt->context->contextSize = 0; 13067 ctxt->context->proximityPosition = 0; 13068 /* QUESTION TODO: Why was this code commented out? 13069 if (op->ch2 != -1) 13070 total += 13071 xmlXPathCompOpEval(ctxt, 13072 &comp->steps[op->ch2]); 13073 CHECK_ERROR0; 13074 res = valuePop(ctxt); 13075 if (res != NULL) 13076 xmlXPathFreeObject(res); 13077 */ 13078 valuePush(ctxt, obj); 13079 ctxt->context->node = oldnode; 13080 CHECK_ERROR0; 13081 } else { 13082 xmlNodeSetPtr newset; 13083 xmlXPathObjectPtr tmp = NULL; 13084 /* 13085 * Initialize the new set. 13086 * Also set the xpath document in case things like 13087 * key() evaluation are attempted on the predicate 13088 */ 13089 newset = xmlXPathNodeSetCreate(NULL); 13090 /* XXX what if xmlXPathNodeSetCreate returned NULL? */ 13091 13092 for (i = 0; i < oldset->nodeNr; i++) { 13093 /* 13094 * Run the evaluation with a node list made of 13095 * a single item in the nodeset. 13096 */ 13097 ctxt->context->node = oldset->nodeTab[i]; 13098 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) && 13099 (oldset->nodeTab[i]->doc != NULL)) 13100 ctxt->context->doc = oldset->nodeTab[i]->doc; 13101 if (tmp == NULL) { 13102 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13103 ctxt->context->node); 13104 } else { 13105 xmlXPathNodeSetAddUnique(tmp->nodesetval, 13106 ctxt->context->node); 13107 } 13108 valuePush(ctxt, tmp); 13109 ctxt->context->contextSize = oldset->nodeNr; 13110 ctxt->context->proximityPosition = i + 1; 13111 if (op->ch2 != -1) 13112 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13113 if (ctxt->error != XPATH_EXPRESSION_OK) { 13114 xmlXPathFreeNodeSet(newset); 13115 xmlXPathFreeObject(obj); 13116 return(0); 13117 } 13118 /* 13119 * The result of the evaluation needs to be tested to 13120 * decide whether the filter succeeded or not 13121 */ 13122 res = valuePop(ctxt); 13123 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 13124 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]); 13125 } 13126 /* 13127 * Cleanup 13128 */ 13129 if (res != NULL) { 13130 xmlXPathReleaseObject(ctxt->context, res); 13131 } 13132 if (ctxt->value == tmp) { 13133 valuePop(ctxt); 13134 /* 13135 * Don't free the temporary nodeset 13136 * in order to avoid massive recreation inside this 13137 * loop. 13138 */ 13139 xmlXPathNodeSetClear(tmp->nodesetval, 1); 13140 } else 13141 tmp = NULL; 13142 ctxt->context->node = NULL; 13143 /* 13144 * Only put the first node in the result, then leave. 13145 */ 13146 if (newset->nodeNr > 0) { 13147 *first = *(newset->nodeTab); 13148 break; 13149 } 13150 } 13151 if (tmp != NULL) { 13152 xmlXPathReleaseObject(ctxt->context, tmp); 13153 } 13154 /* 13155 * The result is used as the new evaluation set. 13156 */ 13157 xmlXPathReleaseObject(ctxt->context, obj); 13158 ctxt->context->node = NULL; 13159 ctxt->context->contextSize = -1; 13160 ctxt->context->proximityPosition = -1; 13161 /* may want to move this past the '}' later */ 13162 ctxt->context->doc = oldDoc; 13163 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset)); 13164 } 13165 ctxt->context->node = oldnode; 13166 return(total); 13167 } 13168 #endif /* XP_OPTIMIZED_FILTER_FIRST */ 13169 13170 /** 13171 * xmlXPathCompOpEval: 13172 * @ctxt: the XPath parser context with the compiled expression 13173 * @op: an XPath compiled operation 13174 * 13175 * Evaluate the Precompiled XPath operation 13176 * Returns the number of nodes traversed 13177 */ 13178 static int 13179 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) 13180 { 13181 int total = 0; 13182 int equal, ret; 13183 xmlXPathCompExprPtr comp; 13184 xmlXPathObjectPtr arg1, arg2; 13185 xmlNodePtr bak; 13186 xmlDocPtr bakd; 13187 int pp; 13188 int cs; 13189 13190 CHECK_ERROR0; 13191 comp = ctxt->comp; 13192 switch (op->op) { 13193 case XPATH_OP_END: 13194 return (0); 13195 case XPATH_OP_AND: 13196 bakd = ctxt->context->doc; 13197 bak = ctxt->context->node; 13198 pp = ctxt->context->proximityPosition; 13199 cs = ctxt->context->contextSize; 13200 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13201 CHECK_ERROR0; 13202 xmlXPathBooleanFunction(ctxt, 1); 13203 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0)) 13204 return (total); 13205 arg2 = valuePop(ctxt); 13206 ctxt->context->doc = bakd; 13207 ctxt->context->node = bak; 13208 ctxt->context->proximityPosition = pp; 13209 ctxt->context->contextSize = cs; 13210 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13211 if (ctxt->error) { 13212 xmlXPathFreeObject(arg2); 13213 return(0); 13214 } 13215 xmlXPathBooleanFunction(ctxt, 1); 13216 arg1 = valuePop(ctxt); 13217 arg1->boolval &= arg2->boolval; 13218 valuePush(ctxt, arg1); 13219 xmlXPathReleaseObject(ctxt->context, arg2); 13220 return (total); 13221 case XPATH_OP_OR: 13222 bakd = ctxt->context->doc; 13223 bak = ctxt->context->node; 13224 pp = ctxt->context->proximityPosition; 13225 cs = ctxt->context->contextSize; 13226 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13227 CHECK_ERROR0; 13228 xmlXPathBooleanFunction(ctxt, 1); 13229 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1)) 13230 return (total); 13231 arg2 = valuePop(ctxt); 13232 ctxt->context->doc = bakd; 13233 ctxt->context->node = bak; 13234 ctxt->context->proximityPosition = pp; 13235 ctxt->context->contextSize = cs; 13236 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13237 if (ctxt->error) { 13238 xmlXPathFreeObject(arg2); 13239 return(0); 13240 } 13241 xmlXPathBooleanFunction(ctxt, 1); 13242 arg1 = valuePop(ctxt); 13243 arg1->boolval |= arg2->boolval; 13244 valuePush(ctxt, arg1); 13245 xmlXPathReleaseObject(ctxt->context, arg2); 13246 return (total); 13247 case XPATH_OP_EQUAL: 13248 bakd = ctxt->context->doc; 13249 bak = ctxt->context->node; 13250 pp = ctxt->context->proximityPosition; 13251 cs = ctxt->context->contextSize; 13252 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13253 CHECK_ERROR0; 13254 ctxt->context->doc = bakd; 13255 ctxt->context->node = bak; 13256 ctxt->context->proximityPosition = pp; 13257 ctxt->context->contextSize = cs; 13258 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13259 CHECK_ERROR0; 13260 if (op->value) 13261 equal = xmlXPathEqualValues(ctxt); 13262 else 13263 equal = xmlXPathNotEqualValues(ctxt); 13264 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal)); 13265 return (total); 13266 case XPATH_OP_CMP: 13267 bakd = ctxt->context->doc; 13268 bak = ctxt->context->node; 13269 pp = ctxt->context->proximityPosition; 13270 cs = ctxt->context->contextSize; 13271 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13272 CHECK_ERROR0; 13273 ctxt->context->doc = bakd; 13274 ctxt->context->node = bak; 13275 ctxt->context->proximityPosition = pp; 13276 ctxt->context->contextSize = cs; 13277 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13278 CHECK_ERROR0; 13279 ret = xmlXPathCompareValues(ctxt, op->value, op->value2); 13280 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret)); 13281 return (total); 13282 case XPATH_OP_PLUS: 13283 bakd = ctxt->context->doc; 13284 bak = ctxt->context->node; 13285 pp = ctxt->context->proximityPosition; 13286 cs = ctxt->context->contextSize; 13287 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13288 CHECK_ERROR0; 13289 if (op->ch2 != -1) { 13290 ctxt->context->doc = bakd; 13291 ctxt->context->node = bak; 13292 ctxt->context->proximityPosition = pp; 13293 ctxt->context->contextSize = cs; 13294 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13295 } 13296 CHECK_ERROR0; 13297 if (op->value == 0) 13298 xmlXPathSubValues(ctxt); 13299 else if (op->value == 1) 13300 xmlXPathAddValues(ctxt); 13301 else if (op->value == 2) 13302 xmlXPathValueFlipSign(ctxt); 13303 else if (op->value == 3) { 13304 CAST_TO_NUMBER; 13305 CHECK_TYPE0(XPATH_NUMBER); 13306 } 13307 return (total); 13308 case XPATH_OP_MULT: 13309 bakd = ctxt->context->doc; 13310 bak = ctxt->context->node; 13311 pp = ctxt->context->proximityPosition; 13312 cs = ctxt->context->contextSize; 13313 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13314 CHECK_ERROR0; 13315 ctxt->context->doc = bakd; 13316 ctxt->context->node = bak; 13317 ctxt->context->proximityPosition = pp; 13318 ctxt->context->contextSize = cs; 13319 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13320 CHECK_ERROR0; 13321 if (op->value == 0) 13322 xmlXPathMultValues(ctxt); 13323 else if (op->value == 1) 13324 xmlXPathDivValues(ctxt); 13325 else if (op->value == 2) 13326 xmlXPathModValues(ctxt); 13327 return (total); 13328 case XPATH_OP_UNION: 13329 bakd = ctxt->context->doc; 13330 bak = ctxt->context->node; 13331 pp = ctxt->context->proximityPosition; 13332 cs = ctxt->context->contextSize; 13333 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13334 CHECK_ERROR0; 13335 ctxt->context->doc = bakd; 13336 ctxt->context->node = bak; 13337 ctxt->context->proximityPosition = pp; 13338 ctxt->context->contextSize = cs; 13339 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13340 CHECK_ERROR0; 13341 CHECK_TYPE0(XPATH_NODESET); 13342 arg2 = valuePop(ctxt); 13343 13344 CHECK_TYPE0(XPATH_NODESET); 13345 arg1 = valuePop(ctxt); 13346 13347 if ((arg1->nodesetval == NULL) || 13348 ((arg2->nodesetval != NULL) && 13349 (arg2->nodesetval->nodeNr != 0))) 13350 { 13351 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 13352 arg2->nodesetval); 13353 } 13354 13355 valuePush(ctxt, arg1); 13356 xmlXPathReleaseObject(ctxt->context, arg2); 13357 return (total); 13358 case XPATH_OP_ROOT: 13359 xmlXPathRoot(ctxt); 13360 return (total); 13361 case XPATH_OP_NODE: 13362 if (op->ch1 != -1) 13363 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13364 CHECK_ERROR0; 13365 if (op->ch2 != -1) 13366 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13367 CHECK_ERROR0; 13368 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 13369 ctxt->context->node)); 13370 return (total); 13371 case XPATH_OP_RESET: 13372 if (op->ch1 != -1) 13373 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13374 CHECK_ERROR0; 13375 if (op->ch2 != -1) 13376 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13377 CHECK_ERROR0; 13378 ctxt->context->node = NULL; 13379 return (total); 13380 case XPATH_OP_COLLECT:{ 13381 if (op->ch1 == -1) 13382 return (total); 13383 13384 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13385 CHECK_ERROR0; 13386 13387 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0); 13388 return (total); 13389 } 13390 case XPATH_OP_VALUE: 13391 valuePush(ctxt, 13392 xmlXPathCacheObjectCopy(ctxt->context, 13393 (xmlXPathObjectPtr) op->value4)); 13394 return (total); 13395 case XPATH_OP_VARIABLE:{ 13396 xmlXPathObjectPtr val; 13397 13398 if (op->ch1 != -1) 13399 total += 13400 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13401 if (op->value5 == NULL) { 13402 val = xmlXPathVariableLookup(ctxt->context, op->value4); 13403 if (val == NULL) { 13404 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR; 13405 return(0); 13406 } 13407 valuePush(ctxt, val); 13408 } else { 13409 const xmlChar *URI; 13410 13411 URI = xmlXPathNsLookup(ctxt->context, op->value5); 13412 if (URI == NULL) { 13413 xmlGenericError(xmlGenericErrorContext, 13414 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n", 13415 (char *) op->value4, (char *)op->value5); 13416 ctxt->error = XPATH_UNDEF_PREFIX_ERROR; 13417 return (total); 13418 } 13419 val = xmlXPathVariableLookupNS(ctxt->context, 13420 op->value4, URI); 13421 if (val == NULL) { 13422 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR; 13423 return(0); 13424 } 13425 valuePush(ctxt, val); 13426 } 13427 return (total); 13428 } 13429 case XPATH_OP_FUNCTION:{ 13430 xmlXPathFunction func; 13431 const xmlChar *oldFunc, *oldFuncURI; 13432 int i; 13433 int frame; 13434 13435 frame = xmlXPathSetFrame(ctxt); 13436 if (op->ch1 != -1) 13437 total += 13438 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13439 if (ctxt->valueNr < op->value) { 13440 xmlGenericError(xmlGenericErrorContext, 13441 "xmlXPathCompOpEval: parameter error\n"); 13442 ctxt->error = XPATH_INVALID_OPERAND; 13443 xmlXPathPopFrame(ctxt, frame); 13444 return (total); 13445 } 13446 for (i = 0; i < op->value; i++) { 13447 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) { 13448 xmlGenericError(xmlGenericErrorContext, 13449 "xmlXPathCompOpEval: parameter error\n"); 13450 ctxt->error = XPATH_INVALID_OPERAND; 13451 xmlXPathPopFrame(ctxt, frame); 13452 return (total); 13453 } 13454 } 13455 if (op->cache != NULL) 13456 XML_CAST_FPTR(func) = op->cache; 13457 else { 13458 const xmlChar *URI = NULL; 13459 13460 if (op->value5 == NULL) 13461 func = 13462 xmlXPathFunctionLookup(ctxt->context, 13463 op->value4); 13464 else { 13465 URI = xmlXPathNsLookup(ctxt->context, op->value5); 13466 if (URI == NULL) { 13467 xmlGenericError(xmlGenericErrorContext, 13468 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n", 13469 (char *)op->value4, (char *)op->value5); 13470 xmlXPathPopFrame(ctxt, frame); 13471 ctxt->error = XPATH_UNDEF_PREFIX_ERROR; 13472 return (total); 13473 } 13474 func = xmlXPathFunctionLookupNS(ctxt->context, 13475 op->value4, URI); 13476 } 13477 if (func == NULL) { 13478 xmlGenericError(xmlGenericErrorContext, 13479 "xmlXPathCompOpEval: function %s not found\n", 13480 (char *)op->value4); 13481 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR); 13482 } 13483 op->cache = XML_CAST_FPTR(func); 13484 op->cacheURI = (void *) URI; 13485 } 13486 oldFunc = ctxt->context->function; 13487 oldFuncURI = ctxt->context->functionURI; 13488 ctxt->context->function = op->value4; 13489 ctxt->context->functionURI = op->cacheURI; 13490 func(ctxt, op->value); 13491 ctxt->context->function = oldFunc; 13492 ctxt->context->functionURI = oldFuncURI; 13493 xmlXPathPopFrame(ctxt, frame); 13494 return (total); 13495 } 13496 case XPATH_OP_ARG: 13497 bakd = ctxt->context->doc; 13498 bak = ctxt->context->node; 13499 pp = ctxt->context->proximityPosition; 13500 cs = ctxt->context->contextSize; 13501 if (op->ch1 != -1) 13502 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13503 ctxt->context->contextSize = cs; 13504 ctxt->context->proximityPosition = pp; 13505 ctxt->context->node = bak; 13506 ctxt->context->doc = bakd; 13507 CHECK_ERROR0; 13508 if (op->ch2 != -1) { 13509 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13510 ctxt->context->doc = bakd; 13511 ctxt->context->node = bak; 13512 CHECK_ERROR0; 13513 } 13514 return (total); 13515 case XPATH_OP_PREDICATE: 13516 case XPATH_OP_FILTER:{ 13517 xmlXPathObjectPtr res; 13518 xmlXPathObjectPtr obj, tmp; 13519 xmlNodeSetPtr newset = NULL; 13520 xmlNodeSetPtr oldset; 13521 xmlNodePtr oldnode; 13522 xmlDocPtr oldDoc; 13523 int i; 13524 13525 /* 13526 * Optimization for ()[1] selection i.e. the first elem 13527 */ 13528 if ((op->ch1 != -1) && (op->ch2 != -1) && 13529 #ifdef XP_OPTIMIZED_FILTER_FIRST 13530 /* 13531 * FILTER TODO: Can we assume that the inner processing 13532 * will result in an ordered list if we have an 13533 * XPATH_OP_FILTER? 13534 * What about an additional field or flag on 13535 * xmlXPathObject like @sorted ? This way we wouln'd need 13536 * to assume anything, so it would be more robust and 13537 * easier to optimize. 13538 */ 13539 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */ 13540 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */ 13541 #else 13542 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 13543 #endif 13544 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */ 13545 xmlXPathObjectPtr val; 13546 13547 val = comp->steps[op->ch2].value4; 13548 if ((val != NULL) && (val->type == XPATH_NUMBER) && 13549 (val->floatval == 1.0)) { 13550 xmlNodePtr first = NULL; 13551 13552 total += 13553 xmlXPathCompOpEvalFirst(ctxt, 13554 &comp->steps[op->ch1], 13555 &first); 13556 CHECK_ERROR0; 13557 /* 13558 * The nodeset should be in document order, 13559 * Keep only the first value 13560 */ 13561 if ((ctxt->value != NULL) && 13562 (ctxt->value->type == XPATH_NODESET) && 13563 (ctxt->value->nodesetval != NULL) && 13564 (ctxt->value->nodesetval->nodeNr > 1)) 13565 ctxt->value->nodesetval->nodeNr = 1; 13566 return (total); 13567 } 13568 } 13569 /* 13570 * Optimization for ()[last()] selection i.e. the last elem 13571 */ 13572 if ((op->ch1 != -1) && (op->ch2 != -1) && 13573 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 13574 (comp->steps[op->ch2].op == XPATH_OP_SORT)) { 13575 int f = comp->steps[op->ch2].ch1; 13576 13577 if ((f != -1) && 13578 (comp->steps[f].op == XPATH_OP_FUNCTION) && 13579 (comp->steps[f].value5 == NULL) && 13580 (comp->steps[f].value == 0) && 13581 (comp->steps[f].value4 != NULL) && 13582 (xmlStrEqual 13583 (comp->steps[f].value4, BAD_CAST "last"))) { 13584 xmlNodePtr last = NULL; 13585 13586 total += 13587 xmlXPathCompOpEvalLast(ctxt, 13588 &comp->steps[op->ch1], 13589 &last); 13590 CHECK_ERROR0; 13591 /* 13592 * The nodeset should be in document order, 13593 * Keep only the last value 13594 */ 13595 if ((ctxt->value != NULL) && 13596 (ctxt->value->type == XPATH_NODESET) && 13597 (ctxt->value->nodesetval != NULL) && 13598 (ctxt->value->nodesetval->nodeTab != NULL) && 13599 (ctxt->value->nodesetval->nodeNr > 1)) { 13600 ctxt->value->nodesetval->nodeTab[0] = 13601 ctxt->value->nodesetval->nodeTab[ctxt-> 13602 value-> 13603 nodesetval-> 13604 nodeNr - 13605 1]; 13606 ctxt->value->nodesetval->nodeNr = 1; 13607 } 13608 return (total); 13609 } 13610 } 13611 /* 13612 * Process inner predicates first. 13613 * Example "index[parent::book][1]": 13614 * ... 13615 * PREDICATE <-- we are here "[1]" 13616 * PREDICATE <-- process "[parent::book]" first 13617 * SORT 13618 * COLLECT 'parent' 'name' 'node' book 13619 * NODE 13620 * ELEM Object is a number : 1 13621 */ 13622 if (op->ch1 != -1) 13623 total += 13624 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13625 CHECK_ERROR0; 13626 if (op->ch2 == -1) 13627 return (total); 13628 if (ctxt->value == NULL) 13629 return (total); 13630 13631 oldnode = ctxt->context->node; 13632 13633 #ifdef LIBXML_XPTR_ENABLED 13634 /* 13635 * Hum are we filtering the result of an XPointer expression 13636 */ 13637 if (ctxt->value->type == XPATH_LOCATIONSET) { 13638 xmlLocationSetPtr newlocset = NULL; 13639 xmlLocationSetPtr oldlocset; 13640 13641 /* 13642 * Extract the old locset, and then evaluate the result of the 13643 * expression for all the element in the locset. use it to grow 13644 * up a new locset. 13645 */ 13646 CHECK_TYPE0(XPATH_LOCATIONSET); 13647 obj = valuePop(ctxt); 13648 oldlocset = obj->user; 13649 ctxt->context->node = NULL; 13650 13651 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) { 13652 ctxt->context->contextSize = 0; 13653 ctxt->context->proximityPosition = 0; 13654 if (op->ch2 != -1) 13655 total += 13656 xmlXPathCompOpEval(ctxt, 13657 &comp->steps[op->ch2]); 13658 res = valuePop(ctxt); 13659 if (res != NULL) { 13660 xmlXPathReleaseObject(ctxt->context, res); 13661 } 13662 valuePush(ctxt, obj); 13663 CHECK_ERROR0; 13664 return (total); 13665 } 13666 newlocset = xmlXPtrLocationSetCreate(NULL); 13667 13668 for (i = 0; i < oldlocset->locNr; i++) { 13669 /* 13670 * Run the evaluation with a node list made of a 13671 * single item in the nodelocset. 13672 */ 13673 ctxt->context->node = oldlocset->locTab[i]->user; 13674 ctxt->context->contextSize = oldlocset->locNr; 13675 ctxt->context->proximityPosition = i + 1; 13676 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13677 ctxt->context->node); 13678 valuePush(ctxt, tmp); 13679 13680 if (op->ch2 != -1) 13681 total += 13682 xmlXPathCompOpEval(ctxt, 13683 &comp->steps[op->ch2]); 13684 if (ctxt->error != XPATH_EXPRESSION_OK) { 13685 xmlXPathFreeObject(obj); 13686 return(0); 13687 } 13688 13689 /* 13690 * The result of the evaluation need to be tested to 13691 * decided whether the filter succeeded or not 13692 */ 13693 res = valuePop(ctxt); 13694 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 13695 xmlXPtrLocationSetAdd(newlocset, 13696 xmlXPathObjectCopy 13697 (oldlocset->locTab[i])); 13698 } 13699 13700 /* 13701 * Cleanup 13702 */ 13703 if (res != NULL) { 13704 xmlXPathReleaseObject(ctxt->context, res); 13705 } 13706 if (ctxt->value == tmp) { 13707 res = valuePop(ctxt); 13708 xmlXPathReleaseObject(ctxt->context, res); 13709 } 13710 13711 ctxt->context->node = NULL; 13712 } 13713 13714 /* 13715 * The result is used as the new evaluation locset. 13716 */ 13717 xmlXPathReleaseObject(ctxt->context, obj); 13718 ctxt->context->node = NULL; 13719 ctxt->context->contextSize = -1; 13720 ctxt->context->proximityPosition = -1; 13721 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset)); 13722 ctxt->context->node = oldnode; 13723 return (total); 13724 } 13725 #endif /* LIBXML_XPTR_ENABLED */ 13726 13727 /* 13728 * Extract the old set, and then evaluate the result of the 13729 * expression for all the element in the set. use it to grow 13730 * up a new set. 13731 */ 13732 CHECK_TYPE0(XPATH_NODESET); 13733 obj = valuePop(ctxt); 13734 oldset = obj->nodesetval; 13735 13736 oldnode = ctxt->context->node; 13737 oldDoc = ctxt->context->doc; 13738 ctxt->context->node = NULL; 13739 13740 if ((oldset == NULL) || (oldset->nodeNr == 0)) { 13741 ctxt->context->contextSize = 0; 13742 ctxt->context->proximityPosition = 0; 13743 /* 13744 if (op->ch2 != -1) 13745 total += 13746 xmlXPathCompOpEval(ctxt, 13747 &comp->steps[op->ch2]); 13748 CHECK_ERROR0; 13749 res = valuePop(ctxt); 13750 if (res != NULL) 13751 xmlXPathFreeObject(res); 13752 */ 13753 valuePush(ctxt, obj); 13754 ctxt->context->node = oldnode; 13755 CHECK_ERROR0; 13756 } else { 13757 tmp = NULL; 13758 /* 13759 * Initialize the new set. 13760 * Also set the xpath document in case things like 13761 * key() evaluation are attempted on the predicate 13762 */ 13763 newset = xmlXPathNodeSetCreate(NULL); 13764 /* 13765 * SPEC XPath 1.0: 13766 * "For each node in the node-set to be filtered, the 13767 * PredicateExpr is evaluated with that node as the 13768 * context node, with the number of nodes in the 13769 * node-set as the context size, and with the proximity 13770 * position of the node in the node-set with respect to 13771 * the axis as the context position;" 13772 * @oldset is the node-set" to be filtered. 13773 * 13774 * SPEC XPath 1.0: 13775 * "only predicates change the context position and 13776 * context size (see [2.4 Predicates])." 13777 * Example: 13778 * node-set context pos 13779 * nA 1 13780 * nB 2 13781 * nC 3 13782 * After applying predicate [position() > 1] : 13783 * node-set context pos 13784 * nB 1 13785 * nC 2 13786 * 13787 * removed the first node in the node-set, then 13788 * the context position of the 13789 */ 13790 for (i = 0; i < oldset->nodeNr; i++) { 13791 /* 13792 * Run the evaluation with a node list made of 13793 * a single item in the nodeset. 13794 */ 13795 ctxt->context->node = oldset->nodeTab[i]; 13796 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) && 13797 (oldset->nodeTab[i]->doc != NULL)) 13798 ctxt->context->doc = oldset->nodeTab[i]->doc; 13799 if (tmp == NULL) { 13800 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13801 ctxt->context->node); 13802 } else { 13803 xmlXPathNodeSetAddUnique(tmp->nodesetval, 13804 ctxt->context->node); 13805 } 13806 valuePush(ctxt, tmp); 13807 ctxt->context->contextSize = oldset->nodeNr; 13808 ctxt->context->proximityPosition = i + 1; 13809 /* 13810 * Evaluate the predicate against the context node. 13811 * Can/should we optimize position() predicates 13812 * here (e.g. "[1]")? 13813 */ 13814 if (op->ch2 != -1) 13815 total += 13816 xmlXPathCompOpEval(ctxt, 13817 &comp->steps[op->ch2]); 13818 if (ctxt->error != XPATH_EXPRESSION_OK) { 13819 xmlXPathFreeNodeSet(newset); 13820 xmlXPathFreeObject(obj); 13821 return(0); 13822 } 13823 13824 /* 13825 * The result of the evaluation needs to be tested to 13826 * decide whether the filter succeeded or not 13827 */ 13828 /* 13829 * OPTIMIZE TODO: Can we use 13830 * xmlXPathNodeSetAdd*Unique()* instead? 13831 */ 13832 res = valuePop(ctxt); 13833 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 13834 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]); 13835 } 13836 13837 /* 13838 * Cleanup 13839 */ 13840 if (res != NULL) { 13841 xmlXPathReleaseObject(ctxt->context, res); 13842 } 13843 if (ctxt->value == tmp) { 13844 valuePop(ctxt); 13845 xmlXPathNodeSetClear(tmp->nodesetval, 1); 13846 /* 13847 * Don't free the temporary nodeset 13848 * in order to avoid massive recreation inside this 13849 * loop. 13850 */ 13851 } else 13852 tmp = NULL; 13853 ctxt->context->node = NULL; 13854 } 13855 if (tmp != NULL) 13856 xmlXPathReleaseObject(ctxt->context, tmp); 13857 /* 13858 * The result is used as the new evaluation set. 13859 */ 13860 xmlXPathReleaseObject(ctxt->context, obj); 13861 ctxt->context->node = NULL; 13862 ctxt->context->contextSize = -1; 13863 ctxt->context->proximityPosition = -1; 13864 /* may want to move this past the '}' later */ 13865 ctxt->context->doc = oldDoc; 13866 valuePush(ctxt, 13867 xmlXPathCacheWrapNodeSet(ctxt->context, newset)); 13868 } 13869 ctxt->context->node = oldnode; 13870 return (total); 13871 } 13872 case XPATH_OP_SORT: 13873 if (op->ch1 != -1) 13874 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13875 CHECK_ERROR0; 13876 if ((ctxt->value != NULL) && 13877 (ctxt->value->type == XPATH_NODESET) && 13878 (ctxt->value->nodesetval != NULL) && 13879 (ctxt->value->nodesetval->nodeNr > 1)) 13880 { 13881 xmlXPathNodeSetSort(ctxt->value->nodesetval); 13882 } 13883 return (total); 13884 #ifdef LIBXML_XPTR_ENABLED 13885 case XPATH_OP_RANGETO:{ 13886 xmlXPathObjectPtr range; 13887 xmlXPathObjectPtr res, obj; 13888 xmlXPathObjectPtr tmp; 13889 xmlLocationSetPtr newlocset = NULL; 13890 xmlLocationSetPtr oldlocset; 13891 xmlNodeSetPtr oldset; 13892 int i, j; 13893 13894 if (op->ch1 != -1) 13895 total += 13896 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13897 if (op->ch2 == -1) 13898 return (total); 13899 13900 if (ctxt->value->type == XPATH_LOCATIONSET) { 13901 /* 13902 * Extract the old locset, and then evaluate the result of the 13903 * expression for all the element in the locset. use it to grow 13904 * up a new locset. 13905 */ 13906 CHECK_TYPE0(XPATH_LOCATIONSET); 13907 obj = valuePop(ctxt); 13908 oldlocset = obj->user; 13909 13910 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) { 13911 ctxt->context->node = NULL; 13912 ctxt->context->contextSize = 0; 13913 ctxt->context->proximityPosition = 0; 13914 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]); 13915 res = valuePop(ctxt); 13916 if (res != NULL) { 13917 xmlXPathReleaseObject(ctxt->context, res); 13918 } 13919 valuePush(ctxt, obj); 13920 CHECK_ERROR0; 13921 return (total); 13922 } 13923 newlocset = xmlXPtrLocationSetCreate(NULL); 13924 13925 for (i = 0; i < oldlocset->locNr; i++) { 13926 /* 13927 * Run the evaluation with a node list made of a 13928 * single item in the nodelocset. 13929 */ 13930 ctxt->context->node = oldlocset->locTab[i]->user; 13931 ctxt->context->contextSize = oldlocset->locNr; 13932 ctxt->context->proximityPosition = i + 1; 13933 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13934 ctxt->context->node); 13935 valuePush(ctxt, tmp); 13936 13937 if (op->ch2 != -1) 13938 total += 13939 xmlXPathCompOpEval(ctxt, 13940 &comp->steps[op->ch2]); 13941 if (ctxt->error != XPATH_EXPRESSION_OK) { 13942 xmlXPathFreeObject(obj); 13943 return(0); 13944 } 13945 13946 res = valuePop(ctxt); 13947 if (res->type == XPATH_LOCATIONSET) { 13948 xmlLocationSetPtr rloc = 13949 (xmlLocationSetPtr)res->user; 13950 for (j=0; j<rloc->locNr; j++) { 13951 range = xmlXPtrNewRange( 13952 oldlocset->locTab[i]->user, 13953 oldlocset->locTab[i]->index, 13954 rloc->locTab[j]->user2, 13955 rloc->locTab[j]->index2); 13956 if (range != NULL) { 13957 xmlXPtrLocationSetAdd(newlocset, range); 13958 } 13959 } 13960 } else { 13961 range = xmlXPtrNewRangeNodeObject( 13962 (xmlNodePtr)oldlocset->locTab[i]->user, res); 13963 if (range != NULL) { 13964 xmlXPtrLocationSetAdd(newlocset,range); 13965 } 13966 } 13967 13968 /* 13969 * Cleanup 13970 */ 13971 if (res != NULL) { 13972 xmlXPathReleaseObject(ctxt->context, res); 13973 } 13974 if (ctxt->value == tmp) { 13975 res = valuePop(ctxt); 13976 xmlXPathReleaseObject(ctxt->context, res); 13977 } 13978 13979 ctxt->context->node = NULL; 13980 } 13981 } else { /* Not a location set */ 13982 CHECK_TYPE0(XPATH_NODESET); 13983 obj = valuePop(ctxt); 13984 oldset = obj->nodesetval; 13985 ctxt->context->node = NULL; 13986 13987 newlocset = xmlXPtrLocationSetCreate(NULL); 13988 13989 if (oldset != NULL) { 13990 for (i = 0; i < oldset->nodeNr; i++) { 13991 /* 13992 * Run the evaluation with a node list made of a single item 13993 * in the nodeset. 13994 */ 13995 ctxt->context->node = oldset->nodeTab[i]; 13996 /* 13997 * OPTIMIZE TODO: Avoid recreation for every iteration. 13998 */ 13999 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 14000 ctxt->context->node); 14001 valuePush(ctxt, tmp); 14002 14003 if (op->ch2 != -1) 14004 total += 14005 xmlXPathCompOpEval(ctxt, 14006 &comp->steps[op->ch2]); 14007 if (ctxt->error != XPATH_EXPRESSION_OK) { 14008 xmlXPathFreeObject(obj); 14009 return(0); 14010 } 14011 14012 res = valuePop(ctxt); 14013 range = 14014 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i], 14015 res); 14016 if (range != NULL) { 14017 xmlXPtrLocationSetAdd(newlocset, range); 14018 } 14019 14020 /* 14021 * Cleanup 14022 */ 14023 if (res != NULL) { 14024 xmlXPathReleaseObject(ctxt->context, res); 14025 } 14026 if (ctxt->value == tmp) { 14027 res = valuePop(ctxt); 14028 xmlXPathReleaseObject(ctxt->context, res); 14029 } 14030 14031 ctxt->context->node = NULL; 14032 } 14033 } 14034 } 14035 14036 /* 14037 * The result is used as the new evaluation set. 14038 */ 14039 xmlXPathReleaseObject(ctxt->context, obj); 14040 ctxt->context->node = NULL; 14041 ctxt->context->contextSize = -1; 14042 ctxt->context->proximityPosition = -1; 14043 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset)); 14044 return (total); 14045 } 14046 #endif /* LIBXML_XPTR_ENABLED */ 14047 } 14048 xmlGenericError(xmlGenericErrorContext, 14049 "XPath: unknown precompiled operation %d\n", op->op); 14050 ctxt->error = XPATH_INVALID_OPERAND; 14051 return (total); 14052 } 14053 14054 /** 14055 * xmlXPathCompOpEvalToBoolean: 14056 * @ctxt: the XPath parser context 14057 * 14058 * Evaluates if the expression evaluates to true. 14059 * 14060 * Returns 1 if true, 0 if false and -1 on API or internal errors. 14061 */ 14062 static int 14063 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt, 14064 xmlXPathStepOpPtr op, 14065 int isPredicate) 14066 { 14067 xmlXPathObjectPtr resObj = NULL; 14068 14069 start: 14070 /* comp = ctxt->comp; */ 14071 switch (op->op) { 14072 case XPATH_OP_END: 14073 return (0); 14074 case XPATH_OP_VALUE: 14075 resObj = (xmlXPathObjectPtr) op->value4; 14076 if (isPredicate) 14077 return(xmlXPathEvaluatePredicateResult(ctxt, resObj)); 14078 return(xmlXPathCastToBoolean(resObj)); 14079 case XPATH_OP_SORT: 14080 /* 14081 * We don't need sorting for boolean results. Skip this one. 14082 */ 14083 if (op->ch1 != -1) { 14084 op = &ctxt->comp->steps[op->ch1]; 14085 goto start; 14086 } 14087 return(0); 14088 case XPATH_OP_COLLECT: 14089 if (op->ch1 == -1) 14090 return(0); 14091 14092 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]); 14093 if (ctxt->error != XPATH_EXPRESSION_OK) 14094 return(-1); 14095 14096 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1); 14097 if (ctxt->error != XPATH_EXPRESSION_OK) 14098 return(-1); 14099 14100 resObj = valuePop(ctxt); 14101 if (resObj == NULL) 14102 return(-1); 14103 break; 14104 default: 14105 /* 14106 * Fallback to call xmlXPathCompOpEval(). 14107 */ 14108 xmlXPathCompOpEval(ctxt, op); 14109 if (ctxt->error != XPATH_EXPRESSION_OK) 14110 return(-1); 14111 14112 resObj = valuePop(ctxt); 14113 if (resObj == NULL) 14114 return(-1); 14115 break; 14116 } 14117 14118 if (resObj) { 14119 int res; 14120 14121 if (resObj->type == XPATH_BOOLEAN) { 14122 res = resObj->boolval; 14123 } else if (isPredicate) { 14124 /* 14125 * For predicates a result of type "number" is handled 14126 * differently: 14127 * SPEC XPath 1.0: 14128 * "If the result is a number, the result will be converted 14129 * to true if the number is equal to the context position 14130 * and will be converted to false otherwise;" 14131 */ 14132 res = xmlXPathEvaluatePredicateResult(ctxt, resObj); 14133 } else { 14134 res = xmlXPathCastToBoolean(resObj); 14135 } 14136 xmlXPathReleaseObject(ctxt->context, resObj); 14137 return(res); 14138 } 14139 14140 return(0); 14141 } 14142 14143 #ifdef XPATH_STREAMING 14144 /** 14145 * xmlXPathRunStreamEval: 14146 * @ctxt: the XPath parser context with the compiled expression 14147 * 14148 * Evaluate the Precompiled Streamable XPath expression in the given context. 14149 */ 14150 static int 14151 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp, 14152 xmlXPathObjectPtr *resultSeq, int toBool) 14153 { 14154 int max_depth, min_depth; 14155 int from_root; 14156 int ret, depth; 14157 int eval_all_nodes; 14158 xmlNodePtr cur = NULL, limit = NULL; 14159 xmlStreamCtxtPtr patstream = NULL; 14160 14161 int nb_nodes = 0; 14162 14163 if ((ctxt == NULL) || (comp == NULL)) 14164 return(-1); 14165 max_depth = xmlPatternMaxDepth(comp); 14166 if (max_depth == -1) 14167 return(-1); 14168 if (max_depth == -2) 14169 max_depth = 10000; 14170 min_depth = xmlPatternMinDepth(comp); 14171 if (min_depth == -1) 14172 return(-1); 14173 from_root = xmlPatternFromRoot(comp); 14174 if (from_root < 0) 14175 return(-1); 14176 #if 0 14177 printf("stream eval: depth %d from root %d\n", max_depth, from_root); 14178 #endif 14179 14180 if (! toBool) { 14181 if (resultSeq == NULL) 14182 return(-1); 14183 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL); 14184 if (*resultSeq == NULL) 14185 return(-1); 14186 } 14187 14188 /* 14189 * handle the special cases of "/" amd "." being matched 14190 */ 14191 if (min_depth == 0) { 14192 if (from_root) { 14193 /* Select "/" */ 14194 if (toBool) 14195 return(1); 14196 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, 14197 (xmlNodePtr) ctxt->doc); 14198 } else { 14199 /* Select "self::node()" */ 14200 if (toBool) 14201 return(1); 14202 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node); 14203 } 14204 } 14205 if (max_depth == 0) { 14206 return(0); 14207 } 14208 14209 if (from_root) { 14210 cur = (xmlNodePtr)ctxt->doc; 14211 } else if (ctxt->node != NULL) { 14212 switch (ctxt->node->type) { 14213 case XML_ELEMENT_NODE: 14214 case XML_DOCUMENT_NODE: 14215 case XML_DOCUMENT_FRAG_NODE: 14216 case XML_HTML_DOCUMENT_NODE: 14217 #ifdef LIBXML_DOCB_ENABLED 14218 case XML_DOCB_DOCUMENT_NODE: 14219 #endif 14220 cur = ctxt->node; 14221 break; 14222 case XML_ATTRIBUTE_NODE: 14223 case XML_TEXT_NODE: 14224 case XML_CDATA_SECTION_NODE: 14225 case XML_ENTITY_REF_NODE: 14226 case XML_ENTITY_NODE: 14227 case XML_PI_NODE: 14228 case XML_COMMENT_NODE: 14229 case XML_NOTATION_NODE: 14230 case XML_DTD_NODE: 14231 case XML_DOCUMENT_TYPE_NODE: 14232 case XML_ELEMENT_DECL: 14233 case XML_ATTRIBUTE_DECL: 14234 case XML_ENTITY_DECL: 14235 case XML_NAMESPACE_DECL: 14236 case XML_XINCLUDE_START: 14237 case XML_XINCLUDE_END: 14238 break; 14239 } 14240 limit = cur; 14241 } 14242 if (cur == NULL) { 14243 return(0); 14244 } 14245 14246 patstream = xmlPatternGetStreamCtxt(comp); 14247 if (patstream == NULL) { 14248 /* 14249 * QUESTION TODO: Is this an error? 14250 */ 14251 return(0); 14252 } 14253 14254 eval_all_nodes = xmlStreamWantsAnyNode(patstream); 14255 14256 if (from_root) { 14257 ret = xmlStreamPush(patstream, NULL, NULL); 14258 if (ret < 0) { 14259 } else if (ret == 1) { 14260 if (toBool) 14261 goto return_1; 14262 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur); 14263 } 14264 } 14265 depth = 0; 14266 goto scan_children; 14267 next_node: 14268 do { 14269 nb_nodes++; 14270 14271 switch (cur->type) { 14272 case XML_ELEMENT_NODE: 14273 case XML_TEXT_NODE: 14274 case XML_CDATA_SECTION_NODE: 14275 case XML_COMMENT_NODE: 14276 case XML_PI_NODE: 14277 if (cur->type == XML_ELEMENT_NODE) { 14278 ret = xmlStreamPush(patstream, cur->name, 14279 (cur->ns ? cur->ns->href : NULL)); 14280 } else if (eval_all_nodes) 14281 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type); 14282 else 14283 break; 14284 14285 if (ret < 0) { 14286 /* NOP. */ 14287 } else if (ret == 1) { 14288 if (toBool) 14289 goto return_1; 14290 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur); 14291 } 14292 if ((cur->children == NULL) || (depth >= max_depth)) { 14293 ret = xmlStreamPop(patstream); 14294 while (cur->next != NULL) { 14295 cur = cur->next; 14296 if ((cur->type != XML_ENTITY_DECL) && 14297 (cur->type != XML_DTD_NODE)) 14298 goto next_node; 14299 } 14300 } 14301 default: 14302 break; 14303 } 14304 14305 scan_children: 14306 if ((cur->children != NULL) && (depth < max_depth)) { 14307 /* 14308 * Do not descend on entities declarations 14309 */ 14310 if (cur->children->type != XML_ENTITY_DECL) { 14311 cur = cur->children; 14312 depth++; 14313 /* 14314 * Skip DTDs 14315 */ 14316 if (cur->type != XML_DTD_NODE) 14317 continue; 14318 } 14319 } 14320 14321 if (cur == limit) 14322 break; 14323 14324 while (cur->next != NULL) { 14325 cur = cur->next; 14326 if ((cur->type != XML_ENTITY_DECL) && 14327 (cur->type != XML_DTD_NODE)) 14328 goto next_node; 14329 } 14330 14331 do { 14332 cur = cur->parent; 14333 depth--; 14334 if ((cur == NULL) || (cur == limit)) 14335 goto done; 14336 if (cur->type == XML_ELEMENT_NODE) { 14337 ret = xmlStreamPop(patstream); 14338 } else if ((eval_all_nodes) && 14339 ((cur->type == XML_TEXT_NODE) || 14340 (cur->type == XML_CDATA_SECTION_NODE) || 14341 (cur->type == XML_COMMENT_NODE) || 14342 (cur->type == XML_PI_NODE))) 14343 { 14344 ret = xmlStreamPop(patstream); 14345 } 14346 if (cur->next != NULL) { 14347 cur = cur->next; 14348 break; 14349 } 14350 } while (cur != NULL); 14351 14352 } while ((cur != NULL) && (depth >= 0)); 14353 14354 done: 14355 14356 #if 0 14357 printf("stream eval: checked %d nodes selected %d\n", 14358 nb_nodes, retObj->nodesetval->nodeNr); 14359 #endif 14360 14361 if (patstream) 14362 xmlFreeStreamCtxt(patstream); 14363 return(0); 14364 14365 return_1: 14366 if (patstream) 14367 xmlFreeStreamCtxt(patstream); 14368 return(1); 14369 } 14370 #endif /* XPATH_STREAMING */ 14371 14372 /** 14373 * xmlXPathRunEval: 14374 * @ctxt: the XPath parser context with the compiled expression 14375 * @toBool: evaluate to a boolean result 14376 * 14377 * Evaluate the Precompiled XPath expression in the given context. 14378 */ 14379 static int 14380 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool) 14381 { 14382 xmlXPathCompExprPtr comp; 14383 14384 if ((ctxt == NULL) || (ctxt->comp == NULL)) 14385 return(-1); 14386 14387 if (ctxt->valueTab == NULL) { 14388 /* Allocate the value stack */ 14389 ctxt->valueTab = (xmlXPathObjectPtr *) 14390 xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); 14391 if (ctxt->valueTab == NULL) { 14392 xmlXPathPErrMemory(ctxt, "creating evaluation context\n"); 14393 xmlFree(ctxt); 14394 } 14395 ctxt->valueNr = 0; 14396 ctxt->valueMax = 10; 14397 ctxt->value = NULL; 14398 ctxt->valueFrame = 0; 14399 } 14400 #ifdef XPATH_STREAMING 14401 if (ctxt->comp->stream) { 14402 int res; 14403 14404 if (toBool) { 14405 /* 14406 * Evaluation to boolean result. 14407 */ 14408 res = xmlXPathRunStreamEval(ctxt->context, 14409 ctxt->comp->stream, NULL, 1); 14410 if (res != -1) 14411 return(res); 14412 } else { 14413 xmlXPathObjectPtr resObj = NULL; 14414 14415 /* 14416 * Evaluation to a sequence. 14417 */ 14418 res = xmlXPathRunStreamEval(ctxt->context, 14419 ctxt->comp->stream, &resObj, 0); 14420 14421 if ((res != -1) && (resObj != NULL)) { 14422 valuePush(ctxt, resObj); 14423 return(0); 14424 } 14425 if (resObj != NULL) 14426 xmlXPathReleaseObject(ctxt->context, resObj); 14427 } 14428 /* 14429 * QUESTION TODO: This falls back to normal XPath evaluation 14430 * if res == -1. Is this intended? 14431 */ 14432 } 14433 #endif 14434 comp = ctxt->comp; 14435 if (comp->last < 0) { 14436 xmlGenericError(xmlGenericErrorContext, 14437 "xmlXPathRunEval: last is less than zero\n"); 14438 return(-1); 14439 } 14440 if (toBool) 14441 return(xmlXPathCompOpEvalToBoolean(ctxt, 14442 &comp->steps[comp->last], 0)); 14443 else 14444 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]); 14445 14446 return(0); 14447 } 14448 14449 /************************************************************************ 14450 * * 14451 * Public interfaces * 14452 * * 14453 ************************************************************************/ 14454 14455 /** 14456 * xmlXPathEvalPredicate: 14457 * @ctxt: the XPath context 14458 * @res: the Predicate Expression evaluation result 14459 * 14460 * Evaluate a predicate result for the current node. 14461 * A PredicateExpr is evaluated by evaluating the Expr and converting 14462 * the result to a boolean. If the result is a number, the result will 14463 * be converted to true if the number is equal to the position of the 14464 * context node in the context node list (as returned by the position 14465 * function) and will be converted to false otherwise; if the result 14466 * is not a number, then the result will be converted as if by a call 14467 * to the boolean function. 14468 * 14469 * Returns 1 if predicate is true, 0 otherwise 14470 */ 14471 int 14472 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) { 14473 if ((ctxt == NULL) || (res == NULL)) return(0); 14474 switch (res->type) { 14475 case XPATH_BOOLEAN: 14476 return(res->boolval); 14477 case XPATH_NUMBER: 14478 return(res->floatval == ctxt->proximityPosition); 14479 case XPATH_NODESET: 14480 case XPATH_XSLT_TREE: 14481 if (res->nodesetval == NULL) 14482 return(0); 14483 return(res->nodesetval->nodeNr != 0); 14484 case XPATH_STRING: 14485 return((res->stringval != NULL) && 14486 (xmlStrlen(res->stringval) != 0)); 14487 default: 14488 STRANGE 14489 } 14490 return(0); 14491 } 14492 14493 /** 14494 * xmlXPathEvaluatePredicateResult: 14495 * @ctxt: the XPath Parser context 14496 * @res: the Predicate Expression evaluation result 14497 * 14498 * Evaluate a predicate result for the current node. 14499 * A PredicateExpr is evaluated by evaluating the Expr and converting 14500 * the result to a boolean. If the result is a number, the result will 14501 * be converted to true if the number is equal to the position of the 14502 * context node in the context node list (as returned by the position 14503 * function) and will be converted to false otherwise; if the result 14504 * is not a number, then the result will be converted as if by a call 14505 * to the boolean function. 14506 * 14507 * Returns 1 if predicate is true, 0 otherwise 14508 */ 14509 int 14510 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt, 14511 xmlXPathObjectPtr res) { 14512 if ((ctxt == NULL) || (res == NULL)) return(0); 14513 switch (res->type) { 14514 case XPATH_BOOLEAN: 14515 return(res->boolval); 14516 case XPATH_NUMBER: 14517 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200)) 14518 return((res->floatval == ctxt->context->proximityPosition) && 14519 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/ 14520 #else 14521 return(res->floatval == ctxt->context->proximityPosition); 14522 #endif 14523 case XPATH_NODESET: 14524 case XPATH_XSLT_TREE: 14525 if (res->nodesetval == NULL) 14526 return(0); 14527 return(res->nodesetval->nodeNr != 0); 14528 case XPATH_STRING: 14529 return((res->stringval != NULL) && (res->stringval[0] != 0)); 14530 #ifdef LIBXML_XPTR_ENABLED 14531 case XPATH_LOCATIONSET:{ 14532 xmlLocationSetPtr ptr = res->user; 14533 if (ptr == NULL) 14534 return(0); 14535 return (ptr->locNr != 0); 14536 } 14537 #endif 14538 default: 14539 STRANGE 14540 } 14541 return(0); 14542 } 14543 14544 #ifdef XPATH_STREAMING 14545 /** 14546 * xmlXPathTryStreamCompile: 14547 * @ctxt: an XPath context 14548 * @str: the XPath expression 14549 * 14550 * Try to compile the XPath expression as a streamable subset. 14551 * 14552 * Returns the compiled expression or NULL if failed to compile. 14553 */ 14554 static xmlXPathCompExprPtr 14555 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { 14556 /* 14557 * Optimization: use streaming patterns when the XPath expression can 14558 * be compiled to a stream lookup 14559 */ 14560 xmlPatternPtr stream; 14561 xmlXPathCompExprPtr comp; 14562 xmlDictPtr dict = NULL; 14563 const xmlChar **namespaces = NULL; 14564 xmlNsPtr ns; 14565 int i, j; 14566 14567 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) && 14568 (!xmlStrchr(str, '@'))) { 14569 const xmlChar *tmp; 14570 14571 /* 14572 * We don't try to handle expressions using the verbose axis 14573 * specifiers ("::"), just the simplied form at this point. 14574 * Additionally, if there is no list of namespaces available and 14575 * there's a ":" in the expression, indicating a prefixed QName, 14576 * then we won't try to compile either. xmlPatterncompile() needs 14577 * to have a list of namespaces at compilation time in order to 14578 * compile prefixed name tests. 14579 */ 14580 tmp = xmlStrchr(str, ':'); 14581 if ((tmp != NULL) && 14582 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':'))) 14583 return(NULL); 14584 14585 if (ctxt != NULL) { 14586 dict = ctxt->dict; 14587 if (ctxt->nsNr > 0) { 14588 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*)); 14589 if (namespaces == NULL) { 14590 xmlXPathErrMemory(ctxt, "allocating namespaces array\n"); 14591 return(NULL); 14592 } 14593 for (i = 0, j = 0; (j < ctxt->nsNr); j++) { 14594 ns = ctxt->namespaces[j]; 14595 namespaces[i++] = ns->href; 14596 namespaces[i++] = ns->prefix; 14597 } 14598 namespaces[i++] = NULL; 14599 namespaces[i] = NULL; 14600 } 14601 } 14602 14603 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, 14604 &namespaces[0]); 14605 if (namespaces != NULL) { 14606 xmlFree((xmlChar **)namespaces); 14607 } 14608 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) { 14609 comp = xmlXPathNewCompExpr(); 14610 if (comp == NULL) { 14611 xmlXPathErrMemory(ctxt, "allocating streamable expression\n"); 14612 return(NULL); 14613 } 14614 comp->stream = stream; 14615 comp->dict = dict; 14616 if (comp->dict) 14617 xmlDictReference(comp->dict); 14618 return(comp); 14619 } 14620 xmlFreePattern(stream); 14621 } 14622 return(NULL); 14623 } 14624 #endif /* XPATH_STREAMING */ 14625 14626 static int 14627 xmlXPathCanRewriteDosExpression(xmlChar *expr) 14628 { 14629 if (expr == NULL) 14630 return(0); 14631 do { 14632 if ((*expr == '/') && (*(++expr) == '/')) 14633 return(1); 14634 } while (*expr++); 14635 return(0); 14636 } 14637 static void 14638 xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op) 14639 { 14640 /* 14641 * Try to rewrite "descendant-or-self::node()/foo" to an optimized 14642 * internal representation. 14643 */ 14644 if (op->ch1 != -1) { 14645 if ((op->op == XPATH_OP_COLLECT /* 11 */) && 14646 ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) && 14647 ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) && 14648 ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */)) 14649 { 14650 /* 14651 * This is a "child::foo" 14652 */ 14653 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1]; 14654 14655 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) && 14656 (prevop->ch1 != -1) && 14657 ((xmlXPathAxisVal) prevop->value == 14658 AXIS_DESCENDANT_OR_SELF) && 14659 (prevop->ch2 == -1) && 14660 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) && 14661 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) && 14662 (comp->steps[prevop->ch1].op == XPATH_OP_ROOT)) 14663 { 14664 /* 14665 * This is a "/descendant-or-self::node()" without predicates. 14666 * Eliminate it. 14667 */ 14668 op->ch1 = prevop->ch1; 14669 op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM; 14670 } 14671 } 14672 if (op->ch1 != -1) 14673 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]); 14674 } 14675 if (op->ch2 != -1) 14676 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]); 14677 } 14678 14679 /** 14680 * xmlXPathCtxtCompile: 14681 * @ctxt: an XPath context 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 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { 14691 xmlXPathParserContextPtr pctxt; 14692 xmlXPathCompExprPtr comp; 14693 14694 #ifdef XPATH_STREAMING 14695 comp = xmlXPathTryStreamCompile(ctxt, str); 14696 if (comp != NULL) 14697 return(comp); 14698 #endif 14699 14700 xmlXPathInit(); 14701 14702 pctxt = xmlXPathNewParserContext(str, ctxt); 14703 if (pctxt == NULL) 14704 return NULL; 14705 xmlXPathCompileExpr(pctxt, 1); 14706 14707 if( pctxt->error != XPATH_EXPRESSION_OK ) 14708 { 14709 xmlXPathFreeParserContext(pctxt); 14710 return(NULL); 14711 } 14712 14713 if (*pctxt->cur != 0) { 14714 /* 14715 * aleksey: in some cases this line prints *second* error message 14716 * (see bug #78858) and probably this should be fixed. 14717 * However, we are not sure that all error messages are printed 14718 * out in other places. It's not critical so we leave it as-is for now 14719 */ 14720 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR); 14721 comp = NULL; 14722 } else { 14723 comp = pctxt->comp; 14724 pctxt->comp = NULL; 14725 } 14726 xmlXPathFreeParserContext(pctxt); 14727 14728 if (comp != NULL) { 14729 comp->expr = xmlStrdup(str); 14730 #ifdef DEBUG_EVAL_COUNTS 14731 comp->string = xmlStrdup(str); 14732 comp->nb = 0; 14733 #endif 14734 if ((comp->expr != NULL) && 14735 (comp->nbStep > 2) && 14736 (comp->last >= 0) && 14737 (xmlXPathCanRewriteDosExpression(comp->expr) == 1)) 14738 { 14739 xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]); 14740 } 14741 } 14742 return(comp); 14743 } 14744 14745 /** 14746 * xmlXPathCompile: 14747 * @str: the XPath expression 14748 * 14749 * Compile an XPath expression 14750 * 14751 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL. 14752 * the caller has to free the object. 14753 */ 14754 xmlXPathCompExprPtr 14755 xmlXPathCompile(const xmlChar *str) { 14756 return(xmlXPathCtxtCompile(NULL, str)); 14757 } 14758 14759 /** 14760 * xmlXPathCompiledEvalInternal: 14761 * @comp: the compiled XPath expression 14762 * @ctxt: the XPath context 14763 * @resObj: the resulting XPath object or NULL 14764 * @toBool: 1 if only a boolean result is requested 14765 * 14766 * Evaluate the Precompiled XPath expression in the given context. 14767 * The caller has to free @resObj. 14768 * 14769 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14770 * the caller has to free the object. 14771 */ 14772 static int 14773 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp, 14774 xmlXPathContextPtr ctxt, 14775 xmlXPathObjectPtr *resObj, 14776 int toBool) 14777 { 14778 xmlXPathParserContextPtr pctxt; 14779 #ifndef LIBXML_THREAD_ENABLED 14780 static int reentance = 0; 14781 #endif 14782 int res; 14783 14784 CHECK_CTXT_NEG(ctxt) 14785 14786 if (comp == NULL) 14787 return(-1); 14788 xmlXPathInit(); 14789 14790 #ifndef LIBXML_THREAD_ENABLED 14791 reentance++; 14792 if (reentance > 1) 14793 xmlXPathDisableOptimizer = 1; 14794 #endif 14795 14796 #ifdef DEBUG_EVAL_COUNTS 14797 comp->nb++; 14798 if ((comp->string != NULL) && (comp->nb > 100)) { 14799 fprintf(stderr, "100 x %s\n", comp->string); 14800 comp->nb = 0; 14801 } 14802 #endif 14803 pctxt = xmlXPathCompParserContext(comp, ctxt); 14804 res = xmlXPathRunEval(pctxt, toBool); 14805 14806 if (resObj) { 14807 if (pctxt->value == NULL) { 14808 xmlGenericError(xmlGenericErrorContext, 14809 "xmlXPathCompiledEval: evaluation failed\n"); 14810 *resObj = NULL; 14811 } else { 14812 *resObj = valuePop(pctxt); 14813 } 14814 } 14815 14816 /* 14817 * Pop all remaining objects from the stack. 14818 */ 14819 if (pctxt->valueNr > 0) { 14820 xmlXPathObjectPtr tmp; 14821 int stack = 0; 14822 14823 do { 14824 tmp = valuePop(pctxt); 14825 if (tmp != NULL) { 14826 stack++; 14827 xmlXPathReleaseObject(ctxt, tmp); 14828 } 14829 } while (tmp != NULL); 14830 if ((stack != 0) && 14831 ((toBool) || ((resObj) && (*resObj)))) 14832 { 14833 xmlGenericError(xmlGenericErrorContext, 14834 "xmlXPathCompiledEval: %d objects left on the stack.\n", 14835 stack); 14836 } 14837 } 14838 14839 if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) { 14840 xmlXPathFreeObject(*resObj); 14841 *resObj = NULL; 14842 } 14843 pctxt->comp = NULL; 14844 xmlXPathFreeParserContext(pctxt); 14845 #ifndef LIBXML_THREAD_ENABLED 14846 reentance--; 14847 #endif 14848 14849 return(res); 14850 } 14851 14852 /** 14853 * xmlXPathCompiledEval: 14854 * @comp: the compiled XPath expression 14855 * @ctx: the XPath context 14856 * 14857 * Evaluate the Precompiled XPath expression in the given context. 14858 * 14859 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14860 * the caller has to free the object. 14861 */ 14862 xmlXPathObjectPtr 14863 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) 14864 { 14865 xmlXPathObjectPtr res = NULL; 14866 14867 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0); 14868 return(res); 14869 } 14870 14871 /** 14872 * xmlXPathCompiledEvalToBoolean: 14873 * @comp: the compiled XPath expression 14874 * @ctxt: the XPath context 14875 * 14876 * Applies the XPath boolean() function on the result of the given 14877 * compiled expression. 14878 * 14879 * Returns 1 if the expression evaluated to true, 0 if to false and 14880 * -1 in API and internal errors. 14881 */ 14882 int 14883 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp, 14884 xmlXPathContextPtr ctxt) 14885 { 14886 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1)); 14887 } 14888 14889 /** 14890 * xmlXPathEvalExpr: 14891 * @ctxt: the XPath Parser context 14892 * 14893 * Parse and evaluate an XPath expression in the given context, 14894 * then push the result on the context stack 14895 */ 14896 void 14897 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) { 14898 #ifdef XPATH_STREAMING 14899 xmlXPathCompExprPtr comp; 14900 #endif 14901 14902 if (ctxt == NULL) return; 14903 14904 #ifdef XPATH_STREAMING 14905 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base); 14906 if (comp != NULL) { 14907 if (ctxt->comp != NULL) 14908 xmlXPathFreeCompExpr(ctxt->comp); 14909 ctxt->comp = comp; 14910 if (ctxt->cur != NULL) 14911 while (*ctxt->cur != 0) ctxt->cur++; 14912 } else 14913 #endif 14914 { 14915 xmlXPathCompileExpr(ctxt, 1); 14916 /* 14917 * In this scenario the expression string will sit in ctxt->base. 14918 */ 14919 if ((ctxt->error == XPATH_EXPRESSION_OK) && 14920 (ctxt->comp != NULL) && 14921 (ctxt->base != NULL) && 14922 (ctxt->comp->nbStep > 2) && 14923 (ctxt->comp->last >= 0) && 14924 (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1)) 14925 { 14926 xmlXPathRewriteDOSExpression(ctxt->comp, 14927 &ctxt->comp->steps[ctxt->comp->last]); 14928 } 14929 } 14930 CHECK_ERROR; 14931 xmlXPathRunEval(ctxt, 0); 14932 } 14933 14934 /** 14935 * xmlXPathEval: 14936 * @str: the XPath expression 14937 * @ctx: the XPath context 14938 * 14939 * Evaluate the XPath Location Path in the given context. 14940 * 14941 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14942 * the caller has to free the object. 14943 */ 14944 xmlXPathObjectPtr 14945 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) { 14946 xmlXPathParserContextPtr ctxt; 14947 xmlXPathObjectPtr res, tmp, init = NULL; 14948 int stack = 0; 14949 14950 CHECK_CTXT(ctx) 14951 14952 xmlXPathInit(); 14953 14954 ctxt = xmlXPathNewParserContext(str, ctx); 14955 if (ctxt == NULL) 14956 return NULL; 14957 xmlXPathEvalExpr(ctxt); 14958 14959 if (ctxt->value == NULL) { 14960 xmlGenericError(xmlGenericErrorContext, 14961 "xmlXPathEval: evaluation failed\n"); 14962 res = NULL; 14963 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL) 14964 #ifdef XPATH_STREAMING 14965 && (ctxt->comp->stream == NULL) 14966 #endif 14967 ) { 14968 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR); 14969 res = NULL; 14970 } else { 14971 res = valuePop(ctxt); 14972 } 14973 14974 do { 14975 tmp = valuePop(ctxt); 14976 if (tmp != NULL) { 14977 if (tmp != init) 14978 stack++; 14979 xmlXPathReleaseObject(ctx, tmp); 14980 } 14981 } while (tmp != NULL); 14982 if ((stack != 0) && (res != NULL)) { 14983 xmlGenericError(xmlGenericErrorContext, 14984 "xmlXPathEval: %d object left on the stack\n", 14985 stack); 14986 } 14987 if (ctxt->error != XPATH_EXPRESSION_OK) { 14988 xmlXPathFreeObject(res); 14989 res = NULL; 14990 } 14991 14992 xmlXPathFreeParserContext(ctxt); 14993 return(res); 14994 } 14995 14996 /** 14997 * xmlXPathEvalExpression: 14998 * @str: the XPath expression 14999 * @ctxt: the XPath context 15000 * 15001 * Evaluate the XPath expression in the given context. 15002 * 15003 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 15004 * the caller has to free the object. 15005 */ 15006 xmlXPathObjectPtr 15007 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) { 15008 xmlXPathParserContextPtr pctxt; 15009 xmlXPathObjectPtr res, tmp; 15010 int stack = 0; 15011 15012 CHECK_CTXT(ctxt) 15013 15014 xmlXPathInit(); 15015 15016 pctxt = xmlXPathNewParserContext(str, ctxt); 15017 if (pctxt == NULL) 15018 return NULL; 15019 xmlXPathEvalExpr(pctxt); 15020 15021 if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) { 15022 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR); 15023 res = NULL; 15024 } else { 15025 res = valuePop(pctxt); 15026 } 15027 do { 15028 tmp = valuePop(pctxt); 15029 if (tmp != NULL) { 15030 xmlXPathReleaseObject(ctxt, tmp); 15031 stack++; 15032 } 15033 } while (tmp != NULL); 15034 if ((stack != 0) && (res != NULL)) { 15035 xmlGenericError(xmlGenericErrorContext, 15036 "xmlXPathEvalExpression: %d object left on the stack\n", 15037 stack); 15038 } 15039 xmlXPathFreeParserContext(pctxt); 15040 return(res); 15041 } 15042 15043 /************************************************************************ 15044 * * 15045 * Extra functions not pertaining to the XPath spec * 15046 * * 15047 ************************************************************************/ 15048 /** 15049 * xmlXPathEscapeUriFunction: 15050 * @ctxt: the XPath Parser context 15051 * @nargs: the number of arguments 15052 * 15053 * Implement the escape-uri() XPath function 15054 * string escape-uri(string $str, bool $escape-reserved) 15055 * 15056 * This function applies the URI escaping rules defined in section 2 of [RFC 15057 * 2396] to the string supplied as $uri-part, which typically represents all 15058 * or part of a URI. The effect of the function is to replace any special 15059 * character in the string by an escape sequence of the form %xx%yy..., 15060 * where xxyy... is the hexadecimal representation of the octets used to 15061 * represent the character in UTF-8. 15062 * 15063 * The set of characters that are escaped depends on the setting of the 15064 * boolean argument $escape-reserved. 15065 * 15066 * If $escape-reserved is true, all characters are escaped other than lower 15067 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters 15068 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!" 15069 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only 15070 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and 15071 * A-F). 15072 * 15073 * If $escape-reserved is false, the behavior differs in that characters 15074 * referred to in [RFC 2396] as reserved characters are not escaped. These 15075 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",". 15076 * 15077 * [RFC 2396] does not define whether escaped URIs should use lower case or 15078 * upper case for hexadecimal digits. To ensure that escaped URIs can be 15079 * compared using string comparison functions, this function must always use 15080 * the upper-case letters A-F. 15081 * 15082 * Generally, $escape-reserved should be set to true when escaping a string 15083 * that is to form a single part of a URI, and to false when escaping an 15084 * entire URI or URI reference. 15085 * 15086 * In the case of non-ascii characters, the string is encoded according to 15087 * utf-8 and then converted according to RFC 2396. 15088 * 15089 * Examples 15090 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true()) 15091 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean" 15092 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false()) 15093 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean" 15094 * 15095 */ 15096 static void 15097 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) { 15098 xmlXPathObjectPtr str; 15099 int escape_reserved; 15100 xmlBufferPtr target; 15101 xmlChar *cptr; 15102 xmlChar escape[4]; 15103 15104 CHECK_ARITY(2); 15105 15106 escape_reserved = xmlXPathPopBoolean(ctxt); 15107 15108 CAST_TO_STRING; 15109 str = valuePop(ctxt); 15110 15111 target = xmlBufferCreate(); 15112 15113 escape[0] = '%'; 15114 escape[3] = 0; 15115 15116 if (target) { 15117 for (cptr = str->stringval; *cptr; cptr++) { 15118 if ((*cptr >= 'A' && *cptr <= 'Z') || 15119 (*cptr >= 'a' && *cptr <= 'z') || 15120 (*cptr >= '0' && *cptr <= '9') || 15121 *cptr == '-' || *cptr == '_' || *cptr == '.' || 15122 *cptr == '!' || *cptr == '~' || *cptr == '*' || 15123 *cptr == '\''|| *cptr == '(' || *cptr == ')' || 15124 (*cptr == '%' && 15125 ((cptr[1] >= 'A' && cptr[1] <= 'F') || 15126 (cptr[1] >= 'a' && cptr[1] <= 'f') || 15127 (cptr[1] >= '0' && cptr[1] <= '9')) && 15128 ((cptr[2] >= 'A' && cptr[2] <= 'F') || 15129 (cptr[2] >= 'a' && cptr[2] <= 'f') || 15130 (cptr[2] >= '0' && cptr[2] <= '9'))) || 15131 (!escape_reserved && 15132 (*cptr == ';' || *cptr == '/' || *cptr == '?' || 15133 *cptr == ':' || *cptr == '@' || *cptr == '&' || 15134 *cptr == '=' || *cptr == '+' || *cptr == '$' || 15135 *cptr == ','))) { 15136 xmlBufferAdd(target, cptr, 1); 15137 } else { 15138 if ((*cptr >> 4) < 10) 15139 escape[1] = '0' + (*cptr >> 4); 15140 else 15141 escape[1] = 'A' - 10 + (*cptr >> 4); 15142 if ((*cptr & 0xF) < 10) 15143 escape[2] = '0' + (*cptr & 0xF); 15144 else 15145 escape[2] = 'A' - 10 + (*cptr & 0xF); 15146 15147 xmlBufferAdd(target, &escape[0], 3); 15148 } 15149 } 15150 } 15151 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 15152 xmlBufferContent(target))); 15153 xmlBufferFree(target); 15154 xmlXPathReleaseObject(ctxt->context, str); 15155 } 15156 15157 /** 15158 * xmlXPathRegisterAllFunctions: 15159 * @ctxt: the XPath context 15160 * 15161 * Registers all default XPath functions in this context 15162 */ 15163 void 15164 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt) 15165 { 15166 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean", 15167 xmlXPathBooleanFunction); 15168 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling", 15169 xmlXPathCeilingFunction); 15170 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count", 15171 xmlXPathCountFunction); 15172 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat", 15173 xmlXPathConcatFunction); 15174 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains", 15175 xmlXPathContainsFunction); 15176 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id", 15177 xmlXPathIdFunction); 15178 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false", 15179 xmlXPathFalseFunction); 15180 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor", 15181 xmlXPathFloorFunction); 15182 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last", 15183 xmlXPathLastFunction); 15184 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang", 15185 xmlXPathLangFunction); 15186 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name", 15187 xmlXPathLocalNameFunction); 15188 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not", 15189 xmlXPathNotFunction); 15190 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name", 15191 xmlXPathNameFunction); 15192 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri", 15193 xmlXPathNamespaceURIFunction); 15194 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space", 15195 xmlXPathNormalizeFunction); 15196 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number", 15197 xmlXPathNumberFunction); 15198 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position", 15199 xmlXPathPositionFunction); 15200 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round", 15201 xmlXPathRoundFunction); 15202 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string", 15203 xmlXPathStringFunction); 15204 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length", 15205 xmlXPathStringLengthFunction); 15206 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with", 15207 xmlXPathStartsWithFunction); 15208 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring", 15209 xmlXPathSubstringFunction); 15210 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before", 15211 xmlXPathSubstringBeforeFunction); 15212 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after", 15213 xmlXPathSubstringAfterFunction); 15214 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum", 15215 xmlXPathSumFunction); 15216 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true", 15217 xmlXPathTrueFunction); 15218 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate", 15219 xmlXPathTranslateFunction); 15220 15221 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri", 15222 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions", 15223 xmlXPathEscapeUriFunction); 15224 } 15225 15226 #endif /* LIBXML_XPATH_ENABLED */ 15227 #define bottom_xpath 15228 #include "elfgcchack.h" 15229