1 /* 2 * xpointer.c : Code to handle XML Pointer 3 * 4 * Base implementation was made accordingly to 5 * W3C Candidate Recommendation 7 June 2000 6 * http://www.w3.org/TR/2000/CR-xptr-20000607 7 * 8 * Added support for the element() scheme described in: 9 * W3C Proposed Recommendation 13 November 2002 10 * http://www.w3.org/TR/2002/PR-xptr-element-20021113/ 11 * 12 * See Copyright for the status of this software. 13 * 14 * daniel@veillard.com 15 */ 16 17 /* To avoid EBCDIC trouble when parsing on zOS */ 18 #if defined(__MVS__) 19 #pragma convert("ISO8859-1") 20 #endif 21 22 #define IN_LIBXML 23 #include "libxml.h" 24 25 /* 26 * TODO: better handling of error cases, the full expression should 27 * be parsed beforehand instead of a progressive evaluation 28 * TODO: Access into entities references are not supported now ... 29 * need a start to be able to pop out of entities refs since 30 * parent is the entity declaration, not the ref. 31 */ 32 33 #include <string.h> 34 #include <libxml/xpointer.h> 35 #include <libxml/xmlmemory.h> 36 #include <libxml/parserInternals.h> 37 #include <libxml/uri.h> 38 #include <libxml/xpath.h> 39 #include <libxml/xpathInternals.h> 40 #include <libxml/xmlerror.h> 41 #include <libxml/globals.h> 42 43 #ifdef LIBXML_XPTR_ENABLED 44 45 /* Add support of the xmlns() xpointer scheme to initialize the namespaces */ 46 #define XPTR_XMLNS_SCHEME 47 48 /* #define DEBUG_RANGES */ 49 #ifdef DEBUG_RANGES 50 #ifdef LIBXML_DEBUG_ENABLED 51 #include <libxml/debugXML.h> 52 #endif 53 #endif 54 55 #define TODO \ 56 xmlGenericError(xmlGenericErrorContext, \ 57 "Unimplemented block at %s:%d\n", \ 58 __FILE__, __LINE__); 59 60 #define STRANGE \ 61 xmlGenericError(xmlGenericErrorContext, \ 62 "Internal error at %s:%d\n", \ 63 __FILE__, __LINE__); 64 65 /************************************************************************ 66 * * 67 * Some factorized error routines * 68 * * 69 ************************************************************************/ 70 71 /** 72 * xmlXPtrErrMemory: 73 * @extra: extra information 74 * 75 * Handle a redefinition of attribute error 76 */ 77 static void 78 xmlXPtrErrMemory(const char *extra) 79 { 80 __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_XPOINTER, 81 XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0, extra, 82 NULL, NULL, 0, 0, 83 "Memory allocation failed : %s\n", extra); 84 } 85 86 /** 87 * xmlXPtrErr: 88 * @ctxt: an XPTR evaluation context 89 * @extra: extra information 90 * 91 * Handle a redefinition of attribute error 92 */ 93 static void LIBXML_ATTR_FORMAT(3,0) 94 xmlXPtrErr(xmlXPathParserContextPtr ctxt, int error, 95 const char * msg, const xmlChar *extra) 96 { 97 if (ctxt != NULL) 98 ctxt->error = error; 99 if ((ctxt == NULL) || (ctxt->context == NULL)) { 100 __xmlRaiseError(NULL, NULL, NULL, 101 NULL, NULL, XML_FROM_XPOINTER, error, 102 XML_ERR_ERROR, NULL, 0, 103 (const char *) extra, NULL, NULL, 0, 0, 104 msg, extra); 105 return; 106 } 107 108 /* cleanup current last error */ 109 xmlResetError(&ctxt->context->lastError); 110 111 ctxt->context->lastError.domain = XML_FROM_XPOINTER; 112 ctxt->context->lastError.code = error; 113 ctxt->context->lastError.level = XML_ERR_ERROR; 114 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base); 115 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base; 116 ctxt->context->lastError.node = ctxt->context->debugNode; 117 if (ctxt->context->error != NULL) { 118 ctxt->context->error(ctxt->context->userData, 119 &ctxt->context->lastError); 120 } else { 121 __xmlRaiseError(NULL, NULL, NULL, 122 NULL, ctxt->context->debugNode, XML_FROM_XPOINTER, 123 error, XML_ERR_ERROR, NULL, 0, 124 (const char *) extra, (const char *) ctxt->base, NULL, 125 ctxt->cur - ctxt->base, 0, 126 msg, extra); 127 } 128 } 129 130 /************************************************************************ 131 * * 132 * A few helper functions for child sequences * 133 * * 134 ************************************************************************/ 135 #ifdef LIBXML_XPTR_LOCS_ENABLED 136 /* xmlXPtrAdvanceNode is a private function, but used by xinclude.c */ 137 xmlNodePtr xmlXPtrAdvanceNode(xmlNodePtr cur, int *level); 138 /** 139 * xmlXPtrGetArity: 140 * @cur: the node 141 * 142 * Returns the number of child for an element, -1 in case of error 143 */ 144 static int 145 xmlXPtrGetArity(xmlNodePtr cur) { 146 int i; 147 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) 148 return(-1); 149 cur = cur->children; 150 for (i = 0;cur != NULL;cur = cur->next) { 151 if ((cur->type == XML_ELEMENT_NODE) || 152 (cur->type == XML_DOCUMENT_NODE) || 153 (cur->type == XML_HTML_DOCUMENT_NODE)) { 154 i++; 155 } 156 } 157 return(i); 158 } 159 160 /** 161 * xmlXPtrGetIndex: 162 * @cur: the node 163 * 164 * Returns the index of the node in its parent children list, -1 165 * in case of error 166 */ 167 static int 168 xmlXPtrGetIndex(xmlNodePtr cur) { 169 int i; 170 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) 171 return(-1); 172 for (i = 1;cur != NULL;cur = cur->prev) { 173 if ((cur->type == XML_ELEMENT_NODE) || 174 (cur->type == XML_DOCUMENT_NODE) || 175 (cur->type == XML_HTML_DOCUMENT_NODE)) { 176 i++; 177 } 178 } 179 return(i); 180 } 181 #endif /* LIBXML_XPTR_LOCS_ENABLED */ 182 183 /** 184 * xmlXPtrGetNthChild: 185 * @cur: the node 186 * @no: the child number 187 * 188 * Returns the @no'th element child of @cur or NULL 189 */ 190 static xmlNodePtr 191 xmlXPtrGetNthChild(xmlNodePtr cur, int no) { 192 int i; 193 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) 194 return(cur); 195 cur = cur->children; 196 for (i = 0;i <= no;cur = cur->next) { 197 if (cur == NULL) 198 return(cur); 199 if ((cur->type == XML_ELEMENT_NODE) || 200 (cur->type == XML_DOCUMENT_NODE) || 201 (cur->type == XML_HTML_DOCUMENT_NODE)) { 202 i++; 203 if (i == no) 204 break; 205 } 206 } 207 return(cur); 208 } 209 210 #ifdef LIBXML_XPTR_LOCS_ENABLED 211 /************************************************************************ 212 * * 213 * Handling of XPointer specific types * 214 * * 215 ************************************************************************/ 216 217 /** 218 * xmlXPtrCmpPoints: 219 * @node1: the first node 220 * @index1: the first index 221 * @node2: the second node 222 * @index2: the second index 223 * 224 * Compare two points w.r.t document order 225 * 226 * Returns -2 in case of error 1 if first point < second point, 0 if 227 * that's the same point, -1 otherwise 228 */ 229 static int 230 xmlXPtrCmpPoints(xmlNodePtr node1, int index1, xmlNodePtr node2, int index2) { 231 if ((node1 == NULL) || (node2 == NULL)) 232 return(-2); 233 /* 234 * a couple of optimizations which will avoid computations in most cases 235 */ 236 if (node1 == node2) { 237 if (index1 < index2) 238 return(1); 239 if (index1 > index2) 240 return(-1); 241 return(0); 242 } 243 return(xmlXPathCmpNodes(node1, node2)); 244 } 245 246 /** 247 * xmlXPtrNewPoint: 248 * @node: the xmlNodePtr 249 * @indx: the indx within the node 250 * 251 * Create a new xmlXPathObjectPtr of type point 252 * 253 * Returns the newly created object. 254 */ 255 static xmlXPathObjectPtr 256 xmlXPtrNewPoint(xmlNodePtr node, int indx) { 257 xmlXPathObjectPtr ret; 258 259 if (node == NULL) 260 return(NULL); 261 if (indx < 0) 262 return(NULL); 263 264 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 265 if (ret == NULL) { 266 xmlXPtrErrMemory("allocating point"); 267 return(NULL); 268 } 269 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 270 ret->type = XPATH_POINT; 271 ret->user = (void *) node; 272 ret->index = indx; 273 return(ret); 274 } 275 276 /** 277 * xmlXPtrRangeCheckOrder: 278 * @range: an object range 279 * 280 * Make sure the points in the range are in the right order 281 */ 282 static void 283 xmlXPtrRangeCheckOrder(xmlXPathObjectPtr range) { 284 int tmp; 285 xmlNodePtr tmp2; 286 if (range == NULL) 287 return; 288 if (range->type != XPATH_RANGE) 289 return; 290 if (range->user2 == NULL) 291 return; 292 tmp = xmlXPtrCmpPoints(range->user, range->index, 293 range->user2, range->index2); 294 if (tmp == -1) { 295 tmp2 = range->user; 296 range->user = range->user2; 297 range->user2 = tmp2; 298 tmp = range->index; 299 range->index = range->index2; 300 range->index2 = tmp; 301 } 302 } 303 304 /** 305 * xmlXPtrRangesEqual: 306 * @range1: the first range 307 * @range2: the second range 308 * 309 * Compare two ranges 310 * 311 * Returns 1 if equal, 0 otherwise 312 */ 313 static int 314 xmlXPtrRangesEqual(xmlXPathObjectPtr range1, xmlXPathObjectPtr range2) { 315 if (range1 == range2) 316 return(1); 317 if ((range1 == NULL) || (range2 == NULL)) 318 return(0); 319 if (range1->type != range2->type) 320 return(0); 321 if (range1->type != XPATH_RANGE) 322 return(0); 323 if (range1->user != range2->user) 324 return(0); 325 if (range1->index != range2->index) 326 return(0); 327 if (range1->user2 != range2->user2) 328 return(0); 329 if (range1->index2 != range2->index2) 330 return(0); 331 return(1); 332 } 333 334 /** 335 * xmlXPtrNewRangeInternal: 336 * @start: the starting node 337 * @startindex: the start index 338 * @end: the ending point 339 * @endindex: the ending index 340 * 341 * Internal function to create a new xmlXPathObjectPtr of type range 342 * 343 * Returns the newly created object. 344 */ 345 static xmlXPathObjectPtr 346 xmlXPtrNewRangeInternal(xmlNodePtr start, int startindex, 347 xmlNodePtr end, int endindex) { 348 xmlXPathObjectPtr ret; 349 350 /* 351 * Namespace nodes must be copied (see xmlXPathNodeSetDupNs). 352 * Disallow them for now. 353 */ 354 if ((start != NULL) && (start->type == XML_NAMESPACE_DECL)) 355 return(NULL); 356 if ((end != NULL) && (end->type == XML_NAMESPACE_DECL)) 357 return(NULL); 358 359 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 360 if (ret == NULL) { 361 xmlXPtrErrMemory("allocating range"); 362 return(NULL); 363 } 364 memset(ret, 0, sizeof(xmlXPathObject)); 365 ret->type = XPATH_RANGE; 366 ret->user = start; 367 ret->index = startindex; 368 ret->user2 = end; 369 ret->index2 = endindex; 370 return(ret); 371 } 372 373 /** 374 * xmlXPtrNewRange: 375 * @start: the starting node 376 * @startindex: the start index 377 * @end: the ending point 378 * @endindex: the ending index 379 * 380 * Create a new xmlXPathObjectPtr of type range 381 * 382 * Returns the newly created object. 383 */ 384 xmlXPathObjectPtr 385 xmlXPtrNewRange(xmlNodePtr start, int startindex, 386 xmlNodePtr end, int endindex) { 387 xmlXPathObjectPtr ret; 388 389 if (start == NULL) 390 return(NULL); 391 if (end == NULL) 392 return(NULL); 393 if (startindex < 0) 394 return(NULL); 395 if (endindex < 0) 396 return(NULL); 397 398 ret = xmlXPtrNewRangeInternal(start, startindex, end, endindex); 399 xmlXPtrRangeCheckOrder(ret); 400 return(ret); 401 } 402 403 /** 404 * xmlXPtrNewRangePoints: 405 * @start: the starting point 406 * @end: the ending point 407 * 408 * Create a new xmlXPathObjectPtr of type range using 2 Points 409 * 410 * Returns the newly created object. 411 */ 412 xmlXPathObjectPtr 413 xmlXPtrNewRangePoints(xmlXPathObjectPtr start, xmlXPathObjectPtr end) { 414 xmlXPathObjectPtr ret; 415 416 if (start == NULL) 417 return(NULL); 418 if (end == NULL) 419 return(NULL); 420 if (start->type != XPATH_POINT) 421 return(NULL); 422 if (end->type != XPATH_POINT) 423 return(NULL); 424 425 ret = xmlXPtrNewRangeInternal(start->user, start->index, end->user, 426 end->index); 427 xmlXPtrRangeCheckOrder(ret); 428 return(ret); 429 } 430 431 /** 432 * xmlXPtrNewRangePointNode: 433 * @start: the starting point 434 * @end: the ending node 435 * 436 * Create a new xmlXPathObjectPtr of type range from a point to a node 437 * 438 * Returns the newly created object. 439 */ 440 xmlXPathObjectPtr 441 xmlXPtrNewRangePointNode(xmlXPathObjectPtr start, xmlNodePtr end) { 442 xmlXPathObjectPtr ret; 443 444 if (start == NULL) 445 return(NULL); 446 if (end == NULL) 447 return(NULL); 448 if (start->type != XPATH_POINT) 449 return(NULL); 450 451 ret = xmlXPtrNewRangeInternal(start->user, start->index, end, -1); 452 xmlXPtrRangeCheckOrder(ret); 453 return(ret); 454 } 455 456 /** 457 * xmlXPtrNewRangeNodePoint: 458 * @start: the starting node 459 * @end: the ending point 460 * 461 * Create a new xmlXPathObjectPtr of type range from a node to a point 462 * 463 * Returns the newly created object. 464 */ 465 xmlXPathObjectPtr 466 xmlXPtrNewRangeNodePoint(xmlNodePtr start, xmlXPathObjectPtr end) { 467 xmlXPathObjectPtr ret; 468 469 if (start == NULL) 470 return(NULL); 471 if (end == NULL) 472 return(NULL); 473 if (end->type != XPATH_POINT) 474 return(NULL); 475 476 ret = xmlXPtrNewRangeInternal(start, -1, end->user, end->index); 477 xmlXPtrRangeCheckOrder(ret); 478 return(ret); 479 } 480 481 /** 482 * xmlXPtrNewRangeNodes: 483 * @start: the starting node 484 * @end: the ending node 485 * 486 * Create a new xmlXPathObjectPtr of type range using 2 nodes 487 * 488 * Returns the newly created object. 489 */ 490 xmlXPathObjectPtr 491 xmlXPtrNewRangeNodes(xmlNodePtr start, xmlNodePtr end) { 492 xmlXPathObjectPtr ret; 493 494 if (start == NULL) 495 return(NULL); 496 if (end == NULL) 497 return(NULL); 498 499 ret = xmlXPtrNewRangeInternal(start, -1, end, -1); 500 xmlXPtrRangeCheckOrder(ret); 501 return(ret); 502 } 503 504 /** 505 * xmlXPtrNewCollapsedRange: 506 * @start: the starting and ending node 507 * 508 * Create a new xmlXPathObjectPtr of type range using a single nodes 509 * 510 * Returns the newly created object. 511 */ 512 xmlXPathObjectPtr 513 xmlXPtrNewCollapsedRange(xmlNodePtr start) { 514 xmlXPathObjectPtr ret; 515 516 if (start == NULL) 517 return(NULL); 518 519 ret = xmlXPtrNewRangeInternal(start, -1, NULL, -1); 520 return(ret); 521 } 522 523 /** 524 * xmlXPtrNewRangeNodeObject: 525 * @start: the starting node 526 * @end: the ending object 527 * 528 * Create a new xmlXPathObjectPtr of type range from a not to an object 529 * 530 * Returns the newly created object. 531 */ 532 xmlXPathObjectPtr 533 xmlXPtrNewRangeNodeObject(xmlNodePtr start, xmlXPathObjectPtr end) { 534 xmlNodePtr endNode; 535 int endIndex; 536 xmlXPathObjectPtr ret; 537 538 if (start == NULL) 539 return(NULL); 540 if (end == NULL) 541 return(NULL); 542 switch (end->type) { 543 case XPATH_POINT: 544 endNode = end->user; 545 endIndex = end->index; 546 break; 547 case XPATH_RANGE: 548 endNode = end->user2; 549 endIndex = end->index2; 550 break; 551 case XPATH_NODESET: 552 /* 553 * Empty set ... 554 */ 555 if ((end->nodesetval == NULL) || (end->nodesetval->nodeNr <= 0)) 556 return(NULL); 557 endNode = end->nodesetval->nodeTab[end->nodesetval->nodeNr - 1]; 558 endIndex = -1; 559 break; 560 default: 561 /* TODO */ 562 return(NULL); 563 } 564 565 ret = xmlXPtrNewRangeInternal(start, -1, endNode, endIndex); 566 xmlXPtrRangeCheckOrder(ret); 567 return(ret); 568 } 569 570 #define XML_RANGESET_DEFAULT 10 571 572 /** 573 * xmlXPtrLocationSetCreate: 574 * @val: an initial xmlXPathObjectPtr, or NULL 575 * 576 * Create a new xmlLocationSetPtr of type double and of value @val 577 * 578 * Returns the newly created object. 579 */ 580 xmlLocationSetPtr 581 xmlXPtrLocationSetCreate(xmlXPathObjectPtr val) { 582 xmlLocationSetPtr ret; 583 584 ret = (xmlLocationSetPtr) xmlMalloc(sizeof(xmlLocationSet)); 585 if (ret == NULL) { 586 xmlXPtrErrMemory("allocating locationset"); 587 return(NULL); 588 } 589 memset(ret, 0 , (size_t) sizeof(xmlLocationSet)); 590 if (val != NULL) { 591 ret->locTab = (xmlXPathObjectPtr *) xmlMalloc(XML_RANGESET_DEFAULT * 592 sizeof(xmlXPathObjectPtr)); 593 if (ret->locTab == NULL) { 594 xmlXPtrErrMemory("allocating locationset"); 595 xmlFree(ret); 596 return(NULL); 597 } 598 memset(ret->locTab, 0 , 599 XML_RANGESET_DEFAULT * (size_t) sizeof(xmlXPathObjectPtr)); 600 ret->locMax = XML_RANGESET_DEFAULT; 601 ret->locTab[ret->locNr++] = val; 602 } 603 return(ret); 604 } 605 606 /** 607 * xmlXPtrLocationSetAdd: 608 * @cur: the initial range set 609 * @val: a new xmlXPathObjectPtr 610 * 611 * add a new xmlXPathObjectPtr to an existing LocationSet 612 * If the location already exist in the set @val is freed. 613 */ 614 void 615 xmlXPtrLocationSetAdd(xmlLocationSetPtr cur, xmlXPathObjectPtr val) { 616 int i; 617 618 if ((cur == NULL) || (val == NULL)) return; 619 620 /* 621 * check against doublons 622 */ 623 for (i = 0;i < cur->locNr;i++) { 624 if (xmlXPtrRangesEqual(cur->locTab[i], val)) { 625 xmlXPathFreeObject(val); 626 return; 627 } 628 } 629 630 /* 631 * grow the locTab if needed 632 */ 633 if (cur->locMax == 0) { 634 cur->locTab = (xmlXPathObjectPtr *) xmlMalloc(XML_RANGESET_DEFAULT * 635 sizeof(xmlXPathObjectPtr)); 636 if (cur->locTab == NULL) { 637 xmlXPtrErrMemory("adding location to set"); 638 return; 639 } 640 memset(cur->locTab, 0 , 641 XML_RANGESET_DEFAULT * (size_t) sizeof(xmlXPathObjectPtr)); 642 cur->locMax = XML_RANGESET_DEFAULT; 643 } else if (cur->locNr == cur->locMax) { 644 xmlXPathObjectPtr *temp; 645 646 cur->locMax *= 2; 647 temp = (xmlXPathObjectPtr *) xmlRealloc(cur->locTab, cur->locMax * 648 sizeof(xmlXPathObjectPtr)); 649 if (temp == NULL) { 650 xmlXPtrErrMemory("adding location to set"); 651 return; 652 } 653 cur->locTab = temp; 654 } 655 cur->locTab[cur->locNr++] = val; 656 } 657 658 /** 659 * xmlXPtrLocationSetMerge: 660 * @val1: the first LocationSet 661 * @val2: the second LocationSet 662 * 663 * Merges two rangesets, all ranges from @val2 are added to @val1 664 * 665 * Returns val1 once extended or NULL in case of error. 666 */ 667 xmlLocationSetPtr 668 xmlXPtrLocationSetMerge(xmlLocationSetPtr val1, xmlLocationSetPtr val2) { 669 int i; 670 671 if (val1 == NULL) return(NULL); 672 if (val2 == NULL) return(val1); 673 674 /* 675 * !!!!! this can be optimized a lot, knowing that both 676 * val1 and val2 already have unicity of their values. 677 */ 678 679 for (i = 0;i < val2->locNr;i++) 680 xmlXPtrLocationSetAdd(val1, val2->locTab[i]); 681 682 return(val1); 683 } 684 685 /** 686 * xmlXPtrLocationSetDel: 687 * @cur: the initial range set 688 * @val: an xmlXPathObjectPtr 689 * 690 * Removes an xmlXPathObjectPtr from an existing LocationSet 691 */ 692 void 693 xmlXPtrLocationSetDel(xmlLocationSetPtr cur, xmlXPathObjectPtr val) { 694 int i; 695 696 if (cur == NULL) return; 697 if (val == NULL) return; 698 699 /* 700 * check against doublons 701 */ 702 for (i = 0;i < cur->locNr;i++) 703 if (cur->locTab[i] == val) break; 704 705 if (i >= cur->locNr) { 706 #ifdef DEBUG 707 xmlGenericError(xmlGenericErrorContext, 708 "xmlXPtrLocationSetDel: Range wasn't found in RangeList\n"); 709 #endif 710 return; 711 } 712 cur->locNr--; 713 for (;i < cur->locNr;i++) 714 cur->locTab[i] = cur->locTab[i + 1]; 715 cur->locTab[cur->locNr] = NULL; 716 } 717 718 /** 719 * xmlXPtrLocationSetRemove: 720 * @cur: the initial range set 721 * @val: the index to remove 722 * 723 * Removes an entry from an existing LocationSet list. 724 */ 725 void 726 xmlXPtrLocationSetRemove(xmlLocationSetPtr cur, int val) { 727 if (cur == NULL) return; 728 if (val >= cur->locNr) return; 729 cur->locNr--; 730 for (;val < cur->locNr;val++) 731 cur->locTab[val] = cur->locTab[val + 1]; 732 cur->locTab[cur->locNr] = NULL; 733 } 734 735 /** 736 * xmlXPtrFreeLocationSet: 737 * @obj: the xmlLocationSetPtr to free 738 * 739 * Free the LocationSet compound (not the actual ranges !). 740 */ 741 void 742 xmlXPtrFreeLocationSet(xmlLocationSetPtr obj) { 743 int i; 744 745 if (obj == NULL) return; 746 if (obj->locTab != NULL) { 747 for (i = 0;i < obj->locNr; i++) { 748 xmlXPathFreeObject(obj->locTab[i]); 749 } 750 xmlFree(obj->locTab); 751 } 752 xmlFree(obj); 753 } 754 755 /** 756 * xmlXPtrNewLocationSetNodes: 757 * @start: the start NodePtr value 758 * @end: the end NodePtr value or NULL 759 * 760 * Create a new xmlXPathObjectPtr of type LocationSet and initialize 761 * it with the single range made of the two nodes @start and @end 762 * 763 * Returns the newly created object. 764 */ 765 xmlXPathObjectPtr 766 xmlXPtrNewLocationSetNodes(xmlNodePtr start, xmlNodePtr end) { 767 xmlXPathObjectPtr ret; 768 769 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 770 if (ret == NULL) { 771 xmlXPtrErrMemory("allocating locationset"); 772 return(NULL); 773 } 774 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 775 ret->type = XPATH_LOCATIONSET; 776 if (end == NULL) 777 ret->user = xmlXPtrLocationSetCreate(xmlXPtrNewCollapsedRange(start)); 778 else 779 ret->user = xmlXPtrLocationSetCreate(xmlXPtrNewRangeNodes(start,end)); 780 return(ret); 781 } 782 783 /** 784 * xmlXPtrNewLocationSetNodeSet: 785 * @set: a node set 786 * 787 * Create a new xmlXPathObjectPtr of type LocationSet and initialize 788 * it with all the nodes from @set 789 * 790 * Returns the newly created object. 791 */ 792 xmlXPathObjectPtr 793 xmlXPtrNewLocationSetNodeSet(xmlNodeSetPtr set) { 794 xmlXPathObjectPtr ret; 795 796 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 797 if (ret == NULL) { 798 xmlXPtrErrMemory("allocating locationset"); 799 return(NULL); 800 } 801 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 802 ret->type = XPATH_LOCATIONSET; 803 if (set != NULL) { 804 int i; 805 xmlLocationSetPtr newset; 806 807 newset = xmlXPtrLocationSetCreate(NULL); 808 if (newset == NULL) 809 return(ret); 810 811 for (i = 0;i < set->nodeNr;i++) 812 xmlXPtrLocationSetAdd(newset, 813 xmlXPtrNewCollapsedRange(set->nodeTab[i])); 814 815 ret->user = (void *) newset; 816 } 817 return(ret); 818 } 819 820 /** 821 * xmlXPtrWrapLocationSet: 822 * @val: the LocationSet value 823 * 824 * Wrap the LocationSet @val in a new xmlXPathObjectPtr 825 * 826 * Returns the newly created object. 827 */ 828 xmlXPathObjectPtr 829 xmlXPtrWrapLocationSet(xmlLocationSetPtr val) { 830 xmlXPathObjectPtr ret; 831 832 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 833 if (ret == NULL) { 834 xmlXPtrErrMemory("allocating locationset"); 835 return(NULL); 836 } 837 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 838 ret->type = XPATH_LOCATIONSET; 839 ret->user = (void *) val; 840 return(ret); 841 } 842 #endif /* LIBXML_XPTR_LOCS_ENABLED */ 843 844 /************************************************************************ 845 * * 846 * The parser * 847 * * 848 ************************************************************************/ 849 850 static void xmlXPtrEvalChildSeq(xmlXPathParserContextPtr ctxt, xmlChar *name); 851 852 /* 853 * Macros for accessing the content. Those should be used only by the parser, 854 * and not exported. 855 * 856 * Dirty macros, i.e. one need to make assumption on the context to use them 857 * 858 * CUR returns the current xmlChar value, i.e. a 8 bit value 859 * in ISO-Latin or UTF-8. 860 * This should be used internally by the parser 861 * only to compare to ASCII values otherwise it would break when 862 * running with UTF-8 encoding. 863 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only 864 * to compare on ASCII based substring. 865 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined 866 * strings within the parser. 867 * CURRENT Returns the current char value, with the full decoding of 868 * UTF-8 if we are using this mode. It returns an int. 869 * NEXT Skip to the next character, this does the proper decoding 870 * in UTF-8 mode. It also pop-up unfinished entities on the fly. 871 * It returns the pointer to the current xmlChar. 872 */ 873 874 #define CUR (*ctxt->cur) 875 #define SKIP(val) ctxt->cur += (val) 876 #define NXT(val) ctxt->cur[(val)] 877 878 #define SKIP_BLANKS \ 879 while (IS_BLANK_CH(*(ctxt->cur))) NEXT 880 881 #define CURRENT (*ctxt->cur) 882 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur) 883 884 /* 885 * xmlXPtrGetChildNo: 886 * @ctxt: the XPointer Parser context 887 * @index: the child number 888 * 889 * Move the current node of the nodeset on the stack to the 890 * given child if found 891 */ 892 static void 893 xmlXPtrGetChildNo(xmlXPathParserContextPtr ctxt, int indx) { 894 xmlNodePtr cur = NULL; 895 xmlXPathObjectPtr obj; 896 xmlNodeSetPtr oldset; 897 898 CHECK_TYPE(XPATH_NODESET); 899 obj = valuePop(ctxt); 900 oldset = obj->nodesetval; 901 if ((indx <= 0) || (oldset == NULL) || (oldset->nodeNr != 1)) { 902 xmlXPathFreeObject(obj); 903 valuePush(ctxt, xmlXPathNewNodeSet(NULL)); 904 return; 905 } 906 cur = xmlXPtrGetNthChild(oldset->nodeTab[0], indx); 907 if (cur == NULL) { 908 xmlXPathFreeObject(obj); 909 valuePush(ctxt, xmlXPathNewNodeSet(NULL)); 910 return; 911 } 912 oldset->nodeTab[0] = cur; 913 valuePush(ctxt, obj); 914 } 915 916 /** 917 * xmlXPtrEvalXPtrPart: 918 * @ctxt: the XPointer Parser context 919 * @name: the preparsed Scheme for the XPtrPart 920 * 921 * XPtrPart ::= 'xpointer' '(' XPtrExpr ')' 922 * | Scheme '(' SchemeSpecificExpr ')' 923 * 924 * Scheme ::= NCName - 'xpointer' [VC: Non-XPointer schemes] 925 * 926 * SchemeSpecificExpr ::= StringWithBalancedParens 927 * 928 * StringWithBalancedParens ::= 929 * [^()]* ('(' StringWithBalancedParens ')' [^()]*)* 930 * [VC: Parenthesis escaping] 931 * 932 * XPtrExpr ::= Expr [VC: Parenthesis escaping] 933 * 934 * VC: Parenthesis escaping: 935 * The end of an XPointer part is signaled by the right parenthesis ")" 936 * character that is balanced with the left parenthesis "(" character 937 * that began the part. Any unbalanced parenthesis character inside the 938 * expression, even within literals, must be escaped with a circumflex (^) 939 * character preceding it. If the expression contains any literal 940 * occurrences of the circumflex, each must be escaped with an additional 941 * circumflex (that is, ^^). If the unescaped parentheses in the expression 942 * are not balanced, a syntax error results. 943 * 944 * Parse and evaluate an XPtrPart. Basically it generates the unescaped 945 * string and if the scheme is 'xpointer' it will call the XPath interpreter. 946 * 947 * TODO: there is no new scheme registration mechanism 948 */ 949 950 static void 951 xmlXPtrEvalXPtrPart(xmlXPathParserContextPtr ctxt, xmlChar *name) { 952 xmlChar *buffer, *cur; 953 int len; 954 int level; 955 956 if (name == NULL) 957 name = xmlXPathParseName(ctxt); 958 if (name == NULL) 959 XP_ERROR(XPATH_EXPR_ERROR); 960 961 if (CUR != '(') { 962 xmlFree(name); 963 XP_ERROR(XPATH_EXPR_ERROR); 964 } 965 NEXT; 966 level = 1; 967 968 len = xmlStrlen(ctxt->cur); 969 len++; 970 buffer = (xmlChar *) xmlMallocAtomic(len * sizeof (xmlChar)); 971 if (buffer == NULL) { 972 xmlXPtrErrMemory("allocating buffer"); 973 xmlFree(name); 974 return; 975 } 976 977 cur = buffer; 978 while (CUR != 0) { 979 if (CUR == ')') { 980 level--; 981 if (level == 0) { 982 NEXT; 983 break; 984 } 985 } else if (CUR == '(') { 986 level++; 987 } else if (CUR == '^') { 988 if ((NXT(1) == ')') || (NXT(1) == '(') || (NXT(1) == '^')) { 989 NEXT; 990 } 991 } 992 *cur++ = CUR; 993 NEXT; 994 } 995 *cur = 0; 996 997 if ((level != 0) && (CUR == 0)) { 998 xmlFree(name); 999 xmlFree(buffer); 1000 XP_ERROR(XPTR_SYNTAX_ERROR); 1001 } 1002 1003 if (xmlStrEqual(name, (xmlChar *) "xpointer") || 1004 xmlStrEqual(name, (xmlChar *) "xpath1")) { 1005 const xmlChar *oldBase = ctxt->base; 1006 const xmlChar *oldCur = ctxt->cur; 1007 1008 ctxt->cur = ctxt->base = buffer; 1009 /* 1010 * To evaluate an xpointer scheme element (4.3) we need: 1011 * context initialized to the root 1012 * context position initialized to 1 1013 * context size initialized to 1 1014 */ 1015 ctxt->context->node = (xmlNodePtr)ctxt->context->doc; 1016 ctxt->context->proximityPosition = 1; 1017 ctxt->context->contextSize = 1; 1018 #ifdef LIBXML_XPTR_LOCS_ENABLED 1019 ctxt->xptr = xmlStrEqual(name, (xmlChar *) "xpointer"); 1020 #endif 1021 xmlXPathEvalExpr(ctxt); 1022 ctxt->base = oldBase; 1023 ctxt->cur = oldCur; 1024 } else if (xmlStrEqual(name, (xmlChar *) "element")) { 1025 const xmlChar *oldBase = ctxt->base; 1026 const xmlChar *oldCur = ctxt->cur; 1027 xmlChar *name2; 1028 1029 ctxt->cur = ctxt->base = buffer; 1030 if (buffer[0] == '/') { 1031 xmlXPathRoot(ctxt); 1032 xmlXPtrEvalChildSeq(ctxt, NULL); 1033 } else { 1034 name2 = xmlXPathParseName(ctxt); 1035 if (name2 == NULL) { 1036 ctxt->base = oldBase; 1037 ctxt->cur = oldCur; 1038 xmlFree(buffer); 1039 xmlFree(name); 1040 XP_ERROR(XPATH_EXPR_ERROR); 1041 } 1042 xmlXPtrEvalChildSeq(ctxt, name2); 1043 } 1044 ctxt->base = oldBase; 1045 ctxt->cur = oldCur; 1046 #ifdef XPTR_XMLNS_SCHEME 1047 } else if (xmlStrEqual(name, (xmlChar *) "xmlns")) { 1048 const xmlChar *oldBase = ctxt->base; 1049 const xmlChar *oldCur = ctxt->cur; 1050 xmlChar *prefix; 1051 1052 ctxt->cur = ctxt->base = buffer; 1053 prefix = xmlXPathParseNCName(ctxt); 1054 if (prefix == NULL) { 1055 ctxt->base = oldBase; 1056 ctxt->cur = oldCur; 1057 xmlFree(buffer); 1058 xmlFree(name); 1059 XP_ERROR(XPTR_SYNTAX_ERROR); 1060 } 1061 SKIP_BLANKS; 1062 if (CUR != '=') { 1063 ctxt->base = oldBase; 1064 ctxt->cur = oldCur; 1065 xmlFree(prefix); 1066 xmlFree(buffer); 1067 xmlFree(name); 1068 XP_ERROR(XPTR_SYNTAX_ERROR); 1069 } 1070 NEXT; 1071 SKIP_BLANKS; 1072 1073 xmlXPathRegisterNs(ctxt->context, prefix, ctxt->cur); 1074 ctxt->base = oldBase; 1075 ctxt->cur = oldCur; 1076 xmlFree(prefix); 1077 #endif /* XPTR_XMLNS_SCHEME */ 1078 } else { 1079 xmlXPtrErr(ctxt, XML_XPTR_UNKNOWN_SCHEME, 1080 "unsupported scheme '%s'\n", name); 1081 } 1082 xmlFree(buffer); 1083 xmlFree(name); 1084 } 1085 1086 /** 1087 * xmlXPtrEvalFullXPtr: 1088 * @ctxt: the XPointer Parser context 1089 * @name: the preparsed Scheme for the first XPtrPart 1090 * 1091 * FullXPtr ::= XPtrPart (S? XPtrPart)* 1092 * 1093 * As the specs says: 1094 * ----------- 1095 * When multiple XPtrParts are provided, they must be evaluated in 1096 * left-to-right order. If evaluation of one part fails, the nexti 1097 * is evaluated. The following conditions cause XPointer part failure: 1098 * 1099 * - An unknown scheme 1100 * - A scheme that does not locate any sub-resource present in the resource 1101 * - A scheme that is not applicable to the media type of the resource 1102 * 1103 * The XPointer application must consume a failed XPointer part and 1104 * attempt to evaluate the next one, if any. The result of the first 1105 * XPointer part whose evaluation succeeds is taken to be the fragment 1106 * located by the XPointer as a whole. If all the parts fail, the result 1107 * for the XPointer as a whole is a sub-resource error. 1108 * ----------- 1109 * 1110 * Parse and evaluate a Full XPtr i.e. possibly a cascade of XPath based 1111 * expressions or other schemes. 1112 */ 1113 static void 1114 xmlXPtrEvalFullXPtr(xmlXPathParserContextPtr ctxt, xmlChar *name) { 1115 if (name == NULL) 1116 name = xmlXPathParseName(ctxt); 1117 if (name == NULL) 1118 XP_ERROR(XPATH_EXPR_ERROR); 1119 while (name != NULL) { 1120 ctxt->error = XPATH_EXPRESSION_OK; 1121 xmlXPtrEvalXPtrPart(ctxt, name); 1122 1123 /* in case of syntax error, break here */ 1124 if ((ctxt->error != XPATH_EXPRESSION_OK) && 1125 (ctxt->error != XML_XPTR_UNKNOWN_SCHEME)) 1126 return; 1127 1128 /* 1129 * If the returned value is a non-empty nodeset 1130 * or location set, return here. 1131 */ 1132 if (ctxt->value != NULL) { 1133 xmlXPathObjectPtr obj = ctxt->value; 1134 1135 switch (obj->type) { 1136 #ifdef LIBXML_XPTR_LOCS_ENABLED 1137 case XPATH_LOCATIONSET: { 1138 xmlLocationSetPtr loc = ctxt->value->user; 1139 if ((loc != NULL) && (loc->locNr > 0)) 1140 return; 1141 break; 1142 } 1143 #endif 1144 case XPATH_NODESET: { 1145 xmlNodeSetPtr loc = ctxt->value->nodesetval; 1146 if ((loc != NULL) && (loc->nodeNr > 0)) 1147 return; 1148 break; 1149 } 1150 default: 1151 break; 1152 } 1153 1154 /* 1155 * Evaluating to improper values is equivalent to 1156 * a sub-resource error, clean-up the stack 1157 */ 1158 do { 1159 obj = valuePop(ctxt); 1160 if (obj != NULL) { 1161 xmlXPathFreeObject(obj); 1162 } 1163 } while (obj != NULL); 1164 } 1165 1166 /* 1167 * Is there another XPointer part. 1168 */ 1169 SKIP_BLANKS; 1170 name = xmlXPathParseName(ctxt); 1171 } 1172 } 1173 1174 /** 1175 * xmlXPtrEvalChildSeq: 1176 * @ctxt: the XPointer Parser context 1177 * @name: a possible ID name of the child sequence 1178 * 1179 * ChildSeq ::= '/1' ('/' [0-9]*)* 1180 * | Name ('/' [0-9]*)+ 1181 * 1182 * Parse and evaluate a Child Sequence. This routine also handle the 1183 * case of a Bare Name used to get a document ID. 1184 */ 1185 static void 1186 xmlXPtrEvalChildSeq(xmlXPathParserContextPtr ctxt, xmlChar *name) { 1187 /* 1188 * XPointer don't allow by syntax to address in multirooted trees 1189 * this might prove useful in some cases, warn about it. 1190 */ 1191 if ((name == NULL) && (CUR == '/') && (NXT(1) != '1')) { 1192 xmlXPtrErr(ctxt, XML_XPTR_CHILDSEQ_START, 1193 "warning: ChildSeq not starting by /1\n", NULL); 1194 } 1195 1196 if (name != NULL) { 1197 valuePush(ctxt, xmlXPathNewString(name)); 1198 xmlFree(name); 1199 xmlXPathIdFunction(ctxt, 1); 1200 CHECK_ERROR; 1201 } 1202 1203 while (CUR == '/') { 1204 int child = 0, overflow = 0; 1205 NEXT; 1206 1207 while ((CUR >= '0') && (CUR <= '9')) { 1208 int d = CUR - '0'; 1209 if (child > INT_MAX / 10) 1210 overflow = 1; 1211 else 1212 child *= 10; 1213 if (child > INT_MAX - d) 1214 overflow = 1; 1215 else 1216 child += d; 1217 NEXT; 1218 } 1219 if (overflow) 1220 child = 0; 1221 xmlXPtrGetChildNo(ctxt, child); 1222 } 1223 } 1224 1225 1226 /** 1227 * xmlXPtrEvalXPointer: 1228 * @ctxt: the XPointer Parser context 1229 * 1230 * XPointer ::= Name 1231 * | ChildSeq 1232 * | FullXPtr 1233 * 1234 * Parse and evaluate an XPointer 1235 */ 1236 static void 1237 xmlXPtrEvalXPointer(xmlXPathParserContextPtr ctxt) { 1238 if (ctxt->valueTab == NULL) { 1239 /* Allocate the value stack */ 1240 ctxt->valueTab = (xmlXPathObjectPtr *) 1241 xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); 1242 if (ctxt->valueTab == NULL) { 1243 xmlXPtrErrMemory("allocating evaluation context"); 1244 return; 1245 } 1246 ctxt->valueNr = 0; 1247 ctxt->valueMax = 10; 1248 ctxt->value = NULL; 1249 ctxt->valueFrame = 0; 1250 } 1251 SKIP_BLANKS; 1252 if (CUR == '/') { 1253 xmlXPathRoot(ctxt); 1254 xmlXPtrEvalChildSeq(ctxt, NULL); 1255 } else { 1256 xmlChar *name; 1257 1258 name = xmlXPathParseName(ctxt); 1259 if (name == NULL) 1260 XP_ERROR(XPATH_EXPR_ERROR); 1261 if (CUR == '(') { 1262 xmlXPtrEvalFullXPtr(ctxt, name); 1263 /* Short evaluation */ 1264 return; 1265 } else { 1266 /* this handle both Bare Names and Child Sequences */ 1267 xmlXPtrEvalChildSeq(ctxt, name); 1268 } 1269 } 1270 SKIP_BLANKS; 1271 if (CUR != 0) 1272 XP_ERROR(XPATH_EXPR_ERROR); 1273 } 1274 1275 1276 /************************************************************************ 1277 * * 1278 * General routines * 1279 * * 1280 ************************************************************************/ 1281 1282 #ifdef LIBXML_XPTR_LOCS_ENABLED 1283 static 1284 void xmlXPtrStringRangeFunction(xmlXPathParserContextPtr ctxt, int nargs); 1285 static 1286 void xmlXPtrStartPointFunction(xmlXPathParserContextPtr ctxt, int nargs); 1287 static 1288 void xmlXPtrEndPointFunction(xmlXPathParserContextPtr ctxt, int nargs); 1289 static 1290 void xmlXPtrHereFunction(xmlXPathParserContextPtr ctxt, int nargs); 1291 static 1292 void xmlXPtrOriginFunction(xmlXPathParserContextPtr ctxt, int nargs); 1293 static 1294 void xmlXPtrRangeInsideFunction(xmlXPathParserContextPtr ctxt, int nargs); 1295 static 1296 void xmlXPtrRangeFunction(xmlXPathParserContextPtr ctxt, int nargs); 1297 #endif /* LIBXML_XPTR_LOCS_ENABLED */ 1298 1299 /** 1300 * xmlXPtrNewContext: 1301 * @doc: the XML document 1302 * @here: the node that directly contains the XPointer being evaluated or NULL 1303 * @origin: the element from which a user or program initiated traversal of 1304 * the link, or NULL. 1305 * 1306 * Create a new XPointer context 1307 * 1308 * Returns the xmlXPathContext just allocated. 1309 */ 1310 xmlXPathContextPtr 1311 xmlXPtrNewContext(xmlDocPtr doc, xmlNodePtr here, xmlNodePtr origin) { 1312 xmlXPathContextPtr ret; 1313 (void) here; 1314 (void) origin; 1315 1316 ret = xmlXPathNewContext(doc); 1317 if (ret == NULL) 1318 return(ret); 1319 #ifdef LIBXML_XPTR_LOCS_ENABLED 1320 ret->xptr = 1; 1321 ret->here = here; 1322 ret->origin = origin; 1323 1324 xmlXPathRegisterFunc(ret, (xmlChar *)"range", 1325 xmlXPtrRangeFunction); 1326 xmlXPathRegisterFunc(ret, (xmlChar *)"range-inside", 1327 xmlXPtrRangeInsideFunction); 1328 xmlXPathRegisterFunc(ret, (xmlChar *)"string-range", 1329 xmlXPtrStringRangeFunction); 1330 xmlXPathRegisterFunc(ret, (xmlChar *)"start-point", 1331 xmlXPtrStartPointFunction); 1332 xmlXPathRegisterFunc(ret, (xmlChar *)"end-point", 1333 xmlXPtrEndPointFunction); 1334 xmlXPathRegisterFunc(ret, (xmlChar *)"here", 1335 xmlXPtrHereFunction); 1336 xmlXPathRegisterFunc(ret, (xmlChar *)" origin", 1337 xmlXPtrOriginFunction); 1338 #endif /* LIBXML_XPTR_LOCS_ENABLED */ 1339 1340 return(ret); 1341 } 1342 1343 /** 1344 * xmlXPtrEval: 1345 * @str: the XPointer expression 1346 * @ctx: the XPointer context 1347 * 1348 * Evaluate the XPath Location Path in the given context. 1349 * 1350 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 1351 * the caller has to free the object. 1352 */ 1353 xmlXPathObjectPtr 1354 xmlXPtrEval(const xmlChar *str, xmlXPathContextPtr ctx) { 1355 xmlXPathParserContextPtr ctxt; 1356 xmlXPathObjectPtr res = NULL, tmp; 1357 xmlXPathObjectPtr init = NULL; 1358 int stack = 0; 1359 1360 xmlInitParser(); 1361 1362 if ((ctx == NULL) || (str == NULL)) 1363 return(NULL); 1364 1365 ctxt = xmlXPathNewParserContext(str, ctx); 1366 if (ctxt == NULL) 1367 return(NULL); 1368 xmlXPtrEvalXPointer(ctxt); 1369 1370 if ((ctxt->value != NULL) && 1371 #ifdef LIBXML_XPTR_LOCS_ENABLED 1372 (ctxt->value->type != XPATH_LOCATIONSET) && 1373 #endif 1374 (ctxt->value->type != XPATH_NODESET)) { 1375 xmlXPtrErr(ctxt, XML_XPTR_EVAL_FAILED, 1376 "xmlXPtrEval: evaluation failed to return a node set\n", 1377 NULL); 1378 } else { 1379 res = valuePop(ctxt); 1380 } 1381 1382 do { 1383 tmp = valuePop(ctxt); 1384 if (tmp != NULL) { 1385 if (tmp != init) { 1386 if (tmp->type == XPATH_NODESET) { 1387 /* 1388 * Evaluation may push a root nodeset which is unused 1389 */ 1390 xmlNodeSetPtr set; 1391 set = tmp->nodesetval; 1392 if ((set == NULL) || (set->nodeNr != 1) || 1393 (set->nodeTab[0] != (xmlNodePtr) ctx->doc)) 1394 stack++; 1395 } else 1396 stack++; 1397 } 1398 xmlXPathFreeObject(tmp); 1399 } 1400 } while (tmp != NULL); 1401 if (stack != 0) { 1402 xmlXPtrErr(ctxt, XML_XPTR_EXTRA_OBJECTS, 1403 "xmlXPtrEval: object(s) left on the eval stack\n", 1404 NULL); 1405 } 1406 if (ctxt->error != XPATH_EXPRESSION_OK) { 1407 xmlXPathFreeObject(res); 1408 res = NULL; 1409 } 1410 1411 xmlXPathFreeParserContext(ctxt); 1412 return(res); 1413 } 1414 1415 #ifdef LIBXML_XPTR_LOCS_ENABLED 1416 /** 1417 * xmlXPtrBuildRangeNodeList: 1418 * @range: a range object 1419 * 1420 * Build a node list tree copy of the range 1421 * 1422 * Returns an xmlNodePtr list or NULL. 1423 * the caller has to free the node tree. 1424 */ 1425 static xmlNodePtr 1426 xmlXPtrBuildRangeNodeList(xmlXPathObjectPtr range) { 1427 /* pointers to generated nodes */ 1428 xmlNodePtr list = NULL, last = NULL, parent = NULL, tmp; 1429 /* pointers to traversal nodes */ 1430 xmlNodePtr start, cur, end; 1431 int index1, index2; 1432 1433 if (range == NULL) 1434 return(NULL); 1435 if (range->type != XPATH_RANGE) 1436 return(NULL); 1437 start = (xmlNodePtr) range->user; 1438 1439 if ((start == NULL) || (start->type == XML_NAMESPACE_DECL)) 1440 return(NULL); 1441 end = range->user2; 1442 if (end == NULL) 1443 return(xmlCopyNode(start, 1)); 1444 if (end->type == XML_NAMESPACE_DECL) 1445 return(NULL); 1446 1447 cur = start; 1448 index1 = range->index; 1449 index2 = range->index2; 1450 while (cur != NULL) { 1451 if (cur == end) { 1452 if (cur->type == XML_TEXT_NODE) { 1453 const xmlChar *content = cur->content; 1454 int len; 1455 1456 if (content == NULL) { 1457 tmp = xmlNewTextLen(NULL, 0); 1458 } else { 1459 len = index2; 1460 if ((cur == start) && (index1 > 1)) { 1461 content += (index1 - 1); 1462 len -= (index1 - 1); 1463 index1 = 0; 1464 } else { 1465 len = index2; 1466 } 1467 tmp = xmlNewTextLen(content, len); 1468 } 1469 /* single sub text node selection */ 1470 if (list == NULL) 1471 return(tmp); 1472 /* prune and return full set */ 1473 if (last != NULL) 1474 xmlAddNextSibling(last, tmp); 1475 else 1476 xmlAddChild(parent, tmp); 1477 return(list); 1478 } else { 1479 tmp = xmlCopyNode(cur, 0); 1480 if (list == NULL) { 1481 list = tmp; 1482 parent = tmp; 1483 } else { 1484 if (last != NULL) 1485 parent = xmlAddNextSibling(last, tmp); 1486 else 1487 parent = xmlAddChild(parent, tmp); 1488 } 1489 last = NULL; 1490 1491 if (index2 > 1) { 1492 end = xmlXPtrGetNthChild(cur, index2 - 1); 1493 index2 = 0; 1494 } 1495 if ((cur == start) && (index1 > 1)) { 1496 cur = xmlXPtrGetNthChild(cur, index1 - 1); 1497 index1 = 0; 1498 } else { 1499 cur = cur->children; 1500 } 1501 /* 1502 * Now gather the remaining nodes from cur to end 1503 */ 1504 continue; /* while */ 1505 } 1506 } else if ((cur == start) && 1507 (list == NULL) /* looks superfluous but ... */ ) { 1508 if ((cur->type == XML_TEXT_NODE) || 1509 (cur->type == XML_CDATA_SECTION_NODE)) { 1510 const xmlChar *content = cur->content; 1511 1512 if (content == NULL) { 1513 tmp = xmlNewTextLen(NULL, 0); 1514 } else { 1515 if (index1 > 1) { 1516 content += (index1 - 1); 1517 } 1518 tmp = xmlNewText(content); 1519 } 1520 last = list = tmp; 1521 } else { 1522 if ((cur == start) && (index1 > 1)) { 1523 tmp = xmlCopyNode(cur, 0); 1524 list = tmp; 1525 parent = tmp; 1526 last = NULL; 1527 cur = xmlXPtrGetNthChild(cur, index1 - 1); 1528 index1 = 0; 1529 /* 1530 * Now gather the remaining nodes from cur to end 1531 */ 1532 continue; /* while */ 1533 } 1534 tmp = xmlCopyNode(cur, 1); 1535 list = tmp; 1536 parent = NULL; 1537 last = tmp; 1538 } 1539 } else { 1540 tmp = NULL; 1541 switch (cur->type) { 1542 case XML_DTD_NODE: 1543 case XML_ELEMENT_DECL: 1544 case XML_ATTRIBUTE_DECL: 1545 case XML_ENTITY_NODE: 1546 /* Do not copy DTD information */ 1547 break; 1548 case XML_ENTITY_DECL: 1549 TODO /* handle crossing entities -> stack needed */ 1550 break; 1551 case XML_XINCLUDE_START: 1552 case XML_XINCLUDE_END: 1553 /* don't consider it part of the tree content */ 1554 break; 1555 case XML_ATTRIBUTE_NODE: 1556 /* Humm, should not happen ! */ 1557 STRANGE 1558 break; 1559 default: 1560 tmp = xmlCopyNode(cur, 1); 1561 break; 1562 } 1563 if (tmp != NULL) { 1564 if ((list == NULL) || ((last == NULL) && (parent == NULL))) { 1565 STRANGE 1566 return(NULL); 1567 } 1568 if (last != NULL) 1569 xmlAddNextSibling(last, tmp); 1570 else { 1571 last = xmlAddChild(parent, tmp); 1572 } 1573 } 1574 } 1575 /* 1576 * Skip to next node in document order 1577 */ 1578 if ((list == NULL) || ((last == NULL) && (parent == NULL))) { 1579 STRANGE 1580 return(NULL); 1581 } 1582 cur = xmlXPtrAdvanceNode(cur, NULL); 1583 } 1584 return(list); 1585 } 1586 1587 /** 1588 * xmlXPtrBuildNodeList: 1589 * @obj: the XPointer result from the evaluation. 1590 * 1591 * Build a node list tree copy of the XPointer result. 1592 * This will drop Attributes and Namespace declarations. 1593 * 1594 * Returns an xmlNodePtr list or NULL. 1595 * the caller has to free the node tree. 1596 */ 1597 xmlNodePtr 1598 xmlXPtrBuildNodeList(xmlXPathObjectPtr obj) { 1599 xmlNodePtr list = NULL, last = NULL; 1600 int i; 1601 1602 if (obj == NULL) 1603 return(NULL); 1604 switch (obj->type) { 1605 case XPATH_NODESET: { 1606 xmlNodeSetPtr set = obj->nodesetval; 1607 if (set == NULL) 1608 return(NULL); 1609 for (i = 0;i < set->nodeNr;i++) { 1610 if (set->nodeTab[i] == NULL) 1611 continue; 1612 switch (set->nodeTab[i]->type) { 1613 case XML_TEXT_NODE: 1614 case XML_CDATA_SECTION_NODE: 1615 case XML_ELEMENT_NODE: 1616 case XML_ENTITY_REF_NODE: 1617 case XML_ENTITY_NODE: 1618 case XML_PI_NODE: 1619 case XML_COMMENT_NODE: 1620 case XML_DOCUMENT_NODE: 1621 case XML_HTML_DOCUMENT_NODE: 1622 case XML_XINCLUDE_START: 1623 case XML_XINCLUDE_END: 1624 break; 1625 case XML_ATTRIBUTE_NODE: 1626 case XML_NAMESPACE_DECL: 1627 case XML_DOCUMENT_TYPE_NODE: 1628 case XML_DOCUMENT_FRAG_NODE: 1629 case XML_NOTATION_NODE: 1630 case XML_DTD_NODE: 1631 case XML_ELEMENT_DECL: 1632 case XML_ATTRIBUTE_DECL: 1633 case XML_ENTITY_DECL: 1634 continue; /* for */ 1635 } 1636 if (last == NULL) 1637 list = last = xmlCopyNode(set->nodeTab[i], 1); 1638 else { 1639 xmlAddNextSibling(last, xmlCopyNode(set->nodeTab[i], 1)); 1640 if (last->next != NULL) 1641 last = last->next; 1642 } 1643 } 1644 break; 1645 } 1646 case XPATH_LOCATIONSET: { 1647 xmlLocationSetPtr set = (xmlLocationSetPtr) obj->user; 1648 if (set == NULL) 1649 return(NULL); 1650 for (i = 0;i < set->locNr;i++) { 1651 if (last == NULL) 1652 list = last = xmlXPtrBuildNodeList(set->locTab[i]); 1653 else 1654 xmlAddNextSibling(last, 1655 xmlXPtrBuildNodeList(set->locTab[i])); 1656 if (last != NULL) { 1657 while (last->next != NULL) 1658 last = last->next; 1659 } 1660 } 1661 break; 1662 } 1663 case XPATH_RANGE: 1664 return(xmlXPtrBuildRangeNodeList(obj)); 1665 case XPATH_POINT: 1666 return(xmlCopyNode(obj->user, 0)); 1667 default: 1668 break; 1669 } 1670 return(list); 1671 } 1672 1673 /************************************************************************ 1674 * * 1675 * XPointer functions * 1676 * * 1677 ************************************************************************/ 1678 1679 /** 1680 * xmlXPtrNbLocChildren: 1681 * @node: an xmlNodePtr 1682 * 1683 * Count the number of location children of @node or the length of the 1684 * string value in case of text/PI/Comments nodes 1685 * 1686 * Returns the number of location children 1687 */ 1688 static int 1689 xmlXPtrNbLocChildren(xmlNodePtr node) { 1690 int ret = 0; 1691 if (node == NULL) 1692 return(-1); 1693 switch (node->type) { 1694 case XML_HTML_DOCUMENT_NODE: 1695 case XML_DOCUMENT_NODE: 1696 case XML_ELEMENT_NODE: 1697 node = node->children; 1698 while (node != NULL) { 1699 if (node->type == XML_ELEMENT_NODE) 1700 ret++; 1701 node = node->next; 1702 } 1703 break; 1704 case XML_ATTRIBUTE_NODE: 1705 return(-1); 1706 1707 case XML_PI_NODE: 1708 case XML_COMMENT_NODE: 1709 case XML_TEXT_NODE: 1710 case XML_CDATA_SECTION_NODE: 1711 case XML_ENTITY_REF_NODE: 1712 ret = xmlStrlen(node->content); 1713 break; 1714 default: 1715 return(-1); 1716 } 1717 return(ret); 1718 } 1719 1720 /** 1721 * xmlXPtrHereFunction: 1722 * @ctxt: the XPointer Parser context 1723 * @nargs: the number of args 1724 * 1725 * Function implementing here() operation 1726 * as described in 5.4.3 1727 */ 1728 static void 1729 xmlXPtrHereFunction(xmlXPathParserContextPtr ctxt, int nargs) { 1730 CHECK_ARITY(0); 1731 1732 if (ctxt->context->here == NULL) 1733 XP_ERROR(XPTR_SYNTAX_ERROR); 1734 1735 valuePush(ctxt, xmlXPtrNewLocationSetNodes(ctxt->context->here, NULL)); 1736 } 1737 1738 /** 1739 * xmlXPtrOriginFunction: 1740 * @ctxt: the XPointer Parser context 1741 * @nargs: the number of args 1742 * 1743 * Function implementing origin() operation 1744 * as described in 5.4.3 1745 */ 1746 static void 1747 xmlXPtrOriginFunction(xmlXPathParserContextPtr ctxt, int nargs) { 1748 CHECK_ARITY(0); 1749 1750 if (ctxt->context->origin == NULL) 1751 XP_ERROR(XPTR_SYNTAX_ERROR); 1752 1753 valuePush(ctxt, xmlXPtrNewLocationSetNodes(ctxt->context->origin, NULL)); 1754 } 1755 1756 /** 1757 * xmlXPtrStartPointFunction: 1758 * @ctxt: the XPointer Parser context 1759 * @nargs: the number of args 1760 * 1761 * Function implementing start-point() operation 1762 * as described in 5.4.3 1763 * ---------------- 1764 * location-set start-point(location-set) 1765 * 1766 * For each location x in the argument location-set, start-point adds a 1767 * location of type point to the result location-set. That point represents 1768 * the start point of location x and is determined by the following rules: 1769 * 1770 * - If x is of type point, the start point is x. 1771 * - If x is of type range, the start point is the start point of x. 1772 * - If x is of type root, element, text, comment, or processing instruction, 1773 * - the container node of the start point is x and the index is 0. 1774 * - If x is of type attribute or namespace, the function must signal a 1775 * syntax error. 1776 * ---------------- 1777 * 1778 */ 1779 static void 1780 xmlXPtrStartPointFunction(xmlXPathParserContextPtr ctxt, int nargs) { 1781 xmlXPathObjectPtr tmp, obj, point; 1782 xmlLocationSetPtr newset = NULL; 1783 xmlLocationSetPtr oldset = NULL; 1784 1785 CHECK_ARITY(1); 1786 if ((ctxt->value == NULL) || 1787 ((ctxt->value->type != XPATH_LOCATIONSET) && 1788 (ctxt->value->type != XPATH_NODESET))) 1789 XP_ERROR(XPATH_INVALID_TYPE) 1790 1791 obj = valuePop(ctxt); 1792 if (obj->type == XPATH_NODESET) { 1793 /* 1794 * First convert to a location set 1795 */ 1796 tmp = xmlXPtrNewLocationSetNodeSet(obj->nodesetval); 1797 xmlXPathFreeObject(obj); 1798 if (tmp == NULL) 1799 XP_ERROR(XPATH_MEMORY_ERROR) 1800 obj = tmp; 1801 } 1802 1803 newset = xmlXPtrLocationSetCreate(NULL); 1804 if (newset == NULL) { 1805 xmlXPathFreeObject(obj); 1806 XP_ERROR(XPATH_MEMORY_ERROR); 1807 } 1808 oldset = (xmlLocationSetPtr) obj->user; 1809 if (oldset != NULL) { 1810 int i; 1811 1812 for (i = 0; i < oldset->locNr; i++) { 1813 tmp = oldset->locTab[i]; 1814 if (tmp == NULL) 1815 continue; 1816 point = NULL; 1817 switch (tmp->type) { 1818 case XPATH_POINT: 1819 point = xmlXPtrNewPoint(tmp->user, tmp->index); 1820 break; 1821 case XPATH_RANGE: { 1822 xmlNodePtr node = tmp->user; 1823 if (node != NULL) { 1824 if ((node->type == XML_ATTRIBUTE_NODE) || 1825 (node->type == XML_NAMESPACE_DECL)) { 1826 xmlXPathFreeObject(obj); 1827 xmlXPtrFreeLocationSet(newset); 1828 XP_ERROR(XPTR_SYNTAX_ERROR); 1829 } 1830 point = xmlXPtrNewPoint(node, tmp->index); 1831 } 1832 break; 1833 } 1834 default: 1835 /*** Should we raise an error ? 1836 xmlXPathFreeObject(obj); 1837 xmlXPathFreeObject(newset); 1838 XP_ERROR(XPATH_INVALID_TYPE) 1839 ***/ 1840 break; 1841 } 1842 if (point != NULL) 1843 xmlXPtrLocationSetAdd(newset, point); 1844 } 1845 } 1846 xmlXPathFreeObject(obj); 1847 valuePush(ctxt, xmlXPtrWrapLocationSet(newset)); 1848 } 1849 1850 /** 1851 * xmlXPtrEndPointFunction: 1852 * @ctxt: the XPointer Parser context 1853 * @nargs: the number of args 1854 * 1855 * Function implementing end-point() operation 1856 * as described in 5.4.3 1857 * ---------------------------- 1858 * location-set end-point(location-set) 1859 * 1860 * For each location x in the argument location-set, end-point adds a 1861 * location of type point to the result location-set. That point represents 1862 * the end point of location x and is determined by the following rules: 1863 * 1864 * - If x is of type point, the resulting point is x. 1865 * - If x is of type range, the resulting point is the end point of x. 1866 * - If x is of type root or element, the container node of the resulting 1867 * point is x and the index is the number of location children of x. 1868 * - If x is of type text, comment, or processing instruction, the container 1869 * node of the resulting point is x and the index is the length of the 1870 * string-value of x. 1871 * - If x is of type attribute or namespace, the function must signal a 1872 * syntax error. 1873 * ---------------------------- 1874 */ 1875 static void 1876 xmlXPtrEndPointFunction(xmlXPathParserContextPtr ctxt, int nargs) { 1877 xmlXPathObjectPtr tmp, obj, point; 1878 xmlLocationSetPtr newset = NULL; 1879 xmlLocationSetPtr oldset = NULL; 1880 1881 CHECK_ARITY(1); 1882 if ((ctxt->value == NULL) || 1883 ((ctxt->value->type != XPATH_LOCATIONSET) && 1884 (ctxt->value->type != XPATH_NODESET))) 1885 XP_ERROR(XPATH_INVALID_TYPE) 1886 1887 obj = valuePop(ctxt); 1888 if (obj->type == XPATH_NODESET) { 1889 /* 1890 * First convert to a location set 1891 */ 1892 tmp = xmlXPtrNewLocationSetNodeSet(obj->nodesetval); 1893 xmlXPathFreeObject(obj); 1894 if (tmp == NULL) 1895 XP_ERROR(XPATH_MEMORY_ERROR) 1896 obj = tmp; 1897 } 1898 1899 newset = xmlXPtrLocationSetCreate(NULL); 1900 if (newset == NULL) { 1901 xmlXPathFreeObject(obj); 1902 XP_ERROR(XPATH_MEMORY_ERROR); 1903 } 1904 oldset = (xmlLocationSetPtr) obj->user; 1905 if (oldset != NULL) { 1906 int i; 1907 1908 for (i = 0; i < oldset->locNr; i++) { 1909 tmp = oldset->locTab[i]; 1910 if (tmp == NULL) 1911 continue; 1912 point = NULL; 1913 switch (tmp->type) { 1914 case XPATH_POINT: 1915 point = xmlXPtrNewPoint(tmp->user, tmp->index); 1916 break; 1917 case XPATH_RANGE: { 1918 xmlNodePtr node = tmp->user2; 1919 if (node != NULL) { 1920 if ((node->type == XML_ATTRIBUTE_NODE) || 1921 (node->type == XML_NAMESPACE_DECL)) { 1922 xmlXPathFreeObject(obj); 1923 xmlXPtrFreeLocationSet(newset); 1924 XP_ERROR(XPTR_SYNTAX_ERROR); 1925 } 1926 point = xmlXPtrNewPoint(node, tmp->index2); 1927 } else if (tmp->user == NULL) { 1928 point = xmlXPtrNewPoint(node, 1929 xmlXPtrNbLocChildren(node)); 1930 } 1931 break; 1932 } 1933 default: 1934 /*** Should we raise an error ? 1935 xmlXPathFreeObject(obj); 1936 xmlXPathFreeObject(newset); 1937 XP_ERROR(XPATH_INVALID_TYPE) 1938 ***/ 1939 break; 1940 } 1941 if (point != NULL) 1942 xmlXPtrLocationSetAdd(newset, point); 1943 } 1944 } 1945 xmlXPathFreeObject(obj); 1946 valuePush(ctxt, xmlXPtrWrapLocationSet(newset)); 1947 } 1948 1949 1950 /** 1951 * xmlXPtrCoveringRange: 1952 * @ctxt: the XPointer Parser context 1953 * @loc: the location for which the covering range must be computed 1954 * 1955 * A covering range is a range that wholly encompasses a location 1956 * Section 5.3.3. Covering Ranges for All Location Types 1957 * http://www.w3.org/TR/xptr#N2267 1958 * 1959 * Returns a new location or NULL in case of error 1960 */ 1961 static xmlXPathObjectPtr 1962 xmlXPtrCoveringRange(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr loc) { 1963 if (loc == NULL) 1964 return(NULL); 1965 if ((ctxt == NULL) || (ctxt->context == NULL) || 1966 (ctxt->context->doc == NULL)) 1967 return(NULL); 1968 switch (loc->type) { 1969 case XPATH_POINT: 1970 return(xmlXPtrNewRange(loc->user, loc->index, 1971 loc->user, loc->index)); 1972 case XPATH_RANGE: 1973 if (loc->user2 != NULL) { 1974 return(xmlXPtrNewRange(loc->user, loc->index, 1975 loc->user2, loc->index2)); 1976 } else { 1977 xmlNodePtr node = (xmlNodePtr) loc->user; 1978 if (node == (xmlNodePtr) ctxt->context->doc) { 1979 return(xmlXPtrNewRange(node, 0, node, 1980 xmlXPtrGetArity(node))); 1981 } else { 1982 switch (node->type) { 1983 case XML_ATTRIBUTE_NODE: 1984 /* !!! our model is slightly different than XPath */ 1985 return(xmlXPtrNewRange(node, 0, node, 1986 xmlXPtrGetArity(node))); 1987 case XML_ELEMENT_NODE: 1988 case XML_TEXT_NODE: 1989 case XML_CDATA_SECTION_NODE: 1990 case XML_ENTITY_REF_NODE: 1991 case XML_PI_NODE: 1992 case XML_COMMENT_NODE: 1993 case XML_DOCUMENT_NODE: 1994 case XML_NOTATION_NODE: 1995 case XML_HTML_DOCUMENT_NODE: { 1996 int indx = xmlXPtrGetIndex(node); 1997 1998 node = node->parent; 1999 return(xmlXPtrNewRange(node, indx - 1, 2000 node, indx + 1)); 2001 } 2002 default: 2003 return(NULL); 2004 } 2005 } 2006 } 2007 default: 2008 TODO /* missed one case ??? */ 2009 } 2010 return(NULL); 2011 } 2012 2013 /** 2014 * xmlXPtrRangeFunction: 2015 * @ctxt: the XPointer Parser context 2016 * @nargs: the number of args 2017 * 2018 * Function implementing the range() function 5.4.3 2019 * location-set range(location-set ) 2020 * 2021 * The range function returns ranges covering the locations in 2022 * the argument location-set. For each location x in the argument 2023 * location-set, a range location representing the covering range of 2024 * x is added to the result location-set. 2025 */ 2026 static void 2027 xmlXPtrRangeFunction(xmlXPathParserContextPtr ctxt, int nargs) { 2028 int i; 2029 xmlXPathObjectPtr set; 2030 xmlLocationSetPtr oldset; 2031 xmlLocationSetPtr newset; 2032 2033 CHECK_ARITY(1); 2034 if ((ctxt->value == NULL) || 2035 ((ctxt->value->type != XPATH_LOCATIONSET) && 2036 (ctxt->value->type != XPATH_NODESET))) 2037 XP_ERROR(XPATH_INVALID_TYPE) 2038 2039 set = valuePop(ctxt); 2040 if (set->type == XPATH_NODESET) { 2041 xmlXPathObjectPtr tmp; 2042 2043 /* 2044 * First convert to a location set 2045 */ 2046 tmp = xmlXPtrNewLocationSetNodeSet(set->nodesetval); 2047 xmlXPathFreeObject(set); 2048 if (tmp == NULL) 2049 XP_ERROR(XPATH_MEMORY_ERROR) 2050 set = tmp; 2051 } 2052 oldset = (xmlLocationSetPtr) set->user; 2053 2054 /* 2055 * The loop is to compute the covering range for each item and add it 2056 */ 2057 newset = xmlXPtrLocationSetCreate(NULL); 2058 if (newset == NULL) { 2059 xmlXPathFreeObject(set); 2060 XP_ERROR(XPATH_MEMORY_ERROR); 2061 } 2062 if (oldset != NULL) { 2063 for (i = 0;i < oldset->locNr;i++) { 2064 xmlXPtrLocationSetAdd(newset, 2065 xmlXPtrCoveringRange(ctxt, oldset->locTab[i])); 2066 } 2067 } 2068 2069 /* 2070 * Save the new value and cleanup 2071 */ 2072 valuePush(ctxt, xmlXPtrWrapLocationSet(newset)); 2073 xmlXPathFreeObject(set); 2074 } 2075 2076 /** 2077 * xmlXPtrInsideRange: 2078 * @ctxt: the XPointer Parser context 2079 * @loc: the location for which the inside range must be computed 2080 * 2081 * A inside range is a range described in the range-inside() description 2082 * 2083 * Returns a new location or NULL in case of error 2084 */ 2085 static xmlXPathObjectPtr 2086 xmlXPtrInsideRange(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr loc) { 2087 if (loc == NULL) 2088 return(NULL); 2089 if ((ctxt == NULL) || (ctxt->context == NULL) || 2090 (ctxt->context->doc == NULL)) 2091 return(NULL); 2092 switch (loc->type) { 2093 case XPATH_POINT: { 2094 xmlNodePtr node = (xmlNodePtr) loc->user; 2095 switch (node->type) { 2096 case XML_PI_NODE: 2097 case XML_COMMENT_NODE: 2098 case XML_TEXT_NODE: 2099 case XML_CDATA_SECTION_NODE: { 2100 if (node->content == NULL) { 2101 return(xmlXPtrNewRange(node, 0, node, 0)); 2102 } else { 2103 return(xmlXPtrNewRange(node, 0, node, 2104 xmlStrlen(node->content))); 2105 } 2106 } 2107 case XML_ATTRIBUTE_NODE: 2108 case XML_ELEMENT_NODE: 2109 case XML_ENTITY_REF_NODE: 2110 case XML_DOCUMENT_NODE: 2111 case XML_NOTATION_NODE: 2112 case XML_HTML_DOCUMENT_NODE: { 2113 return(xmlXPtrNewRange(node, 0, node, 2114 xmlXPtrGetArity(node))); 2115 } 2116 default: 2117 break; 2118 } 2119 return(NULL); 2120 } 2121 case XPATH_RANGE: { 2122 xmlNodePtr node = (xmlNodePtr) loc->user; 2123 if (loc->user2 != NULL) { 2124 return(xmlXPtrNewRange(node, loc->index, 2125 loc->user2, loc->index2)); 2126 } else { 2127 switch (node->type) { 2128 case XML_PI_NODE: 2129 case XML_COMMENT_NODE: 2130 case XML_TEXT_NODE: 2131 case XML_CDATA_SECTION_NODE: { 2132 if (node->content == NULL) { 2133 return(xmlXPtrNewRange(node, 0, node, 0)); 2134 } else { 2135 return(xmlXPtrNewRange(node, 0, node, 2136 xmlStrlen(node->content))); 2137 } 2138 } 2139 case XML_ATTRIBUTE_NODE: 2140 case XML_ELEMENT_NODE: 2141 case XML_ENTITY_REF_NODE: 2142 case XML_DOCUMENT_NODE: 2143 case XML_NOTATION_NODE: 2144 case XML_HTML_DOCUMENT_NODE: { 2145 return(xmlXPtrNewRange(node, 0, node, 2146 xmlXPtrGetArity(node))); 2147 } 2148 default: 2149 break; 2150 } 2151 return(NULL); 2152 } 2153 } 2154 default: 2155 TODO /* missed one case ??? */ 2156 } 2157 return(NULL); 2158 } 2159 2160 /** 2161 * xmlXPtrRangeInsideFunction: 2162 * @ctxt: the XPointer Parser context 2163 * @nargs: the number of args 2164 * 2165 * Function implementing the range-inside() function 5.4.3 2166 * location-set range-inside(location-set ) 2167 * 2168 * The range-inside function returns ranges covering the contents of 2169 * the locations in the argument location-set. For each location x in 2170 * the argument location-set, a range location is added to the result 2171 * location-set. If x is a range location, then x is added to the 2172 * result location-set. If x is not a range location, then x is used 2173 * as the container location of the start and end points of the range 2174 * location to be added; the index of the start point of the range is 2175 * zero; if the end point is a character point then its index is the 2176 * length of the string-value of x, and otherwise is the number of 2177 * location children of x. 2178 * 2179 */ 2180 static void 2181 xmlXPtrRangeInsideFunction(xmlXPathParserContextPtr ctxt, int nargs) { 2182 int i; 2183 xmlXPathObjectPtr set; 2184 xmlLocationSetPtr oldset; 2185 xmlLocationSetPtr newset; 2186 2187 CHECK_ARITY(1); 2188 if ((ctxt->value == NULL) || 2189 ((ctxt->value->type != XPATH_LOCATIONSET) && 2190 (ctxt->value->type != XPATH_NODESET))) 2191 XP_ERROR(XPATH_INVALID_TYPE) 2192 2193 set = valuePop(ctxt); 2194 if (set->type == XPATH_NODESET) { 2195 xmlXPathObjectPtr tmp; 2196 2197 /* 2198 * First convert to a location set 2199 */ 2200 tmp = xmlXPtrNewLocationSetNodeSet(set->nodesetval); 2201 xmlXPathFreeObject(set); 2202 if (tmp == NULL) 2203 XP_ERROR(XPATH_MEMORY_ERROR) 2204 set = tmp; 2205 } 2206 2207 /* 2208 * The loop is to compute the covering range for each item and add it 2209 */ 2210 newset = xmlXPtrLocationSetCreate(NULL); 2211 if (newset == NULL) { 2212 xmlXPathFreeObject(set); 2213 XP_ERROR(XPATH_MEMORY_ERROR); 2214 } 2215 oldset = (xmlLocationSetPtr) set->user; 2216 if (oldset != NULL) { 2217 for (i = 0;i < oldset->locNr;i++) { 2218 xmlXPtrLocationSetAdd(newset, 2219 xmlXPtrInsideRange(ctxt, oldset->locTab[i])); 2220 } 2221 } 2222 2223 /* 2224 * Save the new value and cleanup 2225 */ 2226 valuePush(ctxt, xmlXPtrWrapLocationSet(newset)); 2227 xmlXPathFreeObject(set); 2228 } 2229 2230 /** 2231 * xmlXPtrRangeToFunction: 2232 * @ctxt: the XPointer Parser context 2233 * @nargs: the number of args 2234 * 2235 * Implement the range-to() XPointer function 2236 * 2237 * Obsolete. range-to is not a real function but a special type of location 2238 * step which is handled in xpath.c. 2239 */ 2240 void 2241 xmlXPtrRangeToFunction(xmlXPathParserContextPtr ctxt, 2242 int nargs ATTRIBUTE_UNUSED) { 2243 XP_ERROR(XPATH_EXPR_ERROR); 2244 } 2245 2246 /** 2247 * xmlXPtrAdvanceNode: 2248 * @cur: the node 2249 * @level: incremented/decremented to show level in tree 2250 * 2251 * Advance to the next element or text node in document order 2252 * TODO: add a stack for entering/exiting entities 2253 * 2254 * Returns -1 in case of failure, 0 otherwise 2255 */ 2256 xmlNodePtr 2257 xmlXPtrAdvanceNode(xmlNodePtr cur, int *level) { 2258 next: 2259 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) 2260 return(NULL); 2261 if (cur->children != NULL) { 2262 cur = cur->children ; 2263 if (level != NULL) 2264 (*level)++; 2265 goto found; 2266 } 2267 skip: /* This label should only be needed if something is wrong! */ 2268 if (cur->next != NULL) { 2269 cur = cur->next; 2270 goto found; 2271 } 2272 do { 2273 cur = cur->parent; 2274 if (level != NULL) 2275 (*level)--; 2276 if (cur == NULL) return(NULL); 2277 if (cur->next != NULL) { 2278 cur = cur->next; 2279 goto found; 2280 } 2281 } while (cur != NULL); 2282 2283 found: 2284 if ((cur->type != XML_ELEMENT_NODE) && 2285 (cur->type != XML_TEXT_NODE) && 2286 (cur->type != XML_DOCUMENT_NODE) && 2287 (cur->type != XML_HTML_DOCUMENT_NODE) && 2288 (cur->type != XML_CDATA_SECTION_NODE)) { 2289 if (cur->type == XML_ENTITY_REF_NODE) { /* Shouldn't happen */ 2290 TODO 2291 goto skip; 2292 } 2293 goto next; 2294 } 2295 return(cur); 2296 } 2297 2298 /** 2299 * xmlXPtrAdvanceChar: 2300 * @node: the node 2301 * @indx: the indx 2302 * @bytes: the number of bytes 2303 * 2304 * Advance a point of the associated number of bytes (not UTF8 chars) 2305 * 2306 * Returns -1 in case of failure, 0 otherwise 2307 */ 2308 static int 2309 xmlXPtrAdvanceChar(xmlNodePtr *node, int *indx, int bytes) { 2310 xmlNodePtr cur; 2311 int pos; 2312 int len; 2313 2314 if ((node == NULL) || (indx == NULL)) 2315 return(-1); 2316 cur = *node; 2317 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) 2318 return(-1); 2319 pos = *indx; 2320 2321 while (bytes >= 0) { 2322 /* 2323 * First position to the beginning of the first text node 2324 * corresponding to this point 2325 */ 2326 while ((cur != NULL) && 2327 ((cur->type == XML_ELEMENT_NODE) || 2328 (cur->type == XML_DOCUMENT_NODE) || 2329 (cur->type == XML_HTML_DOCUMENT_NODE))) { 2330 if (pos > 0) { 2331 cur = xmlXPtrGetNthChild(cur, pos); 2332 pos = 0; 2333 } else { 2334 cur = xmlXPtrAdvanceNode(cur, NULL); 2335 pos = 0; 2336 } 2337 } 2338 2339 if (cur == NULL) { 2340 *node = NULL; 2341 *indx = 0; 2342 return(-1); 2343 } 2344 2345 /* 2346 * if there is no move needed return the current value. 2347 */ 2348 if (pos == 0) pos = 1; 2349 if (bytes == 0) { 2350 *node = cur; 2351 *indx = pos; 2352 return(0); 2353 } 2354 /* 2355 * We should have a text (or cdata) node ... 2356 */ 2357 len = 0; 2358 if ((cur->type != XML_ELEMENT_NODE) && 2359 (cur->content != NULL)) { 2360 len = xmlStrlen(cur->content); 2361 } 2362 if (pos > len) { 2363 /* Strange, the indx in the text node is greater than it's len */ 2364 STRANGE 2365 pos = len; 2366 } 2367 if (pos + bytes >= len) { 2368 bytes -= (len - pos); 2369 cur = xmlXPtrAdvanceNode(cur, NULL); 2370 pos = 0; 2371 } else if (pos + bytes < len) { 2372 pos += bytes; 2373 *node = cur; 2374 *indx = pos; 2375 return(0); 2376 } 2377 } 2378 return(-1); 2379 } 2380 2381 /** 2382 * xmlXPtrMatchString: 2383 * @string: the string to search 2384 * @start: the start textnode 2385 * @startindex: the start index 2386 * @end: the end textnode IN/OUT 2387 * @endindex: the end index IN/OUT 2388 * 2389 * Check whether the document contains @string at the position 2390 * (@start, @startindex) and limited by the (@end, @endindex) point 2391 * 2392 * Returns -1 in case of failure, 0 if not found, 1 if found in which case 2393 * (@start, @startindex) will indicate the position of the beginning 2394 * of the range and (@end, @endindex) will indicate the end 2395 * of the range 2396 */ 2397 static int 2398 xmlXPtrMatchString(const xmlChar *string, xmlNodePtr start, int startindex, 2399 xmlNodePtr *end, int *endindex) { 2400 xmlNodePtr cur; 2401 int pos; /* 0 based */ 2402 int len; /* in bytes */ 2403 int stringlen; /* in bytes */ 2404 int match; 2405 2406 if (string == NULL) 2407 return(-1); 2408 if ((start == NULL) || (start->type == XML_NAMESPACE_DECL)) 2409 return(-1); 2410 if ((end == NULL) || (*end == NULL) || 2411 ((*end)->type == XML_NAMESPACE_DECL) || (endindex == NULL)) 2412 return(-1); 2413 cur = start; 2414 pos = startindex - 1; 2415 stringlen = xmlStrlen(string); 2416 2417 while (stringlen > 0) { 2418 if ((cur == *end) && (pos + stringlen > *endindex)) 2419 return(0); 2420 2421 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) { 2422 len = xmlStrlen(cur->content); 2423 if (len >= pos + stringlen) { 2424 match = (!xmlStrncmp(&cur->content[pos], string, stringlen)); 2425 if (match) { 2426 #ifdef DEBUG_RANGES 2427 xmlGenericError(xmlGenericErrorContext, 2428 "found range %d bytes at index %d of ->", 2429 stringlen, pos + 1); 2430 xmlDebugDumpString(stdout, cur->content); 2431 xmlGenericError(xmlGenericErrorContext, "\n"); 2432 #endif 2433 *end = cur; 2434 *endindex = pos + stringlen; 2435 return(1); 2436 } else { 2437 return(0); 2438 } 2439 } else { 2440 int sub = len - pos; 2441 match = (!xmlStrncmp(&cur->content[pos], string, sub)); 2442 if (match) { 2443 #ifdef DEBUG_RANGES 2444 xmlGenericError(xmlGenericErrorContext, 2445 "found subrange %d bytes at index %d of ->", 2446 sub, pos + 1); 2447 xmlDebugDumpString(stdout, cur->content); 2448 xmlGenericError(xmlGenericErrorContext, "\n"); 2449 #endif 2450 string = &string[sub]; 2451 stringlen -= sub; 2452 } else { 2453 return(0); 2454 } 2455 } 2456 } 2457 cur = xmlXPtrAdvanceNode(cur, NULL); 2458 if (cur == NULL) 2459 return(0); 2460 pos = 0; 2461 } 2462 return(1); 2463 } 2464 2465 /** 2466 * xmlXPtrSearchString: 2467 * @string: the string to search 2468 * @start: the start textnode IN/OUT 2469 * @startindex: the start index IN/OUT 2470 * @end: the end textnode 2471 * @endindex: the end index 2472 * 2473 * Search the next occurrence of @string within the document content 2474 * until the (@end, @endindex) point is reached 2475 * 2476 * Returns -1 in case of failure, 0 if not found, 1 if found in which case 2477 * (@start, @startindex) will indicate the position of the beginning 2478 * of the range and (@end, @endindex) will indicate the end 2479 * of the range 2480 */ 2481 static int 2482 xmlXPtrSearchString(const xmlChar *string, xmlNodePtr *start, int *startindex, 2483 xmlNodePtr *end, int *endindex) { 2484 xmlNodePtr cur; 2485 const xmlChar *str; 2486 int pos; /* 0 based */ 2487 int len; /* in bytes */ 2488 xmlChar first; 2489 2490 if (string == NULL) 2491 return(-1); 2492 if ((start == NULL) || (*start == NULL) || 2493 ((*start)->type == XML_NAMESPACE_DECL) || (startindex == NULL)) 2494 return(-1); 2495 if ((end == NULL) || (endindex == NULL)) 2496 return(-1); 2497 cur = *start; 2498 pos = *startindex - 1; 2499 first = string[0]; 2500 2501 while (cur != NULL) { 2502 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) { 2503 len = xmlStrlen(cur->content); 2504 while (pos <= len) { 2505 if (first != 0) { 2506 str = xmlStrchr(&cur->content[pos], first); 2507 if (str != NULL) { 2508 pos = (str - (xmlChar *)(cur->content)); 2509 #ifdef DEBUG_RANGES 2510 xmlGenericError(xmlGenericErrorContext, 2511 "found '%c' at index %d of ->", 2512 first, pos + 1); 2513 xmlDebugDumpString(stdout, cur->content); 2514 xmlGenericError(xmlGenericErrorContext, "\n"); 2515 #endif 2516 if (xmlXPtrMatchString(string, cur, pos + 1, 2517 end, endindex)) { 2518 *start = cur; 2519 *startindex = pos + 1; 2520 return(1); 2521 } 2522 pos++; 2523 } else { 2524 pos = len + 1; 2525 } 2526 } else { 2527 /* 2528 * An empty string is considered to match before each 2529 * character of the string-value and after the final 2530 * character. 2531 */ 2532 #ifdef DEBUG_RANGES 2533 xmlGenericError(xmlGenericErrorContext, 2534 "found '' at index %d of ->", 2535 pos + 1); 2536 xmlDebugDumpString(stdout, cur->content); 2537 xmlGenericError(xmlGenericErrorContext, "\n"); 2538 #endif 2539 *start = cur; 2540 *startindex = pos + 1; 2541 *end = cur; 2542 *endindex = pos + 1; 2543 return(1); 2544 } 2545 } 2546 } 2547 if ((cur == *end) && (pos >= *endindex)) 2548 return(0); 2549 cur = xmlXPtrAdvanceNode(cur, NULL); 2550 if (cur == NULL) 2551 return(0); 2552 pos = 1; 2553 } 2554 return(0); 2555 } 2556 2557 /** 2558 * xmlXPtrGetLastChar: 2559 * @node: the node 2560 * @index: the index 2561 * 2562 * Computes the point coordinates of the last char of this point 2563 * 2564 * Returns -1 in case of failure, 0 otherwise 2565 */ 2566 static int 2567 xmlXPtrGetLastChar(xmlNodePtr *node, int *indx) { 2568 xmlNodePtr cur; 2569 int pos, len = 0; 2570 2571 if ((node == NULL) || (*node == NULL) || 2572 ((*node)->type == XML_NAMESPACE_DECL) || (indx == NULL)) 2573 return(-1); 2574 cur = *node; 2575 pos = *indx; 2576 2577 if ((cur->type == XML_ELEMENT_NODE) || 2578 (cur->type == XML_DOCUMENT_NODE) || 2579 (cur->type == XML_HTML_DOCUMENT_NODE)) { 2580 if (pos > 0) { 2581 cur = xmlXPtrGetNthChild(cur, pos); 2582 } 2583 } 2584 while (cur != NULL) { 2585 if (cur->last != NULL) 2586 cur = cur->last; 2587 else if ((cur->type != XML_ELEMENT_NODE) && 2588 (cur->content != NULL)) { 2589 len = xmlStrlen(cur->content); 2590 break; 2591 } else { 2592 return(-1); 2593 } 2594 } 2595 if (cur == NULL) 2596 return(-1); 2597 *node = cur; 2598 *indx = len; 2599 return(0); 2600 } 2601 2602 /** 2603 * xmlXPtrGetStartPoint: 2604 * @obj: an range 2605 * @node: the resulting node 2606 * @indx: the resulting index 2607 * 2608 * read the object and return the start point coordinates. 2609 * 2610 * Returns -1 in case of failure, 0 otherwise 2611 */ 2612 static int 2613 xmlXPtrGetStartPoint(xmlXPathObjectPtr obj, xmlNodePtr *node, int *indx) { 2614 if ((obj == NULL) || (node == NULL) || (indx == NULL)) 2615 return(-1); 2616 2617 switch (obj->type) { 2618 case XPATH_POINT: 2619 *node = obj->user; 2620 if (obj->index <= 0) 2621 *indx = 0; 2622 else 2623 *indx = obj->index; 2624 return(0); 2625 case XPATH_RANGE: 2626 *node = obj->user; 2627 if (obj->index <= 0) 2628 *indx = 0; 2629 else 2630 *indx = obj->index; 2631 return(0); 2632 default: 2633 break; 2634 } 2635 return(-1); 2636 } 2637 2638 /** 2639 * xmlXPtrGetEndPoint: 2640 * @obj: an range 2641 * @node: the resulting node 2642 * @indx: the resulting indx 2643 * 2644 * read the object and return the end point coordinates. 2645 * 2646 * Returns -1 in case of failure, 0 otherwise 2647 */ 2648 static int 2649 xmlXPtrGetEndPoint(xmlXPathObjectPtr obj, xmlNodePtr *node, int *indx) { 2650 if ((obj == NULL) || (node == NULL) || (indx == NULL)) 2651 return(-1); 2652 2653 switch (obj->type) { 2654 case XPATH_POINT: 2655 *node = obj->user; 2656 if (obj->index <= 0) 2657 *indx = 0; 2658 else 2659 *indx = obj->index; 2660 return(0); 2661 case XPATH_RANGE: 2662 *node = obj->user; 2663 if (obj->index <= 0) 2664 *indx = 0; 2665 else 2666 *indx = obj->index; 2667 return(0); 2668 default: 2669 break; 2670 } 2671 return(-1); 2672 } 2673 2674 /** 2675 * xmlXPtrStringRangeFunction: 2676 * @ctxt: the XPointer Parser context 2677 * @nargs: the number of args 2678 * 2679 * Function implementing the string-range() function 2680 * range as described in 5.4.2 2681 * 2682 * ------------------------------ 2683 * [Definition: For each location in the location-set argument, 2684 * string-range returns a set of string ranges, a set of substrings in a 2685 * string. Specifically, the string-value of the location is searched for 2686 * substrings that match the string argument, and the resulting location-set 2687 * will contain a range location for each non-overlapping match.] 2688 * An empty string is considered to match before each character of the 2689 * string-value and after the final character. Whitespace in a string 2690 * is matched literally, with no normalization except that provided by 2691 * XML for line ends. The third argument gives the position of the first 2692 * character to be in the resulting range, relative to the start of the 2693 * match. The default value is 1, which makes the range start immediately 2694 * before the first character of the matched string. The fourth argument 2695 * gives the number of characters in the range; the default is that the 2696 * range extends to the end of the matched string. 2697 * 2698 * Element boundaries, as well as entire embedded nodes such as processing 2699 * instructions and comments, are ignored as defined in [XPath]. 2700 * 2701 * If the string in the second argument is not found in the string-value 2702 * of the location, or if a value in the third or fourth argument indicates 2703 * a string that is beyond the beginning or end of the document, the 2704 * expression fails. 2705 * 2706 * The points of the range-locations in the returned location-set will 2707 * all be character points. 2708 * ------------------------------ 2709 */ 2710 static void 2711 xmlXPtrStringRangeFunction(xmlXPathParserContextPtr ctxt, int nargs) { 2712 int i, startindex, endindex = 0, fendindex; 2713 xmlNodePtr start, end = 0, fend; 2714 xmlXPathObjectPtr set = NULL; 2715 xmlLocationSetPtr oldset; 2716 xmlLocationSetPtr newset = NULL; 2717 xmlXPathObjectPtr string = NULL; 2718 xmlXPathObjectPtr position = NULL; 2719 xmlXPathObjectPtr number = NULL; 2720 int found, pos = 0, num = 0; 2721 2722 /* 2723 * Grab the arguments 2724 */ 2725 if ((nargs < 2) || (nargs > 4)) 2726 XP_ERROR(XPATH_INVALID_ARITY); 2727 2728 if (nargs >= 4) { 2729 if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_NUMBER)) { 2730 xmlXPathErr(ctxt, XPATH_INVALID_TYPE); 2731 goto error; 2732 } 2733 number = valuePop(ctxt); 2734 if (number != NULL) 2735 num = (int) number->floatval; 2736 } 2737 if (nargs >= 3) { 2738 if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_NUMBER)) { 2739 xmlXPathErr(ctxt, XPATH_INVALID_TYPE); 2740 goto error; 2741 } 2742 position = valuePop(ctxt); 2743 if (position != NULL) 2744 pos = (int) position->floatval; 2745 } 2746 if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) { 2747 xmlXPathErr(ctxt, XPATH_INVALID_TYPE); 2748 goto error; 2749 } 2750 string = valuePop(ctxt); 2751 if ((ctxt->value == NULL) || 2752 ((ctxt->value->type != XPATH_LOCATIONSET) && 2753 (ctxt->value->type != XPATH_NODESET))) { 2754 xmlXPathErr(ctxt, XPATH_INVALID_TYPE); 2755 goto error; 2756 } 2757 set = valuePop(ctxt); 2758 newset = xmlXPtrLocationSetCreate(NULL); 2759 if (newset == NULL) { 2760 xmlXPathErr(ctxt, XPATH_MEMORY_ERROR); 2761 goto error; 2762 } 2763 if (set->nodesetval == NULL) { 2764 goto error; 2765 } 2766 if (set->type == XPATH_NODESET) { 2767 xmlXPathObjectPtr tmp; 2768 2769 /* 2770 * First convert to a location set 2771 */ 2772 tmp = xmlXPtrNewLocationSetNodeSet(set->nodesetval); 2773 xmlXPathFreeObject(set); 2774 set = NULL; 2775 if (tmp == NULL) { 2776 xmlXPathErr(ctxt, XPATH_MEMORY_ERROR); 2777 goto error; 2778 } 2779 set = tmp; 2780 } 2781 oldset = (xmlLocationSetPtr) set->user; 2782 2783 /* 2784 * The loop is to search for each element in the location set 2785 * the list of location set corresponding to that search 2786 */ 2787 for (i = 0;i < oldset->locNr;i++) { 2788 #ifdef DEBUG_RANGES 2789 xmlXPathDebugDumpObject(stdout, oldset->locTab[i], 0); 2790 #endif 2791 2792 xmlXPtrGetStartPoint(oldset->locTab[i], &start, &startindex); 2793 xmlXPtrGetEndPoint(oldset->locTab[i], &end, &endindex); 2794 xmlXPtrAdvanceChar(&start, &startindex, 0); 2795 xmlXPtrGetLastChar(&end, &endindex); 2796 2797 #ifdef DEBUG_RANGES 2798 xmlGenericError(xmlGenericErrorContext, 2799 "from index %d of ->", startindex); 2800 xmlDebugDumpString(stdout, start->content); 2801 xmlGenericError(xmlGenericErrorContext, "\n"); 2802 xmlGenericError(xmlGenericErrorContext, 2803 "to index %d of ->", endindex); 2804 xmlDebugDumpString(stdout, end->content); 2805 xmlGenericError(xmlGenericErrorContext, "\n"); 2806 #endif 2807 do { 2808 fend = end; 2809 fendindex = endindex; 2810 found = xmlXPtrSearchString(string->stringval, &start, &startindex, 2811 &fend, &fendindex); 2812 if (found == 1) { 2813 if (position == NULL) { 2814 xmlXPtrLocationSetAdd(newset, 2815 xmlXPtrNewRange(start, startindex, fend, fendindex)); 2816 } else if (xmlXPtrAdvanceChar(&start, &startindex, 2817 pos - 1) == 0) { 2818 if ((number != NULL) && (num > 0)) { 2819 int rindx; 2820 xmlNodePtr rend; 2821 rend = start; 2822 rindx = startindex - 1; 2823 if (xmlXPtrAdvanceChar(&rend, &rindx, 2824 num) == 0) { 2825 xmlXPtrLocationSetAdd(newset, 2826 xmlXPtrNewRange(start, startindex, 2827 rend, rindx)); 2828 } 2829 } else if ((number != NULL) && (num <= 0)) { 2830 xmlXPtrLocationSetAdd(newset, 2831 xmlXPtrNewRange(start, startindex, 2832 start, startindex)); 2833 } else { 2834 xmlXPtrLocationSetAdd(newset, 2835 xmlXPtrNewRange(start, startindex, 2836 fend, fendindex)); 2837 } 2838 } 2839 start = fend; 2840 startindex = fendindex; 2841 if (string->stringval[0] == 0) 2842 startindex++; 2843 } 2844 } while (found == 1); 2845 } 2846 2847 /* 2848 * Save the new value and cleanup 2849 */ 2850 error: 2851 if (newset != NULL) 2852 valuePush(ctxt, xmlXPtrWrapLocationSet(newset)); 2853 xmlXPathFreeObject(set); 2854 xmlXPathFreeObject(string); 2855 if (position) xmlXPathFreeObject(position); 2856 if (number) xmlXPathFreeObject(number); 2857 } 2858 2859 /** 2860 * xmlXPtrEvalRangePredicate: 2861 * @ctxt: the XPointer Parser context 2862 * 2863 * [8] Predicate ::= '[' PredicateExpr ']' 2864 * [9] PredicateExpr ::= Expr 2865 * 2866 * Evaluate a predicate as in xmlXPathEvalPredicate() but for 2867 * a Location Set instead of a node set 2868 */ 2869 void 2870 xmlXPtrEvalRangePredicate(xmlXPathParserContextPtr ctxt) { 2871 const xmlChar *cur; 2872 xmlXPathObjectPtr res; 2873 xmlXPathObjectPtr obj, tmp; 2874 xmlLocationSetPtr newset = NULL; 2875 xmlLocationSetPtr oldset; 2876 int i; 2877 2878 if (ctxt == NULL) return; 2879 2880 SKIP_BLANKS; 2881 if (CUR != '[') { 2882 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); 2883 } 2884 NEXT; 2885 SKIP_BLANKS; 2886 2887 /* 2888 * Extract the old set, and then evaluate the result of the 2889 * expression for all the element in the set. use it to grow 2890 * up a new set. 2891 */ 2892 CHECK_TYPE(XPATH_LOCATIONSET); 2893 obj = valuePop(ctxt); 2894 oldset = obj->user; 2895 ctxt->context->node = NULL; 2896 2897 if ((oldset == NULL) || (oldset->locNr == 0)) { 2898 ctxt->context->contextSize = 0; 2899 ctxt->context->proximityPosition = 0; 2900 xmlXPathEvalExpr(ctxt); 2901 res = valuePop(ctxt); 2902 if (res != NULL) 2903 xmlXPathFreeObject(res); 2904 valuePush(ctxt, obj); 2905 CHECK_ERROR; 2906 } else { 2907 /* 2908 * Save the expression pointer since we will have to evaluate 2909 * it multiple times. Initialize the new set. 2910 */ 2911 cur = ctxt->cur; 2912 newset = xmlXPtrLocationSetCreate(NULL); 2913 2914 for (i = 0; i < oldset->locNr; i++) { 2915 ctxt->cur = cur; 2916 2917 /* 2918 * Run the evaluation with a node list made of a single item 2919 * in the nodeset. 2920 */ 2921 ctxt->context->node = oldset->locTab[i]->user; 2922 tmp = xmlXPathNewNodeSet(ctxt->context->node); 2923 valuePush(ctxt, tmp); 2924 ctxt->context->contextSize = oldset->locNr; 2925 ctxt->context->proximityPosition = i + 1; 2926 2927 xmlXPathEvalExpr(ctxt); 2928 CHECK_ERROR; 2929 2930 /* 2931 * The result of the evaluation need to be tested to 2932 * decided whether the filter succeeded or not 2933 */ 2934 res = valuePop(ctxt); 2935 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 2936 xmlXPtrLocationSetAdd(newset, 2937 xmlXPathObjectCopy(oldset->locTab[i])); 2938 } 2939 2940 /* 2941 * Cleanup 2942 */ 2943 if (res != NULL) 2944 xmlXPathFreeObject(res); 2945 if (ctxt->value == tmp) { 2946 res = valuePop(ctxt); 2947 xmlXPathFreeObject(res); 2948 } 2949 2950 ctxt->context->node = NULL; 2951 } 2952 2953 /* 2954 * The result is used as the new evaluation set. 2955 */ 2956 xmlXPathFreeObject(obj); 2957 ctxt->context->node = NULL; 2958 ctxt->context->contextSize = -1; 2959 ctxt->context->proximityPosition = -1; 2960 valuePush(ctxt, xmlXPtrWrapLocationSet(newset)); 2961 } 2962 if (CUR != ']') { 2963 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); 2964 } 2965 2966 NEXT; 2967 SKIP_BLANKS; 2968 } 2969 #endif /* LIBXML_XPTR_LOCS_ENABLED */ 2970 2971 #endif 2972 2973