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 "?? Unknown error ??\n" /* Must be last in the list! */ 256 }; 257 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \ 258 sizeof(xmlXPathErrorMessages[0])) - 1) 259 /** 260 * xmlXPathErrMemory: 261 * @ctxt: an XPath context 262 * @extra: extra informations 263 * 264 * Handle a redefinition of attribute error 265 */ 266 static void 267 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra) 268 { 269 if (ctxt != NULL) { 270 if (extra) { 271 xmlChar buf[200]; 272 273 xmlStrPrintf(buf, 200, 274 BAD_CAST "Memory allocation failed : %s\n", 275 extra); 276 ctxt->lastError.message = (char *) xmlStrdup(buf); 277 } else { 278 ctxt->lastError.message = (char *) 279 xmlStrdup(BAD_CAST "Memory allocation failed\n"); 280 } 281 ctxt->lastError.domain = XML_FROM_XPATH; 282 ctxt->lastError.code = XML_ERR_NO_MEMORY; 283 if (ctxt->error != NULL) 284 ctxt->error(ctxt->userData, &ctxt->lastError); 285 } else { 286 if (extra) 287 __xmlRaiseError(NULL, NULL, NULL, 288 NULL, NULL, XML_FROM_XPATH, 289 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, 290 extra, NULL, NULL, 0, 0, 291 "Memory allocation failed : %s\n", extra); 292 else 293 __xmlRaiseError(NULL, NULL, NULL, 294 NULL, NULL, XML_FROM_XPATH, 295 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, 296 NULL, NULL, NULL, 0, 0, 297 "Memory allocation failed\n"); 298 } 299 } 300 301 /** 302 * xmlXPathPErrMemory: 303 * @ctxt: an XPath parser context 304 * @extra: extra informations 305 * 306 * Handle a redefinition of attribute error 307 */ 308 static void 309 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra) 310 { 311 if (ctxt == NULL) 312 xmlXPathErrMemory(NULL, extra); 313 else { 314 ctxt->error = XPATH_MEMORY_ERROR; 315 xmlXPathErrMemory(ctxt->context, extra); 316 } 317 } 318 319 /** 320 * xmlXPathErr: 321 * @ctxt: a XPath parser context 322 * @error: the error code 323 * 324 * Handle an XPath error 325 */ 326 void 327 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error) 328 { 329 if ((error < 0) || (error > MAXERRNO)) 330 error = MAXERRNO; 331 if (ctxt == NULL) { 332 __xmlRaiseError(NULL, NULL, NULL, 333 NULL, NULL, XML_FROM_XPATH, 334 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, 335 XML_ERR_ERROR, NULL, 0, 336 NULL, NULL, NULL, 0, 0, 337 "%s", xmlXPathErrorMessages[error]); 338 return; 339 } 340 ctxt->error = error; 341 if (ctxt->context == NULL) { 342 __xmlRaiseError(NULL, NULL, NULL, 343 NULL, NULL, XML_FROM_XPATH, 344 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, 345 XML_ERR_ERROR, NULL, 0, 346 (const char *) ctxt->base, NULL, NULL, 347 ctxt->cur - ctxt->base, 0, 348 "%s", xmlXPathErrorMessages[error]); 349 return; 350 } 351 352 /* cleanup current last error */ 353 xmlResetError(&ctxt->context->lastError); 354 355 ctxt->context->lastError.domain = XML_FROM_XPATH; 356 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK - 357 XPATH_EXPRESSION_OK; 358 ctxt->context->lastError.level = XML_ERR_ERROR; 359 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base); 360 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base; 361 ctxt->context->lastError.node = ctxt->context->debugNode; 362 if (ctxt->context->error != NULL) { 363 ctxt->context->error(ctxt->context->userData, 364 &ctxt->context->lastError); 365 } else { 366 __xmlRaiseError(NULL, NULL, NULL, 367 NULL, ctxt->context->debugNode, XML_FROM_XPATH, 368 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, 369 XML_ERR_ERROR, NULL, 0, 370 (const char *) ctxt->base, NULL, NULL, 371 ctxt->cur - ctxt->base, 0, 372 "%s", xmlXPathErrorMessages[error]); 373 } 374 375 } 376 377 /** 378 * xmlXPatherror: 379 * @ctxt: the XPath Parser context 380 * @file: the file name 381 * @line: the line number 382 * @no: the error number 383 * 384 * Formats an error message. 385 */ 386 void 387 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED, 388 int line ATTRIBUTE_UNUSED, int no) { 389 xmlXPathErr(ctxt, no); 390 } 391 392 /************************************************************************ 393 * * 394 * Utilities * 395 * * 396 ************************************************************************/ 397 398 /** 399 * xsltPointerList: 400 * 401 * Pointer-list for various purposes. 402 */ 403 typedef struct _xmlPointerList xmlPointerList; 404 typedef xmlPointerList *xmlPointerListPtr; 405 struct _xmlPointerList { 406 void **items; 407 int number; 408 int size; 409 }; 410 /* 411 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt 412 * and here, we should make the functions public. 413 */ 414 static int 415 xmlPointerListAddSize(xmlPointerListPtr list, 416 void *item, 417 int initialSize) 418 { 419 if (list->items == NULL) { 420 if (initialSize <= 0) 421 initialSize = 1; 422 list->items = (void **) xmlMalloc( 423 initialSize * sizeof(void *)); 424 if (list->items == NULL) { 425 xmlXPathErrMemory(NULL, 426 "xmlPointerListCreate: allocating item\n"); 427 return(-1); 428 } 429 list->number = 0; 430 list->size = initialSize; 431 } else if (list->size <= list->number) { 432 list->size *= 2; 433 list->items = (void **) xmlRealloc(list->items, 434 list->size * sizeof(void *)); 435 if (list->items == NULL) { 436 xmlXPathErrMemory(NULL, 437 "xmlPointerListCreate: re-allocating item\n"); 438 list->size = 0; 439 return(-1); 440 } 441 } 442 list->items[list->number++] = item; 443 return(0); 444 } 445 446 /** 447 * xsltPointerListCreate: 448 * 449 * Creates an xsltPointerList structure. 450 * 451 * Returns a xsltPointerList structure or NULL in case of an error. 452 */ 453 static xmlPointerListPtr 454 xmlPointerListCreate(int initialSize) 455 { 456 xmlPointerListPtr ret; 457 458 ret = xmlMalloc(sizeof(xmlPointerList)); 459 if (ret == NULL) { 460 xmlXPathErrMemory(NULL, 461 "xmlPointerListCreate: allocating item\n"); 462 return (NULL); 463 } 464 memset(ret, 0, sizeof(xmlPointerList)); 465 if (initialSize > 0) { 466 xmlPointerListAddSize(ret, NULL, initialSize); 467 ret->number = 0; 468 } 469 return (ret); 470 } 471 472 /** 473 * xsltPointerListFree: 474 * 475 * Frees the xsltPointerList structure. This does not free 476 * the content of the list. 477 */ 478 static void 479 xmlPointerListFree(xmlPointerListPtr list) 480 { 481 if (list == NULL) 482 return; 483 if (list->items != NULL) 484 xmlFree(list->items); 485 xmlFree(list); 486 } 487 488 /************************************************************************ 489 * * 490 * Parser Types * 491 * * 492 ************************************************************************/ 493 494 /* 495 * Types are private: 496 */ 497 498 typedef enum { 499 XPATH_OP_END=0, 500 XPATH_OP_AND, 501 XPATH_OP_OR, 502 XPATH_OP_EQUAL, 503 XPATH_OP_CMP, 504 XPATH_OP_PLUS, 505 XPATH_OP_MULT, 506 XPATH_OP_UNION, 507 XPATH_OP_ROOT, 508 XPATH_OP_NODE, 509 XPATH_OP_RESET, /* 10 */ 510 XPATH_OP_COLLECT, 511 XPATH_OP_VALUE, /* 12 */ 512 XPATH_OP_VARIABLE, 513 XPATH_OP_FUNCTION, 514 XPATH_OP_ARG, 515 XPATH_OP_PREDICATE, 516 XPATH_OP_FILTER, /* 17 */ 517 XPATH_OP_SORT /* 18 */ 518 #ifdef LIBXML_XPTR_ENABLED 519 ,XPATH_OP_RANGETO 520 #endif 521 } xmlXPathOp; 522 523 typedef enum { 524 AXIS_ANCESTOR = 1, 525 AXIS_ANCESTOR_OR_SELF, 526 AXIS_ATTRIBUTE, 527 AXIS_CHILD, 528 AXIS_DESCENDANT, 529 AXIS_DESCENDANT_OR_SELF, 530 AXIS_FOLLOWING, 531 AXIS_FOLLOWING_SIBLING, 532 AXIS_NAMESPACE, 533 AXIS_PARENT, 534 AXIS_PRECEDING, 535 AXIS_PRECEDING_SIBLING, 536 AXIS_SELF 537 } xmlXPathAxisVal; 538 539 typedef enum { 540 NODE_TEST_NONE = 0, 541 NODE_TEST_TYPE = 1, 542 NODE_TEST_PI = 2, 543 NODE_TEST_ALL = 3, 544 NODE_TEST_NS = 4, 545 NODE_TEST_NAME = 5 546 } xmlXPathTestVal; 547 548 typedef enum { 549 NODE_TYPE_NODE = 0, 550 NODE_TYPE_COMMENT = XML_COMMENT_NODE, 551 NODE_TYPE_TEXT = XML_TEXT_NODE, 552 NODE_TYPE_PI = XML_PI_NODE 553 } xmlXPathTypeVal; 554 555 #define XP_REWRITE_DOS_CHILD_ELEM 1 556 557 typedef struct _xmlXPathStepOp xmlXPathStepOp; 558 typedef xmlXPathStepOp *xmlXPathStepOpPtr; 559 struct _xmlXPathStepOp { 560 xmlXPathOp op; /* The identifier of the operation */ 561 int ch1; /* First child */ 562 int ch2; /* Second child */ 563 int value; 564 int value2; 565 int value3; 566 void *value4; 567 void *value5; 568 void *cache; 569 void *cacheURI; 570 int rewriteType; 571 }; 572 573 struct _xmlXPathCompExpr { 574 int nbStep; /* Number of steps in this expression */ 575 int maxStep; /* Maximum number of steps allocated */ 576 xmlXPathStepOp *steps; /* ops for computation of this expression */ 577 int last; /* index of last step in expression */ 578 xmlChar *expr; /* the expression being computed */ 579 xmlDictPtr dict; /* the dictionnary to use if any */ 580 #ifdef DEBUG_EVAL_COUNTS 581 int nb; 582 xmlChar *string; 583 #endif 584 #ifdef XPATH_STREAMING 585 xmlPatternPtr stream; 586 #endif 587 }; 588 589 /************************************************************************ 590 * * 591 * Forward declarations * 592 * * 593 ************************************************************************/ 594 static void 595 xmlXPathFreeValueTree(xmlNodeSetPtr obj); 596 static void 597 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj); 598 static int 599 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt, 600 xmlXPathStepOpPtr op, xmlNodePtr *first); 601 static int 602 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt, 603 xmlXPathStepOpPtr op, 604 int isPredicate); 605 606 /************************************************************************ 607 * * 608 * Parser Type functions * 609 * * 610 ************************************************************************/ 611 612 /** 613 * xmlXPathNewCompExpr: 614 * 615 * Create a new Xpath component 616 * 617 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error 618 */ 619 static xmlXPathCompExprPtr 620 xmlXPathNewCompExpr(void) { 621 xmlXPathCompExprPtr cur; 622 623 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr)); 624 if (cur == NULL) { 625 xmlXPathErrMemory(NULL, "allocating component\n"); 626 return(NULL); 627 } 628 memset(cur, 0, sizeof(xmlXPathCompExpr)); 629 cur->maxStep = 10; 630 cur->nbStep = 0; 631 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep * 632 sizeof(xmlXPathStepOp)); 633 if (cur->steps == NULL) { 634 xmlXPathErrMemory(NULL, "allocating steps\n"); 635 xmlFree(cur); 636 return(NULL); 637 } 638 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp)); 639 cur->last = -1; 640 #ifdef DEBUG_EVAL_COUNTS 641 cur->nb = 0; 642 #endif 643 return(cur); 644 } 645 646 /** 647 * xmlXPathFreeCompExpr: 648 * @comp: an XPATH comp 649 * 650 * Free up the memory allocated by @comp 651 */ 652 void 653 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp) 654 { 655 xmlXPathStepOpPtr op; 656 int i; 657 658 if (comp == NULL) 659 return; 660 if (comp->dict == NULL) { 661 for (i = 0; i < comp->nbStep; i++) { 662 op = &comp->steps[i]; 663 if (op->value4 != NULL) { 664 if (op->op == XPATH_OP_VALUE) 665 xmlXPathFreeObject(op->value4); 666 else 667 xmlFree(op->value4); 668 } 669 if (op->value5 != NULL) 670 xmlFree(op->value5); 671 } 672 } else { 673 for (i = 0; i < comp->nbStep; i++) { 674 op = &comp->steps[i]; 675 if (op->value4 != NULL) { 676 if (op->op == XPATH_OP_VALUE) 677 xmlXPathFreeObject(op->value4); 678 } 679 } 680 xmlDictFree(comp->dict); 681 } 682 if (comp->steps != NULL) { 683 xmlFree(comp->steps); 684 } 685 #ifdef DEBUG_EVAL_COUNTS 686 if (comp->string != NULL) { 687 xmlFree(comp->string); 688 } 689 #endif 690 #ifdef XPATH_STREAMING 691 if (comp->stream != NULL) { 692 xmlFreePatternList(comp->stream); 693 } 694 #endif 695 if (comp->expr != NULL) { 696 xmlFree(comp->expr); 697 } 698 699 xmlFree(comp); 700 } 701 702 /** 703 * xmlXPathCompExprAdd: 704 * @comp: the compiled expression 705 * @ch1: first child index 706 * @ch2: second child index 707 * @op: an op 708 * @value: the first int value 709 * @value2: the second int value 710 * @value3: the third int value 711 * @value4: the first string value 712 * @value5: the second string value 713 * 714 * Add a step to an XPath Compiled Expression 715 * 716 * Returns -1 in case of failure, the index otherwise 717 */ 718 static int 719 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2, 720 xmlXPathOp op, int value, 721 int value2, int value3, void *value4, void *value5) { 722 if (comp->nbStep >= comp->maxStep) { 723 xmlXPathStepOp *real; 724 725 comp->maxStep *= 2; 726 real = (xmlXPathStepOp *) xmlRealloc(comp->steps, 727 comp->maxStep * sizeof(xmlXPathStepOp)); 728 if (real == NULL) { 729 comp->maxStep /= 2; 730 xmlXPathErrMemory(NULL, "adding step\n"); 731 return(-1); 732 } 733 comp->steps = real; 734 } 735 comp->last = comp->nbStep; 736 comp->steps[comp->nbStep].rewriteType = 0; 737 comp->steps[comp->nbStep].ch1 = ch1; 738 comp->steps[comp->nbStep].ch2 = ch2; 739 comp->steps[comp->nbStep].op = op; 740 comp->steps[comp->nbStep].value = value; 741 comp->steps[comp->nbStep].value2 = value2; 742 comp->steps[comp->nbStep].value3 = value3; 743 if ((comp->dict != NULL) && 744 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) || 745 (op == XPATH_OP_COLLECT))) { 746 if (value4 != NULL) { 747 comp->steps[comp->nbStep].value4 = (xmlChar *) 748 (void *)xmlDictLookup(comp->dict, value4, -1); 749 xmlFree(value4); 750 } else 751 comp->steps[comp->nbStep].value4 = NULL; 752 if (value5 != NULL) { 753 comp->steps[comp->nbStep].value5 = (xmlChar *) 754 (void *)xmlDictLookup(comp->dict, value5, -1); 755 xmlFree(value5); 756 } else 757 comp->steps[comp->nbStep].value5 = NULL; 758 } else { 759 comp->steps[comp->nbStep].value4 = value4; 760 comp->steps[comp->nbStep].value5 = value5; 761 } 762 comp->steps[comp->nbStep].cache = NULL; 763 return(comp->nbStep++); 764 } 765 766 /** 767 * xmlXPathCompSwap: 768 * @comp: the compiled expression 769 * @op: operation index 770 * 771 * Swaps 2 operations in the compiled expression 772 */ 773 static void 774 xmlXPathCompSwap(xmlXPathStepOpPtr op) { 775 int tmp; 776 777 #ifndef LIBXML_THREAD_ENABLED 778 /* 779 * Since this manipulates possibly shared variables, this is 780 * disabled if one detects that the library is used in a multithreaded 781 * application 782 */ 783 if (xmlXPathDisableOptimizer) 784 return; 785 #endif 786 787 tmp = op->ch1; 788 op->ch1 = op->ch2; 789 op->ch2 = tmp; 790 } 791 792 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \ 793 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \ 794 (op), (val), (val2), (val3), (val4), (val5)) 795 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \ 796 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \ 797 (op), (val), (val2), (val3), (val4), (val5)) 798 799 #define PUSH_LEAVE_EXPR(op, val, val2) \ 800 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL) 801 802 #define PUSH_UNARY_EXPR(op, ch, val, val2) \ 803 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL) 804 805 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \ 806 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \ 807 (val), (val2), 0 ,NULL ,NULL) 808 809 /************************************************************************ 810 * * 811 * XPath object cache structures * 812 * * 813 ************************************************************************/ 814 815 /* #define XP_DEFAULT_CACHE_ON */ 816 817 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL)) 818 819 typedef struct _xmlXPathContextCache xmlXPathContextCache; 820 typedef xmlXPathContextCache *xmlXPathContextCachePtr; 821 struct _xmlXPathContextCache { 822 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */ 823 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */ 824 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */ 825 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */ 826 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */ 827 int maxNodeset; 828 int maxString; 829 int maxBoolean; 830 int maxNumber; 831 int maxMisc; 832 #ifdef XP_DEBUG_OBJ_USAGE 833 int dbgCachedAll; 834 int dbgCachedNodeset; 835 int dbgCachedString; 836 int dbgCachedBool; 837 int dbgCachedNumber; 838 int dbgCachedPoint; 839 int dbgCachedRange; 840 int dbgCachedLocset; 841 int dbgCachedUsers; 842 int dbgCachedXSLTTree; 843 int dbgCachedUndefined; 844 845 846 int dbgReusedAll; 847 int dbgReusedNodeset; 848 int dbgReusedString; 849 int dbgReusedBool; 850 int dbgReusedNumber; 851 int dbgReusedPoint; 852 int dbgReusedRange; 853 int dbgReusedLocset; 854 int dbgReusedUsers; 855 int dbgReusedXSLTTree; 856 int dbgReusedUndefined; 857 858 #endif 859 }; 860 861 /************************************************************************ 862 * * 863 * Debugging related functions * 864 * * 865 ************************************************************************/ 866 867 #define STRANGE \ 868 xmlGenericError(xmlGenericErrorContext, \ 869 "Internal error at %s:%d\n", \ 870 __FILE__, __LINE__); 871 872 #ifdef LIBXML_DEBUG_ENABLED 873 static void 874 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) { 875 int i; 876 char shift[100]; 877 878 for (i = 0;((i < depth) && (i < 25));i++) 879 shift[2 * i] = shift[2 * i + 1] = ' '; 880 shift[2 * i] = shift[2 * i + 1] = 0; 881 if (cur == NULL) { 882 fprintf(output, "%s", shift); 883 fprintf(output, "Node is NULL !\n"); 884 return; 885 886 } 887 888 if ((cur->type == XML_DOCUMENT_NODE) || 889 (cur->type == XML_HTML_DOCUMENT_NODE)) { 890 fprintf(output, "%s", shift); 891 fprintf(output, " /\n"); 892 } else if (cur->type == XML_ATTRIBUTE_NODE) 893 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth); 894 else 895 xmlDebugDumpOneNode(output, cur, depth); 896 } 897 static void 898 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) { 899 xmlNodePtr tmp; 900 int i; 901 char shift[100]; 902 903 for (i = 0;((i < depth) && (i < 25));i++) 904 shift[2 * i] = shift[2 * i + 1] = ' '; 905 shift[2 * i] = shift[2 * i + 1] = 0; 906 if (cur == NULL) { 907 fprintf(output, "%s", shift); 908 fprintf(output, "Node is NULL !\n"); 909 return; 910 911 } 912 913 while (cur != NULL) { 914 tmp = cur; 915 cur = cur->next; 916 xmlDebugDumpOneNode(output, tmp, depth); 917 } 918 } 919 920 static void 921 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) { 922 int i; 923 char shift[100]; 924 925 for (i = 0;((i < depth) && (i < 25));i++) 926 shift[2 * i] = shift[2 * i + 1] = ' '; 927 shift[2 * i] = shift[2 * i + 1] = 0; 928 929 if (cur == NULL) { 930 fprintf(output, "%s", shift); 931 fprintf(output, "NodeSet is NULL !\n"); 932 return; 933 934 } 935 936 if (cur != NULL) { 937 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr); 938 for (i = 0;i < cur->nodeNr;i++) { 939 fprintf(output, "%s", shift); 940 fprintf(output, "%d", i + 1); 941 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1); 942 } 943 } 944 } 945 946 static void 947 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) { 948 int i; 949 char shift[100]; 950 951 for (i = 0;((i < depth) && (i < 25));i++) 952 shift[2 * i] = shift[2 * i + 1] = ' '; 953 shift[2 * i] = shift[2 * i + 1] = 0; 954 955 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) { 956 fprintf(output, "%s", shift); 957 fprintf(output, "Value Tree is NULL !\n"); 958 return; 959 960 } 961 962 fprintf(output, "%s", shift); 963 fprintf(output, "%d", i + 1); 964 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1); 965 } 966 #if defined(LIBXML_XPTR_ENABLED) 967 static void 968 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) { 969 int i; 970 char shift[100]; 971 972 for (i = 0;((i < depth) && (i < 25));i++) 973 shift[2 * i] = shift[2 * i + 1] = ' '; 974 shift[2 * i] = shift[2 * i + 1] = 0; 975 976 if (cur == NULL) { 977 fprintf(output, "%s", shift); 978 fprintf(output, "LocationSet is NULL !\n"); 979 return; 980 981 } 982 983 for (i = 0;i < cur->locNr;i++) { 984 fprintf(output, "%s", shift); 985 fprintf(output, "%d : ", i + 1); 986 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1); 987 } 988 } 989 #endif /* LIBXML_XPTR_ENABLED */ 990 991 /** 992 * xmlXPathDebugDumpObject: 993 * @output: the FILE * to dump the output 994 * @cur: the object to inspect 995 * @depth: indentation level 996 * 997 * Dump the content of the object for debugging purposes 998 */ 999 void 1000 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) { 1001 int i; 1002 char shift[100]; 1003 1004 if (output == NULL) return; 1005 1006 for (i = 0;((i < depth) && (i < 25));i++) 1007 shift[2 * i] = shift[2 * i + 1] = ' '; 1008 shift[2 * i] = shift[2 * i + 1] = 0; 1009 1010 1011 fprintf(output, "%s", shift); 1012 1013 if (cur == NULL) { 1014 fprintf(output, "Object is empty (NULL)\n"); 1015 return; 1016 } 1017 switch(cur->type) { 1018 case XPATH_UNDEFINED: 1019 fprintf(output, "Object is uninitialized\n"); 1020 break; 1021 case XPATH_NODESET: 1022 fprintf(output, "Object is a Node Set :\n"); 1023 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth); 1024 break; 1025 case XPATH_XSLT_TREE: 1026 fprintf(output, "Object is an XSLT value tree :\n"); 1027 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth); 1028 break; 1029 case XPATH_BOOLEAN: 1030 fprintf(output, "Object is a Boolean : "); 1031 if (cur->boolval) fprintf(output, "true\n"); 1032 else fprintf(output, "false\n"); 1033 break; 1034 case XPATH_NUMBER: 1035 switch (xmlXPathIsInf(cur->floatval)) { 1036 case 1: 1037 fprintf(output, "Object is a number : Infinity\n"); 1038 break; 1039 case -1: 1040 fprintf(output, "Object is a number : -Infinity\n"); 1041 break; 1042 default: 1043 if (xmlXPathIsNaN(cur->floatval)) { 1044 fprintf(output, "Object is a number : NaN\n"); 1045 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) { 1046 fprintf(output, "Object is a number : 0\n"); 1047 } else { 1048 fprintf(output, "Object is a number : %0g\n", cur->floatval); 1049 } 1050 } 1051 break; 1052 case XPATH_STRING: 1053 fprintf(output, "Object is a string : "); 1054 xmlDebugDumpString(output, cur->stringval); 1055 fprintf(output, "\n"); 1056 break; 1057 case XPATH_POINT: 1058 fprintf(output, "Object is a point : index %d in node", cur->index); 1059 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1); 1060 fprintf(output, "\n"); 1061 break; 1062 case XPATH_RANGE: 1063 if ((cur->user2 == NULL) || 1064 ((cur->user2 == cur->user) && (cur->index == cur->index2))) { 1065 fprintf(output, "Object is a collapsed range :\n"); 1066 fprintf(output, "%s", shift); 1067 if (cur->index >= 0) 1068 fprintf(output, "index %d in ", cur->index); 1069 fprintf(output, "node\n"); 1070 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, 1071 depth + 1); 1072 } else { 1073 fprintf(output, "Object is a range :\n"); 1074 fprintf(output, "%s", shift); 1075 fprintf(output, "From "); 1076 if (cur->index >= 0) 1077 fprintf(output, "index %d in ", cur->index); 1078 fprintf(output, "node\n"); 1079 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, 1080 depth + 1); 1081 fprintf(output, "%s", shift); 1082 fprintf(output, "To "); 1083 if (cur->index2 >= 0) 1084 fprintf(output, "index %d in ", cur->index2); 1085 fprintf(output, "node\n"); 1086 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2, 1087 depth + 1); 1088 fprintf(output, "\n"); 1089 } 1090 break; 1091 case XPATH_LOCATIONSET: 1092 #if defined(LIBXML_XPTR_ENABLED) 1093 fprintf(output, "Object is a Location Set:\n"); 1094 xmlXPathDebugDumpLocationSet(output, 1095 (xmlLocationSetPtr) cur->user, depth); 1096 #endif 1097 break; 1098 case XPATH_USERS: 1099 fprintf(output, "Object is user defined\n"); 1100 break; 1101 } 1102 } 1103 1104 static void 1105 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp, 1106 xmlXPathStepOpPtr op, int depth) { 1107 int i; 1108 char shift[100]; 1109 1110 for (i = 0;((i < depth) && (i < 25));i++) 1111 shift[2 * i] = shift[2 * i + 1] = ' '; 1112 shift[2 * i] = shift[2 * i + 1] = 0; 1113 1114 fprintf(output, "%s", shift); 1115 if (op == NULL) { 1116 fprintf(output, "Step is NULL\n"); 1117 return; 1118 } 1119 switch (op->op) { 1120 case XPATH_OP_END: 1121 fprintf(output, "END"); break; 1122 case XPATH_OP_AND: 1123 fprintf(output, "AND"); break; 1124 case XPATH_OP_OR: 1125 fprintf(output, "OR"); break; 1126 case XPATH_OP_EQUAL: 1127 if (op->value) 1128 fprintf(output, "EQUAL ="); 1129 else 1130 fprintf(output, "EQUAL !="); 1131 break; 1132 case XPATH_OP_CMP: 1133 if (op->value) 1134 fprintf(output, "CMP <"); 1135 else 1136 fprintf(output, "CMP >"); 1137 if (!op->value2) 1138 fprintf(output, "="); 1139 break; 1140 case XPATH_OP_PLUS: 1141 if (op->value == 0) 1142 fprintf(output, "PLUS -"); 1143 else if (op->value == 1) 1144 fprintf(output, "PLUS +"); 1145 else if (op->value == 2) 1146 fprintf(output, "PLUS unary -"); 1147 else if (op->value == 3) 1148 fprintf(output, "PLUS unary - -"); 1149 break; 1150 case XPATH_OP_MULT: 1151 if (op->value == 0) 1152 fprintf(output, "MULT *"); 1153 else if (op->value == 1) 1154 fprintf(output, "MULT div"); 1155 else 1156 fprintf(output, "MULT mod"); 1157 break; 1158 case XPATH_OP_UNION: 1159 fprintf(output, "UNION"); break; 1160 case XPATH_OP_ROOT: 1161 fprintf(output, "ROOT"); break; 1162 case XPATH_OP_NODE: 1163 fprintf(output, "NODE"); break; 1164 case XPATH_OP_RESET: 1165 fprintf(output, "RESET"); break; 1166 case XPATH_OP_SORT: 1167 fprintf(output, "SORT"); break; 1168 case XPATH_OP_COLLECT: { 1169 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value; 1170 xmlXPathTestVal test = (xmlXPathTestVal)op->value2; 1171 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3; 1172 const xmlChar *prefix = op->value4; 1173 const xmlChar *name = op->value5; 1174 1175 fprintf(output, "COLLECT "); 1176 switch (axis) { 1177 case AXIS_ANCESTOR: 1178 fprintf(output, " 'ancestors' "); break; 1179 case AXIS_ANCESTOR_OR_SELF: 1180 fprintf(output, " 'ancestors-or-self' "); break; 1181 case AXIS_ATTRIBUTE: 1182 fprintf(output, " 'attributes' "); break; 1183 case AXIS_CHILD: 1184 fprintf(output, " 'child' "); break; 1185 case AXIS_DESCENDANT: 1186 fprintf(output, " 'descendant' "); break; 1187 case AXIS_DESCENDANT_OR_SELF: 1188 fprintf(output, " 'descendant-or-self' "); break; 1189 case AXIS_FOLLOWING: 1190 fprintf(output, " 'following' "); break; 1191 case AXIS_FOLLOWING_SIBLING: 1192 fprintf(output, " 'following-siblings' "); break; 1193 case AXIS_NAMESPACE: 1194 fprintf(output, " 'namespace' "); break; 1195 case AXIS_PARENT: 1196 fprintf(output, " 'parent' "); break; 1197 case AXIS_PRECEDING: 1198 fprintf(output, " 'preceding' "); break; 1199 case AXIS_PRECEDING_SIBLING: 1200 fprintf(output, " 'preceding-sibling' "); break; 1201 case AXIS_SELF: 1202 fprintf(output, " 'self' "); break; 1203 } 1204 switch (test) { 1205 case NODE_TEST_NONE: 1206 fprintf(output, "'none' "); break; 1207 case NODE_TEST_TYPE: 1208 fprintf(output, "'type' "); break; 1209 case NODE_TEST_PI: 1210 fprintf(output, "'PI' "); break; 1211 case NODE_TEST_ALL: 1212 fprintf(output, "'all' "); break; 1213 case NODE_TEST_NS: 1214 fprintf(output, "'namespace' "); break; 1215 case NODE_TEST_NAME: 1216 fprintf(output, "'name' "); break; 1217 } 1218 switch (type) { 1219 case NODE_TYPE_NODE: 1220 fprintf(output, "'node' "); break; 1221 case NODE_TYPE_COMMENT: 1222 fprintf(output, "'comment' "); break; 1223 case NODE_TYPE_TEXT: 1224 fprintf(output, "'text' "); break; 1225 case NODE_TYPE_PI: 1226 fprintf(output, "'PI' "); break; 1227 } 1228 if (prefix != NULL) 1229 fprintf(output, "%s:", prefix); 1230 if (name != NULL) 1231 fprintf(output, "%s", (const char *) name); 1232 break; 1233 1234 } 1235 case XPATH_OP_VALUE: { 1236 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4; 1237 1238 fprintf(output, "ELEM "); 1239 xmlXPathDebugDumpObject(output, object, 0); 1240 goto finish; 1241 } 1242 case XPATH_OP_VARIABLE: { 1243 const xmlChar *prefix = op->value5; 1244 const xmlChar *name = op->value4; 1245 1246 if (prefix != NULL) 1247 fprintf(output, "VARIABLE %s:%s", prefix, name); 1248 else 1249 fprintf(output, "VARIABLE %s", name); 1250 break; 1251 } 1252 case XPATH_OP_FUNCTION: { 1253 int nbargs = op->value; 1254 const xmlChar *prefix = op->value5; 1255 const xmlChar *name = op->value4; 1256 1257 if (prefix != NULL) 1258 fprintf(output, "FUNCTION %s:%s(%d args)", 1259 prefix, name, nbargs); 1260 else 1261 fprintf(output, "FUNCTION %s(%d args)", name, nbargs); 1262 break; 1263 } 1264 case XPATH_OP_ARG: fprintf(output, "ARG"); break; 1265 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break; 1266 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break; 1267 #ifdef LIBXML_XPTR_ENABLED 1268 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break; 1269 #endif 1270 default: 1271 fprintf(output, "UNKNOWN %d\n", op->op); return; 1272 } 1273 fprintf(output, "\n"); 1274 finish: 1275 if (op->ch1 >= 0) 1276 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1); 1277 if (op->ch2 >= 0) 1278 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1); 1279 } 1280 1281 /** 1282 * xmlXPathDebugDumpCompExpr: 1283 * @output: the FILE * for the output 1284 * @comp: the precompiled XPath expression 1285 * @depth: the indentation level. 1286 * 1287 * Dumps the tree of the compiled XPath expression. 1288 */ 1289 void 1290 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp, 1291 int depth) { 1292 int i; 1293 char shift[100]; 1294 1295 if ((output == NULL) || (comp == NULL)) return; 1296 1297 for (i = 0;((i < depth) && (i < 25));i++) 1298 shift[2 * i] = shift[2 * i + 1] = ' '; 1299 shift[2 * i] = shift[2 * i + 1] = 0; 1300 1301 fprintf(output, "%s", shift); 1302 1303 fprintf(output, "Compiled Expression : %d elements\n", 1304 comp->nbStep); 1305 i = comp->last; 1306 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1); 1307 } 1308 1309 #ifdef XP_DEBUG_OBJ_USAGE 1310 1311 /* 1312 * XPath object usage related debugging variables. 1313 */ 1314 static int xmlXPathDebugObjCounterUndefined = 0; 1315 static int xmlXPathDebugObjCounterNodeset = 0; 1316 static int xmlXPathDebugObjCounterBool = 0; 1317 static int xmlXPathDebugObjCounterNumber = 0; 1318 static int xmlXPathDebugObjCounterString = 0; 1319 static int xmlXPathDebugObjCounterPoint = 0; 1320 static int xmlXPathDebugObjCounterRange = 0; 1321 static int xmlXPathDebugObjCounterLocset = 0; 1322 static int xmlXPathDebugObjCounterUsers = 0; 1323 static int xmlXPathDebugObjCounterXSLTTree = 0; 1324 static int xmlXPathDebugObjCounterAll = 0; 1325 1326 static int xmlXPathDebugObjTotalUndefined = 0; 1327 static int xmlXPathDebugObjTotalNodeset = 0; 1328 static int xmlXPathDebugObjTotalBool = 0; 1329 static int xmlXPathDebugObjTotalNumber = 0; 1330 static int xmlXPathDebugObjTotalString = 0; 1331 static int xmlXPathDebugObjTotalPoint = 0; 1332 static int xmlXPathDebugObjTotalRange = 0; 1333 static int xmlXPathDebugObjTotalLocset = 0; 1334 static int xmlXPathDebugObjTotalUsers = 0; 1335 static int xmlXPathDebugObjTotalXSLTTree = 0; 1336 static int xmlXPathDebugObjTotalAll = 0; 1337 1338 static int xmlXPathDebugObjMaxUndefined = 0; 1339 static int xmlXPathDebugObjMaxNodeset = 0; 1340 static int xmlXPathDebugObjMaxBool = 0; 1341 static int xmlXPathDebugObjMaxNumber = 0; 1342 static int xmlXPathDebugObjMaxString = 0; 1343 static int xmlXPathDebugObjMaxPoint = 0; 1344 static int xmlXPathDebugObjMaxRange = 0; 1345 static int xmlXPathDebugObjMaxLocset = 0; 1346 static int xmlXPathDebugObjMaxUsers = 0; 1347 static int xmlXPathDebugObjMaxXSLTTree = 0; 1348 static int xmlXPathDebugObjMaxAll = 0; 1349 1350 /* REVISIT TODO: Make this static when committing */ 1351 static void 1352 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt) 1353 { 1354 if (ctxt != NULL) { 1355 if (ctxt->cache != NULL) { 1356 xmlXPathContextCachePtr cache = 1357 (xmlXPathContextCachePtr) ctxt->cache; 1358 1359 cache->dbgCachedAll = 0; 1360 cache->dbgCachedNodeset = 0; 1361 cache->dbgCachedString = 0; 1362 cache->dbgCachedBool = 0; 1363 cache->dbgCachedNumber = 0; 1364 cache->dbgCachedPoint = 0; 1365 cache->dbgCachedRange = 0; 1366 cache->dbgCachedLocset = 0; 1367 cache->dbgCachedUsers = 0; 1368 cache->dbgCachedXSLTTree = 0; 1369 cache->dbgCachedUndefined = 0; 1370 1371 cache->dbgReusedAll = 0; 1372 cache->dbgReusedNodeset = 0; 1373 cache->dbgReusedString = 0; 1374 cache->dbgReusedBool = 0; 1375 cache->dbgReusedNumber = 0; 1376 cache->dbgReusedPoint = 0; 1377 cache->dbgReusedRange = 0; 1378 cache->dbgReusedLocset = 0; 1379 cache->dbgReusedUsers = 0; 1380 cache->dbgReusedXSLTTree = 0; 1381 cache->dbgReusedUndefined = 0; 1382 } 1383 } 1384 1385 xmlXPathDebugObjCounterUndefined = 0; 1386 xmlXPathDebugObjCounterNodeset = 0; 1387 xmlXPathDebugObjCounterBool = 0; 1388 xmlXPathDebugObjCounterNumber = 0; 1389 xmlXPathDebugObjCounterString = 0; 1390 xmlXPathDebugObjCounterPoint = 0; 1391 xmlXPathDebugObjCounterRange = 0; 1392 xmlXPathDebugObjCounterLocset = 0; 1393 xmlXPathDebugObjCounterUsers = 0; 1394 xmlXPathDebugObjCounterXSLTTree = 0; 1395 xmlXPathDebugObjCounterAll = 0; 1396 1397 xmlXPathDebugObjTotalUndefined = 0; 1398 xmlXPathDebugObjTotalNodeset = 0; 1399 xmlXPathDebugObjTotalBool = 0; 1400 xmlXPathDebugObjTotalNumber = 0; 1401 xmlXPathDebugObjTotalString = 0; 1402 xmlXPathDebugObjTotalPoint = 0; 1403 xmlXPathDebugObjTotalRange = 0; 1404 xmlXPathDebugObjTotalLocset = 0; 1405 xmlXPathDebugObjTotalUsers = 0; 1406 xmlXPathDebugObjTotalXSLTTree = 0; 1407 xmlXPathDebugObjTotalAll = 0; 1408 1409 xmlXPathDebugObjMaxUndefined = 0; 1410 xmlXPathDebugObjMaxNodeset = 0; 1411 xmlXPathDebugObjMaxBool = 0; 1412 xmlXPathDebugObjMaxNumber = 0; 1413 xmlXPathDebugObjMaxString = 0; 1414 xmlXPathDebugObjMaxPoint = 0; 1415 xmlXPathDebugObjMaxRange = 0; 1416 xmlXPathDebugObjMaxLocset = 0; 1417 xmlXPathDebugObjMaxUsers = 0; 1418 xmlXPathDebugObjMaxXSLTTree = 0; 1419 xmlXPathDebugObjMaxAll = 0; 1420 1421 } 1422 1423 static void 1424 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt, 1425 xmlXPathObjectType objType) 1426 { 1427 int isCached = 0; 1428 1429 if (ctxt != NULL) { 1430 if (ctxt->cache != NULL) { 1431 xmlXPathContextCachePtr cache = 1432 (xmlXPathContextCachePtr) ctxt->cache; 1433 1434 isCached = 1; 1435 1436 cache->dbgReusedAll++; 1437 switch (objType) { 1438 case XPATH_UNDEFINED: 1439 cache->dbgReusedUndefined++; 1440 break; 1441 case XPATH_NODESET: 1442 cache->dbgReusedNodeset++; 1443 break; 1444 case XPATH_BOOLEAN: 1445 cache->dbgReusedBool++; 1446 break; 1447 case XPATH_NUMBER: 1448 cache->dbgReusedNumber++; 1449 break; 1450 case XPATH_STRING: 1451 cache->dbgReusedString++; 1452 break; 1453 case XPATH_POINT: 1454 cache->dbgReusedPoint++; 1455 break; 1456 case XPATH_RANGE: 1457 cache->dbgReusedRange++; 1458 break; 1459 case XPATH_LOCATIONSET: 1460 cache->dbgReusedLocset++; 1461 break; 1462 case XPATH_USERS: 1463 cache->dbgReusedUsers++; 1464 break; 1465 case XPATH_XSLT_TREE: 1466 cache->dbgReusedXSLTTree++; 1467 break; 1468 default: 1469 break; 1470 } 1471 } 1472 } 1473 1474 switch (objType) { 1475 case XPATH_UNDEFINED: 1476 if (! isCached) 1477 xmlXPathDebugObjTotalUndefined++; 1478 xmlXPathDebugObjCounterUndefined++; 1479 if (xmlXPathDebugObjCounterUndefined > 1480 xmlXPathDebugObjMaxUndefined) 1481 xmlXPathDebugObjMaxUndefined = 1482 xmlXPathDebugObjCounterUndefined; 1483 break; 1484 case XPATH_NODESET: 1485 if (! isCached) 1486 xmlXPathDebugObjTotalNodeset++; 1487 xmlXPathDebugObjCounterNodeset++; 1488 if (xmlXPathDebugObjCounterNodeset > 1489 xmlXPathDebugObjMaxNodeset) 1490 xmlXPathDebugObjMaxNodeset = 1491 xmlXPathDebugObjCounterNodeset; 1492 break; 1493 case XPATH_BOOLEAN: 1494 if (! isCached) 1495 xmlXPathDebugObjTotalBool++; 1496 xmlXPathDebugObjCounterBool++; 1497 if (xmlXPathDebugObjCounterBool > 1498 xmlXPathDebugObjMaxBool) 1499 xmlXPathDebugObjMaxBool = 1500 xmlXPathDebugObjCounterBool; 1501 break; 1502 case XPATH_NUMBER: 1503 if (! isCached) 1504 xmlXPathDebugObjTotalNumber++; 1505 xmlXPathDebugObjCounterNumber++; 1506 if (xmlXPathDebugObjCounterNumber > 1507 xmlXPathDebugObjMaxNumber) 1508 xmlXPathDebugObjMaxNumber = 1509 xmlXPathDebugObjCounterNumber; 1510 break; 1511 case XPATH_STRING: 1512 if (! isCached) 1513 xmlXPathDebugObjTotalString++; 1514 xmlXPathDebugObjCounterString++; 1515 if (xmlXPathDebugObjCounterString > 1516 xmlXPathDebugObjMaxString) 1517 xmlXPathDebugObjMaxString = 1518 xmlXPathDebugObjCounterString; 1519 break; 1520 case XPATH_POINT: 1521 if (! isCached) 1522 xmlXPathDebugObjTotalPoint++; 1523 xmlXPathDebugObjCounterPoint++; 1524 if (xmlXPathDebugObjCounterPoint > 1525 xmlXPathDebugObjMaxPoint) 1526 xmlXPathDebugObjMaxPoint = 1527 xmlXPathDebugObjCounterPoint; 1528 break; 1529 case XPATH_RANGE: 1530 if (! isCached) 1531 xmlXPathDebugObjTotalRange++; 1532 xmlXPathDebugObjCounterRange++; 1533 if (xmlXPathDebugObjCounterRange > 1534 xmlXPathDebugObjMaxRange) 1535 xmlXPathDebugObjMaxRange = 1536 xmlXPathDebugObjCounterRange; 1537 break; 1538 case XPATH_LOCATIONSET: 1539 if (! isCached) 1540 xmlXPathDebugObjTotalLocset++; 1541 xmlXPathDebugObjCounterLocset++; 1542 if (xmlXPathDebugObjCounterLocset > 1543 xmlXPathDebugObjMaxLocset) 1544 xmlXPathDebugObjMaxLocset = 1545 xmlXPathDebugObjCounterLocset; 1546 break; 1547 case XPATH_USERS: 1548 if (! isCached) 1549 xmlXPathDebugObjTotalUsers++; 1550 xmlXPathDebugObjCounterUsers++; 1551 if (xmlXPathDebugObjCounterUsers > 1552 xmlXPathDebugObjMaxUsers) 1553 xmlXPathDebugObjMaxUsers = 1554 xmlXPathDebugObjCounterUsers; 1555 break; 1556 case XPATH_XSLT_TREE: 1557 if (! isCached) 1558 xmlXPathDebugObjTotalXSLTTree++; 1559 xmlXPathDebugObjCounterXSLTTree++; 1560 if (xmlXPathDebugObjCounterXSLTTree > 1561 xmlXPathDebugObjMaxXSLTTree) 1562 xmlXPathDebugObjMaxXSLTTree = 1563 xmlXPathDebugObjCounterXSLTTree; 1564 break; 1565 default: 1566 break; 1567 } 1568 if (! isCached) 1569 xmlXPathDebugObjTotalAll++; 1570 xmlXPathDebugObjCounterAll++; 1571 if (xmlXPathDebugObjCounterAll > 1572 xmlXPathDebugObjMaxAll) 1573 xmlXPathDebugObjMaxAll = 1574 xmlXPathDebugObjCounterAll; 1575 } 1576 1577 static void 1578 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt, 1579 xmlXPathObjectType objType) 1580 { 1581 int isCached = 0; 1582 1583 if (ctxt != NULL) { 1584 if (ctxt->cache != NULL) { 1585 xmlXPathContextCachePtr cache = 1586 (xmlXPathContextCachePtr) ctxt->cache; 1587 1588 isCached = 1; 1589 1590 cache->dbgCachedAll++; 1591 switch (objType) { 1592 case XPATH_UNDEFINED: 1593 cache->dbgCachedUndefined++; 1594 break; 1595 case XPATH_NODESET: 1596 cache->dbgCachedNodeset++; 1597 break; 1598 case XPATH_BOOLEAN: 1599 cache->dbgCachedBool++; 1600 break; 1601 case XPATH_NUMBER: 1602 cache->dbgCachedNumber++; 1603 break; 1604 case XPATH_STRING: 1605 cache->dbgCachedString++; 1606 break; 1607 case XPATH_POINT: 1608 cache->dbgCachedPoint++; 1609 break; 1610 case XPATH_RANGE: 1611 cache->dbgCachedRange++; 1612 break; 1613 case XPATH_LOCATIONSET: 1614 cache->dbgCachedLocset++; 1615 break; 1616 case XPATH_USERS: 1617 cache->dbgCachedUsers++; 1618 break; 1619 case XPATH_XSLT_TREE: 1620 cache->dbgCachedXSLTTree++; 1621 break; 1622 default: 1623 break; 1624 } 1625 1626 } 1627 } 1628 switch (objType) { 1629 case XPATH_UNDEFINED: 1630 xmlXPathDebugObjCounterUndefined--; 1631 break; 1632 case XPATH_NODESET: 1633 xmlXPathDebugObjCounterNodeset--; 1634 break; 1635 case XPATH_BOOLEAN: 1636 xmlXPathDebugObjCounterBool--; 1637 break; 1638 case XPATH_NUMBER: 1639 xmlXPathDebugObjCounterNumber--; 1640 break; 1641 case XPATH_STRING: 1642 xmlXPathDebugObjCounterString--; 1643 break; 1644 case XPATH_POINT: 1645 xmlXPathDebugObjCounterPoint--; 1646 break; 1647 case XPATH_RANGE: 1648 xmlXPathDebugObjCounterRange--; 1649 break; 1650 case XPATH_LOCATIONSET: 1651 xmlXPathDebugObjCounterLocset--; 1652 break; 1653 case XPATH_USERS: 1654 xmlXPathDebugObjCounterUsers--; 1655 break; 1656 case XPATH_XSLT_TREE: 1657 xmlXPathDebugObjCounterXSLTTree--; 1658 break; 1659 default: 1660 break; 1661 } 1662 xmlXPathDebugObjCounterAll--; 1663 } 1664 1665 /* REVISIT TODO: Make this static when committing */ 1666 static void 1667 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt) 1668 { 1669 int reqAll, reqNodeset, reqString, reqBool, reqNumber, 1670 reqXSLTTree, reqUndefined; 1671 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0, 1672 caNumber = 0, caXSLTTree = 0, caUndefined = 0; 1673 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0, 1674 reNumber = 0, reXSLTTree = 0, reUndefined = 0; 1675 int leftObjs = xmlXPathDebugObjCounterAll; 1676 1677 reqAll = xmlXPathDebugObjTotalAll; 1678 reqNodeset = xmlXPathDebugObjTotalNodeset; 1679 reqString = xmlXPathDebugObjTotalString; 1680 reqBool = xmlXPathDebugObjTotalBool; 1681 reqNumber = xmlXPathDebugObjTotalNumber; 1682 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree; 1683 reqUndefined = xmlXPathDebugObjTotalUndefined; 1684 1685 printf("# XPath object usage:\n"); 1686 1687 if (ctxt != NULL) { 1688 if (ctxt->cache != NULL) { 1689 xmlXPathContextCachePtr cache = 1690 (xmlXPathContextCachePtr) ctxt->cache; 1691 1692 reAll = cache->dbgReusedAll; 1693 reqAll += reAll; 1694 reNodeset = cache->dbgReusedNodeset; 1695 reqNodeset += reNodeset; 1696 reString = cache->dbgReusedString; 1697 reqString += reString; 1698 reBool = cache->dbgReusedBool; 1699 reqBool += reBool; 1700 reNumber = cache->dbgReusedNumber; 1701 reqNumber += reNumber; 1702 reXSLTTree = cache->dbgReusedXSLTTree; 1703 reqXSLTTree += reXSLTTree; 1704 reUndefined = cache->dbgReusedUndefined; 1705 reqUndefined += reUndefined; 1706 1707 caAll = cache->dbgCachedAll; 1708 caBool = cache->dbgCachedBool; 1709 caNodeset = cache->dbgCachedNodeset; 1710 caString = cache->dbgCachedString; 1711 caNumber = cache->dbgCachedNumber; 1712 caXSLTTree = cache->dbgCachedXSLTTree; 1713 caUndefined = cache->dbgCachedUndefined; 1714 1715 if (cache->nodesetObjs) 1716 leftObjs -= cache->nodesetObjs->number; 1717 if (cache->stringObjs) 1718 leftObjs -= cache->stringObjs->number; 1719 if (cache->booleanObjs) 1720 leftObjs -= cache->booleanObjs->number; 1721 if (cache->numberObjs) 1722 leftObjs -= cache->numberObjs->number; 1723 if (cache->miscObjs) 1724 leftObjs -= cache->miscObjs->number; 1725 } 1726 } 1727 1728 printf("# all\n"); 1729 printf("# total : %d\n", reqAll); 1730 printf("# left : %d\n", leftObjs); 1731 printf("# created: %d\n", xmlXPathDebugObjTotalAll); 1732 printf("# reused : %d\n", reAll); 1733 printf("# max : %d\n", xmlXPathDebugObjMaxAll); 1734 1735 printf("# node-sets\n"); 1736 printf("# total : %d\n", reqNodeset); 1737 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset); 1738 printf("# reused : %d\n", reNodeset); 1739 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset); 1740 1741 printf("# strings\n"); 1742 printf("# total : %d\n", reqString); 1743 printf("# created: %d\n", xmlXPathDebugObjTotalString); 1744 printf("# reused : %d\n", reString); 1745 printf("# max : %d\n", xmlXPathDebugObjMaxString); 1746 1747 printf("# booleans\n"); 1748 printf("# total : %d\n", reqBool); 1749 printf("# created: %d\n", xmlXPathDebugObjTotalBool); 1750 printf("# reused : %d\n", reBool); 1751 printf("# max : %d\n", xmlXPathDebugObjMaxBool); 1752 1753 printf("# numbers\n"); 1754 printf("# total : %d\n", reqNumber); 1755 printf("# created: %d\n", xmlXPathDebugObjTotalNumber); 1756 printf("# reused : %d\n", reNumber); 1757 printf("# max : %d\n", xmlXPathDebugObjMaxNumber); 1758 1759 printf("# XSLT result tree fragments\n"); 1760 printf("# total : %d\n", reqXSLTTree); 1761 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree); 1762 printf("# reused : %d\n", reXSLTTree); 1763 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree); 1764 1765 printf("# undefined\n"); 1766 printf("# total : %d\n", reqUndefined); 1767 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined); 1768 printf("# reused : %d\n", reUndefined); 1769 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined); 1770 1771 } 1772 1773 #endif /* XP_DEBUG_OBJ_USAGE */ 1774 1775 #endif /* LIBXML_DEBUG_ENABLED */ 1776 1777 /************************************************************************ 1778 * * 1779 * XPath object caching * 1780 * * 1781 ************************************************************************/ 1782 1783 /** 1784 * xmlXPathNewCache: 1785 * 1786 * Create a new object cache 1787 * 1788 * Returns the xmlXPathCache just allocated. 1789 */ 1790 static xmlXPathContextCachePtr 1791 xmlXPathNewCache(void) 1792 { 1793 xmlXPathContextCachePtr ret; 1794 1795 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache)); 1796 if (ret == NULL) { 1797 xmlXPathErrMemory(NULL, "creating object cache\n"); 1798 return(NULL); 1799 } 1800 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache)); 1801 ret->maxNodeset = 100; 1802 ret->maxString = 100; 1803 ret->maxBoolean = 100; 1804 ret->maxNumber = 100; 1805 ret->maxMisc = 100; 1806 return(ret); 1807 } 1808 1809 static void 1810 xmlXPathCacheFreeObjectList(xmlPointerListPtr list) 1811 { 1812 int i; 1813 xmlXPathObjectPtr obj; 1814 1815 if (list == NULL) 1816 return; 1817 1818 for (i = 0; i < list->number; i++) { 1819 obj = list->items[i]; 1820 /* 1821 * Note that it is already assured that we don't need to 1822 * look out for namespace nodes in the node-set. 1823 */ 1824 if (obj->nodesetval != NULL) { 1825 if (obj->nodesetval->nodeTab != NULL) 1826 xmlFree(obj->nodesetval->nodeTab); 1827 xmlFree(obj->nodesetval); 1828 } 1829 xmlFree(obj); 1830 #ifdef XP_DEBUG_OBJ_USAGE 1831 xmlXPathDebugObjCounterAll--; 1832 #endif 1833 } 1834 xmlPointerListFree(list); 1835 } 1836 1837 static void 1838 xmlXPathFreeCache(xmlXPathContextCachePtr cache) 1839 { 1840 if (cache == NULL) 1841 return; 1842 if (cache->nodesetObjs) 1843 xmlXPathCacheFreeObjectList(cache->nodesetObjs); 1844 if (cache->stringObjs) 1845 xmlXPathCacheFreeObjectList(cache->stringObjs); 1846 if (cache->booleanObjs) 1847 xmlXPathCacheFreeObjectList(cache->booleanObjs); 1848 if (cache->numberObjs) 1849 xmlXPathCacheFreeObjectList(cache->numberObjs); 1850 if (cache->miscObjs) 1851 xmlXPathCacheFreeObjectList(cache->miscObjs); 1852 xmlFree(cache); 1853 } 1854 1855 /** 1856 * xmlXPathContextSetCache: 1857 * 1858 * @ctxt: the XPath context 1859 * @active: enables/disables (creates/frees) the cache 1860 * @value: a value with semantics dependant on @options 1861 * @options: options (currently only the value 0 is used) 1862 * 1863 * Creates/frees an object cache on the XPath context. 1864 * If activates XPath objects (xmlXPathObject) will be cached internally 1865 * to be reused. 1866 * @options: 1867 * 0: This will set the XPath object caching: 1868 * @value: 1869 * This will set the maximum number of XPath objects 1870 * to be cached per slot 1871 * There are 5 slots for: node-set, string, number, boolean, and 1872 * misc objects. Use <0 for the default number (100). 1873 * Other values for @options have currently no effect. 1874 * 1875 * Returns 0 if the setting succeeded, and -1 on API or internal errors. 1876 */ 1877 int 1878 xmlXPathContextSetCache(xmlXPathContextPtr ctxt, 1879 int active, 1880 int value, 1881 int options) 1882 { 1883 if (ctxt == NULL) 1884 return(-1); 1885 if (active) { 1886 xmlXPathContextCachePtr cache; 1887 1888 if (ctxt->cache == NULL) { 1889 ctxt->cache = xmlXPathNewCache(); 1890 if (ctxt->cache == NULL) 1891 return(-1); 1892 } 1893 cache = (xmlXPathContextCachePtr) ctxt->cache; 1894 if (options == 0) { 1895 if (value < 0) 1896 value = 100; 1897 cache->maxNodeset = value; 1898 cache->maxString = value; 1899 cache->maxNumber = value; 1900 cache->maxBoolean = value; 1901 cache->maxMisc = value; 1902 } 1903 } else if (ctxt->cache != NULL) { 1904 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache); 1905 ctxt->cache = NULL; 1906 } 1907 return(0); 1908 } 1909 1910 /** 1911 * xmlXPathCacheWrapNodeSet: 1912 * @ctxt: the XPath context 1913 * @val: the NodePtr value 1914 * 1915 * This is the cached version of xmlXPathWrapNodeSet(). 1916 * Wrap the Nodeset @val in a new xmlXPathObjectPtr 1917 * 1918 * Returns the created or reused object. 1919 */ 1920 static xmlXPathObjectPtr 1921 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val) 1922 { 1923 if ((ctxt != NULL) && (ctxt->cache != NULL)) { 1924 xmlXPathContextCachePtr cache = 1925 (xmlXPathContextCachePtr) ctxt->cache; 1926 1927 if ((cache->miscObjs != NULL) && 1928 (cache->miscObjs->number != 0)) 1929 { 1930 xmlXPathObjectPtr ret; 1931 1932 ret = (xmlXPathObjectPtr) 1933 cache->miscObjs->items[--cache->miscObjs->number]; 1934 ret->type = XPATH_NODESET; 1935 ret->nodesetval = val; 1936 #ifdef XP_DEBUG_OBJ_USAGE 1937 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 1938 #endif 1939 return(ret); 1940 } 1941 } 1942 1943 return(xmlXPathWrapNodeSet(val)); 1944 1945 } 1946 1947 /** 1948 * xmlXPathCacheWrapString: 1949 * @ctxt: the XPath context 1950 * @val: the xmlChar * value 1951 * 1952 * This is the cached version of xmlXPathWrapString(). 1953 * Wraps the @val string into an XPath object. 1954 * 1955 * Returns the created or reused object. 1956 */ 1957 static xmlXPathObjectPtr 1958 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val) 1959 { 1960 if ((ctxt != NULL) && (ctxt->cache != NULL)) { 1961 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 1962 1963 if ((cache->stringObjs != NULL) && 1964 (cache->stringObjs->number != 0)) 1965 { 1966 1967 xmlXPathObjectPtr ret; 1968 1969 ret = (xmlXPathObjectPtr) 1970 cache->stringObjs->items[--cache->stringObjs->number]; 1971 ret->type = XPATH_STRING; 1972 ret->stringval = val; 1973 #ifdef XP_DEBUG_OBJ_USAGE 1974 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 1975 #endif 1976 return(ret); 1977 } else if ((cache->miscObjs != NULL) && 1978 (cache->miscObjs->number != 0)) 1979 { 1980 xmlXPathObjectPtr ret; 1981 /* 1982 * Fallback to misc-cache. 1983 */ 1984 ret = (xmlXPathObjectPtr) 1985 cache->miscObjs->items[--cache->miscObjs->number]; 1986 1987 ret->type = XPATH_STRING; 1988 ret->stringval = val; 1989 #ifdef XP_DEBUG_OBJ_USAGE 1990 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 1991 #endif 1992 return(ret); 1993 } 1994 } 1995 return(xmlXPathWrapString(val)); 1996 } 1997 1998 /** 1999 * xmlXPathCacheNewNodeSet: 2000 * @ctxt: the XPath context 2001 * @val: the NodePtr value 2002 * 2003 * This is the cached version of xmlXPathNewNodeSet(). 2004 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize 2005 * it with the single Node @val 2006 * 2007 * Returns the created or reused object. 2008 */ 2009 static xmlXPathObjectPtr 2010 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val) 2011 { 2012 if ((ctxt != NULL) && (ctxt->cache)) { 2013 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2014 2015 if ((cache->nodesetObjs != NULL) && 2016 (cache->nodesetObjs->number != 0)) 2017 { 2018 xmlXPathObjectPtr ret; 2019 /* 2020 * Use the nodset-cache. 2021 */ 2022 ret = (xmlXPathObjectPtr) 2023 cache->nodesetObjs->items[--cache->nodesetObjs->number]; 2024 ret->type = XPATH_NODESET; 2025 ret->boolval = 0; 2026 if (val) { 2027 if ((ret->nodesetval->nodeMax == 0) || 2028 (val->type == XML_NAMESPACE_DECL)) 2029 { 2030 xmlXPathNodeSetAddUnique(ret->nodesetval, val); 2031 } else { 2032 ret->nodesetval->nodeTab[0] = val; 2033 ret->nodesetval->nodeNr = 1; 2034 } 2035 } 2036 #ifdef XP_DEBUG_OBJ_USAGE 2037 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 2038 #endif 2039 return(ret); 2040 } else if ((cache->miscObjs != NULL) && 2041 (cache->miscObjs->number != 0)) 2042 { 2043 xmlXPathObjectPtr ret; 2044 /* 2045 * Fallback to misc-cache. 2046 */ 2047 2048 ret = (xmlXPathObjectPtr) 2049 cache->miscObjs->items[--cache->miscObjs->number]; 2050 2051 ret->type = XPATH_NODESET; 2052 ret->boolval = 0; 2053 ret->nodesetval = xmlXPathNodeSetCreate(val); 2054 #ifdef XP_DEBUG_OBJ_USAGE 2055 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 2056 #endif 2057 return(ret); 2058 } 2059 } 2060 return(xmlXPathNewNodeSet(val)); 2061 } 2062 2063 /** 2064 * xmlXPathCacheNewCString: 2065 * @ctxt: the XPath context 2066 * @val: the char * value 2067 * 2068 * This is the cached version of xmlXPathNewCString(). 2069 * Acquire an xmlXPathObjectPtr of type string and of value @val 2070 * 2071 * Returns the created or reused object. 2072 */ 2073 static xmlXPathObjectPtr 2074 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val) 2075 { 2076 if ((ctxt != NULL) && (ctxt->cache)) { 2077 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2078 2079 if ((cache->stringObjs != NULL) && 2080 (cache->stringObjs->number != 0)) 2081 { 2082 xmlXPathObjectPtr ret; 2083 2084 ret = (xmlXPathObjectPtr) 2085 cache->stringObjs->items[--cache->stringObjs->number]; 2086 2087 ret->type = XPATH_STRING; 2088 ret->stringval = xmlStrdup(BAD_CAST val); 2089 #ifdef XP_DEBUG_OBJ_USAGE 2090 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2091 #endif 2092 return(ret); 2093 } else if ((cache->miscObjs != NULL) && 2094 (cache->miscObjs->number != 0)) 2095 { 2096 xmlXPathObjectPtr ret; 2097 2098 ret = (xmlXPathObjectPtr) 2099 cache->miscObjs->items[--cache->miscObjs->number]; 2100 2101 ret->type = XPATH_STRING; 2102 ret->stringval = xmlStrdup(BAD_CAST val); 2103 #ifdef XP_DEBUG_OBJ_USAGE 2104 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2105 #endif 2106 return(ret); 2107 } 2108 } 2109 return(xmlXPathNewCString(val)); 2110 } 2111 2112 /** 2113 * xmlXPathCacheNewString: 2114 * @ctxt: the XPath context 2115 * @val: the xmlChar * value 2116 * 2117 * This is the cached version of xmlXPathNewString(). 2118 * Acquire an xmlXPathObjectPtr of type string and of value @val 2119 * 2120 * Returns the created or reused object. 2121 */ 2122 static xmlXPathObjectPtr 2123 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val) 2124 { 2125 if ((ctxt != NULL) && (ctxt->cache)) { 2126 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2127 2128 if ((cache->stringObjs != NULL) && 2129 (cache->stringObjs->number != 0)) 2130 { 2131 xmlXPathObjectPtr ret; 2132 2133 ret = (xmlXPathObjectPtr) 2134 cache->stringObjs->items[--cache->stringObjs->number]; 2135 ret->type = XPATH_STRING; 2136 if (val != NULL) 2137 ret->stringval = xmlStrdup(val); 2138 else 2139 ret->stringval = xmlStrdup((const xmlChar *)""); 2140 #ifdef XP_DEBUG_OBJ_USAGE 2141 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2142 #endif 2143 return(ret); 2144 } else if ((cache->miscObjs != NULL) && 2145 (cache->miscObjs->number != 0)) 2146 { 2147 xmlXPathObjectPtr ret; 2148 2149 ret = (xmlXPathObjectPtr) 2150 cache->miscObjs->items[--cache->miscObjs->number]; 2151 2152 ret->type = XPATH_STRING; 2153 if (val != NULL) 2154 ret->stringval = xmlStrdup(val); 2155 else 2156 ret->stringval = xmlStrdup((const xmlChar *)""); 2157 #ifdef XP_DEBUG_OBJ_USAGE 2158 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2159 #endif 2160 return(ret); 2161 } 2162 } 2163 return(xmlXPathNewString(val)); 2164 } 2165 2166 /** 2167 * xmlXPathCacheNewBoolean: 2168 * @ctxt: the XPath context 2169 * @val: the boolean value 2170 * 2171 * This is the cached version of xmlXPathNewBoolean(). 2172 * Acquires an xmlXPathObjectPtr of type boolean and of value @val 2173 * 2174 * Returns the created or reused object. 2175 */ 2176 static xmlXPathObjectPtr 2177 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val) 2178 { 2179 if ((ctxt != NULL) && (ctxt->cache)) { 2180 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2181 2182 if ((cache->booleanObjs != NULL) && 2183 (cache->booleanObjs->number != 0)) 2184 { 2185 xmlXPathObjectPtr ret; 2186 2187 ret = (xmlXPathObjectPtr) 2188 cache->booleanObjs->items[--cache->booleanObjs->number]; 2189 ret->type = XPATH_BOOLEAN; 2190 ret->boolval = (val != 0); 2191 #ifdef XP_DEBUG_OBJ_USAGE 2192 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN); 2193 #endif 2194 return(ret); 2195 } else if ((cache->miscObjs != NULL) && 2196 (cache->miscObjs->number != 0)) 2197 { 2198 xmlXPathObjectPtr ret; 2199 2200 ret = (xmlXPathObjectPtr) 2201 cache->miscObjs->items[--cache->miscObjs->number]; 2202 2203 ret->type = XPATH_BOOLEAN; 2204 ret->boolval = (val != 0); 2205 #ifdef XP_DEBUG_OBJ_USAGE 2206 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN); 2207 #endif 2208 return(ret); 2209 } 2210 } 2211 return(xmlXPathNewBoolean(val)); 2212 } 2213 2214 /** 2215 * xmlXPathCacheNewFloat: 2216 * @ctxt: the XPath context 2217 * @val: the double value 2218 * 2219 * This is the cached version of xmlXPathNewFloat(). 2220 * Acquires an xmlXPathObjectPtr of type double and of value @val 2221 * 2222 * Returns the created or reused object. 2223 */ 2224 static xmlXPathObjectPtr 2225 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val) 2226 { 2227 if ((ctxt != NULL) && (ctxt->cache)) { 2228 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2229 2230 if ((cache->numberObjs != NULL) && 2231 (cache->numberObjs->number != 0)) 2232 { 2233 xmlXPathObjectPtr ret; 2234 2235 ret = (xmlXPathObjectPtr) 2236 cache->numberObjs->items[--cache->numberObjs->number]; 2237 ret->type = XPATH_NUMBER; 2238 ret->floatval = val; 2239 #ifdef XP_DEBUG_OBJ_USAGE 2240 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER); 2241 #endif 2242 return(ret); 2243 } else if ((cache->miscObjs != NULL) && 2244 (cache->miscObjs->number != 0)) 2245 { 2246 xmlXPathObjectPtr ret; 2247 2248 ret = (xmlXPathObjectPtr) 2249 cache->miscObjs->items[--cache->miscObjs->number]; 2250 2251 ret->type = XPATH_NUMBER; 2252 ret->floatval = val; 2253 #ifdef XP_DEBUG_OBJ_USAGE 2254 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER); 2255 #endif 2256 return(ret); 2257 } 2258 } 2259 return(xmlXPathNewFloat(val)); 2260 } 2261 2262 /** 2263 * xmlXPathCacheConvertString: 2264 * @ctxt: the XPath context 2265 * @val: an XPath object 2266 * 2267 * This is the cached version of xmlXPathConvertString(). 2268 * Converts an existing object to its string() equivalent 2269 * 2270 * Returns a created or reused object, the old one is freed (cached) 2271 * (or the operation is done directly on @val) 2272 */ 2273 2274 static xmlXPathObjectPtr 2275 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 2276 xmlChar *res = NULL; 2277 2278 if (val == NULL) 2279 return(xmlXPathCacheNewCString(ctxt, "")); 2280 2281 switch (val->type) { 2282 case XPATH_UNDEFINED: 2283 #ifdef DEBUG_EXPR 2284 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n"); 2285 #endif 2286 break; 2287 case XPATH_NODESET: 2288 case XPATH_XSLT_TREE: 2289 res = xmlXPathCastNodeSetToString(val->nodesetval); 2290 break; 2291 case XPATH_STRING: 2292 return(val); 2293 case XPATH_BOOLEAN: 2294 res = xmlXPathCastBooleanToString(val->boolval); 2295 break; 2296 case XPATH_NUMBER: 2297 res = xmlXPathCastNumberToString(val->floatval); 2298 break; 2299 case XPATH_USERS: 2300 case XPATH_POINT: 2301 case XPATH_RANGE: 2302 case XPATH_LOCATIONSET: 2303 TODO; 2304 break; 2305 } 2306 xmlXPathReleaseObject(ctxt, val); 2307 if (res == NULL) 2308 return(xmlXPathCacheNewCString(ctxt, "")); 2309 return(xmlXPathCacheWrapString(ctxt, res)); 2310 } 2311 2312 /** 2313 * xmlXPathCacheObjectCopy: 2314 * @ctxt: the XPath context 2315 * @val: the original object 2316 * 2317 * This is the cached version of xmlXPathObjectCopy(). 2318 * Acquire a copy of a given object 2319 * 2320 * Returns a created or reused created object. 2321 */ 2322 static xmlXPathObjectPtr 2323 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) 2324 { 2325 if (val == NULL) 2326 return(NULL); 2327 2328 if (XP_HAS_CACHE(ctxt)) { 2329 switch (val->type) { 2330 case XPATH_NODESET: 2331 return(xmlXPathCacheWrapNodeSet(ctxt, 2332 xmlXPathNodeSetMerge(NULL, val->nodesetval))); 2333 case XPATH_STRING: 2334 return(xmlXPathCacheNewString(ctxt, val->stringval)); 2335 case XPATH_BOOLEAN: 2336 return(xmlXPathCacheNewBoolean(ctxt, val->boolval)); 2337 case XPATH_NUMBER: 2338 return(xmlXPathCacheNewFloat(ctxt, val->floatval)); 2339 default: 2340 break; 2341 } 2342 } 2343 return(xmlXPathObjectCopy(val)); 2344 } 2345 2346 /** 2347 * xmlXPathCacheConvertBoolean: 2348 * @ctxt: the XPath context 2349 * @val: an XPath object 2350 * 2351 * This is the cached version of xmlXPathConvertBoolean(). 2352 * Converts an existing object to its boolean() equivalent 2353 * 2354 * Returns a created or reused object, the old one is freed (or the operation 2355 * is done directly on @val) 2356 */ 2357 static xmlXPathObjectPtr 2358 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 2359 xmlXPathObjectPtr ret; 2360 2361 if (val == NULL) 2362 return(xmlXPathCacheNewBoolean(ctxt, 0)); 2363 if (val->type == XPATH_BOOLEAN) 2364 return(val); 2365 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val)); 2366 xmlXPathReleaseObject(ctxt, val); 2367 return(ret); 2368 } 2369 2370 /** 2371 * xmlXPathCacheConvertNumber: 2372 * @ctxt: the XPath context 2373 * @val: an XPath object 2374 * 2375 * This is the cached version of xmlXPathConvertNumber(). 2376 * Converts an existing object to its number() equivalent 2377 * 2378 * Returns a created or reused object, the old one is freed (or the operation 2379 * is done directly on @val) 2380 */ 2381 static xmlXPathObjectPtr 2382 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 2383 xmlXPathObjectPtr ret; 2384 2385 if (val == NULL) 2386 return(xmlXPathCacheNewFloat(ctxt, 0.0)); 2387 if (val->type == XPATH_NUMBER) 2388 return(val); 2389 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val)); 2390 xmlXPathReleaseObject(ctxt, val); 2391 return(ret); 2392 } 2393 2394 /************************************************************************ 2395 * * 2396 * Parser stacks related functions and macros * 2397 * * 2398 ************************************************************************/ 2399 2400 /** 2401 * valuePop: 2402 * @ctxt: an XPath evaluation context 2403 * 2404 * Pops the top XPath object from the value stack 2405 * 2406 * Returns the XPath object just removed 2407 */ 2408 xmlXPathObjectPtr 2409 valuePop(xmlXPathParserContextPtr ctxt) 2410 { 2411 xmlXPathObjectPtr ret; 2412 2413 if ((ctxt == NULL) || (ctxt->valueNr <= 0)) 2414 return (NULL); 2415 ctxt->valueNr--; 2416 if (ctxt->valueNr > 0) 2417 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1]; 2418 else 2419 ctxt->value = NULL; 2420 ret = ctxt->valueTab[ctxt->valueNr]; 2421 ctxt->valueTab[ctxt->valueNr] = NULL; 2422 return (ret); 2423 } 2424 /** 2425 * valuePush: 2426 * @ctxt: an XPath evaluation context 2427 * @value: the XPath object 2428 * 2429 * Pushes a new XPath object on top of the value stack 2430 * 2431 * returns the number of items on the value stack 2432 */ 2433 int 2434 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value) 2435 { 2436 if ((ctxt == NULL) || (value == NULL)) return(-1); 2437 if (ctxt->valueNr >= ctxt->valueMax) { 2438 xmlXPathObjectPtr *tmp; 2439 2440 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab, 2441 2 * ctxt->valueMax * 2442 sizeof(ctxt->valueTab[0])); 2443 if (tmp == NULL) { 2444 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); 2445 return (0); 2446 } 2447 ctxt->valueMax *= 2; 2448 ctxt->valueTab = tmp; 2449 } 2450 ctxt->valueTab[ctxt->valueNr] = value; 2451 ctxt->value = value; 2452 return (ctxt->valueNr++); 2453 } 2454 2455 /** 2456 * xmlXPathPopBoolean: 2457 * @ctxt: an XPath parser context 2458 * 2459 * Pops a boolean from the stack, handling conversion if needed. 2460 * Check error with #xmlXPathCheckError. 2461 * 2462 * Returns the boolean 2463 */ 2464 int 2465 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) { 2466 xmlXPathObjectPtr obj; 2467 int ret; 2468 2469 obj = valuePop(ctxt); 2470 if (obj == NULL) { 2471 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2472 return(0); 2473 } 2474 if (obj->type != XPATH_BOOLEAN) 2475 ret = xmlXPathCastToBoolean(obj); 2476 else 2477 ret = obj->boolval; 2478 xmlXPathReleaseObject(ctxt->context, obj); 2479 return(ret); 2480 } 2481 2482 /** 2483 * xmlXPathPopNumber: 2484 * @ctxt: an XPath parser context 2485 * 2486 * Pops a number from the stack, handling conversion if needed. 2487 * Check error with #xmlXPathCheckError. 2488 * 2489 * Returns the number 2490 */ 2491 double 2492 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) { 2493 xmlXPathObjectPtr obj; 2494 double ret; 2495 2496 obj = valuePop(ctxt); 2497 if (obj == NULL) { 2498 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2499 return(0); 2500 } 2501 if (obj->type != XPATH_NUMBER) 2502 ret = xmlXPathCastToNumber(obj); 2503 else 2504 ret = obj->floatval; 2505 xmlXPathReleaseObject(ctxt->context, obj); 2506 return(ret); 2507 } 2508 2509 /** 2510 * xmlXPathPopString: 2511 * @ctxt: an XPath parser context 2512 * 2513 * Pops a string from the stack, handling conversion if needed. 2514 * Check error with #xmlXPathCheckError. 2515 * 2516 * Returns the string 2517 */ 2518 xmlChar * 2519 xmlXPathPopString (xmlXPathParserContextPtr ctxt) { 2520 xmlXPathObjectPtr obj; 2521 xmlChar * ret; 2522 2523 obj = valuePop(ctxt); 2524 if (obj == NULL) { 2525 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2526 return(NULL); 2527 } 2528 ret = xmlXPathCastToString(obj); /* this does required strdup */ 2529 /* TODO: needs refactoring somewhere else */ 2530 if (obj->stringval == ret) 2531 obj->stringval = NULL; 2532 xmlXPathReleaseObject(ctxt->context, obj); 2533 return(ret); 2534 } 2535 2536 /** 2537 * xmlXPathPopNodeSet: 2538 * @ctxt: an XPath parser context 2539 * 2540 * Pops a node-set from the stack, handling conversion if needed. 2541 * Check error with #xmlXPathCheckError. 2542 * 2543 * Returns the node-set 2544 */ 2545 xmlNodeSetPtr 2546 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) { 2547 xmlXPathObjectPtr obj; 2548 xmlNodeSetPtr ret; 2549 2550 if (ctxt == NULL) return(NULL); 2551 if (ctxt->value == NULL) { 2552 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2553 return(NULL); 2554 } 2555 if (!xmlXPathStackIsNodeSet(ctxt)) { 2556 xmlXPathSetTypeError(ctxt); 2557 return(NULL); 2558 } 2559 obj = valuePop(ctxt); 2560 ret = obj->nodesetval; 2561 #if 0 2562 /* to fix memory leak of not clearing obj->user */ 2563 if (obj->boolval && obj->user != NULL) 2564 xmlFreeNodeList((xmlNodePtr) obj->user); 2565 #endif 2566 obj->nodesetval = NULL; 2567 xmlXPathReleaseObject(ctxt->context, obj); 2568 return(ret); 2569 } 2570 2571 /** 2572 * xmlXPathPopExternal: 2573 * @ctxt: an XPath parser context 2574 * 2575 * Pops an external object from the stack, handling conversion if needed. 2576 * Check error with #xmlXPathCheckError. 2577 * 2578 * Returns the object 2579 */ 2580 void * 2581 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) { 2582 xmlXPathObjectPtr obj; 2583 void * ret; 2584 2585 if ((ctxt == NULL) || (ctxt->value == NULL)) { 2586 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2587 return(NULL); 2588 } 2589 if (ctxt->value->type != XPATH_USERS) { 2590 xmlXPathSetTypeError(ctxt); 2591 return(NULL); 2592 } 2593 obj = valuePop(ctxt); 2594 ret = obj->user; 2595 obj->user = NULL; 2596 xmlXPathReleaseObject(ctxt->context, obj); 2597 return(ret); 2598 } 2599 2600 /* 2601 * Macros for accessing the content. Those should be used only by the parser, 2602 * and not exported. 2603 * 2604 * Dirty macros, i.e. one need to make assumption on the context to use them 2605 * 2606 * CUR_PTR return the current pointer to the xmlChar to be parsed. 2607 * CUR returns the current xmlChar value, i.e. a 8 bit value 2608 * in ISO-Latin or UTF-8. 2609 * This should be used internally by the parser 2610 * only to compare to ASCII values otherwise it would break when 2611 * running with UTF-8 encoding. 2612 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only 2613 * to compare on ASCII based substring. 2614 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined 2615 * strings within the parser. 2616 * CURRENT Returns the current char value, with the full decoding of 2617 * UTF-8 if we are using this mode. It returns an int. 2618 * NEXT Skip to the next character, this does the proper decoding 2619 * in UTF-8 mode. It also pop-up unfinished entities on the fly. 2620 * It returns the pointer to the current xmlChar. 2621 */ 2622 2623 #define CUR (*ctxt->cur) 2624 #define SKIP(val) ctxt->cur += (val) 2625 #define NXT(val) ctxt->cur[(val)] 2626 #define CUR_PTR ctxt->cur 2627 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l) 2628 2629 #define COPY_BUF(l,b,i,v) \ 2630 if (l == 1) b[i++] = (xmlChar) v; \ 2631 else i += xmlCopyChar(l,&b[i],v) 2632 2633 #define NEXTL(l) ctxt->cur += l 2634 2635 #define SKIP_BLANKS \ 2636 while (IS_BLANK_CH(*(ctxt->cur))) NEXT 2637 2638 #define CURRENT (*ctxt->cur) 2639 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur) 2640 2641 2642 #ifndef DBL_DIG 2643 #define DBL_DIG 16 2644 #endif 2645 #ifndef DBL_EPSILON 2646 #define DBL_EPSILON 1E-9 2647 #endif 2648 2649 #define UPPER_DOUBLE 1E9 2650 #define LOWER_DOUBLE 1E-5 2651 #define LOWER_DOUBLE_EXP 5 2652 2653 #define INTEGER_DIGITS DBL_DIG 2654 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP)) 2655 #define EXPONENT_DIGITS (3 + 2) 2656 2657 /** 2658 * xmlXPathFormatNumber: 2659 * @number: number to format 2660 * @buffer: output buffer 2661 * @buffersize: size of output buffer 2662 * 2663 * Convert the number into a string representation. 2664 */ 2665 static void 2666 xmlXPathFormatNumber(double number, char buffer[], int buffersize) 2667 { 2668 switch (xmlXPathIsInf(number)) { 2669 case 1: 2670 if (buffersize > (int)sizeof("Infinity")) 2671 snprintf(buffer, buffersize, "Infinity"); 2672 break; 2673 case -1: 2674 if (buffersize > (int)sizeof("-Infinity")) 2675 snprintf(buffer, buffersize, "-Infinity"); 2676 break; 2677 default: 2678 if (xmlXPathIsNaN(number)) { 2679 if (buffersize > (int)sizeof("NaN")) 2680 snprintf(buffer, buffersize, "NaN"); 2681 } else if (number == 0 && xmlXPathGetSign(number) != 0) { 2682 snprintf(buffer, buffersize, "0"); 2683 } else if (number == ((int) number)) { 2684 char work[30]; 2685 char *ptr, *cur; 2686 int value = (int) number; 2687 2688 ptr = &buffer[0]; 2689 if (value == 0) { 2690 *ptr++ = '0'; 2691 } else { 2692 snprintf(work, 29, "%d", value); 2693 cur = &work[0]; 2694 while ((*cur) && (ptr - buffer < buffersize)) { 2695 *ptr++ = *cur++; 2696 } 2697 } 2698 if (ptr - buffer < buffersize) { 2699 *ptr = 0; 2700 } else if (buffersize > 0) { 2701 ptr--; 2702 *ptr = 0; 2703 } 2704 } else { 2705 /* 2706 For the dimension of work, 2707 DBL_DIG is number of significant digits 2708 EXPONENT is only needed for "scientific notation" 2709 3 is sign, decimal point, and terminating zero 2710 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction 2711 Note that this dimension is slightly (a few characters) 2712 larger than actually necessary. 2713 */ 2714 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP]; 2715 int integer_place, fraction_place; 2716 char *ptr; 2717 char *after_fraction; 2718 double absolute_value; 2719 int size; 2720 2721 absolute_value = fabs(number); 2722 2723 /* 2724 * First choose format - scientific or regular floating point. 2725 * In either case, result is in work, and after_fraction points 2726 * just past the fractional part. 2727 */ 2728 if ( ((absolute_value > UPPER_DOUBLE) || 2729 (absolute_value < LOWER_DOUBLE)) && 2730 (absolute_value != 0.0) ) { 2731 /* Use scientific notation */ 2732 integer_place = DBL_DIG + EXPONENT_DIGITS + 1; 2733 fraction_place = DBL_DIG - 1; 2734 size = snprintf(work, sizeof(work),"%*.*e", 2735 integer_place, fraction_place, number); 2736 while ((size > 0) && (work[size] != 'e')) size--; 2737 2738 } 2739 else { 2740 /* Use regular notation */ 2741 if (absolute_value > 0.0) { 2742 integer_place = (int)log10(absolute_value); 2743 if (integer_place > 0) 2744 fraction_place = DBL_DIG - integer_place - 1; 2745 else 2746 fraction_place = DBL_DIG - integer_place; 2747 } else { 2748 fraction_place = 1; 2749 } 2750 size = snprintf(work, sizeof(work), "%0.*f", 2751 fraction_place, number); 2752 } 2753 2754 /* Remove fractional trailing zeroes */ 2755 after_fraction = work + size; 2756 ptr = after_fraction; 2757 while (*(--ptr) == '0') 2758 ; 2759 if (*ptr != '.') 2760 ptr++; 2761 while ((*ptr++ = *after_fraction++) != 0); 2762 2763 /* Finally copy result back to caller */ 2764 size = strlen(work) + 1; 2765 if (size > buffersize) { 2766 work[buffersize - 1] = 0; 2767 size = buffersize; 2768 } 2769 memmove(buffer, work, size); 2770 } 2771 break; 2772 } 2773 } 2774 2775 2776 /************************************************************************ 2777 * * 2778 * Routines to handle NodeSets * 2779 * * 2780 ************************************************************************/ 2781 2782 /** 2783 * xmlXPathOrderDocElems: 2784 * @doc: an input document 2785 * 2786 * Call this routine to speed up XPath computation on static documents. 2787 * This stamps all the element nodes with the document order 2788 * Like for line information, the order is kept in the element->content 2789 * field, the value stored is actually - the node number (starting at -1) 2790 * to be able to differentiate from line numbers. 2791 * 2792 * Returns the number of elements found in the document or -1 in case 2793 * of error. 2794 */ 2795 long 2796 xmlXPathOrderDocElems(xmlDocPtr doc) { 2797 long count = 0; 2798 xmlNodePtr cur; 2799 2800 if (doc == NULL) 2801 return(-1); 2802 cur = doc->children; 2803 while (cur != NULL) { 2804 if (cur->type == XML_ELEMENT_NODE) { 2805 cur->content = (void *) (-(++count)); 2806 if (cur->children != NULL) { 2807 cur = cur->children; 2808 continue; 2809 } 2810 } 2811 if (cur->next != NULL) { 2812 cur = cur->next; 2813 continue; 2814 } 2815 do { 2816 cur = cur->parent; 2817 if (cur == NULL) 2818 break; 2819 if (cur == (xmlNodePtr) doc) { 2820 cur = NULL; 2821 break; 2822 } 2823 if (cur->next != NULL) { 2824 cur = cur->next; 2825 break; 2826 } 2827 } while (cur != NULL); 2828 } 2829 return(count); 2830 } 2831 2832 /** 2833 * xmlXPathCmpNodes: 2834 * @node1: the first node 2835 * @node2: the second node 2836 * 2837 * Compare two nodes w.r.t document order 2838 * 2839 * Returns -2 in case of error 1 if first point < second point, 0 if 2840 * it's the same node, -1 otherwise 2841 */ 2842 int 2843 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) { 2844 int depth1, depth2; 2845 int attr1 = 0, attr2 = 0; 2846 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL; 2847 xmlNodePtr cur, root; 2848 2849 if ((node1 == NULL) || (node2 == NULL)) 2850 return(-2); 2851 /* 2852 * a couple of optimizations which will avoid computations in most cases 2853 */ 2854 if (node1 == node2) /* trivial case */ 2855 return(0); 2856 if (node1->type == XML_ATTRIBUTE_NODE) { 2857 attr1 = 1; 2858 attrNode1 = node1; 2859 node1 = node1->parent; 2860 } 2861 if (node2->type == XML_ATTRIBUTE_NODE) { 2862 attr2 = 1; 2863 attrNode2 = node2; 2864 node2 = node2->parent; 2865 } 2866 if (node1 == node2) { 2867 if (attr1 == attr2) { 2868 /* not required, but we keep attributes in order */ 2869 if (attr1 != 0) { 2870 cur = attrNode2->prev; 2871 while (cur != NULL) { 2872 if (cur == attrNode1) 2873 return (1); 2874 cur = cur->prev; 2875 } 2876 return (-1); 2877 } 2878 return(0); 2879 } 2880 if (attr2 == 1) 2881 return(1); 2882 return(-1); 2883 } 2884 if ((node1->type == XML_NAMESPACE_DECL) || 2885 (node2->type == XML_NAMESPACE_DECL)) 2886 return(1); 2887 if (node1 == node2->prev) 2888 return(1); 2889 if (node1 == node2->next) 2890 return(-1); 2891 2892 /* 2893 * Speedup using document order if availble. 2894 */ 2895 if ((node1->type == XML_ELEMENT_NODE) && 2896 (node2->type == XML_ELEMENT_NODE) && 2897 (0 > (long) node1->content) && 2898 (0 > (long) node2->content) && 2899 (node1->doc == node2->doc)) { 2900 long l1, l2; 2901 2902 l1 = -((long) node1->content); 2903 l2 = -((long) node2->content); 2904 if (l1 < l2) 2905 return(1); 2906 if (l1 > l2) 2907 return(-1); 2908 } 2909 2910 /* 2911 * compute depth to root 2912 */ 2913 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) { 2914 if (cur == node1) 2915 return(1); 2916 depth2++; 2917 } 2918 root = cur; 2919 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) { 2920 if (cur == node2) 2921 return(-1); 2922 depth1++; 2923 } 2924 /* 2925 * Distinct document (or distinct entities :-( ) case. 2926 */ 2927 if (root != cur) { 2928 return(-2); 2929 } 2930 /* 2931 * get the nearest common ancestor. 2932 */ 2933 while (depth1 > depth2) { 2934 depth1--; 2935 node1 = node1->parent; 2936 } 2937 while (depth2 > depth1) { 2938 depth2--; 2939 node2 = node2->parent; 2940 } 2941 while (node1->parent != node2->parent) { 2942 node1 = node1->parent; 2943 node2 = node2->parent; 2944 /* should not happen but just in case ... */ 2945 if ((node1 == NULL) || (node2 == NULL)) 2946 return(-2); 2947 } 2948 /* 2949 * Find who's first. 2950 */ 2951 if (node1 == node2->prev) 2952 return(1); 2953 if (node1 == node2->next) 2954 return(-1); 2955 /* 2956 * Speedup using document order if availble. 2957 */ 2958 if ((node1->type == XML_ELEMENT_NODE) && 2959 (node2->type == XML_ELEMENT_NODE) && 2960 (0 > (long) node1->content) && 2961 (0 > (long) node2->content) && 2962 (node1->doc == node2->doc)) { 2963 long l1, l2; 2964 2965 l1 = -((long) node1->content); 2966 l2 = -((long) node2->content); 2967 if (l1 < l2) 2968 return(1); 2969 if (l1 > l2) 2970 return(-1); 2971 } 2972 2973 for (cur = node1->next;cur != NULL;cur = cur->next) 2974 if (cur == node2) 2975 return(1); 2976 return(-1); /* assume there is no sibling list corruption */ 2977 } 2978 2979 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 2980 /** 2981 * xmlXPathCmpNodesExt: 2982 * @node1: the first node 2983 * @node2: the second node 2984 * 2985 * Compare two nodes w.r.t document order. 2986 * This one is optimized for handling of non-element nodes. 2987 * 2988 * Returns -2 in case of error 1 if first point < second point, 0 if 2989 * it's the same node, -1 otherwise 2990 */ 2991 static int 2992 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) { 2993 int depth1, depth2; 2994 int misc = 0, precedence1 = 0, precedence2 = 0; 2995 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL; 2996 xmlNodePtr cur, root; 2997 long l1, l2; 2998 2999 if ((node1 == NULL) || (node2 == NULL)) 3000 return(-2); 3001 3002 if (node1 == node2) 3003 return(0); 3004 3005 /* 3006 * a couple of optimizations which will avoid computations in most cases 3007 */ 3008 switch (node1->type) { 3009 case XML_ELEMENT_NODE: 3010 if (node2->type == XML_ELEMENT_NODE) { 3011 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */ 3012 (0 > (long) node2->content) && 3013 (node1->doc == node2->doc)) 3014 { 3015 l1 = -((long) node1->content); 3016 l2 = -((long) node2->content); 3017 if (l1 < l2) 3018 return(1); 3019 if (l1 > l2) 3020 return(-1); 3021 } else 3022 goto turtle_comparison; 3023 } 3024 break; 3025 case XML_ATTRIBUTE_NODE: 3026 precedence1 = 1; /* element is owner */ 3027 miscNode1 = node1; 3028 node1 = node1->parent; 3029 misc = 1; 3030 break; 3031 case XML_TEXT_NODE: 3032 case XML_CDATA_SECTION_NODE: 3033 case XML_COMMENT_NODE: 3034 case XML_PI_NODE: { 3035 miscNode1 = node1; 3036 /* 3037 * Find nearest element node. 3038 */ 3039 if (node1->prev != NULL) { 3040 do { 3041 node1 = node1->prev; 3042 if (node1->type == XML_ELEMENT_NODE) { 3043 precedence1 = 3; /* element in prev-sibl axis */ 3044 break; 3045 } 3046 if (node1->prev == NULL) { 3047 precedence1 = 2; /* element is parent */ 3048 /* 3049 * URGENT TODO: Are there any cases, where the 3050 * parent of such a node is not an element node? 3051 */ 3052 node1 = node1->parent; 3053 break; 3054 } 3055 } while (1); 3056 } else { 3057 precedence1 = 2; /* element is parent */ 3058 node1 = node1->parent; 3059 } 3060 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) || 3061 (0 <= (long) node1->content)) { 3062 /* 3063 * Fallback for whatever case. 3064 */ 3065 node1 = miscNode1; 3066 precedence1 = 0; 3067 } else 3068 misc = 1; 3069 } 3070 break; 3071 case XML_NAMESPACE_DECL: 3072 /* 3073 * TODO: why do we return 1 for namespace nodes? 3074 */ 3075 return(1); 3076 default: 3077 break; 3078 } 3079 switch (node2->type) { 3080 case XML_ELEMENT_NODE: 3081 break; 3082 case XML_ATTRIBUTE_NODE: 3083 precedence2 = 1; /* element is owner */ 3084 miscNode2 = node2; 3085 node2 = node2->parent; 3086 misc = 1; 3087 break; 3088 case XML_TEXT_NODE: 3089 case XML_CDATA_SECTION_NODE: 3090 case XML_COMMENT_NODE: 3091 case XML_PI_NODE: { 3092 miscNode2 = node2; 3093 if (node2->prev != NULL) { 3094 do { 3095 node2 = node2->prev; 3096 if (node2->type == XML_ELEMENT_NODE) { 3097 precedence2 = 3; /* element in prev-sibl axis */ 3098 break; 3099 } 3100 if (node2->prev == NULL) { 3101 precedence2 = 2; /* element is parent */ 3102 node2 = node2->parent; 3103 break; 3104 } 3105 } while (1); 3106 } else { 3107 precedence2 = 2; /* element is parent */ 3108 node2 = node2->parent; 3109 } 3110 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) || 3111 (0 <= (long) node1->content)) 3112 { 3113 node2 = miscNode2; 3114 precedence2 = 0; 3115 } else 3116 misc = 1; 3117 } 3118 break; 3119 case XML_NAMESPACE_DECL: 3120 return(1); 3121 default: 3122 break; 3123 } 3124 if (misc) { 3125 if (node1 == node2) { 3126 if (precedence1 == precedence2) { 3127 /* 3128 * The ugly case; but normally there aren't many 3129 * adjacent non-element nodes around. 3130 */ 3131 cur = miscNode2->prev; 3132 while (cur != NULL) { 3133 if (cur == miscNode1) 3134 return(1); 3135 if (cur->type == XML_ELEMENT_NODE) 3136 return(-1); 3137 cur = cur->prev; 3138 } 3139 return (-1); 3140 } else { 3141 /* 3142 * Evaluate based on higher precedence wrt to the element. 3143 * TODO: This assumes attributes are sorted before content. 3144 * Is this 100% correct? 3145 */ 3146 if (precedence1 < precedence2) 3147 return(1); 3148 else 3149 return(-1); 3150 } 3151 } 3152 /* 3153 * Special case: One of the helper-elements is contained by the other. 3154 * <foo> 3155 * <node2> 3156 * <node1>Text-1(precedence1 == 2)</node1> 3157 * </node2> 3158 * Text-6(precedence2 == 3) 3159 * </foo> 3160 */ 3161 if ((precedence2 == 3) && (precedence1 > 1)) { 3162 cur = node1->parent; 3163 while (cur) { 3164 if (cur == node2) 3165 return(1); 3166 cur = cur->parent; 3167 } 3168 } 3169 if ((precedence1 == 3) && (precedence2 > 1)) { 3170 cur = node2->parent; 3171 while (cur) { 3172 if (cur == node1) 3173 return(-1); 3174 cur = cur->parent; 3175 } 3176 } 3177 } 3178 3179 /* 3180 * Speedup using document order if availble. 3181 */ 3182 if ((node1->type == XML_ELEMENT_NODE) && 3183 (node2->type == XML_ELEMENT_NODE) && 3184 (0 > (long) node1->content) && 3185 (0 > (long) node2->content) && 3186 (node1->doc == node2->doc)) { 3187 3188 l1 = -((long) node1->content); 3189 l2 = -((long) node2->content); 3190 if (l1 < l2) 3191 return(1); 3192 if (l1 > l2) 3193 return(-1); 3194 } 3195 3196 turtle_comparison: 3197 3198 if (node1 == node2->prev) 3199 return(1); 3200 if (node1 == node2->next) 3201 return(-1); 3202 /* 3203 * compute depth to root 3204 */ 3205 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) { 3206 if (cur == node1) 3207 return(1); 3208 depth2++; 3209 } 3210 root = cur; 3211 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) { 3212 if (cur == node2) 3213 return(-1); 3214 depth1++; 3215 } 3216 /* 3217 * Distinct document (or distinct entities :-( ) case. 3218 */ 3219 if (root != cur) { 3220 return(-2); 3221 } 3222 /* 3223 * get the nearest common ancestor. 3224 */ 3225 while (depth1 > depth2) { 3226 depth1--; 3227 node1 = node1->parent; 3228 } 3229 while (depth2 > depth1) { 3230 depth2--; 3231 node2 = node2->parent; 3232 } 3233 while (node1->parent != node2->parent) { 3234 node1 = node1->parent; 3235 node2 = node2->parent; 3236 /* should not happen but just in case ... */ 3237 if ((node1 == NULL) || (node2 == NULL)) 3238 return(-2); 3239 } 3240 /* 3241 * Find who's first. 3242 */ 3243 if (node1 == node2->prev) 3244 return(1); 3245 if (node1 == node2->next) 3246 return(-1); 3247 /* 3248 * Speedup using document order if availble. 3249 */ 3250 if ((node1->type == XML_ELEMENT_NODE) && 3251 (node2->type == XML_ELEMENT_NODE) && 3252 (0 > (long) node1->content) && 3253 (0 > (long) node2->content) && 3254 (node1->doc == node2->doc)) { 3255 3256 l1 = -((long) node1->content); 3257 l2 = -((long) node2->content); 3258 if (l1 < l2) 3259 return(1); 3260 if (l1 > l2) 3261 return(-1); 3262 } 3263 3264 for (cur = node1->next;cur != NULL;cur = cur->next) 3265 if (cur == node2) 3266 return(1); 3267 return(-1); /* assume there is no sibling list corruption */ 3268 } 3269 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */ 3270 3271 /** 3272 * xmlXPathNodeSetSort: 3273 * @set: the node set 3274 * 3275 * Sort the node set in document order 3276 */ 3277 void 3278 xmlXPathNodeSetSort(xmlNodeSetPtr set) { 3279 int i, j, incr, len; 3280 xmlNodePtr tmp; 3281 3282 if (set == NULL) 3283 return; 3284 3285 /* Use Shell's sort to sort the node-set */ 3286 len = set->nodeNr; 3287 for (incr = len / 2; incr > 0; incr /= 2) { 3288 for (i = incr; i < len; i++) { 3289 j = i - incr; 3290 while (j >= 0) { 3291 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 3292 if (xmlXPathCmpNodesExt(set->nodeTab[j], 3293 set->nodeTab[j + incr]) == -1) 3294 #else 3295 if (xmlXPathCmpNodes(set->nodeTab[j], 3296 set->nodeTab[j + incr]) == -1) 3297 #endif 3298 { 3299 tmp = set->nodeTab[j]; 3300 set->nodeTab[j] = set->nodeTab[j + incr]; 3301 set->nodeTab[j + incr] = tmp; 3302 j -= incr; 3303 } else 3304 break; 3305 } 3306 } 3307 } 3308 } 3309 3310 #define XML_NODESET_DEFAULT 10 3311 /** 3312 * xmlXPathNodeSetDupNs: 3313 * @node: the parent node of the namespace XPath node 3314 * @ns: the libxml namespace declaration node. 3315 * 3316 * Namespace node in libxml don't match the XPath semantic. In a node set 3317 * the namespace nodes are duplicated and the next pointer is set to the 3318 * parent node in the XPath semantic. 3319 * 3320 * Returns the newly created object. 3321 */ 3322 static xmlNodePtr 3323 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) { 3324 xmlNsPtr cur; 3325 3326 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) 3327 return(NULL); 3328 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) 3329 return((xmlNodePtr) ns); 3330 3331 /* 3332 * Allocate a new Namespace and fill the fields. 3333 */ 3334 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); 3335 if (cur == NULL) { 3336 xmlXPathErrMemory(NULL, "duplicating namespace\n"); 3337 return(NULL); 3338 } 3339 memset(cur, 0, sizeof(xmlNs)); 3340 cur->type = XML_NAMESPACE_DECL; 3341 if (ns->href != NULL) 3342 cur->href = xmlStrdup(ns->href); 3343 if (ns->prefix != NULL) 3344 cur->prefix = xmlStrdup(ns->prefix); 3345 cur->next = (xmlNsPtr) node; 3346 return((xmlNodePtr) cur); 3347 } 3348 3349 /** 3350 * xmlXPathNodeSetFreeNs: 3351 * @ns: the XPath namespace node found in a nodeset. 3352 * 3353 * Namespace nodes in libxml don't match the XPath semantic. In a node set 3354 * the namespace nodes are duplicated and the next pointer is set to the 3355 * parent node in the XPath semantic. Check if such a node needs to be freed 3356 */ 3357 void 3358 xmlXPathNodeSetFreeNs(xmlNsPtr ns) { 3359 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) 3360 return; 3361 3362 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) { 3363 if (ns->href != NULL) 3364 xmlFree((xmlChar *)ns->href); 3365 if (ns->prefix != NULL) 3366 xmlFree((xmlChar *)ns->prefix); 3367 xmlFree(ns); 3368 } 3369 } 3370 3371 /** 3372 * xmlXPathNodeSetCreate: 3373 * @val: an initial xmlNodePtr, or NULL 3374 * 3375 * Create a new xmlNodeSetPtr of type double and of value @val 3376 * 3377 * Returns the newly created object. 3378 */ 3379 xmlNodeSetPtr 3380 xmlXPathNodeSetCreate(xmlNodePtr val) { 3381 xmlNodeSetPtr ret; 3382 3383 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet)); 3384 if (ret == NULL) { 3385 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3386 return(NULL); 3387 } 3388 memset(ret, 0 , (size_t) sizeof(xmlNodeSet)); 3389 if (val != NULL) { 3390 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3391 sizeof(xmlNodePtr)); 3392 if (ret->nodeTab == NULL) { 3393 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3394 xmlFree(ret); 3395 return(NULL); 3396 } 3397 memset(ret->nodeTab, 0 , 3398 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3399 ret->nodeMax = XML_NODESET_DEFAULT; 3400 if (val->type == XML_NAMESPACE_DECL) { 3401 xmlNsPtr ns = (xmlNsPtr) val; 3402 3403 ret->nodeTab[ret->nodeNr++] = 3404 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3405 } else 3406 ret->nodeTab[ret->nodeNr++] = val; 3407 } 3408 return(ret); 3409 } 3410 3411 /** 3412 * xmlXPathNodeSetCreateSize: 3413 * @size: the initial size of the set 3414 * 3415 * Create a new xmlNodeSetPtr of type double and of value @val 3416 * 3417 * Returns the newly created object. 3418 */ 3419 static xmlNodeSetPtr 3420 xmlXPathNodeSetCreateSize(int size) { 3421 xmlNodeSetPtr ret; 3422 3423 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet)); 3424 if (ret == NULL) { 3425 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3426 return(NULL); 3427 } 3428 memset(ret, 0 , (size_t) sizeof(xmlNodeSet)); 3429 if (size < XML_NODESET_DEFAULT) 3430 size = XML_NODESET_DEFAULT; 3431 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr)); 3432 if (ret->nodeTab == NULL) { 3433 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3434 xmlFree(ret); 3435 return(NULL); 3436 } 3437 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr)); 3438 ret->nodeMax = size; 3439 return(ret); 3440 } 3441 3442 /** 3443 * xmlXPathNodeSetContains: 3444 * @cur: the node-set 3445 * @val: the node 3446 * 3447 * checks whether @cur contains @val 3448 * 3449 * Returns true (1) if @cur contains @val, false (0) otherwise 3450 */ 3451 int 3452 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) { 3453 int i; 3454 3455 if ((cur == NULL) || (val == NULL)) return(0); 3456 if (val->type == XML_NAMESPACE_DECL) { 3457 for (i = 0; i < cur->nodeNr; i++) { 3458 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) { 3459 xmlNsPtr ns1, ns2; 3460 3461 ns1 = (xmlNsPtr) val; 3462 ns2 = (xmlNsPtr) cur->nodeTab[i]; 3463 if (ns1 == ns2) 3464 return(1); 3465 if ((ns1->next != NULL) && (ns2->next == ns1->next) && 3466 (xmlStrEqual(ns1->prefix, ns2->prefix))) 3467 return(1); 3468 } 3469 } 3470 } else { 3471 for (i = 0; i < cur->nodeNr; i++) { 3472 if (cur->nodeTab[i] == val) 3473 return(1); 3474 } 3475 } 3476 return(0); 3477 } 3478 3479 /** 3480 * xmlXPathNodeSetAddNs: 3481 * @cur: the initial node set 3482 * @node: the hosting node 3483 * @ns: a the namespace node 3484 * 3485 * add a new namespace node to an existing NodeSet 3486 */ 3487 void 3488 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) { 3489 int i; 3490 3491 3492 if ((cur == NULL) || (ns == NULL) || (node == NULL) || 3493 (ns->type != XML_NAMESPACE_DECL) || 3494 (node->type != XML_ELEMENT_NODE)) 3495 return; 3496 3497 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3498 /* 3499 * prevent duplicates 3500 */ 3501 for (i = 0;i < cur->nodeNr;i++) { 3502 if ((cur->nodeTab[i] != NULL) && 3503 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) && 3504 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) && 3505 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix))) 3506 return; 3507 } 3508 3509 /* 3510 * grow the nodeTab if needed 3511 */ 3512 if (cur->nodeMax == 0) { 3513 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3514 sizeof(xmlNodePtr)); 3515 if (cur->nodeTab == NULL) { 3516 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3517 return; 3518 } 3519 memset(cur->nodeTab, 0 , 3520 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3521 cur->nodeMax = XML_NODESET_DEFAULT; 3522 } else if (cur->nodeNr == cur->nodeMax) { 3523 xmlNodePtr *temp; 3524 3525 cur->nodeMax *= 2; 3526 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 3527 sizeof(xmlNodePtr)); 3528 if (temp == NULL) { 3529 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3530 return; 3531 } 3532 cur->nodeTab = temp; 3533 } 3534 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns); 3535 } 3536 3537 /** 3538 * xmlXPathNodeSetAdd: 3539 * @cur: the initial node set 3540 * @val: a new xmlNodePtr 3541 * 3542 * add a new xmlNodePtr to an existing NodeSet 3543 */ 3544 void 3545 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) { 3546 int i; 3547 3548 if ((cur == NULL) || (val == NULL)) return; 3549 3550 #if 0 3551 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' ')) 3552 return; /* an XSLT fake node */ 3553 #endif 3554 3555 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3556 /* 3557 * prevent duplcates 3558 */ 3559 for (i = 0;i < cur->nodeNr;i++) 3560 if (cur->nodeTab[i] == val) return; 3561 3562 /* 3563 * grow the nodeTab if needed 3564 */ 3565 if (cur->nodeMax == 0) { 3566 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3567 sizeof(xmlNodePtr)); 3568 if (cur->nodeTab == NULL) { 3569 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3570 return; 3571 } 3572 memset(cur->nodeTab, 0 , 3573 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3574 cur->nodeMax = XML_NODESET_DEFAULT; 3575 } else if (cur->nodeNr == cur->nodeMax) { 3576 xmlNodePtr *temp; 3577 3578 cur->nodeMax *= 2; 3579 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 3580 sizeof(xmlNodePtr)); 3581 if (temp == NULL) { 3582 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3583 return; 3584 } 3585 cur->nodeTab = temp; 3586 } 3587 if (val->type == XML_NAMESPACE_DECL) { 3588 xmlNsPtr ns = (xmlNsPtr) val; 3589 3590 cur->nodeTab[cur->nodeNr++] = 3591 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3592 } else 3593 cur->nodeTab[cur->nodeNr++] = val; 3594 } 3595 3596 /** 3597 * xmlXPathNodeSetAddUnique: 3598 * @cur: the initial node set 3599 * @val: a new xmlNodePtr 3600 * 3601 * add a new xmlNodePtr to an existing NodeSet, optimized version 3602 * when we are sure the node is not already in the set. 3603 */ 3604 void 3605 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) { 3606 if ((cur == NULL) || (val == NULL)) return; 3607 3608 #if 0 3609 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' ')) 3610 return; /* an XSLT fake node */ 3611 #endif 3612 3613 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3614 /* 3615 * grow the nodeTab if needed 3616 */ 3617 if (cur->nodeMax == 0) { 3618 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3619 sizeof(xmlNodePtr)); 3620 if (cur->nodeTab == NULL) { 3621 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3622 return; 3623 } 3624 memset(cur->nodeTab, 0 , 3625 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3626 cur->nodeMax = XML_NODESET_DEFAULT; 3627 } else if (cur->nodeNr == cur->nodeMax) { 3628 xmlNodePtr *temp; 3629 3630 cur->nodeMax *= 2; 3631 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 3632 sizeof(xmlNodePtr)); 3633 if (temp == NULL) { 3634 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3635 return; 3636 } 3637 cur->nodeTab = temp; 3638 } 3639 if (val->type == XML_NAMESPACE_DECL) { 3640 xmlNsPtr ns = (xmlNsPtr) val; 3641 3642 cur->nodeTab[cur->nodeNr++] = 3643 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3644 } else 3645 cur->nodeTab[cur->nodeNr++] = val; 3646 } 3647 3648 /** 3649 * xmlXPathNodeSetMerge: 3650 * @val1: the first NodeSet or NULL 3651 * @val2: the second NodeSet 3652 * 3653 * Merges two nodesets, all nodes from @val2 are added to @val1 3654 * if @val1 is NULL, a new set is created and copied from @val2 3655 * 3656 * Returns @val1 once extended or NULL in case of error. 3657 */ 3658 xmlNodeSetPtr 3659 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) { 3660 int i, j, initNr, skip; 3661 xmlNodePtr n1, n2; 3662 3663 if (val2 == NULL) return(val1); 3664 if (val1 == NULL) { 3665 val1 = xmlXPathNodeSetCreate(NULL); 3666 if (val1 == NULL) 3667 return (NULL); 3668 #if 0 3669 /* 3670 * TODO: The optimization won't work in every case, since 3671 * those nasty namespace nodes need to be added with 3672 * xmlXPathNodeSetDupNs() to the set; thus a pure 3673 * memcpy is not possible. 3674 * If there was a flag on the nodesetval, indicating that 3675 * some temporary nodes are in, that would be helpfull. 3676 */ 3677 /* 3678 * Optimization: Create an equally sized node-set 3679 * and memcpy the content. 3680 */ 3681 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr); 3682 if (val1 == NULL) 3683 return(NULL); 3684 if (val2->nodeNr != 0) { 3685 if (val2->nodeNr == 1) 3686 *(val1->nodeTab) = *(val2->nodeTab); 3687 else { 3688 memcpy(val1->nodeTab, val2->nodeTab, 3689 val2->nodeNr * sizeof(xmlNodePtr)); 3690 } 3691 val1->nodeNr = val2->nodeNr; 3692 } 3693 return(val1); 3694 #endif 3695 } 3696 3697 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3698 initNr = val1->nodeNr; 3699 3700 for (i = 0;i < val2->nodeNr;i++) { 3701 n2 = val2->nodeTab[i]; 3702 /* 3703 * check against duplicates 3704 */ 3705 skip = 0; 3706 for (j = 0; j < initNr; j++) { 3707 n1 = val1->nodeTab[j]; 3708 if (n1 == n2) { 3709 skip = 1; 3710 break; 3711 } else if ((n1->type == XML_NAMESPACE_DECL) && 3712 (n2->type == XML_NAMESPACE_DECL)) { 3713 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) && 3714 (xmlStrEqual(((xmlNsPtr) n1)->prefix, 3715 ((xmlNsPtr) n2)->prefix))) 3716 { 3717 skip = 1; 3718 break; 3719 } 3720 } 3721 } 3722 if (skip) 3723 continue; 3724 3725 /* 3726 * grow the nodeTab if needed 3727 */ 3728 if (val1->nodeMax == 0) { 3729 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3730 sizeof(xmlNodePtr)); 3731 if (val1->nodeTab == NULL) { 3732 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3733 return(NULL); 3734 } 3735 memset(val1->nodeTab, 0 , 3736 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3737 val1->nodeMax = XML_NODESET_DEFAULT; 3738 } else if (val1->nodeNr == val1->nodeMax) { 3739 xmlNodePtr *temp; 3740 3741 val1->nodeMax *= 2; 3742 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 3743 sizeof(xmlNodePtr)); 3744 if (temp == NULL) { 3745 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3746 return(NULL); 3747 } 3748 val1->nodeTab = temp; 3749 } 3750 if (n2->type == XML_NAMESPACE_DECL) { 3751 xmlNsPtr ns = (xmlNsPtr) n2; 3752 3753 val1->nodeTab[val1->nodeNr++] = 3754 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3755 } else 3756 val1->nodeTab[val1->nodeNr++] = n2; 3757 } 3758 3759 return(val1); 3760 } 3761 3762 #if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */ 3763 /** 3764 * xmlXPathNodeSetMergeUnique: 3765 * @val1: the first NodeSet or NULL 3766 * @val2: the second NodeSet 3767 * 3768 * Merges two nodesets, all nodes from @val2 are added to @val1 3769 * if @val1 is NULL, a new set is created and copied from @val2 3770 * 3771 * Returns @val1 once extended or NULL in case of error. 3772 */ 3773 static xmlNodeSetPtr 3774 xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) { 3775 int i; 3776 3777 if (val2 == NULL) return(val1); 3778 if (val1 == NULL) { 3779 val1 = xmlXPathNodeSetCreate(NULL); 3780 } 3781 if (val1 == NULL) 3782 return (NULL); 3783 3784 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3785 3786 for (i = 0;i < val2->nodeNr;i++) { 3787 /* 3788 * grow the nodeTab if needed 3789 */ 3790 if (val1->nodeMax == 0) { 3791 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3792 sizeof(xmlNodePtr)); 3793 if (val1->nodeTab == NULL) { 3794 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3795 return(NULL); 3796 } 3797 memset(val1->nodeTab, 0 , 3798 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3799 val1->nodeMax = XML_NODESET_DEFAULT; 3800 } else if (val1->nodeNr == val1->nodeMax) { 3801 xmlNodePtr *temp; 3802 3803 val1->nodeMax *= 2; 3804 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 3805 sizeof(xmlNodePtr)); 3806 if (temp == NULL) { 3807 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3808 return(NULL); 3809 } 3810 val1->nodeTab = temp; 3811 } 3812 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) { 3813 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i]; 3814 3815 val1->nodeTab[val1->nodeNr++] = 3816 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3817 } else 3818 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i]; 3819 } 3820 3821 return(val1); 3822 } 3823 #endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */ 3824 3825 /** 3826 * xmlXPathNodeSetMergeAndClear: 3827 * @set1: the first NodeSet or NULL 3828 * @set2: the second NodeSet 3829 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes 3830 * 3831 * Merges two nodesets, all nodes from @set2 are added to @set1 3832 * if @set1 is NULL, a new set is created and copied from @set2. 3833 * Checks for duplicate nodes. Clears set2. 3834 * 3835 * Returns @set1 once extended or NULL in case of error. 3836 */ 3837 static xmlNodeSetPtr 3838 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2, 3839 int hasNullEntries) 3840 { 3841 if ((set1 == NULL) && (hasNullEntries == 0)) { 3842 /* 3843 * Note that doing a memcpy of the list, namespace nodes are 3844 * just assigned to set1, since set2 is cleared anyway. 3845 */ 3846 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr); 3847 if (set1 == NULL) 3848 return(NULL); 3849 if (set2->nodeNr != 0) { 3850 memcpy(set1->nodeTab, set2->nodeTab, 3851 set2->nodeNr * sizeof(xmlNodePtr)); 3852 set1->nodeNr = set2->nodeNr; 3853 } 3854 } else { 3855 int i, j, initNbSet1; 3856 xmlNodePtr n1, n2; 3857 3858 if (set1 == NULL) 3859 set1 = xmlXPathNodeSetCreate(NULL); 3860 if (set1 == NULL) 3861 return (NULL); 3862 3863 initNbSet1 = set1->nodeNr; 3864 for (i = 0;i < set2->nodeNr;i++) { 3865 n2 = set2->nodeTab[i]; 3866 /* 3867 * Skip NULLed entries. 3868 */ 3869 if (n2 == NULL) 3870 continue; 3871 /* 3872 * Skip duplicates. 3873 */ 3874 for (j = 0; j < initNbSet1; j++) { 3875 n1 = set1->nodeTab[j]; 3876 if (n1 == n2) { 3877 goto skip_node; 3878 } else if ((n1->type == XML_NAMESPACE_DECL) && 3879 (n2->type == XML_NAMESPACE_DECL)) 3880 { 3881 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) && 3882 (xmlStrEqual(((xmlNsPtr) n1)->prefix, 3883 ((xmlNsPtr) n2)->prefix))) 3884 { 3885 /* 3886 * Free the namespace node. 3887 */ 3888 set2->nodeTab[i] = NULL; 3889 xmlXPathNodeSetFreeNs((xmlNsPtr) n2); 3890 goto skip_node; 3891 } 3892 } 3893 } 3894 /* 3895 * grow the nodeTab if needed 3896 */ 3897 if (set1->nodeMax == 0) { 3898 set1->nodeTab = (xmlNodePtr *) xmlMalloc( 3899 XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); 3900 if (set1->nodeTab == NULL) { 3901 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3902 return(NULL); 3903 } 3904 memset(set1->nodeTab, 0, 3905 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3906 set1->nodeMax = XML_NODESET_DEFAULT; 3907 } else if (set1->nodeNr >= set1->nodeMax) { 3908 xmlNodePtr *temp; 3909 3910 set1->nodeMax *= 2; 3911 temp = (xmlNodePtr *) xmlRealloc( 3912 set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr)); 3913 if (temp == NULL) { 3914 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3915 return(NULL); 3916 } 3917 set1->nodeTab = temp; 3918 } 3919 if (n2->type == XML_NAMESPACE_DECL) { 3920 xmlNsPtr ns = (xmlNsPtr) n2; 3921 3922 set1->nodeTab[set1->nodeNr++] = 3923 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3924 } else 3925 set1->nodeTab[set1->nodeNr++] = n2; 3926 skip_node: 3927 {} 3928 } 3929 } 3930 set2->nodeNr = 0; 3931 return(set1); 3932 } 3933 3934 /** 3935 * xmlXPathNodeSetMergeAndClearNoDupls: 3936 * @set1: the first NodeSet or NULL 3937 * @set2: the second NodeSet 3938 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes 3939 * 3940 * Merges two nodesets, all nodes from @set2 are added to @set1 3941 * if @set1 is NULL, a new set is created and copied from @set2. 3942 * Doesn't chack for duplicate nodes. Clears set2. 3943 * 3944 * Returns @set1 once extended or NULL in case of error. 3945 */ 3946 static xmlNodeSetPtr 3947 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2, 3948 int hasNullEntries) 3949 { 3950 if (set2 == NULL) 3951 return(set1); 3952 if ((set1 == NULL) && (hasNullEntries == 0)) { 3953 /* 3954 * Note that doing a memcpy of the list, namespace nodes are 3955 * just assigned to set1, since set2 is cleared anyway. 3956 */ 3957 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr); 3958 if (set1 == NULL) 3959 return(NULL); 3960 if (set2->nodeNr != 0) { 3961 memcpy(set1->nodeTab, set2->nodeTab, 3962 set2->nodeNr * sizeof(xmlNodePtr)); 3963 set1->nodeNr = set2->nodeNr; 3964 } 3965 } else { 3966 int i; 3967 xmlNodePtr n2; 3968 3969 if (set1 == NULL) 3970 set1 = xmlXPathNodeSetCreate(NULL); 3971 if (set1 == NULL) 3972 return (NULL); 3973 3974 for (i = 0;i < set2->nodeNr;i++) { 3975 n2 = set2->nodeTab[i]; 3976 /* 3977 * Skip NULLed entries. 3978 */ 3979 if (n2 == NULL) 3980 continue; 3981 if (set1->nodeMax == 0) { 3982 set1->nodeTab = (xmlNodePtr *) xmlMalloc( 3983 XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); 3984 if (set1->nodeTab == NULL) { 3985 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3986 return(NULL); 3987 } 3988 memset(set1->nodeTab, 0, 3989 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3990 set1->nodeMax = XML_NODESET_DEFAULT; 3991 } else if (set1->nodeNr >= set1->nodeMax) { 3992 xmlNodePtr *temp; 3993 3994 set1->nodeMax *= 2; 3995 temp = (xmlNodePtr *) xmlRealloc( 3996 set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr)); 3997 if (temp == NULL) { 3998 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3999 return(NULL); 4000 } 4001 set1->nodeTab = temp; 4002 } 4003 set1->nodeTab[set1->nodeNr++] = n2; 4004 } 4005 } 4006 set2->nodeNr = 0; 4007 return(set1); 4008 } 4009 4010 /** 4011 * xmlXPathNodeSetDel: 4012 * @cur: the initial node set 4013 * @val: an xmlNodePtr 4014 * 4015 * Removes an xmlNodePtr from an existing NodeSet 4016 */ 4017 void 4018 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) { 4019 int i; 4020 4021 if (cur == NULL) return; 4022 if (val == NULL) return; 4023 4024 /* 4025 * find node in nodeTab 4026 */ 4027 for (i = 0;i < cur->nodeNr;i++) 4028 if (cur->nodeTab[i] == val) break; 4029 4030 if (i >= cur->nodeNr) { /* not found */ 4031 #ifdef DEBUG 4032 xmlGenericError(xmlGenericErrorContext, 4033 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n", 4034 val->name); 4035 #endif 4036 return; 4037 } 4038 if ((cur->nodeTab[i] != NULL) && 4039 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL)) 4040 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]); 4041 cur->nodeNr--; 4042 for (;i < cur->nodeNr;i++) 4043 cur->nodeTab[i] = cur->nodeTab[i + 1]; 4044 cur->nodeTab[cur->nodeNr] = NULL; 4045 } 4046 4047 /** 4048 * xmlXPathNodeSetRemove: 4049 * @cur: the initial node set 4050 * @val: the index to remove 4051 * 4052 * Removes an entry from an existing NodeSet list. 4053 */ 4054 void 4055 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) { 4056 if (cur == NULL) return; 4057 if (val >= cur->nodeNr) return; 4058 if ((cur->nodeTab[val] != NULL) && 4059 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL)) 4060 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]); 4061 cur->nodeNr--; 4062 for (;val < cur->nodeNr;val++) 4063 cur->nodeTab[val] = cur->nodeTab[val + 1]; 4064 cur->nodeTab[cur->nodeNr] = NULL; 4065 } 4066 4067 /** 4068 * xmlXPathFreeNodeSet: 4069 * @obj: the xmlNodeSetPtr to free 4070 * 4071 * Free the NodeSet compound (not the actual nodes !). 4072 */ 4073 void 4074 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) { 4075 if (obj == NULL) return; 4076 if (obj->nodeTab != NULL) { 4077 int i; 4078 4079 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 4080 for (i = 0;i < obj->nodeNr;i++) 4081 if ((obj->nodeTab[i] != NULL) && 4082 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL)) 4083 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]); 4084 xmlFree(obj->nodeTab); 4085 } 4086 xmlFree(obj); 4087 } 4088 4089 /** 4090 * xmlXPathNodeSetClear: 4091 * @set: the node set to clear 4092 * 4093 * Clears the list from all temporary XPath objects (e.g. namespace nodes 4094 * are feed), but does *not* free the list itself. Sets the length of the 4095 * list to 0. 4096 */ 4097 static void 4098 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes) 4099 { 4100 if ((set == NULL) || (set->nodeNr <= 0)) 4101 return; 4102 else if (hasNsNodes) { 4103 int i; 4104 xmlNodePtr node; 4105 4106 for (i = 0; i < set->nodeNr; i++) { 4107 node = set->nodeTab[i]; 4108 if ((node != NULL) && 4109 (node->type == XML_NAMESPACE_DECL)) 4110 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 4111 } 4112 } 4113 set->nodeNr = 0; 4114 } 4115 4116 /** 4117 * xmlXPathNodeSetClearFromPos: 4118 * @set: the node set to be cleared 4119 * @pos: the start position to clear from 4120 * 4121 * Clears the list from temporary XPath objects (e.g. namespace nodes 4122 * are feed) starting with the entry at @pos, but does *not* free the list 4123 * itself. Sets the length of the list to @pos. 4124 */ 4125 static void 4126 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes) 4127 { 4128 if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr)) 4129 return; 4130 else if ((hasNsNodes)) { 4131 int i; 4132 xmlNodePtr node; 4133 4134 for (i = pos; i < set->nodeNr; i++) { 4135 node = set->nodeTab[i]; 4136 if ((node != NULL) && 4137 (node->type == XML_NAMESPACE_DECL)) 4138 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 4139 } 4140 } 4141 set->nodeNr = pos; 4142 } 4143 4144 /** 4145 * xmlXPathFreeValueTree: 4146 * @obj: the xmlNodeSetPtr to free 4147 * 4148 * Free the NodeSet compound and the actual tree, this is different 4149 * from xmlXPathFreeNodeSet() 4150 */ 4151 static void 4152 xmlXPathFreeValueTree(xmlNodeSetPtr obj) { 4153 int i; 4154 4155 if (obj == NULL) return; 4156 4157 if (obj->nodeTab != NULL) { 4158 for (i = 0;i < obj->nodeNr;i++) { 4159 if (obj->nodeTab[i] != NULL) { 4160 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) { 4161 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]); 4162 } else { 4163 xmlFreeNodeList(obj->nodeTab[i]); 4164 } 4165 } 4166 } 4167 xmlFree(obj->nodeTab); 4168 } 4169 xmlFree(obj); 4170 } 4171 4172 #if defined(DEBUG) || defined(DEBUG_STEP) 4173 /** 4174 * xmlGenericErrorContextNodeSet: 4175 * @output: a FILE * for the output 4176 * @obj: the xmlNodeSetPtr to display 4177 * 4178 * Quick display of a NodeSet 4179 */ 4180 void 4181 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) { 4182 int i; 4183 4184 if (output == NULL) output = xmlGenericErrorContext; 4185 if (obj == NULL) { 4186 fprintf(output, "NodeSet == NULL !\n"); 4187 return; 4188 } 4189 if (obj->nodeNr == 0) { 4190 fprintf(output, "NodeSet is empty\n"); 4191 return; 4192 } 4193 if (obj->nodeTab == NULL) { 4194 fprintf(output, " nodeTab == NULL !\n"); 4195 return; 4196 } 4197 for (i = 0; i < obj->nodeNr; i++) { 4198 if (obj->nodeTab[i] == NULL) { 4199 fprintf(output, " NULL !\n"); 4200 return; 4201 } 4202 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) || 4203 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE)) 4204 fprintf(output, " /"); 4205 else if (obj->nodeTab[i]->name == NULL) 4206 fprintf(output, " noname!"); 4207 else fprintf(output, " %s", obj->nodeTab[i]->name); 4208 } 4209 fprintf(output, "\n"); 4210 } 4211 #endif 4212 4213 /** 4214 * xmlXPathNewNodeSet: 4215 * @val: the NodePtr value 4216 * 4217 * Create a new xmlXPathObjectPtr of type NodeSet and initialize 4218 * it with the single Node @val 4219 * 4220 * Returns the newly created object. 4221 */ 4222 xmlXPathObjectPtr 4223 xmlXPathNewNodeSet(xmlNodePtr val) { 4224 xmlXPathObjectPtr ret; 4225 4226 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4227 if (ret == NULL) { 4228 xmlXPathErrMemory(NULL, "creating nodeset\n"); 4229 return(NULL); 4230 } 4231 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4232 ret->type = XPATH_NODESET; 4233 ret->boolval = 0; 4234 ret->nodesetval = xmlXPathNodeSetCreate(val); 4235 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 4236 #ifdef XP_DEBUG_OBJ_USAGE 4237 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET); 4238 #endif 4239 return(ret); 4240 } 4241 4242 /** 4243 * xmlXPathNewValueTree: 4244 * @val: the NodePtr value 4245 * 4246 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize 4247 * it with the tree root @val 4248 * 4249 * Returns the newly created object. 4250 */ 4251 xmlXPathObjectPtr 4252 xmlXPathNewValueTree(xmlNodePtr val) { 4253 xmlXPathObjectPtr ret; 4254 4255 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4256 if (ret == NULL) { 4257 xmlXPathErrMemory(NULL, "creating result value tree\n"); 4258 return(NULL); 4259 } 4260 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4261 ret->type = XPATH_XSLT_TREE; 4262 ret->boolval = 1; 4263 ret->user = (void *) val; 4264 ret->nodesetval = xmlXPathNodeSetCreate(val); 4265 #ifdef XP_DEBUG_OBJ_USAGE 4266 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE); 4267 #endif 4268 return(ret); 4269 } 4270 4271 /** 4272 * xmlXPathNewNodeSetList: 4273 * @val: an existing NodeSet 4274 * 4275 * Create a new xmlXPathObjectPtr of type NodeSet and initialize 4276 * it with the Nodeset @val 4277 * 4278 * Returns the newly created object. 4279 */ 4280 xmlXPathObjectPtr 4281 xmlXPathNewNodeSetList(xmlNodeSetPtr val) 4282 { 4283 xmlXPathObjectPtr ret; 4284 int i; 4285 4286 if (val == NULL) 4287 ret = NULL; 4288 else if (val->nodeTab == NULL) 4289 ret = xmlXPathNewNodeSet(NULL); 4290 else { 4291 ret = xmlXPathNewNodeSet(val->nodeTab[0]); 4292 if (ret) 4293 for (i = 1; i < val->nodeNr; ++i) 4294 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]); 4295 } 4296 4297 return (ret); 4298 } 4299 4300 /** 4301 * xmlXPathWrapNodeSet: 4302 * @val: the NodePtr value 4303 * 4304 * Wrap the Nodeset @val in a new xmlXPathObjectPtr 4305 * 4306 * Returns the newly created object. 4307 */ 4308 xmlXPathObjectPtr 4309 xmlXPathWrapNodeSet(xmlNodeSetPtr val) { 4310 xmlXPathObjectPtr ret; 4311 4312 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4313 if (ret == NULL) { 4314 xmlXPathErrMemory(NULL, "creating node set object\n"); 4315 return(NULL); 4316 } 4317 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4318 ret->type = XPATH_NODESET; 4319 ret->nodesetval = val; 4320 #ifdef XP_DEBUG_OBJ_USAGE 4321 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET); 4322 #endif 4323 return(ret); 4324 } 4325 4326 /** 4327 * xmlXPathFreeNodeSetList: 4328 * @obj: an existing NodeSetList object 4329 * 4330 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in 4331 * the list contrary to xmlXPathFreeObject(). 4332 */ 4333 void 4334 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) { 4335 if (obj == NULL) return; 4336 #ifdef XP_DEBUG_OBJ_USAGE 4337 xmlXPathDebugObjUsageReleased(NULL, obj->type); 4338 #endif 4339 xmlFree(obj); 4340 } 4341 4342 /** 4343 * xmlXPathDifference: 4344 * @nodes1: a node-set 4345 * @nodes2: a node-set 4346 * 4347 * Implements the EXSLT - Sets difference() function: 4348 * node-set set:difference (node-set, node-set) 4349 * 4350 * Returns the difference between the two node sets, or nodes1 if 4351 * nodes2 is empty 4352 */ 4353 xmlNodeSetPtr 4354 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4355 xmlNodeSetPtr ret; 4356 int i, l1; 4357 xmlNodePtr cur; 4358 4359 if (xmlXPathNodeSetIsEmpty(nodes2)) 4360 return(nodes1); 4361 4362 ret = xmlXPathNodeSetCreate(NULL); 4363 if (xmlXPathNodeSetIsEmpty(nodes1)) 4364 return(ret); 4365 4366 l1 = xmlXPathNodeSetGetLength(nodes1); 4367 4368 for (i = 0; i < l1; i++) { 4369 cur = xmlXPathNodeSetItem(nodes1, i); 4370 if (!xmlXPathNodeSetContains(nodes2, cur)) 4371 xmlXPathNodeSetAddUnique(ret, cur); 4372 } 4373 return(ret); 4374 } 4375 4376 /** 4377 * xmlXPathIntersection: 4378 * @nodes1: a node-set 4379 * @nodes2: a node-set 4380 * 4381 * Implements the EXSLT - Sets intersection() function: 4382 * node-set set:intersection (node-set, node-set) 4383 * 4384 * Returns a node set comprising the nodes that are within both the 4385 * node sets passed as arguments 4386 */ 4387 xmlNodeSetPtr 4388 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4389 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL); 4390 int i, l1; 4391 xmlNodePtr cur; 4392 4393 if (ret == NULL) 4394 return(ret); 4395 if (xmlXPathNodeSetIsEmpty(nodes1)) 4396 return(ret); 4397 if (xmlXPathNodeSetIsEmpty(nodes2)) 4398 return(ret); 4399 4400 l1 = xmlXPathNodeSetGetLength(nodes1); 4401 4402 for (i = 0; i < l1; i++) { 4403 cur = xmlXPathNodeSetItem(nodes1, i); 4404 if (xmlXPathNodeSetContains(nodes2, cur)) 4405 xmlXPathNodeSetAddUnique(ret, cur); 4406 } 4407 return(ret); 4408 } 4409 4410 /** 4411 * xmlXPathDistinctSorted: 4412 * @nodes: a node-set, sorted by document order 4413 * 4414 * Implements the EXSLT - Sets distinct() function: 4415 * node-set set:distinct (node-set) 4416 * 4417 * Returns a subset of the nodes contained in @nodes, or @nodes if 4418 * it is empty 4419 */ 4420 xmlNodeSetPtr 4421 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) { 4422 xmlNodeSetPtr ret; 4423 xmlHashTablePtr hash; 4424 int i, l; 4425 xmlChar * strval; 4426 xmlNodePtr cur; 4427 4428 if (xmlXPathNodeSetIsEmpty(nodes)) 4429 return(nodes); 4430 4431 ret = xmlXPathNodeSetCreate(NULL); 4432 if (ret == NULL) 4433 return(ret); 4434 l = xmlXPathNodeSetGetLength(nodes); 4435 hash = xmlHashCreate (l); 4436 for (i = 0; i < l; i++) { 4437 cur = xmlXPathNodeSetItem(nodes, i); 4438 strval = xmlXPathCastNodeToString(cur); 4439 if (xmlHashLookup(hash, strval) == NULL) { 4440 xmlHashAddEntry(hash, strval, strval); 4441 xmlXPathNodeSetAddUnique(ret, cur); 4442 } else { 4443 xmlFree(strval); 4444 } 4445 } 4446 xmlHashFree(hash, (xmlHashDeallocator) xmlFree); 4447 return(ret); 4448 } 4449 4450 /** 4451 * xmlXPathDistinct: 4452 * @nodes: a node-set 4453 * 4454 * Implements the EXSLT - Sets distinct() function: 4455 * node-set set:distinct (node-set) 4456 * @nodes is sorted by document order, then #exslSetsDistinctSorted 4457 * is called with the sorted node-set 4458 * 4459 * Returns a subset of the nodes contained in @nodes, or @nodes if 4460 * it is empty 4461 */ 4462 xmlNodeSetPtr 4463 xmlXPathDistinct (xmlNodeSetPtr nodes) { 4464 if (xmlXPathNodeSetIsEmpty(nodes)) 4465 return(nodes); 4466 4467 xmlXPathNodeSetSort(nodes); 4468 return(xmlXPathDistinctSorted(nodes)); 4469 } 4470 4471 /** 4472 * xmlXPathHasSameNodes: 4473 * @nodes1: a node-set 4474 * @nodes2: a node-set 4475 * 4476 * Implements the EXSLT - Sets has-same-nodes function: 4477 * boolean set:has-same-node(node-set, node-set) 4478 * 4479 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0) 4480 * otherwise 4481 */ 4482 int 4483 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4484 int i, l; 4485 xmlNodePtr cur; 4486 4487 if (xmlXPathNodeSetIsEmpty(nodes1) || 4488 xmlXPathNodeSetIsEmpty(nodes2)) 4489 return(0); 4490 4491 l = xmlXPathNodeSetGetLength(nodes1); 4492 for (i = 0; i < l; i++) { 4493 cur = xmlXPathNodeSetItem(nodes1, i); 4494 if (xmlXPathNodeSetContains(nodes2, cur)) 4495 return(1); 4496 } 4497 return(0); 4498 } 4499 4500 /** 4501 * xmlXPathNodeLeadingSorted: 4502 * @nodes: a node-set, sorted by document order 4503 * @node: a node 4504 * 4505 * Implements the EXSLT - Sets leading() function: 4506 * node-set set:leading (node-set, node-set) 4507 * 4508 * Returns the nodes in @nodes that precede @node in document order, 4509 * @nodes if @node is NULL or an empty node-set if @nodes 4510 * doesn't contain @node 4511 */ 4512 xmlNodeSetPtr 4513 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { 4514 int i, l; 4515 xmlNodePtr cur; 4516 xmlNodeSetPtr ret; 4517 4518 if (node == NULL) 4519 return(nodes); 4520 4521 ret = xmlXPathNodeSetCreate(NULL); 4522 if (ret == NULL) 4523 return(ret); 4524 if (xmlXPathNodeSetIsEmpty(nodes) || 4525 (!xmlXPathNodeSetContains(nodes, node))) 4526 return(ret); 4527 4528 l = xmlXPathNodeSetGetLength(nodes); 4529 for (i = 0; i < l; i++) { 4530 cur = xmlXPathNodeSetItem(nodes, i); 4531 if (cur == node) 4532 break; 4533 xmlXPathNodeSetAddUnique(ret, cur); 4534 } 4535 return(ret); 4536 } 4537 4538 /** 4539 * xmlXPathNodeLeading: 4540 * @nodes: a node-set 4541 * @node: a node 4542 * 4543 * Implements the EXSLT - Sets leading() function: 4544 * node-set set:leading (node-set, node-set) 4545 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted 4546 * is called. 4547 * 4548 * Returns the nodes in @nodes that precede @node in document order, 4549 * @nodes if @node is NULL or an empty node-set if @nodes 4550 * doesn't contain @node 4551 */ 4552 xmlNodeSetPtr 4553 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) { 4554 xmlXPathNodeSetSort(nodes); 4555 return(xmlXPathNodeLeadingSorted(nodes, node)); 4556 } 4557 4558 /** 4559 * xmlXPathLeadingSorted: 4560 * @nodes1: a node-set, sorted by document order 4561 * @nodes2: a node-set, sorted by document order 4562 * 4563 * Implements the EXSLT - Sets leading() function: 4564 * node-set set:leading (node-set, node-set) 4565 * 4566 * Returns the nodes in @nodes1 that precede the first node in @nodes2 4567 * in document order, @nodes1 if @nodes2 is NULL or empty or 4568 * an empty node-set if @nodes1 doesn't contain @nodes2 4569 */ 4570 xmlNodeSetPtr 4571 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4572 if (xmlXPathNodeSetIsEmpty(nodes2)) 4573 return(nodes1); 4574 return(xmlXPathNodeLeadingSorted(nodes1, 4575 xmlXPathNodeSetItem(nodes2, 1))); 4576 } 4577 4578 /** 4579 * xmlXPathLeading: 4580 * @nodes1: a node-set 4581 * @nodes2: a node-set 4582 * 4583 * Implements the EXSLT - Sets leading() function: 4584 * node-set set:leading (node-set, node-set) 4585 * @nodes1 and @nodes2 are sorted by document order, then 4586 * #exslSetsLeadingSorted is called. 4587 * 4588 * Returns the nodes in @nodes1 that precede the first node in @nodes2 4589 * in document order, @nodes1 if @nodes2 is NULL or empty or 4590 * an empty node-set if @nodes1 doesn't contain @nodes2 4591 */ 4592 xmlNodeSetPtr 4593 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4594 if (xmlXPathNodeSetIsEmpty(nodes2)) 4595 return(nodes1); 4596 if (xmlXPathNodeSetIsEmpty(nodes1)) 4597 return(xmlXPathNodeSetCreate(NULL)); 4598 xmlXPathNodeSetSort(nodes1); 4599 xmlXPathNodeSetSort(nodes2); 4600 return(xmlXPathNodeLeadingSorted(nodes1, 4601 xmlXPathNodeSetItem(nodes2, 1))); 4602 } 4603 4604 /** 4605 * xmlXPathNodeTrailingSorted: 4606 * @nodes: a node-set, sorted by document order 4607 * @node: a node 4608 * 4609 * Implements the EXSLT - Sets trailing() function: 4610 * node-set set:trailing (node-set, node-set) 4611 * 4612 * Returns the nodes in @nodes that follow @node in document order, 4613 * @nodes if @node is NULL or an empty node-set if @nodes 4614 * doesn't contain @node 4615 */ 4616 xmlNodeSetPtr 4617 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { 4618 int i, l; 4619 xmlNodePtr cur; 4620 xmlNodeSetPtr ret; 4621 4622 if (node == NULL) 4623 return(nodes); 4624 4625 ret = xmlXPathNodeSetCreate(NULL); 4626 if (ret == NULL) 4627 return(ret); 4628 if (xmlXPathNodeSetIsEmpty(nodes) || 4629 (!xmlXPathNodeSetContains(nodes, node))) 4630 return(ret); 4631 4632 l = xmlXPathNodeSetGetLength(nodes); 4633 for (i = l - 1; i >= 0; i--) { 4634 cur = xmlXPathNodeSetItem(nodes, i); 4635 if (cur == node) 4636 break; 4637 xmlXPathNodeSetAddUnique(ret, cur); 4638 } 4639 xmlXPathNodeSetSort(ret); /* bug 413451 */ 4640 return(ret); 4641 } 4642 4643 /** 4644 * xmlXPathNodeTrailing: 4645 * @nodes: a node-set 4646 * @node: a node 4647 * 4648 * Implements the EXSLT - Sets trailing() function: 4649 * node-set set:trailing (node-set, node-set) 4650 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted 4651 * is called. 4652 * 4653 * Returns the nodes in @nodes that follow @node in document order, 4654 * @nodes if @node is NULL or an empty node-set if @nodes 4655 * doesn't contain @node 4656 */ 4657 xmlNodeSetPtr 4658 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) { 4659 xmlXPathNodeSetSort(nodes); 4660 return(xmlXPathNodeTrailingSorted(nodes, node)); 4661 } 4662 4663 /** 4664 * xmlXPathTrailingSorted: 4665 * @nodes1: a node-set, sorted by document order 4666 * @nodes2: a node-set, sorted by document order 4667 * 4668 * Implements the EXSLT - Sets trailing() function: 4669 * node-set set:trailing (node-set, node-set) 4670 * 4671 * Returns the nodes in @nodes1 that follow the first node in @nodes2 4672 * in document order, @nodes1 if @nodes2 is NULL or empty or 4673 * an empty node-set if @nodes1 doesn't contain @nodes2 4674 */ 4675 xmlNodeSetPtr 4676 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4677 if (xmlXPathNodeSetIsEmpty(nodes2)) 4678 return(nodes1); 4679 return(xmlXPathNodeTrailingSorted(nodes1, 4680 xmlXPathNodeSetItem(nodes2, 0))); 4681 } 4682 4683 /** 4684 * xmlXPathTrailing: 4685 * @nodes1: a node-set 4686 * @nodes2: a node-set 4687 * 4688 * Implements the EXSLT - Sets trailing() function: 4689 * node-set set:trailing (node-set, node-set) 4690 * @nodes1 and @nodes2 are sorted by document order, then 4691 * #xmlXPathTrailingSorted is called. 4692 * 4693 * Returns the nodes in @nodes1 that follow the first node in @nodes2 4694 * in document order, @nodes1 if @nodes2 is NULL or empty or 4695 * an empty node-set if @nodes1 doesn't contain @nodes2 4696 */ 4697 xmlNodeSetPtr 4698 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4699 if (xmlXPathNodeSetIsEmpty(nodes2)) 4700 return(nodes1); 4701 if (xmlXPathNodeSetIsEmpty(nodes1)) 4702 return(xmlXPathNodeSetCreate(NULL)); 4703 xmlXPathNodeSetSort(nodes1); 4704 xmlXPathNodeSetSort(nodes2); 4705 return(xmlXPathNodeTrailingSorted(nodes1, 4706 xmlXPathNodeSetItem(nodes2, 0))); 4707 } 4708 4709 /************************************************************************ 4710 * * 4711 * Routines to handle extra functions * 4712 * * 4713 ************************************************************************/ 4714 4715 /** 4716 * xmlXPathRegisterFunc: 4717 * @ctxt: the XPath context 4718 * @name: the function name 4719 * @f: the function implementation or NULL 4720 * 4721 * Register a new function. If @f is NULL it unregisters the function 4722 * 4723 * Returns 0 in case of success, -1 in case of error 4724 */ 4725 int 4726 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name, 4727 xmlXPathFunction f) { 4728 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f)); 4729 } 4730 4731 /** 4732 * xmlXPathRegisterFuncNS: 4733 * @ctxt: the XPath context 4734 * @name: the function name 4735 * @ns_uri: the function namespace URI 4736 * @f: the function implementation or NULL 4737 * 4738 * Register a new function. If @f is NULL it unregisters the function 4739 * 4740 * Returns 0 in case of success, -1 in case of error 4741 */ 4742 int 4743 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name, 4744 const xmlChar *ns_uri, xmlXPathFunction f) { 4745 if (ctxt == NULL) 4746 return(-1); 4747 if (name == NULL) 4748 return(-1); 4749 4750 if (ctxt->funcHash == NULL) 4751 ctxt->funcHash = xmlHashCreate(0); 4752 if (ctxt->funcHash == NULL) 4753 return(-1); 4754 if (f == NULL) 4755 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL)); 4756 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f))); 4757 } 4758 4759 /** 4760 * xmlXPathRegisterFuncLookup: 4761 * @ctxt: the XPath context 4762 * @f: the lookup function 4763 * @funcCtxt: the lookup data 4764 * 4765 * Registers an external mechanism to do function lookup. 4766 */ 4767 void 4768 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt, 4769 xmlXPathFuncLookupFunc f, 4770 void *funcCtxt) { 4771 if (ctxt == NULL) 4772 return; 4773 ctxt->funcLookupFunc = f; 4774 ctxt->funcLookupData = funcCtxt; 4775 } 4776 4777 /** 4778 * xmlXPathFunctionLookup: 4779 * @ctxt: the XPath context 4780 * @name: the function name 4781 * 4782 * Search in the Function array of the context for the given 4783 * function. 4784 * 4785 * Returns the xmlXPathFunction or NULL if not found 4786 */ 4787 xmlXPathFunction 4788 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { 4789 if (ctxt == NULL) 4790 return (NULL); 4791 4792 if (ctxt->funcLookupFunc != NULL) { 4793 xmlXPathFunction ret; 4794 xmlXPathFuncLookupFunc f; 4795 4796 f = ctxt->funcLookupFunc; 4797 ret = f(ctxt->funcLookupData, name, NULL); 4798 if (ret != NULL) 4799 return(ret); 4800 } 4801 return(xmlXPathFunctionLookupNS(ctxt, name, NULL)); 4802 } 4803 4804 /** 4805 * xmlXPathFunctionLookupNS: 4806 * @ctxt: the XPath context 4807 * @name: the function name 4808 * @ns_uri: the function namespace URI 4809 * 4810 * Search in the Function array of the context for the given 4811 * function. 4812 * 4813 * Returns the xmlXPathFunction or NULL if not found 4814 */ 4815 xmlXPathFunction 4816 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name, 4817 const xmlChar *ns_uri) { 4818 xmlXPathFunction ret; 4819 4820 if (ctxt == NULL) 4821 return(NULL); 4822 if (name == NULL) 4823 return(NULL); 4824 4825 if (ctxt->funcLookupFunc != NULL) { 4826 xmlXPathFuncLookupFunc f; 4827 4828 f = ctxt->funcLookupFunc; 4829 ret = f(ctxt->funcLookupData, name, ns_uri); 4830 if (ret != NULL) 4831 return(ret); 4832 } 4833 4834 if (ctxt->funcHash == NULL) 4835 return(NULL); 4836 4837 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri); 4838 return(ret); 4839 } 4840 4841 /** 4842 * xmlXPathRegisteredFuncsCleanup: 4843 * @ctxt: the XPath context 4844 * 4845 * Cleanup the XPath context data associated to registered functions 4846 */ 4847 void 4848 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) { 4849 if (ctxt == NULL) 4850 return; 4851 4852 xmlHashFree(ctxt->funcHash, NULL); 4853 ctxt->funcHash = NULL; 4854 } 4855 4856 /************************************************************************ 4857 * * 4858 * Routines to handle Variables * 4859 * * 4860 ************************************************************************/ 4861 4862 /** 4863 * xmlXPathRegisterVariable: 4864 * @ctxt: the XPath context 4865 * @name: the variable name 4866 * @value: the variable value or NULL 4867 * 4868 * Register a new variable value. If @value is NULL it unregisters 4869 * the variable 4870 * 4871 * Returns 0 in case of success, -1 in case of error 4872 */ 4873 int 4874 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name, 4875 xmlXPathObjectPtr value) { 4876 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value)); 4877 } 4878 4879 /** 4880 * xmlXPathRegisterVariableNS: 4881 * @ctxt: the XPath context 4882 * @name: the variable name 4883 * @ns_uri: the variable namespace URI 4884 * @value: the variable value or NULL 4885 * 4886 * Register a new variable value. If @value is NULL it unregisters 4887 * the variable 4888 * 4889 * Returns 0 in case of success, -1 in case of error 4890 */ 4891 int 4892 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name, 4893 const xmlChar *ns_uri, 4894 xmlXPathObjectPtr value) { 4895 if (ctxt == NULL) 4896 return(-1); 4897 if (name == NULL) 4898 return(-1); 4899 4900 if (ctxt->varHash == NULL) 4901 ctxt->varHash = xmlHashCreate(0); 4902 if (ctxt->varHash == NULL) 4903 return(-1); 4904 if (value == NULL) 4905 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri, 4906 (xmlHashDeallocator)xmlXPathFreeObject)); 4907 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri, 4908 (void *) value, 4909 (xmlHashDeallocator)xmlXPathFreeObject)); 4910 } 4911 4912 /** 4913 * xmlXPathRegisterVariableLookup: 4914 * @ctxt: the XPath context 4915 * @f: the lookup function 4916 * @data: the lookup data 4917 * 4918 * register an external mechanism to do variable lookup 4919 */ 4920 void 4921 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt, 4922 xmlXPathVariableLookupFunc f, void *data) { 4923 if (ctxt == NULL) 4924 return; 4925 ctxt->varLookupFunc = f; 4926 ctxt->varLookupData = data; 4927 } 4928 4929 /** 4930 * xmlXPathVariableLookup: 4931 * @ctxt: the XPath context 4932 * @name: the variable name 4933 * 4934 * Search in the Variable array of the context for the given 4935 * variable value. 4936 * 4937 * Returns a copy of the value or NULL if not found 4938 */ 4939 xmlXPathObjectPtr 4940 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { 4941 if (ctxt == NULL) 4942 return(NULL); 4943 4944 if (ctxt->varLookupFunc != NULL) { 4945 xmlXPathObjectPtr ret; 4946 4947 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc) 4948 (ctxt->varLookupData, name, NULL); 4949 return(ret); 4950 } 4951 return(xmlXPathVariableLookupNS(ctxt, name, NULL)); 4952 } 4953 4954 /** 4955 * xmlXPathVariableLookupNS: 4956 * @ctxt: the XPath context 4957 * @name: the variable name 4958 * @ns_uri: the variable namespace URI 4959 * 4960 * Search in the Variable array of the context for the given 4961 * variable value. 4962 * 4963 * Returns the a copy of the value or NULL if not found 4964 */ 4965 xmlXPathObjectPtr 4966 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name, 4967 const xmlChar *ns_uri) { 4968 if (ctxt == NULL) 4969 return(NULL); 4970 4971 if (ctxt->varLookupFunc != NULL) { 4972 xmlXPathObjectPtr ret; 4973 4974 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc) 4975 (ctxt->varLookupData, name, ns_uri); 4976 if (ret != NULL) return(ret); 4977 } 4978 4979 if (ctxt->varHash == NULL) 4980 return(NULL); 4981 if (name == NULL) 4982 return(NULL); 4983 4984 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr) 4985 xmlHashLookup2(ctxt->varHash, name, ns_uri))); 4986 } 4987 4988 /** 4989 * xmlXPathRegisteredVariablesCleanup: 4990 * @ctxt: the XPath context 4991 * 4992 * Cleanup the XPath context data associated to registered variables 4993 */ 4994 void 4995 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) { 4996 if (ctxt == NULL) 4997 return; 4998 4999 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject); 5000 ctxt->varHash = NULL; 5001 } 5002 5003 /** 5004 * xmlXPathRegisterNs: 5005 * @ctxt: the XPath context 5006 * @prefix: the namespace prefix 5007 * @ns_uri: the namespace name 5008 * 5009 * Register a new namespace. If @ns_uri is NULL it unregisters 5010 * the namespace 5011 * 5012 * Returns 0 in case of success, -1 in case of error 5013 */ 5014 int 5015 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix, 5016 const xmlChar *ns_uri) { 5017 if (ctxt == NULL) 5018 return(-1); 5019 if (prefix == NULL) 5020 return(-1); 5021 5022 if (ctxt->nsHash == NULL) 5023 ctxt->nsHash = xmlHashCreate(10); 5024 if (ctxt->nsHash == NULL) 5025 return(-1); 5026 if (ns_uri == NULL) 5027 return(xmlHashRemoveEntry(ctxt->nsHash, prefix, 5028 (xmlHashDeallocator)xmlFree)); 5029 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri), 5030 (xmlHashDeallocator)xmlFree)); 5031 } 5032 5033 /** 5034 * xmlXPathNsLookup: 5035 * @ctxt: the XPath context 5036 * @prefix: the namespace prefix value 5037 * 5038 * Search in the namespace declaration array of the context for the given 5039 * namespace name associated to the given prefix 5040 * 5041 * Returns the value or NULL if not found 5042 */ 5043 const xmlChar * 5044 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) { 5045 if (ctxt == NULL) 5046 return(NULL); 5047 if (prefix == NULL) 5048 return(NULL); 5049 5050 #ifdef XML_XML_NAMESPACE 5051 if (xmlStrEqual(prefix, (const xmlChar *) "xml")) 5052 return(XML_XML_NAMESPACE); 5053 #endif 5054 5055 if (ctxt->namespaces != NULL) { 5056 int i; 5057 5058 for (i = 0;i < ctxt->nsNr;i++) { 5059 if ((ctxt->namespaces[i] != NULL) && 5060 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix))) 5061 return(ctxt->namespaces[i]->href); 5062 } 5063 } 5064 5065 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix)); 5066 } 5067 5068 /** 5069 * xmlXPathRegisteredNsCleanup: 5070 * @ctxt: the XPath context 5071 * 5072 * Cleanup the XPath context data associated to registered variables 5073 */ 5074 void 5075 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) { 5076 if (ctxt == NULL) 5077 return; 5078 5079 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree); 5080 ctxt->nsHash = NULL; 5081 } 5082 5083 /************************************************************************ 5084 * * 5085 * Routines to handle Values * 5086 * * 5087 ************************************************************************/ 5088 5089 /* Allocations are terrible, one needs to optimize all this !!! */ 5090 5091 /** 5092 * xmlXPathNewFloat: 5093 * @val: the double value 5094 * 5095 * Create a new xmlXPathObjectPtr of type double and of value @val 5096 * 5097 * Returns the newly created object. 5098 */ 5099 xmlXPathObjectPtr 5100 xmlXPathNewFloat(double val) { 5101 xmlXPathObjectPtr ret; 5102 5103 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5104 if (ret == NULL) { 5105 xmlXPathErrMemory(NULL, "creating float object\n"); 5106 return(NULL); 5107 } 5108 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5109 ret->type = XPATH_NUMBER; 5110 ret->floatval = val; 5111 #ifdef XP_DEBUG_OBJ_USAGE 5112 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER); 5113 #endif 5114 return(ret); 5115 } 5116 5117 /** 5118 * xmlXPathNewBoolean: 5119 * @val: the boolean value 5120 * 5121 * Create a new xmlXPathObjectPtr of type boolean and of value @val 5122 * 5123 * Returns the newly created object. 5124 */ 5125 xmlXPathObjectPtr 5126 xmlXPathNewBoolean(int val) { 5127 xmlXPathObjectPtr ret; 5128 5129 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5130 if (ret == NULL) { 5131 xmlXPathErrMemory(NULL, "creating boolean object\n"); 5132 return(NULL); 5133 } 5134 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5135 ret->type = XPATH_BOOLEAN; 5136 ret->boolval = (val != 0); 5137 #ifdef XP_DEBUG_OBJ_USAGE 5138 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN); 5139 #endif 5140 return(ret); 5141 } 5142 5143 /** 5144 * xmlXPathNewString: 5145 * @val: the xmlChar * value 5146 * 5147 * Create a new xmlXPathObjectPtr of type string and of value @val 5148 * 5149 * Returns the newly created object. 5150 */ 5151 xmlXPathObjectPtr 5152 xmlXPathNewString(const xmlChar *val) { 5153 xmlXPathObjectPtr ret; 5154 5155 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5156 if (ret == NULL) { 5157 xmlXPathErrMemory(NULL, "creating string object\n"); 5158 return(NULL); 5159 } 5160 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5161 ret->type = XPATH_STRING; 5162 if (val != NULL) 5163 ret->stringval = xmlStrdup(val); 5164 else 5165 ret->stringval = xmlStrdup((const xmlChar *)""); 5166 #ifdef XP_DEBUG_OBJ_USAGE 5167 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); 5168 #endif 5169 return(ret); 5170 } 5171 5172 /** 5173 * xmlXPathWrapString: 5174 * @val: the xmlChar * value 5175 * 5176 * Wraps the @val string into an XPath object. 5177 * 5178 * Returns the newly created object. 5179 */ 5180 xmlXPathObjectPtr 5181 xmlXPathWrapString (xmlChar *val) { 5182 xmlXPathObjectPtr ret; 5183 5184 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5185 if (ret == NULL) { 5186 xmlXPathErrMemory(NULL, "creating string object\n"); 5187 return(NULL); 5188 } 5189 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5190 ret->type = XPATH_STRING; 5191 ret->stringval = val; 5192 #ifdef XP_DEBUG_OBJ_USAGE 5193 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); 5194 #endif 5195 return(ret); 5196 } 5197 5198 /** 5199 * xmlXPathNewCString: 5200 * @val: the char * value 5201 * 5202 * Create a new xmlXPathObjectPtr of type string and of value @val 5203 * 5204 * Returns the newly created object. 5205 */ 5206 xmlXPathObjectPtr 5207 xmlXPathNewCString(const char *val) { 5208 xmlXPathObjectPtr ret; 5209 5210 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5211 if (ret == NULL) { 5212 xmlXPathErrMemory(NULL, "creating string object\n"); 5213 return(NULL); 5214 } 5215 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5216 ret->type = XPATH_STRING; 5217 ret->stringval = xmlStrdup(BAD_CAST val); 5218 #ifdef XP_DEBUG_OBJ_USAGE 5219 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); 5220 #endif 5221 return(ret); 5222 } 5223 5224 /** 5225 * xmlXPathWrapCString: 5226 * @val: the char * value 5227 * 5228 * Wraps a string into an XPath object. 5229 * 5230 * Returns the newly created object. 5231 */ 5232 xmlXPathObjectPtr 5233 xmlXPathWrapCString (char * val) { 5234 return(xmlXPathWrapString((xmlChar *)(val))); 5235 } 5236 5237 /** 5238 * xmlXPathWrapExternal: 5239 * @val: the user data 5240 * 5241 * Wraps the @val data into an XPath object. 5242 * 5243 * Returns the newly created object. 5244 */ 5245 xmlXPathObjectPtr 5246 xmlXPathWrapExternal (void *val) { 5247 xmlXPathObjectPtr ret; 5248 5249 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5250 if (ret == NULL) { 5251 xmlXPathErrMemory(NULL, "creating user object\n"); 5252 return(NULL); 5253 } 5254 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5255 ret->type = XPATH_USERS; 5256 ret->user = val; 5257 #ifdef XP_DEBUG_OBJ_USAGE 5258 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS); 5259 #endif 5260 return(ret); 5261 } 5262 5263 /** 5264 * xmlXPathObjectCopy: 5265 * @val: the original object 5266 * 5267 * allocate a new copy of a given object 5268 * 5269 * Returns the newly created object. 5270 */ 5271 xmlXPathObjectPtr 5272 xmlXPathObjectCopy(xmlXPathObjectPtr val) { 5273 xmlXPathObjectPtr ret; 5274 5275 if (val == NULL) 5276 return(NULL); 5277 5278 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5279 if (ret == NULL) { 5280 xmlXPathErrMemory(NULL, "copying object\n"); 5281 return(NULL); 5282 } 5283 memcpy(ret, val , (size_t) sizeof(xmlXPathObject)); 5284 #ifdef XP_DEBUG_OBJ_USAGE 5285 xmlXPathDebugObjUsageRequested(NULL, val->type); 5286 #endif 5287 switch (val->type) { 5288 case XPATH_BOOLEAN: 5289 case XPATH_NUMBER: 5290 case XPATH_POINT: 5291 case XPATH_RANGE: 5292 break; 5293 case XPATH_STRING: 5294 ret->stringval = xmlStrdup(val->stringval); 5295 break; 5296 case XPATH_XSLT_TREE: 5297 #if 0 5298 /* 5299 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that 5300 this previous handling is no longer correct, and can cause some serious 5301 problems (ref. bug 145547) 5302 */ 5303 if ((val->nodesetval != NULL) && 5304 (val->nodesetval->nodeTab != NULL)) { 5305 xmlNodePtr cur, tmp; 5306 xmlDocPtr top; 5307 5308 ret->boolval = 1; 5309 top = xmlNewDoc(NULL); 5310 top->name = (char *) 5311 xmlStrdup(val->nodesetval->nodeTab[0]->name); 5312 ret->user = top; 5313 if (top != NULL) { 5314 top->doc = top; 5315 cur = val->nodesetval->nodeTab[0]->children; 5316 while (cur != NULL) { 5317 tmp = xmlDocCopyNode(cur, top, 1); 5318 xmlAddChild((xmlNodePtr) top, tmp); 5319 cur = cur->next; 5320 } 5321 } 5322 5323 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top); 5324 } else 5325 ret->nodesetval = xmlXPathNodeSetCreate(NULL); 5326 /* Deallocate the copied tree value */ 5327 break; 5328 #endif 5329 case XPATH_NODESET: 5330 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval); 5331 /* Do not deallocate the copied tree value */ 5332 ret->boolval = 0; 5333 break; 5334 case XPATH_LOCATIONSET: 5335 #ifdef LIBXML_XPTR_ENABLED 5336 { 5337 xmlLocationSetPtr loc = val->user; 5338 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc); 5339 break; 5340 } 5341 #endif 5342 case XPATH_USERS: 5343 ret->user = val->user; 5344 break; 5345 case XPATH_UNDEFINED: 5346 xmlGenericError(xmlGenericErrorContext, 5347 "xmlXPathObjectCopy: unsupported type %d\n", 5348 val->type); 5349 break; 5350 } 5351 return(ret); 5352 } 5353 5354 /** 5355 * xmlXPathFreeObject: 5356 * @obj: the object to free 5357 * 5358 * Free up an xmlXPathObjectPtr object. 5359 */ 5360 void 5361 xmlXPathFreeObject(xmlXPathObjectPtr obj) { 5362 if (obj == NULL) return; 5363 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) { 5364 if (obj->boolval) { 5365 #if 0 5366 if (obj->user != NULL) { 5367 xmlXPathFreeNodeSet(obj->nodesetval); 5368 xmlFreeNodeList((xmlNodePtr) obj->user); 5369 } else 5370 #endif 5371 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */ 5372 if (obj->nodesetval != NULL) 5373 xmlXPathFreeValueTree(obj->nodesetval); 5374 } else { 5375 if (obj->nodesetval != NULL) 5376 xmlXPathFreeNodeSet(obj->nodesetval); 5377 } 5378 #ifdef LIBXML_XPTR_ENABLED 5379 } else if (obj->type == XPATH_LOCATIONSET) { 5380 if (obj->user != NULL) 5381 xmlXPtrFreeLocationSet(obj->user); 5382 #endif 5383 } else if (obj->type == XPATH_STRING) { 5384 if (obj->stringval != NULL) 5385 xmlFree(obj->stringval); 5386 } 5387 #ifdef XP_DEBUG_OBJ_USAGE 5388 xmlXPathDebugObjUsageReleased(NULL, obj->type); 5389 #endif 5390 xmlFree(obj); 5391 } 5392 5393 /** 5394 * xmlXPathReleaseObject: 5395 * @obj: the xmlXPathObjectPtr to free or to cache 5396 * 5397 * Depending on the state of the cache this frees the given 5398 * XPath object or stores it in the cache. 5399 */ 5400 static void 5401 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj) 5402 { 5403 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \ 5404 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \ 5405 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj; 5406 5407 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n)) 5408 5409 if (obj == NULL) 5410 return; 5411 if ((ctxt == NULL) || (ctxt->cache == NULL)) { 5412 xmlXPathFreeObject(obj); 5413 } else { 5414 xmlXPathContextCachePtr cache = 5415 (xmlXPathContextCachePtr) ctxt->cache; 5416 5417 switch (obj->type) { 5418 case XPATH_NODESET: 5419 case XPATH_XSLT_TREE: 5420 if (obj->nodesetval != NULL) { 5421 if (obj->boolval) { 5422 /* 5423 * It looks like the @boolval is used for 5424 * evaluation if this an XSLT Result Tree Fragment. 5425 * TODO: Check if this assumption is correct. 5426 */ 5427 obj->type = XPATH_XSLT_TREE; /* just for debugging */ 5428 xmlXPathFreeValueTree(obj->nodesetval); 5429 obj->nodesetval = NULL; 5430 } else if ((obj->nodesetval->nodeMax <= 40) && 5431 (XP_CACHE_WANTS(cache->nodesetObjs, 5432 cache->maxNodeset))) 5433 { 5434 XP_CACHE_ADD(cache->nodesetObjs, obj); 5435 goto obj_cached; 5436 } else { 5437 xmlXPathFreeNodeSet(obj->nodesetval); 5438 obj->nodesetval = NULL; 5439 } 5440 } 5441 break; 5442 case XPATH_STRING: 5443 if (obj->stringval != NULL) 5444 xmlFree(obj->stringval); 5445 5446 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) { 5447 XP_CACHE_ADD(cache->stringObjs, obj); 5448 goto obj_cached; 5449 } 5450 break; 5451 case XPATH_BOOLEAN: 5452 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) { 5453 XP_CACHE_ADD(cache->booleanObjs, obj); 5454 goto obj_cached; 5455 } 5456 break; 5457 case XPATH_NUMBER: 5458 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) { 5459 XP_CACHE_ADD(cache->numberObjs, obj); 5460 goto obj_cached; 5461 } 5462 break; 5463 #ifdef LIBXML_XPTR_ENABLED 5464 case XPATH_LOCATIONSET: 5465 if (obj->user != NULL) { 5466 xmlXPtrFreeLocationSet(obj->user); 5467 } 5468 goto free_obj; 5469 #endif 5470 default: 5471 goto free_obj; 5472 } 5473 5474 /* 5475 * Fallback to adding to the misc-objects slot. 5476 */ 5477 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) { 5478 XP_CACHE_ADD(cache->miscObjs, obj); 5479 } else 5480 goto free_obj; 5481 5482 obj_cached: 5483 5484 #ifdef XP_DEBUG_OBJ_USAGE 5485 xmlXPathDebugObjUsageReleased(ctxt, obj->type); 5486 #endif 5487 5488 if (obj->nodesetval != NULL) { 5489 xmlNodeSetPtr tmpset = obj->nodesetval; 5490 5491 /* 5492 * TODO: Due to those nasty ns-nodes, we need to traverse 5493 * the list and free the ns-nodes. 5494 * URGENT TODO: Check if it's actually slowing things down. 5495 * Maybe we shouldn't try to preserve the list. 5496 */ 5497 if (tmpset->nodeNr > 1) { 5498 int i; 5499 xmlNodePtr node; 5500 5501 for (i = 0; i < tmpset->nodeNr; i++) { 5502 node = tmpset->nodeTab[i]; 5503 if ((node != NULL) && 5504 (node->type == XML_NAMESPACE_DECL)) 5505 { 5506 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 5507 } 5508 } 5509 } else if (tmpset->nodeNr == 1) { 5510 if ((tmpset->nodeTab[0] != NULL) && 5511 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL)) 5512 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]); 5513 } 5514 tmpset->nodeNr = 0; 5515 memset(obj, 0, sizeof(xmlXPathObject)); 5516 obj->nodesetval = tmpset; 5517 } else 5518 memset(obj, 0, sizeof(xmlXPathObject)); 5519 5520 return; 5521 5522 free_obj: 5523 /* 5524 * Cache is full; free the object. 5525 */ 5526 if (obj->nodesetval != NULL) 5527 xmlXPathFreeNodeSet(obj->nodesetval); 5528 #ifdef XP_DEBUG_OBJ_USAGE 5529 xmlXPathDebugObjUsageReleased(NULL, obj->type); 5530 #endif 5531 xmlFree(obj); 5532 } 5533 return; 5534 } 5535 5536 5537 /************************************************************************ 5538 * * 5539 * Type Casting Routines * 5540 * * 5541 ************************************************************************/ 5542 5543 /** 5544 * xmlXPathCastBooleanToString: 5545 * @val: a boolean 5546 * 5547 * Converts a boolean to its string value. 5548 * 5549 * Returns a newly allocated string. 5550 */ 5551 xmlChar * 5552 xmlXPathCastBooleanToString (int val) { 5553 xmlChar *ret; 5554 if (val) 5555 ret = xmlStrdup((const xmlChar *) "true"); 5556 else 5557 ret = xmlStrdup((const xmlChar *) "false"); 5558 return(ret); 5559 } 5560 5561 /** 5562 * xmlXPathCastNumberToString: 5563 * @val: a number 5564 * 5565 * Converts a number to its string value. 5566 * 5567 * Returns a newly allocated string. 5568 */ 5569 xmlChar * 5570 xmlXPathCastNumberToString (double val) { 5571 xmlChar *ret; 5572 switch (xmlXPathIsInf(val)) { 5573 case 1: 5574 ret = xmlStrdup((const xmlChar *) "Infinity"); 5575 break; 5576 case -1: 5577 ret = xmlStrdup((const xmlChar *) "-Infinity"); 5578 break; 5579 default: 5580 if (xmlXPathIsNaN(val)) { 5581 ret = xmlStrdup((const xmlChar *) "NaN"); 5582 } else if (val == 0 && xmlXPathGetSign(val) != 0) { 5583 ret = xmlStrdup((const xmlChar *) "0"); 5584 } else { 5585 /* could be improved */ 5586 char buf[100]; 5587 xmlXPathFormatNumber(val, buf, 99); 5588 buf[99] = 0; 5589 ret = xmlStrdup((const xmlChar *) buf); 5590 } 5591 } 5592 return(ret); 5593 } 5594 5595 /** 5596 * xmlXPathCastNodeToString: 5597 * @node: a node 5598 * 5599 * Converts a node to its string value. 5600 * 5601 * Returns a newly allocated string. 5602 */ 5603 xmlChar * 5604 xmlXPathCastNodeToString (xmlNodePtr node) { 5605 xmlChar *ret; 5606 if ((ret = xmlNodeGetContent(node)) == NULL) 5607 ret = xmlStrdup((const xmlChar *) ""); 5608 return(ret); 5609 } 5610 5611 /** 5612 * xmlXPathCastNodeSetToString: 5613 * @ns: a node-set 5614 * 5615 * Converts a node-set to its string value. 5616 * 5617 * Returns a newly allocated string. 5618 */ 5619 xmlChar * 5620 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) { 5621 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL)) 5622 return(xmlStrdup((const xmlChar *) "")); 5623 5624 if (ns->nodeNr > 1) 5625 xmlXPathNodeSetSort(ns); 5626 return(xmlXPathCastNodeToString(ns->nodeTab[0])); 5627 } 5628 5629 /** 5630 * xmlXPathCastToString: 5631 * @val: an XPath object 5632 * 5633 * Converts an existing object to its string() equivalent 5634 * 5635 * Returns the allocated string value of the object, NULL in case of error. 5636 * It's up to the caller to free the string memory with xmlFree(). 5637 */ 5638 xmlChar * 5639 xmlXPathCastToString(xmlXPathObjectPtr val) { 5640 xmlChar *ret = NULL; 5641 5642 if (val == NULL) 5643 return(xmlStrdup((const xmlChar *) "")); 5644 switch (val->type) { 5645 case XPATH_UNDEFINED: 5646 #ifdef DEBUG_EXPR 5647 xmlGenericError(xmlGenericErrorContext, "String: undefined\n"); 5648 #endif 5649 ret = xmlStrdup((const xmlChar *) ""); 5650 break; 5651 case XPATH_NODESET: 5652 case XPATH_XSLT_TREE: 5653 ret = xmlXPathCastNodeSetToString(val->nodesetval); 5654 break; 5655 case XPATH_STRING: 5656 return(xmlStrdup(val->stringval)); 5657 case XPATH_BOOLEAN: 5658 ret = xmlXPathCastBooleanToString(val->boolval); 5659 break; 5660 case XPATH_NUMBER: { 5661 ret = xmlXPathCastNumberToString(val->floatval); 5662 break; 5663 } 5664 case XPATH_USERS: 5665 case XPATH_POINT: 5666 case XPATH_RANGE: 5667 case XPATH_LOCATIONSET: 5668 TODO 5669 ret = xmlStrdup((const xmlChar *) ""); 5670 break; 5671 } 5672 return(ret); 5673 } 5674 5675 /** 5676 * xmlXPathConvertString: 5677 * @val: an XPath object 5678 * 5679 * Converts an existing object to its string() equivalent 5680 * 5681 * Returns the new object, the old one is freed (or the operation 5682 * is done directly on @val) 5683 */ 5684 xmlXPathObjectPtr 5685 xmlXPathConvertString(xmlXPathObjectPtr val) { 5686 xmlChar *res = NULL; 5687 5688 if (val == NULL) 5689 return(xmlXPathNewCString("")); 5690 5691 switch (val->type) { 5692 case XPATH_UNDEFINED: 5693 #ifdef DEBUG_EXPR 5694 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n"); 5695 #endif 5696 break; 5697 case XPATH_NODESET: 5698 case XPATH_XSLT_TREE: 5699 res = xmlXPathCastNodeSetToString(val->nodesetval); 5700 break; 5701 case XPATH_STRING: 5702 return(val); 5703 case XPATH_BOOLEAN: 5704 res = xmlXPathCastBooleanToString(val->boolval); 5705 break; 5706 case XPATH_NUMBER: 5707 res = xmlXPathCastNumberToString(val->floatval); 5708 break; 5709 case XPATH_USERS: 5710 case XPATH_POINT: 5711 case XPATH_RANGE: 5712 case XPATH_LOCATIONSET: 5713 TODO; 5714 break; 5715 } 5716 xmlXPathFreeObject(val); 5717 if (res == NULL) 5718 return(xmlXPathNewCString("")); 5719 return(xmlXPathWrapString(res)); 5720 } 5721 5722 /** 5723 * xmlXPathCastBooleanToNumber: 5724 * @val: a boolean 5725 * 5726 * Converts a boolean to its number value 5727 * 5728 * Returns the number value 5729 */ 5730 double 5731 xmlXPathCastBooleanToNumber(int val) { 5732 if (val) 5733 return(1.0); 5734 return(0.0); 5735 } 5736 5737 /** 5738 * xmlXPathCastStringToNumber: 5739 * @val: a string 5740 * 5741 * Converts a string to its number value 5742 * 5743 * Returns the number value 5744 */ 5745 double 5746 xmlXPathCastStringToNumber(const xmlChar * val) { 5747 return(xmlXPathStringEvalNumber(val)); 5748 } 5749 5750 /** 5751 * xmlXPathCastNodeToNumber: 5752 * @node: a node 5753 * 5754 * Converts a node to its number value 5755 * 5756 * Returns the number value 5757 */ 5758 double 5759 xmlXPathCastNodeToNumber (xmlNodePtr node) { 5760 xmlChar *strval; 5761 double ret; 5762 5763 if (node == NULL) 5764 return(xmlXPathNAN); 5765 strval = xmlXPathCastNodeToString(node); 5766 if (strval == NULL) 5767 return(xmlXPathNAN); 5768 ret = xmlXPathCastStringToNumber(strval); 5769 xmlFree(strval); 5770 5771 return(ret); 5772 } 5773 5774 /** 5775 * xmlXPathCastNodeSetToNumber: 5776 * @ns: a node-set 5777 * 5778 * Converts a node-set to its number value 5779 * 5780 * Returns the number value 5781 */ 5782 double 5783 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) { 5784 xmlChar *str; 5785 double ret; 5786 5787 if (ns == NULL) 5788 return(xmlXPathNAN); 5789 str = xmlXPathCastNodeSetToString(ns); 5790 ret = xmlXPathCastStringToNumber(str); 5791 xmlFree(str); 5792 return(ret); 5793 } 5794 5795 /** 5796 * xmlXPathCastToNumber: 5797 * @val: an XPath object 5798 * 5799 * Converts an XPath object to its number value 5800 * 5801 * Returns the number value 5802 */ 5803 double 5804 xmlXPathCastToNumber(xmlXPathObjectPtr val) { 5805 double ret = 0.0; 5806 5807 if (val == NULL) 5808 return(xmlXPathNAN); 5809 switch (val->type) { 5810 case XPATH_UNDEFINED: 5811 #ifdef DEGUB_EXPR 5812 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n"); 5813 #endif 5814 ret = xmlXPathNAN; 5815 break; 5816 case XPATH_NODESET: 5817 case XPATH_XSLT_TREE: 5818 ret = xmlXPathCastNodeSetToNumber(val->nodesetval); 5819 break; 5820 case XPATH_STRING: 5821 ret = xmlXPathCastStringToNumber(val->stringval); 5822 break; 5823 case XPATH_NUMBER: 5824 ret = val->floatval; 5825 break; 5826 case XPATH_BOOLEAN: 5827 ret = xmlXPathCastBooleanToNumber(val->boolval); 5828 break; 5829 case XPATH_USERS: 5830 case XPATH_POINT: 5831 case XPATH_RANGE: 5832 case XPATH_LOCATIONSET: 5833 TODO; 5834 ret = xmlXPathNAN; 5835 break; 5836 } 5837 return(ret); 5838 } 5839 5840 /** 5841 * xmlXPathConvertNumber: 5842 * @val: an XPath object 5843 * 5844 * Converts an existing object to its number() equivalent 5845 * 5846 * Returns the new object, the old one is freed (or the operation 5847 * is done directly on @val) 5848 */ 5849 xmlXPathObjectPtr 5850 xmlXPathConvertNumber(xmlXPathObjectPtr val) { 5851 xmlXPathObjectPtr ret; 5852 5853 if (val == NULL) 5854 return(xmlXPathNewFloat(0.0)); 5855 if (val->type == XPATH_NUMBER) 5856 return(val); 5857 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val)); 5858 xmlXPathFreeObject(val); 5859 return(ret); 5860 } 5861 5862 /** 5863 * xmlXPathCastNumberToBoolean: 5864 * @val: a number 5865 * 5866 * Converts a number to its boolean value 5867 * 5868 * Returns the boolean value 5869 */ 5870 int 5871 xmlXPathCastNumberToBoolean (double val) { 5872 if (xmlXPathIsNaN(val) || (val == 0.0)) 5873 return(0); 5874 return(1); 5875 } 5876 5877 /** 5878 * xmlXPathCastStringToBoolean: 5879 * @val: a string 5880 * 5881 * Converts a string to its boolean value 5882 * 5883 * Returns the boolean value 5884 */ 5885 int 5886 xmlXPathCastStringToBoolean (const xmlChar *val) { 5887 if ((val == NULL) || (xmlStrlen(val) == 0)) 5888 return(0); 5889 return(1); 5890 } 5891 5892 /** 5893 * xmlXPathCastNodeSetToBoolean: 5894 * @ns: a node-set 5895 * 5896 * Converts a node-set to its boolean value 5897 * 5898 * Returns the boolean value 5899 */ 5900 int 5901 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) { 5902 if ((ns == NULL) || (ns->nodeNr == 0)) 5903 return(0); 5904 return(1); 5905 } 5906 5907 /** 5908 * xmlXPathCastToBoolean: 5909 * @val: an XPath object 5910 * 5911 * Converts an XPath object to its boolean value 5912 * 5913 * Returns the boolean value 5914 */ 5915 int 5916 xmlXPathCastToBoolean (xmlXPathObjectPtr val) { 5917 int ret = 0; 5918 5919 if (val == NULL) 5920 return(0); 5921 switch (val->type) { 5922 case XPATH_UNDEFINED: 5923 #ifdef DEBUG_EXPR 5924 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n"); 5925 #endif 5926 ret = 0; 5927 break; 5928 case XPATH_NODESET: 5929 case XPATH_XSLT_TREE: 5930 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval); 5931 break; 5932 case XPATH_STRING: 5933 ret = xmlXPathCastStringToBoolean(val->stringval); 5934 break; 5935 case XPATH_NUMBER: 5936 ret = xmlXPathCastNumberToBoolean(val->floatval); 5937 break; 5938 case XPATH_BOOLEAN: 5939 ret = val->boolval; 5940 break; 5941 case XPATH_USERS: 5942 case XPATH_POINT: 5943 case XPATH_RANGE: 5944 case XPATH_LOCATIONSET: 5945 TODO; 5946 ret = 0; 5947 break; 5948 } 5949 return(ret); 5950 } 5951 5952 5953 /** 5954 * xmlXPathConvertBoolean: 5955 * @val: an XPath object 5956 * 5957 * Converts an existing object to its boolean() equivalent 5958 * 5959 * Returns the new object, the old one is freed (or the operation 5960 * is done directly on @val) 5961 */ 5962 xmlXPathObjectPtr 5963 xmlXPathConvertBoolean(xmlXPathObjectPtr val) { 5964 xmlXPathObjectPtr ret; 5965 5966 if (val == NULL) 5967 return(xmlXPathNewBoolean(0)); 5968 if (val->type == XPATH_BOOLEAN) 5969 return(val); 5970 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val)); 5971 xmlXPathFreeObject(val); 5972 return(ret); 5973 } 5974 5975 /************************************************************************ 5976 * * 5977 * Routines to handle XPath contexts * 5978 * * 5979 ************************************************************************/ 5980 5981 /** 5982 * xmlXPathNewContext: 5983 * @doc: the XML document 5984 * 5985 * Create a new xmlXPathContext 5986 * 5987 * Returns the xmlXPathContext just allocated. The caller will need to free it. 5988 */ 5989 xmlXPathContextPtr 5990 xmlXPathNewContext(xmlDocPtr doc) { 5991 xmlXPathContextPtr ret; 5992 5993 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext)); 5994 if (ret == NULL) { 5995 xmlXPathErrMemory(NULL, "creating context\n"); 5996 return(NULL); 5997 } 5998 memset(ret, 0 , (size_t) sizeof(xmlXPathContext)); 5999 ret->doc = doc; 6000 ret->node = NULL; 6001 6002 ret->varHash = NULL; 6003 6004 ret->nb_types = 0; 6005 ret->max_types = 0; 6006 ret->types = NULL; 6007 6008 ret->funcHash = xmlHashCreate(0); 6009 6010 ret->nb_axis = 0; 6011 ret->max_axis = 0; 6012 ret->axis = NULL; 6013 6014 ret->nsHash = NULL; 6015 ret->user = NULL; 6016 6017 ret->contextSize = -1; 6018 ret->proximityPosition = -1; 6019 6020 #ifdef XP_DEFAULT_CACHE_ON 6021 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) { 6022 xmlXPathFreeContext(ret); 6023 return(NULL); 6024 } 6025 #endif 6026 6027 xmlXPathRegisterAllFunctions(ret); 6028 6029 return(ret); 6030 } 6031 6032 /** 6033 * xmlXPathFreeContext: 6034 * @ctxt: the context to free 6035 * 6036 * Free up an xmlXPathContext 6037 */ 6038 void 6039 xmlXPathFreeContext(xmlXPathContextPtr ctxt) { 6040 if (ctxt == NULL) return; 6041 6042 if (ctxt->cache != NULL) 6043 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache); 6044 xmlXPathRegisteredNsCleanup(ctxt); 6045 xmlXPathRegisteredFuncsCleanup(ctxt); 6046 xmlXPathRegisteredVariablesCleanup(ctxt); 6047 xmlResetError(&ctxt->lastError); 6048 xmlFree(ctxt); 6049 } 6050 6051 /************************************************************************ 6052 * * 6053 * Routines to handle XPath parser contexts * 6054 * * 6055 ************************************************************************/ 6056 6057 #define CHECK_CTXT(ctxt) \ 6058 if (ctxt == NULL) { \ 6059 __xmlRaiseError(NULL, NULL, NULL, \ 6060 NULL, NULL, XML_FROM_XPATH, \ 6061 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \ 6062 __FILE__, __LINE__, \ 6063 NULL, NULL, NULL, 0, 0, \ 6064 "NULL context pointer\n"); \ 6065 return(NULL); \ 6066 } \ 6067 6068 #define CHECK_CTXT_NEG(ctxt) \ 6069 if (ctxt == NULL) { \ 6070 __xmlRaiseError(NULL, NULL, NULL, \ 6071 NULL, NULL, XML_FROM_XPATH, \ 6072 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \ 6073 __FILE__, __LINE__, \ 6074 NULL, NULL, NULL, 0, 0, \ 6075 "NULL context pointer\n"); \ 6076 return(-1); \ 6077 } \ 6078 6079 6080 #define CHECK_CONTEXT(ctxt) \ 6081 if ((ctxt == NULL) || (ctxt->doc == NULL) || \ 6082 (ctxt->doc->children == NULL)) { \ 6083 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \ 6084 return(NULL); \ 6085 } 6086 6087 6088 /** 6089 * xmlXPathNewParserContext: 6090 * @str: the XPath expression 6091 * @ctxt: the XPath context 6092 * 6093 * Create a new xmlXPathParserContext 6094 * 6095 * Returns the xmlXPathParserContext just allocated. 6096 */ 6097 xmlXPathParserContextPtr 6098 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) { 6099 xmlXPathParserContextPtr ret; 6100 6101 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext)); 6102 if (ret == NULL) { 6103 xmlXPathErrMemory(ctxt, "creating parser context\n"); 6104 return(NULL); 6105 } 6106 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext)); 6107 ret->cur = ret->base = str; 6108 ret->context = ctxt; 6109 6110 ret->comp = xmlXPathNewCompExpr(); 6111 if (ret->comp == NULL) { 6112 xmlFree(ret->valueTab); 6113 xmlFree(ret); 6114 return(NULL); 6115 } 6116 if ((ctxt != NULL) && (ctxt->dict != NULL)) { 6117 ret->comp->dict = ctxt->dict; 6118 xmlDictReference(ret->comp->dict); 6119 } 6120 6121 return(ret); 6122 } 6123 6124 /** 6125 * xmlXPathCompParserContext: 6126 * @comp: the XPath compiled expression 6127 * @ctxt: the XPath context 6128 * 6129 * Create a new xmlXPathParserContext when processing a compiled expression 6130 * 6131 * Returns the xmlXPathParserContext just allocated. 6132 */ 6133 static xmlXPathParserContextPtr 6134 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) { 6135 xmlXPathParserContextPtr ret; 6136 6137 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext)); 6138 if (ret == NULL) { 6139 xmlXPathErrMemory(ctxt, "creating evaluation context\n"); 6140 return(NULL); 6141 } 6142 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext)); 6143 6144 /* Allocate the value stack */ 6145 ret->valueTab = (xmlXPathObjectPtr *) 6146 xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); 6147 if (ret->valueTab == NULL) { 6148 xmlFree(ret); 6149 xmlXPathErrMemory(ctxt, "creating evaluation context\n"); 6150 return(NULL); 6151 } 6152 ret->valueNr = 0; 6153 ret->valueMax = 10; 6154 ret->value = NULL; 6155 6156 ret->context = ctxt; 6157 ret->comp = comp; 6158 6159 return(ret); 6160 } 6161 6162 /** 6163 * xmlXPathFreeParserContext: 6164 * @ctxt: the context to free 6165 * 6166 * Free up an xmlXPathParserContext 6167 */ 6168 void 6169 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) { 6170 if (ctxt->valueTab != NULL) { 6171 xmlFree(ctxt->valueTab); 6172 } 6173 if (ctxt->comp != NULL) { 6174 #ifdef XPATH_STREAMING 6175 if (ctxt->comp->stream != NULL) { 6176 xmlFreePatternList(ctxt->comp->stream); 6177 ctxt->comp->stream = NULL; 6178 } 6179 #endif 6180 xmlXPathFreeCompExpr(ctxt->comp); 6181 } 6182 xmlFree(ctxt); 6183 } 6184 6185 /************************************************************************ 6186 * * 6187 * The implicit core function library * 6188 * * 6189 ************************************************************************/ 6190 6191 /** 6192 * xmlXPathNodeValHash: 6193 * @node: a node pointer 6194 * 6195 * Function computing the beginning of the string value of the node, 6196 * used to speed up comparisons 6197 * 6198 * Returns an int usable as a hash 6199 */ 6200 static unsigned int 6201 xmlXPathNodeValHash(xmlNodePtr node) { 6202 int len = 2; 6203 const xmlChar * string = NULL; 6204 xmlNodePtr tmp = NULL; 6205 unsigned int ret = 0; 6206 6207 if (node == NULL) 6208 return(0); 6209 6210 if (node->type == XML_DOCUMENT_NODE) { 6211 tmp = xmlDocGetRootElement((xmlDocPtr) node); 6212 if (tmp == NULL) 6213 node = node->children; 6214 else 6215 node = tmp; 6216 6217 if (node == NULL) 6218 return(0); 6219 } 6220 6221 switch (node->type) { 6222 case XML_COMMENT_NODE: 6223 case XML_PI_NODE: 6224 case XML_CDATA_SECTION_NODE: 6225 case XML_TEXT_NODE: 6226 string = node->content; 6227 if (string == NULL) 6228 return(0); 6229 if (string[0] == 0) 6230 return(0); 6231 return(((unsigned int) string[0]) + 6232 (((unsigned int) string[1]) << 8)); 6233 case XML_NAMESPACE_DECL: 6234 string = ((xmlNsPtr)node)->href; 6235 if (string == NULL) 6236 return(0); 6237 if (string[0] == 0) 6238 return(0); 6239 return(((unsigned int) string[0]) + 6240 (((unsigned int) string[1]) << 8)); 6241 case XML_ATTRIBUTE_NODE: 6242 tmp = ((xmlAttrPtr) node)->children; 6243 break; 6244 case XML_ELEMENT_NODE: 6245 tmp = node->children; 6246 break; 6247 default: 6248 return(0); 6249 } 6250 while (tmp != NULL) { 6251 switch (tmp->type) { 6252 case XML_COMMENT_NODE: 6253 case XML_PI_NODE: 6254 case XML_CDATA_SECTION_NODE: 6255 case XML_TEXT_NODE: 6256 string = tmp->content; 6257 break; 6258 case XML_NAMESPACE_DECL: 6259 string = ((xmlNsPtr)tmp)->href; 6260 break; 6261 default: 6262 break; 6263 } 6264 if ((string != NULL) && (string[0] != 0)) { 6265 if (len == 1) { 6266 return(ret + (((unsigned int) string[0]) << 8)); 6267 } 6268 if (string[1] == 0) { 6269 len = 1; 6270 ret = (unsigned int) string[0]; 6271 } else { 6272 return(((unsigned int) string[0]) + 6273 (((unsigned int) string[1]) << 8)); 6274 } 6275 } 6276 /* 6277 * Skip to next node 6278 */ 6279 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) { 6280 if (tmp->children->type != XML_ENTITY_DECL) { 6281 tmp = tmp->children; 6282 continue; 6283 } 6284 } 6285 if (tmp == node) 6286 break; 6287 6288 if (tmp->next != NULL) { 6289 tmp = tmp->next; 6290 continue; 6291 } 6292 6293 do { 6294 tmp = tmp->parent; 6295 if (tmp == NULL) 6296 break; 6297 if (tmp == node) { 6298 tmp = NULL; 6299 break; 6300 } 6301 if (tmp->next != NULL) { 6302 tmp = tmp->next; 6303 break; 6304 } 6305 } while (tmp != NULL); 6306 } 6307 return(ret); 6308 } 6309 6310 /** 6311 * xmlXPathStringHash: 6312 * @string: a string 6313 * 6314 * Function computing the beginning of the string value of the node, 6315 * used to speed up comparisons 6316 * 6317 * Returns an int usable as a hash 6318 */ 6319 static unsigned int 6320 xmlXPathStringHash(const xmlChar * string) { 6321 if (string == NULL) 6322 return((unsigned int) 0); 6323 if (string[0] == 0) 6324 return(0); 6325 return(((unsigned int) string[0]) + 6326 (((unsigned int) string[1]) << 8)); 6327 } 6328 6329 /** 6330 * xmlXPathCompareNodeSetFloat: 6331 * @ctxt: the XPath Parser context 6332 * @inf: less than (1) or greater than (0) 6333 * @strict: is the comparison strict 6334 * @arg: the node set 6335 * @f: the value 6336 * 6337 * Implement the compare operation between a nodeset and a number 6338 * @ns < @val (1, 1, ... 6339 * @ns <= @val (1, 0, ... 6340 * @ns > @val (0, 1, ... 6341 * @ns >= @val (0, 0, ... 6342 * 6343 * If one object to be compared is a node-set and the other is a number, 6344 * then the comparison will be true if and only if there is a node in the 6345 * node-set such that the result of performing the comparison on the number 6346 * to be compared and on the result of converting the string-value of that 6347 * node to a number using the number function is true. 6348 * 6349 * Returns 0 or 1 depending on the results of the test. 6350 */ 6351 static int 6352 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict, 6353 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) { 6354 int i, ret = 0; 6355 xmlNodeSetPtr ns; 6356 xmlChar *str2; 6357 6358 if ((f == NULL) || (arg == NULL) || 6359 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) { 6360 xmlXPathReleaseObject(ctxt->context, arg); 6361 xmlXPathReleaseObject(ctxt->context, f); 6362 return(0); 6363 } 6364 ns = arg->nodesetval; 6365 if (ns != NULL) { 6366 for (i = 0;i < ns->nodeNr;i++) { 6367 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 6368 if (str2 != NULL) { 6369 valuePush(ctxt, 6370 xmlXPathCacheNewString(ctxt->context, str2)); 6371 xmlFree(str2); 6372 xmlXPathNumberFunction(ctxt, 1); 6373 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f)); 6374 ret = xmlXPathCompareValues(ctxt, inf, strict); 6375 if (ret) 6376 break; 6377 } 6378 } 6379 } 6380 xmlXPathReleaseObject(ctxt->context, arg); 6381 xmlXPathReleaseObject(ctxt->context, f); 6382 return(ret); 6383 } 6384 6385 /** 6386 * xmlXPathCompareNodeSetString: 6387 * @ctxt: the XPath Parser context 6388 * @inf: less than (1) or greater than (0) 6389 * @strict: is the comparison strict 6390 * @arg: the node set 6391 * @s: the value 6392 * 6393 * Implement the compare operation between a nodeset and a string 6394 * @ns < @val (1, 1, ... 6395 * @ns <= @val (1, 0, ... 6396 * @ns > @val (0, 1, ... 6397 * @ns >= @val (0, 0, ... 6398 * 6399 * If one object to be compared is a node-set and the other is a string, 6400 * then the comparison will be true if and only if there is a node in 6401 * the node-set such that the result of performing the comparison on the 6402 * string-value of the node and the other string is true. 6403 * 6404 * Returns 0 or 1 depending on the results of the test. 6405 */ 6406 static int 6407 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict, 6408 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) { 6409 int i, ret = 0; 6410 xmlNodeSetPtr ns; 6411 xmlChar *str2; 6412 6413 if ((s == NULL) || (arg == NULL) || 6414 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) { 6415 xmlXPathReleaseObject(ctxt->context, arg); 6416 xmlXPathReleaseObject(ctxt->context, s); 6417 return(0); 6418 } 6419 ns = arg->nodesetval; 6420 if (ns != NULL) { 6421 for (i = 0;i < ns->nodeNr;i++) { 6422 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 6423 if (str2 != NULL) { 6424 valuePush(ctxt, 6425 xmlXPathCacheNewString(ctxt->context, str2)); 6426 xmlFree(str2); 6427 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s)); 6428 ret = xmlXPathCompareValues(ctxt, inf, strict); 6429 if (ret) 6430 break; 6431 } 6432 } 6433 } 6434 xmlXPathReleaseObject(ctxt->context, arg); 6435 xmlXPathReleaseObject(ctxt->context, s); 6436 return(ret); 6437 } 6438 6439 /** 6440 * xmlXPathCompareNodeSets: 6441 * @inf: less than (1) or greater than (0) 6442 * @strict: is the comparison strict 6443 * @arg1: the first node set object 6444 * @arg2: the second node set object 6445 * 6446 * Implement the compare operation on nodesets: 6447 * 6448 * If both objects to be compared are node-sets, then the comparison 6449 * will be true if and only if there is a node in the first node-set 6450 * and a node in the second node-set such that the result of performing 6451 * the comparison on the string-values of the two nodes is true. 6452 * .... 6453 * When neither object to be compared is a node-set and the operator 6454 * is <=, <, >= or >, then the objects are compared by converting both 6455 * objects to numbers and comparing the numbers according to IEEE 754. 6456 * .... 6457 * The number function converts its argument to a number as follows: 6458 * - a string that consists of optional whitespace followed by an 6459 * optional minus sign followed by a Number followed by whitespace 6460 * is converted to the IEEE 754 number that is nearest (according 6461 * to the IEEE 754 round-to-nearest rule) to the mathematical value 6462 * represented by the string; any other string is converted to NaN 6463 * 6464 * Conclusion all nodes need to be converted first to their string value 6465 * and then the comparison must be done when possible 6466 */ 6467 static int 6468 xmlXPathCompareNodeSets(int inf, int strict, 6469 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) { 6470 int i, j, init = 0; 6471 double val1; 6472 double *values2; 6473 int ret = 0; 6474 xmlNodeSetPtr ns1; 6475 xmlNodeSetPtr ns2; 6476 6477 if ((arg1 == NULL) || 6478 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) { 6479 xmlXPathFreeObject(arg2); 6480 return(0); 6481 } 6482 if ((arg2 == NULL) || 6483 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) { 6484 xmlXPathFreeObject(arg1); 6485 xmlXPathFreeObject(arg2); 6486 return(0); 6487 } 6488 6489 ns1 = arg1->nodesetval; 6490 ns2 = arg2->nodesetval; 6491 6492 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) { 6493 xmlXPathFreeObject(arg1); 6494 xmlXPathFreeObject(arg2); 6495 return(0); 6496 } 6497 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) { 6498 xmlXPathFreeObject(arg1); 6499 xmlXPathFreeObject(arg2); 6500 return(0); 6501 } 6502 6503 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double)); 6504 if (values2 == NULL) { 6505 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6506 xmlXPathFreeObject(arg1); 6507 xmlXPathFreeObject(arg2); 6508 return(0); 6509 } 6510 for (i = 0;i < ns1->nodeNr;i++) { 6511 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]); 6512 if (xmlXPathIsNaN(val1)) 6513 continue; 6514 for (j = 0;j < ns2->nodeNr;j++) { 6515 if (init == 0) { 6516 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]); 6517 } 6518 if (xmlXPathIsNaN(values2[j])) 6519 continue; 6520 if (inf && strict) 6521 ret = (val1 < values2[j]); 6522 else if (inf && !strict) 6523 ret = (val1 <= values2[j]); 6524 else if (!inf && strict) 6525 ret = (val1 > values2[j]); 6526 else if (!inf && !strict) 6527 ret = (val1 >= values2[j]); 6528 if (ret) 6529 break; 6530 } 6531 if (ret) 6532 break; 6533 init = 1; 6534 } 6535 xmlFree(values2); 6536 xmlXPathFreeObject(arg1); 6537 xmlXPathFreeObject(arg2); 6538 return(ret); 6539 } 6540 6541 /** 6542 * xmlXPathCompareNodeSetValue: 6543 * @ctxt: the XPath Parser context 6544 * @inf: less than (1) or greater than (0) 6545 * @strict: is the comparison strict 6546 * @arg: the node set 6547 * @val: the value 6548 * 6549 * Implement the compare operation between a nodeset and a value 6550 * @ns < @val (1, 1, ... 6551 * @ns <= @val (1, 0, ... 6552 * @ns > @val (0, 1, ... 6553 * @ns >= @val (0, 0, ... 6554 * 6555 * If one object to be compared is a node-set and the other is a boolean, 6556 * then the comparison will be true if and only if the result of performing 6557 * the comparison on the boolean and on the result of converting 6558 * the node-set to a boolean using the boolean function is true. 6559 * 6560 * Returns 0 or 1 depending on the results of the test. 6561 */ 6562 static int 6563 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict, 6564 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) { 6565 if ((val == NULL) || (arg == NULL) || 6566 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 6567 return(0); 6568 6569 switch(val->type) { 6570 case XPATH_NUMBER: 6571 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val)); 6572 case XPATH_NODESET: 6573 case XPATH_XSLT_TREE: 6574 return(xmlXPathCompareNodeSets(inf, strict, arg, val)); 6575 case XPATH_STRING: 6576 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val)); 6577 case XPATH_BOOLEAN: 6578 valuePush(ctxt, arg); 6579 xmlXPathBooleanFunction(ctxt, 1); 6580 valuePush(ctxt, val); 6581 return(xmlXPathCompareValues(ctxt, inf, strict)); 6582 default: 6583 TODO 6584 } 6585 return(0); 6586 } 6587 6588 /** 6589 * xmlXPathEqualNodeSetString: 6590 * @arg: the nodeset object argument 6591 * @str: the string to compare to. 6592 * @neq: flag to show whether for '=' (0) or '!=' (1) 6593 * 6594 * Implement the equal operation on XPath objects content: @arg1 == @arg2 6595 * If one object to be compared is a node-set and the other is a string, 6596 * then the comparison will be true if and only if there is a node in 6597 * the node-set such that the result of performing the comparison on the 6598 * string-value of the node and the other string is true. 6599 * 6600 * Returns 0 or 1 depending on the results of the test. 6601 */ 6602 static int 6603 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq) 6604 { 6605 int i; 6606 xmlNodeSetPtr ns; 6607 xmlChar *str2; 6608 unsigned int hash; 6609 6610 if ((str == NULL) || (arg == NULL) || 6611 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 6612 return (0); 6613 ns = arg->nodesetval; 6614 /* 6615 * A NULL nodeset compared with a string is always false 6616 * (since there is no node equal, and no node not equal) 6617 */ 6618 if ((ns == NULL) || (ns->nodeNr <= 0) ) 6619 return (0); 6620 hash = xmlXPathStringHash(str); 6621 for (i = 0; i < ns->nodeNr; i++) { 6622 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) { 6623 str2 = xmlNodeGetContent(ns->nodeTab[i]); 6624 if ((str2 != NULL) && (xmlStrEqual(str, str2))) { 6625 xmlFree(str2); 6626 if (neq) 6627 continue; 6628 return (1); 6629 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) { 6630 if (neq) 6631 continue; 6632 return (1); 6633 } else if (neq) { 6634 if (str2 != NULL) 6635 xmlFree(str2); 6636 return (1); 6637 } 6638 if (str2 != NULL) 6639 xmlFree(str2); 6640 } else if (neq) 6641 return (1); 6642 } 6643 return (0); 6644 } 6645 6646 /** 6647 * xmlXPathEqualNodeSetFloat: 6648 * @arg: the nodeset object argument 6649 * @f: the float to compare to 6650 * @neq: flag to show whether to compare '=' (0) or '!=' (1) 6651 * 6652 * Implement the equal operation on XPath objects content: @arg1 == @arg2 6653 * If one object to be compared is a node-set and the other is a number, 6654 * then the comparison will be true if and only if there is a node in 6655 * the node-set such that the result of performing the comparison on the 6656 * number to be compared and on the result of converting the string-value 6657 * of that node to a number using the number function is true. 6658 * 6659 * Returns 0 or 1 depending on the results of the test. 6660 */ 6661 static int 6662 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt, 6663 xmlXPathObjectPtr arg, double f, int neq) { 6664 int i, ret=0; 6665 xmlNodeSetPtr ns; 6666 xmlChar *str2; 6667 xmlXPathObjectPtr val; 6668 double v; 6669 6670 if ((arg == NULL) || 6671 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 6672 return(0); 6673 6674 ns = arg->nodesetval; 6675 if (ns != NULL) { 6676 for (i=0;i<ns->nodeNr;i++) { 6677 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 6678 if (str2 != NULL) { 6679 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2)); 6680 xmlFree(str2); 6681 xmlXPathNumberFunction(ctxt, 1); 6682 val = valuePop(ctxt); 6683 v = val->floatval; 6684 xmlXPathReleaseObject(ctxt->context, val); 6685 if (!xmlXPathIsNaN(v)) { 6686 if ((!neq) && (v==f)) { 6687 ret = 1; 6688 break; 6689 } else if ((neq) && (v!=f)) { 6690 ret = 1; 6691 break; 6692 } 6693 } else { /* NaN is unequal to any value */ 6694 if (neq) 6695 ret = 1; 6696 } 6697 } 6698 } 6699 } 6700 6701 return(ret); 6702 } 6703 6704 6705 /** 6706 * xmlXPathEqualNodeSets: 6707 * @arg1: first nodeset object argument 6708 * @arg2: second nodeset object argument 6709 * @neq: flag to show whether to test '=' (0) or '!=' (1) 6710 * 6711 * Implement the equal / not equal operation on XPath nodesets: 6712 * @arg1 == @arg2 or @arg1 != @arg2 6713 * If both objects to be compared are node-sets, then the comparison 6714 * will be true if and only if there is a node in the first node-set and 6715 * a node in the second node-set such that the result of performing the 6716 * comparison on the string-values of the two nodes is true. 6717 * 6718 * (needless to say, this is a costly operation) 6719 * 6720 * Returns 0 or 1 depending on the results of the test. 6721 */ 6722 static int 6723 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) { 6724 int i, j; 6725 unsigned int *hashs1; 6726 unsigned int *hashs2; 6727 xmlChar **values1; 6728 xmlChar **values2; 6729 int ret = 0; 6730 xmlNodeSetPtr ns1; 6731 xmlNodeSetPtr ns2; 6732 6733 if ((arg1 == NULL) || 6734 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) 6735 return(0); 6736 if ((arg2 == NULL) || 6737 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) 6738 return(0); 6739 6740 ns1 = arg1->nodesetval; 6741 ns2 = arg2->nodesetval; 6742 6743 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) 6744 return(0); 6745 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) 6746 return(0); 6747 6748 /* 6749 * for equal, check if there is a node pertaining to both sets 6750 */ 6751 if (neq == 0) 6752 for (i = 0;i < ns1->nodeNr;i++) 6753 for (j = 0;j < ns2->nodeNr;j++) 6754 if (ns1->nodeTab[i] == ns2->nodeTab[j]) 6755 return(1); 6756 6757 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *)); 6758 if (values1 == NULL) { 6759 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6760 return(0); 6761 } 6762 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int)); 6763 if (hashs1 == NULL) { 6764 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6765 xmlFree(values1); 6766 return(0); 6767 } 6768 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *)); 6769 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *)); 6770 if (values2 == NULL) { 6771 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6772 xmlFree(hashs1); 6773 xmlFree(values1); 6774 return(0); 6775 } 6776 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int)); 6777 if (hashs2 == NULL) { 6778 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6779 xmlFree(hashs1); 6780 xmlFree(values1); 6781 xmlFree(values2); 6782 return(0); 6783 } 6784 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *)); 6785 for (i = 0;i < ns1->nodeNr;i++) { 6786 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]); 6787 for (j = 0;j < ns2->nodeNr;j++) { 6788 if (i == 0) 6789 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]); 6790 if (hashs1[i] != hashs2[j]) { 6791 if (neq) { 6792 ret = 1; 6793 break; 6794 } 6795 } 6796 else { 6797 if (values1[i] == NULL) 6798 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]); 6799 if (values2[j] == NULL) 6800 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]); 6801 ret = xmlStrEqual(values1[i], values2[j]) ^ neq; 6802 if (ret) 6803 break; 6804 } 6805 } 6806 if (ret) 6807 break; 6808 } 6809 for (i = 0;i < ns1->nodeNr;i++) 6810 if (values1[i] != NULL) 6811 xmlFree(values1[i]); 6812 for (j = 0;j < ns2->nodeNr;j++) 6813 if (values2[j] != NULL) 6814 xmlFree(values2[j]); 6815 xmlFree(values1); 6816 xmlFree(values2); 6817 xmlFree(hashs1); 6818 xmlFree(hashs2); 6819 return(ret); 6820 } 6821 6822 static int 6823 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt, 6824 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) { 6825 int ret = 0; 6826 /* 6827 *At this point we are assured neither arg1 nor arg2 6828 *is a nodeset, so we can just pick the appropriate routine. 6829 */ 6830 switch (arg1->type) { 6831 case XPATH_UNDEFINED: 6832 #ifdef DEBUG_EXPR 6833 xmlGenericError(xmlGenericErrorContext, 6834 "Equal: undefined\n"); 6835 #endif 6836 break; 6837 case XPATH_BOOLEAN: 6838 switch (arg2->type) { 6839 case XPATH_UNDEFINED: 6840 #ifdef DEBUG_EXPR 6841 xmlGenericError(xmlGenericErrorContext, 6842 "Equal: undefined\n"); 6843 #endif 6844 break; 6845 case XPATH_BOOLEAN: 6846 #ifdef DEBUG_EXPR 6847 xmlGenericError(xmlGenericErrorContext, 6848 "Equal: %d boolean %d \n", 6849 arg1->boolval, arg2->boolval); 6850 #endif 6851 ret = (arg1->boolval == arg2->boolval); 6852 break; 6853 case XPATH_NUMBER: 6854 ret = (arg1->boolval == 6855 xmlXPathCastNumberToBoolean(arg2->floatval)); 6856 break; 6857 case XPATH_STRING: 6858 if ((arg2->stringval == NULL) || 6859 (arg2->stringval[0] == 0)) ret = 0; 6860 else 6861 ret = 1; 6862 ret = (arg1->boolval == ret); 6863 break; 6864 case XPATH_USERS: 6865 case XPATH_POINT: 6866 case XPATH_RANGE: 6867 case XPATH_LOCATIONSET: 6868 TODO 6869 break; 6870 case XPATH_NODESET: 6871 case XPATH_XSLT_TREE: 6872 break; 6873 } 6874 break; 6875 case XPATH_NUMBER: 6876 switch (arg2->type) { 6877 case XPATH_UNDEFINED: 6878 #ifdef DEBUG_EXPR 6879 xmlGenericError(xmlGenericErrorContext, 6880 "Equal: undefined\n"); 6881 #endif 6882 break; 6883 case XPATH_BOOLEAN: 6884 ret = (arg2->boolval== 6885 xmlXPathCastNumberToBoolean(arg1->floatval)); 6886 break; 6887 case XPATH_STRING: 6888 valuePush(ctxt, arg2); 6889 xmlXPathNumberFunction(ctxt, 1); 6890 arg2 = valuePop(ctxt); 6891 /* no break on purpose */ 6892 case XPATH_NUMBER: 6893 /* Hand check NaN and Infinity equalities */ 6894 if (xmlXPathIsNaN(arg1->floatval) || 6895 xmlXPathIsNaN(arg2->floatval)) { 6896 ret = 0; 6897 } else if (xmlXPathIsInf(arg1->floatval) == 1) { 6898 if (xmlXPathIsInf(arg2->floatval) == 1) 6899 ret = 1; 6900 else 6901 ret = 0; 6902 } else if (xmlXPathIsInf(arg1->floatval) == -1) { 6903 if (xmlXPathIsInf(arg2->floatval) == -1) 6904 ret = 1; 6905 else 6906 ret = 0; 6907 } else if (xmlXPathIsInf(arg2->floatval) == 1) { 6908 if (xmlXPathIsInf(arg1->floatval) == 1) 6909 ret = 1; 6910 else 6911 ret = 0; 6912 } else if (xmlXPathIsInf(arg2->floatval) == -1) { 6913 if (xmlXPathIsInf(arg1->floatval) == -1) 6914 ret = 1; 6915 else 6916 ret = 0; 6917 } else { 6918 ret = (arg1->floatval == arg2->floatval); 6919 } 6920 break; 6921 case XPATH_USERS: 6922 case XPATH_POINT: 6923 case XPATH_RANGE: 6924 case XPATH_LOCATIONSET: 6925 TODO 6926 break; 6927 case XPATH_NODESET: 6928 case XPATH_XSLT_TREE: 6929 break; 6930 } 6931 break; 6932 case XPATH_STRING: 6933 switch (arg2->type) { 6934 case XPATH_UNDEFINED: 6935 #ifdef DEBUG_EXPR 6936 xmlGenericError(xmlGenericErrorContext, 6937 "Equal: undefined\n"); 6938 #endif 6939 break; 6940 case XPATH_BOOLEAN: 6941 if ((arg1->stringval == NULL) || 6942 (arg1->stringval[0] == 0)) ret = 0; 6943 else 6944 ret = 1; 6945 ret = (arg2->boolval == ret); 6946 break; 6947 case XPATH_STRING: 6948 ret = xmlStrEqual(arg1->stringval, arg2->stringval); 6949 break; 6950 case XPATH_NUMBER: 6951 valuePush(ctxt, arg1); 6952 xmlXPathNumberFunction(ctxt, 1); 6953 arg1 = valuePop(ctxt); 6954 /* Hand check NaN and Infinity equalities */ 6955 if (xmlXPathIsNaN(arg1->floatval) || 6956 xmlXPathIsNaN(arg2->floatval)) { 6957 ret = 0; 6958 } else if (xmlXPathIsInf(arg1->floatval) == 1) { 6959 if (xmlXPathIsInf(arg2->floatval) == 1) 6960 ret = 1; 6961 else 6962 ret = 0; 6963 } else if (xmlXPathIsInf(arg1->floatval) == -1) { 6964 if (xmlXPathIsInf(arg2->floatval) == -1) 6965 ret = 1; 6966 else 6967 ret = 0; 6968 } else if (xmlXPathIsInf(arg2->floatval) == 1) { 6969 if (xmlXPathIsInf(arg1->floatval) == 1) 6970 ret = 1; 6971 else 6972 ret = 0; 6973 } else if (xmlXPathIsInf(arg2->floatval) == -1) { 6974 if (xmlXPathIsInf(arg1->floatval) == -1) 6975 ret = 1; 6976 else 6977 ret = 0; 6978 } else { 6979 ret = (arg1->floatval == arg2->floatval); 6980 } 6981 break; 6982 case XPATH_USERS: 6983 case XPATH_POINT: 6984 case XPATH_RANGE: 6985 case XPATH_LOCATIONSET: 6986 TODO 6987 break; 6988 case XPATH_NODESET: 6989 case XPATH_XSLT_TREE: 6990 break; 6991 } 6992 break; 6993 case XPATH_USERS: 6994 case XPATH_POINT: 6995 case XPATH_RANGE: 6996 case XPATH_LOCATIONSET: 6997 TODO 6998 break; 6999 case XPATH_NODESET: 7000 case XPATH_XSLT_TREE: 7001 break; 7002 } 7003 xmlXPathReleaseObject(ctxt->context, arg1); 7004 xmlXPathReleaseObject(ctxt->context, arg2); 7005 return(ret); 7006 } 7007 7008 /** 7009 * xmlXPathEqualValues: 7010 * @ctxt: the XPath Parser context 7011 * 7012 * Implement the equal operation on XPath objects content: @arg1 == @arg2 7013 * 7014 * Returns 0 or 1 depending on the results of the test. 7015 */ 7016 int 7017 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) { 7018 xmlXPathObjectPtr arg1, arg2, argtmp; 7019 int ret = 0; 7020 7021 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); 7022 arg2 = valuePop(ctxt); 7023 arg1 = valuePop(ctxt); 7024 if ((arg1 == NULL) || (arg2 == NULL)) { 7025 if (arg1 != NULL) 7026 xmlXPathReleaseObject(ctxt->context, arg1); 7027 else 7028 xmlXPathReleaseObject(ctxt->context, arg2); 7029 XP_ERROR0(XPATH_INVALID_OPERAND); 7030 } 7031 7032 if (arg1 == arg2) { 7033 #ifdef DEBUG_EXPR 7034 xmlGenericError(xmlGenericErrorContext, 7035 "Equal: by pointer\n"); 7036 #endif 7037 xmlXPathFreeObject(arg1); 7038 return(1); 7039 } 7040 7041 /* 7042 *If either argument is a nodeset, it's a 'special case' 7043 */ 7044 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 7045 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7046 /* 7047 *Hack it to assure arg1 is the nodeset 7048 */ 7049 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) { 7050 argtmp = arg2; 7051 arg2 = arg1; 7052 arg1 = argtmp; 7053 } 7054 switch (arg2->type) { 7055 case XPATH_UNDEFINED: 7056 #ifdef DEBUG_EXPR 7057 xmlGenericError(xmlGenericErrorContext, 7058 "Equal: undefined\n"); 7059 #endif 7060 break; 7061 case XPATH_NODESET: 7062 case XPATH_XSLT_TREE: 7063 ret = xmlXPathEqualNodeSets(arg1, arg2, 0); 7064 break; 7065 case XPATH_BOOLEAN: 7066 if ((arg1->nodesetval == NULL) || 7067 (arg1->nodesetval->nodeNr == 0)) ret = 0; 7068 else 7069 ret = 1; 7070 ret = (ret == arg2->boolval); 7071 break; 7072 case XPATH_NUMBER: 7073 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0); 7074 break; 7075 case XPATH_STRING: 7076 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0); 7077 break; 7078 case XPATH_USERS: 7079 case XPATH_POINT: 7080 case XPATH_RANGE: 7081 case XPATH_LOCATIONSET: 7082 TODO 7083 break; 7084 } 7085 xmlXPathReleaseObject(ctxt->context, arg1); 7086 xmlXPathReleaseObject(ctxt->context, arg2); 7087 return(ret); 7088 } 7089 7090 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2)); 7091 } 7092 7093 /** 7094 * xmlXPathNotEqualValues: 7095 * @ctxt: the XPath Parser context 7096 * 7097 * Implement the equal operation on XPath objects content: @arg1 == @arg2 7098 * 7099 * Returns 0 or 1 depending on the results of the test. 7100 */ 7101 int 7102 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) { 7103 xmlXPathObjectPtr arg1, arg2, argtmp; 7104 int ret = 0; 7105 7106 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); 7107 arg2 = valuePop(ctxt); 7108 arg1 = valuePop(ctxt); 7109 if ((arg1 == NULL) || (arg2 == NULL)) { 7110 if (arg1 != NULL) 7111 xmlXPathReleaseObject(ctxt->context, arg1); 7112 else 7113 xmlXPathReleaseObject(ctxt->context, arg2); 7114 XP_ERROR0(XPATH_INVALID_OPERAND); 7115 } 7116 7117 if (arg1 == arg2) { 7118 #ifdef DEBUG_EXPR 7119 xmlGenericError(xmlGenericErrorContext, 7120 "NotEqual: by pointer\n"); 7121 #endif 7122 xmlXPathReleaseObject(ctxt->context, arg1); 7123 return(0); 7124 } 7125 7126 /* 7127 *If either argument is a nodeset, it's a 'special case' 7128 */ 7129 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 7130 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7131 /* 7132 *Hack it to assure arg1 is the nodeset 7133 */ 7134 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) { 7135 argtmp = arg2; 7136 arg2 = arg1; 7137 arg1 = argtmp; 7138 } 7139 switch (arg2->type) { 7140 case XPATH_UNDEFINED: 7141 #ifdef DEBUG_EXPR 7142 xmlGenericError(xmlGenericErrorContext, 7143 "NotEqual: undefined\n"); 7144 #endif 7145 break; 7146 case XPATH_NODESET: 7147 case XPATH_XSLT_TREE: 7148 ret = xmlXPathEqualNodeSets(arg1, arg2, 1); 7149 break; 7150 case XPATH_BOOLEAN: 7151 if ((arg1->nodesetval == NULL) || 7152 (arg1->nodesetval->nodeNr == 0)) ret = 0; 7153 else 7154 ret = 1; 7155 ret = (ret != arg2->boolval); 7156 break; 7157 case XPATH_NUMBER: 7158 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1); 7159 break; 7160 case XPATH_STRING: 7161 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1); 7162 break; 7163 case XPATH_USERS: 7164 case XPATH_POINT: 7165 case XPATH_RANGE: 7166 case XPATH_LOCATIONSET: 7167 TODO 7168 break; 7169 } 7170 xmlXPathReleaseObject(ctxt->context, arg1); 7171 xmlXPathReleaseObject(ctxt->context, arg2); 7172 return(ret); 7173 } 7174 7175 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2)); 7176 } 7177 7178 /** 7179 * xmlXPathCompareValues: 7180 * @ctxt: the XPath Parser context 7181 * @inf: less than (1) or greater than (0) 7182 * @strict: is the comparison strict 7183 * 7184 * Implement the compare operation on XPath objects: 7185 * @arg1 < @arg2 (1, 1, ... 7186 * @arg1 <= @arg2 (1, 0, ... 7187 * @arg1 > @arg2 (0, 1, ... 7188 * @arg1 >= @arg2 (0, 0, ... 7189 * 7190 * When neither object to be compared is a node-set and the operator is 7191 * <=, <, >=, >, then the objects are compared by converted both objects 7192 * to numbers and comparing the numbers according to IEEE 754. The < 7193 * comparison will be true if and only if the first number is less than the 7194 * second number. The <= comparison will be true if and only if the first 7195 * number is less than or equal to the second number. The > comparison 7196 * will be true if and only if the first number is greater than the second 7197 * number. The >= comparison will be true if and only if the first number 7198 * is greater than or equal to the second number. 7199 * 7200 * Returns 1 if the comparison succeeded, 0 if it failed 7201 */ 7202 int 7203 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) { 7204 int ret = 0, arg1i = 0, arg2i = 0; 7205 xmlXPathObjectPtr arg1, arg2; 7206 7207 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); 7208 arg2 = valuePop(ctxt); 7209 arg1 = valuePop(ctxt); 7210 if ((arg1 == NULL) || (arg2 == NULL)) { 7211 if (arg1 != NULL) 7212 xmlXPathReleaseObject(ctxt->context, arg1); 7213 else 7214 xmlXPathReleaseObject(ctxt->context, arg2); 7215 XP_ERROR0(XPATH_INVALID_OPERAND); 7216 } 7217 7218 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 7219 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7220 /* 7221 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments 7222 * are not freed from within this routine; they will be freed from the 7223 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue 7224 */ 7225 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) && 7226 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){ 7227 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2); 7228 } else { 7229 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7230 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict, 7231 arg1, arg2); 7232 } else { 7233 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict, 7234 arg2, arg1); 7235 } 7236 } 7237 return(ret); 7238 } 7239 7240 if (arg1->type != XPATH_NUMBER) { 7241 valuePush(ctxt, arg1); 7242 xmlXPathNumberFunction(ctxt, 1); 7243 arg1 = valuePop(ctxt); 7244 } 7245 if (arg1->type != XPATH_NUMBER) { 7246 xmlXPathFreeObject(arg1); 7247 xmlXPathFreeObject(arg2); 7248 XP_ERROR0(XPATH_INVALID_OPERAND); 7249 } 7250 if (arg2->type != XPATH_NUMBER) { 7251 valuePush(ctxt, arg2); 7252 xmlXPathNumberFunction(ctxt, 1); 7253 arg2 = valuePop(ctxt); 7254 } 7255 if (arg2->type != XPATH_NUMBER) { 7256 xmlXPathReleaseObject(ctxt->context, arg1); 7257 xmlXPathReleaseObject(ctxt->context, arg2); 7258 XP_ERROR0(XPATH_INVALID_OPERAND); 7259 } 7260 /* 7261 * Add tests for infinity and nan 7262 * => feedback on 3.4 for Inf and NaN 7263 */ 7264 /* Hand check NaN and Infinity comparisons */ 7265 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) { 7266 ret=0; 7267 } else { 7268 arg1i=xmlXPathIsInf(arg1->floatval); 7269 arg2i=xmlXPathIsInf(arg2->floatval); 7270 if (inf && strict) { 7271 if ((arg1i == -1 && arg2i != -1) || 7272 (arg2i == 1 && arg1i != 1)) { 7273 ret = 1; 7274 } else if (arg1i == 0 && arg2i == 0) { 7275 ret = (arg1->floatval < arg2->floatval); 7276 } else { 7277 ret = 0; 7278 } 7279 } 7280 else if (inf && !strict) { 7281 if (arg1i == -1 || arg2i == 1) { 7282 ret = 1; 7283 } else if (arg1i == 0 && arg2i == 0) { 7284 ret = (arg1->floatval <= arg2->floatval); 7285 } else { 7286 ret = 0; 7287 } 7288 } 7289 else if (!inf && strict) { 7290 if ((arg1i == 1 && arg2i != 1) || 7291 (arg2i == -1 && arg1i != -1)) { 7292 ret = 1; 7293 } else if (arg1i == 0 && arg2i == 0) { 7294 ret = (arg1->floatval > arg2->floatval); 7295 } else { 7296 ret = 0; 7297 } 7298 } 7299 else if (!inf && !strict) { 7300 if (arg1i == 1 || arg2i == -1) { 7301 ret = 1; 7302 } else if (arg1i == 0 && arg2i == 0) { 7303 ret = (arg1->floatval >= arg2->floatval); 7304 } else { 7305 ret = 0; 7306 } 7307 } 7308 } 7309 xmlXPathReleaseObject(ctxt->context, arg1); 7310 xmlXPathReleaseObject(ctxt->context, arg2); 7311 return(ret); 7312 } 7313 7314 /** 7315 * xmlXPathValueFlipSign: 7316 * @ctxt: the XPath Parser context 7317 * 7318 * Implement the unary - operation on an XPath object 7319 * The numeric operators convert their operands to numbers as if 7320 * by calling the number function. 7321 */ 7322 void 7323 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) { 7324 if ((ctxt == NULL) || (ctxt->context == NULL)) return; 7325 CAST_TO_NUMBER; 7326 CHECK_TYPE(XPATH_NUMBER); 7327 if (xmlXPathIsNaN(ctxt->value->floatval)) 7328 ctxt->value->floatval=xmlXPathNAN; 7329 else if (xmlXPathIsInf(ctxt->value->floatval) == 1) 7330 ctxt->value->floatval=xmlXPathNINF; 7331 else if (xmlXPathIsInf(ctxt->value->floatval) == -1) 7332 ctxt->value->floatval=xmlXPathPINF; 7333 else if (ctxt->value->floatval == 0) { 7334 if (xmlXPathGetSign(ctxt->value->floatval) == 0) 7335 ctxt->value->floatval = xmlXPathNZERO; 7336 else 7337 ctxt->value->floatval = 0; 7338 } 7339 else 7340 ctxt->value->floatval = - ctxt->value->floatval; 7341 } 7342 7343 /** 7344 * xmlXPathAddValues: 7345 * @ctxt: the XPath Parser context 7346 * 7347 * Implement the add operation on XPath objects: 7348 * The numeric operators convert their operands to numbers as if 7349 * by calling the number function. 7350 */ 7351 void 7352 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) { 7353 xmlXPathObjectPtr arg; 7354 double val; 7355 7356 arg = valuePop(ctxt); 7357 if (arg == NULL) 7358 XP_ERROR(XPATH_INVALID_OPERAND); 7359 val = xmlXPathCastToNumber(arg); 7360 xmlXPathReleaseObject(ctxt->context, arg); 7361 CAST_TO_NUMBER; 7362 CHECK_TYPE(XPATH_NUMBER); 7363 ctxt->value->floatval += val; 7364 } 7365 7366 /** 7367 * xmlXPathSubValues: 7368 * @ctxt: the XPath Parser context 7369 * 7370 * Implement the subtraction operation on XPath objects: 7371 * The numeric operators convert their operands to numbers as if 7372 * by calling the number function. 7373 */ 7374 void 7375 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) { 7376 xmlXPathObjectPtr arg; 7377 double val; 7378 7379 arg = valuePop(ctxt); 7380 if (arg == NULL) 7381 XP_ERROR(XPATH_INVALID_OPERAND); 7382 val = xmlXPathCastToNumber(arg); 7383 xmlXPathReleaseObject(ctxt->context, arg); 7384 CAST_TO_NUMBER; 7385 CHECK_TYPE(XPATH_NUMBER); 7386 ctxt->value->floatval -= val; 7387 } 7388 7389 /** 7390 * xmlXPathMultValues: 7391 * @ctxt: the XPath Parser context 7392 * 7393 * Implement the multiply operation on XPath objects: 7394 * The numeric operators convert their operands to numbers as if 7395 * by calling the number function. 7396 */ 7397 void 7398 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) { 7399 xmlXPathObjectPtr arg; 7400 double val; 7401 7402 arg = valuePop(ctxt); 7403 if (arg == NULL) 7404 XP_ERROR(XPATH_INVALID_OPERAND); 7405 val = xmlXPathCastToNumber(arg); 7406 xmlXPathReleaseObject(ctxt->context, arg); 7407 CAST_TO_NUMBER; 7408 CHECK_TYPE(XPATH_NUMBER); 7409 ctxt->value->floatval *= val; 7410 } 7411 7412 /** 7413 * xmlXPathDivValues: 7414 * @ctxt: the XPath Parser context 7415 * 7416 * Implement the div operation on XPath objects @arg1 / @arg2: 7417 * The numeric operators convert their operands to numbers as if 7418 * by calling the number function. 7419 */ 7420 void 7421 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) { 7422 xmlXPathObjectPtr arg; 7423 double val; 7424 7425 arg = valuePop(ctxt); 7426 if (arg == NULL) 7427 XP_ERROR(XPATH_INVALID_OPERAND); 7428 val = xmlXPathCastToNumber(arg); 7429 xmlXPathReleaseObject(ctxt->context, arg); 7430 CAST_TO_NUMBER; 7431 CHECK_TYPE(XPATH_NUMBER); 7432 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval)) 7433 ctxt->value->floatval = xmlXPathNAN; 7434 else if (val == 0 && xmlXPathGetSign(val) != 0) { 7435 if (ctxt->value->floatval == 0) 7436 ctxt->value->floatval = xmlXPathNAN; 7437 else if (ctxt->value->floatval > 0) 7438 ctxt->value->floatval = xmlXPathNINF; 7439 else if (ctxt->value->floatval < 0) 7440 ctxt->value->floatval = xmlXPathPINF; 7441 } 7442 else if (val == 0) { 7443 if (ctxt->value->floatval == 0) 7444 ctxt->value->floatval = xmlXPathNAN; 7445 else if (ctxt->value->floatval > 0) 7446 ctxt->value->floatval = xmlXPathPINF; 7447 else if (ctxt->value->floatval < 0) 7448 ctxt->value->floatval = xmlXPathNINF; 7449 } else 7450 ctxt->value->floatval /= val; 7451 } 7452 7453 /** 7454 * xmlXPathModValues: 7455 * @ctxt: the XPath Parser context 7456 * 7457 * Implement the mod operation on XPath objects: @arg1 / @arg2 7458 * The numeric operators convert their operands to numbers as if 7459 * by calling the number function. 7460 */ 7461 void 7462 xmlXPathModValues(xmlXPathParserContextPtr ctxt) { 7463 xmlXPathObjectPtr arg; 7464 double arg1, arg2; 7465 7466 arg = valuePop(ctxt); 7467 if (arg == NULL) 7468 XP_ERROR(XPATH_INVALID_OPERAND); 7469 arg2 = xmlXPathCastToNumber(arg); 7470 xmlXPathReleaseObject(ctxt->context, arg); 7471 CAST_TO_NUMBER; 7472 CHECK_TYPE(XPATH_NUMBER); 7473 arg1 = ctxt->value->floatval; 7474 if (arg2 == 0) 7475 ctxt->value->floatval = xmlXPathNAN; 7476 else { 7477 ctxt->value->floatval = fmod(arg1, arg2); 7478 } 7479 } 7480 7481 /************************************************************************ 7482 * * 7483 * The traversal functions * 7484 * * 7485 ************************************************************************/ 7486 7487 /* 7488 * A traversal function enumerates nodes along an axis. 7489 * Initially it must be called with NULL, and it indicates 7490 * termination on the axis by returning NULL. 7491 */ 7492 typedef xmlNodePtr (*xmlXPathTraversalFunction) 7493 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur); 7494 7495 /* 7496 * xmlXPathTraversalFunctionExt: 7497 * A traversal function enumerates nodes along an axis. 7498 * Initially it must be called with NULL, and it indicates 7499 * termination on the axis by returning NULL. 7500 * The context node of the traversal is specified via @contextNode. 7501 */ 7502 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt) 7503 (xmlNodePtr cur, xmlNodePtr contextNode); 7504 7505 /* 7506 * xmlXPathNodeSetMergeFunction: 7507 * Used for merging node sets in xmlXPathCollectAndTest(). 7508 */ 7509 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction) 7510 (xmlNodeSetPtr, xmlNodeSetPtr, int); 7511 7512 7513 /** 7514 * xmlXPathNextSelf: 7515 * @ctxt: the XPath Parser context 7516 * @cur: the current node in the traversal 7517 * 7518 * Traversal function for the "self" direction 7519 * The self axis contains just the context node itself 7520 * 7521 * Returns the next element following that axis 7522 */ 7523 xmlNodePtr 7524 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7525 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7526 if (cur == NULL) 7527 return(ctxt->context->node); 7528 return(NULL); 7529 } 7530 7531 /** 7532 * xmlXPathNextChild: 7533 * @ctxt: the XPath Parser context 7534 * @cur: the current node in the traversal 7535 * 7536 * Traversal function for the "child" direction 7537 * The child axis contains the children of the context node in document order. 7538 * 7539 * Returns the next element following that axis 7540 */ 7541 xmlNodePtr 7542 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7543 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7544 if (cur == NULL) { 7545 if (ctxt->context->node == NULL) return(NULL); 7546 switch (ctxt->context->node->type) { 7547 case XML_ELEMENT_NODE: 7548 case XML_TEXT_NODE: 7549 case XML_CDATA_SECTION_NODE: 7550 case XML_ENTITY_REF_NODE: 7551 case XML_ENTITY_NODE: 7552 case XML_PI_NODE: 7553 case XML_COMMENT_NODE: 7554 case XML_NOTATION_NODE: 7555 case XML_DTD_NODE: 7556 return(ctxt->context->node->children); 7557 case XML_DOCUMENT_NODE: 7558 case XML_DOCUMENT_TYPE_NODE: 7559 case XML_DOCUMENT_FRAG_NODE: 7560 case XML_HTML_DOCUMENT_NODE: 7561 #ifdef LIBXML_DOCB_ENABLED 7562 case XML_DOCB_DOCUMENT_NODE: 7563 #endif 7564 return(((xmlDocPtr) ctxt->context->node)->children); 7565 case XML_ELEMENT_DECL: 7566 case XML_ATTRIBUTE_DECL: 7567 case XML_ENTITY_DECL: 7568 case XML_ATTRIBUTE_NODE: 7569 case XML_NAMESPACE_DECL: 7570 case XML_XINCLUDE_START: 7571 case XML_XINCLUDE_END: 7572 return(NULL); 7573 } 7574 return(NULL); 7575 } 7576 if ((cur->type == XML_DOCUMENT_NODE) || 7577 (cur->type == XML_HTML_DOCUMENT_NODE)) 7578 return(NULL); 7579 return(cur->next); 7580 } 7581 7582 /** 7583 * xmlXPathNextChildElement: 7584 * @ctxt: the XPath Parser context 7585 * @cur: the current node in the traversal 7586 * 7587 * Traversal function for the "child" direction and nodes of type element. 7588 * The child axis contains the children of the context node in document order. 7589 * 7590 * Returns the next element following that axis 7591 */ 7592 static xmlNodePtr 7593 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7594 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7595 if (cur == NULL) { 7596 cur = ctxt->context->node; 7597 if (cur == NULL) return(NULL); 7598 /* 7599 * Get the first element child. 7600 */ 7601 switch (cur->type) { 7602 case XML_ELEMENT_NODE: 7603 case XML_DOCUMENT_FRAG_NODE: 7604 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */ 7605 case XML_ENTITY_NODE: 7606 cur = cur->children; 7607 if (cur != NULL) { 7608 if (cur->type == XML_ELEMENT_NODE) 7609 return(cur); 7610 do { 7611 cur = cur->next; 7612 } while ((cur != NULL) && 7613 (cur->type != XML_ELEMENT_NODE)); 7614 return(cur); 7615 } 7616 return(NULL); 7617 case XML_DOCUMENT_NODE: 7618 case XML_HTML_DOCUMENT_NODE: 7619 #ifdef LIBXML_DOCB_ENABLED 7620 case XML_DOCB_DOCUMENT_NODE: 7621 #endif 7622 return(xmlDocGetRootElement((xmlDocPtr) cur)); 7623 default: 7624 return(NULL); 7625 } 7626 return(NULL); 7627 } 7628 /* 7629 * Get the next sibling element node. 7630 */ 7631 switch (cur->type) { 7632 case XML_ELEMENT_NODE: 7633 case XML_TEXT_NODE: 7634 case XML_ENTITY_REF_NODE: 7635 case XML_ENTITY_NODE: 7636 case XML_CDATA_SECTION_NODE: 7637 case XML_PI_NODE: 7638 case XML_COMMENT_NODE: 7639 case XML_XINCLUDE_END: 7640 break; 7641 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */ 7642 default: 7643 return(NULL); 7644 } 7645 if (cur->next != NULL) { 7646 if (cur->next->type == XML_ELEMENT_NODE) 7647 return(cur->next); 7648 cur = cur->next; 7649 do { 7650 cur = cur->next; 7651 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE)); 7652 return(cur); 7653 } 7654 return(NULL); 7655 } 7656 7657 /** 7658 * xmlXPathNextDescendantOrSelfElemParent: 7659 * @ctxt: the XPath Parser context 7660 * @cur: the current node in the traversal 7661 * 7662 * Traversal function for the "descendant-or-self" axis. 7663 * Additionally it returns only nodes which can be parents of 7664 * element nodes. 7665 * 7666 * 7667 * Returns the next element following that axis 7668 */ 7669 static xmlNodePtr 7670 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur, 7671 xmlNodePtr contextNode) 7672 { 7673 if (cur == NULL) { 7674 if (contextNode == NULL) 7675 return(NULL); 7676 switch (contextNode->type) { 7677 case XML_ELEMENT_NODE: 7678 case XML_XINCLUDE_START: 7679 case XML_DOCUMENT_FRAG_NODE: 7680 case XML_DOCUMENT_NODE: 7681 #ifdef LIBXML_DOCB_ENABLED 7682 case XML_DOCB_DOCUMENT_NODE: 7683 #endif 7684 case XML_HTML_DOCUMENT_NODE: 7685 return(contextNode); 7686 default: 7687 return(NULL); 7688 } 7689 return(NULL); 7690 } else { 7691 xmlNodePtr start = cur; 7692 7693 while (cur != NULL) { 7694 switch (cur->type) { 7695 case XML_ELEMENT_NODE: 7696 /* TODO: OK to have XInclude here? */ 7697 case XML_XINCLUDE_START: 7698 case XML_DOCUMENT_FRAG_NODE: 7699 if (cur != start) 7700 return(cur); 7701 if (cur->children != NULL) { 7702 cur = cur->children; 7703 continue; 7704 } 7705 break; 7706 /* Not sure if we need those here. */ 7707 case XML_DOCUMENT_NODE: 7708 #ifdef LIBXML_DOCB_ENABLED 7709 case XML_DOCB_DOCUMENT_NODE: 7710 #endif 7711 case XML_HTML_DOCUMENT_NODE: 7712 if (cur != start) 7713 return(cur); 7714 return(xmlDocGetRootElement((xmlDocPtr) cur)); 7715 default: 7716 break; 7717 } 7718 7719 next_sibling: 7720 if ((cur == NULL) || (cur == contextNode)) 7721 return(NULL); 7722 if (cur->next != NULL) { 7723 cur = cur->next; 7724 } else { 7725 cur = cur->parent; 7726 goto next_sibling; 7727 } 7728 } 7729 } 7730 return(NULL); 7731 } 7732 7733 /** 7734 * xmlXPathNextDescendant: 7735 * @ctxt: the XPath Parser context 7736 * @cur: the current node in the traversal 7737 * 7738 * Traversal function for the "descendant" direction 7739 * the descendant axis contains the descendants of the context node in document 7740 * order; a descendant is a child or a child of a child and so on. 7741 * 7742 * Returns the next element following that axis 7743 */ 7744 xmlNodePtr 7745 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7746 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7747 if (cur == NULL) { 7748 if (ctxt->context->node == NULL) 7749 return(NULL); 7750 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 7751 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 7752 return(NULL); 7753 7754 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc) 7755 return(ctxt->context->doc->children); 7756 return(ctxt->context->node->children); 7757 } 7758 7759 if (cur->children != NULL) { 7760 /* 7761 * Do not descend on entities declarations 7762 */ 7763 if (cur->children->type != XML_ENTITY_DECL) { 7764 cur = cur->children; 7765 /* 7766 * Skip DTDs 7767 */ 7768 if (cur->type != XML_DTD_NODE) 7769 return(cur); 7770 } 7771 } 7772 7773 if (cur == ctxt->context->node) return(NULL); 7774 7775 while (cur->next != NULL) { 7776 cur = cur->next; 7777 if ((cur->type != XML_ENTITY_DECL) && 7778 (cur->type != XML_DTD_NODE)) 7779 return(cur); 7780 } 7781 7782 do { 7783 cur = cur->parent; 7784 if (cur == NULL) break; 7785 if (cur == ctxt->context->node) return(NULL); 7786 if (cur->next != NULL) { 7787 cur = cur->next; 7788 return(cur); 7789 } 7790 } while (cur != NULL); 7791 return(cur); 7792 } 7793 7794 /** 7795 * xmlXPathNextDescendantOrSelf: 7796 * @ctxt: the XPath Parser context 7797 * @cur: the current node in the traversal 7798 * 7799 * Traversal function for the "descendant-or-self" direction 7800 * the descendant-or-self axis contains the context node and the descendants 7801 * of the context node in document order; thus the context node is the first 7802 * node on the axis, and the first child of the context node is the second node 7803 * on the axis 7804 * 7805 * Returns the next element following that axis 7806 */ 7807 xmlNodePtr 7808 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7809 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7810 if (cur == NULL) { 7811 if (ctxt->context->node == NULL) 7812 return(NULL); 7813 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 7814 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 7815 return(NULL); 7816 return(ctxt->context->node); 7817 } 7818 7819 return(xmlXPathNextDescendant(ctxt, cur)); 7820 } 7821 7822 /** 7823 * xmlXPathNextParent: 7824 * @ctxt: the XPath Parser context 7825 * @cur: the current node in the traversal 7826 * 7827 * Traversal function for the "parent" direction 7828 * The parent axis contains the parent of the context node, if there is one. 7829 * 7830 * Returns the next element following that axis 7831 */ 7832 xmlNodePtr 7833 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7834 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7835 /* 7836 * the parent of an attribute or namespace node is the element 7837 * to which the attribute or namespace node is attached 7838 * Namespace handling !!! 7839 */ 7840 if (cur == NULL) { 7841 if (ctxt->context->node == NULL) return(NULL); 7842 switch (ctxt->context->node->type) { 7843 case XML_ELEMENT_NODE: 7844 case XML_TEXT_NODE: 7845 case XML_CDATA_SECTION_NODE: 7846 case XML_ENTITY_REF_NODE: 7847 case XML_ENTITY_NODE: 7848 case XML_PI_NODE: 7849 case XML_COMMENT_NODE: 7850 case XML_NOTATION_NODE: 7851 case XML_DTD_NODE: 7852 case XML_ELEMENT_DECL: 7853 case XML_ATTRIBUTE_DECL: 7854 case XML_XINCLUDE_START: 7855 case XML_XINCLUDE_END: 7856 case XML_ENTITY_DECL: 7857 if (ctxt->context->node->parent == NULL) 7858 return((xmlNodePtr) ctxt->context->doc); 7859 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) && 7860 ((ctxt->context->node->parent->name[0] == ' ') || 7861 (xmlStrEqual(ctxt->context->node->parent->name, 7862 BAD_CAST "fake node libxslt")))) 7863 return(NULL); 7864 return(ctxt->context->node->parent); 7865 case XML_ATTRIBUTE_NODE: { 7866 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node; 7867 7868 return(att->parent); 7869 } 7870 case XML_DOCUMENT_NODE: 7871 case XML_DOCUMENT_TYPE_NODE: 7872 case XML_DOCUMENT_FRAG_NODE: 7873 case XML_HTML_DOCUMENT_NODE: 7874 #ifdef LIBXML_DOCB_ENABLED 7875 case XML_DOCB_DOCUMENT_NODE: 7876 #endif 7877 return(NULL); 7878 case XML_NAMESPACE_DECL: { 7879 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; 7880 7881 if ((ns->next != NULL) && 7882 (ns->next->type != XML_NAMESPACE_DECL)) 7883 return((xmlNodePtr) ns->next); 7884 return(NULL); 7885 } 7886 } 7887 } 7888 return(NULL); 7889 } 7890 7891 /** 7892 * xmlXPathNextAncestor: 7893 * @ctxt: the XPath Parser context 7894 * @cur: the current node in the traversal 7895 * 7896 * Traversal function for the "ancestor" direction 7897 * the ancestor axis contains the ancestors of the context node; the ancestors 7898 * of the context node consist of the parent of context node and the parent's 7899 * parent and so on; the nodes are ordered in reverse document order; thus the 7900 * parent is the first node on the axis, and the parent's parent is the second 7901 * node on the axis 7902 * 7903 * Returns the next element following that axis 7904 */ 7905 xmlNodePtr 7906 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7907 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7908 /* 7909 * the parent of an attribute or namespace node is the element 7910 * to which the attribute or namespace node is attached 7911 * !!!!!!!!!!!!! 7912 */ 7913 if (cur == NULL) { 7914 if (ctxt->context->node == NULL) return(NULL); 7915 switch (ctxt->context->node->type) { 7916 case XML_ELEMENT_NODE: 7917 case XML_TEXT_NODE: 7918 case XML_CDATA_SECTION_NODE: 7919 case XML_ENTITY_REF_NODE: 7920 case XML_ENTITY_NODE: 7921 case XML_PI_NODE: 7922 case XML_COMMENT_NODE: 7923 case XML_DTD_NODE: 7924 case XML_ELEMENT_DECL: 7925 case XML_ATTRIBUTE_DECL: 7926 case XML_ENTITY_DECL: 7927 case XML_NOTATION_NODE: 7928 case XML_XINCLUDE_START: 7929 case XML_XINCLUDE_END: 7930 if (ctxt->context->node->parent == NULL) 7931 return((xmlNodePtr) ctxt->context->doc); 7932 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) && 7933 ((ctxt->context->node->parent->name[0] == ' ') || 7934 (xmlStrEqual(ctxt->context->node->parent->name, 7935 BAD_CAST "fake node libxslt")))) 7936 return(NULL); 7937 return(ctxt->context->node->parent); 7938 case XML_ATTRIBUTE_NODE: { 7939 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node; 7940 7941 return(tmp->parent); 7942 } 7943 case XML_DOCUMENT_NODE: 7944 case XML_DOCUMENT_TYPE_NODE: 7945 case XML_DOCUMENT_FRAG_NODE: 7946 case XML_HTML_DOCUMENT_NODE: 7947 #ifdef LIBXML_DOCB_ENABLED 7948 case XML_DOCB_DOCUMENT_NODE: 7949 #endif 7950 return(NULL); 7951 case XML_NAMESPACE_DECL: { 7952 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; 7953 7954 if ((ns->next != NULL) && 7955 (ns->next->type != XML_NAMESPACE_DECL)) 7956 return((xmlNodePtr) ns->next); 7957 /* Bad, how did that namespace end up here ? */ 7958 return(NULL); 7959 } 7960 } 7961 return(NULL); 7962 } 7963 if (cur == ctxt->context->doc->children) 7964 return((xmlNodePtr) ctxt->context->doc); 7965 if (cur == (xmlNodePtr) ctxt->context->doc) 7966 return(NULL); 7967 switch (cur->type) { 7968 case XML_ELEMENT_NODE: 7969 case XML_TEXT_NODE: 7970 case XML_CDATA_SECTION_NODE: 7971 case XML_ENTITY_REF_NODE: 7972 case XML_ENTITY_NODE: 7973 case XML_PI_NODE: 7974 case XML_COMMENT_NODE: 7975 case XML_NOTATION_NODE: 7976 case XML_DTD_NODE: 7977 case XML_ELEMENT_DECL: 7978 case XML_ATTRIBUTE_DECL: 7979 case XML_ENTITY_DECL: 7980 case XML_XINCLUDE_START: 7981 case XML_XINCLUDE_END: 7982 if (cur->parent == NULL) 7983 return(NULL); 7984 if ((cur->parent->type == XML_ELEMENT_NODE) && 7985 ((cur->parent->name[0] == ' ') || 7986 (xmlStrEqual(cur->parent->name, 7987 BAD_CAST "fake node libxslt")))) 7988 return(NULL); 7989 return(cur->parent); 7990 case XML_ATTRIBUTE_NODE: { 7991 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node; 7992 7993 return(att->parent); 7994 } 7995 case XML_NAMESPACE_DECL: { 7996 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; 7997 7998 if ((ns->next != NULL) && 7999 (ns->next->type != XML_NAMESPACE_DECL)) 8000 return((xmlNodePtr) ns->next); 8001 /* Bad, how did that namespace end up here ? */ 8002 return(NULL); 8003 } 8004 case XML_DOCUMENT_NODE: 8005 case XML_DOCUMENT_TYPE_NODE: 8006 case XML_DOCUMENT_FRAG_NODE: 8007 case XML_HTML_DOCUMENT_NODE: 8008 #ifdef LIBXML_DOCB_ENABLED 8009 case XML_DOCB_DOCUMENT_NODE: 8010 #endif 8011 return(NULL); 8012 } 8013 return(NULL); 8014 } 8015 8016 /** 8017 * xmlXPathNextAncestorOrSelf: 8018 * @ctxt: the XPath Parser context 8019 * @cur: the current node in the traversal 8020 * 8021 * Traversal function for the "ancestor-or-self" direction 8022 * he ancestor-or-self axis contains the context node and ancestors of 8023 * the context node in reverse document order; thus the context node is 8024 * the first node on the axis, and the context node's parent the second; 8025 * parent here is defined the same as with the parent axis. 8026 * 8027 * Returns the next element following that axis 8028 */ 8029 xmlNodePtr 8030 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8031 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8032 if (cur == NULL) 8033 return(ctxt->context->node); 8034 return(xmlXPathNextAncestor(ctxt, cur)); 8035 } 8036 8037 /** 8038 * xmlXPathNextFollowingSibling: 8039 * @ctxt: the XPath Parser context 8040 * @cur: the current node in the traversal 8041 * 8042 * Traversal function for the "following-sibling" direction 8043 * The following-sibling axis contains the following siblings of the context 8044 * node in document order. 8045 * 8046 * Returns the next element following that axis 8047 */ 8048 xmlNodePtr 8049 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8050 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8051 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 8052 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 8053 return(NULL); 8054 if (cur == (xmlNodePtr) ctxt->context->doc) 8055 return(NULL); 8056 if (cur == NULL) 8057 return(ctxt->context->node->next); 8058 return(cur->next); 8059 } 8060 8061 /** 8062 * xmlXPathNextPrecedingSibling: 8063 * @ctxt: the XPath Parser context 8064 * @cur: the current node in the traversal 8065 * 8066 * Traversal function for the "preceding-sibling" direction 8067 * The preceding-sibling axis contains the preceding siblings of the context 8068 * node in reverse document order; the first preceding sibling is first on the 8069 * axis; the sibling preceding that node is the second on the axis and so on. 8070 * 8071 * Returns the next element following that axis 8072 */ 8073 xmlNodePtr 8074 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8075 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8076 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 8077 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 8078 return(NULL); 8079 if (cur == (xmlNodePtr) ctxt->context->doc) 8080 return(NULL); 8081 if (cur == NULL) 8082 return(ctxt->context->node->prev); 8083 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) { 8084 cur = cur->prev; 8085 if (cur == NULL) 8086 return(ctxt->context->node->prev); 8087 } 8088 return(cur->prev); 8089 } 8090 8091 /** 8092 * xmlXPathNextFollowing: 8093 * @ctxt: the XPath Parser context 8094 * @cur: the current node in the traversal 8095 * 8096 * Traversal function for the "following" direction 8097 * The following axis contains all nodes in the same document as the context 8098 * node that are after the context node in document order, excluding any 8099 * descendants and excluding attribute nodes and namespace nodes; the nodes 8100 * are ordered in document order 8101 * 8102 * Returns the next element following that axis 8103 */ 8104 xmlNodePtr 8105 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8106 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8107 if (cur != NULL && cur->children != NULL) 8108 return cur->children ; 8109 if (cur == NULL) cur = ctxt->context->node; 8110 if (cur == NULL) return(NULL) ; /* ERROR */ 8111 if (cur->next != NULL) return(cur->next) ; 8112 do { 8113 cur = cur->parent; 8114 if (cur == NULL) break; 8115 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL); 8116 if (cur->next != NULL) return(cur->next); 8117 } while (cur != NULL); 8118 return(cur); 8119 } 8120 8121 /* 8122 * xmlXPathIsAncestor: 8123 * @ancestor: the ancestor node 8124 * @node: the current node 8125 * 8126 * Check that @ancestor is a @node's ancestor 8127 * 8128 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise. 8129 */ 8130 static int 8131 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) { 8132 if ((ancestor == NULL) || (node == NULL)) return(0); 8133 /* nodes need to be in the same document */ 8134 if (ancestor->doc != node->doc) return(0); 8135 /* avoid searching if ancestor or node is the root node */ 8136 if (ancestor == (xmlNodePtr) node->doc) return(1); 8137 if (node == (xmlNodePtr) ancestor->doc) return(0); 8138 while (node->parent != NULL) { 8139 if (node->parent == ancestor) 8140 return(1); 8141 node = node->parent; 8142 } 8143 return(0); 8144 } 8145 8146 /** 8147 * xmlXPathNextPreceding: 8148 * @ctxt: the XPath Parser context 8149 * @cur: the current node in the traversal 8150 * 8151 * Traversal function for the "preceding" direction 8152 * the preceding axis contains all nodes in the same document as the context 8153 * node that are before the context node in document order, excluding any 8154 * ancestors and excluding attribute nodes and namespace nodes; the nodes are 8155 * ordered in reverse document order 8156 * 8157 * Returns the next element following that axis 8158 */ 8159 xmlNodePtr 8160 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) 8161 { 8162 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8163 if (cur == NULL) 8164 cur = ctxt->context->node; 8165 if (cur == NULL) 8166 return (NULL); 8167 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) 8168 cur = cur->prev; 8169 do { 8170 if (cur->prev != NULL) { 8171 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ; 8172 return (cur); 8173 } 8174 8175 cur = cur->parent; 8176 if (cur == NULL) 8177 return (NULL); 8178 if (cur == ctxt->context->doc->children) 8179 return (NULL); 8180 } while (xmlXPathIsAncestor(cur, ctxt->context->node)); 8181 return (cur); 8182 } 8183 8184 /** 8185 * xmlXPathNextPrecedingInternal: 8186 * @ctxt: the XPath Parser context 8187 * @cur: the current node in the traversal 8188 * 8189 * Traversal function for the "preceding" direction 8190 * the preceding axis contains all nodes in the same document as the context 8191 * node that are before the context node in document order, excluding any 8192 * ancestors and excluding attribute nodes and namespace nodes; the nodes are 8193 * ordered in reverse document order 8194 * This is a faster implementation but internal only since it requires a 8195 * state kept in the parser context: ctxt->ancestor. 8196 * 8197 * Returns the next element following that axis 8198 */ 8199 static xmlNodePtr 8200 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt, 8201 xmlNodePtr cur) 8202 { 8203 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8204 if (cur == NULL) { 8205 cur = ctxt->context->node; 8206 if (cur == NULL) 8207 return (NULL); 8208 if (cur->type == XML_NAMESPACE_DECL) 8209 cur = (xmlNodePtr)((xmlNsPtr)cur)->next; 8210 ctxt->ancestor = cur->parent; 8211 } 8212 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) 8213 cur = cur->prev; 8214 while (cur->prev == NULL) { 8215 cur = cur->parent; 8216 if (cur == NULL) 8217 return (NULL); 8218 if (cur == ctxt->context->doc->children) 8219 return (NULL); 8220 if (cur != ctxt->ancestor) 8221 return (cur); 8222 ctxt->ancestor = cur->parent; 8223 } 8224 cur = cur->prev; 8225 while (cur->last != NULL) 8226 cur = cur->last; 8227 return (cur); 8228 } 8229 8230 /** 8231 * xmlXPathNextNamespace: 8232 * @ctxt: the XPath Parser context 8233 * @cur: the current attribute in the traversal 8234 * 8235 * Traversal function for the "namespace" direction 8236 * the namespace axis contains the namespace nodes of the context node; 8237 * the order of nodes on this axis is implementation-defined; the axis will 8238 * be empty unless the context node is an element 8239 * 8240 * We keep the XML namespace node at the end of the list. 8241 * 8242 * Returns the next element following that axis 8243 */ 8244 xmlNodePtr 8245 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8246 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8247 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL); 8248 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) { 8249 if (ctxt->context->tmpNsList != NULL) 8250 xmlFree(ctxt->context->tmpNsList); 8251 ctxt->context->tmpNsList = 8252 xmlGetNsList(ctxt->context->doc, ctxt->context->node); 8253 ctxt->context->tmpNsNr = 0; 8254 if (ctxt->context->tmpNsList != NULL) { 8255 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) { 8256 ctxt->context->tmpNsNr++; 8257 } 8258 } 8259 return((xmlNodePtr) xmlXPathXMLNamespace); 8260 } 8261 if (ctxt->context->tmpNsNr > 0) { 8262 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr]; 8263 } else { 8264 if (ctxt->context->tmpNsList != NULL) 8265 xmlFree(ctxt->context->tmpNsList); 8266 ctxt->context->tmpNsList = NULL; 8267 return(NULL); 8268 } 8269 } 8270 8271 /** 8272 * xmlXPathNextAttribute: 8273 * @ctxt: the XPath Parser context 8274 * @cur: the current attribute in the traversal 8275 * 8276 * Traversal function for the "attribute" direction 8277 * TODO: support DTD inherited default attributes 8278 * 8279 * Returns the next element following that axis 8280 */ 8281 xmlNodePtr 8282 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8283 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8284 if (ctxt->context->node == NULL) 8285 return(NULL); 8286 if (ctxt->context->node->type != XML_ELEMENT_NODE) 8287 return(NULL); 8288 if (cur == NULL) { 8289 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc) 8290 return(NULL); 8291 return((xmlNodePtr)ctxt->context->node->properties); 8292 } 8293 return((xmlNodePtr)cur->next); 8294 } 8295 8296 /************************************************************************ 8297 * * 8298 * NodeTest Functions * 8299 * * 8300 ************************************************************************/ 8301 8302 #define IS_FUNCTION 200 8303 8304 8305 /************************************************************************ 8306 * * 8307 * Implicit tree core function library * 8308 * * 8309 ************************************************************************/ 8310 8311 /** 8312 * xmlXPathRoot: 8313 * @ctxt: the XPath Parser context 8314 * 8315 * Initialize the context to the root of the document 8316 */ 8317 void 8318 xmlXPathRoot(xmlXPathParserContextPtr ctxt) { 8319 if ((ctxt == NULL) || (ctxt->context == NULL)) 8320 return; 8321 ctxt->context->node = (xmlNodePtr) ctxt->context->doc; 8322 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8323 ctxt->context->node)); 8324 } 8325 8326 /************************************************************************ 8327 * * 8328 * The explicit core function library * 8329 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib * 8330 * * 8331 ************************************************************************/ 8332 8333 8334 /** 8335 * xmlXPathLastFunction: 8336 * @ctxt: the XPath Parser context 8337 * @nargs: the number of arguments 8338 * 8339 * Implement the last() XPath function 8340 * number last() 8341 * The last function returns the number of nodes in the context node list. 8342 */ 8343 void 8344 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8345 CHECK_ARITY(0); 8346 if (ctxt->context->contextSize >= 0) { 8347 valuePush(ctxt, 8348 xmlXPathCacheNewFloat(ctxt->context, 8349 (double) ctxt->context->contextSize)); 8350 #ifdef DEBUG_EXPR 8351 xmlGenericError(xmlGenericErrorContext, 8352 "last() : %d\n", ctxt->context->contextSize); 8353 #endif 8354 } else { 8355 XP_ERROR(XPATH_INVALID_CTXT_SIZE); 8356 } 8357 } 8358 8359 /** 8360 * xmlXPathPositionFunction: 8361 * @ctxt: the XPath Parser context 8362 * @nargs: the number of arguments 8363 * 8364 * Implement the position() XPath function 8365 * number position() 8366 * The position function returns the position of the context node in the 8367 * context node list. The first position is 1, and so the last position 8368 * will be equal to last(). 8369 */ 8370 void 8371 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8372 CHECK_ARITY(0); 8373 if (ctxt->context->proximityPosition >= 0) { 8374 valuePush(ctxt, 8375 xmlXPathCacheNewFloat(ctxt->context, 8376 (double) ctxt->context->proximityPosition)); 8377 #ifdef DEBUG_EXPR 8378 xmlGenericError(xmlGenericErrorContext, "position() : %d\n", 8379 ctxt->context->proximityPosition); 8380 #endif 8381 } else { 8382 XP_ERROR(XPATH_INVALID_CTXT_POSITION); 8383 } 8384 } 8385 8386 /** 8387 * xmlXPathCountFunction: 8388 * @ctxt: the XPath Parser context 8389 * @nargs: the number of arguments 8390 * 8391 * Implement the count() XPath function 8392 * number count(node-set) 8393 */ 8394 void 8395 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8396 xmlXPathObjectPtr cur; 8397 8398 CHECK_ARITY(1); 8399 if ((ctxt->value == NULL) || 8400 ((ctxt->value->type != XPATH_NODESET) && 8401 (ctxt->value->type != XPATH_XSLT_TREE))) 8402 XP_ERROR(XPATH_INVALID_TYPE); 8403 cur = valuePop(ctxt); 8404 8405 if ((cur == NULL) || (cur->nodesetval == NULL)) 8406 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0)); 8407 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) { 8408 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 8409 (double) cur->nodesetval->nodeNr)); 8410 } else { 8411 if ((cur->nodesetval->nodeNr != 1) || 8412 (cur->nodesetval->nodeTab == NULL)) { 8413 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0)); 8414 } else { 8415 xmlNodePtr tmp; 8416 int i = 0; 8417 8418 tmp = cur->nodesetval->nodeTab[0]; 8419 if (tmp != NULL) { 8420 tmp = tmp->children; 8421 while (tmp != NULL) { 8422 tmp = tmp->next; 8423 i++; 8424 } 8425 } 8426 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i)); 8427 } 8428 } 8429 xmlXPathReleaseObject(ctxt->context, cur); 8430 } 8431 8432 /** 8433 * xmlXPathGetElementsByIds: 8434 * @doc: the document 8435 * @ids: a whitespace separated list of IDs 8436 * 8437 * Selects elements by their unique ID. 8438 * 8439 * Returns a node-set of selected elements. 8440 */ 8441 static xmlNodeSetPtr 8442 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) { 8443 xmlNodeSetPtr ret; 8444 const xmlChar *cur = ids; 8445 xmlChar *ID; 8446 xmlAttrPtr attr; 8447 xmlNodePtr elem = NULL; 8448 8449 if (ids == NULL) return(NULL); 8450 8451 ret = xmlXPathNodeSetCreate(NULL); 8452 if (ret == NULL) 8453 return(ret); 8454 8455 while (IS_BLANK_CH(*cur)) cur++; 8456 while (*cur != 0) { 8457 while ((!IS_BLANK_CH(*cur)) && (*cur != 0)) 8458 cur++; 8459 8460 ID = xmlStrndup(ids, cur - ids); 8461 if (ID != NULL) { 8462 /* 8463 * We used to check the fact that the value passed 8464 * was an NCName, but this generated much troubles for 8465 * me and Aleksey Sanin, people blatantly violated that 8466 * constaint, like Visa3D spec. 8467 * if (xmlValidateNCName(ID, 1) == 0) 8468 */ 8469 attr = xmlGetID(doc, ID); 8470 if (attr != NULL) { 8471 if (attr->type == XML_ATTRIBUTE_NODE) 8472 elem = attr->parent; 8473 else if (attr->type == XML_ELEMENT_NODE) 8474 elem = (xmlNodePtr) attr; 8475 else 8476 elem = NULL; 8477 if (elem != NULL) 8478 xmlXPathNodeSetAdd(ret, elem); 8479 } 8480 xmlFree(ID); 8481 } 8482 8483 while (IS_BLANK_CH(*cur)) cur++; 8484 ids = cur; 8485 } 8486 return(ret); 8487 } 8488 8489 /** 8490 * xmlXPathIdFunction: 8491 * @ctxt: the XPath Parser context 8492 * @nargs: the number of arguments 8493 * 8494 * Implement the id() XPath function 8495 * node-set id(object) 8496 * The id function selects elements by their unique ID 8497 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set, 8498 * then the result is the union of the result of applying id to the 8499 * string value of each of the nodes in the argument node-set. When the 8500 * argument to id is of any other type, the argument is converted to a 8501 * string as if by a call to the string function; the string is split 8502 * into a whitespace-separated list of tokens (whitespace is any sequence 8503 * of characters matching the production S); the result is a node-set 8504 * containing the elements in the same document as the context node that 8505 * have a unique ID equal to any of the tokens in the list. 8506 */ 8507 void 8508 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8509 xmlChar *tokens; 8510 xmlNodeSetPtr ret; 8511 xmlXPathObjectPtr obj; 8512 8513 CHECK_ARITY(1); 8514 obj = valuePop(ctxt); 8515 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 8516 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) { 8517 xmlNodeSetPtr ns; 8518 int i; 8519 8520 ret = xmlXPathNodeSetCreate(NULL); 8521 /* 8522 * FIXME -- in an out-of-memory condition this will behave badly. 8523 * The solution is not clear -- we already popped an item from 8524 * ctxt, so the object is in a corrupt state. 8525 */ 8526 8527 if (obj->nodesetval != NULL) { 8528 for (i = 0; i < obj->nodesetval->nodeNr; i++) { 8529 tokens = 8530 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]); 8531 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens); 8532 ret = xmlXPathNodeSetMerge(ret, ns); 8533 xmlXPathFreeNodeSet(ns); 8534 if (tokens != NULL) 8535 xmlFree(tokens); 8536 } 8537 } 8538 xmlXPathReleaseObject(ctxt->context, obj); 8539 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret)); 8540 return; 8541 } 8542 obj = xmlXPathCacheConvertString(ctxt->context, obj); 8543 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval); 8544 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret)); 8545 xmlXPathReleaseObject(ctxt->context, obj); 8546 return; 8547 } 8548 8549 /** 8550 * xmlXPathLocalNameFunction: 8551 * @ctxt: the XPath Parser context 8552 * @nargs: the number of arguments 8553 * 8554 * Implement the local-name() XPath function 8555 * string local-name(node-set?) 8556 * The local-name function returns a string containing the local part 8557 * of the name of the node in the argument node-set that is first in 8558 * document order. If the node-set is empty or the first node has no 8559 * name, an empty string is returned. If the argument is omitted it 8560 * defaults to the context node. 8561 */ 8562 void 8563 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8564 xmlXPathObjectPtr cur; 8565 8566 if (ctxt == NULL) return; 8567 8568 if (nargs == 0) { 8569 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8570 ctxt->context->node)); 8571 nargs = 1; 8572 } 8573 8574 CHECK_ARITY(1); 8575 if ((ctxt->value == NULL) || 8576 ((ctxt->value->type != XPATH_NODESET) && 8577 (ctxt->value->type != XPATH_XSLT_TREE))) 8578 XP_ERROR(XPATH_INVALID_TYPE); 8579 cur = valuePop(ctxt); 8580 8581 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 8582 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8583 } else { 8584 int i = 0; /* Should be first in document order !!!!! */ 8585 switch (cur->nodesetval->nodeTab[i]->type) { 8586 case XML_ELEMENT_NODE: 8587 case XML_ATTRIBUTE_NODE: 8588 case XML_PI_NODE: 8589 if (cur->nodesetval->nodeTab[i]->name[0] == ' ') 8590 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8591 else 8592 valuePush(ctxt, 8593 xmlXPathCacheNewString(ctxt->context, 8594 cur->nodesetval->nodeTab[i]->name)); 8595 break; 8596 case XML_NAMESPACE_DECL: 8597 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 8598 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix)); 8599 break; 8600 default: 8601 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8602 } 8603 } 8604 xmlXPathReleaseObject(ctxt->context, cur); 8605 } 8606 8607 /** 8608 * xmlXPathNamespaceURIFunction: 8609 * @ctxt: the XPath Parser context 8610 * @nargs: the number of arguments 8611 * 8612 * Implement the namespace-uri() XPath function 8613 * string namespace-uri(node-set?) 8614 * The namespace-uri function returns a string containing the 8615 * namespace URI of the expanded name of the node in the argument 8616 * node-set that is first in document order. If the node-set is empty, 8617 * the first node has no name, or the expanded name has no namespace 8618 * URI, an empty string is returned. If the argument is omitted it 8619 * defaults to the context node. 8620 */ 8621 void 8622 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8623 xmlXPathObjectPtr cur; 8624 8625 if (ctxt == NULL) return; 8626 8627 if (nargs == 0) { 8628 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8629 ctxt->context->node)); 8630 nargs = 1; 8631 } 8632 CHECK_ARITY(1); 8633 if ((ctxt->value == NULL) || 8634 ((ctxt->value->type != XPATH_NODESET) && 8635 (ctxt->value->type != XPATH_XSLT_TREE))) 8636 XP_ERROR(XPATH_INVALID_TYPE); 8637 cur = valuePop(ctxt); 8638 8639 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 8640 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8641 } else { 8642 int i = 0; /* Should be first in document order !!!!! */ 8643 switch (cur->nodesetval->nodeTab[i]->type) { 8644 case XML_ELEMENT_NODE: 8645 case XML_ATTRIBUTE_NODE: 8646 if (cur->nodesetval->nodeTab[i]->ns == NULL) 8647 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8648 else 8649 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 8650 cur->nodesetval->nodeTab[i]->ns->href)); 8651 break; 8652 default: 8653 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8654 } 8655 } 8656 xmlXPathReleaseObject(ctxt->context, cur); 8657 } 8658 8659 /** 8660 * xmlXPathNameFunction: 8661 * @ctxt: the XPath Parser context 8662 * @nargs: the number of arguments 8663 * 8664 * Implement the name() XPath function 8665 * string name(node-set?) 8666 * The name function returns a string containing a QName representing 8667 * the name of the node in the argument node-set that is first in document 8668 * order. The QName must represent the name with respect to the namespace 8669 * declarations in effect on the node whose name is being represented. 8670 * Typically, this will be the form in which the name occurred in the XML 8671 * source. This need not be the case if there are namespace declarations 8672 * in effect on the node that associate multiple prefixes with the same 8673 * namespace. However, an implementation may include information about 8674 * the original prefix in its representation of nodes; in this case, an 8675 * implementation can ensure that the returned string is always the same 8676 * as the QName used in the XML source. If the argument it omitted it 8677 * defaults to the context node. 8678 * Libxml keep the original prefix so the "real qualified name" used is 8679 * returned. 8680 */ 8681 static void 8682 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) 8683 { 8684 xmlXPathObjectPtr cur; 8685 8686 if (nargs == 0) { 8687 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8688 ctxt->context->node)); 8689 nargs = 1; 8690 } 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 8704 switch (cur->nodesetval->nodeTab[i]->type) { 8705 case XML_ELEMENT_NODE: 8706 case XML_ATTRIBUTE_NODE: 8707 if (cur->nodesetval->nodeTab[i]->name[0] == ' ') 8708 valuePush(ctxt, 8709 xmlXPathCacheNewCString(ctxt->context, "")); 8710 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) || 8711 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) { 8712 valuePush(ctxt, 8713 xmlXPathCacheNewString(ctxt->context, 8714 cur->nodesetval->nodeTab[i]->name)); 8715 } else { 8716 xmlChar *fullname; 8717 8718 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name, 8719 cur->nodesetval->nodeTab[i]->ns->prefix, 8720 NULL, 0); 8721 if (fullname == cur->nodesetval->nodeTab[i]->name) 8722 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name); 8723 if (fullname == NULL) { 8724 XP_ERROR(XPATH_MEMORY_ERROR); 8725 } 8726 valuePush(ctxt, xmlXPathCacheWrapString( 8727 ctxt->context, fullname)); 8728 } 8729 break; 8730 default: 8731 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8732 cur->nodesetval->nodeTab[i])); 8733 xmlXPathLocalNameFunction(ctxt, 1); 8734 } 8735 } 8736 xmlXPathReleaseObject(ctxt->context, cur); 8737 } 8738 8739 8740 /** 8741 * xmlXPathStringFunction: 8742 * @ctxt: the XPath Parser context 8743 * @nargs: the number of arguments 8744 * 8745 * Implement the string() XPath function 8746 * string string(object?) 8747 * The string function converts an object to a string as follows: 8748 * - A node-set is converted to a string by returning the value of 8749 * the node in the node-set that is first in document order. 8750 * If the node-set is empty, an empty string is returned. 8751 * - A number is converted to a string as follows 8752 * + NaN is converted to the string NaN 8753 * + positive zero is converted to the string 0 8754 * + negative zero is converted to the string 0 8755 * + positive infinity is converted to the string Infinity 8756 * + negative infinity is converted to the string -Infinity 8757 * + if the number is an integer, the number is represented in 8758 * decimal form as a Number with no decimal point and no leading 8759 * zeros, preceded by a minus sign (-) if the number is negative 8760 * + otherwise, the number is represented in decimal form as a 8761 * Number including a decimal point with at least one digit 8762 * before the decimal point and at least one digit after the 8763 * decimal point, preceded by a minus sign (-) if the number 8764 * is negative; there must be no leading zeros before the decimal 8765 * point apart possibly from the one required digit immediately 8766 * before the decimal point; beyond the one required digit 8767 * after the decimal point there must be as many, but only as 8768 * many, more digits as are needed to uniquely distinguish the 8769 * number from all other IEEE 754 numeric values. 8770 * - The boolean false value is converted to the string false. 8771 * The boolean true value is converted to the string true. 8772 * 8773 * If the argument is omitted, it defaults to a node-set with the 8774 * context node as its only member. 8775 */ 8776 void 8777 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8778 xmlXPathObjectPtr cur; 8779 8780 if (ctxt == NULL) return; 8781 if (nargs == 0) { 8782 valuePush(ctxt, 8783 xmlXPathCacheWrapString(ctxt->context, 8784 xmlXPathCastNodeToString(ctxt->context->node))); 8785 return; 8786 } 8787 8788 CHECK_ARITY(1); 8789 cur = valuePop(ctxt); 8790 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 8791 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur)); 8792 } 8793 8794 /** 8795 * xmlXPathStringLengthFunction: 8796 * @ctxt: the XPath Parser context 8797 * @nargs: the number of arguments 8798 * 8799 * Implement the string-length() XPath function 8800 * number string-length(string?) 8801 * The string-length returns the number of characters in the string 8802 * (see [3.6 Strings]). If the argument is omitted, it defaults to 8803 * the context node converted to a string, in other words the value 8804 * of the context node. 8805 */ 8806 void 8807 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8808 xmlXPathObjectPtr cur; 8809 8810 if (nargs == 0) { 8811 if ((ctxt == NULL) || (ctxt->context == NULL)) 8812 return; 8813 if (ctxt->context->node == NULL) { 8814 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0)); 8815 } else { 8816 xmlChar *content; 8817 8818 content = xmlXPathCastNodeToString(ctxt->context->node); 8819 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 8820 xmlUTF8Strlen(content))); 8821 xmlFree(content); 8822 } 8823 return; 8824 } 8825 CHECK_ARITY(1); 8826 CAST_TO_STRING; 8827 CHECK_TYPE(XPATH_STRING); 8828 cur = valuePop(ctxt); 8829 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 8830 xmlUTF8Strlen(cur->stringval))); 8831 xmlXPathReleaseObject(ctxt->context, cur); 8832 } 8833 8834 /** 8835 * xmlXPathConcatFunction: 8836 * @ctxt: the XPath Parser context 8837 * @nargs: the number of arguments 8838 * 8839 * Implement the concat() XPath function 8840 * string concat(string, string, string*) 8841 * The concat function returns the concatenation of its arguments. 8842 */ 8843 void 8844 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8845 xmlXPathObjectPtr cur, newobj; 8846 xmlChar *tmp; 8847 8848 if (ctxt == NULL) return; 8849 if (nargs < 2) { 8850 CHECK_ARITY(2); 8851 } 8852 8853 CAST_TO_STRING; 8854 cur = valuePop(ctxt); 8855 if ((cur == NULL) || (cur->type != XPATH_STRING)) { 8856 xmlXPathReleaseObject(ctxt->context, cur); 8857 return; 8858 } 8859 nargs--; 8860 8861 while (nargs > 0) { 8862 CAST_TO_STRING; 8863 newobj = valuePop(ctxt); 8864 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) { 8865 xmlXPathReleaseObject(ctxt->context, newobj); 8866 xmlXPathReleaseObject(ctxt->context, cur); 8867 XP_ERROR(XPATH_INVALID_TYPE); 8868 } 8869 tmp = xmlStrcat(newobj->stringval, cur->stringval); 8870 newobj->stringval = cur->stringval; 8871 cur->stringval = tmp; 8872 xmlXPathReleaseObject(ctxt->context, newobj); 8873 nargs--; 8874 } 8875 valuePush(ctxt, cur); 8876 } 8877 8878 /** 8879 * xmlXPathContainsFunction: 8880 * @ctxt: the XPath Parser context 8881 * @nargs: the number of arguments 8882 * 8883 * Implement the contains() XPath function 8884 * boolean contains(string, string) 8885 * The contains function returns true if the first argument string 8886 * contains the second argument string, and otherwise returns false. 8887 */ 8888 void 8889 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8890 xmlXPathObjectPtr hay, needle; 8891 8892 CHECK_ARITY(2); 8893 CAST_TO_STRING; 8894 CHECK_TYPE(XPATH_STRING); 8895 needle = valuePop(ctxt); 8896 CAST_TO_STRING; 8897 hay = valuePop(ctxt); 8898 8899 if ((hay == NULL) || (hay->type != XPATH_STRING)) { 8900 xmlXPathReleaseObject(ctxt->context, hay); 8901 xmlXPathReleaseObject(ctxt->context, needle); 8902 XP_ERROR(XPATH_INVALID_TYPE); 8903 } 8904 if (xmlStrstr(hay->stringval, needle->stringval)) 8905 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); 8906 else 8907 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); 8908 xmlXPathReleaseObject(ctxt->context, hay); 8909 xmlXPathReleaseObject(ctxt->context, needle); 8910 } 8911 8912 /** 8913 * xmlXPathStartsWithFunction: 8914 * @ctxt: the XPath Parser context 8915 * @nargs: the number of arguments 8916 * 8917 * Implement the starts-with() XPath function 8918 * boolean starts-with(string, string) 8919 * The starts-with function returns true if the first argument string 8920 * starts with the second argument string, and otherwise returns false. 8921 */ 8922 void 8923 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8924 xmlXPathObjectPtr hay, needle; 8925 int n; 8926 8927 CHECK_ARITY(2); 8928 CAST_TO_STRING; 8929 CHECK_TYPE(XPATH_STRING); 8930 needle = valuePop(ctxt); 8931 CAST_TO_STRING; 8932 hay = valuePop(ctxt); 8933 8934 if ((hay == NULL) || (hay->type != XPATH_STRING)) { 8935 xmlXPathReleaseObject(ctxt->context, hay); 8936 xmlXPathReleaseObject(ctxt->context, needle); 8937 XP_ERROR(XPATH_INVALID_TYPE); 8938 } 8939 n = xmlStrlen(needle->stringval); 8940 if (xmlStrncmp(hay->stringval, needle->stringval, n)) 8941 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); 8942 else 8943 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); 8944 xmlXPathReleaseObject(ctxt->context, hay); 8945 xmlXPathReleaseObject(ctxt->context, needle); 8946 } 8947 8948 /** 8949 * xmlXPathSubstringFunction: 8950 * @ctxt: the XPath Parser context 8951 * @nargs: the number of arguments 8952 * 8953 * Implement the substring() XPath function 8954 * string substring(string, number, number?) 8955 * The substring function returns the substring of the first argument 8956 * starting at the position specified in the second argument with 8957 * length specified in the third argument. For example, 8958 * substring("12345",2,3) returns "234". If the third argument is not 8959 * specified, it returns the substring starting at the position specified 8960 * in the second argument and continuing to the end of the string. For 8961 * example, substring("12345",2) returns "2345". More precisely, each 8962 * character in the string (see [3.6 Strings]) is considered to have a 8963 * numeric position: the position of the first character is 1, the position 8964 * of the second character is 2 and so on. The returned substring contains 8965 * those characters for which the position of the character is greater than 8966 * or equal to the second argument and, if the third argument is specified, 8967 * less than the sum of the second and third arguments; the comparisons 8968 * and addition used for the above follow the standard IEEE 754 rules. Thus: 8969 * - substring("12345", 1.5, 2.6) returns "234" 8970 * - substring("12345", 0, 3) returns "12" 8971 * - substring("12345", 0 div 0, 3) returns "" 8972 * - substring("12345", 1, 0 div 0) returns "" 8973 * - substring("12345", -42, 1 div 0) returns "12345" 8974 * - substring("12345", -1 div 0, 1 div 0) returns "" 8975 */ 8976 void 8977 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8978 xmlXPathObjectPtr str, start, len; 8979 double le=0, in; 8980 int i, l, m; 8981 xmlChar *ret; 8982 8983 if (nargs < 2) { 8984 CHECK_ARITY(2); 8985 } 8986 if (nargs > 3) { 8987 CHECK_ARITY(3); 8988 } 8989 /* 8990 * take care of possible last (position) argument 8991 */ 8992 if (nargs == 3) { 8993 CAST_TO_NUMBER; 8994 CHECK_TYPE(XPATH_NUMBER); 8995 len = valuePop(ctxt); 8996 le = len->floatval; 8997 xmlXPathReleaseObject(ctxt->context, len); 8998 } 8999 9000 CAST_TO_NUMBER; 9001 CHECK_TYPE(XPATH_NUMBER); 9002 start = valuePop(ctxt); 9003 in = start->floatval; 9004 xmlXPathReleaseObject(ctxt->context, start); 9005 CAST_TO_STRING; 9006 CHECK_TYPE(XPATH_STRING); 9007 str = valuePop(ctxt); 9008 m = xmlUTF8Strlen((const unsigned char *)str->stringval); 9009 9010 /* 9011 * If last pos not present, calculate last position 9012 */ 9013 if (nargs != 3) { 9014 le = (double)m; 9015 if (in < 1.0) 9016 in = 1.0; 9017 } 9018 9019 /* Need to check for the special cases where either 9020 * the index is NaN, the length is NaN, or both 9021 * arguments are infinity (relying on Inf + -Inf = NaN) 9022 */ 9023 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) { 9024 /* 9025 * To meet the requirements of the spec, the arguments 9026 * must be converted to integer format before 9027 * initial index calculations are done 9028 * 9029 * First we go to integer form, rounding up 9030 * and checking for special cases 9031 */ 9032 i = (int) in; 9033 if (((double)i)+0.5 <= in) i++; 9034 9035 if (xmlXPathIsInf(le) == 1) { 9036 l = m; 9037 if (i < 1) 9038 i = 1; 9039 } 9040 else if (xmlXPathIsInf(le) == -1 || le < 0.0) 9041 l = 0; 9042 else { 9043 l = (int) le; 9044 if (((double)l)+0.5 <= le) l++; 9045 } 9046 9047 /* Now we normalize inidices */ 9048 i -= 1; 9049 l += i; 9050 if (i < 0) 9051 i = 0; 9052 if (l > m) 9053 l = m; 9054 9055 /* number of chars to copy */ 9056 l -= i; 9057 9058 ret = xmlUTF8Strsub(str->stringval, i, l); 9059 } 9060 else { 9061 ret = NULL; 9062 } 9063 if (ret == NULL) 9064 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 9065 else { 9066 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret)); 9067 xmlFree(ret); 9068 } 9069 xmlXPathReleaseObject(ctxt->context, str); 9070 } 9071 9072 /** 9073 * xmlXPathSubstringBeforeFunction: 9074 * @ctxt: the XPath Parser context 9075 * @nargs: the number of arguments 9076 * 9077 * Implement the substring-before() XPath function 9078 * string substring-before(string, string) 9079 * The substring-before function returns the substring of the first 9080 * argument string that precedes the first occurrence of the second 9081 * argument string in the first argument string, or the empty string 9082 * if the first argument string does not contain the second argument 9083 * string. For example, substring-before("1999/04/01","/") returns 1999. 9084 */ 9085 void 9086 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9087 xmlXPathObjectPtr str; 9088 xmlXPathObjectPtr find; 9089 xmlBufferPtr target; 9090 const xmlChar *point; 9091 int offset; 9092 9093 CHECK_ARITY(2); 9094 CAST_TO_STRING; 9095 find = valuePop(ctxt); 9096 CAST_TO_STRING; 9097 str = valuePop(ctxt); 9098 9099 target = xmlBufferCreate(); 9100 if (target) { 9101 point = xmlStrstr(str->stringval, find->stringval); 9102 if (point) { 9103 offset = (int)(point - str->stringval); 9104 xmlBufferAdd(target, str->stringval, offset); 9105 } 9106 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9107 xmlBufferContent(target))); 9108 xmlBufferFree(target); 9109 } 9110 xmlXPathReleaseObject(ctxt->context, str); 9111 xmlXPathReleaseObject(ctxt->context, find); 9112 } 9113 9114 /** 9115 * xmlXPathSubstringAfterFunction: 9116 * @ctxt: the XPath Parser context 9117 * @nargs: the number of arguments 9118 * 9119 * Implement the substring-after() XPath function 9120 * string substring-after(string, string) 9121 * The substring-after function returns the substring of the first 9122 * argument string that follows the first occurrence of the second 9123 * argument string in the first argument string, or the empty stringi 9124 * if the first argument string does not contain the second argument 9125 * string. For example, substring-after("1999/04/01","/") returns 04/01, 9126 * and substring-after("1999/04/01","19") returns 99/04/01. 9127 */ 9128 void 9129 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9130 xmlXPathObjectPtr str; 9131 xmlXPathObjectPtr find; 9132 xmlBufferPtr target; 9133 const xmlChar *point; 9134 int offset; 9135 9136 CHECK_ARITY(2); 9137 CAST_TO_STRING; 9138 find = valuePop(ctxt); 9139 CAST_TO_STRING; 9140 str = valuePop(ctxt); 9141 9142 target = xmlBufferCreate(); 9143 if (target) { 9144 point = xmlStrstr(str->stringval, find->stringval); 9145 if (point) { 9146 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval); 9147 xmlBufferAdd(target, &str->stringval[offset], 9148 xmlStrlen(str->stringval) - offset); 9149 } 9150 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9151 xmlBufferContent(target))); 9152 xmlBufferFree(target); 9153 } 9154 xmlXPathReleaseObject(ctxt->context, str); 9155 xmlXPathReleaseObject(ctxt->context, find); 9156 } 9157 9158 /** 9159 * xmlXPathNormalizeFunction: 9160 * @ctxt: the XPath Parser context 9161 * @nargs: the number of arguments 9162 * 9163 * Implement the normalize-space() XPath function 9164 * string normalize-space(string?) 9165 * The normalize-space function returns the argument string with white 9166 * space normalized by stripping leading and trailing whitespace 9167 * and replacing sequences of whitespace characters by a single 9168 * space. Whitespace characters are the same allowed by the S production 9169 * in XML. If the argument is omitted, it defaults to the context 9170 * node converted to a string, in other words the value of the context node. 9171 */ 9172 void 9173 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9174 xmlXPathObjectPtr obj = NULL; 9175 xmlChar *source = NULL; 9176 xmlBufferPtr target; 9177 xmlChar blank; 9178 9179 if (ctxt == NULL) return; 9180 if (nargs == 0) { 9181 /* Use current context node */ 9182 valuePush(ctxt, 9183 xmlXPathCacheWrapString(ctxt->context, 9184 xmlXPathCastNodeToString(ctxt->context->node))); 9185 nargs = 1; 9186 } 9187 9188 CHECK_ARITY(1); 9189 CAST_TO_STRING; 9190 CHECK_TYPE(XPATH_STRING); 9191 obj = valuePop(ctxt); 9192 source = obj->stringval; 9193 9194 target = xmlBufferCreate(); 9195 if (target && source) { 9196 9197 /* Skip leading whitespaces */ 9198 while (IS_BLANK_CH(*source)) 9199 source++; 9200 9201 /* Collapse intermediate whitespaces, and skip trailing whitespaces */ 9202 blank = 0; 9203 while (*source) { 9204 if (IS_BLANK_CH(*source)) { 9205 blank = 0x20; 9206 } else { 9207 if (blank) { 9208 xmlBufferAdd(target, &blank, 1); 9209 blank = 0; 9210 } 9211 xmlBufferAdd(target, source, 1); 9212 } 9213 source++; 9214 } 9215 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9216 xmlBufferContent(target))); 9217 xmlBufferFree(target); 9218 } 9219 xmlXPathReleaseObject(ctxt->context, obj); 9220 } 9221 9222 /** 9223 * xmlXPathTranslateFunction: 9224 * @ctxt: the XPath Parser context 9225 * @nargs: the number of arguments 9226 * 9227 * Implement the translate() XPath function 9228 * string translate(string, string, string) 9229 * The translate function returns the first argument string with 9230 * occurrences of characters in the second argument string replaced 9231 * by the character at the corresponding position in the third argument 9232 * string. For example, translate("bar","abc","ABC") returns the string 9233 * BAr. If there is a character in the second argument string with no 9234 * character at a corresponding position in the third argument string 9235 * (because the second argument string is longer than the third argument 9236 * string), then occurrences of that character in the first argument 9237 * string are removed. For example, translate("--aaa--","abc-","ABC") 9238 * returns "AAA". If a character occurs more than once in second 9239 * argument string, then the first occurrence determines the replacement 9240 * character. If the third argument string is longer than the second 9241 * argument string, then excess characters are ignored. 9242 */ 9243 void 9244 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9245 xmlXPathObjectPtr str; 9246 xmlXPathObjectPtr from; 9247 xmlXPathObjectPtr to; 9248 xmlBufferPtr target; 9249 int offset, max; 9250 xmlChar ch; 9251 const xmlChar *point; 9252 xmlChar *cptr; 9253 9254 CHECK_ARITY(3); 9255 9256 CAST_TO_STRING; 9257 to = valuePop(ctxt); 9258 CAST_TO_STRING; 9259 from = valuePop(ctxt); 9260 CAST_TO_STRING; 9261 str = valuePop(ctxt); 9262 9263 target = xmlBufferCreate(); 9264 if (target) { 9265 max = xmlUTF8Strlen(to->stringval); 9266 for (cptr = str->stringval; (ch=*cptr); ) { 9267 offset = xmlUTF8Strloc(from->stringval, cptr); 9268 if (offset >= 0) { 9269 if (offset < max) { 9270 point = xmlUTF8Strpos(to->stringval, offset); 9271 if (point) 9272 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1)); 9273 } 9274 } else 9275 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1)); 9276 9277 /* Step to next character in input */ 9278 cptr++; 9279 if ( ch & 0x80 ) { 9280 /* if not simple ascii, verify proper format */ 9281 if ( (ch & 0xc0) != 0xc0 ) { 9282 xmlGenericError(xmlGenericErrorContext, 9283 "xmlXPathTranslateFunction: Invalid UTF8 string\n"); 9284 break; 9285 } 9286 /* then skip over remaining bytes for this char */ 9287 while ( (ch <<= 1) & 0x80 ) 9288 if ( (*cptr++ & 0xc0) != 0x80 ) { 9289 xmlGenericError(xmlGenericErrorContext, 9290 "xmlXPathTranslateFunction: Invalid UTF8 string\n"); 9291 break; 9292 } 9293 if (ch & 0x80) /* must have had error encountered */ 9294 break; 9295 } 9296 } 9297 } 9298 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9299 xmlBufferContent(target))); 9300 xmlBufferFree(target); 9301 xmlXPathReleaseObject(ctxt->context, str); 9302 xmlXPathReleaseObject(ctxt->context, from); 9303 xmlXPathReleaseObject(ctxt->context, to); 9304 } 9305 9306 /** 9307 * xmlXPathBooleanFunction: 9308 * @ctxt: the XPath Parser context 9309 * @nargs: the number of arguments 9310 * 9311 * Implement the boolean() XPath function 9312 * boolean boolean(object) 9313 * The boolean function converts its argument to a boolean as follows: 9314 * - a number is true if and only if it is neither positive or 9315 * negative zero nor NaN 9316 * - a node-set is true if and only if it is non-empty 9317 * - a string is true if and only if its length is non-zero 9318 */ 9319 void 9320 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9321 xmlXPathObjectPtr cur; 9322 9323 CHECK_ARITY(1); 9324 cur = valuePop(ctxt); 9325 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 9326 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur); 9327 valuePush(ctxt, cur); 9328 } 9329 9330 /** 9331 * xmlXPathNotFunction: 9332 * @ctxt: the XPath Parser context 9333 * @nargs: the number of arguments 9334 * 9335 * Implement the not() XPath function 9336 * boolean not(boolean) 9337 * The not function returns true if its argument is false, 9338 * and false otherwise. 9339 */ 9340 void 9341 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9342 CHECK_ARITY(1); 9343 CAST_TO_BOOLEAN; 9344 CHECK_TYPE(XPATH_BOOLEAN); 9345 ctxt->value->boolval = ! ctxt->value->boolval; 9346 } 9347 9348 /** 9349 * xmlXPathTrueFunction: 9350 * @ctxt: the XPath Parser context 9351 * @nargs: the number of arguments 9352 * 9353 * Implement the true() XPath function 9354 * boolean true() 9355 */ 9356 void 9357 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9358 CHECK_ARITY(0); 9359 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); 9360 } 9361 9362 /** 9363 * xmlXPathFalseFunction: 9364 * @ctxt: the XPath Parser context 9365 * @nargs: the number of arguments 9366 * 9367 * Implement the false() XPath function 9368 * boolean false() 9369 */ 9370 void 9371 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9372 CHECK_ARITY(0); 9373 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); 9374 } 9375 9376 /** 9377 * xmlXPathLangFunction: 9378 * @ctxt: the XPath Parser context 9379 * @nargs: the number of arguments 9380 * 9381 * Implement the lang() XPath function 9382 * boolean lang(string) 9383 * The lang function returns true or false depending on whether the 9384 * language of the context node as specified by xml:lang attributes 9385 * is the same as or is a sublanguage of the language specified by 9386 * the argument string. The language of the context node is determined 9387 * by the value of the xml:lang attribute on the context node, or, if 9388 * the context node has no xml:lang attribute, by the value of the 9389 * xml:lang attribute on the nearest ancestor of the context node that 9390 * has an xml:lang attribute. If there is no such attribute, then lang 9391 * returns false. If there is such an attribute, then lang returns 9392 * true if the attribute value is equal to the argument ignoring case, 9393 * or if there is some suffix starting with - such that the attribute 9394 * value is equal to the argument ignoring that suffix of the attribute 9395 * value and ignoring case. 9396 */ 9397 void 9398 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9399 xmlXPathObjectPtr val = NULL; 9400 const xmlChar *theLang = NULL; 9401 const xmlChar *lang; 9402 int ret = 0; 9403 int i; 9404 9405 CHECK_ARITY(1); 9406 CAST_TO_STRING; 9407 CHECK_TYPE(XPATH_STRING); 9408 val = valuePop(ctxt); 9409 lang = val->stringval; 9410 theLang = xmlNodeGetLang(ctxt->context->node); 9411 if ((theLang != NULL) && (lang != NULL)) { 9412 for (i = 0;lang[i] != 0;i++) 9413 if (toupper(lang[i]) != toupper(theLang[i])) 9414 goto not_equal; 9415 if ((theLang[i] == 0) || (theLang[i] == '-')) 9416 ret = 1; 9417 } 9418 not_equal: 9419 if (theLang != NULL) 9420 xmlFree((void *)theLang); 9421 9422 xmlXPathReleaseObject(ctxt->context, val); 9423 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret)); 9424 } 9425 9426 /** 9427 * xmlXPathNumberFunction: 9428 * @ctxt: the XPath Parser context 9429 * @nargs: the number of arguments 9430 * 9431 * Implement the number() XPath function 9432 * number number(object?) 9433 */ 9434 void 9435 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9436 xmlXPathObjectPtr cur; 9437 double res; 9438 9439 if (ctxt == NULL) return; 9440 if (nargs == 0) { 9441 if (ctxt->context->node == NULL) { 9442 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0)); 9443 } else { 9444 xmlChar* content = xmlNodeGetContent(ctxt->context->node); 9445 9446 res = xmlXPathStringEvalNumber(content); 9447 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res)); 9448 xmlFree(content); 9449 } 9450 return; 9451 } 9452 9453 CHECK_ARITY(1); 9454 cur = valuePop(ctxt); 9455 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur)); 9456 } 9457 9458 /** 9459 * xmlXPathSumFunction: 9460 * @ctxt: the XPath Parser context 9461 * @nargs: the number of arguments 9462 * 9463 * Implement the sum() XPath function 9464 * number sum(node-set) 9465 * The sum function returns the sum of the values of the nodes in 9466 * the argument node-set. 9467 */ 9468 void 9469 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9470 xmlXPathObjectPtr cur; 9471 int i; 9472 double res = 0.0; 9473 9474 CHECK_ARITY(1); 9475 if ((ctxt->value == NULL) || 9476 ((ctxt->value->type != XPATH_NODESET) && 9477 (ctxt->value->type != XPATH_XSLT_TREE))) 9478 XP_ERROR(XPATH_INVALID_TYPE); 9479 cur = valuePop(ctxt); 9480 9481 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) { 9482 for (i = 0; i < cur->nodesetval->nodeNr; i++) { 9483 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]); 9484 } 9485 } 9486 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res)); 9487 xmlXPathReleaseObject(ctxt->context, cur); 9488 } 9489 9490 /* 9491 * To assure working code on multiple platforms, we want to only depend 9492 * upon the characteristic truncation of converting a floating point value 9493 * to an integer. Unfortunately, because of the different storage sizes 9494 * of our internal floating point value (double) and integer (int), we 9495 * can't directly convert (see bug 301162). This macro is a messy 9496 * 'workaround' 9497 */ 9498 #define XTRUNC(f, v) \ 9499 f = fmod((v), INT_MAX); \ 9500 f = (v) - (f) + (double)((int)(f)); 9501 9502 /** 9503 * xmlXPathFloorFunction: 9504 * @ctxt: the XPath Parser context 9505 * @nargs: the number of arguments 9506 * 9507 * Implement the floor() XPath function 9508 * number floor(number) 9509 * The floor function returns the largest (closest to positive infinity) 9510 * number that is not greater than the argument and that is an integer. 9511 */ 9512 void 9513 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9514 double f; 9515 9516 CHECK_ARITY(1); 9517 CAST_TO_NUMBER; 9518 CHECK_TYPE(XPATH_NUMBER); 9519 9520 XTRUNC(f, ctxt->value->floatval); 9521 if (f != ctxt->value->floatval) { 9522 if (ctxt->value->floatval > 0) 9523 ctxt->value->floatval = f; 9524 else 9525 ctxt->value->floatval = f - 1; 9526 } 9527 } 9528 9529 /** 9530 * xmlXPathCeilingFunction: 9531 * @ctxt: the XPath Parser context 9532 * @nargs: the number of arguments 9533 * 9534 * Implement the ceiling() XPath function 9535 * number ceiling(number) 9536 * The ceiling function returns the smallest (closest to negative infinity) 9537 * number that is not less than the argument and that is an integer. 9538 */ 9539 void 9540 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9541 double f; 9542 9543 CHECK_ARITY(1); 9544 CAST_TO_NUMBER; 9545 CHECK_TYPE(XPATH_NUMBER); 9546 9547 #if 0 9548 ctxt->value->floatval = ceil(ctxt->value->floatval); 9549 #else 9550 XTRUNC(f, ctxt->value->floatval); 9551 if (f != ctxt->value->floatval) { 9552 if (ctxt->value->floatval > 0) 9553 ctxt->value->floatval = f + 1; 9554 else { 9555 if (ctxt->value->floatval < 0 && f == 0) 9556 ctxt->value->floatval = xmlXPathNZERO; 9557 else 9558 ctxt->value->floatval = f; 9559 } 9560 9561 } 9562 #endif 9563 } 9564 9565 /** 9566 * xmlXPathRoundFunction: 9567 * @ctxt: the XPath Parser context 9568 * @nargs: the number of arguments 9569 * 9570 * Implement the round() XPath function 9571 * number round(number) 9572 * The round function returns the number that is closest to the 9573 * argument and that is an integer. If there are two such numbers, 9574 * then the one that is even is returned. 9575 */ 9576 void 9577 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9578 double f; 9579 9580 CHECK_ARITY(1); 9581 CAST_TO_NUMBER; 9582 CHECK_TYPE(XPATH_NUMBER); 9583 9584 if ((xmlXPathIsNaN(ctxt->value->floatval)) || 9585 (xmlXPathIsInf(ctxt->value->floatval) == 1) || 9586 (xmlXPathIsInf(ctxt->value->floatval) == -1) || 9587 (ctxt->value->floatval == 0.0)) 9588 return; 9589 9590 XTRUNC(f, ctxt->value->floatval); 9591 if (ctxt->value->floatval < 0) { 9592 if (ctxt->value->floatval < f - 0.5) 9593 ctxt->value->floatval = f - 1; 9594 else 9595 ctxt->value->floatval = f; 9596 if (ctxt->value->floatval == 0) 9597 ctxt->value->floatval = xmlXPathNZERO; 9598 } else { 9599 if (ctxt->value->floatval < f + 0.5) 9600 ctxt->value->floatval = f; 9601 else 9602 ctxt->value->floatval = f + 1; 9603 } 9604 } 9605 9606 /************************************************************************ 9607 * * 9608 * The Parser * 9609 * * 9610 ************************************************************************/ 9611 9612 /* 9613 * a few forward declarations since we use a recursive call based 9614 * implementation. 9615 */ 9616 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort); 9617 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter); 9618 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt); 9619 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt); 9620 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, 9621 int qualified); 9622 9623 /** 9624 * xmlXPathCurrentChar: 9625 * @ctxt: the XPath parser context 9626 * @cur: pointer to the beginning of the char 9627 * @len: pointer to the length of the char read 9628 * 9629 * The current char value, if using UTF-8 this may actually span multiple 9630 * bytes in the input buffer. 9631 * 9632 * Returns the current char value and its length 9633 */ 9634 9635 static int 9636 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) { 9637 unsigned char c; 9638 unsigned int val; 9639 const xmlChar *cur; 9640 9641 if (ctxt == NULL) 9642 return(0); 9643 cur = ctxt->cur; 9644 9645 /* 9646 * We are supposed to handle UTF8, check it's valid 9647 * From rfc2044: encoding of the Unicode values on UTF-8: 9648 * 9649 * UCS-4 range (hex.) UTF-8 octet sequence (binary) 9650 * 0000 0000-0000 007F 0xxxxxxx 9651 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx 9652 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx 9653 * 9654 * Check for the 0x110000 limit too 9655 */ 9656 c = *cur; 9657 if (c & 0x80) { 9658 if ((cur[1] & 0xc0) != 0x80) 9659 goto encoding_error; 9660 if ((c & 0xe0) == 0xe0) { 9661 9662 if ((cur[2] & 0xc0) != 0x80) 9663 goto encoding_error; 9664 if ((c & 0xf0) == 0xf0) { 9665 if (((c & 0xf8) != 0xf0) || 9666 ((cur[3] & 0xc0) != 0x80)) 9667 goto encoding_error; 9668 /* 4-byte code */ 9669 *len = 4; 9670 val = (cur[0] & 0x7) << 18; 9671 val |= (cur[1] & 0x3f) << 12; 9672 val |= (cur[2] & 0x3f) << 6; 9673 val |= cur[3] & 0x3f; 9674 } else { 9675 /* 3-byte code */ 9676 *len = 3; 9677 val = (cur[0] & 0xf) << 12; 9678 val |= (cur[1] & 0x3f) << 6; 9679 val |= cur[2] & 0x3f; 9680 } 9681 } else { 9682 /* 2-byte code */ 9683 *len = 2; 9684 val = (cur[0] & 0x1f) << 6; 9685 val |= cur[1] & 0x3f; 9686 } 9687 if (!IS_CHAR(val)) { 9688 XP_ERROR0(XPATH_INVALID_CHAR_ERROR); 9689 } 9690 return(val); 9691 } else { 9692 /* 1-byte code */ 9693 *len = 1; 9694 return((int) *cur); 9695 } 9696 encoding_error: 9697 /* 9698 * If we detect an UTF8 error that probably means that the 9699 * input encoding didn't get properly advertised in the 9700 * declaration header. Report the error and switch the encoding 9701 * to ISO-Latin-1 (if you don't like this policy, just declare the 9702 * encoding !) 9703 */ 9704 *len = 0; 9705 XP_ERROR0(XPATH_ENCODING_ERROR); 9706 } 9707 9708 /** 9709 * xmlXPathParseNCName: 9710 * @ctxt: the XPath Parser context 9711 * 9712 * parse an XML namespace non qualified name. 9713 * 9714 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)* 9715 * 9716 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' | 9717 * CombiningChar | Extender 9718 * 9719 * Returns the namespace name or NULL 9720 */ 9721 9722 xmlChar * 9723 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) { 9724 const xmlChar *in; 9725 xmlChar *ret; 9726 int count = 0; 9727 9728 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL); 9729 /* 9730 * Accelerator for simple ASCII names 9731 */ 9732 in = ctxt->cur; 9733 if (((*in >= 0x61) && (*in <= 0x7A)) || 9734 ((*in >= 0x41) && (*in <= 0x5A)) || 9735 (*in == '_')) { 9736 in++; 9737 while (((*in >= 0x61) && (*in <= 0x7A)) || 9738 ((*in >= 0x41) && (*in <= 0x5A)) || 9739 ((*in >= 0x30) && (*in <= 0x39)) || 9740 (*in == '_') || (*in == '.') || 9741 (*in == '-')) 9742 in++; 9743 if ((*in == ' ') || (*in == '>') || (*in == '/') || 9744 (*in == '[') || (*in == ']') || (*in == ':') || 9745 (*in == '@') || (*in == '*')) { 9746 count = in - ctxt->cur; 9747 if (count == 0) 9748 return(NULL); 9749 ret = xmlStrndup(ctxt->cur, count); 9750 ctxt->cur = in; 9751 return(ret); 9752 } 9753 } 9754 return(xmlXPathParseNameComplex(ctxt, 0)); 9755 } 9756 9757 9758 /** 9759 * xmlXPathParseQName: 9760 * @ctxt: the XPath Parser context 9761 * @prefix: a xmlChar ** 9762 * 9763 * parse an XML qualified name 9764 * 9765 * [NS 5] QName ::= (Prefix ':')? LocalPart 9766 * 9767 * [NS 6] Prefix ::= NCName 9768 * 9769 * [NS 7] LocalPart ::= NCName 9770 * 9771 * Returns the function returns the local part, and prefix is updated 9772 * to get the Prefix if any. 9773 */ 9774 9775 static xmlChar * 9776 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) { 9777 xmlChar *ret = NULL; 9778 9779 *prefix = NULL; 9780 ret = xmlXPathParseNCName(ctxt); 9781 if (ret && CUR == ':') { 9782 *prefix = ret; 9783 NEXT; 9784 ret = xmlXPathParseNCName(ctxt); 9785 } 9786 return(ret); 9787 } 9788 9789 /** 9790 * xmlXPathParseName: 9791 * @ctxt: the XPath Parser context 9792 * 9793 * parse an XML name 9794 * 9795 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | 9796 * CombiningChar | Extender 9797 * 9798 * [5] Name ::= (Letter | '_' | ':') (NameChar)* 9799 * 9800 * Returns the namespace name or NULL 9801 */ 9802 9803 xmlChar * 9804 xmlXPathParseName(xmlXPathParserContextPtr ctxt) { 9805 const xmlChar *in; 9806 xmlChar *ret; 9807 int count = 0; 9808 9809 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL); 9810 /* 9811 * Accelerator for simple ASCII names 9812 */ 9813 in = ctxt->cur; 9814 if (((*in >= 0x61) && (*in <= 0x7A)) || 9815 ((*in >= 0x41) && (*in <= 0x5A)) || 9816 (*in == '_') || (*in == ':')) { 9817 in++; 9818 while (((*in >= 0x61) && (*in <= 0x7A)) || 9819 ((*in >= 0x41) && (*in <= 0x5A)) || 9820 ((*in >= 0x30) && (*in <= 0x39)) || 9821 (*in == '_') || (*in == '-') || 9822 (*in == ':') || (*in == '.')) 9823 in++; 9824 if ((*in > 0) && (*in < 0x80)) { 9825 count = in - ctxt->cur; 9826 ret = xmlStrndup(ctxt->cur, count); 9827 ctxt->cur = in; 9828 return(ret); 9829 } 9830 } 9831 return(xmlXPathParseNameComplex(ctxt, 1)); 9832 } 9833 9834 static xmlChar * 9835 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) { 9836 xmlChar buf[XML_MAX_NAMELEN + 5]; 9837 int len = 0, l; 9838 int c; 9839 9840 /* 9841 * Handler for more complex cases 9842 */ 9843 c = CUR_CHAR(l); 9844 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */ 9845 (c == '[') || (c == ']') || (c == '@') || /* accelerators */ 9846 (c == '*') || /* accelerators */ 9847 (!IS_LETTER(c) && (c != '_') && 9848 ((qualified) && (c != ':')))) { 9849 return(NULL); 9850 } 9851 9852 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */ 9853 ((IS_LETTER(c)) || (IS_DIGIT(c)) || 9854 (c == '.') || (c == '-') || 9855 (c == '_') || ((qualified) && (c == ':')) || 9856 (IS_COMBINING(c)) || 9857 (IS_EXTENDER(c)))) { 9858 COPY_BUF(l,buf,len,c); 9859 NEXTL(l); 9860 c = CUR_CHAR(l); 9861 if (len >= XML_MAX_NAMELEN) { 9862 /* 9863 * Okay someone managed to make a huge name, so he's ready to pay 9864 * for the processing speed. 9865 */ 9866 xmlChar *buffer; 9867 int max = len * 2; 9868 9869 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar)); 9870 if (buffer == NULL) { 9871 XP_ERRORNULL(XPATH_MEMORY_ERROR); 9872 } 9873 memcpy(buffer, buf, len); 9874 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */ 9875 (c == '.') || (c == '-') || 9876 (c == '_') || ((qualified) && (c == ':')) || 9877 (IS_COMBINING(c)) || 9878 (IS_EXTENDER(c))) { 9879 if (len + 10 > max) { 9880 max *= 2; 9881 buffer = (xmlChar *) xmlRealloc(buffer, 9882 max * sizeof(xmlChar)); 9883 if (buffer == NULL) { 9884 XP_ERRORNULL(XPATH_MEMORY_ERROR); 9885 } 9886 } 9887 COPY_BUF(l,buffer,len,c); 9888 NEXTL(l); 9889 c = CUR_CHAR(l); 9890 } 9891 buffer[len] = 0; 9892 return(buffer); 9893 } 9894 } 9895 if (len == 0) 9896 return(NULL); 9897 return(xmlStrndup(buf, len)); 9898 } 9899 9900 #define MAX_FRAC 20 9901 9902 /* 9903 * These are used as divisors for the fractional part of a number. 9904 * Since the table includes 1.0 (representing '0' fractional digits), 9905 * it must be dimensioned at MAX_FRAC+1 (bug 133921) 9906 */ 9907 static double my_pow10[MAX_FRAC+1] = { 9908 1.0, 10.0, 100.0, 1000.0, 10000.0, 9909 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0, 9910 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0, 9911 100000000000000.0, 9912 1000000000000000.0, 10000000000000000.0, 100000000000000000.0, 9913 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0 9914 }; 9915 9916 /** 9917 * xmlXPathStringEvalNumber: 9918 * @str: A string to scan 9919 * 9920 * [30a] Float ::= Number ('e' Digits?)? 9921 * 9922 * [30] Number ::= Digits ('.' Digits?)? 9923 * | '.' Digits 9924 * [31] Digits ::= [0-9]+ 9925 * 9926 * Compile a Number in the string 9927 * In complement of the Number expression, this function also handles 9928 * negative values : '-' Number. 9929 * 9930 * Returns the double value. 9931 */ 9932 double 9933 xmlXPathStringEvalNumber(const xmlChar *str) { 9934 const xmlChar *cur = str; 9935 double ret; 9936 int ok = 0; 9937 int isneg = 0; 9938 int exponent = 0; 9939 int is_exponent_negative = 0; 9940 #ifdef __GNUC__ 9941 unsigned long tmp = 0; 9942 double temp; 9943 #endif 9944 if (cur == NULL) return(0); 9945 while (IS_BLANK_CH(*cur)) cur++; 9946 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) { 9947 return(xmlXPathNAN); 9948 } 9949 if (*cur == '-') { 9950 isneg = 1; 9951 cur++; 9952 } 9953 9954 #ifdef __GNUC__ 9955 /* 9956 * tmp/temp is a workaround against a gcc compiler bug 9957 * http://veillard.com/gcc.bug 9958 */ 9959 ret = 0; 9960 while ((*cur >= '0') && (*cur <= '9')) { 9961 ret = ret * 10; 9962 tmp = (*cur - '0'); 9963 ok = 1; 9964 cur++; 9965 temp = (double) tmp; 9966 ret = ret + temp; 9967 } 9968 #else 9969 ret = 0; 9970 while ((*cur >= '0') && (*cur <= '9')) { 9971 ret = ret * 10 + (*cur - '0'); 9972 ok = 1; 9973 cur++; 9974 } 9975 #endif 9976 9977 if (*cur == '.') { 9978 int v, frac = 0; 9979 double fraction = 0; 9980 9981 cur++; 9982 if (((*cur < '0') || (*cur > '9')) && (!ok)) { 9983 return(xmlXPathNAN); 9984 } 9985 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) { 9986 v = (*cur - '0'); 9987 fraction = fraction * 10 + v; 9988 frac = frac + 1; 9989 cur++; 9990 } 9991 fraction /= my_pow10[frac]; 9992 ret = ret + fraction; 9993 while ((*cur >= '0') && (*cur <= '9')) 9994 cur++; 9995 } 9996 if ((*cur == 'e') || (*cur == 'E')) { 9997 cur++; 9998 if (*cur == '-') { 9999 is_exponent_negative = 1; 10000 cur++; 10001 } else if (*cur == '+') { 10002 cur++; 10003 } 10004 while ((*cur >= '0') && (*cur <= '9')) { 10005 exponent = exponent * 10 + (*cur - '0'); 10006 cur++; 10007 } 10008 } 10009 while (IS_BLANK_CH(*cur)) cur++; 10010 if (*cur != 0) return(xmlXPathNAN); 10011 if (isneg) ret = -ret; 10012 if (is_exponent_negative) exponent = -exponent; 10013 ret *= pow(10.0, (double)exponent); 10014 return(ret); 10015 } 10016 10017 /** 10018 * xmlXPathCompNumber: 10019 * @ctxt: the XPath Parser context 10020 * 10021 * [30] Number ::= Digits ('.' Digits?)? 10022 * | '.' Digits 10023 * [31] Digits ::= [0-9]+ 10024 * 10025 * Compile a Number, then push it on the stack 10026 * 10027 */ 10028 static void 10029 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt) 10030 { 10031 double ret = 0.0; 10032 double mult = 1; 10033 int ok = 0; 10034 int exponent = 0; 10035 int is_exponent_negative = 0; 10036 #ifdef __GNUC__ 10037 unsigned long tmp = 0; 10038 double temp; 10039 #endif 10040 10041 CHECK_ERROR; 10042 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) { 10043 XP_ERROR(XPATH_NUMBER_ERROR); 10044 } 10045 #ifdef __GNUC__ 10046 /* 10047 * tmp/temp is a workaround against a gcc compiler bug 10048 * http://veillard.com/gcc.bug 10049 */ 10050 ret = 0; 10051 while ((CUR >= '0') && (CUR <= '9')) { 10052 ret = ret * 10; 10053 tmp = (CUR - '0'); 10054 ok = 1; 10055 NEXT; 10056 temp = (double) tmp; 10057 ret = ret + temp; 10058 } 10059 #else 10060 ret = 0; 10061 while ((CUR >= '0') && (CUR <= '9')) { 10062 ret = ret * 10 + (CUR - '0'); 10063 ok = 1; 10064 NEXT; 10065 } 10066 #endif 10067 if (CUR == '.') { 10068 NEXT; 10069 if (((CUR < '0') || (CUR > '9')) && (!ok)) { 10070 XP_ERROR(XPATH_NUMBER_ERROR); 10071 } 10072 while ((CUR >= '0') && (CUR <= '9')) { 10073 mult /= 10; 10074 ret = ret + (CUR - '0') * mult; 10075 NEXT; 10076 } 10077 } 10078 if ((CUR == 'e') || (CUR == 'E')) { 10079 NEXT; 10080 if (CUR == '-') { 10081 is_exponent_negative = 1; 10082 NEXT; 10083 } else if (CUR == '+') { 10084 NEXT; 10085 } 10086 while ((CUR >= '0') && (CUR <= '9')) { 10087 exponent = exponent * 10 + (CUR - '0'); 10088 NEXT; 10089 } 10090 if (is_exponent_negative) 10091 exponent = -exponent; 10092 ret *= pow(10.0, (double) exponent); 10093 } 10094 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, 10095 xmlXPathCacheNewFloat(ctxt->context, ret), NULL); 10096 } 10097 10098 /** 10099 * xmlXPathParseLiteral: 10100 * @ctxt: the XPath Parser context 10101 * 10102 * Parse a Literal 10103 * 10104 * [29] Literal ::= '"' [^"]* '"' 10105 * | "'" [^']* "'" 10106 * 10107 * Returns the value found or NULL in case of error 10108 */ 10109 static xmlChar * 10110 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) { 10111 const xmlChar *q; 10112 xmlChar *ret = NULL; 10113 10114 if (CUR == '"') { 10115 NEXT; 10116 q = CUR_PTR; 10117 while ((IS_CHAR_CH(CUR)) && (CUR != '"')) 10118 NEXT; 10119 if (!IS_CHAR_CH(CUR)) { 10120 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR); 10121 } else { 10122 ret = xmlStrndup(q, CUR_PTR - q); 10123 NEXT; 10124 } 10125 } else if (CUR == '\'') { 10126 NEXT; 10127 q = CUR_PTR; 10128 while ((IS_CHAR_CH(CUR)) && (CUR != '\'')) 10129 NEXT; 10130 if (!IS_CHAR_CH(CUR)) { 10131 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR); 10132 } else { 10133 ret = xmlStrndup(q, CUR_PTR - q); 10134 NEXT; 10135 } 10136 } else { 10137 XP_ERRORNULL(XPATH_START_LITERAL_ERROR); 10138 } 10139 return(ret); 10140 } 10141 10142 /** 10143 * xmlXPathCompLiteral: 10144 * @ctxt: the XPath Parser context 10145 * 10146 * Parse a Literal and push it on the stack. 10147 * 10148 * [29] Literal ::= '"' [^"]* '"' 10149 * | "'" [^']* "'" 10150 * 10151 * TODO: xmlXPathCompLiteral memory allocation could be improved. 10152 */ 10153 static void 10154 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) { 10155 const xmlChar *q; 10156 xmlChar *ret = NULL; 10157 10158 if (CUR == '"') { 10159 NEXT; 10160 q = CUR_PTR; 10161 while ((IS_CHAR_CH(CUR)) && (CUR != '"')) 10162 NEXT; 10163 if (!IS_CHAR_CH(CUR)) { 10164 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR); 10165 } else { 10166 ret = xmlStrndup(q, CUR_PTR - q); 10167 NEXT; 10168 } 10169 } else if (CUR == '\'') { 10170 NEXT; 10171 q = CUR_PTR; 10172 while ((IS_CHAR_CH(CUR)) && (CUR != '\'')) 10173 NEXT; 10174 if (!IS_CHAR_CH(CUR)) { 10175 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR); 10176 } else { 10177 ret = xmlStrndup(q, CUR_PTR - q); 10178 NEXT; 10179 } 10180 } else { 10181 XP_ERROR(XPATH_START_LITERAL_ERROR); 10182 } 10183 if (ret == NULL) return; 10184 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, 10185 xmlXPathCacheNewString(ctxt->context, ret), NULL); 10186 xmlFree(ret); 10187 } 10188 10189 /** 10190 * xmlXPathCompVariableReference: 10191 * @ctxt: the XPath Parser context 10192 * 10193 * Parse a VariableReference, evaluate it and push it on the stack. 10194 * 10195 * The variable bindings consist of a mapping from variable names 10196 * to variable values. The value of a variable is an object, which can be 10197 * of any of the types that are possible for the value of an expression, 10198 * and may also be of additional types not specified here. 10199 * 10200 * Early evaluation is possible since: 10201 * The variable bindings [...] used to evaluate a subexpression are 10202 * always the same as those used to evaluate the containing expression. 10203 * 10204 * [36] VariableReference ::= '$' QName 10205 */ 10206 static void 10207 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) { 10208 xmlChar *name; 10209 xmlChar *prefix; 10210 10211 SKIP_BLANKS; 10212 if (CUR != '$') { 10213 XP_ERROR(XPATH_VARIABLE_REF_ERROR); 10214 } 10215 NEXT; 10216 name = xmlXPathParseQName(ctxt, &prefix); 10217 if (name == NULL) { 10218 XP_ERROR(XPATH_VARIABLE_REF_ERROR); 10219 } 10220 ctxt->comp->last = -1; 10221 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, 10222 name, prefix); 10223 SKIP_BLANKS; 10224 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) { 10225 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR); 10226 } 10227 } 10228 10229 /** 10230 * xmlXPathIsNodeType: 10231 * @name: a name string 10232 * 10233 * Is the name given a NodeType one. 10234 * 10235 * [38] NodeType ::= 'comment' 10236 * | 'text' 10237 * | 'processing-instruction' 10238 * | 'node' 10239 * 10240 * Returns 1 if true 0 otherwise 10241 */ 10242 int 10243 xmlXPathIsNodeType(const xmlChar *name) { 10244 if (name == NULL) 10245 return(0); 10246 10247 if (xmlStrEqual(name, BAD_CAST "node")) 10248 return(1); 10249 if (xmlStrEqual(name, BAD_CAST "text")) 10250 return(1); 10251 if (xmlStrEqual(name, BAD_CAST "comment")) 10252 return(1); 10253 if (xmlStrEqual(name, BAD_CAST "processing-instruction")) 10254 return(1); 10255 return(0); 10256 } 10257 10258 /** 10259 * xmlXPathCompFunctionCall: 10260 * @ctxt: the XPath Parser context 10261 * 10262 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')' 10263 * [17] Argument ::= Expr 10264 * 10265 * Compile a function call, the evaluation of all arguments are 10266 * pushed on the stack 10267 */ 10268 static void 10269 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) { 10270 xmlChar *name; 10271 xmlChar *prefix; 10272 int nbargs = 0; 10273 int sort = 1; 10274 10275 name = xmlXPathParseQName(ctxt, &prefix); 10276 if (name == NULL) { 10277 xmlFree(prefix); 10278 XP_ERROR(XPATH_EXPR_ERROR); 10279 } 10280 SKIP_BLANKS; 10281 #ifdef DEBUG_EXPR 10282 if (prefix == NULL) 10283 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n", 10284 name); 10285 else 10286 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n", 10287 prefix, name); 10288 #endif 10289 10290 if (CUR != '(') { 10291 XP_ERROR(XPATH_EXPR_ERROR); 10292 } 10293 NEXT; 10294 SKIP_BLANKS; 10295 10296 /* 10297 * Optimization for count(): we don't need the node-set to be sorted. 10298 */ 10299 if ((prefix == NULL) && (name[0] == 'c') && 10300 xmlStrEqual(name, BAD_CAST "count")) 10301 { 10302 sort = 0; 10303 } 10304 ctxt->comp->last = -1; 10305 if (CUR != ')') { 10306 while (CUR != 0) { 10307 int op1 = ctxt->comp->last; 10308 ctxt->comp->last = -1; 10309 xmlXPathCompileExpr(ctxt, sort); 10310 if (ctxt->error != XPATH_EXPRESSION_OK) { 10311 xmlFree(name); 10312 xmlFree(prefix); 10313 return; 10314 } 10315 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0); 10316 nbargs++; 10317 if (CUR == ')') break; 10318 if (CUR != ',') { 10319 XP_ERROR(XPATH_EXPR_ERROR); 10320 } 10321 NEXT; 10322 SKIP_BLANKS; 10323 } 10324 } 10325 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, 10326 name, prefix); 10327 NEXT; 10328 SKIP_BLANKS; 10329 } 10330 10331 /** 10332 * xmlXPathCompPrimaryExpr: 10333 * @ctxt: the XPath Parser context 10334 * 10335 * [15] PrimaryExpr ::= VariableReference 10336 * | '(' Expr ')' 10337 * | Literal 10338 * | Number 10339 * | FunctionCall 10340 * 10341 * Compile a primary expression. 10342 */ 10343 static void 10344 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) { 10345 SKIP_BLANKS; 10346 if (CUR == '$') xmlXPathCompVariableReference(ctxt); 10347 else if (CUR == '(') { 10348 NEXT; 10349 SKIP_BLANKS; 10350 xmlXPathCompileExpr(ctxt, 1); 10351 CHECK_ERROR; 10352 if (CUR != ')') { 10353 XP_ERROR(XPATH_EXPR_ERROR); 10354 } 10355 NEXT; 10356 SKIP_BLANKS; 10357 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) { 10358 xmlXPathCompNumber(ctxt); 10359 } else if ((CUR == '\'') || (CUR == '"')) { 10360 xmlXPathCompLiteral(ctxt); 10361 } else { 10362 xmlXPathCompFunctionCall(ctxt); 10363 } 10364 SKIP_BLANKS; 10365 } 10366 10367 /** 10368 * xmlXPathCompFilterExpr: 10369 * @ctxt: the XPath Parser context 10370 * 10371 * [20] FilterExpr ::= PrimaryExpr 10372 * | FilterExpr Predicate 10373 * 10374 * Compile a filter expression. 10375 * Square brackets are used to filter expressions in the same way that 10376 * they are used in location paths. It is an error if the expression to 10377 * be filtered does not evaluate to a node-set. The context node list 10378 * used for evaluating the expression in square brackets is the node-set 10379 * to be filtered listed in document order. 10380 */ 10381 10382 static void 10383 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) { 10384 xmlXPathCompPrimaryExpr(ctxt); 10385 CHECK_ERROR; 10386 SKIP_BLANKS; 10387 10388 while (CUR == '[') { 10389 xmlXPathCompPredicate(ctxt, 1); 10390 SKIP_BLANKS; 10391 } 10392 10393 10394 } 10395 10396 /** 10397 * xmlXPathScanName: 10398 * @ctxt: the XPath Parser context 10399 * 10400 * Trickery: parse an XML name but without consuming the input flow 10401 * Needed to avoid insanity in the parser state. 10402 * 10403 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | 10404 * CombiningChar | Extender 10405 * 10406 * [5] Name ::= (Letter | '_' | ':') (NameChar)* 10407 * 10408 * [6] Names ::= Name (S Name)* 10409 * 10410 * Returns the Name parsed or NULL 10411 */ 10412 10413 static xmlChar * 10414 xmlXPathScanName(xmlXPathParserContextPtr ctxt) { 10415 int len = 0, l; 10416 int c; 10417 const xmlChar *cur; 10418 xmlChar *ret; 10419 10420 cur = ctxt->cur; 10421 10422 c = CUR_CHAR(l); 10423 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */ 10424 (!IS_LETTER(c) && (c != '_') && 10425 (c != ':'))) { 10426 return(NULL); 10427 } 10428 10429 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */ 10430 ((IS_LETTER(c)) || (IS_DIGIT(c)) || 10431 (c == '.') || (c == '-') || 10432 (c == '_') || (c == ':') || 10433 (IS_COMBINING(c)) || 10434 (IS_EXTENDER(c)))) { 10435 len += l; 10436 NEXTL(l); 10437 c = CUR_CHAR(l); 10438 } 10439 ret = xmlStrndup(cur, ctxt->cur - cur); 10440 ctxt->cur = cur; 10441 return(ret); 10442 } 10443 10444 /** 10445 * xmlXPathCompPathExpr: 10446 * @ctxt: the XPath Parser context 10447 * 10448 * [19] PathExpr ::= LocationPath 10449 * | FilterExpr 10450 * | FilterExpr '/' RelativeLocationPath 10451 * | FilterExpr '//' RelativeLocationPath 10452 * 10453 * Compile a path expression. 10454 * The / operator and // operators combine an arbitrary expression 10455 * and a relative location path. It is an error if the expression 10456 * does not evaluate to a node-set. 10457 * The / operator does composition in the same way as when / is 10458 * used in a location path. As in location paths, // is short for 10459 * /descendant-or-self::node()/. 10460 */ 10461 10462 static void 10463 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) { 10464 int lc = 1; /* Should we branch to LocationPath ? */ 10465 xmlChar *name = NULL; /* we may have to preparse a name to find out */ 10466 10467 SKIP_BLANKS; 10468 if ((CUR == '$') || (CUR == '(') || 10469 (IS_ASCII_DIGIT(CUR)) || 10470 (CUR == '\'') || (CUR == '"') || 10471 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) { 10472 lc = 0; 10473 } else if (CUR == '*') { 10474 /* relative or absolute location path */ 10475 lc = 1; 10476 } else if (CUR == '/') { 10477 /* relative or absolute location path */ 10478 lc = 1; 10479 } else if (CUR == '@') { 10480 /* relative abbreviated attribute location path */ 10481 lc = 1; 10482 } else if (CUR == '.') { 10483 /* relative abbreviated attribute location path */ 10484 lc = 1; 10485 } else { 10486 /* 10487 * Problem is finding if we have a name here whether it's: 10488 * - a nodetype 10489 * - a function call in which case it's followed by '(' 10490 * - an axis in which case it's followed by ':' 10491 * - a element name 10492 * We do an a priori analysis here rather than having to 10493 * maintain parsed token content through the recursive function 10494 * calls. This looks uglier but makes the code easier to 10495 * read/write/debug. 10496 */ 10497 SKIP_BLANKS; 10498 name = xmlXPathScanName(ctxt); 10499 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) { 10500 #ifdef DEBUG_STEP 10501 xmlGenericError(xmlGenericErrorContext, 10502 "PathExpr: Axis\n"); 10503 #endif 10504 lc = 1; 10505 xmlFree(name); 10506 } else if (name != NULL) { 10507 int len =xmlStrlen(name); 10508 10509 10510 while (NXT(len) != 0) { 10511 if (NXT(len) == '/') { 10512 /* element name */ 10513 #ifdef DEBUG_STEP 10514 xmlGenericError(xmlGenericErrorContext, 10515 "PathExpr: AbbrRelLocation\n"); 10516 #endif 10517 lc = 1; 10518 break; 10519 } else if (IS_BLANK_CH(NXT(len))) { 10520 /* ignore blanks */ 10521 ; 10522 } else if (NXT(len) == ':') { 10523 #ifdef DEBUG_STEP 10524 xmlGenericError(xmlGenericErrorContext, 10525 "PathExpr: AbbrRelLocation\n"); 10526 #endif 10527 lc = 1; 10528 break; 10529 } else if ((NXT(len) == '(')) { 10530 /* Note Type or Function */ 10531 if (xmlXPathIsNodeType(name)) { 10532 #ifdef DEBUG_STEP 10533 xmlGenericError(xmlGenericErrorContext, 10534 "PathExpr: Type search\n"); 10535 #endif 10536 lc = 1; 10537 } else { 10538 #ifdef DEBUG_STEP 10539 xmlGenericError(xmlGenericErrorContext, 10540 "PathExpr: function call\n"); 10541 #endif 10542 lc = 0; 10543 } 10544 break; 10545 } else if ((NXT(len) == '[')) { 10546 /* element name */ 10547 #ifdef DEBUG_STEP 10548 xmlGenericError(xmlGenericErrorContext, 10549 "PathExpr: AbbrRelLocation\n"); 10550 #endif 10551 lc = 1; 10552 break; 10553 } else if ((NXT(len) == '<') || (NXT(len) == '>') || 10554 (NXT(len) == '=')) { 10555 lc = 1; 10556 break; 10557 } else { 10558 lc = 1; 10559 break; 10560 } 10561 len++; 10562 } 10563 if (NXT(len) == 0) { 10564 #ifdef DEBUG_STEP 10565 xmlGenericError(xmlGenericErrorContext, 10566 "PathExpr: AbbrRelLocation\n"); 10567 #endif 10568 /* element name */ 10569 lc = 1; 10570 } 10571 xmlFree(name); 10572 } else { 10573 /* make sure all cases are covered explicitly */ 10574 XP_ERROR(XPATH_EXPR_ERROR); 10575 } 10576 } 10577 10578 if (lc) { 10579 if (CUR == '/') { 10580 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0); 10581 } else { 10582 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0); 10583 } 10584 xmlXPathCompLocationPath(ctxt); 10585 } else { 10586 xmlXPathCompFilterExpr(ctxt); 10587 CHECK_ERROR; 10588 if ((CUR == '/') && (NXT(1) == '/')) { 10589 SKIP(2); 10590 SKIP_BLANKS; 10591 10592 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 10593 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 10594 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0); 10595 10596 xmlXPathCompRelativeLocationPath(ctxt); 10597 } else if (CUR == '/') { 10598 xmlXPathCompRelativeLocationPath(ctxt); 10599 } 10600 } 10601 SKIP_BLANKS; 10602 } 10603 10604 /** 10605 * xmlXPathCompUnionExpr: 10606 * @ctxt: the XPath Parser context 10607 * 10608 * [18] UnionExpr ::= PathExpr 10609 * | UnionExpr '|' PathExpr 10610 * 10611 * Compile an union expression. 10612 */ 10613 10614 static void 10615 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) { 10616 xmlXPathCompPathExpr(ctxt); 10617 CHECK_ERROR; 10618 SKIP_BLANKS; 10619 while (CUR == '|') { 10620 int op1 = ctxt->comp->last; 10621 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0); 10622 10623 NEXT; 10624 SKIP_BLANKS; 10625 xmlXPathCompPathExpr(ctxt); 10626 10627 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0); 10628 10629 SKIP_BLANKS; 10630 } 10631 } 10632 10633 /** 10634 * xmlXPathCompUnaryExpr: 10635 * @ctxt: the XPath Parser context 10636 * 10637 * [27] UnaryExpr ::= UnionExpr 10638 * | '-' UnaryExpr 10639 * 10640 * Compile an unary expression. 10641 */ 10642 10643 static void 10644 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) { 10645 int minus = 0; 10646 int found = 0; 10647 10648 SKIP_BLANKS; 10649 while (CUR == '-') { 10650 minus = 1 - minus; 10651 found = 1; 10652 NEXT; 10653 SKIP_BLANKS; 10654 } 10655 10656 xmlXPathCompUnionExpr(ctxt); 10657 CHECK_ERROR; 10658 if (found) { 10659 if (minus) 10660 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0); 10661 else 10662 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0); 10663 } 10664 } 10665 10666 /** 10667 * xmlXPathCompMultiplicativeExpr: 10668 * @ctxt: the XPath Parser context 10669 * 10670 * [26] MultiplicativeExpr ::= UnaryExpr 10671 * | MultiplicativeExpr MultiplyOperator UnaryExpr 10672 * | MultiplicativeExpr 'div' UnaryExpr 10673 * | MultiplicativeExpr 'mod' UnaryExpr 10674 * [34] MultiplyOperator ::= '*' 10675 * 10676 * Compile an Additive expression. 10677 */ 10678 10679 static void 10680 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) { 10681 xmlXPathCompUnaryExpr(ctxt); 10682 CHECK_ERROR; 10683 SKIP_BLANKS; 10684 while ((CUR == '*') || 10685 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) || 10686 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) { 10687 int op = -1; 10688 int op1 = ctxt->comp->last; 10689 10690 if (CUR == '*') { 10691 op = 0; 10692 NEXT; 10693 } else if (CUR == 'd') { 10694 op = 1; 10695 SKIP(3); 10696 } else if (CUR == 'm') { 10697 op = 2; 10698 SKIP(3); 10699 } 10700 SKIP_BLANKS; 10701 xmlXPathCompUnaryExpr(ctxt); 10702 CHECK_ERROR; 10703 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0); 10704 SKIP_BLANKS; 10705 } 10706 } 10707 10708 /** 10709 * xmlXPathCompAdditiveExpr: 10710 * @ctxt: the XPath Parser context 10711 * 10712 * [25] AdditiveExpr ::= MultiplicativeExpr 10713 * | AdditiveExpr '+' MultiplicativeExpr 10714 * | AdditiveExpr '-' MultiplicativeExpr 10715 * 10716 * Compile an Additive expression. 10717 */ 10718 10719 static void 10720 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) { 10721 10722 xmlXPathCompMultiplicativeExpr(ctxt); 10723 CHECK_ERROR; 10724 SKIP_BLANKS; 10725 while ((CUR == '+') || (CUR == '-')) { 10726 int plus; 10727 int op1 = ctxt->comp->last; 10728 10729 if (CUR == '+') plus = 1; 10730 else plus = 0; 10731 NEXT; 10732 SKIP_BLANKS; 10733 xmlXPathCompMultiplicativeExpr(ctxt); 10734 CHECK_ERROR; 10735 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0); 10736 SKIP_BLANKS; 10737 } 10738 } 10739 10740 /** 10741 * xmlXPathCompRelationalExpr: 10742 * @ctxt: the XPath Parser context 10743 * 10744 * [24] RelationalExpr ::= AdditiveExpr 10745 * | RelationalExpr '<' AdditiveExpr 10746 * | RelationalExpr '>' AdditiveExpr 10747 * | RelationalExpr '<=' AdditiveExpr 10748 * | RelationalExpr '>=' AdditiveExpr 10749 * 10750 * A <= B > C is allowed ? Answer from James, yes with 10751 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr 10752 * which is basically what got implemented. 10753 * 10754 * Compile a Relational expression, then push the result 10755 * on the stack 10756 */ 10757 10758 static void 10759 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) { 10760 xmlXPathCompAdditiveExpr(ctxt); 10761 CHECK_ERROR; 10762 SKIP_BLANKS; 10763 while ((CUR == '<') || 10764 (CUR == '>') || 10765 ((CUR == '<') && (NXT(1) == '=')) || 10766 ((CUR == '>') && (NXT(1) == '='))) { 10767 int inf, strict; 10768 int op1 = ctxt->comp->last; 10769 10770 if (CUR == '<') inf = 1; 10771 else inf = 0; 10772 if (NXT(1) == '=') strict = 0; 10773 else strict = 1; 10774 NEXT; 10775 if (!strict) NEXT; 10776 SKIP_BLANKS; 10777 xmlXPathCompAdditiveExpr(ctxt); 10778 CHECK_ERROR; 10779 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict); 10780 SKIP_BLANKS; 10781 } 10782 } 10783 10784 /** 10785 * xmlXPathCompEqualityExpr: 10786 * @ctxt: the XPath Parser context 10787 * 10788 * [23] EqualityExpr ::= RelationalExpr 10789 * | EqualityExpr '=' RelationalExpr 10790 * | EqualityExpr '!=' RelationalExpr 10791 * 10792 * A != B != C is allowed ? Answer from James, yes with 10793 * (RelationalExpr = RelationalExpr) = RelationalExpr 10794 * (RelationalExpr != RelationalExpr) != RelationalExpr 10795 * which is basically what got implemented. 10796 * 10797 * Compile an Equality expression. 10798 * 10799 */ 10800 static void 10801 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) { 10802 xmlXPathCompRelationalExpr(ctxt); 10803 CHECK_ERROR; 10804 SKIP_BLANKS; 10805 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) { 10806 int eq; 10807 int op1 = ctxt->comp->last; 10808 10809 if (CUR == '=') eq = 1; 10810 else eq = 0; 10811 NEXT; 10812 if (!eq) NEXT; 10813 SKIP_BLANKS; 10814 xmlXPathCompRelationalExpr(ctxt); 10815 CHECK_ERROR; 10816 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0); 10817 SKIP_BLANKS; 10818 } 10819 } 10820 10821 /** 10822 * xmlXPathCompAndExpr: 10823 * @ctxt: the XPath Parser context 10824 * 10825 * [22] AndExpr ::= EqualityExpr 10826 * | AndExpr 'and' EqualityExpr 10827 * 10828 * Compile an AND expression. 10829 * 10830 */ 10831 static void 10832 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) { 10833 xmlXPathCompEqualityExpr(ctxt); 10834 CHECK_ERROR; 10835 SKIP_BLANKS; 10836 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) { 10837 int op1 = ctxt->comp->last; 10838 SKIP(3); 10839 SKIP_BLANKS; 10840 xmlXPathCompEqualityExpr(ctxt); 10841 CHECK_ERROR; 10842 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0); 10843 SKIP_BLANKS; 10844 } 10845 } 10846 10847 /** 10848 * xmlXPathCompileExpr: 10849 * @ctxt: the XPath Parser context 10850 * 10851 * [14] Expr ::= OrExpr 10852 * [21] OrExpr ::= AndExpr 10853 * | OrExpr 'or' AndExpr 10854 * 10855 * Parse and compile an expression 10856 */ 10857 static void 10858 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) { 10859 xmlXPathCompAndExpr(ctxt); 10860 CHECK_ERROR; 10861 SKIP_BLANKS; 10862 while ((CUR == 'o') && (NXT(1) == 'r')) { 10863 int op1 = ctxt->comp->last; 10864 SKIP(2); 10865 SKIP_BLANKS; 10866 xmlXPathCompAndExpr(ctxt); 10867 CHECK_ERROR; 10868 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0); 10869 op1 = ctxt->comp->nbStep; 10870 SKIP_BLANKS; 10871 } 10872 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) { 10873 /* more ops could be optimized too */ 10874 /* 10875 * This is the main place to eliminate sorting for 10876 * operations which don't require a sorted node-set. 10877 * E.g. count(). 10878 */ 10879 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0); 10880 } 10881 } 10882 10883 /** 10884 * xmlXPathCompPredicate: 10885 * @ctxt: the XPath Parser context 10886 * @filter: act as a filter 10887 * 10888 * [8] Predicate ::= '[' PredicateExpr ']' 10889 * [9] PredicateExpr ::= Expr 10890 * 10891 * Compile a predicate expression 10892 */ 10893 static void 10894 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) { 10895 int op1 = ctxt->comp->last; 10896 10897 SKIP_BLANKS; 10898 if (CUR != '[') { 10899 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); 10900 } 10901 NEXT; 10902 SKIP_BLANKS; 10903 10904 ctxt->comp->last = -1; 10905 /* 10906 * This call to xmlXPathCompileExpr() will deactivate sorting 10907 * of the predicate result. 10908 * TODO: Sorting is still activated for filters, since I'm not 10909 * sure if needed. Normally sorting should not be needed, since 10910 * a filter can only diminish the number of items in a sequence, 10911 * but won't change its order; so if the initial sequence is sorted, 10912 * subsequent sorting is not needed. 10913 */ 10914 if (! filter) 10915 xmlXPathCompileExpr(ctxt, 0); 10916 else 10917 xmlXPathCompileExpr(ctxt, 1); 10918 CHECK_ERROR; 10919 10920 if (CUR != ']') { 10921 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); 10922 } 10923 10924 if (filter) 10925 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0); 10926 else 10927 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0); 10928 10929 NEXT; 10930 SKIP_BLANKS; 10931 } 10932 10933 /** 10934 * xmlXPathCompNodeTest: 10935 * @ctxt: the XPath Parser context 10936 * @test: pointer to a xmlXPathTestVal 10937 * @type: pointer to a xmlXPathTypeVal 10938 * @prefix: placeholder for a possible name prefix 10939 * 10940 * [7] NodeTest ::= NameTest 10941 * | NodeType '(' ')' 10942 * | 'processing-instruction' '(' Literal ')' 10943 * 10944 * [37] NameTest ::= '*' 10945 * | NCName ':' '*' 10946 * | QName 10947 * [38] NodeType ::= 'comment' 10948 * | 'text' 10949 * | 'processing-instruction' 10950 * | 'node' 10951 * 10952 * Returns the name found and updates @test, @type and @prefix appropriately 10953 */ 10954 static xmlChar * 10955 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test, 10956 xmlXPathTypeVal *type, const xmlChar **prefix, 10957 xmlChar *name) { 10958 int blanks; 10959 10960 if ((test == NULL) || (type == NULL) || (prefix == NULL)) { 10961 STRANGE; 10962 return(NULL); 10963 } 10964 *type = (xmlXPathTypeVal) 0; 10965 *test = (xmlXPathTestVal) 0; 10966 *prefix = NULL; 10967 SKIP_BLANKS; 10968 10969 if ((name == NULL) && (CUR == '*')) { 10970 /* 10971 * All elements 10972 */ 10973 NEXT; 10974 *test = NODE_TEST_ALL; 10975 return(NULL); 10976 } 10977 10978 if (name == NULL) 10979 name = xmlXPathParseNCName(ctxt); 10980 if (name == NULL) { 10981 XP_ERRORNULL(XPATH_EXPR_ERROR); 10982 } 10983 10984 blanks = IS_BLANK_CH(CUR); 10985 SKIP_BLANKS; 10986 if (CUR == '(') { 10987 NEXT; 10988 /* 10989 * NodeType or PI search 10990 */ 10991 if (xmlStrEqual(name, BAD_CAST "comment")) 10992 *type = NODE_TYPE_COMMENT; 10993 else if (xmlStrEqual(name, BAD_CAST "node")) 10994 *type = NODE_TYPE_NODE; 10995 else if (xmlStrEqual(name, BAD_CAST "processing-instruction")) 10996 *type = NODE_TYPE_PI; 10997 else if (xmlStrEqual(name, BAD_CAST "text")) 10998 *type = NODE_TYPE_TEXT; 10999 else { 11000 if (name != NULL) 11001 xmlFree(name); 11002 XP_ERRORNULL(XPATH_EXPR_ERROR); 11003 } 11004 11005 *test = NODE_TEST_TYPE; 11006 11007 SKIP_BLANKS; 11008 if (*type == NODE_TYPE_PI) { 11009 /* 11010 * Specific case: search a PI by name. 11011 */ 11012 if (name != NULL) 11013 xmlFree(name); 11014 name = NULL; 11015 if (CUR != ')') { 11016 name = xmlXPathParseLiteral(ctxt); 11017 CHECK_ERROR NULL; 11018 *test = NODE_TEST_PI; 11019 SKIP_BLANKS; 11020 } 11021 } 11022 if (CUR != ')') { 11023 if (name != NULL) 11024 xmlFree(name); 11025 XP_ERRORNULL(XPATH_UNCLOSED_ERROR); 11026 } 11027 NEXT; 11028 return(name); 11029 } 11030 *test = NODE_TEST_NAME; 11031 if ((!blanks) && (CUR == ':')) { 11032 NEXT; 11033 11034 /* 11035 * Since currently the parser context don't have a 11036 * namespace list associated: 11037 * The namespace name for this prefix can be computed 11038 * only at evaluation time. The compilation is done 11039 * outside of any context. 11040 */ 11041 #if 0 11042 *prefix = xmlXPathNsLookup(ctxt->context, name); 11043 if (name != NULL) 11044 xmlFree(name); 11045 if (*prefix == NULL) { 11046 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); 11047 } 11048 #else 11049 *prefix = name; 11050 #endif 11051 11052 if (CUR == '*') { 11053 /* 11054 * All elements 11055 */ 11056 NEXT; 11057 *test = NODE_TEST_ALL; 11058 return(NULL); 11059 } 11060 11061 name = xmlXPathParseNCName(ctxt); 11062 if (name == NULL) { 11063 XP_ERRORNULL(XPATH_EXPR_ERROR); 11064 } 11065 } 11066 return(name); 11067 } 11068 11069 /** 11070 * xmlXPathIsAxisName: 11071 * @name: a preparsed name token 11072 * 11073 * [6] AxisName ::= 'ancestor' 11074 * | 'ancestor-or-self' 11075 * | 'attribute' 11076 * | 'child' 11077 * | 'descendant' 11078 * | 'descendant-or-self' 11079 * | 'following' 11080 * | 'following-sibling' 11081 * | 'namespace' 11082 * | 'parent' 11083 * | 'preceding' 11084 * | 'preceding-sibling' 11085 * | 'self' 11086 * 11087 * Returns the axis or 0 11088 */ 11089 static xmlXPathAxisVal 11090 xmlXPathIsAxisName(const xmlChar *name) { 11091 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0; 11092 switch (name[0]) { 11093 case 'a': 11094 if (xmlStrEqual(name, BAD_CAST "ancestor")) 11095 ret = AXIS_ANCESTOR; 11096 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self")) 11097 ret = AXIS_ANCESTOR_OR_SELF; 11098 if (xmlStrEqual(name, BAD_CAST "attribute")) 11099 ret = AXIS_ATTRIBUTE; 11100 break; 11101 case 'c': 11102 if (xmlStrEqual(name, BAD_CAST "child")) 11103 ret = AXIS_CHILD; 11104 break; 11105 case 'd': 11106 if (xmlStrEqual(name, BAD_CAST "descendant")) 11107 ret = AXIS_DESCENDANT; 11108 if (xmlStrEqual(name, BAD_CAST "descendant-or-self")) 11109 ret = AXIS_DESCENDANT_OR_SELF; 11110 break; 11111 case 'f': 11112 if (xmlStrEqual(name, BAD_CAST "following")) 11113 ret = AXIS_FOLLOWING; 11114 if (xmlStrEqual(name, BAD_CAST "following-sibling")) 11115 ret = AXIS_FOLLOWING_SIBLING; 11116 break; 11117 case 'n': 11118 if (xmlStrEqual(name, BAD_CAST "namespace")) 11119 ret = AXIS_NAMESPACE; 11120 break; 11121 case 'p': 11122 if (xmlStrEqual(name, BAD_CAST "parent")) 11123 ret = AXIS_PARENT; 11124 if (xmlStrEqual(name, BAD_CAST "preceding")) 11125 ret = AXIS_PRECEDING; 11126 if (xmlStrEqual(name, BAD_CAST "preceding-sibling")) 11127 ret = AXIS_PRECEDING_SIBLING; 11128 break; 11129 case 's': 11130 if (xmlStrEqual(name, BAD_CAST "self")) 11131 ret = AXIS_SELF; 11132 break; 11133 } 11134 return(ret); 11135 } 11136 11137 /** 11138 * xmlXPathCompStep: 11139 * @ctxt: the XPath Parser context 11140 * 11141 * [4] Step ::= AxisSpecifier NodeTest Predicate* 11142 * | AbbreviatedStep 11143 * 11144 * [12] AbbreviatedStep ::= '.' | '..' 11145 * 11146 * [5] AxisSpecifier ::= AxisName '::' 11147 * | AbbreviatedAxisSpecifier 11148 * 11149 * [13] AbbreviatedAxisSpecifier ::= '@'? 11150 * 11151 * Modified for XPtr range support as: 11152 * 11153 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate* 11154 * | AbbreviatedStep 11155 * | 'range-to' '(' Expr ')' Predicate* 11156 * 11157 * Compile one step in a Location Path 11158 * A location step of . is short for self::node(). This is 11159 * particularly useful in conjunction with //. For example, the 11160 * location path .//para is short for 11161 * self::node()/descendant-or-self::node()/child::para 11162 * and so will select all para descendant elements of the context 11163 * node. 11164 * Similarly, a location step of .. is short for parent::node(). 11165 * For example, ../title is short for parent::node()/child::title 11166 * and so will select the title children of the parent of the context 11167 * node. 11168 */ 11169 static void 11170 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) { 11171 #ifdef LIBXML_XPTR_ENABLED 11172 int rangeto = 0; 11173 int op2 = -1; 11174 #endif 11175 11176 SKIP_BLANKS; 11177 if ((CUR == '.') && (NXT(1) == '.')) { 11178 SKIP(2); 11179 SKIP_BLANKS; 11180 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT, 11181 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11182 } else if (CUR == '.') { 11183 NEXT; 11184 SKIP_BLANKS; 11185 } else { 11186 xmlChar *name = NULL; 11187 const xmlChar *prefix = NULL; 11188 xmlXPathTestVal test = (xmlXPathTestVal) 0; 11189 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0; 11190 xmlXPathTypeVal type = (xmlXPathTypeVal) 0; 11191 int op1; 11192 11193 /* 11194 * The modification needed for XPointer change to the production 11195 */ 11196 #ifdef LIBXML_XPTR_ENABLED 11197 if (ctxt->xptr) { 11198 name = xmlXPathParseNCName(ctxt); 11199 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) { 11200 op2 = ctxt->comp->last; 11201 xmlFree(name); 11202 SKIP_BLANKS; 11203 if (CUR != '(') { 11204 XP_ERROR(XPATH_EXPR_ERROR); 11205 } 11206 NEXT; 11207 SKIP_BLANKS; 11208 11209 xmlXPathCompileExpr(ctxt, 1); 11210 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */ 11211 CHECK_ERROR; 11212 11213 SKIP_BLANKS; 11214 if (CUR != ')') { 11215 XP_ERROR(XPATH_EXPR_ERROR); 11216 } 11217 NEXT; 11218 rangeto = 1; 11219 goto eval_predicates; 11220 } 11221 } 11222 #endif 11223 if (CUR == '*') { 11224 axis = AXIS_CHILD; 11225 } else { 11226 if (name == NULL) 11227 name = xmlXPathParseNCName(ctxt); 11228 if (name != NULL) { 11229 axis = xmlXPathIsAxisName(name); 11230 if (axis != 0) { 11231 SKIP_BLANKS; 11232 if ((CUR == ':') && (NXT(1) == ':')) { 11233 SKIP(2); 11234 xmlFree(name); 11235 name = NULL; 11236 } else { 11237 /* an element name can conflict with an axis one :-\ */ 11238 axis = AXIS_CHILD; 11239 } 11240 } else { 11241 axis = AXIS_CHILD; 11242 } 11243 } else if (CUR == '@') { 11244 NEXT; 11245 axis = AXIS_ATTRIBUTE; 11246 } else { 11247 axis = AXIS_CHILD; 11248 } 11249 } 11250 11251 CHECK_ERROR; 11252 11253 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name); 11254 if (test == 0) 11255 return; 11256 11257 if ((prefix != NULL) && (ctxt->context != NULL) && 11258 (ctxt->context->flags & XML_XPATH_CHECKNS)) { 11259 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) { 11260 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR); 11261 } 11262 } 11263 #ifdef DEBUG_STEP 11264 xmlGenericError(xmlGenericErrorContext, 11265 "Basis : computing new set\n"); 11266 #endif 11267 11268 #ifdef DEBUG_STEP 11269 xmlGenericError(xmlGenericErrorContext, "Basis : "); 11270 if (ctxt->value == NULL) 11271 xmlGenericError(xmlGenericErrorContext, "no value\n"); 11272 else if (ctxt->value->nodesetval == NULL) 11273 xmlGenericError(xmlGenericErrorContext, "Empty\n"); 11274 else 11275 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval); 11276 #endif 11277 11278 #ifdef LIBXML_XPTR_ENABLED 11279 eval_predicates: 11280 #endif 11281 op1 = ctxt->comp->last; 11282 ctxt->comp->last = -1; 11283 11284 SKIP_BLANKS; 11285 while (CUR == '[') { 11286 xmlXPathCompPredicate(ctxt, 0); 11287 } 11288 11289 #ifdef LIBXML_XPTR_ENABLED 11290 if (rangeto) { 11291 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0); 11292 } else 11293 #endif 11294 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis, 11295 test, type, (void *)prefix, (void *)name); 11296 11297 } 11298 #ifdef DEBUG_STEP 11299 xmlGenericError(xmlGenericErrorContext, "Step : "); 11300 if (ctxt->value == NULL) 11301 xmlGenericError(xmlGenericErrorContext, "no value\n"); 11302 else if (ctxt->value->nodesetval == NULL) 11303 xmlGenericError(xmlGenericErrorContext, "Empty\n"); 11304 else 11305 xmlGenericErrorContextNodeSet(xmlGenericErrorContext, 11306 ctxt->value->nodesetval); 11307 #endif 11308 } 11309 11310 /** 11311 * xmlXPathCompRelativeLocationPath: 11312 * @ctxt: the XPath Parser context 11313 * 11314 * [3] RelativeLocationPath ::= Step 11315 * | RelativeLocationPath '/' Step 11316 * | AbbreviatedRelativeLocationPath 11317 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step 11318 * 11319 * Compile a relative location path. 11320 */ 11321 static void 11322 xmlXPathCompRelativeLocationPath 11323 (xmlXPathParserContextPtr ctxt) { 11324 SKIP_BLANKS; 11325 if ((CUR == '/') && (NXT(1) == '/')) { 11326 SKIP(2); 11327 SKIP_BLANKS; 11328 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 11329 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11330 } else if (CUR == '/') { 11331 NEXT; 11332 SKIP_BLANKS; 11333 } 11334 xmlXPathCompStep(ctxt); 11335 SKIP_BLANKS; 11336 while (CUR == '/') { 11337 if ((CUR == '/') && (NXT(1) == '/')) { 11338 SKIP(2); 11339 SKIP_BLANKS; 11340 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 11341 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11342 xmlXPathCompStep(ctxt); 11343 } else if (CUR == '/') { 11344 NEXT; 11345 SKIP_BLANKS; 11346 xmlXPathCompStep(ctxt); 11347 } 11348 SKIP_BLANKS; 11349 } 11350 } 11351 11352 /** 11353 * xmlXPathCompLocationPath: 11354 * @ctxt: the XPath Parser context 11355 * 11356 * [1] LocationPath ::= RelativeLocationPath 11357 * | AbsoluteLocationPath 11358 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath? 11359 * | AbbreviatedAbsoluteLocationPath 11360 * [10] AbbreviatedAbsoluteLocationPath ::= 11361 * '//' RelativeLocationPath 11362 * 11363 * Compile a location path 11364 * 11365 * // is short for /descendant-or-self::node()/. For example, 11366 * //para is short for /descendant-or-self::node()/child::para and 11367 * so will select any para element in the document (even a para element 11368 * that is a document element will be selected by //para since the 11369 * document element node is a child of the root node); div//para is 11370 * short for div/descendant-or-self::node()/child::para and so will 11371 * select all para descendants of div children. 11372 */ 11373 static void 11374 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) { 11375 SKIP_BLANKS; 11376 if (CUR != '/') { 11377 xmlXPathCompRelativeLocationPath(ctxt); 11378 } else { 11379 while (CUR == '/') { 11380 if ((CUR == '/') && (NXT(1) == '/')) { 11381 SKIP(2); 11382 SKIP_BLANKS; 11383 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 11384 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11385 xmlXPathCompRelativeLocationPath(ctxt); 11386 } else if (CUR == '/') { 11387 NEXT; 11388 SKIP_BLANKS; 11389 if ((CUR != 0 ) && 11390 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') || 11391 (CUR == '@') || (CUR == '*'))) 11392 xmlXPathCompRelativeLocationPath(ctxt); 11393 } 11394 } 11395 } 11396 } 11397 11398 /************************************************************************ 11399 * * 11400 * XPath precompiled expression evaluation * 11401 * * 11402 ************************************************************************/ 11403 11404 static int 11405 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op); 11406 11407 #ifdef DEBUG_STEP 11408 static void 11409 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op, 11410 int nbNodes) 11411 { 11412 xmlGenericError(xmlGenericErrorContext, "new step : "); 11413 switch (op->value) { 11414 case AXIS_ANCESTOR: 11415 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' "); 11416 break; 11417 case AXIS_ANCESTOR_OR_SELF: 11418 xmlGenericError(xmlGenericErrorContext, 11419 "axis 'ancestors-or-self' "); 11420 break; 11421 case AXIS_ATTRIBUTE: 11422 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' "); 11423 break; 11424 case AXIS_CHILD: 11425 xmlGenericError(xmlGenericErrorContext, "axis 'child' "); 11426 break; 11427 case AXIS_DESCENDANT: 11428 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' "); 11429 break; 11430 case AXIS_DESCENDANT_OR_SELF: 11431 xmlGenericError(xmlGenericErrorContext, 11432 "axis 'descendant-or-self' "); 11433 break; 11434 case AXIS_FOLLOWING: 11435 xmlGenericError(xmlGenericErrorContext, "axis 'following' "); 11436 break; 11437 case AXIS_FOLLOWING_SIBLING: 11438 xmlGenericError(xmlGenericErrorContext, 11439 "axis 'following-siblings' "); 11440 break; 11441 case AXIS_NAMESPACE: 11442 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' "); 11443 break; 11444 case AXIS_PARENT: 11445 xmlGenericError(xmlGenericErrorContext, "axis 'parent' "); 11446 break; 11447 case AXIS_PRECEDING: 11448 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' "); 11449 break; 11450 case AXIS_PRECEDING_SIBLING: 11451 xmlGenericError(xmlGenericErrorContext, 11452 "axis 'preceding-sibling' "); 11453 break; 11454 case AXIS_SELF: 11455 xmlGenericError(xmlGenericErrorContext, "axis 'self' "); 11456 break; 11457 } 11458 xmlGenericError(xmlGenericErrorContext, 11459 " context contains %d nodes\n", nbNodes); 11460 switch (op->value2) { 11461 case NODE_TEST_NONE: 11462 xmlGenericError(xmlGenericErrorContext, 11463 " searching for none !!!\n"); 11464 break; 11465 case NODE_TEST_TYPE: 11466 xmlGenericError(xmlGenericErrorContext, 11467 " searching for type %d\n", op->value3); 11468 break; 11469 case NODE_TEST_PI: 11470 xmlGenericError(xmlGenericErrorContext, 11471 " searching for PI !!!\n"); 11472 break; 11473 case NODE_TEST_ALL: 11474 xmlGenericError(xmlGenericErrorContext, 11475 " searching for *\n"); 11476 break; 11477 case NODE_TEST_NS: 11478 xmlGenericError(xmlGenericErrorContext, 11479 " searching for namespace %s\n", 11480 op->value5); 11481 break; 11482 case NODE_TEST_NAME: 11483 xmlGenericError(xmlGenericErrorContext, 11484 " searching for name %s\n", op->value5); 11485 if (op->value4) 11486 xmlGenericError(xmlGenericErrorContext, 11487 " with namespace %s\n", op->value4); 11488 break; 11489 } 11490 xmlGenericError(xmlGenericErrorContext, "Testing : "); 11491 } 11492 #endif /* DEBUG_STEP */ 11493 11494 static int 11495 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt, 11496 xmlXPathStepOpPtr op, 11497 xmlNodeSetPtr set, 11498 int contextSize, 11499 int hasNsNodes) 11500 { 11501 if (op->ch1 != -1) { 11502 xmlXPathCompExprPtr comp = ctxt->comp; 11503 /* 11504 * Process inner predicates first. 11505 */ 11506 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) { 11507 /* 11508 * TODO: raise an internal error. 11509 */ 11510 } 11511 contextSize = xmlXPathCompOpEvalPredicate(ctxt, 11512 &comp->steps[op->ch1], set, contextSize, hasNsNodes); 11513 CHECK_ERROR0; 11514 if (contextSize <= 0) 11515 return(0); 11516 } 11517 if (op->ch2 != -1) { 11518 xmlXPathContextPtr xpctxt = ctxt->context; 11519 xmlNodePtr contextNode, oldContextNode; 11520 xmlDocPtr oldContextDoc; 11521 int i, res, contextPos = 0, newContextSize; 11522 xmlXPathStepOpPtr exprOp; 11523 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL; 11524 11525 #ifdef LIBXML_XPTR_ENABLED 11526 /* 11527 * URGENT TODO: Check the following: 11528 * We don't expect location sets if evaluating prediates, right? 11529 * Only filters should expect location sets, right? 11530 */ 11531 #endif 11532 /* 11533 * SPEC XPath 1.0: 11534 * "For each node in the node-set to be filtered, the 11535 * PredicateExpr is evaluated with that node as the 11536 * context node, with the number of nodes in the 11537 * node-set as the context size, and with the proximity 11538 * position of the node in the node-set with respect to 11539 * the axis as the context position;" 11540 * @oldset is the node-set" to be filtered. 11541 * 11542 * SPEC XPath 1.0: 11543 * "only predicates change the context position and 11544 * context size (see [2.4 Predicates])." 11545 * Example: 11546 * node-set context pos 11547 * nA 1 11548 * nB 2 11549 * nC 3 11550 * After applying predicate [position() > 1] : 11551 * node-set context pos 11552 * nB 1 11553 * nC 2 11554 */ 11555 oldContextNode = xpctxt->node; 11556 oldContextDoc = xpctxt->doc; 11557 /* 11558 * Get the expression of this predicate. 11559 */ 11560 exprOp = &ctxt->comp->steps[op->ch2]; 11561 newContextSize = 0; 11562 for (i = 0; i < set->nodeNr; i++) { 11563 if (set->nodeTab[i] == NULL) 11564 continue; 11565 11566 contextNode = set->nodeTab[i]; 11567 xpctxt->node = contextNode; 11568 xpctxt->contextSize = contextSize; 11569 xpctxt->proximityPosition = ++contextPos; 11570 11571 /* 11572 * Also set the xpath document in case things like 11573 * key() are evaluated in the predicate. 11574 */ 11575 if ((contextNode->type != XML_NAMESPACE_DECL) && 11576 (contextNode->doc != NULL)) 11577 xpctxt->doc = contextNode->doc; 11578 /* 11579 * Evaluate the predicate expression with 1 context node 11580 * at a time; this node is packaged into a node set; this 11581 * node set is handed over to the evaluation mechanism. 11582 */ 11583 if (contextObj == NULL) 11584 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode); 11585 else 11586 xmlXPathNodeSetAddUnique(contextObj->nodesetval, 11587 contextNode); 11588 11589 valuePush(ctxt, contextObj); 11590 11591 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1); 11592 11593 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) { 11594 xmlXPathNodeSetClear(set, hasNsNodes); 11595 newContextSize = 0; 11596 goto evaluation_exit; 11597 } 11598 11599 if (res != 0) { 11600 newContextSize++; 11601 } else { 11602 /* 11603 * Remove the entry from the initial node set. 11604 */ 11605 set->nodeTab[i] = NULL; 11606 if (contextNode->type == XML_NAMESPACE_DECL) 11607 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode); 11608 } 11609 if (ctxt->value == contextObj) { 11610 /* 11611 * Don't free the temporary XPath object holding the 11612 * context node, in order to avoid massive recreation 11613 * inside this loop. 11614 */ 11615 valuePop(ctxt); 11616 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes); 11617 } else { 11618 /* 11619 * TODO: The object was lost in the evaluation machinery. 11620 * Can this happen? Maybe in internal-error cases. 11621 */ 11622 contextObj = NULL; 11623 } 11624 } 11625 11626 if (contextObj != NULL) { 11627 if (ctxt->value == contextObj) 11628 valuePop(ctxt); 11629 xmlXPathReleaseObject(xpctxt, contextObj); 11630 } 11631 evaluation_exit: 11632 if (exprRes != NULL) 11633 xmlXPathReleaseObject(ctxt->context, exprRes); 11634 /* 11635 * Reset/invalidate the context. 11636 */ 11637 xpctxt->node = oldContextNode; 11638 xpctxt->doc = oldContextDoc; 11639 xpctxt->contextSize = -1; 11640 xpctxt->proximityPosition = -1; 11641 return(newContextSize); 11642 } 11643 return(contextSize); 11644 } 11645 11646 static int 11647 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt, 11648 xmlXPathStepOpPtr op, 11649 xmlNodeSetPtr set, 11650 int contextSize, 11651 int minPos, 11652 int maxPos, 11653 int hasNsNodes) 11654 { 11655 if (op->ch1 != -1) { 11656 xmlXPathCompExprPtr comp = ctxt->comp; 11657 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) { 11658 /* 11659 * TODO: raise an internal error. 11660 */ 11661 } 11662 contextSize = xmlXPathCompOpEvalPredicate(ctxt, 11663 &comp->steps[op->ch1], set, contextSize, hasNsNodes); 11664 CHECK_ERROR0; 11665 if (contextSize <= 0) 11666 return(0); 11667 } 11668 /* 11669 * Check if the node set contains a sufficient number of nodes for 11670 * the requested range. 11671 */ 11672 if (contextSize < minPos) { 11673 xmlXPathNodeSetClear(set, hasNsNodes); 11674 return(0); 11675 } 11676 if (op->ch2 == -1) { 11677 /* 11678 * TODO: Can this ever happen? 11679 */ 11680 return (contextSize); 11681 } else { 11682 xmlDocPtr oldContextDoc; 11683 int i, pos = 0, newContextSize = 0, contextPos = 0, res; 11684 xmlXPathStepOpPtr exprOp; 11685 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL; 11686 xmlNodePtr oldContextNode, contextNode = NULL; 11687 xmlXPathContextPtr xpctxt = ctxt->context; 11688 11689 #ifdef LIBXML_XPTR_ENABLED 11690 /* 11691 * URGENT TODO: Check the following: 11692 * We don't expect location sets if evaluating prediates, right? 11693 * Only filters should expect location sets, right? 11694 */ 11695 #endif /* LIBXML_XPTR_ENABLED */ 11696 11697 /* 11698 * Save old context. 11699 */ 11700 oldContextNode = xpctxt->node; 11701 oldContextDoc = xpctxt->doc; 11702 /* 11703 * Get the expression of this predicate. 11704 */ 11705 exprOp = &ctxt->comp->steps[op->ch2]; 11706 for (i = 0; i < set->nodeNr; i++) { 11707 if (set->nodeTab[i] == NULL) 11708 continue; 11709 11710 contextNode = set->nodeTab[i]; 11711 xpctxt->node = contextNode; 11712 xpctxt->contextSize = contextSize; 11713 xpctxt->proximityPosition = ++contextPos; 11714 11715 /* 11716 * Initialize the new set. 11717 * Also set the xpath document in case things like 11718 * key() evaluation are attempted on the predicate 11719 */ 11720 if ((contextNode->type != XML_NAMESPACE_DECL) && 11721 (contextNode->doc != NULL)) 11722 xpctxt->doc = contextNode->doc; 11723 /* 11724 * Evaluate the predicate expression with 1 context node 11725 * at a time; this node is packaged into a node set; this 11726 * node set is handed over to the evaluation mechanism. 11727 */ 11728 if (contextObj == NULL) 11729 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode); 11730 else 11731 xmlXPathNodeSetAddUnique(contextObj->nodesetval, 11732 contextNode); 11733 11734 valuePush(ctxt, contextObj); 11735 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1); 11736 11737 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) { 11738 xmlXPathObjectPtr tmp; 11739 /* pop the result */ 11740 tmp = valuePop(ctxt); 11741 xmlXPathReleaseObject(xpctxt, tmp); 11742 /* then pop off contextObj, which will be freed later */ 11743 valuePop(ctxt); 11744 goto evaluation_error; 11745 } 11746 11747 if (res) 11748 pos++; 11749 11750 if (res && (pos >= minPos) && (pos <= maxPos)) { 11751 /* 11752 * Fits in the requested range. 11753 */ 11754 newContextSize++; 11755 if (minPos == maxPos) { 11756 /* 11757 * Only 1 node was requested. 11758 */ 11759 if (contextNode->type == XML_NAMESPACE_DECL) { 11760 /* 11761 * As always: take care of those nasty 11762 * namespace nodes. 11763 */ 11764 set->nodeTab[i] = NULL; 11765 } 11766 xmlXPathNodeSetClear(set, hasNsNodes); 11767 set->nodeNr = 1; 11768 set->nodeTab[0] = contextNode; 11769 goto evaluation_exit; 11770 } 11771 if (pos == maxPos) { 11772 /* 11773 * We are done. 11774 */ 11775 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes); 11776 goto evaluation_exit; 11777 } 11778 } else { 11779 /* 11780 * Remove the entry from the initial node set. 11781 */ 11782 set->nodeTab[i] = NULL; 11783 if (contextNode->type == XML_NAMESPACE_DECL) 11784 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode); 11785 } 11786 if (exprRes != NULL) { 11787 xmlXPathReleaseObject(ctxt->context, exprRes); 11788 exprRes = NULL; 11789 } 11790 if (ctxt->value == contextObj) { 11791 /* 11792 * Don't free the temporary XPath object holding the 11793 * context node, in order to avoid massive recreation 11794 * inside this loop. 11795 */ 11796 valuePop(ctxt); 11797 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes); 11798 } else { 11799 /* 11800 * The object was lost in the evaluation machinery. 11801 * Can this happen? Maybe in case of internal-errors. 11802 */ 11803 contextObj = NULL; 11804 } 11805 } 11806 goto evaluation_exit; 11807 11808 evaluation_error: 11809 xmlXPathNodeSetClear(set, hasNsNodes); 11810 newContextSize = 0; 11811 11812 evaluation_exit: 11813 if (contextObj != NULL) { 11814 if (ctxt->value == contextObj) 11815 valuePop(ctxt); 11816 xmlXPathReleaseObject(xpctxt, contextObj); 11817 } 11818 if (exprRes != NULL) 11819 xmlXPathReleaseObject(ctxt->context, exprRes); 11820 /* 11821 * Reset/invalidate the context. 11822 */ 11823 xpctxt->node = oldContextNode; 11824 xpctxt->doc = oldContextDoc; 11825 xpctxt->contextSize = -1; 11826 xpctxt->proximityPosition = -1; 11827 return(newContextSize); 11828 } 11829 return(contextSize); 11830 } 11831 11832 static int 11833 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt, 11834 xmlXPathStepOpPtr op, 11835 int *maxPos) 11836 { 11837 11838 xmlXPathStepOpPtr exprOp; 11839 11840 /* 11841 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet! 11842 */ 11843 11844 /* 11845 * If not -1, then ch1 will point to: 11846 * 1) For predicates (XPATH_OP_PREDICATE): 11847 * - an inner predicate operator 11848 * 2) For filters (XPATH_OP_FILTER): 11849 * - an inner filter operater OR 11850 * - an expression selecting the node set. 11851 * E.g. "key('a', 'b')" or "(//foo | //bar)". 11852 */ 11853 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER)) 11854 return(0); 11855 11856 if (op->ch2 != -1) { 11857 exprOp = &ctxt->comp->steps[op->ch2]; 11858 } else 11859 return(0); 11860 11861 if ((exprOp != NULL) && 11862 (exprOp->op == XPATH_OP_VALUE) && 11863 (exprOp->value4 != NULL) && 11864 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER)) 11865 { 11866 /* 11867 * We have a "[n]" predicate here. 11868 * TODO: Unfortunately this simplistic test here is not 11869 * able to detect a position() predicate in compound 11870 * expressions like "[@attr = 'a" and position() = 1], 11871 * and even not the usage of position() in 11872 * "[position() = 1]"; thus - obviously - a position-range, 11873 * like it "[position() < 5]", is also not detected. 11874 * Maybe we could rewrite the AST to ease the optimization. 11875 */ 11876 *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval; 11877 11878 if (((xmlXPathObjectPtr) exprOp->value4)->floatval == 11879 (float) *maxPos) 11880 { 11881 return(1); 11882 } 11883 } 11884 return(0); 11885 } 11886 11887 static int 11888 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, 11889 xmlXPathStepOpPtr op, 11890 xmlNodePtr * first, xmlNodePtr * last, 11891 int toBool) 11892 { 11893 11894 #define XP_TEST_HIT \ 11895 if (hasAxisRange != 0) { \ 11896 if (++pos == maxPos) { \ 11897 addNode(seq, cur); \ 11898 goto axis_range_end; } \ 11899 } else { \ 11900 addNode(seq, cur); \ 11901 if (breakOnFirstHit) goto first_hit; } 11902 11903 #define XP_TEST_HIT_NS \ 11904 if (hasAxisRange != 0) { \ 11905 if (++pos == maxPos) { \ 11906 hasNsNodes = 1; \ 11907 xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \ 11908 goto axis_range_end; } \ 11909 } else { \ 11910 hasNsNodes = 1; \ 11911 xmlXPathNodeSetAddNs(seq, \ 11912 xpctxt->node, (xmlNsPtr) cur); \ 11913 if (breakOnFirstHit) goto first_hit; } 11914 11915 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value; 11916 xmlXPathTestVal test = (xmlXPathTestVal) op->value2; 11917 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3; 11918 const xmlChar *prefix = op->value4; 11919 const xmlChar *name = op->value5; 11920 const xmlChar *URI = NULL; 11921 11922 #ifdef DEBUG_STEP 11923 int nbMatches = 0, prevMatches = 0; 11924 #endif 11925 int total = 0, hasNsNodes = 0; 11926 /* The popped object holding the context nodes */ 11927 xmlXPathObjectPtr obj; 11928 /* The set of context nodes for the node tests */ 11929 xmlNodeSetPtr contextSeq; 11930 int contextIdx; 11931 xmlNodePtr contextNode; 11932 /* The context node for a compound traversal */ 11933 xmlNodePtr outerContextNode; 11934 /* The final resulting node set wrt to all context nodes */ 11935 xmlNodeSetPtr outSeq; 11936 /* 11937 * The temporary resulting node set wrt 1 context node. 11938 * Used to feed predicate evaluation. 11939 */ 11940 xmlNodeSetPtr seq; 11941 xmlNodePtr cur; 11942 /* First predicate operator */ 11943 xmlXPathStepOpPtr predOp; 11944 int maxPos; /* The requested position() (when a "[n]" predicate) */ 11945 int hasPredicateRange, hasAxisRange, pos, size, newSize; 11946 int breakOnFirstHit; 11947 11948 xmlXPathTraversalFunction next = NULL; 11949 /* compound axis traversal */ 11950 xmlXPathTraversalFunctionExt outerNext = NULL; 11951 void (*addNode) (xmlNodeSetPtr, xmlNodePtr); 11952 xmlXPathNodeSetMergeFunction mergeAndClear; 11953 xmlNodePtr oldContextNode; 11954 xmlXPathContextPtr xpctxt = ctxt->context; 11955 11956 11957 CHECK_TYPE0(XPATH_NODESET); 11958 obj = valuePop(ctxt); 11959 /* 11960 * Setup namespaces. 11961 */ 11962 if (prefix != NULL) { 11963 URI = xmlXPathNsLookup(xpctxt, prefix); 11964 if (URI == NULL) { 11965 xmlXPathReleaseObject(xpctxt, obj); 11966 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); 11967 } 11968 } 11969 /* 11970 * Setup axis. 11971 * 11972 * MAYBE FUTURE TODO: merging optimizations: 11973 * - If the nodes to be traversed wrt to the initial nodes and 11974 * the current axis cannot overlap, then we could avoid searching 11975 * for duplicates during the merge. 11976 * But the question is how/when to evaluate if they cannot overlap. 11977 * Example: if we know that for two initial nodes, the one is 11978 * not in the ancestor-or-self axis of the other, then we could safely 11979 * avoid a duplicate-aware merge, if the axis to be traversed is e.g. 11980 * the descendant-or-self axis. 11981 */ 11982 addNode = xmlXPathNodeSetAdd; 11983 mergeAndClear = xmlXPathNodeSetMergeAndClear; 11984 switch (axis) { 11985 case AXIS_ANCESTOR: 11986 first = NULL; 11987 next = xmlXPathNextAncestor; 11988 break; 11989 case AXIS_ANCESTOR_OR_SELF: 11990 first = NULL; 11991 next = xmlXPathNextAncestorOrSelf; 11992 break; 11993 case AXIS_ATTRIBUTE: 11994 first = NULL; 11995 last = NULL; 11996 next = xmlXPathNextAttribute; 11997 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 11998 break; 11999 case AXIS_CHILD: 12000 last = NULL; 12001 if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) { 12002 /* 12003 * This iterator will give us only nodes which can 12004 * hold element nodes. 12005 */ 12006 outerNext = xmlXPathNextDescendantOrSelfElemParent; 12007 } 12008 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) && 12009 (type == NODE_TYPE_NODE)) 12010 { 12011 /* 12012 * Optimization if an element node type is 'element'. 12013 */ 12014 next = xmlXPathNextChildElement; 12015 } else 12016 next = xmlXPathNextChild; 12017 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12018 break; 12019 case AXIS_DESCENDANT: 12020 last = NULL; 12021 next = xmlXPathNextDescendant; 12022 break; 12023 case AXIS_DESCENDANT_OR_SELF: 12024 last = NULL; 12025 next = xmlXPathNextDescendantOrSelf; 12026 break; 12027 case AXIS_FOLLOWING: 12028 last = NULL; 12029 next = xmlXPathNextFollowing; 12030 break; 12031 case AXIS_FOLLOWING_SIBLING: 12032 last = NULL; 12033 next = xmlXPathNextFollowingSibling; 12034 break; 12035 case AXIS_NAMESPACE: 12036 first = NULL; 12037 last = NULL; 12038 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; 12039 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12040 break; 12041 case AXIS_PARENT: 12042 first = NULL; 12043 next = xmlXPathNextParent; 12044 break; 12045 case AXIS_PRECEDING: 12046 first = NULL; 12047 next = xmlXPathNextPrecedingInternal; 12048 break; 12049 case AXIS_PRECEDING_SIBLING: 12050 first = NULL; 12051 next = xmlXPathNextPrecedingSibling; 12052 break; 12053 case AXIS_SELF: 12054 first = NULL; 12055 last = NULL; 12056 next = xmlXPathNextSelf; 12057 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12058 break; 12059 } 12060 12061 #ifdef DEBUG_STEP 12062 xmlXPathDebugDumpStepAxis(op, 12063 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0); 12064 #endif 12065 12066 if (next == NULL) { 12067 xmlXPathReleaseObject(xpctxt, obj); 12068 return(0); 12069 } 12070 contextSeq = obj->nodesetval; 12071 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) { 12072 xmlXPathReleaseObject(xpctxt, obj); 12073 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL)); 12074 return(0); 12075 } 12076 /* 12077 * Predicate optimization --------------------------------------------- 12078 * If this step has a last predicate, which contains a position(), 12079 * then we'll optimize (although not exactly "position()", but only 12080 * the short-hand form, i.e., "[n]". 12081 * 12082 * Example - expression "/foo[parent::bar][1]": 12083 * 12084 * COLLECT 'child' 'name' 'node' foo -- op (we are here) 12085 * ROOT -- op->ch1 12086 * PREDICATE -- op->ch2 (predOp) 12087 * PREDICATE -- predOp->ch1 = [parent::bar] 12088 * SORT 12089 * COLLECT 'parent' 'name' 'node' bar 12090 * NODE 12091 * ELEM Object is a number : 1 -- predOp->ch2 = [1] 12092 * 12093 */ 12094 maxPos = 0; 12095 predOp = NULL; 12096 hasPredicateRange = 0; 12097 hasAxisRange = 0; 12098 if (op->ch2 != -1) { 12099 /* 12100 * There's at least one predicate. 16 == XPATH_OP_PREDICATE 12101 */ 12102 predOp = &ctxt->comp->steps[op->ch2]; 12103 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) { 12104 if (predOp->ch1 != -1) { 12105 /* 12106 * Use the next inner predicate operator. 12107 */ 12108 predOp = &ctxt->comp->steps[predOp->ch1]; 12109 hasPredicateRange = 1; 12110 } else { 12111 /* 12112 * There's no other predicate than the [n] predicate. 12113 */ 12114 predOp = NULL; 12115 hasAxisRange = 1; 12116 } 12117 } 12118 } 12119 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0; 12120 /* 12121 * Axis traversal ----------------------------------------------------- 12122 */ 12123 /* 12124 * 2.3 Node Tests 12125 * - For the attribute axis, the principal node type is attribute. 12126 * - For the namespace axis, the principal node type is namespace. 12127 * - For other axes, the principal node type is element. 12128 * 12129 * A node test * is true for any node of the 12130 * principal node type. For example, child::* will 12131 * select all element children of the context node 12132 */ 12133 oldContextNode = xpctxt->node; 12134 addNode = xmlXPathNodeSetAddUnique; 12135 outSeq = NULL; 12136 seq = NULL; 12137 outerContextNode = NULL; 12138 contextNode = NULL; 12139 contextIdx = 0; 12140 12141 12142 while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) { 12143 if (outerNext != NULL) { 12144 /* 12145 * This is a compound traversal. 12146 */ 12147 if (contextNode == NULL) { 12148 /* 12149 * Set the context for the outer traversal. 12150 */ 12151 outerContextNode = contextSeq->nodeTab[contextIdx++]; 12152 contextNode = outerNext(NULL, outerContextNode); 12153 } else 12154 contextNode = outerNext(contextNode, outerContextNode); 12155 if (contextNode == NULL) 12156 continue; 12157 /* 12158 * Set the context for the main traversal. 12159 */ 12160 xpctxt->node = contextNode; 12161 } else 12162 xpctxt->node = contextSeq->nodeTab[contextIdx++]; 12163 12164 if (seq == NULL) { 12165 seq = xmlXPathNodeSetCreate(NULL); 12166 if (seq == NULL) { 12167 total = 0; 12168 goto error; 12169 } 12170 } 12171 /* 12172 * Traverse the axis and test the nodes. 12173 */ 12174 pos = 0; 12175 cur = NULL; 12176 hasNsNodes = 0; 12177 do { 12178 cur = next(ctxt, cur); 12179 if (cur == NULL) 12180 break; 12181 12182 /* 12183 * QUESTION TODO: What does the "first" and "last" stuff do? 12184 */ 12185 if ((first != NULL) && (*first != NULL)) { 12186 if (*first == cur) 12187 break; 12188 if (((total % 256) == 0) && 12189 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 12190 (xmlXPathCmpNodesExt(*first, cur) >= 0)) 12191 #else 12192 (xmlXPathCmpNodes(*first, cur) >= 0)) 12193 #endif 12194 { 12195 break; 12196 } 12197 } 12198 if ((last != NULL) && (*last != NULL)) { 12199 if (*last == cur) 12200 break; 12201 if (((total % 256) == 0) && 12202 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 12203 (xmlXPathCmpNodesExt(cur, *last) >= 0)) 12204 #else 12205 (xmlXPathCmpNodes(cur, *last) >= 0)) 12206 #endif 12207 { 12208 break; 12209 } 12210 } 12211 12212 total++; 12213 12214 #ifdef DEBUG_STEP 12215 xmlGenericError(xmlGenericErrorContext, " %s", cur->name); 12216 #endif 12217 12218 switch (test) { 12219 case NODE_TEST_NONE: 12220 total = 0; 12221 STRANGE 12222 goto error; 12223 case NODE_TEST_TYPE: 12224 /* 12225 * TODO: Don't we need to use 12226 * xmlXPathNodeSetAddNs() for namespace nodes here? 12227 * Surprisingly, some c14n tests fail, if we do this. 12228 */ 12229 if (type == NODE_TYPE_NODE) { 12230 switch (cur->type) { 12231 case XML_DOCUMENT_NODE: 12232 case XML_HTML_DOCUMENT_NODE: 12233 #ifdef LIBXML_DOCB_ENABLED 12234 case XML_DOCB_DOCUMENT_NODE: 12235 #endif 12236 case XML_ELEMENT_NODE: 12237 case XML_ATTRIBUTE_NODE: 12238 case XML_PI_NODE: 12239 case XML_COMMENT_NODE: 12240 case XML_CDATA_SECTION_NODE: 12241 case XML_TEXT_NODE: 12242 case XML_NAMESPACE_DECL: 12243 XP_TEST_HIT 12244 break; 12245 default: 12246 break; 12247 } 12248 } else if (cur->type == type) { 12249 if (type == XML_NAMESPACE_DECL) 12250 XP_TEST_HIT_NS 12251 else 12252 XP_TEST_HIT 12253 } else if ((type == NODE_TYPE_TEXT) && 12254 (cur->type == XML_CDATA_SECTION_NODE)) 12255 { 12256 XP_TEST_HIT 12257 } 12258 break; 12259 case NODE_TEST_PI: 12260 if ((cur->type == XML_PI_NODE) && 12261 ((name == NULL) || xmlStrEqual(name, cur->name))) 12262 { 12263 XP_TEST_HIT 12264 } 12265 break; 12266 case NODE_TEST_ALL: 12267 if (axis == AXIS_ATTRIBUTE) { 12268 if (cur->type == XML_ATTRIBUTE_NODE) 12269 { 12270 XP_TEST_HIT 12271 } 12272 } else if (axis == AXIS_NAMESPACE) { 12273 if (cur->type == XML_NAMESPACE_DECL) 12274 { 12275 XP_TEST_HIT_NS 12276 } 12277 } else { 12278 if (cur->type == XML_ELEMENT_NODE) { 12279 if (prefix == NULL) 12280 { 12281 XP_TEST_HIT 12282 12283 } else if ((cur->ns != NULL) && 12284 (xmlStrEqual(URI, cur->ns->href))) 12285 { 12286 XP_TEST_HIT 12287 } 12288 } 12289 } 12290 break; 12291 case NODE_TEST_NS:{ 12292 TODO; 12293 break; 12294 } 12295 case NODE_TEST_NAME: 12296 if (axis == AXIS_ATTRIBUTE) { 12297 if (cur->type != XML_ATTRIBUTE_NODE) 12298 break; 12299 } else if (axis == AXIS_NAMESPACE) { 12300 if (cur->type != XML_NAMESPACE_DECL) 12301 break; 12302 } else { 12303 if (cur->type != XML_ELEMENT_NODE) 12304 break; 12305 } 12306 switch (cur->type) { 12307 case XML_ELEMENT_NODE: 12308 if (xmlStrEqual(name, cur->name)) { 12309 if (prefix == NULL) { 12310 if (cur->ns == NULL) 12311 { 12312 XP_TEST_HIT 12313 } 12314 } else { 12315 if ((cur->ns != NULL) && 12316 (xmlStrEqual(URI, cur->ns->href))) 12317 { 12318 XP_TEST_HIT 12319 } 12320 } 12321 } 12322 break; 12323 case XML_ATTRIBUTE_NODE:{ 12324 xmlAttrPtr attr = (xmlAttrPtr) cur; 12325 12326 if (xmlStrEqual(name, attr->name)) { 12327 if (prefix == NULL) { 12328 if ((attr->ns == NULL) || 12329 (attr->ns->prefix == NULL)) 12330 { 12331 XP_TEST_HIT 12332 } 12333 } else { 12334 if ((attr->ns != NULL) && 12335 (xmlStrEqual(URI, 12336 attr->ns->href))) 12337 { 12338 XP_TEST_HIT 12339 } 12340 } 12341 } 12342 break; 12343 } 12344 case XML_NAMESPACE_DECL: 12345 if (cur->type == XML_NAMESPACE_DECL) { 12346 xmlNsPtr ns = (xmlNsPtr) cur; 12347 12348 if ((ns->prefix != NULL) && (name != NULL) 12349 && (xmlStrEqual(ns->prefix, name))) 12350 { 12351 XP_TEST_HIT_NS 12352 } 12353 } 12354 break; 12355 default: 12356 break; 12357 } 12358 break; 12359 } /* switch(test) */ 12360 } while (cur != NULL); 12361 12362 goto apply_predicates; 12363 12364 axis_range_end: /* ----------------------------------------------------- */ 12365 /* 12366 * We have a "/foo[n]", and position() = n was reached. 12367 * Note that we can have as well "/foo/::parent::foo[1]", so 12368 * a duplicate-aware merge is still needed. 12369 * Merge with the result. 12370 */ 12371 if (outSeq == NULL) { 12372 outSeq = seq; 12373 seq = NULL; 12374 } else 12375 outSeq = mergeAndClear(outSeq, seq, 0); 12376 /* 12377 * Break if only a true/false result was requested. 12378 */ 12379 if (toBool) 12380 break; 12381 continue; 12382 12383 first_hit: /* ---------------------------------------------------------- */ 12384 /* 12385 * Break if only a true/false result was requested and 12386 * no predicates existed and a node test succeeded. 12387 */ 12388 if (outSeq == NULL) { 12389 outSeq = seq; 12390 seq = NULL; 12391 } else 12392 outSeq = mergeAndClear(outSeq, seq, 0); 12393 break; 12394 12395 #ifdef DEBUG_STEP 12396 if (seq != NULL) 12397 nbMatches += seq->nodeNr; 12398 #endif 12399 12400 apply_predicates: /* --------------------------------------------------- */ 12401 /* 12402 * Apply predicates. 12403 */ 12404 if ((predOp != NULL) && (seq->nodeNr > 0)) { 12405 /* 12406 * E.g. when we have a "/foo[some expression][n]". 12407 */ 12408 /* 12409 * QUESTION TODO: The old predicate evaluation took into 12410 * account location-sets. 12411 * (E.g. ctxt->value->type == XPATH_LOCATIONSET) 12412 * Do we expect such a set here? 12413 * All what I learned now from the evaluation semantics 12414 * does not indicate that a location-set will be processed 12415 * here, so this looks OK. 12416 */ 12417 /* 12418 * Iterate over all predicates, starting with the outermost 12419 * predicate. 12420 * TODO: Problem: we cannot execute the inner predicates first 12421 * since we cannot go back *up* the operator tree! 12422 * Options we have: 12423 * 1) Use of recursive functions (like is it currently done 12424 * via xmlXPathCompOpEval()) 12425 * 2) Add a predicate evaluation information stack to the 12426 * context struct 12427 * 3) Change the way the operators are linked; we need a 12428 * "parent" field on xmlXPathStepOp 12429 * 12430 * For the moment, I'll try to solve this with a recursive 12431 * function: xmlXPathCompOpEvalPredicate(). 12432 */ 12433 size = seq->nodeNr; 12434 if (hasPredicateRange != 0) 12435 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt, 12436 predOp, seq, size, maxPos, maxPos, hasNsNodes); 12437 else 12438 newSize = xmlXPathCompOpEvalPredicate(ctxt, 12439 predOp, seq, size, hasNsNodes); 12440 12441 if (ctxt->error != XPATH_EXPRESSION_OK) { 12442 total = 0; 12443 goto error; 12444 } 12445 /* 12446 * Add the filtered set of nodes to the result node set. 12447 */ 12448 if (newSize == 0) { 12449 /* 12450 * The predicates filtered all nodes out. 12451 */ 12452 xmlXPathNodeSetClear(seq, hasNsNodes); 12453 } else if (seq->nodeNr > 0) { 12454 /* 12455 * Add to result set. 12456 */ 12457 if (outSeq == NULL) { 12458 if (size != newSize) { 12459 /* 12460 * We need to merge and clear here, since 12461 * the sequence will contained NULLed entries. 12462 */ 12463 outSeq = mergeAndClear(NULL, seq, 1); 12464 } else { 12465 outSeq = seq; 12466 seq = NULL; 12467 } 12468 } else 12469 outSeq = mergeAndClear(outSeq, seq, 12470 (size != newSize) ? 1: 0); 12471 /* 12472 * Break if only a true/false result was requested. 12473 */ 12474 if (toBool) 12475 break; 12476 } 12477 } else if (seq->nodeNr > 0) { 12478 /* 12479 * Add to result set. 12480 */ 12481 if (outSeq == NULL) { 12482 outSeq = seq; 12483 seq = NULL; 12484 } else { 12485 outSeq = mergeAndClear(outSeq, seq, 0); 12486 } 12487 } 12488 } 12489 12490 error: 12491 if ((obj->boolval) && (obj->user != NULL)) { 12492 /* 12493 * QUESTION TODO: What does this do and why? 12494 * TODO: Do we have to do this also for the "error" 12495 * cleanup further down? 12496 */ 12497 ctxt->value->boolval = 1; 12498 ctxt->value->user = obj->user; 12499 obj->user = NULL; 12500 obj->boolval = 0; 12501 } 12502 xmlXPathReleaseObject(xpctxt, obj); 12503 12504 /* 12505 * Ensure we return at least an emtpy set. 12506 */ 12507 if (outSeq == NULL) { 12508 if ((seq != NULL) && (seq->nodeNr == 0)) 12509 outSeq = seq; 12510 else 12511 outSeq = xmlXPathNodeSetCreate(NULL); 12512 /* XXX what if xmlXPathNodeSetCreate returned NULL here? */ 12513 } 12514 if ((seq != NULL) && (seq != outSeq)) { 12515 xmlXPathFreeNodeSet(seq); 12516 } 12517 /* 12518 * Hand over the result. Better to push the set also in 12519 * case of errors. 12520 */ 12521 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq)); 12522 /* 12523 * Reset the context node. 12524 */ 12525 xpctxt->node = oldContextNode; 12526 12527 #ifdef DEBUG_STEP 12528 xmlGenericError(xmlGenericErrorContext, 12529 "\nExamined %d nodes, found %d nodes at that step\n", 12530 total, nbMatches); 12531 #endif 12532 12533 return(total); 12534 } 12535 12536 static int 12537 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt, 12538 xmlXPathStepOpPtr op, xmlNodePtr * first); 12539 12540 /** 12541 * xmlXPathCompOpEvalFirst: 12542 * @ctxt: the XPath parser context with the compiled expression 12543 * @op: an XPath compiled operation 12544 * @first: the first elem found so far 12545 * 12546 * Evaluate the Precompiled XPath operation searching only the first 12547 * element in document order 12548 * 12549 * Returns the number of examined objects. 12550 */ 12551 static int 12552 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt, 12553 xmlXPathStepOpPtr op, xmlNodePtr * first) 12554 { 12555 int total = 0, cur; 12556 xmlXPathCompExprPtr comp; 12557 xmlXPathObjectPtr arg1, arg2; 12558 12559 CHECK_ERROR0; 12560 comp = ctxt->comp; 12561 switch (op->op) { 12562 case XPATH_OP_END: 12563 return (0); 12564 case XPATH_OP_UNION: 12565 total = 12566 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1], 12567 first); 12568 CHECK_ERROR0; 12569 if ((ctxt->value != NULL) 12570 && (ctxt->value->type == XPATH_NODESET) 12571 && (ctxt->value->nodesetval != NULL) 12572 && (ctxt->value->nodesetval->nodeNr >= 1)) { 12573 /* 12574 * limit tree traversing to first node in the result 12575 */ 12576 /* 12577 * OPTIMIZE TODO: This implicitely sorts 12578 * the result, even if not needed. E.g. if the argument 12579 * of the count() function, no sorting is needed. 12580 * OPTIMIZE TODO: How do we know if the node-list wasn't 12581 * aready sorted? 12582 */ 12583 if (ctxt->value->nodesetval->nodeNr > 1) 12584 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12585 *first = ctxt->value->nodesetval->nodeTab[0]; 12586 } 12587 cur = 12588 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2], 12589 first); 12590 CHECK_ERROR0; 12591 CHECK_TYPE0(XPATH_NODESET); 12592 arg2 = valuePop(ctxt); 12593 12594 CHECK_TYPE0(XPATH_NODESET); 12595 arg1 = valuePop(ctxt); 12596 12597 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 12598 arg2->nodesetval); 12599 valuePush(ctxt, arg1); 12600 xmlXPathReleaseObject(ctxt->context, arg2); 12601 /* optimizer */ 12602 if (total > cur) 12603 xmlXPathCompSwap(op); 12604 return (total + cur); 12605 case XPATH_OP_ROOT: 12606 xmlXPathRoot(ctxt); 12607 return (0); 12608 case XPATH_OP_NODE: 12609 if (op->ch1 != -1) 12610 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12611 CHECK_ERROR0; 12612 if (op->ch2 != -1) 12613 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12614 CHECK_ERROR0; 12615 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 12616 ctxt->context->node)); 12617 return (total); 12618 case XPATH_OP_RESET: 12619 if (op->ch1 != -1) 12620 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12621 CHECK_ERROR0; 12622 if (op->ch2 != -1) 12623 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12624 CHECK_ERROR0; 12625 ctxt->context->node = NULL; 12626 return (total); 12627 case XPATH_OP_COLLECT:{ 12628 if (op->ch1 == -1) 12629 return (total); 12630 12631 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12632 CHECK_ERROR0; 12633 12634 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0); 12635 return (total); 12636 } 12637 case XPATH_OP_VALUE: 12638 valuePush(ctxt, 12639 xmlXPathCacheObjectCopy(ctxt->context, 12640 (xmlXPathObjectPtr) op->value4)); 12641 return (0); 12642 case XPATH_OP_SORT: 12643 if (op->ch1 != -1) 12644 total += 12645 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1], 12646 first); 12647 CHECK_ERROR0; 12648 if ((ctxt->value != NULL) 12649 && (ctxt->value->type == XPATH_NODESET) 12650 && (ctxt->value->nodesetval != NULL) 12651 && (ctxt->value->nodesetval->nodeNr > 1)) 12652 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12653 return (total); 12654 #ifdef XP_OPTIMIZED_FILTER_FIRST 12655 case XPATH_OP_FILTER: 12656 total =+ xmlXPathCompOpEvalFilterFirst(ctxt, op, first); 12657 return (total); 12658 #endif 12659 default: 12660 return (xmlXPathCompOpEval(ctxt, op)); 12661 } 12662 } 12663 12664 /** 12665 * xmlXPathCompOpEvalLast: 12666 * @ctxt: the XPath parser context with the compiled expression 12667 * @op: an XPath compiled operation 12668 * @last: the last elem found so far 12669 * 12670 * Evaluate the Precompiled XPath operation searching only the last 12671 * element in document order 12672 * 12673 * Returns the number of nodes traversed 12674 */ 12675 static int 12676 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op, 12677 xmlNodePtr * last) 12678 { 12679 int total = 0, cur; 12680 xmlXPathCompExprPtr comp; 12681 xmlXPathObjectPtr arg1, arg2; 12682 xmlNodePtr bak; 12683 xmlDocPtr bakd; 12684 int pp; 12685 int cs; 12686 12687 CHECK_ERROR0; 12688 comp = ctxt->comp; 12689 switch (op->op) { 12690 case XPATH_OP_END: 12691 return (0); 12692 case XPATH_OP_UNION: 12693 bakd = ctxt->context->doc; 12694 bak = ctxt->context->node; 12695 pp = ctxt->context->proximityPosition; 12696 cs = ctxt->context->contextSize; 12697 total = 12698 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last); 12699 CHECK_ERROR0; 12700 if ((ctxt->value != NULL) 12701 && (ctxt->value->type == XPATH_NODESET) 12702 && (ctxt->value->nodesetval != NULL) 12703 && (ctxt->value->nodesetval->nodeNr >= 1)) { 12704 /* 12705 * limit tree traversing to first node in the result 12706 */ 12707 if (ctxt->value->nodesetval->nodeNr > 1) 12708 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12709 *last = 12710 ctxt->value->nodesetval->nodeTab[ctxt->value-> 12711 nodesetval->nodeNr - 12712 1]; 12713 } 12714 ctxt->context->doc = bakd; 12715 ctxt->context->node = bak; 12716 ctxt->context->proximityPosition = pp; 12717 ctxt->context->contextSize = cs; 12718 cur = 12719 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last); 12720 CHECK_ERROR0; 12721 if ((ctxt->value != NULL) 12722 && (ctxt->value->type == XPATH_NODESET) 12723 && (ctxt->value->nodesetval != NULL) 12724 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */ 12725 } 12726 CHECK_TYPE0(XPATH_NODESET); 12727 arg2 = valuePop(ctxt); 12728 12729 CHECK_TYPE0(XPATH_NODESET); 12730 arg1 = valuePop(ctxt); 12731 12732 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 12733 arg2->nodesetval); 12734 valuePush(ctxt, arg1); 12735 xmlXPathReleaseObject(ctxt->context, arg2); 12736 /* optimizer */ 12737 if (total > cur) 12738 xmlXPathCompSwap(op); 12739 return (total + cur); 12740 case XPATH_OP_ROOT: 12741 xmlXPathRoot(ctxt); 12742 return (0); 12743 case XPATH_OP_NODE: 12744 if (op->ch1 != -1) 12745 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12746 CHECK_ERROR0; 12747 if (op->ch2 != -1) 12748 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12749 CHECK_ERROR0; 12750 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 12751 ctxt->context->node)); 12752 return (total); 12753 case XPATH_OP_RESET: 12754 if (op->ch1 != -1) 12755 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12756 CHECK_ERROR0; 12757 if (op->ch2 != -1) 12758 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12759 CHECK_ERROR0; 12760 ctxt->context->node = NULL; 12761 return (total); 12762 case XPATH_OP_COLLECT:{ 12763 if (op->ch1 == -1) 12764 return (0); 12765 12766 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12767 CHECK_ERROR0; 12768 12769 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0); 12770 return (total); 12771 } 12772 case XPATH_OP_VALUE: 12773 valuePush(ctxt, 12774 xmlXPathCacheObjectCopy(ctxt->context, 12775 (xmlXPathObjectPtr) op->value4)); 12776 return (0); 12777 case XPATH_OP_SORT: 12778 if (op->ch1 != -1) 12779 total += 12780 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], 12781 last); 12782 CHECK_ERROR0; 12783 if ((ctxt->value != NULL) 12784 && (ctxt->value->type == XPATH_NODESET) 12785 && (ctxt->value->nodesetval != NULL) 12786 && (ctxt->value->nodesetval->nodeNr > 1)) 12787 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12788 return (total); 12789 default: 12790 return (xmlXPathCompOpEval(ctxt, op)); 12791 } 12792 } 12793 12794 #ifdef XP_OPTIMIZED_FILTER_FIRST 12795 static int 12796 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt, 12797 xmlXPathStepOpPtr op, xmlNodePtr * first) 12798 { 12799 int total = 0; 12800 xmlXPathCompExprPtr comp; 12801 xmlXPathObjectPtr res; 12802 xmlXPathObjectPtr obj; 12803 xmlNodeSetPtr oldset; 12804 xmlNodePtr oldnode; 12805 xmlDocPtr oldDoc; 12806 int i; 12807 12808 CHECK_ERROR0; 12809 comp = ctxt->comp; 12810 /* 12811 * Optimization for ()[last()] selection i.e. the last elem 12812 */ 12813 if ((op->ch1 != -1) && (op->ch2 != -1) && 12814 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 12815 (comp->steps[op->ch2].op == XPATH_OP_SORT)) { 12816 int f = comp->steps[op->ch2].ch1; 12817 12818 if ((f != -1) && 12819 (comp->steps[f].op == XPATH_OP_FUNCTION) && 12820 (comp->steps[f].value5 == NULL) && 12821 (comp->steps[f].value == 0) && 12822 (comp->steps[f].value4 != NULL) && 12823 (xmlStrEqual 12824 (comp->steps[f].value4, BAD_CAST "last"))) { 12825 xmlNodePtr last = NULL; 12826 12827 total += 12828 xmlXPathCompOpEvalLast(ctxt, 12829 &comp->steps[op->ch1], 12830 &last); 12831 CHECK_ERROR0; 12832 /* 12833 * The nodeset should be in document order, 12834 * Keep only the last value 12835 */ 12836 if ((ctxt->value != NULL) && 12837 (ctxt->value->type == XPATH_NODESET) && 12838 (ctxt->value->nodesetval != NULL) && 12839 (ctxt->value->nodesetval->nodeTab != NULL) && 12840 (ctxt->value->nodesetval->nodeNr > 1)) { 12841 ctxt->value->nodesetval->nodeTab[0] = 12842 ctxt->value->nodesetval->nodeTab[ctxt-> 12843 value-> 12844 nodesetval-> 12845 nodeNr - 12846 1]; 12847 ctxt->value->nodesetval->nodeNr = 1; 12848 *first = *(ctxt->value->nodesetval->nodeTab); 12849 } 12850 return (total); 12851 } 12852 } 12853 12854 if (op->ch1 != -1) 12855 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12856 CHECK_ERROR0; 12857 if (op->ch2 == -1) 12858 return (total); 12859 if (ctxt->value == NULL) 12860 return (total); 12861 12862 #ifdef LIBXML_XPTR_ENABLED 12863 oldnode = ctxt->context->node; 12864 /* 12865 * Hum are we filtering the result of an XPointer expression 12866 */ 12867 if (ctxt->value->type == XPATH_LOCATIONSET) { 12868 xmlXPathObjectPtr tmp = NULL; 12869 xmlLocationSetPtr newlocset = NULL; 12870 xmlLocationSetPtr oldlocset; 12871 12872 /* 12873 * Extract the old locset, and then evaluate the result of the 12874 * expression for all the element in the locset. use it to grow 12875 * up a new locset. 12876 */ 12877 CHECK_TYPE0(XPATH_LOCATIONSET); 12878 obj = valuePop(ctxt); 12879 oldlocset = obj->user; 12880 ctxt->context->node = NULL; 12881 12882 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) { 12883 ctxt->context->contextSize = 0; 12884 ctxt->context->proximityPosition = 0; 12885 if (op->ch2 != -1) 12886 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12887 res = valuePop(ctxt); 12888 if (res != NULL) { 12889 xmlXPathReleaseObject(ctxt->context, res); 12890 } 12891 valuePush(ctxt, obj); 12892 CHECK_ERROR0; 12893 return (total); 12894 } 12895 newlocset = xmlXPtrLocationSetCreate(NULL); 12896 12897 for (i = 0; i < oldlocset->locNr; i++) { 12898 /* 12899 * Run the evaluation with a node list made of a 12900 * single item in the nodelocset. 12901 */ 12902 ctxt->context->node = oldlocset->locTab[i]->user; 12903 ctxt->context->contextSize = oldlocset->locNr; 12904 ctxt->context->proximityPosition = i + 1; 12905 if (tmp == NULL) { 12906 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 12907 ctxt->context->node); 12908 } else { 12909 xmlXPathNodeSetAddUnique(tmp->nodesetval, 12910 ctxt->context->node); 12911 } 12912 valuePush(ctxt, tmp); 12913 if (op->ch2 != -1) 12914 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12915 if (ctxt->error != XPATH_EXPRESSION_OK) { 12916 xmlXPathFreeObject(obj); 12917 return(0); 12918 } 12919 /* 12920 * The result of the evaluation need to be tested to 12921 * decided whether the filter succeeded or not 12922 */ 12923 res = valuePop(ctxt); 12924 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 12925 xmlXPtrLocationSetAdd(newlocset, 12926 xmlXPathCacheObjectCopy(ctxt->context, 12927 oldlocset->locTab[i])); 12928 } 12929 /* 12930 * Cleanup 12931 */ 12932 if (res != NULL) { 12933 xmlXPathReleaseObject(ctxt->context, res); 12934 } 12935 if (ctxt->value == tmp) { 12936 valuePop(ctxt); 12937 xmlXPathNodeSetClear(tmp->nodesetval, 1); 12938 /* 12939 * REVISIT TODO: Don't create a temporary nodeset 12940 * for everly iteration. 12941 */ 12942 /* OLD: xmlXPathFreeObject(res); */ 12943 } else 12944 tmp = NULL; 12945 ctxt->context->node = NULL; 12946 /* 12947 * Only put the first node in the result, then leave. 12948 */ 12949 if (newlocset->locNr > 0) { 12950 *first = (xmlNodePtr) oldlocset->locTab[i]->user; 12951 break; 12952 } 12953 } 12954 if (tmp != NULL) { 12955 xmlXPathReleaseObject(ctxt->context, tmp); 12956 } 12957 /* 12958 * The result is used as the new evaluation locset. 12959 */ 12960 xmlXPathReleaseObject(ctxt->context, obj); 12961 ctxt->context->node = NULL; 12962 ctxt->context->contextSize = -1; 12963 ctxt->context->proximityPosition = -1; 12964 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset)); 12965 ctxt->context->node = oldnode; 12966 return (total); 12967 } 12968 #endif /* LIBXML_XPTR_ENABLED */ 12969 12970 /* 12971 * Extract the old set, and then evaluate the result of the 12972 * expression for all the element in the set. use it to grow 12973 * up a new set. 12974 */ 12975 CHECK_TYPE0(XPATH_NODESET); 12976 obj = valuePop(ctxt); 12977 oldset = obj->nodesetval; 12978 12979 oldnode = ctxt->context->node; 12980 oldDoc = ctxt->context->doc; 12981 ctxt->context->node = NULL; 12982 12983 if ((oldset == NULL) || (oldset->nodeNr == 0)) { 12984 ctxt->context->contextSize = 0; 12985 ctxt->context->proximityPosition = 0; 12986 /* QUESTION TODO: Why was this code commented out? 12987 if (op->ch2 != -1) 12988 total += 12989 xmlXPathCompOpEval(ctxt, 12990 &comp->steps[op->ch2]); 12991 CHECK_ERROR0; 12992 res = valuePop(ctxt); 12993 if (res != NULL) 12994 xmlXPathFreeObject(res); 12995 */ 12996 valuePush(ctxt, obj); 12997 ctxt->context->node = oldnode; 12998 CHECK_ERROR0; 12999 } else { 13000 xmlNodeSetPtr newset; 13001 xmlXPathObjectPtr tmp = NULL; 13002 /* 13003 * Initialize the new set. 13004 * Also set the xpath document in case things like 13005 * key() evaluation are attempted on the predicate 13006 */ 13007 newset = xmlXPathNodeSetCreate(NULL); 13008 /* XXX what if xmlXPathNodeSetCreate returned NULL? */ 13009 13010 for (i = 0; i < oldset->nodeNr; i++) { 13011 /* 13012 * Run the evaluation with a node list made of 13013 * a single item in the nodeset. 13014 */ 13015 ctxt->context->node = oldset->nodeTab[i]; 13016 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) && 13017 (oldset->nodeTab[i]->doc != NULL)) 13018 ctxt->context->doc = oldset->nodeTab[i]->doc; 13019 if (tmp == NULL) { 13020 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13021 ctxt->context->node); 13022 } else { 13023 xmlXPathNodeSetAddUnique(tmp->nodesetval, 13024 ctxt->context->node); 13025 } 13026 valuePush(ctxt, tmp); 13027 ctxt->context->contextSize = oldset->nodeNr; 13028 ctxt->context->proximityPosition = i + 1; 13029 if (op->ch2 != -1) 13030 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13031 if (ctxt->error != XPATH_EXPRESSION_OK) { 13032 xmlXPathFreeNodeSet(newset); 13033 xmlXPathFreeObject(obj); 13034 return(0); 13035 } 13036 /* 13037 * The result of the evaluation needs to be tested to 13038 * decide whether the filter succeeded or not 13039 */ 13040 res = valuePop(ctxt); 13041 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 13042 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]); 13043 } 13044 /* 13045 * Cleanup 13046 */ 13047 if (res != NULL) { 13048 xmlXPathReleaseObject(ctxt->context, res); 13049 } 13050 if (ctxt->value == tmp) { 13051 valuePop(ctxt); 13052 /* 13053 * Don't free the temporary nodeset 13054 * in order to avoid massive recreation inside this 13055 * loop. 13056 */ 13057 xmlXPathNodeSetClear(tmp->nodesetval, 1); 13058 } else 13059 tmp = NULL; 13060 ctxt->context->node = NULL; 13061 /* 13062 * Only put the first node in the result, then leave. 13063 */ 13064 if (newset->nodeNr > 0) { 13065 *first = *(newset->nodeTab); 13066 break; 13067 } 13068 } 13069 if (tmp != NULL) { 13070 xmlXPathReleaseObject(ctxt->context, tmp); 13071 } 13072 /* 13073 * The result is used as the new evaluation set. 13074 */ 13075 xmlXPathReleaseObject(ctxt->context, obj); 13076 ctxt->context->node = NULL; 13077 ctxt->context->contextSize = -1; 13078 ctxt->context->proximityPosition = -1; 13079 /* may want to move this past the '}' later */ 13080 ctxt->context->doc = oldDoc; 13081 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset)); 13082 } 13083 ctxt->context->node = oldnode; 13084 return(total); 13085 } 13086 #endif /* XP_OPTIMIZED_FILTER_FIRST */ 13087 13088 /** 13089 * xmlXPathCompOpEval: 13090 * @ctxt: the XPath parser context with the compiled expression 13091 * @op: an XPath compiled operation 13092 * 13093 * Evaluate the Precompiled XPath operation 13094 * Returns the number of nodes traversed 13095 */ 13096 static int 13097 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) 13098 { 13099 int total = 0; 13100 int equal, ret; 13101 xmlXPathCompExprPtr comp; 13102 xmlXPathObjectPtr arg1, arg2; 13103 xmlNodePtr bak; 13104 xmlDocPtr bakd; 13105 int pp; 13106 int cs; 13107 13108 CHECK_ERROR0; 13109 comp = ctxt->comp; 13110 switch (op->op) { 13111 case XPATH_OP_END: 13112 return (0); 13113 case XPATH_OP_AND: 13114 bakd = ctxt->context->doc; 13115 bak = ctxt->context->node; 13116 pp = ctxt->context->proximityPosition; 13117 cs = ctxt->context->contextSize; 13118 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13119 CHECK_ERROR0; 13120 xmlXPathBooleanFunction(ctxt, 1); 13121 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0)) 13122 return (total); 13123 arg2 = valuePop(ctxt); 13124 ctxt->context->doc = bakd; 13125 ctxt->context->node = bak; 13126 ctxt->context->proximityPosition = pp; 13127 ctxt->context->contextSize = cs; 13128 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13129 if (ctxt->error) { 13130 xmlXPathFreeObject(arg2); 13131 return(0); 13132 } 13133 xmlXPathBooleanFunction(ctxt, 1); 13134 arg1 = valuePop(ctxt); 13135 arg1->boolval &= arg2->boolval; 13136 valuePush(ctxt, arg1); 13137 xmlXPathReleaseObject(ctxt->context, arg2); 13138 return (total); 13139 case XPATH_OP_OR: 13140 bakd = ctxt->context->doc; 13141 bak = ctxt->context->node; 13142 pp = ctxt->context->proximityPosition; 13143 cs = ctxt->context->contextSize; 13144 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13145 CHECK_ERROR0; 13146 xmlXPathBooleanFunction(ctxt, 1); 13147 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1)) 13148 return (total); 13149 arg2 = valuePop(ctxt); 13150 ctxt->context->doc = bakd; 13151 ctxt->context->node = bak; 13152 ctxt->context->proximityPosition = pp; 13153 ctxt->context->contextSize = cs; 13154 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13155 if (ctxt->error) { 13156 xmlXPathFreeObject(arg2); 13157 return(0); 13158 } 13159 xmlXPathBooleanFunction(ctxt, 1); 13160 arg1 = valuePop(ctxt); 13161 arg1->boolval |= arg2->boolval; 13162 valuePush(ctxt, arg1); 13163 xmlXPathReleaseObject(ctxt->context, arg2); 13164 return (total); 13165 case XPATH_OP_EQUAL: 13166 bakd = ctxt->context->doc; 13167 bak = ctxt->context->node; 13168 pp = ctxt->context->proximityPosition; 13169 cs = ctxt->context->contextSize; 13170 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13171 CHECK_ERROR0; 13172 ctxt->context->doc = bakd; 13173 ctxt->context->node = bak; 13174 ctxt->context->proximityPosition = pp; 13175 ctxt->context->contextSize = cs; 13176 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13177 CHECK_ERROR0; 13178 if (op->value) 13179 equal = xmlXPathEqualValues(ctxt); 13180 else 13181 equal = xmlXPathNotEqualValues(ctxt); 13182 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal)); 13183 return (total); 13184 case XPATH_OP_CMP: 13185 bakd = ctxt->context->doc; 13186 bak = ctxt->context->node; 13187 pp = ctxt->context->proximityPosition; 13188 cs = ctxt->context->contextSize; 13189 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13190 CHECK_ERROR0; 13191 ctxt->context->doc = bakd; 13192 ctxt->context->node = bak; 13193 ctxt->context->proximityPosition = pp; 13194 ctxt->context->contextSize = cs; 13195 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13196 CHECK_ERROR0; 13197 ret = xmlXPathCompareValues(ctxt, op->value, op->value2); 13198 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret)); 13199 return (total); 13200 case XPATH_OP_PLUS: 13201 bakd = ctxt->context->doc; 13202 bak = ctxt->context->node; 13203 pp = ctxt->context->proximityPosition; 13204 cs = ctxt->context->contextSize; 13205 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13206 CHECK_ERROR0; 13207 if (op->ch2 != -1) { 13208 ctxt->context->doc = bakd; 13209 ctxt->context->node = bak; 13210 ctxt->context->proximityPosition = pp; 13211 ctxt->context->contextSize = cs; 13212 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13213 } 13214 CHECK_ERROR0; 13215 if (op->value == 0) 13216 xmlXPathSubValues(ctxt); 13217 else if (op->value == 1) 13218 xmlXPathAddValues(ctxt); 13219 else if (op->value == 2) 13220 xmlXPathValueFlipSign(ctxt); 13221 else if (op->value == 3) { 13222 CAST_TO_NUMBER; 13223 CHECK_TYPE0(XPATH_NUMBER); 13224 } 13225 return (total); 13226 case XPATH_OP_MULT: 13227 bakd = ctxt->context->doc; 13228 bak = ctxt->context->node; 13229 pp = ctxt->context->proximityPosition; 13230 cs = ctxt->context->contextSize; 13231 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13232 CHECK_ERROR0; 13233 ctxt->context->doc = bakd; 13234 ctxt->context->node = bak; 13235 ctxt->context->proximityPosition = pp; 13236 ctxt->context->contextSize = cs; 13237 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13238 CHECK_ERROR0; 13239 if (op->value == 0) 13240 xmlXPathMultValues(ctxt); 13241 else if (op->value == 1) 13242 xmlXPathDivValues(ctxt); 13243 else if (op->value == 2) 13244 xmlXPathModValues(ctxt); 13245 return (total); 13246 case XPATH_OP_UNION: 13247 bakd = ctxt->context->doc; 13248 bak = ctxt->context->node; 13249 pp = ctxt->context->proximityPosition; 13250 cs = ctxt->context->contextSize; 13251 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13252 CHECK_ERROR0; 13253 ctxt->context->doc = bakd; 13254 ctxt->context->node = bak; 13255 ctxt->context->proximityPosition = pp; 13256 ctxt->context->contextSize = cs; 13257 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13258 CHECK_ERROR0; 13259 CHECK_TYPE0(XPATH_NODESET); 13260 arg2 = valuePop(ctxt); 13261 13262 CHECK_TYPE0(XPATH_NODESET); 13263 arg1 = valuePop(ctxt); 13264 13265 if ((arg1->nodesetval == NULL) || 13266 ((arg2->nodesetval != NULL) && 13267 (arg2->nodesetval->nodeNr != 0))) 13268 { 13269 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 13270 arg2->nodesetval); 13271 } 13272 13273 valuePush(ctxt, arg1); 13274 xmlXPathReleaseObject(ctxt->context, arg2); 13275 return (total); 13276 case XPATH_OP_ROOT: 13277 xmlXPathRoot(ctxt); 13278 return (total); 13279 case XPATH_OP_NODE: 13280 if (op->ch1 != -1) 13281 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13282 CHECK_ERROR0; 13283 if (op->ch2 != -1) 13284 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13285 CHECK_ERROR0; 13286 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 13287 ctxt->context->node)); 13288 return (total); 13289 case XPATH_OP_RESET: 13290 if (op->ch1 != -1) 13291 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13292 CHECK_ERROR0; 13293 if (op->ch2 != -1) 13294 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13295 CHECK_ERROR0; 13296 ctxt->context->node = NULL; 13297 return (total); 13298 case XPATH_OP_COLLECT:{ 13299 if (op->ch1 == -1) 13300 return (total); 13301 13302 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13303 CHECK_ERROR0; 13304 13305 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0); 13306 return (total); 13307 } 13308 case XPATH_OP_VALUE: 13309 valuePush(ctxt, 13310 xmlXPathCacheObjectCopy(ctxt->context, 13311 (xmlXPathObjectPtr) op->value4)); 13312 return (total); 13313 case XPATH_OP_VARIABLE:{ 13314 xmlXPathObjectPtr val; 13315 13316 if (op->ch1 != -1) 13317 total += 13318 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13319 if (op->value5 == NULL) { 13320 val = xmlXPathVariableLookup(ctxt->context, op->value4); 13321 if (val == NULL) { 13322 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR; 13323 return(0); 13324 } 13325 valuePush(ctxt, val); 13326 } else { 13327 const xmlChar *URI; 13328 13329 URI = xmlXPathNsLookup(ctxt->context, op->value5); 13330 if (URI == NULL) { 13331 xmlGenericError(xmlGenericErrorContext, 13332 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n", 13333 (char *) op->value4, (char *)op->value5); 13334 return (total); 13335 } 13336 val = xmlXPathVariableLookupNS(ctxt->context, 13337 op->value4, URI); 13338 if (val == NULL) { 13339 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR; 13340 return(0); 13341 } 13342 valuePush(ctxt, val); 13343 } 13344 return (total); 13345 } 13346 case XPATH_OP_FUNCTION:{ 13347 xmlXPathFunction func; 13348 const xmlChar *oldFunc, *oldFuncURI; 13349 int i; 13350 13351 if (op->ch1 != -1) 13352 total += 13353 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13354 if (ctxt->valueNr < op->value) { 13355 xmlGenericError(xmlGenericErrorContext, 13356 "xmlXPathCompOpEval: parameter error\n"); 13357 ctxt->error = XPATH_INVALID_OPERAND; 13358 return (total); 13359 } 13360 for (i = 0; i < op->value; i++) 13361 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) { 13362 xmlGenericError(xmlGenericErrorContext, 13363 "xmlXPathCompOpEval: parameter error\n"); 13364 ctxt->error = XPATH_INVALID_OPERAND; 13365 return (total); 13366 } 13367 if (op->cache != NULL) 13368 XML_CAST_FPTR(func) = op->cache; 13369 else { 13370 const xmlChar *URI = NULL; 13371 13372 if (op->value5 == NULL) 13373 func = 13374 xmlXPathFunctionLookup(ctxt->context, 13375 op->value4); 13376 else { 13377 URI = xmlXPathNsLookup(ctxt->context, op->value5); 13378 if (URI == NULL) { 13379 xmlGenericError(xmlGenericErrorContext, 13380 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n", 13381 (char *)op->value4, (char *)op->value5); 13382 return (total); 13383 } 13384 func = xmlXPathFunctionLookupNS(ctxt->context, 13385 op->value4, URI); 13386 } 13387 if (func == NULL) { 13388 xmlGenericError(xmlGenericErrorContext, 13389 "xmlXPathCompOpEval: function %s not found\n", 13390 (char *)op->value4); 13391 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR); 13392 } 13393 op->cache = XML_CAST_FPTR(func); 13394 op->cacheURI = (void *) URI; 13395 } 13396 oldFunc = ctxt->context->function; 13397 oldFuncURI = ctxt->context->functionURI; 13398 ctxt->context->function = op->value4; 13399 ctxt->context->functionURI = op->cacheURI; 13400 func(ctxt, op->value); 13401 ctxt->context->function = oldFunc; 13402 ctxt->context->functionURI = oldFuncURI; 13403 return (total); 13404 } 13405 case XPATH_OP_ARG: 13406 bakd = ctxt->context->doc; 13407 bak = ctxt->context->node; 13408 pp = ctxt->context->proximityPosition; 13409 cs = ctxt->context->contextSize; 13410 if (op->ch1 != -1) 13411 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13412 ctxt->context->contextSize = cs; 13413 ctxt->context->proximityPosition = pp; 13414 ctxt->context->node = bak; 13415 ctxt->context->doc = bakd; 13416 CHECK_ERROR0; 13417 if (op->ch2 != -1) { 13418 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13419 ctxt->context->doc = bakd; 13420 ctxt->context->node = bak; 13421 CHECK_ERROR0; 13422 } 13423 return (total); 13424 case XPATH_OP_PREDICATE: 13425 case XPATH_OP_FILTER:{ 13426 xmlXPathObjectPtr res; 13427 xmlXPathObjectPtr obj, tmp; 13428 xmlNodeSetPtr newset = NULL; 13429 xmlNodeSetPtr oldset; 13430 xmlNodePtr oldnode; 13431 xmlDocPtr oldDoc; 13432 int i; 13433 13434 /* 13435 * Optimization for ()[1] selection i.e. the first elem 13436 */ 13437 if ((op->ch1 != -1) && (op->ch2 != -1) && 13438 #ifdef XP_OPTIMIZED_FILTER_FIRST 13439 /* 13440 * FILTER TODO: Can we assume that the inner processing 13441 * will result in an ordered list if we have an 13442 * XPATH_OP_FILTER? 13443 * What about an additional field or flag on 13444 * xmlXPathObject like @sorted ? This way we wouln'd need 13445 * to assume anything, so it would be more robust and 13446 * easier to optimize. 13447 */ 13448 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */ 13449 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */ 13450 #else 13451 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 13452 #endif 13453 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */ 13454 xmlXPathObjectPtr val; 13455 13456 val = comp->steps[op->ch2].value4; 13457 if ((val != NULL) && (val->type == XPATH_NUMBER) && 13458 (val->floatval == 1.0)) { 13459 xmlNodePtr first = NULL; 13460 13461 total += 13462 xmlXPathCompOpEvalFirst(ctxt, 13463 &comp->steps[op->ch1], 13464 &first); 13465 CHECK_ERROR0; 13466 /* 13467 * The nodeset should be in document order, 13468 * Keep only the first value 13469 */ 13470 if ((ctxt->value != NULL) && 13471 (ctxt->value->type == XPATH_NODESET) && 13472 (ctxt->value->nodesetval != NULL) && 13473 (ctxt->value->nodesetval->nodeNr > 1)) 13474 ctxt->value->nodesetval->nodeNr = 1; 13475 return (total); 13476 } 13477 } 13478 /* 13479 * Optimization for ()[last()] selection i.e. the last elem 13480 */ 13481 if ((op->ch1 != -1) && (op->ch2 != -1) && 13482 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 13483 (comp->steps[op->ch2].op == XPATH_OP_SORT)) { 13484 int f = comp->steps[op->ch2].ch1; 13485 13486 if ((f != -1) && 13487 (comp->steps[f].op == XPATH_OP_FUNCTION) && 13488 (comp->steps[f].value5 == NULL) && 13489 (comp->steps[f].value == 0) && 13490 (comp->steps[f].value4 != NULL) && 13491 (xmlStrEqual 13492 (comp->steps[f].value4, BAD_CAST "last"))) { 13493 xmlNodePtr last = NULL; 13494 13495 total += 13496 xmlXPathCompOpEvalLast(ctxt, 13497 &comp->steps[op->ch1], 13498 &last); 13499 CHECK_ERROR0; 13500 /* 13501 * The nodeset should be in document order, 13502 * Keep only the last value 13503 */ 13504 if ((ctxt->value != NULL) && 13505 (ctxt->value->type == XPATH_NODESET) && 13506 (ctxt->value->nodesetval != NULL) && 13507 (ctxt->value->nodesetval->nodeTab != NULL) && 13508 (ctxt->value->nodesetval->nodeNr > 1)) { 13509 ctxt->value->nodesetval->nodeTab[0] = 13510 ctxt->value->nodesetval->nodeTab[ctxt-> 13511 value-> 13512 nodesetval-> 13513 nodeNr - 13514 1]; 13515 ctxt->value->nodesetval->nodeNr = 1; 13516 } 13517 return (total); 13518 } 13519 } 13520 /* 13521 * Process inner predicates first. 13522 * Example "index[parent::book][1]": 13523 * ... 13524 * PREDICATE <-- we are here "[1]" 13525 * PREDICATE <-- process "[parent::book]" first 13526 * SORT 13527 * COLLECT 'parent' 'name' 'node' book 13528 * NODE 13529 * ELEM Object is a number : 1 13530 */ 13531 if (op->ch1 != -1) 13532 total += 13533 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13534 CHECK_ERROR0; 13535 if (op->ch2 == -1) 13536 return (total); 13537 if (ctxt->value == NULL) 13538 return (total); 13539 13540 oldnode = ctxt->context->node; 13541 13542 #ifdef LIBXML_XPTR_ENABLED 13543 /* 13544 * Hum are we filtering the result of an XPointer expression 13545 */ 13546 if (ctxt->value->type == XPATH_LOCATIONSET) { 13547 xmlLocationSetPtr newlocset = NULL; 13548 xmlLocationSetPtr oldlocset; 13549 13550 /* 13551 * Extract the old locset, and then evaluate the result of the 13552 * expression for all the element in the locset. use it to grow 13553 * up a new locset. 13554 */ 13555 CHECK_TYPE0(XPATH_LOCATIONSET); 13556 obj = valuePop(ctxt); 13557 oldlocset = obj->user; 13558 ctxt->context->node = NULL; 13559 13560 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) { 13561 ctxt->context->contextSize = 0; 13562 ctxt->context->proximityPosition = 0; 13563 if (op->ch2 != -1) 13564 total += 13565 xmlXPathCompOpEval(ctxt, 13566 &comp->steps[op->ch2]); 13567 res = valuePop(ctxt); 13568 if (res != NULL) { 13569 xmlXPathReleaseObject(ctxt->context, res); 13570 } 13571 valuePush(ctxt, obj); 13572 CHECK_ERROR0; 13573 return (total); 13574 } 13575 newlocset = xmlXPtrLocationSetCreate(NULL); 13576 13577 for (i = 0; i < oldlocset->locNr; i++) { 13578 /* 13579 * Run the evaluation with a node list made of a 13580 * single item in the nodelocset. 13581 */ 13582 ctxt->context->node = oldlocset->locTab[i]->user; 13583 ctxt->context->contextSize = oldlocset->locNr; 13584 ctxt->context->proximityPosition = i + 1; 13585 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13586 ctxt->context->node); 13587 valuePush(ctxt, tmp); 13588 13589 if (op->ch2 != -1) 13590 total += 13591 xmlXPathCompOpEval(ctxt, 13592 &comp->steps[op->ch2]); 13593 if (ctxt->error != XPATH_EXPRESSION_OK) { 13594 xmlXPathFreeObject(obj); 13595 return(0); 13596 } 13597 13598 /* 13599 * The result of the evaluation need to be tested to 13600 * decided whether the filter succeeded or not 13601 */ 13602 res = valuePop(ctxt); 13603 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 13604 xmlXPtrLocationSetAdd(newlocset, 13605 xmlXPathObjectCopy 13606 (oldlocset->locTab[i])); 13607 } 13608 13609 /* 13610 * Cleanup 13611 */ 13612 if (res != NULL) { 13613 xmlXPathReleaseObject(ctxt->context, res); 13614 } 13615 if (ctxt->value == tmp) { 13616 res = valuePop(ctxt); 13617 xmlXPathReleaseObject(ctxt->context, res); 13618 } 13619 13620 ctxt->context->node = NULL; 13621 } 13622 13623 /* 13624 * The result is used as the new evaluation locset. 13625 */ 13626 xmlXPathReleaseObject(ctxt->context, obj); 13627 ctxt->context->node = NULL; 13628 ctxt->context->contextSize = -1; 13629 ctxt->context->proximityPosition = -1; 13630 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset)); 13631 ctxt->context->node = oldnode; 13632 return (total); 13633 } 13634 #endif /* LIBXML_XPTR_ENABLED */ 13635 13636 /* 13637 * Extract the old set, and then evaluate the result of the 13638 * expression for all the element in the set. use it to grow 13639 * up a new set. 13640 */ 13641 CHECK_TYPE0(XPATH_NODESET); 13642 obj = valuePop(ctxt); 13643 oldset = obj->nodesetval; 13644 13645 oldnode = ctxt->context->node; 13646 oldDoc = ctxt->context->doc; 13647 ctxt->context->node = NULL; 13648 13649 if ((oldset == NULL) || (oldset->nodeNr == 0)) { 13650 ctxt->context->contextSize = 0; 13651 ctxt->context->proximityPosition = 0; 13652 /* 13653 if (op->ch2 != -1) 13654 total += 13655 xmlXPathCompOpEval(ctxt, 13656 &comp->steps[op->ch2]); 13657 CHECK_ERROR0; 13658 res = valuePop(ctxt); 13659 if (res != NULL) 13660 xmlXPathFreeObject(res); 13661 */ 13662 valuePush(ctxt, obj); 13663 ctxt->context->node = oldnode; 13664 CHECK_ERROR0; 13665 } else { 13666 tmp = NULL; 13667 /* 13668 * Initialize the new set. 13669 * Also set the xpath document in case things like 13670 * key() evaluation are attempted on the predicate 13671 */ 13672 newset = xmlXPathNodeSetCreate(NULL); 13673 /* 13674 * SPEC XPath 1.0: 13675 * "For each node in the node-set to be filtered, the 13676 * PredicateExpr is evaluated with that node as the 13677 * context node, with the number of nodes in the 13678 * node-set as the context size, and with the proximity 13679 * position of the node in the node-set with respect to 13680 * the axis as the context position;" 13681 * @oldset is the node-set" to be filtered. 13682 * 13683 * SPEC XPath 1.0: 13684 * "only predicates change the context position and 13685 * context size (see [2.4 Predicates])." 13686 * Example: 13687 * node-set context pos 13688 * nA 1 13689 * nB 2 13690 * nC 3 13691 * After applying predicate [position() > 1] : 13692 * node-set context pos 13693 * nB 1 13694 * nC 2 13695 * 13696 * removed the first node in the node-set, then 13697 * the context position of the 13698 */ 13699 for (i = 0; i < oldset->nodeNr; i++) { 13700 /* 13701 * Run the evaluation with a node list made of 13702 * a single item in the nodeset. 13703 */ 13704 ctxt->context->node = oldset->nodeTab[i]; 13705 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) && 13706 (oldset->nodeTab[i]->doc != NULL)) 13707 ctxt->context->doc = oldset->nodeTab[i]->doc; 13708 if (tmp == NULL) { 13709 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13710 ctxt->context->node); 13711 } else { 13712 xmlXPathNodeSetAddUnique(tmp->nodesetval, 13713 ctxt->context->node); 13714 } 13715 valuePush(ctxt, tmp); 13716 ctxt->context->contextSize = oldset->nodeNr; 13717 ctxt->context->proximityPosition = i + 1; 13718 /* 13719 * Evaluate the predicate against the context node. 13720 * Can/should we optimize position() predicates 13721 * here (e.g. "[1]")? 13722 */ 13723 if (op->ch2 != -1) 13724 total += 13725 xmlXPathCompOpEval(ctxt, 13726 &comp->steps[op->ch2]); 13727 if (ctxt->error != XPATH_EXPRESSION_OK) { 13728 xmlXPathFreeNodeSet(newset); 13729 xmlXPathFreeObject(obj); 13730 return(0); 13731 } 13732 13733 /* 13734 * The result of the evaluation needs to be tested to 13735 * decide whether the filter succeeded or not 13736 */ 13737 /* 13738 * OPTIMIZE TODO: Can we use 13739 * xmlXPathNodeSetAdd*Unique()* instead? 13740 */ 13741 res = valuePop(ctxt); 13742 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 13743 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]); 13744 } 13745 13746 /* 13747 * Cleanup 13748 */ 13749 if (res != NULL) { 13750 xmlXPathReleaseObject(ctxt->context, res); 13751 } 13752 if (ctxt->value == tmp) { 13753 valuePop(ctxt); 13754 xmlXPathNodeSetClear(tmp->nodesetval, 1); 13755 /* 13756 * Don't free the temporary nodeset 13757 * in order to avoid massive recreation inside this 13758 * loop. 13759 */ 13760 } else 13761 tmp = NULL; 13762 ctxt->context->node = NULL; 13763 } 13764 if (tmp != NULL) 13765 xmlXPathReleaseObject(ctxt->context, tmp); 13766 /* 13767 * The result is used as the new evaluation set. 13768 */ 13769 xmlXPathReleaseObject(ctxt->context, obj); 13770 ctxt->context->node = NULL; 13771 ctxt->context->contextSize = -1; 13772 ctxt->context->proximityPosition = -1; 13773 /* may want to move this past the '}' later */ 13774 ctxt->context->doc = oldDoc; 13775 valuePush(ctxt, 13776 xmlXPathCacheWrapNodeSet(ctxt->context, newset)); 13777 } 13778 ctxt->context->node = oldnode; 13779 return (total); 13780 } 13781 case XPATH_OP_SORT: 13782 if (op->ch1 != -1) 13783 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13784 CHECK_ERROR0; 13785 if ((ctxt->value != NULL) && 13786 (ctxt->value->type == XPATH_NODESET) && 13787 (ctxt->value->nodesetval != NULL) && 13788 (ctxt->value->nodesetval->nodeNr > 1)) 13789 { 13790 xmlXPathNodeSetSort(ctxt->value->nodesetval); 13791 } 13792 return (total); 13793 #ifdef LIBXML_XPTR_ENABLED 13794 case XPATH_OP_RANGETO:{ 13795 xmlXPathObjectPtr range; 13796 xmlXPathObjectPtr res, obj; 13797 xmlXPathObjectPtr tmp; 13798 xmlLocationSetPtr newlocset = NULL; 13799 xmlLocationSetPtr oldlocset; 13800 xmlNodeSetPtr oldset; 13801 int i, j; 13802 13803 if (op->ch1 != -1) 13804 total += 13805 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13806 if (op->ch2 == -1) 13807 return (total); 13808 13809 if (ctxt->value->type == XPATH_LOCATIONSET) { 13810 /* 13811 * Extract the old locset, and then evaluate the result of the 13812 * expression for all the element in the locset. use it to grow 13813 * up a new locset. 13814 */ 13815 CHECK_TYPE0(XPATH_LOCATIONSET); 13816 obj = valuePop(ctxt); 13817 oldlocset = obj->user; 13818 13819 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) { 13820 ctxt->context->node = NULL; 13821 ctxt->context->contextSize = 0; 13822 ctxt->context->proximityPosition = 0; 13823 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]); 13824 res = valuePop(ctxt); 13825 if (res != NULL) { 13826 xmlXPathReleaseObject(ctxt->context, res); 13827 } 13828 valuePush(ctxt, obj); 13829 CHECK_ERROR0; 13830 return (total); 13831 } 13832 newlocset = xmlXPtrLocationSetCreate(NULL); 13833 13834 for (i = 0; i < oldlocset->locNr; i++) { 13835 /* 13836 * Run the evaluation with a node list made of a 13837 * single item in the nodelocset. 13838 */ 13839 ctxt->context->node = oldlocset->locTab[i]->user; 13840 ctxt->context->contextSize = oldlocset->locNr; 13841 ctxt->context->proximityPosition = i + 1; 13842 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13843 ctxt->context->node); 13844 valuePush(ctxt, tmp); 13845 13846 if (op->ch2 != -1) 13847 total += 13848 xmlXPathCompOpEval(ctxt, 13849 &comp->steps[op->ch2]); 13850 if (ctxt->error != XPATH_EXPRESSION_OK) { 13851 xmlXPathFreeObject(obj); 13852 return(0); 13853 } 13854 13855 res = valuePop(ctxt); 13856 if (res->type == XPATH_LOCATIONSET) { 13857 xmlLocationSetPtr rloc = 13858 (xmlLocationSetPtr)res->user; 13859 for (j=0; j<rloc->locNr; j++) { 13860 range = xmlXPtrNewRange( 13861 oldlocset->locTab[i]->user, 13862 oldlocset->locTab[i]->index, 13863 rloc->locTab[j]->user2, 13864 rloc->locTab[j]->index2); 13865 if (range != NULL) { 13866 xmlXPtrLocationSetAdd(newlocset, range); 13867 } 13868 } 13869 } else { 13870 range = xmlXPtrNewRangeNodeObject( 13871 (xmlNodePtr)oldlocset->locTab[i]->user, res); 13872 if (range != NULL) { 13873 xmlXPtrLocationSetAdd(newlocset,range); 13874 } 13875 } 13876 13877 /* 13878 * Cleanup 13879 */ 13880 if (res != NULL) { 13881 xmlXPathReleaseObject(ctxt->context, res); 13882 } 13883 if (ctxt->value == tmp) { 13884 res = valuePop(ctxt); 13885 xmlXPathReleaseObject(ctxt->context, res); 13886 } 13887 13888 ctxt->context->node = NULL; 13889 } 13890 } else { /* Not a location set */ 13891 CHECK_TYPE0(XPATH_NODESET); 13892 obj = valuePop(ctxt); 13893 oldset = obj->nodesetval; 13894 ctxt->context->node = NULL; 13895 13896 newlocset = xmlXPtrLocationSetCreate(NULL); 13897 13898 if (oldset != NULL) { 13899 for (i = 0; i < oldset->nodeNr; i++) { 13900 /* 13901 * Run the evaluation with a node list made of a single item 13902 * in the nodeset. 13903 */ 13904 ctxt->context->node = oldset->nodeTab[i]; 13905 /* 13906 * OPTIMIZE TODO: Avoid recreation for every iteration. 13907 */ 13908 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13909 ctxt->context->node); 13910 valuePush(ctxt, tmp); 13911 13912 if (op->ch2 != -1) 13913 total += 13914 xmlXPathCompOpEval(ctxt, 13915 &comp->steps[op->ch2]); 13916 if (ctxt->error != XPATH_EXPRESSION_OK) { 13917 xmlXPathFreeObject(obj); 13918 return(0); 13919 } 13920 13921 res = valuePop(ctxt); 13922 range = 13923 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i], 13924 res); 13925 if (range != NULL) { 13926 xmlXPtrLocationSetAdd(newlocset, range); 13927 } 13928 13929 /* 13930 * Cleanup 13931 */ 13932 if (res != NULL) { 13933 xmlXPathReleaseObject(ctxt->context, res); 13934 } 13935 if (ctxt->value == tmp) { 13936 res = valuePop(ctxt); 13937 xmlXPathReleaseObject(ctxt->context, res); 13938 } 13939 13940 ctxt->context->node = NULL; 13941 } 13942 } 13943 } 13944 13945 /* 13946 * The result is used as the new evaluation set. 13947 */ 13948 xmlXPathReleaseObject(ctxt->context, obj); 13949 ctxt->context->node = NULL; 13950 ctxt->context->contextSize = -1; 13951 ctxt->context->proximityPosition = -1; 13952 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset)); 13953 return (total); 13954 } 13955 #endif /* LIBXML_XPTR_ENABLED */ 13956 } 13957 xmlGenericError(xmlGenericErrorContext, 13958 "XPath: unknown precompiled operation %d\n", op->op); 13959 return (total); 13960 } 13961 13962 /** 13963 * xmlXPathCompOpEvalToBoolean: 13964 * @ctxt: the XPath parser context 13965 * 13966 * Evaluates if the expression evaluates to true. 13967 * 13968 * Returns 1 if true, 0 if false and -1 on API or internal errors. 13969 */ 13970 static int 13971 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt, 13972 xmlXPathStepOpPtr op, 13973 int isPredicate) 13974 { 13975 xmlXPathObjectPtr resObj = NULL; 13976 13977 start: 13978 /* comp = ctxt->comp; */ 13979 switch (op->op) { 13980 case XPATH_OP_END: 13981 return (0); 13982 case XPATH_OP_VALUE: 13983 resObj = (xmlXPathObjectPtr) op->value4; 13984 if (isPredicate) 13985 return(xmlXPathEvaluatePredicateResult(ctxt, resObj)); 13986 return(xmlXPathCastToBoolean(resObj)); 13987 case XPATH_OP_SORT: 13988 /* 13989 * We don't need sorting for boolean results. Skip this one. 13990 */ 13991 if (op->ch1 != -1) { 13992 op = &ctxt->comp->steps[op->ch1]; 13993 goto start; 13994 } 13995 return(0); 13996 case XPATH_OP_COLLECT: 13997 if (op->ch1 == -1) 13998 return(0); 13999 14000 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]); 14001 if (ctxt->error != XPATH_EXPRESSION_OK) 14002 return(-1); 14003 14004 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1); 14005 if (ctxt->error != XPATH_EXPRESSION_OK) 14006 return(-1); 14007 14008 resObj = valuePop(ctxt); 14009 if (resObj == NULL) 14010 return(-1); 14011 break; 14012 default: 14013 /* 14014 * Fallback to call xmlXPathCompOpEval(). 14015 */ 14016 xmlXPathCompOpEval(ctxt, op); 14017 if (ctxt->error != XPATH_EXPRESSION_OK) 14018 return(-1); 14019 14020 resObj = valuePop(ctxt); 14021 if (resObj == NULL) 14022 return(-1); 14023 break; 14024 } 14025 14026 if (resObj) { 14027 int res; 14028 14029 if (resObj->type == XPATH_BOOLEAN) { 14030 res = resObj->boolval; 14031 } else if (isPredicate) { 14032 /* 14033 * For predicates a result of type "number" is handled 14034 * differently: 14035 * SPEC XPath 1.0: 14036 * "If the result is a number, the result will be converted 14037 * to true if the number is equal to the context position 14038 * and will be converted to false otherwise;" 14039 */ 14040 res = xmlXPathEvaluatePredicateResult(ctxt, resObj); 14041 } else { 14042 res = xmlXPathCastToBoolean(resObj); 14043 } 14044 xmlXPathReleaseObject(ctxt->context, resObj); 14045 return(res); 14046 } 14047 14048 return(0); 14049 } 14050 14051 #ifdef XPATH_STREAMING 14052 /** 14053 * xmlXPathRunStreamEval: 14054 * @ctxt: the XPath parser context with the compiled expression 14055 * 14056 * Evaluate the Precompiled Streamable XPath expression in the given context. 14057 */ 14058 static int 14059 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp, 14060 xmlXPathObjectPtr *resultSeq, int toBool) 14061 { 14062 int max_depth, min_depth; 14063 int from_root; 14064 int ret, depth; 14065 int eval_all_nodes; 14066 xmlNodePtr cur = NULL, limit = NULL; 14067 xmlStreamCtxtPtr patstream = NULL; 14068 14069 int nb_nodes = 0; 14070 14071 if ((ctxt == NULL) || (comp == NULL)) 14072 return(-1); 14073 max_depth = xmlPatternMaxDepth(comp); 14074 if (max_depth == -1) 14075 return(-1); 14076 if (max_depth == -2) 14077 max_depth = 10000; 14078 min_depth = xmlPatternMinDepth(comp); 14079 if (min_depth == -1) 14080 return(-1); 14081 from_root = xmlPatternFromRoot(comp); 14082 if (from_root < 0) 14083 return(-1); 14084 #if 0 14085 printf("stream eval: depth %d from root %d\n", max_depth, from_root); 14086 #endif 14087 14088 if (! toBool) { 14089 if (resultSeq == NULL) 14090 return(-1); 14091 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL); 14092 if (*resultSeq == NULL) 14093 return(-1); 14094 } 14095 14096 /* 14097 * handle the special cases of "/" amd "." being matched 14098 */ 14099 if (min_depth == 0) { 14100 if (from_root) { 14101 /* Select "/" */ 14102 if (toBool) 14103 return(1); 14104 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, 14105 (xmlNodePtr) ctxt->doc); 14106 } else { 14107 /* Select "self::node()" */ 14108 if (toBool) 14109 return(1); 14110 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node); 14111 } 14112 } 14113 if (max_depth == 0) { 14114 return(0); 14115 } 14116 14117 if (from_root) { 14118 cur = (xmlNodePtr)ctxt->doc; 14119 } else if (ctxt->node != NULL) { 14120 switch (ctxt->node->type) { 14121 case XML_ELEMENT_NODE: 14122 case XML_DOCUMENT_NODE: 14123 case XML_DOCUMENT_FRAG_NODE: 14124 case XML_HTML_DOCUMENT_NODE: 14125 #ifdef LIBXML_DOCB_ENABLED 14126 case XML_DOCB_DOCUMENT_NODE: 14127 #endif 14128 cur = ctxt->node; 14129 break; 14130 case XML_ATTRIBUTE_NODE: 14131 case XML_TEXT_NODE: 14132 case XML_CDATA_SECTION_NODE: 14133 case XML_ENTITY_REF_NODE: 14134 case XML_ENTITY_NODE: 14135 case XML_PI_NODE: 14136 case XML_COMMENT_NODE: 14137 case XML_NOTATION_NODE: 14138 case XML_DTD_NODE: 14139 case XML_DOCUMENT_TYPE_NODE: 14140 case XML_ELEMENT_DECL: 14141 case XML_ATTRIBUTE_DECL: 14142 case XML_ENTITY_DECL: 14143 case XML_NAMESPACE_DECL: 14144 case XML_XINCLUDE_START: 14145 case XML_XINCLUDE_END: 14146 break; 14147 } 14148 limit = cur; 14149 } 14150 if (cur == NULL) { 14151 return(0); 14152 } 14153 14154 patstream = xmlPatternGetStreamCtxt(comp); 14155 if (patstream == NULL) { 14156 /* 14157 * QUESTION TODO: Is this an error? 14158 */ 14159 return(0); 14160 } 14161 14162 eval_all_nodes = xmlStreamWantsAnyNode(patstream); 14163 14164 if (from_root) { 14165 ret = xmlStreamPush(patstream, NULL, NULL); 14166 if (ret < 0) { 14167 } else if (ret == 1) { 14168 if (toBool) 14169 goto return_1; 14170 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur); 14171 } 14172 } 14173 depth = 0; 14174 goto scan_children; 14175 next_node: 14176 do { 14177 nb_nodes++; 14178 14179 switch (cur->type) { 14180 case XML_ELEMENT_NODE: 14181 case XML_TEXT_NODE: 14182 case XML_CDATA_SECTION_NODE: 14183 case XML_COMMENT_NODE: 14184 case XML_PI_NODE: 14185 if (cur->type == XML_ELEMENT_NODE) { 14186 ret = xmlStreamPush(patstream, cur->name, 14187 (cur->ns ? cur->ns->href : NULL)); 14188 } else if (eval_all_nodes) 14189 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type); 14190 else 14191 break; 14192 14193 if (ret < 0) { 14194 /* NOP. */ 14195 } else if (ret == 1) { 14196 if (toBool) 14197 goto return_1; 14198 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur); 14199 } 14200 if ((cur->children == NULL) || (depth >= max_depth)) { 14201 ret = xmlStreamPop(patstream); 14202 while (cur->next != NULL) { 14203 cur = cur->next; 14204 if ((cur->type != XML_ENTITY_DECL) && 14205 (cur->type != XML_DTD_NODE)) 14206 goto next_node; 14207 } 14208 } 14209 default: 14210 break; 14211 } 14212 14213 scan_children: 14214 if ((cur->children != NULL) && (depth < max_depth)) { 14215 /* 14216 * Do not descend on entities declarations 14217 */ 14218 if (cur->children->type != XML_ENTITY_DECL) { 14219 cur = cur->children; 14220 depth++; 14221 /* 14222 * Skip DTDs 14223 */ 14224 if (cur->type != XML_DTD_NODE) 14225 continue; 14226 } 14227 } 14228 14229 if (cur == limit) 14230 break; 14231 14232 while (cur->next != NULL) { 14233 cur = cur->next; 14234 if ((cur->type != XML_ENTITY_DECL) && 14235 (cur->type != XML_DTD_NODE)) 14236 goto next_node; 14237 } 14238 14239 do { 14240 cur = cur->parent; 14241 depth--; 14242 if ((cur == NULL) || (cur == limit)) 14243 goto done; 14244 if (cur->type == XML_ELEMENT_NODE) { 14245 ret = xmlStreamPop(patstream); 14246 } else if ((eval_all_nodes) && 14247 ((cur->type == XML_TEXT_NODE) || 14248 (cur->type == XML_CDATA_SECTION_NODE) || 14249 (cur->type == XML_COMMENT_NODE) || 14250 (cur->type == XML_PI_NODE))) 14251 { 14252 ret = xmlStreamPop(patstream); 14253 } 14254 if (cur->next != NULL) { 14255 cur = cur->next; 14256 break; 14257 } 14258 } while (cur != NULL); 14259 14260 } while ((cur != NULL) && (depth >= 0)); 14261 14262 done: 14263 14264 #if 0 14265 printf("stream eval: checked %d nodes selected %d\n", 14266 nb_nodes, retObj->nodesetval->nodeNr); 14267 #endif 14268 14269 if (patstream) 14270 xmlFreeStreamCtxt(patstream); 14271 return(0); 14272 14273 return_1: 14274 if (patstream) 14275 xmlFreeStreamCtxt(patstream); 14276 return(1); 14277 } 14278 #endif /* XPATH_STREAMING */ 14279 14280 /** 14281 * xmlXPathRunEval: 14282 * @ctxt: the XPath parser context with the compiled expression 14283 * @toBool: evaluate to a boolean result 14284 * 14285 * Evaluate the Precompiled XPath expression in the given context. 14286 */ 14287 static int 14288 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool) 14289 { 14290 xmlXPathCompExprPtr comp; 14291 14292 if ((ctxt == NULL) || (ctxt->comp == NULL)) 14293 return(-1); 14294 14295 if (ctxt->valueTab == NULL) { 14296 /* Allocate the value stack */ 14297 ctxt->valueTab = (xmlXPathObjectPtr *) 14298 xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); 14299 if (ctxt->valueTab == NULL) { 14300 xmlXPathPErrMemory(ctxt, "creating evaluation context\n"); 14301 xmlFree(ctxt); 14302 } 14303 ctxt->valueNr = 0; 14304 ctxt->valueMax = 10; 14305 ctxt->value = NULL; 14306 } 14307 #ifdef XPATH_STREAMING 14308 if (ctxt->comp->stream) { 14309 int res; 14310 14311 if (toBool) { 14312 /* 14313 * Evaluation to boolean result. 14314 */ 14315 res = xmlXPathRunStreamEval(ctxt->context, 14316 ctxt->comp->stream, NULL, 1); 14317 if (res != -1) 14318 return(res); 14319 } else { 14320 xmlXPathObjectPtr resObj = NULL; 14321 14322 /* 14323 * Evaluation to a sequence. 14324 */ 14325 res = xmlXPathRunStreamEval(ctxt->context, 14326 ctxt->comp->stream, &resObj, 0); 14327 14328 if ((res != -1) && (resObj != NULL)) { 14329 valuePush(ctxt, resObj); 14330 return(0); 14331 } 14332 if (resObj != NULL) 14333 xmlXPathReleaseObject(ctxt->context, resObj); 14334 } 14335 /* 14336 * QUESTION TODO: This falls back to normal XPath evaluation 14337 * if res == -1. Is this intended? 14338 */ 14339 } 14340 #endif 14341 comp = ctxt->comp; 14342 if (comp->last < 0) { 14343 xmlGenericError(xmlGenericErrorContext, 14344 "xmlXPathRunEval: last is less than zero\n"); 14345 return(-1); 14346 } 14347 if (toBool) 14348 return(xmlXPathCompOpEvalToBoolean(ctxt, 14349 &comp->steps[comp->last], 0)); 14350 else 14351 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]); 14352 14353 return(0); 14354 } 14355 14356 /************************************************************************ 14357 * * 14358 * Public interfaces * 14359 * * 14360 ************************************************************************/ 14361 14362 /** 14363 * xmlXPathEvalPredicate: 14364 * @ctxt: the XPath context 14365 * @res: the Predicate Expression evaluation result 14366 * 14367 * Evaluate a predicate result for the current node. 14368 * A PredicateExpr is evaluated by evaluating the Expr and converting 14369 * the result to a boolean. If the result is a number, the result will 14370 * be converted to true if the number is equal to the position of the 14371 * context node in the context node list (as returned by the position 14372 * function) and will be converted to false otherwise; if the result 14373 * is not a number, then the result will be converted as if by a call 14374 * to the boolean function. 14375 * 14376 * Returns 1 if predicate is true, 0 otherwise 14377 */ 14378 int 14379 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) { 14380 if ((ctxt == NULL) || (res == NULL)) return(0); 14381 switch (res->type) { 14382 case XPATH_BOOLEAN: 14383 return(res->boolval); 14384 case XPATH_NUMBER: 14385 return(res->floatval == ctxt->proximityPosition); 14386 case XPATH_NODESET: 14387 case XPATH_XSLT_TREE: 14388 if (res->nodesetval == NULL) 14389 return(0); 14390 return(res->nodesetval->nodeNr != 0); 14391 case XPATH_STRING: 14392 return((res->stringval != NULL) && 14393 (xmlStrlen(res->stringval) != 0)); 14394 default: 14395 STRANGE 14396 } 14397 return(0); 14398 } 14399 14400 /** 14401 * xmlXPathEvaluatePredicateResult: 14402 * @ctxt: the XPath Parser context 14403 * @res: the Predicate Expression evaluation result 14404 * 14405 * Evaluate a predicate result for the current node. 14406 * A PredicateExpr is evaluated by evaluating the Expr and converting 14407 * the result to a boolean. If the result is a number, the result will 14408 * be converted to true if the number is equal to the position of the 14409 * context node in the context node list (as returned by the position 14410 * function) and will be converted to false otherwise; if the result 14411 * is not a number, then the result will be converted as if by a call 14412 * to the boolean function. 14413 * 14414 * Returns 1 if predicate is true, 0 otherwise 14415 */ 14416 int 14417 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt, 14418 xmlXPathObjectPtr res) { 14419 if ((ctxt == NULL) || (res == NULL)) return(0); 14420 switch (res->type) { 14421 case XPATH_BOOLEAN: 14422 return(res->boolval); 14423 case XPATH_NUMBER: 14424 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200)) 14425 return((res->floatval == ctxt->context->proximityPosition) && 14426 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/ 14427 #else 14428 return(res->floatval == ctxt->context->proximityPosition); 14429 #endif 14430 case XPATH_NODESET: 14431 case XPATH_XSLT_TREE: 14432 if (res->nodesetval == NULL) 14433 return(0); 14434 return(res->nodesetval->nodeNr != 0); 14435 case XPATH_STRING: 14436 return((res->stringval != NULL) && (res->stringval[0] != 0)); 14437 #ifdef LIBXML_XPTR_ENABLED 14438 case XPATH_LOCATIONSET:{ 14439 xmlLocationSetPtr ptr = res->user; 14440 if (ptr == NULL) 14441 return(0); 14442 return (ptr->locNr != 0); 14443 } 14444 #endif 14445 default: 14446 STRANGE 14447 } 14448 return(0); 14449 } 14450 14451 #ifdef XPATH_STREAMING 14452 /** 14453 * xmlXPathTryStreamCompile: 14454 * @ctxt: an XPath context 14455 * @str: the XPath expression 14456 * 14457 * Try to compile the XPath expression as a streamable subset. 14458 * 14459 * Returns the compiled expression or NULL if failed to compile. 14460 */ 14461 static xmlXPathCompExprPtr 14462 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { 14463 /* 14464 * Optimization: use streaming patterns when the XPath expression can 14465 * be compiled to a stream lookup 14466 */ 14467 xmlPatternPtr stream; 14468 xmlXPathCompExprPtr comp; 14469 xmlDictPtr dict = NULL; 14470 const xmlChar **namespaces = NULL; 14471 xmlNsPtr ns; 14472 int i, j; 14473 14474 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) && 14475 (!xmlStrchr(str, '@'))) { 14476 const xmlChar *tmp; 14477 14478 /* 14479 * We don't try to handle expressions using the verbose axis 14480 * specifiers ("::"), just the simplied form at this point. 14481 * Additionally, if there is no list of namespaces available and 14482 * there's a ":" in the expression, indicating a prefixed QName, 14483 * then we won't try to compile either. xmlPatterncompile() needs 14484 * to have a list of namespaces at compilation time in order to 14485 * compile prefixed name tests. 14486 */ 14487 tmp = xmlStrchr(str, ':'); 14488 if ((tmp != NULL) && 14489 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':'))) 14490 return(NULL); 14491 14492 if (ctxt != NULL) { 14493 dict = ctxt->dict; 14494 if (ctxt->nsNr > 0) { 14495 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*)); 14496 if (namespaces == NULL) { 14497 xmlXPathErrMemory(ctxt, "allocating namespaces array\n"); 14498 return(NULL); 14499 } 14500 for (i = 0, j = 0; (j < ctxt->nsNr); j++) { 14501 ns = ctxt->namespaces[j]; 14502 namespaces[i++] = ns->href; 14503 namespaces[i++] = ns->prefix; 14504 } 14505 namespaces[i++] = NULL; 14506 namespaces[i++] = NULL; 14507 } 14508 } 14509 14510 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, 14511 &namespaces[0]); 14512 if (namespaces != NULL) { 14513 xmlFree((xmlChar **)namespaces); 14514 } 14515 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) { 14516 comp = xmlXPathNewCompExpr(); 14517 if (comp == NULL) { 14518 xmlXPathErrMemory(ctxt, "allocating streamable expression\n"); 14519 return(NULL); 14520 } 14521 comp->stream = stream; 14522 comp->dict = dict; 14523 if (comp->dict) 14524 xmlDictReference(comp->dict); 14525 return(comp); 14526 } 14527 xmlFreePattern(stream); 14528 } 14529 return(NULL); 14530 } 14531 #endif /* XPATH_STREAMING */ 14532 14533 static int 14534 xmlXPathCanRewriteDosExpression(xmlChar *expr) 14535 { 14536 if (expr == NULL) 14537 return(0); 14538 do { 14539 if ((*expr == '/') && (*(++expr) == '/')) 14540 return(1); 14541 } while (*expr++); 14542 return(0); 14543 } 14544 static void 14545 xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op) 14546 { 14547 /* 14548 * Try to rewrite "descendant-or-self::node()/foo" to an optimized 14549 * internal representation. 14550 */ 14551 if (op->ch1 != -1) { 14552 if ((op->op == XPATH_OP_COLLECT /* 11 */) && 14553 ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) && 14554 ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) && 14555 ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */)) 14556 { 14557 /* 14558 * This is a "child::foo" 14559 */ 14560 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1]; 14561 14562 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) && 14563 (prevop->ch1 != -1) && 14564 ((xmlXPathAxisVal) prevop->value == 14565 AXIS_DESCENDANT_OR_SELF) && 14566 (prevop->ch2 == -1) && 14567 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) && 14568 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) && 14569 (comp->steps[prevop->ch1].op == XPATH_OP_ROOT)) 14570 { 14571 /* 14572 * This is a "/descendant-or-self::node()" without predicates. 14573 * Eliminate it. 14574 */ 14575 op->ch1 = prevop->ch1; 14576 op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM; 14577 } 14578 } 14579 if (op->ch1 != -1) 14580 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]); 14581 } 14582 if (op->ch2 != -1) 14583 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]); 14584 } 14585 14586 /** 14587 * xmlXPathCtxtCompile: 14588 * @ctxt: an XPath context 14589 * @str: the XPath expression 14590 * 14591 * Compile an XPath expression 14592 * 14593 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL. 14594 * the caller has to free the object. 14595 */ 14596 xmlXPathCompExprPtr 14597 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { 14598 xmlXPathParserContextPtr pctxt; 14599 xmlXPathCompExprPtr comp; 14600 14601 #ifdef XPATH_STREAMING 14602 comp = xmlXPathTryStreamCompile(ctxt, str); 14603 if (comp != NULL) 14604 return(comp); 14605 #endif 14606 14607 xmlXPathInit(); 14608 14609 pctxt = xmlXPathNewParserContext(str, ctxt); 14610 if (pctxt == NULL) 14611 return NULL; 14612 xmlXPathCompileExpr(pctxt, 1); 14613 14614 if( pctxt->error != XPATH_EXPRESSION_OK ) 14615 { 14616 xmlXPathFreeParserContext(pctxt); 14617 return(NULL); 14618 } 14619 14620 if (*pctxt->cur != 0) { 14621 /* 14622 * aleksey: in some cases this line prints *second* error message 14623 * (see bug #78858) and probably this should be fixed. 14624 * However, we are not sure that all error messages are printed 14625 * out in other places. It's not critical so we leave it as-is for now 14626 */ 14627 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR); 14628 comp = NULL; 14629 } else { 14630 comp = pctxt->comp; 14631 pctxt->comp = NULL; 14632 } 14633 xmlXPathFreeParserContext(pctxt); 14634 14635 if (comp != NULL) { 14636 comp->expr = xmlStrdup(str); 14637 #ifdef DEBUG_EVAL_COUNTS 14638 comp->string = xmlStrdup(str); 14639 comp->nb = 0; 14640 #endif 14641 if ((comp->expr != NULL) && 14642 (comp->nbStep > 2) && 14643 (comp->last >= 0) && 14644 (xmlXPathCanRewriteDosExpression(comp->expr) == 1)) 14645 { 14646 xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]); 14647 } 14648 } 14649 return(comp); 14650 } 14651 14652 /** 14653 * xmlXPathCompile: 14654 * @str: the XPath expression 14655 * 14656 * Compile an XPath expression 14657 * 14658 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL. 14659 * the caller has to free the object. 14660 */ 14661 xmlXPathCompExprPtr 14662 xmlXPathCompile(const xmlChar *str) { 14663 return(xmlXPathCtxtCompile(NULL, str)); 14664 } 14665 14666 /** 14667 * xmlXPathCompiledEvalInternal: 14668 * @comp: the compiled XPath expression 14669 * @ctxt: the XPath context 14670 * @resObj: the resulting XPath object or NULL 14671 * @toBool: 1 if only a boolean result is requested 14672 * 14673 * Evaluate the Precompiled XPath expression in the given context. 14674 * The caller has to free @resObj. 14675 * 14676 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14677 * the caller has to free the object. 14678 */ 14679 static int 14680 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp, 14681 xmlXPathContextPtr ctxt, 14682 xmlXPathObjectPtr *resObj, 14683 int toBool) 14684 { 14685 xmlXPathParserContextPtr pctxt; 14686 #ifndef LIBXML_THREAD_ENABLED 14687 static int reentance = 0; 14688 #endif 14689 int res; 14690 14691 CHECK_CTXT_NEG(ctxt) 14692 14693 if (comp == NULL) 14694 return(-1); 14695 xmlXPathInit(); 14696 14697 #ifndef LIBXML_THREAD_ENABLED 14698 reentance++; 14699 if (reentance > 1) 14700 xmlXPathDisableOptimizer = 1; 14701 #endif 14702 14703 #ifdef DEBUG_EVAL_COUNTS 14704 comp->nb++; 14705 if ((comp->string != NULL) && (comp->nb > 100)) { 14706 fprintf(stderr, "100 x %s\n", comp->string); 14707 comp->nb = 0; 14708 } 14709 #endif 14710 pctxt = xmlXPathCompParserContext(comp, ctxt); 14711 res = xmlXPathRunEval(pctxt, toBool); 14712 14713 if (resObj) { 14714 if (pctxt->value == NULL) { 14715 xmlGenericError(xmlGenericErrorContext, 14716 "xmlXPathCompiledEval: evaluation failed\n"); 14717 *resObj = NULL; 14718 } else { 14719 *resObj = valuePop(pctxt); 14720 } 14721 } 14722 14723 /* 14724 * Pop all remaining objects from the stack. 14725 */ 14726 if (pctxt->valueNr > 0) { 14727 xmlXPathObjectPtr tmp; 14728 int stack = 0; 14729 14730 do { 14731 tmp = valuePop(pctxt); 14732 if (tmp != NULL) { 14733 stack++; 14734 xmlXPathReleaseObject(ctxt, tmp); 14735 } 14736 } while (tmp != NULL); 14737 if ((stack != 0) && 14738 ((toBool) || ((resObj) && (*resObj)))) 14739 { 14740 xmlGenericError(xmlGenericErrorContext, 14741 "xmlXPathCompiledEval: %d objects left on the stack.\n", 14742 stack); 14743 } 14744 } 14745 14746 if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) { 14747 xmlXPathFreeObject(*resObj); 14748 *resObj = NULL; 14749 } 14750 pctxt->comp = NULL; 14751 xmlXPathFreeParserContext(pctxt); 14752 #ifndef LIBXML_THREAD_ENABLED 14753 reentance--; 14754 #endif 14755 14756 return(res); 14757 } 14758 14759 /** 14760 * xmlXPathCompiledEval: 14761 * @comp: the compiled XPath expression 14762 * @ctx: the XPath context 14763 * 14764 * Evaluate the Precompiled XPath expression in the given context. 14765 * 14766 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14767 * the caller has to free the object. 14768 */ 14769 xmlXPathObjectPtr 14770 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) 14771 { 14772 xmlXPathObjectPtr res = NULL; 14773 14774 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0); 14775 return(res); 14776 } 14777 14778 /** 14779 * xmlXPathCompiledEvalToBoolean: 14780 * @comp: the compiled XPath expression 14781 * @ctxt: the XPath context 14782 * 14783 * Applies the XPath boolean() function on the result of the given 14784 * compiled expression. 14785 * 14786 * Returns 1 if the expression evaluated to true, 0 if to false and 14787 * -1 in API and internal errors. 14788 */ 14789 int 14790 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp, 14791 xmlXPathContextPtr ctxt) 14792 { 14793 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1)); 14794 } 14795 14796 /** 14797 * xmlXPathEvalExpr: 14798 * @ctxt: the XPath Parser context 14799 * 14800 * Parse and evaluate an XPath expression in the given context, 14801 * then push the result on the context stack 14802 */ 14803 void 14804 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) { 14805 #ifdef XPATH_STREAMING 14806 xmlXPathCompExprPtr comp; 14807 #endif 14808 14809 if (ctxt == NULL) return; 14810 14811 #ifdef XPATH_STREAMING 14812 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base); 14813 if (comp != NULL) { 14814 if (ctxt->comp != NULL) 14815 xmlXPathFreeCompExpr(ctxt->comp); 14816 ctxt->comp = comp; 14817 if (ctxt->cur != NULL) 14818 while (*ctxt->cur != 0) ctxt->cur++; 14819 } else 14820 #endif 14821 { 14822 xmlXPathCompileExpr(ctxt, 1); 14823 /* 14824 * In this scenario the expression string will sit in ctxt->base. 14825 */ 14826 if ((ctxt->error == XPATH_EXPRESSION_OK) && 14827 (ctxt->comp != NULL) && 14828 (ctxt->base != NULL) && 14829 (ctxt->comp->nbStep > 2) && 14830 (ctxt->comp->last >= 0) && 14831 (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1)) 14832 { 14833 xmlXPathRewriteDOSExpression(ctxt->comp, 14834 &ctxt->comp->steps[ctxt->comp->last]); 14835 } 14836 } 14837 CHECK_ERROR; 14838 xmlXPathRunEval(ctxt, 0); 14839 } 14840 14841 /** 14842 * xmlXPathEval: 14843 * @str: the XPath expression 14844 * @ctx: the XPath context 14845 * 14846 * Evaluate the XPath Location Path in the given context. 14847 * 14848 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14849 * the caller has to free the object. 14850 */ 14851 xmlXPathObjectPtr 14852 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) { 14853 xmlXPathParserContextPtr ctxt; 14854 xmlXPathObjectPtr res, tmp, init = NULL; 14855 int stack = 0; 14856 14857 CHECK_CTXT(ctx) 14858 14859 xmlXPathInit(); 14860 14861 ctxt = xmlXPathNewParserContext(str, ctx); 14862 if (ctxt == NULL) 14863 return NULL; 14864 xmlXPathEvalExpr(ctxt); 14865 14866 if (ctxt->value == NULL) { 14867 xmlGenericError(xmlGenericErrorContext, 14868 "xmlXPathEval: evaluation failed\n"); 14869 res = NULL; 14870 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL) 14871 #ifdef XPATH_STREAMING 14872 && (ctxt->comp->stream == NULL) 14873 #endif 14874 ) { 14875 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR); 14876 res = NULL; 14877 } else { 14878 res = valuePop(ctxt); 14879 } 14880 14881 do { 14882 tmp = valuePop(ctxt); 14883 if (tmp != NULL) { 14884 if (tmp != init) 14885 stack++; 14886 xmlXPathReleaseObject(ctx, tmp); 14887 } 14888 } while (tmp != NULL); 14889 if ((stack != 0) && (res != NULL)) { 14890 xmlGenericError(xmlGenericErrorContext, 14891 "xmlXPathEval: %d object left on the stack\n", 14892 stack); 14893 } 14894 if (ctxt->error != XPATH_EXPRESSION_OK) { 14895 xmlXPathFreeObject(res); 14896 res = NULL; 14897 } 14898 14899 xmlXPathFreeParserContext(ctxt); 14900 return(res); 14901 } 14902 14903 /** 14904 * xmlXPathEvalExpression: 14905 * @str: the XPath expression 14906 * @ctxt: the XPath context 14907 * 14908 * Evaluate the XPath expression in the given context. 14909 * 14910 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14911 * the caller has to free the object. 14912 */ 14913 xmlXPathObjectPtr 14914 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) { 14915 xmlXPathParserContextPtr pctxt; 14916 xmlXPathObjectPtr res, tmp; 14917 int stack = 0; 14918 14919 CHECK_CTXT(ctxt) 14920 14921 xmlXPathInit(); 14922 14923 pctxt = xmlXPathNewParserContext(str, ctxt); 14924 if (pctxt == NULL) 14925 return NULL; 14926 xmlXPathEvalExpr(pctxt); 14927 14928 if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) { 14929 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR); 14930 res = NULL; 14931 } else { 14932 res = valuePop(pctxt); 14933 } 14934 do { 14935 tmp = valuePop(pctxt); 14936 if (tmp != NULL) { 14937 xmlXPathReleaseObject(ctxt, tmp); 14938 stack++; 14939 } 14940 } while (tmp != NULL); 14941 if ((stack != 0) && (res != NULL)) { 14942 xmlGenericError(xmlGenericErrorContext, 14943 "xmlXPathEvalExpression: %d object left on the stack\n", 14944 stack); 14945 } 14946 xmlXPathFreeParserContext(pctxt); 14947 return(res); 14948 } 14949 14950 /************************************************************************ 14951 * * 14952 * Extra functions not pertaining to the XPath spec * 14953 * * 14954 ************************************************************************/ 14955 /** 14956 * xmlXPathEscapeUriFunction: 14957 * @ctxt: the XPath Parser context 14958 * @nargs: the number of arguments 14959 * 14960 * Implement the escape-uri() XPath function 14961 * string escape-uri(string $str, bool $escape-reserved) 14962 * 14963 * This function applies the URI escaping rules defined in section 2 of [RFC 14964 * 2396] to the string supplied as $uri-part, which typically represents all 14965 * or part of a URI. The effect of the function is to replace any special 14966 * character in the string by an escape sequence of the form %xx%yy..., 14967 * where xxyy... is the hexadecimal representation of the octets used to 14968 * represent the character in UTF-8. 14969 * 14970 * The set of characters that are escaped depends on the setting of the 14971 * boolean argument $escape-reserved. 14972 * 14973 * If $escape-reserved is true, all characters are escaped other than lower 14974 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters 14975 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!" 14976 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only 14977 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and 14978 * A-F). 14979 * 14980 * If $escape-reserved is false, the behavior differs in that characters 14981 * referred to in [RFC 2396] as reserved characters are not escaped. These 14982 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",". 14983 * 14984 * [RFC 2396] does not define whether escaped URIs should use lower case or 14985 * upper case for hexadecimal digits. To ensure that escaped URIs can be 14986 * compared using string comparison functions, this function must always use 14987 * the upper-case letters A-F. 14988 * 14989 * Generally, $escape-reserved should be set to true when escaping a string 14990 * that is to form a single part of a URI, and to false when escaping an 14991 * entire URI or URI reference. 14992 * 14993 * In the case of non-ascii characters, the string is encoded according to 14994 * utf-8 and then converted according to RFC 2396. 14995 * 14996 * Examples 14997 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true()) 14998 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean" 14999 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false()) 15000 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean" 15001 * 15002 */ 15003 static void 15004 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) { 15005 xmlXPathObjectPtr str; 15006 int escape_reserved; 15007 xmlBufferPtr target; 15008 xmlChar *cptr; 15009 xmlChar escape[4]; 15010 15011 CHECK_ARITY(2); 15012 15013 escape_reserved = xmlXPathPopBoolean(ctxt); 15014 15015 CAST_TO_STRING; 15016 str = valuePop(ctxt); 15017 15018 target = xmlBufferCreate(); 15019 15020 escape[0] = '%'; 15021 escape[3] = 0; 15022 15023 if (target) { 15024 for (cptr = str->stringval; *cptr; cptr++) { 15025 if ((*cptr >= 'A' && *cptr <= 'Z') || 15026 (*cptr >= 'a' && *cptr <= 'z') || 15027 (*cptr >= '0' && *cptr <= '9') || 15028 *cptr == '-' || *cptr == '_' || *cptr == '.' || 15029 *cptr == '!' || *cptr == '~' || *cptr == '*' || 15030 *cptr == '\''|| *cptr == '(' || *cptr == ')' || 15031 (*cptr == '%' && 15032 ((cptr[1] >= 'A' && cptr[1] <= 'F') || 15033 (cptr[1] >= 'a' && cptr[1] <= 'f') || 15034 (cptr[1] >= '0' && cptr[1] <= '9')) && 15035 ((cptr[2] >= 'A' && cptr[2] <= 'F') || 15036 (cptr[2] >= 'a' && cptr[2] <= 'f') || 15037 (cptr[2] >= '0' && cptr[2] <= '9'))) || 15038 (!escape_reserved && 15039 (*cptr == ';' || *cptr == '/' || *cptr == '?' || 15040 *cptr == ':' || *cptr == '@' || *cptr == '&' || 15041 *cptr == '=' || *cptr == '+' || *cptr == '$' || 15042 *cptr == ','))) { 15043 xmlBufferAdd(target, cptr, 1); 15044 } else { 15045 if ((*cptr >> 4) < 10) 15046 escape[1] = '0' + (*cptr >> 4); 15047 else 15048 escape[1] = 'A' - 10 + (*cptr >> 4); 15049 if ((*cptr & 0xF) < 10) 15050 escape[2] = '0' + (*cptr & 0xF); 15051 else 15052 escape[2] = 'A' - 10 + (*cptr & 0xF); 15053 15054 xmlBufferAdd(target, &escape[0], 3); 15055 } 15056 } 15057 } 15058 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 15059 xmlBufferContent(target))); 15060 xmlBufferFree(target); 15061 xmlXPathReleaseObject(ctxt->context, str); 15062 } 15063 15064 /** 15065 * xmlXPathRegisterAllFunctions: 15066 * @ctxt: the XPath context 15067 * 15068 * Registers all default XPath functions in this context 15069 */ 15070 void 15071 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt) 15072 { 15073 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean", 15074 xmlXPathBooleanFunction); 15075 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling", 15076 xmlXPathCeilingFunction); 15077 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count", 15078 xmlXPathCountFunction); 15079 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat", 15080 xmlXPathConcatFunction); 15081 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains", 15082 xmlXPathContainsFunction); 15083 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id", 15084 xmlXPathIdFunction); 15085 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false", 15086 xmlXPathFalseFunction); 15087 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor", 15088 xmlXPathFloorFunction); 15089 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last", 15090 xmlXPathLastFunction); 15091 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang", 15092 xmlXPathLangFunction); 15093 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name", 15094 xmlXPathLocalNameFunction); 15095 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not", 15096 xmlXPathNotFunction); 15097 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name", 15098 xmlXPathNameFunction); 15099 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri", 15100 xmlXPathNamespaceURIFunction); 15101 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space", 15102 xmlXPathNormalizeFunction); 15103 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number", 15104 xmlXPathNumberFunction); 15105 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position", 15106 xmlXPathPositionFunction); 15107 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round", 15108 xmlXPathRoundFunction); 15109 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string", 15110 xmlXPathStringFunction); 15111 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length", 15112 xmlXPathStringLengthFunction); 15113 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with", 15114 xmlXPathStartsWithFunction); 15115 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring", 15116 xmlXPathSubstringFunction); 15117 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before", 15118 xmlXPathSubstringBeforeFunction); 15119 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after", 15120 xmlXPathSubstringAfterFunction); 15121 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum", 15122 xmlXPathSumFunction); 15123 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true", 15124 xmlXPathTrueFunction); 15125 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate", 15126 xmlXPathTranslateFunction); 15127 15128 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri", 15129 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions", 15130 xmlXPathEscapeUriFunction); 15131 } 15132 15133 #endif /* LIBXML_XPATH_ENABLED */ 15134 #define bottom_xpath 15135 #include "elfgcchack.h" 15136