Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenxpointer.c
Go to the documentation of this file.
00001 /* 00002 * xpointer.c : Code to handle XML Pointer 00003 * 00004 * Base implementation was made accordingly to 00005 * W3C Candidate Recommendation 7 June 2000 00006 * http://www.w3.org/TR/2000/CR-xptr-20000607 00007 * 00008 * Added support for the element() scheme described in: 00009 * W3C Proposed Recommendation 13 November 2002 00010 * http://www.w3.org/TR/2002/PR-xptr-element-20021113/ 00011 * 00012 * See Copyright for the status of this software. 00013 * 00014 * daniel@veillard.com 00015 */ 00016 00017 #define IN_LIBXML 00018 #include "libxml.h" 00019 00020 /* 00021 * TODO: better handling of error cases, the full expression should 00022 * be parsed beforehand instead of a progressive evaluation 00023 * TODO: Access into entities references are not supported now ... 00024 * need a start to be able to pop out of entities refs since 00025 * parent is the endity declaration, not the ref. 00026 */ 00027 00028 #include <string.h> 00029 #include <libxml/xpointer.h> 00030 #include <libxml/xmlmemory.h> 00031 #include <libxml/parserInternals.h> 00032 #include <libxml/uri.h> 00033 #include <libxml/xpath.h> 00034 #include <libxml/xpathInternals.h> 00035 #include <libxml/xmlerror.h> 00036 #include <libxml/globals.h> 00037 00038 #ifdef LIBXML_XPTR_ENABLED 00039 00040 /* Add support of the xmlns() xpointer scheme to initialize the namespaces */ 00041 #define XPTR_XMLNS_SCHEME 00042 00043 /* #define DEBUG_RANGES */ 00044 #ifdef DEBUG_RANGES 00045 #ifdef LIBXML_DEBUG_ENABLED 00046 #include <libxml/debugXML.h> 00047 #endif 00048 #endif 00049 00050 #define TODO \ 00051 xmlGenericError(xmlGenericErrorContext, \ 00052 "Unimplemented block at %s:%d\n", \ 00053 __FILE__, __LINE__); 00054 00055 #define STRANGE \ 00056 xmlGenericError(xmlGenericErrorContext, \ 00057 "Internal error at %s:%d\n", \ 00058 __FILE__, __LINE__); 00059 00060 /************************************************************************ 00061 * * 00062 * Some factorized error routines * 00063 * * 00064 ************************************************************************/ 00065 00072 static void 00073 xmlXPtrErrMemory(const char *extra) 00074 { 00075 __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_XPOINTER, 00076 XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0, extra, 00077 NULL, NULL, 0, 0, 00078 "Memory allocation failed : %s\n", extra); 00079 } 00080 00088 static void 00089 xmlXPtrErr(xmlXPathParserContextPtr ctxt, int error, 00090 const char * msg, const xmlChar *extra) 00091 { 00092 if (ctxt != NULL) 00093 ctxt->error = error; 00094 if ((ctxt == NULL) || (ctxt->context == NULL)) { 00095 __xmlRaiseError(NULL, NULL, NULL, 00096 NULL, NULL, XML_FROM_XPOINTER, error, 00097 XML_ERR_ERROR, NULL, 0, 00098 (const char *) extra, NULL, NULL, 0, 0, 00099 msg, extra); 00100 return; 00101 } 00102 ctxt->context->lastError.domain = XML_FROM_XPOINTER; 00103 ctxt->context->lastError.code = error; 00104 ctxt->context->lastError.level = XML_ERR_ERROR; 00105 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base); 00106 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base; 00107 ctxt->context->lastError.node = ctxt->context->debugNode; 00108 if (ctxt->context->error != NULL) { 00109 ctxt->context->error(ctxt->context->userData, 00110 &ctxt->context->lastError); 00111 } else { 00112 __xmlRaiseError(NULL, NULL, NULL, 00113 NULL, ctxt->context->debugNode, XML_FROM_XPOINTER, 00114 error, XML_ERR_ERROR, NULL, 0, 00115 (const char *) extra, (const char *) ctxt->base, NULL, 00116 ctxt->cur - ctxt->base, 0, 00117 msg, extra); 00118 } 00119 } 00120 00121 /************************************************************************ 00122 * * 00123 * A few helper functions for child sequences * 00124 * * 00125 ************************************************************************/ 00126 /* xmlXPtrAdvanceNode is a private function, but used by xinclude.c */ 00127 xmlNodePtr xmlXPtrAdvanceNode(xmlNodePtr cur, int *level); 00134 static int 00135 xmlXPtrGetArity(xmlNodePtr cur) { 00136 int i; 00137 if (cur == NULL) 00138 return(-1); 00139 cur = cur->children; 00140 for (i = 0;cur != NULL;cur = cur->next) { 00141 if ((cur->type == XML_ELEMENT_NODE) || 00142 (cur->type == XML_DOCUMENT_NODE) || 00143 (cur->type == XML_HTML_DOCUMENT_NODE)) { 00144 i++; 00145 } 00146 } 00147 return(i); 00148 } 00149 00157 static int 00158 xmlXPtrGetIndex(xmlNodePtr cur) { 00159 int i; 00160 if (cur == NULL) 00161 return(-1); 00162 for (i = 1;cur != NULL;cur = cur->prev) { 00163 if ((cur->type == XML_ELEMENT_NODE) || 00164 (cur->type == XML_DOCUMENT_NODE) || 00165 (cur->type == XML_HTML_DOCUMENT_NODE)) { 00166 i++; 00167 } 00168 } 00169 return(i); 00170 } 00171 00179 static xmlNodePtr 00180 xmlXPtrGetNthChild(xmlNodePtr cur, int no) { 00181 int i; 00182 if (cur == NULL) 00183 return(cur); 00184 cur = cur->children; 00185 for (i = 0;i <= no;cur = cur->next) { 00186 if (cur == NULL) 00187 return(cur); 00188 if ((cur->type == XML_ELEMENT_NODE) || 00189 (cur->type == XML_DOCUMENT_NODE) || 00190 (cur->type == XML_HTML_DOCUMENT_NODE)) { 00191 i++; 00192 if (i == no) 00193 break; 00194 } 00195 } 00196 return(cur); 00197 } 00198 00199 /************************************************************************ 00200 * * 00201 * Handling of XPointer specific types * 00202 * * 00203 ************************************************************************/ 00204 00217 static int 00218 xmlXPtrCmpPoints(xmlNodePtr node1, int index1, xmlNodePtr node2, int index2) { 00219 if ((node1 == NULL) || (node2 == NULL)) 00220 return(-2); 00221 /* 00222 * a couple of optimizations which will avoid computations in most cases 00223 */ 00224 if (node1 == node2) { 00225 if (index1 < index2) 00226 return(1); 00227 if (index1 > index2) 00228 return(-1); 00229 return(0); 00230 } 00231 return(xmlXPathCmpNodes(node1, node2)); 00232 } 00233 00243 static xmlXPathObjectPtr 00244 xmlXPtrNewPoint(xmlNodePtr node, int indx) { 00245 xmlXPathObjectPtr ret; 00246 00247 if (node == NULL) 00248 return(NULL); 00249 if (indx < 0) 00250 return(NULL); 00251 00252 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 00253 if (ret == NULL) { 00254 xmlXPtrErrMemory("allocating point"); 00255 return(NULL); 00256 } 00257 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 00258 ret->type = XPATH_POINT; 00259 ret->user = (void *) node; 00260 ret->index = indx; 00261 return(ret); 00262 } 00263 00270 static void 00271 xmlXPtrRangeCheckOrder(xmlXPathObjectPtr range) { 00272 int tmp; 00273 xmlNodePtr tmp2; 00274 if (range == NULL) 00275 return; 00276 if (range->type != XPATH_RANGE) 00277 return; 00278 if (range->user2 == NULL) 00279 return; 00280 tmp = xmlXPtrCmpPoints(range->user, range->index, 00281 range->user2, range->index2); 00282 if (tmp == -1) { 00283 tmp2 = range->user; 00284 range->user = range->user2; 00285 range->user2 = tmp2; 00286 tmp = range->index; 00287 range->index = range->index2; 00288 range->index2 = tmp; 00289 } 00290 } 00291 00301 static int 00302 xmlXPtrRangesEqual(xmlXPathObjectPtr range1, xmlXPathObjectPtr range2) { 00303 if (range1 == range2) 00304 return(1); 00305 if ((range1 == NULL) || (range2 == NULL)) 00306 return(0); 00307 if (range1->type != range2->type) 00308 return(0); 00309 if (range1->type != XPATH_RANGE) 00310 return(0); 00311 if (range1->user != range2->user) 00312 return(0); 00313 if (range1->index != range2->index) 00314 return(0); 00315 if (range1->user2 != range2->user2) 00316 return(0); 00317 if (range1->index2 != range2->index2) 00318 return(0); 00319 return(1); 00320 } 00321 00333 xmlXPathObjectPtr 00334 xmlXPtrNewRange(xmlNodePtr start, int startindex, 00335 xmlNodePtr end, int endindex) { 00336 xmlXPathObjectPtr ret; 00337 00338 if (start == NULL) 00339 return(NULL); 00340 if (end == NULL) 00341 return(NULL); 00342 if (startindex < 0) 00343 return(NULL); 00344 if (endindex < 0) 00345 return(NULL); 00346 00347 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 00348 if (ret == NULL) { 00349 xmlXPtrErrMemory("allocating range"); 00350 return(NULL); 00351 } 00352 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 00353 ret->type = XPATH_RANGE; 00354 ret->user = start; 00355 ret->index = startindex; 00356 ret->user2 = end; 00357 ret->index2 = endindex; 00358 xmlXPtrRangeCheckOrder(ret); 00359 return(ret); 00360 } 00361 00371 xmlXPathObjectPtr 00372 xmlXPtrNewRangePoints(xmlXPathObjectPtr start, xmlXPathObjectPtr end) { 00373 xmlXPathObjectPtr ret; 00374 00375 if (start == NULL) 00376 return(NULL); 00377 if (end == NULL) 00378 return(NULL); 00379 if (start->type != XPATH_POINT) 00380 return(NULL); 00381 if (end->type != XPATH_POINT) 00382 return(NULL); 00383 00384 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 00385 if (ret == NULL) { 00386 xmlXPtrErrMemory("allocating range"); 00387 return(NULL); 00388 } 00389 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 00390 ret->type = XPATH_RANGE; 00391 ret->user = start->user; 00392 ret->index = start->index; 00393 ret->user2 = end->user; 00394 ret->index2 = end->index; 00395 xmlXPtrRangeCheckOrder(ret); 00396 return(ret); 00397 } 00398 00408 xmlXPathObjectPtr 00409 xmlXPtrNewRangePointNode(xmlXPathObjectPtr start, xmlNodePtr end) { 00410 xmlXPathObjectPtr ret; 00411 00412 if (start == NULL) 00413 return(NULL); 00414 if (end == NULL) 00415 return(NULL); 00416 if (start->type != XPATH_POINT) 00417 return(NULL); 00418 00419 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 00420 if (ret == NULL) { 00421 xmlXPtrErrMemory("allocating range"); 00422 return(NULL); 00423 } 00424 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 00425 ret->type = XPATH_RANGE; 00426 ret->user = start->user; 00427 ret->index = start->index; 00428 ret->user2 = end; 00429 ret->index2 = -1; 00430 xmlXPtrRangeCheckOrder(ret); 00431 return(ret); 00432 } 00433 00443 xmlXPathObjectPtr 00444 xmlXPtrNewRangeNodePoint(xmlNodePtr start, xmlXPathObjectPtr end) { 00445 xmlXPathObjectPtr ret; 00446 00447 if (start == NULL) 00448 return(NULL); 00449 if (end == NULL) 00450 return(NULL); 00451 if (start->type != XPATH_POINT) 00452 return(NULL); 00453 if (end->type != XPATH_POINT) 00454 return(NULL); 00455 00456 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 00457 if (ret == NULL) { 00458 xmlXPtrErrMemory("allocating range"); 00459 return(NULL); 00460 } 00461 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 00462 ret->type = XPATH_RANGE; 00463 ret->user = start; 00464 ret->index = -1; 00465 ret->user2 = end->user; 00466 ret->index2 = end->index; 00467 xmlXPtrRangeCheckOrder(ret); 00468 return(ret); 00469 } 00470 00480 xmlXPathObjectPtr 00481 xmlXPtrNewRangeNodes(xmlNodePtr start, xmlNodePtr end) { 00482 xmlXPathObjectPtr ret; 00483 00484 if (start == NULL) 00485 return(NULL); 00486 if (end == NULL) 00487 return(NULL); 00488 00489 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 00490 if (ret == NULL) { 00491 xmlXPtrErrMemory("allocating range"); 00492 return(NULL); 00493 } 00494 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 00495 ret->type = XPATH_RANGE; 00496 ret->user = start; 00497 ret->index = -1; 00498 ret->user2 = end; 00499 ret->index2 = -1; 00500 xmlXPtrRangeCheckOrder(ret); 00501 return(ret); 00502 } 00503 00512 xmlXPathObjectPtr 00513 xmlXPtrNewCollapsedRange(xmlNodePtr start) { 00514 xmlXPathObjectPtr ret; 00515 00516 if (start == NULL) 00517 return(NULL); 00518 00519 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 00520 if (ret == NULL) { 00521 xmlXPtrErrMemory("allocating range"); 00522 return(NULL); 00523 } 00524 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 00525 ret->type = XPATH_RANGE; 00526 ret->user = start; 00527 ret->index = -1; 00528 ret->user2 = NULL; 00529 ret->index2 = -1; 00530 return(ret); 00531 } 00532 00542 xmlXPathObjectPtr 00543 xmlXPtrNewRangeNodeObject(xmlNodePtr start, xmlXPathObjectPtr end) { 00544 xmlXPathObjectPtr ret; 00545 00546 if (start == NULL) 00547 return(NULL); 00548 if (end == NULL) 00549 return(NULL); 00550 switch (end->type) { 00551 case XPATH_POINT: 00552 case XPATH_RANGE: 00553 break; 00554 case XPATH_NODESET: 00555 /* 00556 * Empty set ... 00557 */ 00558 if (end->nodesetval->nodeNr <= 0) 00559 return(NULL); 00560 break; 00561 default: 00562 /* TODO */ 00563 return(NULL); 00564 } 00565 00566 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 00567 if (ret == NULL) { 00568 xmlXPtrErrMemory("allocating range"); 00569 return(NULL); 00570 } 00571 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 00572 ret->type = XPATH_RANGE; 00573 ret->user = start; 00574 ret->index = -1; 00575 switch (end->type) { 00576 case XPATH_POINT: 00577 ret->user2 = end->user; 00578 ret->index2 = end->index; 00579 break; 00580 case XPATH_RANGE: 00581 ret->user2 = end->user2; 00582 ret->index2 = end->index2; 00583 break; 00584 case XPATH_NODESET: { 00585 ret->user2 = end->nodesetval->nodeTab[end->nodesetval->nodeNr - 1]; 00586 ret->index2 = -1; 00587 break; 00588 } 00589 default: 00590 STRANGE 00591 return(NULL); 00592 } 00593 xmlXPtrRangeCheckOrder(ret); 00594 return(ret); 00595 } 00596 00597 #define XML_RANGESET_DEFAULT 10 00598 00607 xmlLocationSetPtr 00608 xmlXPtrLocationSetCreate(xmlXPathObjectPtr val) { 00609 xmlLocationSetPtr ret; 00610 00611 ret = (xmlLocationSetPtr) xmlMalloc(sizeof(xmlLocationSet)); 00612 if (ret == NULL) { 00613 xmlXPtrErrMemory("allocating locationset"); 00614 return(NULL); 00615 } 00616 memset(ret, 0 , (size_t) sizeof(xmlLocationSet)); 00617 if (val != NULL) { 00618 ret->locTab = (xmlXPathObjectPtr *) xmlMalloc(XML_RANGESET_DEFAULT * 00619 sizeof(xmlXPathObjectPtr)); 00620 if (ret->locTab == NULL) { 00621 xmlXPtrErrMemory("allocating locationset"); 00622 xmlFree(ret); 00623 return(NULL); 00624 } 00625 memset(ret->locTab, 0 , 00626 XML_RANGESET_DEFAULT * (size_t) sizeof(xmlXPathObjectPtr)); 00627 ret->locMax = XML_RANGESET_DEFAULT; 00628 ret->locTab[ret->locNr++] = val; 00629 } 00630 return(ret); 00631 } 00632 00641 void 00642 xmlXPtrLocationSetAdd(xmlLocationSetPtr cur, xmlXPathObjectPtr val) { 00643 int i; 00644 00645 if ((cur == NULL) || (val == NULL)) return; 00646 00647 /* 00648 * check against doublons 00649 */ 00650 for (i = 0;i < cur->locNr;i++) { 00651 if (xmlXPtrRangesEqual(cur->locTab[i], val)) { 00652 xmlXPathFreeObject(val); 00653 return; 00654 } 00655 } 00656 00657 /* 00658 * grow the locTab if needed 00659 */ 00660 if (cur->locMax == 0) { 00661 cur->locTab = (xmlXPathObjectPtr *) xmlMalloc(XML_RANGESET_DEFAULT * 00662 sizeof(xmlXPathObjectPtr)); 00663 if (cur->locTab == NULL) { 00664 xmlXPtrErrMemory("adding location to set"); 00665 return; 00666 } 00667 memset(cur->locTab, 0 , 00668 XML_RANGESET_DEFAULT * (size_t) sizeof(xmlXPathObjectPtr)); 00669 cur->locMax = XML_RANGESET_DEFAULT; 00670 } else if (cur->locNr == cur->locMax) { 00671 xmlXPathObjectPtr *temp; 00672 00673 cur->locMax *= 2; 00674 temp = (xmlXPathObjectPtr *) xmlRealloc(cur->locTab, cur->locMax * 00675 sizeof(xmlXPathObjectPtr)); 00676 if (temp == NULL) { 00677 xmlXPtrErrMemory("adding location to set"); 00678 return; 00679 } 00680 cur->locTab = temp; 00681 } 00682 cur->locTab[cur->locNr++] = val; 00683 } 00684 00694 xmlLocationSetPtr 00695 xmlXPtrLocationSetMerge(xmlLocationSetPtr val1, xmlLocationSetPtr val2) { 00696 int i; 00697 00698 if (val1 == NULL) return(NULL); 00699 if (val2 == NULL) return(val1); 00700 00701 /* 00702 * !!!!! this can be optimized a lot, knowing that both 00703 * val1 and val2 already have unicity of their values. 00704 */ 00705 00706 for (i = 0;i < val2->locNr;i++) 00707 xmlXPtrLocationSetAdd(val1, val2->locTab[i]); 00708 00709 return(val1); 00710 } 00711 00719 void 00720 xmlXPtrLocationSetDel(xmlLocationSetPtr cur, xmlXPathObjectPtr val) { 00721 int i; 00722 00723 if (cur == NULL) return; 00724 if (val == NULL) return; 00725 00726 /* 00727 * check against doublons 00728 */ 00729 for (i = 0;i < cur->locNr;i++) 00730 if (cur->locTab[i] == val) break; 00731 00732 if (i >= cur->locNr) { 00733 #ifdef DEBUG 00734 xmlGenericError(xmlGenericErrorContext, 00735 "xmlXPtrLocationSetDel: Range wasn't found in RangeList\n"); 00736 #endif 00737 return; 00738 } 00739 cur->locNr--; 00740 for (;i < cur->locNr;i++) 00741 cur->locTab[i] = cur->locTab[i + 1]; 00742 cur->locTab[cur->locNr] = NULL; 00743 } 00744 00752 void 00753 xmlXPtrLocationSetRemove(xmlLocationSetPtr cur, int val) { 00754 if (cur == NULL) return; 00755 if (val >= cur->locNr) return; 00756 cur->locNr--; 00757 for (;val < cur->locNr;val++) 00758 cur->locTab[val] = cur->locTab[val + 1]; 00759 cur->locTab[cur->locNr] = NULL; 00760 } 00761 00768 void 00769 xmlXPtrFreeLocationSet(xmlLocationSetPtr obj) { 00770 int i; 00771 00772 if (obj == NULL) return; 00773 if (obj->locTab != NULL) { 00774 for (i = 0;i < obj->locNr; i++) { 00775 xmlXPathFreeObject(obj->locTab[i]); 00776 } 00777 xmlFree(obj->locTab); 00778 } 00779 xmlFree(obj); 00780 } 00781 00792 xmlXPathObjectPtr 00793 xmlXPtrNewLocationSetNodes(xmlNodePtr start, xmlNodePtr end) { 00794 xmlXPathObjectPtr ret; 00795 00796 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 00797 if (ret == NULL) { 00798 xmlXPtrErrMemory("allocating locationset"); 00799 return(NULL); 00800 } 00801 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 00802 ret->type = XPATH_LOCATIONSET; 00803 if (end == NULL) 00804 ret->user = xmlXPtrLocationSetCreate(xmlXPtrNewCollapsedRange(start)); 00805 else 00806 ret->user = xmlXPtrLocationSetCreate(xmlXPtrNewRangeNodes(start,end)); 00807 return(ret); 00808 } 00809 00819 xmlXPathObjectPtr 00820 xmlXPtrNewLocationSetNodeSet(xmlNodeSetPtr set) { 00821 xmlXPathObjectPtr ret; 00822 00823 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 00824 if (ret == NULL) { 00825 xmlXPtrErrMemory("allocating locationset"); 00826 return(NULL); 00827 } 00828 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 00829 ret->type = XPATH_LOCATIONSET; 00830 if (set != NULL) { 00831 int i; 00832 xmlLocationSetPtr newset; 00833 00834 newset = xmlXPtrLocationSetCreate(NULL); 00835 if (newset == NULL) 00836 return(ret); 00837 00838 for (i = 0;i < set->nodeNr;i++) 00839 xmlXPtrLocationSetAdd(newset, 00840 xmlXPtrNewCollapsedRange(set->nodeTab[i])); 00841 00842 ret->user = (void *) newset; 00843 } 00844 return(ret); 00845 } 00846 00855 xmlXPathObjectPtr 00856 xmlXPtrWrapLocationSet(xmlLocationSetPtr val) { 00857 xmlXPathObjectPtr ret; 00858 00859 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 00860 if (ret == NULL) { 00861 xmlXPtrErrMemory("allocating locationset"); 00862 return(NULL); 00863 } 00864 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 00865 ret->type = XPATH_LOCATIONSET; 00866 ret->user = (void *) val; 00867 return(ret); 00868 } 00869 00870 /************************************************************************ 00871 * * 00872 * The parser * 00873 * * 00874 ************************************************************************/ 00875 00876 static void xmlXPtrEvalChildSeq(xmlXPathParserContextPtr ctxt, xmlChar *name); 00877 00878 /* 00879 * Macros for accessing the content. Those should be used only by the parser, 00880 * and not exported. 00881 * 00882 * Dirty macros, i.e. one need to make assumption on the context to use them 00883 * 00884 * CUR_PTR return the current pointer to the xmlChar to be parsed. 00885 * CUR returns the current xmlChar value, i.e. a 8 bit value 00886 * in ISO-Latin or UTF-8. 00887 * This should be used internally by the parser 00888 * only to compare to ASCII values otherwise it would break when 00889 * running with UTF-8 encoding. 00890 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only 00891 * to compare on ASCII based substring. 00892 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined 00893 * strings within the parser. 00894 * CURRENT Returns the current char value, with the full decoding of 00895 * UTF-8 if we are using this mode. It returns an int. 00896 * NEXT Skip to the next character, this does the proper decoding 00897 * in UTF-8 mode. It also pop-up unfinished entities on the fly. 00898 * It returns the pointer to the current xmlChar. 00899 */ 00900 00901 #define CUR (*ctxt->cur) 00902 #define SKIP(val) ctxt->cur += (val) 00903 #define NXT(val) ctxt->cur[(val)] 00904 #define CUR_PTR ctxt->cur 00905 00906 #define SKIP_BLANKS \ 00907 while (IS_BLANK_CH(*(ctxt->cur))) NEXT 00908 00909 #define CURRENT (*ctxt->cur) 00910 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur) 00911 00912 /* 00913 * xmlXPtrGetChildNo: 00914 * @ctxt: the XPointer Parser context 00915 * @index: the child number 00916 * 00917 * Move the current node of the nodeset on the stack to the 00918 * given child if found 00919 */ 00920 static void 00921 xmlXPtrGetChildNo(xmlXPathParserContextPtr ctxt, int indx) { 00922 xmlNodePtr cur = NULL; 00923 xmlXPathObjectPtr obj; 00924 xmlNodeSetPtr oldset; 00925 00926 CHECK_TYPE(XPATH_NODESET); 00927 obj = valuePop(ctxt); 00928 oldset = obj->nodesetval; 00929 if ((indx <= 0) || (oldset == NULL) || (oldset->nodeNr != 1)) { 00930 xmlXPathFreeObject(obj); 00931 valuePush(ctxt, xmlXPathNewNodeSet(NULL)); 00932 return; 00933 } 00934 cur = xmlXPtrGetNthChild(oldset->nodeTab[0], indx); 00935 if (cur == NULL) { 00936 xmlXPathFreeObject(obj); 00937 valuePush(ctxt, xmlXPathNewNodeSet(NULL)); 00938 return; 00939 } 00940 oldset->nodeTab[0] = cur; 00941 valuePush(ctxt, obj); 00942 } 00943 00978 static void 00979 xmlXPtrEvalXPtrPart(xmlXPathParserContextPtr ctxt, xmlChar *name) { 00980 xmlChar *buffer, *cur; 00981 int len; 00982 int level; 00983 00984 if (name == NULL) 00985 name = xmlXPathParseName(ctxt); 00986 if (name == NULL) 00987 XP_ERROR(XPATH_EXPR_ERROR); 00988 00989 if (CUR != '(') 00990 XP_ERROR(XPATH_EXPR_ERROR); 00991 NEXT; 00992 level = 1; 00993 00994 len = xmlStrlen(ctxt->cur); 00995 len++; 00996 buffer = (xmlChar *) xmlMallocAtomic(len * sizeof (xmlChar)); 00997 if (buffer == NULL) { 00998 xmlXPtrErrMemory("allocating buffer"); 00999 return; 01000 } 01001 01002 cur = buffer; 01003 while (CUR != 0) { 01004 if (CUR == ')') { 01005 level--; 01006 if (level == 0) { 01007 NEXT; 01008 break; 01009 } 01010 *cur++ = CUR; 01011 } else if (CUR == '(') { 01012 level++; 01013 *cur++ = CUR; 01014 } else if (CUR == '^') { 01015 NEXT; 01016 if ((CUR == ')') || (CUR == '(') || (CUR == '^')) { 01017 *cur++ = CUR; 01018 } else { 01019 *cur++ = '^'; 01020 *cur++ = CUR; 01021 } 01022 } else { 01023 *cur++ = CUR; 01024 } 01025 NEXT; 01026 } 01027 *cur = 0; 01028 01029 if ((level != 0) && (CUR == 0)) { 01030 xmlFree(buffer); 01031 XP_ERROR(XPTR_SYNTAX_ERROR); 01032 } 01033 01034 if (xmlStrEqual(name, (xmlChar *) "xpointer")) { 01035 const xmlChar *left = CUR_PTR; 01036 01037 CUR_PTR = buffer; 01038 /* 01039 * To evaluate an xpointer scheme element (4.3) we need: 01040 * context initialized to the root 01041 * context position initalized to 1 01042 * context size initialized to 1 01043 */ 01044 ctxt->context->node = (xmlNodePtr)ctxt->context->doc; 01045 ctxt->context->proximityPosition = 1; 01046 ctxt->context->contextSize = 1; 01047 xmlXPathEvalExpr(ctxt); 01048 CUR_PTR=left; 01049 } else if (xmlStrEqual(name, (xmlChar *) "element")) { 01050 const xmlChar *left = CUR_PTR; 01051 xmlChar *name2; 01052 01053 CUR_PTR = buffer; 01054 if (buffer[0] == '/') { 01055 xmlXPathRoot(ctxt); 01056 xmlXPtrEvalChildSeq(ctxt, NULL); 01057 } else { 01058 name2 = xmlXPathParseName(ctxt); 01059 if (name2 == NULL) { 01060 CUR_PTR = left; 01061 xmlFree(buffer); 01062 XP_ERROR(XPATH_EXPR_ERROR); 01063 } 01064 xmlXPtrEvalChildSeq(ctxt, name2); 01065 } 01066 CUR_PTR = left; 01067 #ifdef XPTR_XMLNS_SCHEME 01068 } else if (xmlStrEqual(name, (xmlChar *) "xmlns")) { 01069 const xmlChar *left = CUR_PTR; 01070 xmlChar *prefix; 01071 xmlChar *URI; 01072 xmlURIPtr value; 01073 01074 CUR_PTR = buffer; 01075 prefix = xmlXPathParseNCName(ctxt); 01076 if (prefix == NULL) { 01077 xmlFree(buffer); 01078 xmlFree(name); 01079 XP_ERROR(XPTR_SYNTAX_ERROR); 01080 } 01081 SKIP_BLANKS; 01082 if (CUR != '=') { 01083 xmlFree(prefix); 01084 xmlFree(buffer); 01085 xmlFree(name); 01086 XP_ERROR(XPTR_SYNTAX_ERROR); 01087 } 01088 NEXT; 01089 SKIP_BLANKS; 01090 /* @@ check escaping in the XPointer WD */ 01091 01092 value = xmlParseURI((const char *)ctxt->cur); 01093 if (value == NULL) { 01094 xmlFree(prefix); 01095 xmlFree(buffer); 01096 xmlFree(name); 01097 XP_ERROR(XPTR_SYNTAX_ERROR); 01098 } 01099 URI = xmlSaveUri(value); 01100 xmlFreeURI(value); 01101 if (URI == NULL) { 01102 xmlFree(prefix); 01103 xmlFree(buffer); 01104 xmlFree(name); 01105 XP_ERROR(XPATH_MEMORY_ERROR); 01106 } 01107 01108 xmlXPathRegisterNs(ctxt->context, prefix, URI); 01109 CUR_PTR = left; 01110 xmlFree(URI); 01111 xmlFree(prefix); 01112 #endif /* XPTR_XMLNS_SCHEME */ 01113 } else { 01114 xmlXPtrErr(ctxt, XML_XPTR_UNKNOWN_SCHEME, 01115 "unsupported scheme '%s'\n", name); 01116 } 01117 xmlFree(buffer); 01118 xmlFree(name); 01119 } 01120 01148 static void 01149 xmlXPtrEvalFullXPtr(xmlXPathParserContextPtr ctxt, xmlChar *name) { 01150 if (name == NULL) 01151 name = xmlXPathParseName(ctxt); 01152 if (name == NULL) 01153 XP_ERROR(XPATH_EXPR_ERROR); 01154 while (name != NULL) { 01155 ctxt->error = XPATH_EXPRESSION_OK; 01156 xmlXPtrEvalXPtrPart(ctxt, name); 01157 01158 /* in case of syntax error, break here */ 01159 if ((ctxt->error != XPATH_EXPRESSION_OK) && 01160 (ctxt->error != XML_XPTR_UNKNOWN_SCHEME)) 01161 return; 01162 01163 /* 01164 * If the returned value is a non-empty nodeset 01165 * or location set, return here. 01166 */ 01167 if (ctxt->value != NULL) { 01168 xmlXPathObjectPtr obj = ctxt->value; 01169 01170 switch (obj->type) { 01171 case XPATH_LOCATIONSET: { 01172 xmlLocationSetPtr loc = ctxt->value->user; 01173 if ((loc != NULL) && (loc->locNr > 0)) 01174 return; 01175 break; 01176 } 01177 case XPATH_NODESET: { 01178 xmlNodeSetPtr loc = ctxt->value->nodesetval; 01179 if ((loc != NULL) && (loc->nodeNr > 0)) 01180 return; 01181 break; 01182 } 01183 default: 01184 break; 01185 } 01186 01187 /* 01188 * Evaluating to improper values is equivalent to 01189 * a sub-resource error, clean-up the stack 01190 */ 01191 do { 01192 obj = valuePop(ctxt); 01193 if (obj != NULL) { 01194 xmlXPathFreeObject(obj); 01195 } 01196 } while (obj != NULL); 01197 } 01198 01199 /* 01200 * Is there another XPointer part. 01201 */ 01202 SKIP_BLANKS; 01203 name = xmlXPathParseName(ctxt); 01204 } 01205 } 01206 01218 static void 01219 xmlXPtrEvalChildSeq(xmlXPathParserContextPtr ctxt, xmlChar *name) { 01220 /* 01221 * XPointer don't allow by syntax to address in mutirooted trees 01222 * this might prove useful in some cases, warn about it. 01223 */ 01224 if ((name == NULL) && (CUR == '/') && (NXT(1) != '1')) { 01225 xmlXPtrErr(ctxt, XML_XPTR_CHILDSEQ_START, 01226 "warning: ChildSeq not starting by /1\n", NULL); 01227 } 01228 01229 if (name != NULL) { 01230 valuePush(ctxt, xmlXPathNewString(name)); 01231 xmlFree(name); 01232 xmlXPathIdFunction(ctxt, 1); 01233 CHECK_ERROR; 01234 } 01235 01236 while (CUR == '/') { 01237 int child = 0; 01238 NEXT; 01239 01240 while ((CUR >= '0') && (CUR <= '9')) { 01241 child = child * 10 + (CUR - '0'); 01242 NEXT; 01243 } 01244 xmlXPtrGetChildNo(ctxt, child); 01245 } 01246 } 01247 01248 01259 static void 01260 xmlXPtrEvalXPointer(xmlXPathParserContextPtr ctxt) { 01261 if (ctxt->valueTab == NULL) { 01262 /* Allocate the value stack */ 01263 ctxt->valueTab = (xmlXPathObjectPtr *) 01264 xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); 01265 if (ctxt->valueTab == NULL) { 01266 xmlXPtrErrMemory("allocating evaluation context"); 01267 return; 01268 } 01269 ctxt->valueNr = 0; 01270 ctxt->valueMax = 10; 01271 ctxt->value = NULL; 01272 } 01273 SKIP_BLANKS; 01274 if (CUR == '/') { 01275 xmlXPathRoot(ctxt); 01276 xmlXPtrEvalChildSeq(ctxt, NULL); 01277 } else { 01278 xmlChar *name; 01279 01280 name = xmlXPathParseName(ctxt); 01281 if (name == NULL) 01282 XP_ERROR(XPATH_EXPR_ERROR); 01283 if (CUR == '(') { 01284 xmlXPtrEvalFullXPtr(ctxt, name); 01285 /* Short evaluation */ 01286 return; 01287 } else { 01288 /* this handle both Bare Names and Child Sequences */ 01289 xmlXPtrEvalChildSeq(ctxt, name); 01290 } 01291 } 01292 SKIP_BLANKS; 01293 if (CUR != 0) 01294 XP_ERROR(XPATH_EXPR_ERROR); 01295 } 01296 01297 01298 /************************************************************************ 01299 * * 01300 * General routines * 01301 * * 01302 ************************************************************************/ 01303 01304 static 01305 void xmlXPtrStringRangeFunction(xmlXPathParserContextPtr ctxt, int nargs); 01306 static 01307 void xmlXPtrStartPointFunction(xmlXPathParserContextPtr ctxt, int nargs); 01308 static 01309 void xmlXPtrEndPointFunction(xmlXPathParserContextPtr ctxt, int nargs); 01310 static 01311 void xmlXPtrHereFunction(xmlXPathParserContextPtr ctxt, int nargs); 01312 static 01313 void xmlXPtrOriginFunction(xmlXPathParserContextPtr ctxt, int nargs); 01314 static 01315 void xmlXPtrRangeInsideFunction(xmlXPathParserContextPtr ctxt, int nargs); 01316 static 01317 void xmlXPtrRangeFunction(xmlXPathParserContextPtr ctxt, int nargs); 01318 01330 xmlXPathContextPtr 01331 xmlXPtrNewContext(xmlDocPtr doc, xmlNodePtr here, xmlNodePtr origin) { 01332 xmlXPathContextPtr ret; 01333 01334 ret = xmlXPathNewContext(doc); 01335 if (ret == NULL) 01336 return(ret); 01337 ret->xptr = 1; 01338 ret->here = here; 01339 ret->origin = origin; 01340 01341 xmlXPathRegisterFunc(ret, (xmlChar *)"range-to", 01342 xmlXPtrRangeToFunction); 01343 xmlXPathRegisterFunc(ret, (xmlChar *)"range", 01344 xmlXPtrRangeFunction); 01345 xmlXPathRegisterFunc(ret, (xmlChar *)"range-inside", 01346 xmlXPtrRangeInsideFunction); 01347 xmlXPathRegisterFunc(ret, (xmlChar *)"string-range", 01348 xmlXPtrStringRangeFunction); 01349 xmlXPathRegisterFunc(ret, (xmlChar *)"start-point", 01350 xmlXPtrStartPointFunction); 01351 xmlXPathRegisterFunc(ret, (xmlChar *)"end-point", 01352 xmlXPtrEndPointFunction); 01353 xmlXPathRegisterFunc(ret, (xmlChar *)"here", 01354 xmlXPtrHereFunction); 01355 xmlXPathRegisterFunc(ret, (xmlChar *)" origin", 01356 xmlXPtrOriginFunction); 01357 01358 return(ret); 01359 } 01360 01371 xmlXPathObjectPtr 01372 xmlXPtrEval(const xmlChar *str, xmlXPathContextPtr ctx) { 01373 xmlXPathParserContextPtr ctxt; 01374 xmlXPathObjectPtr res = NULL, tmp; 01375 xmlXPathObjectPtr init = NULL; 01376 int stack = 0; 01377 01378 xmlXPathInit(); 01379 01380 if ((ctx == NULL) || (str == NULL)) 01381 return(NULL); 01382 01383 ctxt = xmlXPathNewParserContext(str, ctx); 01384 ctxt->xptr = 1; 01385 xmlXPtrEvalXPointer(ctxt); 01386 01387 if ((ctxt->value != NULL) && 01388 (ctxt->value->type != XPATH_NODESET) && 01389 (ctxt->value->type != XPATH_LOCATIONSET)) { 01390 xmlXPtrErr(ctxt, XML_XPTR_EVAL_FAILED, 01391 "xmlXPtrEval: evaluation failed to return a node set\n", 01392 NULL); 01393 } else { 01394 res = valuePop(ctxt); 01395 } 01396 01397 do { 01398 tmp = valuePop(ctxt); 01399 if (tmp != NULL) { 01400 if (tmp != init) { 01401 if (tmp->type == XPATH_NODESET) { 01402 /* 01403 * Evaluation may push a root nodeset which is unused 01404 */ 01405 xmlNodeSetPtr set; 01406 set = tmp->nodesetval; 01407 if ((set->nodeNr != 1) || 01408 (set->nodeTab[0] != (xmlNodePtr) ctx->doc)) 01409 stack++; 01410 } else 01411 stack++; 01412 } 01413 xmlXPathFreeObject(tmp); 01414 } 01415 } while (tmp != NULL); 01416 if (stack != 0) { 01417 xmlXPtrErr(ctxt, XML_XPTR_EXTRA_OBJECTS, 01418 "xmlXPtrEval: object(s) left on the eval stack\n", 01419 NULL); 01420 } 01421 if (ctxt->error != XPATH_EXPRESSION_OK) { 01422 xmlXPathFreeObject(res); 01423 res = NULL; 01424 } 01425 01426 xmlXPathFreeParserContext(ctxt); 01427 return(res); 01428 } 01429 01439 static xmlNodePtr 01440 xmlXPtrBuildRangeNodeList(xmlXPathObjectPtr range) { 01441 /* pointers to generated nodes */ 01442 xmlNodePtr list = NULL, last = NULL, parent = NULL, tmp; 01443 /* pointers to traversal nodes */ 01444 xmlNodePtr start, cur, end; 01445 int index1, index2; 01446 01447 if (range == NULL) 01448 return(NULL); 01449 if (range->type != XPATH_RANGE) 01450 return(NULL); 01451 start = (xmlNodePtr) range->user; 01452 01453 if (start == NULL) 01454 return(NULL); 01455 end = range->user2; 01456 if (end == NULL) 01457 return(xmlCopyNode(start, 1)); 01458 01459 cur = start; 01460 index1 = range->index; 01461 index2 = range->index2; 01462 while (cur != NULL) { 01463 if (cur == end) { 01464 if (cur->type == XML_TEXT_NODE) { 01465 const xmlChar *content = cur->content; 01466 int len; 01467 01468 if (content == NULL) { 01469 tmp = xmlNewTextLen(NULL, 0); 01470 } else { 01471 len = index2; 01472 if ((cur == start) && (index1 > 1)) { 01473 content += (index1 - 1); 01474 len -= (index1 - 1); 01475 index1 = 0; 01476 } else { 01477 len = index2; 01478 } 01479 tmp = xmlNewTextLen(content, len); 01480 } 01481 /* single sub text node selection */ 01482 if (list == NULL) 01483 return(tmp); 01484 /* prune and return full set */ 01485 if (last != NULL) 01486 xmlAddNextSibling(last, tmp); 01487 else 01488 xmlAddChild(parent, tmp); 01489 return(list); 01490 } else { 01491 tmp = xmlCopyNode(cur, 0); 01492 if (list == NULL) 01493 list = tmp; 01494 else { 01495 if (last != NULL) 01496 xmlAddNextSibling(last, tmp); 01497 else 01498 xmlAddChild(parent, tmp); 01499 } 01500 last = NULL; 01501 parent = tmp; 01502 01503 if (index2 > 1) { 01504 end = xmlXPtrGetNthChild(cur, index2 - 1); 01505 index2 = 0; 01506 } 01507 if ((cur == start) && (index1 > 1)) { 01508 cur = xmlXPtrGetNthChild(cur, index1 - 1); 01509 index1 = 0; 01510 } else { 01511 cur = cur->children; 01512 } 01513 /* 01514 * Now gather the remaining nodes from cur to end 01515 */ 01516 continue; /* while */ 01517 } 01518 } else if ((cur == start) && 01519 (list == NULL) /* looks superfluous but ... */ ) { 01520 if ((cur->type == XML_TEXT_NODE) || 01521 (cur->type == XML_CDATA_SECTION_NODE)) { 01522 const xmlChar *content = cur->content; 01523 01524 if (content == NULL) { 01525 tmp = xmlNewTextLen(NULL, 0); 01526 } else { 01527 if (index1 > 1) { 01528 content += (index1 - 1); 01529 } 01530 tmp = xmlNewText(content); 01531 } 01532 last = list = tmp; 01533 } else { 01534 if ((cur == start) && (index1 > 1)) { 01535 tmp = xmlCopyNode(cur, 0); 01536 list = tmp; 01537 parent = tmp; 01538 last = NULL; 01539 cur = xmlXPtrGetNthChild(cur, index1 - 1); 01540 index1 = 0; 01541 /* 01542 * Now gather the remaining nodes from cur to end 01543 */ 01544 continue; /* while */ 01545 } 01546 tmp = xmlCopyNode(cur, 1); 01547 list = tmp; 01548 parent = NULL; 01549 last = tmp; 01550 } 01551 } else { 01552 tmp = NULL; 01553 switch (cur->type) { 01554 case XML_DTD_NODE: 01555 case XML_ELEMENT_DECL: 01556 case XML_ATTRIBUTE_DECL: 01557 case XML_ENTITY_NODE: 01558 /* Do not copy DTD informations */ 01559 break; 01560 case XML_ENTITY_DECL: 01561 TODO /* handle crossing entities -> stack needed */ 01562 break; 01563 case XML_XINCLUDE_START: 01564 case XML_XINCLUDE_END: 01565 /* don't consider it part of the tree content */ 01566 break; 01567 case XML_ATTRIBUTE_NODE: 01568 /* Humm, should not happen ! */ 01569 STRANGE 01570 break; 01571 default: 01572 tmp = xmlCopyNode(cur, 1); 01573 break; 01574 } 01575 if (tmp != NULL) { 01576 if ((list == NULL) || ((last == NULL) && (parent == NULL))) { 01577 STRANGE 01578 return(NULL); 01579 } 01580 if (last != NULL) 01581 xmlAddNextSibling(last, tmp); 01582 else { 01583 xmlAddChild(parent, tmp); 01584 last = tmp; 01585 } 01586 } 01587 } 01588 /* 01589 * Skip to next node in document order 01590 */ 01591 if ((list == NULL) || ((last == NULL) && (parent == NULL))) { 01592 STRANGE 01593 return(NULL); 01594 } 01595 cur = xmlXPtrAdvanceNode(cur, NULL); 01596 } 01597 return(list); 01598 } 01599 01610 xmlNodePtr 01611 xmlXPtrBuildNodeList(xmlXPathObjectPtr obj) { 01612 xmlNodePtr list = NULL, last = NULL; 01613 int i; 01614 01615 if (obj == NULL) 01616 return(NULL); 01617 switch (obj->type) { 01618 case XPATH_NODESET: { 01619 xmlNodeSetPtr set = obj->nodesetval; 01620 if (set == NULL) 01621 return(NULL); 01622 for (i = 0;i < set->nodeNr;i++) { 01623 if (set->nodeTab[i] == NULL) 01624 continue; 01625 switch (set->nodeTab[i]->type) { 01626 case XML_TEXT_NODE: 01627 case XML_CDATA_SECTION_NODE: 01628 case XML_ELEMENT_NODE: 01629 case XML_ENTITY_REF_NODE: 01630 case XML_ENTITY_NODE: 01631 case XML_PI_NODE: 01632 case XML_COMMENT_NODE: 01633 case XML_DOCUMENT_NODE: 01634 case XML_HTML_DOCUMENT_NODE: 01635 #ifdef LIBXML_DOCB_ENABLED 01636 case XML_DOCB_DOCUMENT_NODE: 01637 #endif 01638 case XML_XINCLUDE_START: 01639 case XML_XINCLUDE_END: 01640 break; 01641 case XML_ATTRIBUTE_NODE: 01642 case XML_NAMESPACE_DECL: 01643 case XML_DOCUMENT_TYPE_NODE: 01644 case XML_DOCUMENT_FRAG_NODE: 01645 case XML_NOTATION_NODE: 01646 case XML_DTD_NODE: 01647 case XML_ELEMENT_DECL: 01648 case XML_ATTRIBUTE_DECL: 01649 case XML_ENTITY_DECL: 01650 continue; /* for */ 01651 } 01652 if (last == NULL) 01653 list = last = xmlCopyNode(set->nodeTab[i], 1); 01654 else { 01655 xmlAddNextSibling(last, xmlCopyNode(set->nodeTab[i], 1)); 01656 if (last->next != NULL) 01657 last = last->next; 01658 } 01659 } 01660 break; 01661 } 01662 case XPATH_LOCATIONSET: { 01663 xmlLocationSetPtr set = (xmlLocationSetPtr) obj->user; 01664 if (set == NULL) 01665 return(NULL); 01666 for (i = 0;i < set->locNr;i++) { 01667 if (last == NULL) 01668 list = last = xmlXPtrBuildNodeList(set->locTab[i]); 01669 else 01670 xmlAddNextSibling(last, 01671 xmlXPtrBuildNodeList(set->locTab[i])); 01672 if (last != NULL) { 01673 while (last->next != NULL) 01674 last = last->next; 01675 } 01676 } 01677 break; 01678 } 01679 case XPATH_RANGE: 01680 return(xmlXPtrBuildRangeNodeList(obj)); 01681 case XPATH_POINT: 01682 return(xmlCopyNode(obj->user, 0)); 01683 default: 01684 break; 01685 } 01686 return(list); 01687 } 01688 01689 /************************************************************************ 01690 * * 01691 * XPointer functions * 01692 * * 01693 ************************************************************************/ 01694 01704 static int 01705 xmlXPtrNbLocChildren(xmlNodePtr node) { 01706 int ret = 0; 01707 if (node == NULL) 01708 return(-1); 01709 switch (node->type) { 01710 case XML_HTML_DOCUMENT_NODE: 01711 case XML_DOCUMENT_NODE: 01712 case XML_ELEMENT_NODE: 01713 node = node->children; 01714 while (node != NULL) { 01715 if (node->type == XML_ELEMENT_NODE) 01716 ret++; 01717 node = node->next; 01718 } 01719 break; 01720 case XML_ATTRIBUTE_NODE: 01721 return(-1); 01722 01723 case XML_PI_NODE: 01724 case XML_COMMENT_NODE: 01725 case XML_TEXT_NODE: 01726 case XML_CDATA_SECTION_NODE: 01727 case XML_ENTITY_REF_NODE: 01728 ret = xmlStrlen(node->content); 01729 break; 01730 default: 01731 return(-1); 01732 } 01733 return(ret); 01734 } 01735 01744 static void 01745 xmlXPtrHereFunction(xmlXPathParserContextPtr ctxt, int nargs) { 01746 CHECK_ARITY(0); 01747 01748 if (ctxt->context->here == NULL) 01749 XP_ERROR(XPTR_SYNTAX_ERROR); 01750 01751 valuePush(ctxt, xmlXPtrNewLocationSetNodes(ctxt->context->here, NULL)); 01752 } 01753 01762 static void 01763 xmlXPtrOriginFunction(xmlXPathParserContextPtr ctxt, int nargs) { 01764 CHECK_ARITY(0); 01765 01766 if (ctxt->context->origin == NULL) 01767 XP_ERROR(XPTR_SYNTAX_ERROR); 01768 01769 valuePush(ctxt, xmlXPtrNewLocationSetNodes(ctxt->context->origin, NULL)); 01770 } 01771 01795 static void 01796 xmlXPtrStartPointFunction(xmlXPathParserContextPtr ctxt, int nargs) { 01797 xmlXPathObjectPtr tmp, obj, point; 01798 xmlLocationSetPtr newset = NULL; 01799 xmlLocationSetPtr oldset = NULL; 01800 01801 CHECK_ARITY(1); 01802 if ((ctxt->value == NULL) || 01803 ((ctxt->value->type != XPATH_LOCATIONSET) && 01804 (ctxt->value->type != XPATH_NODESET))) 01805 XP_ERROR(XPATH_INVALID_TYPE) 01806 01807 obj = valuePop(ctxt); 01808 if (obj->type == XPATH_NODESET) { 01809 /* 01810 * First convert to a location set 01811 */ 01812 tmp = xmlXPtrNewLocationSetNodeSet(obj->nodesetval); 01813 xmlXPathFreeObject(obj); 01814 obj = tmp; 01815 } 01816 01817 newset = xmlXPtrLocationSetCreate(NULL); 01818 if (newset == NULL) { 01819 xmlXPathFreeObject(obj); 01820 XP_ERROR(XPATH_MEMORY_ERROR); 01821 } 01822 oldset = (xmlLocationSetPtr) obj->user; 01823 if (oldset != NULL) { 01824 int i; 01825 01826 for (i = 0; i < oldset->locNr; i++) { 01827 tmp = oldset->locTab[i]; 01828 if (tmp == NULL) 01829 continue; 01830 point = NULL; 01831 switch (tmp->type) { 01832 case XPATH_POINT: 01833 point = xmlXPtrNewPoint(tmp->user, tmp->index); 01834 break; 01835 case XPATH_RANGE: { 01836 xmlNodePtr node = tmp->user; 01837 if (node != NULL) { 01838 if (node->type == XML_ATTRIBUTE_NODE) { 01839 /* TODO: Namespace Nodes ??? */ 01840 xmlXPathFreeObject(obj); 01841 xmlXPtrFreeLocationSet(newset); 01842 XP_ERROR(XPTR_SYNTAX_ERROR); 01843 } 01844 point = xmlXPtrNewPoint(node, tmp->index); 01845 } 01846 break; 01847 } 01848 default: 01849 /*** Should we raise an error ? 01850 xmlXPathFreeObject(obj); 01851 xmlXPathFreeObject(newset); 01852 XP_ERROR(XPATH_INVALID_TYPE) 01853 ***/ 01854 break; 01855 } 01856 if (point != NULL) 01857 xmlXPtrLocationSetAdd(newset, point); 01858 } 01859 } 01860 xmlXPathFreeObject(obj); 01861 valuePush(ctxt, xmlXPtrWrapLocationSet(newset)); 01862 } 01863 01889 static void 01890 xmlXPtrEndPointFunction(xmlXPathParserContextPtr ctxt, int nargs) { 01891 xmlXPathObjectPtr tmp, obj, point; 01892 xmlLocationSetPtr newset = NULL; 01893 xmlLocationSetPtr oldset = NULL; 01894 01895 CHECK_ARITY(1); 01896 if ((ctxt->value == NULL) || 01897 ((ctxt->value->type != XPATH_LOCATIONSET) && 01898 (ctxt->value->type != XPATH_NODESET))) 01899 XP_ERROR(XPATH_INVALID_TYPE) 01900 01901 obj = valuePop(ctxt); 01902 if (obj->type == XPATH_NODESET) { 01903 /* 01904 * First convert to a location set 01905 */ 01906 tmp = xmlXPtrNewLocationSetNodeSet(obj->nodesetval); 01907 xmlXPathFreeObject(obj); 01908 obj = tmp; 01909 } 01910 01911 newset = xmlXPtrLocationSetCreate(NULL); 01912 oldset = (xmlLocationSetPtr) obj->user; 01913 if (oldset != NULL) { 01914 int i; 01915 01916 for (i = 0; i < oldset->locNr; i++) { 01917 tmp = oldset->locTab[i]; 01918 if (tmp == NULL) 01919 continue; 01920 point = NULL; 01921 switch (tmp->type) { 01922 case XPATH_POINT: 01923 point = xmlXPtrNewPoint(tmp->user, tmp->index); 01924 break; 01925 case XPATH_RANGE: { 01926 xmlNodePtr node = tmp->user2; 01927 if (node != NULL) { 01928 if (node->type == XML_ATTRIBUTE_NODE) { 01929 /* TODO: Namespace Nodes ??? */ 01930 xmlXPathFreeObject(obj); 01931 xmlXPtrFreeLocationSet(newset); 01932 XP_ERROR(XPTR_SYNTAX_ERROR); 01933 } 01934 point = xmlXPtrNewPoint(node, tmp->index2); 01935 } else if (tmp->user == NULL) { 01936 point = xmlXPtrNewPoint(node, 01937 xmlXPtrNbLocChildren(node)); 01938 } 01939 break; 01940 } 01941 default: 01942 /*** Should we raise an error ? 01943 xmlXPathFreeObject(obj); 01944 xmlXPathFreeObject(newset); 01945 XP_ERROR(XPATH_INVALID_TYPE) 01946 ***/ 01947 break; 01948 } 01949 if (point != NULL) 01950 xmlXPtrLocationSetAdd(newset, point); 01951 } 01952 } 01953 xmlXPathFreeObject(obj); 01954 valuePush(ctxt, xmlXPtrWrapLocationSet(newset)); 01955 } 01956 01957 01969 static xmlXPathObjectPtr 01970 xmlXPtrCoveringRange(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr loc) { 01971 if (loc == NULL) 01972 return(NULL); 01973 if ((ctxt == NULL) || (ctxt->context == NULL) || 01974 (ctxt->context->doc == NULL)) 01975 return(NULL); 01976 switch (loc->type) { 01977 case XPATH_POINT: 01978 return(xmlXPtrNewRange(loc->user, loc->index, 01979 loc->user, loc->index)); 01980 case XPATH_RANGE: 01981 if (loc->user2 != NULL) { 01982 return(xmlXPtrNewRange(loc->user, loc->index, 01983 loc->user2, loc->index2)); 01984 } else { 01985 xmlNodePtr node = (xmlNodePtr) loc->user; 01986 if (node == (xmlNodePtr) ctxt->context->doc) { 01987 return(xmlXPtrNewRange(node, 0, node, 01988 xmlXPtrGetArity(node))); 01989 } else { 01990 switch (node->type) { 01991 case XML_ATTRIBUTE_NODE: 01992 /* !!! our model is slightly different than XPath */ 01993 return(xmlXPtrNewRange(node, 0, node, 01994 xmlXPtrGetArity(node))); 01995 case XML_ELEMENT_NODE: 01996 case XML_TEXT_NODE: 01997 case XML_CDATA_SECTION_NODE: 01998 case XML_ENTITY_REF_NODE: 01999 case XML_PI_NODE: 02000 case XML_COMMENT_NODE: 02001 case XML_DOCUMENT_NODE: 02002 case XML_NOTATION_NODE: 02003 case XML_HTML_DOCUMENT_NODE: { 02004 int indx = xmlXPtrGetIndex(node); 02005 02006 node = node->parent; 02007 return(xmlXPtrNewRange(node, indx - 1, 02008 node, indx + 1)); 02009 } 02010 default: 02011 return(NULL); 02012 } 02013 } 02014 } 02015 default: 02016 TODO /* missed one case ??? */ 02017 } 02018 return(NULL); 02019 } 02020 02034 static void 02035 xmlXPtrRangeFunction(xmlXPathParserContextPtr ctxt, int nargs) { 02036 int i; 02037 xmlXPathObjectPtr set; 02038 xmlLocationSetPtr oldset; 02039 xmlLocationSetPtr newset; 02040 02041 CHECK_ARITY(1); 02042 if ((ctxt->value == NULL) || 02043 ((ctxt->value->type != XPATH_LOCATIONSET) && 02044 (ctxt->value->type != XPATH_NODESET))) 02045 XP_ERROR(XPATH_INVALID_TYPE) 02046 02047 set = valuePop(ctxt); 02048 if (set->type == XPATH_NODESET) { 02049 xmlXPathObjectPtr tmp; 02050 02051 /* 02052 * First convert to a location set 02053 */ 02054 tmp = xmlXPtrNewLocationSetNodeSet(set->nodesetval); 02055 xmlXPathFreeObject(set); 02056 set = tmp; 02057 } 02058 oldset = (xmlLocationSetPtr) set->user; 02059 02060 /* 02061 * The loop is to compute the covering range for each item and add it 02062 */ 02063 newset = xmlXPtrLocationSetCreate(NULL); 02064 for (i = 0;i < oldset->locNr;i++) { 02065 xmlXPtrLocationSetAdd(newset, 02066 xmlXPtrCoveringRange(ctxt, oldset->locTab[i])); 02067 } 02068 02069 /* 02070 * Save the new value and cleanup 02071 */ 02072 valuePush(ctxt, xmlXPtrWrapLocationSet(newset)); 02073 xmlXPathFreeObject(set); 02074 } 02075 02085 static xmlXPathObjectPtr 02086 xmlXPtrInsideRange(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr loc) { 02087 if (loc == NULL) 02088 return(NULL); 02089 if ((ctxt == NULL) || (ctxt->context == NULL) || 02090 (ctxt->context->doc == NULL)) 02091 return(NULL); 02092 switch (loc->type) { 02093 case XPATH_POINT: { 02094 xmlNodePtr node = (xmlNodePtr) loc->user; 02095 switch (node->type) { 02096 case XML_PI_NODE: 02097 case XML_COMMENT_NODE: 02098 case XML_TEXT_NODE: 02099 case XML_CDATA_SECTION_NODE: { 02100 if (node->content == NULL) { 02101 return(xmlXPtrNewRange(node, 0, node, 0)); 02102 } else { 02103 return(xmlXPtrNewRange(node, 0, node, 02104 xmlStrlen(node->content))); 02105 } 02106 } 02107 case XML_ATTRIBUTE_NODE: 02108 case XML_ELEMENT_NODE: 02109 case XML_ENTITY_REF_NODE: 02110 case XML_DOCUMENT_NODE: 02111 case XML_NOTATION_NODE: 02112 case XML_HTML_DOCUMENT_NODE: { 02113 return(xmlXPtrNewRange(node, 0, node, 02114 xmlXPtrGetArity(node))); 02115 } 02116 default: 02117 break; 02118 } 02119 return(NULL); 02120 } 02121 case XPATH_RANGE: { 02122 xmlNodePtr node = (xmlNodePtr) loc->user; 02123 if (loc->user2 != NULL) { 02124 return(xmlXPtrNewRange(node, loc->index, 02125 loc->user2, loc->index2)); 02126 } else { 02127 switch (node->type) { 02128 case XML_PI_NODE: 02129 case XML_COMMENT_NODE: 02130 case XML_TEXT_NODE: 02131 case XML_CDATA_SECTION_NODE: { 02132 if (node->content == NULL) { 02133 return(xmlXPtrNewRange(node, 0, node, 0)); 02134 } else { 02135 return(xmlXPtrNewRange(node, 0, node, 02136 xmlStrlen(node->content))); 02137 } 02138 } 02139 case XML_ATTRIBUTE_NODE: 02140 case XML_ELEMENT_NODE: 02141 case XML_ENTITY_REF_NODE: 02142 case XML_DOCUMENT_NODE: 02143 case XML_NOTATION_NODE: 02144 case XML_HTML_DOCUMENT_NODE: { 02145 return(xmlXPtrNewRange(node, 0, node, 02146 xmlXPtrGetArity(node))); 02147 } 02148 default: 02149 break; 02150 } 02151 return(NULL); 02152 } 02153 } 02154 default: 02155 TODO /* missed one case ??? */ 02156 } 02157 return(NULL); 02158 } 02159 02180 static void 02181 xmlXPtrRangeInsideFunction(xmlXPathParserContextPtr ctxt, int nargs) { 02182 int i; 02183 xmlXPathObjectPtr set; 02184 xmlLocationSetPtr oldset; 02185 xmlLocationSetPtr newset; 02186 02187 CHECK_ARITY(1); 02188 if ((ctxt->value == NULL) || 02189 ((ctxt->value->type != XPATH_LOCATIONSET) && 02190 (ctxt->value->type != XPATH_NODESET))) 02191 XP_ERROR(XPATH_INVALID_TYPE) 02192 02193 set = valuePop(ctxt); 02194 if (set->type == XPATH_NODESET) { 02195 xmlXPathObjectPtr tmp; 02196 02197 /* 02198 * First convert to a location set 02199 */ 02200 tmp = xmlXPtrNewLocationSetNodeSet(set->nodesetval); 02201 xmlXPathFreeObject(set); 02202 set = tmp; 02203 } 02204 oldset = (xmlLocationSetPtr) set->user; 02205 02206 /* 02207 * The loop is to compute the covering range for each item and add it 02208 */ 02209 newset = xmlXPtrLocationSetCreate(NULL); 02210 for (i = 0;i < oldset->locNr;i++) { 02211 xmlXPtrLocationSetAdd(newset, 02212 xmlXPtrInsideRange(ctxt, oldset->locTab[i])); 02213 } 02214 02215 /* 02216 * Save the new value and cleanup 02217 */ 02218 valuePush(ctxt, xmlXPtrWrapLocationSet(newset)); 02219 xmlXPathFreeObject(set); 02220 } 02221 02229 void 02230 xmlXPtrRangeToFunction(xmlXPathParserContextPtr ctxt, int nargs) { 02231 xmlXPathObjectPtr range; 02232 const xmlChar *cur; 02233 xmlXPathObjectPtr res, obj; 02234 xmlXPathObjectPtr tmp; 02235 xmlLocationSetPtr newset = NULL; 02236 xmlNodeSetPtr oldset; 02237 int i; 02238 02239 if (ctxt == NULL) return; 02240 CHECK_ARITY(1); 02241 /* 02242 * Save the expression pointer since we will have to evaluate 02243 * it multiple times. Initialize the new set. 02244 */ 02245 CHECK_TYPE(XPATH_NODESET); 02246 obj = valuePop(ctxt); 02247 oldset = obj->nodesetval; 02248 ctxt->context->node = NULL; 02249 02250 cur = ctxt->cur; 02251 newset = xmlXPtrLocationSetCreate(NULL); 02252 02253 for (i = 0; i < oldset->nodeNr; i++) { 02254 ctxt->cur = cur; 02255 02256 /* 02257 * Run the evaluation with a node list made of a single item 02258 * in the nodeset. 02259 */ 02260 ctxt->context->node = oldset->nodeTab[i]; 02261 tmp = xmlXPathNewNodeSet(ctxt->context->node); 02262 valuePush(ctxt, tmp); 02263 02264 xmlXPathEvalExpr(ctxt); 02265 CHECK_ERROR; 02266 02267 /* 02268 * The result of the evaluation need to be tested to 02269 * decided whether the filter succeeded or not 02270 */ 02271 res = valuePop(ctxt); 02272 range = xmlXPtrNewRangeNodeObject(oldset->nodeTab[i], res); 02273 if (range != NULL) { 02274 xmlXPtrLocationSetAdd(newset, range); 02275 } 02276 02277 /* 02278 * Cleanup 02279 */ 02280 if (res != NULL) 02281 xmlXPathFreeObject(res); 02282 if (ctxt->value == tmp) { 02283 res = valuePop(ctxt); 02284 xmlXPathFreeObject(res); 02285 } 02286 02287 ctxt->context->node = NULL; 02288 } 02289 02290 /* 02291 * The result is used as the new evaluation set. 02292 */ 02293 xmlXPathFreeObject(obj); 02294 ctxt->context->node = NULL; 02295 ctxt->context->contextSize = -1; 02296 ctxt->context->proximityPosition = -1; 02297 valuePush(ctxt, xmlXPtrWrapLocationSet(newset)); 02298 } 02299 02310 xmlNodePtr 02311 xmlXPtrAdvanceNode(xmlNodePtr cur, int *level) { 02312 next: 02313 if (cur == NULL) 02314 return(NULL); 02315 if (cur->children != NULL) { 02316 cur = cur->children ; 02317 if (level != NULL) 02318 (*level)++; 02319 goto found; 02320 } 02321 skip: /* This label should only be needed if something is wrong! */ 02322 if (cur->next != NULL) { 02323 cur = cur->next; 02324 goto found; 02325 } 02326 do { 02327 cur = cur->parent; 02328 if (level != NULL) 02329 (*level)--; 02330 if (cur == NULL) return(NULL); 02331 if (cur->next != NULL) { 02332 cur = cur->next; 02333 goto found; 02334 } 02335 } while (cur != NULL); 02336 02337 found: 02338 if ((cur->type != XML_ELEMENT_NODE) && 02339 (cur->type != XML_TEXT_NODE) && 02340 (cur->type != XML_DOCUMENT_NODE) && 02341 (cur->type != XML_HTML_DOCUMENT_NODE) && 02342 (cur->type != XML_CDATA_SECTION_NODE)) { 02343 if (cur->type == XML_ENTITY_REF_NODE) { /* Shouldn't happen */ 02344 TODO 02345 goto skip; 02346 } 02347 goto next; 02348 } 02349 return(cur); 02350 } 02351 02362 static int 02363 xmlXPtrAdvanceChar(xmlNodePtr *node, int *indx, int bytes) { 02364 xmlNodePtr cur; 02365 int pos; 02366 int len; 02367 02368 if ((node == NULL) || (indx == NULL)) 02369 return(-1); 02370 cur = *node; 02371 if (cur == NULL) 02372 return(-1); 02373 pos = *indx; 02374 02375 while (bytes >= 0) { 02376 /* 02377 * First position to the beginning of the first text node 02378 * corresponding to this point 02379 */ 02380 while ((cur != NULL) && 02381 ((cur->type == XML_ELEMENT_NODE) || 02382 (cur->type == XML_DOCUMENT_NODE) || 02383 (cur->type == XML_HTML_DOCUMENT_NODE))) { 02384 if (pos > 0) { 02385 cur = xmlXPtrGetNthChild(cur, pos); 02386 pos = 0; 02387 } else { 02388 cur = xmlXPtrAdvanceNode(cur, NULL); 02389 pos = 0; 02390 } 02391 } 02392 02393 if (cur == NULL) { 02394 *node = NULL; 02395 *indx = 0; 02396 return(-1); 02397 } 02398 02399 /* 02400 * if there is no move needed return the current value. 02401 */ 02402 if (pos == 0) pos = 1; 02403 if (bytes == 0) { 02404 *node = cur; 02405 *indx = pos; 02406 return(0); 02407 } 02408 /* 02409 * We should have a text (or cdata) node ... 02410 */ 02411 len = 0; 02412 if ((cur->type != XML_ELEMENT_NODE) && 02413 (cur->content != NULL)) { 02414 len = xmlStrlen(cur->content); 02415 } 02416 if (pos > len) { 02417 /* Strange, the indx in the text node is greater than it's len */ 02418 STRANGE 02419 pos = len; 02420 } 02421 if (pos + bytes >= len) { 02422 bytes -= (len - pos); 02423 cur = xmlXPtrAdvanceNode(cur, NULL); 02424 pos = 0; 02425 } else if (pos + bytes < len) { 02426 pos += bytes; 02427 *node = cur; 02428 *indx = pos; 02429 return(0); 02430 } 02431 } 02432 return(-1); 02433 } 02434 02451 static int 02452 xmlXPtrMatchString(const xmlChar *string, xmlNodePtr start, int startindex, 02453 xmlNodePtr *end, int *endindex) { 02454 xmlNodePtr cur; 02455 int pos; /* 0 based */ 02456 int len; /* in bytes */ 02457 int stringlen; /* in bytes */ 02458 int match; 02459 02460 if (string == NULL) 02461 return(-1); 02462 if (start == NULL) 02463 return(-1); 02464 if ((end == NULL) || (endindex == NULL)) 02465 return(-1); 02466 cur = start; 02467 if (cur == NULL) 02468 return(-1); 02469 pos = startindex - 1; 02470 stringlen = xmlStrlen(string); 02471 02472 while (stringlen > 0) { 02473 if ((cur == *end) && (pos + stringlen > *endindex)) 02474 return(0); 02475 02476 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) { 02477 len = xmlStrlen(cur->content); 02478 if (len >= pos + stringlen) { 02479 match = (!xmlStrncmp(&cur->content[pos], string, stringlen)); 02480 if (match) { 02481 #ifdef DEBUG_RANGES 02482 xmlGenericError(xmlGenericErrorContext, 02483 "found range %d bytes at index %d of ->", 02484 stringlen, pos + 1); 02485 xmlDebugDumpString(stdout, cur->content); 02486 xmlGenericError(xmlGenericErrorContext, "\n"); 02487 #endif 02488 *end = cur; 02489 *endindex = pos + stringlen; 02490 return(1); 02491 } else { 02492 return(0); 02493 } 02494 } else { 02495 int sub = len - pos; 02496 match = (!xmlStrncmp(&cur->content[pos], string, sub)); 02497 if (match) { 02498 #ifdef DEBUG_RANGES 02499 xmlGenericError(xmlGenericErrorContext, 02500 "found subrange %d bytes at index %d of ->", 02501 sub, pos + 1); 02502 xmlDebugDumpString(stdout, cur->content); 02503 xmlGenericError(xmlGenericErrorContext, "\n"); 02504 #endif 02505 string = &string[sub]; 02506 stringlen -= sub; 02507 } else { 02508 return(0); 02509 } 02510 } 02511 } 02512 cur = xmlXPtrAdvanceNode(cur, NULL); 02513 if (cur == NULL) 02514 return(0); 02515 pos = 0; 02516 } 02517 return(1); 02518 } 02519 02536 static int 02537 xmlXPtrSearchString(const xmlChar *string, xmlNodePtr *start, int *startindex, 02538 xmlNodePtr *end, int *endindex) { 02539 xmlNodePtr cur; 02540 const xmlChar *str; 02541 int pos; /* 0 based */ 02542 int len; /* in bytes */ 02543 xmlChar first; 02544 02545 if (string == NULL) 02546 return(-1); 02547 if ((start == NULL) || (startindex == NULL)) 02548 return(-1); 02549 if ((end == NULL) || (endindex == NULL)) 02550 return(-1); 02551 cur = *start; 02552 if (cur == NULL) 02553 return(-1); 02554 pos = *startindex - 1; 02555 first = string[0]; 02556 02557 while (cur != NULL) { 02558 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) { 02559 len = xmlStrlen(cur->content); 02560 while (pos <= len) { 02561 if (first != 0) { 02562 str = xmlStrchr(&cur->content[pos], first); 02563 if (str != NULL) { 02564 pos = (str - (xmlChar *)(cur->content)); 02565 #ifdef DEBUG_RANGES 02566 xmlGenericError(xmlGenericErrorContext, 02567 "found '%c' at index %d of ->", 02568 first, pos + 1); 02569 xmlDebugDumpString(stdout, cur->content); 02570 xmlGenericError(xmlGenericErrorContext, "\n"); 02571 #endif 02572 if (xmlXPtrMatchString(string, cur, pos + 1, 02573 end, endindex)) { 02574 *start = cur; 02575 *startindex = pos + 1; 02576 return(1); 02577 } 02578 pos++; 02579 } else { 02580 pos = len + 1; 02581 } 02582 } else { 02583 /* 02584 * An empty string is considered to match before each 02585 * character of the string-value and after the final 02586 * character. 02587 */ 02588 #ifdef DEBUG_RANGES 02589 xmlGenericError(xmlGenericErrorContext, 02590 "found '' at index %d of ->", 02591 pos + 1); 02592 xmlDebugDumpString(stdout, cur->content); 02593 xmlGenericError(xmlGenericErrorContext, "\n"); 02594 #endif 02595 *start = cur; 02596 *startindex = pos + 1; 02597 *end = cur; 02598 *endindex = pos + 1; 02599 return(1); 02600 } 02601 } 02602 } 02603 if ((cur == *end) && (pos >= *endindex)) 02604 return(0); 02605 cur = xmlXPtrAdvanceNode(cur, NULL); 02606 if (cur == NULL) 02607 return(0); 02608 pos = 1; 02609 } 02610 return(0); 02611 } 02612 02622 static int 02623 xmlXPtrGetLastChar(xmlNodePtr *node, int *indx) { 02624 xmlNodePtr cur; 02625 int pos, len = 0; 02626 02627 if ((node == NULL) || (indx == NULL)) 02628 return(-1); 02629 cur = *node; 02630 pos = *indx; 02631 02632 if (cur == NULL) 02633 return(-1); 02634 02635 if ((cur->type == XML_ELEMENT_NODE) || 02636 (cur->type == XML_DOCUMENT_NODE) || 02637 (cur->type == XML_HTML_DOCUMENT_NODE)) { 02638 if (pos > 0) { 02639 cur = xmlXPtrGetNthChild(cur, pos); 02640 } 02641 } 02642 while (cur != NULL) { 02643 if (cur->last != NULL) 02644 cur = cur->last; 02645 else if ((cur->type != XML_ELEMENT_NODE) && 02646 (cur->content != NULL)) { 02647 len = xmlStrlen(cur->content); 02648 break; 02649 } else { 02650 return(-1); 02651 } 02652 } 02653 if (cur == NULL) 02654 return(-1); 02655 *node = cur; 02656 *indx = len; 02657 return(0); 02658 } 02659 02670 static int 02671 xmlXPtrGetStartPoint(xmlXPathObjectPtr obj, xmlNodePtr *node, int *indx) { 02672 if ((obj == NULL) || (node == NULL) || (indx == NULL)) 02673 return(-1); 02674 02675 switch (obj->type) { 02676 case XPATH_POINT: 02677 *node = obj->user; 02678 if (obj->index <= 0) 02679 *indx = 0; 02680 else 02681 *indx = obj->index; 02682 return(0); 02683 case XPATH_RANGE: 02684 *node = obj->user; 02685 if (obj->index <= 0) 02686 *indx = 0; 02687 else 02688 *indx = obj->index; 02689 return(0); 02690 default: 02691 break; 02692 } 02693 return(-1); 02694 } 02695 02706 static int 02707 xmlXPtrGetEndPoint(xmlXPathObjectPtr obj, xmlNodePtr *node, int *indx) { 02708 if ((obj == NULL) || (node == NULL) || (indx == NULL)) 02709 return(-1); 02710 02711 switch (obj->type) { 02712 case XPATH_POINT: 02713 *node = obj->user; 02714 if (obj->index <= 0) 02715 *indx = 0; 02716 else 02717 *indx = obj->index; 02718 return(0); 02719 case XPATH_RANGE: 02720 *node = obj->user; 02721 if (obj->index <= 0) 02722 *indx = 0; 02723 else 02724 *indx = obj->index; 02725 return(0); 02726 default: 02727 break; 02728 } 02729 return(-1); 02730 } 02731 02768 static void 02769 xmlXPtrStringRangeFunction(xmlXPathParserContextPtr ctxt, int nargs) { 02770 int i, startindex, endindex = 0, fendindex; 02771 xmlNodePtr start, end = 0, fend; 02772 xmlXPathObjectPtr set; 02773 xmlLocationSetPtr oldset; 02774 xmlLocationSetPtr newset; 02775 xmlXPathObjectPtr string; 02776 xmlXPathObjectPtr position = NULL; 02777 xmlXPathObjectPtr number = NULL; 02778 int found, pos = 0, num = 0; 02779 02780 /* 02781 * Grab the arguments 02782 */ 02783 if ((nargs < 2) || (nargs > 4)) 02784 XP_ERROR(XPATH_INVALID_ARITY); 02785 02786 if (nargs >= 4) { 02787 CHECK_TYPE(XPATH_NUMBER); 02788 number = valuePop(ctxt); 02789 if (number != NULL) 02790 num = (int) number->floatval; 02791 } 02792 if (nargs >= 3) { 02793 CHECK_TYPE(XPATH_NUMBER); 02794 position = valuePop(ctxt); 02795 if (position != NULL) 02796 pos = (int) position->floatval; 02797 } 02798 CHECK_TYPE(XPATH_STRING); 02799 string = valuePop(ctxt); 02800 if ((ctxt->value == NULL) || 02801 ((ctxt->value->type != XPATH_LOCATIONSET) && 02802 (ctxt->value->type != XPATH_NODESET))) 02803 XP_ERROR(XPATH_INVALID_TYPE) 02804 02805 set = valuePop(ctxt); 02806 newset = xmlXPtrLocationSetCreate(NULL); 02807 if (set->nodesetval == NULL) { 02808 goto error; 02809 } 02810 if (set->type == XPATH_NODESET) { 02811 xmlXPathObjectPtr tmp; 02812 02813 /* 02814 * First convert to a location set 02815 */ 02816 tmp = xmlXPtrNewLocationSetNodeSet(set->nodesetval); 02817 xmlXPathFreeObject(set); 02818 set = tmp; 02819 } 02820 oldset = (xmlLocationSetPtr) set->user; 02821 02822 /* 02823 * The loop is to search for each element in the location set 02824 * the list of location set corresponding to that search 02825 */ 02826 for (i = 0;i < oldset->locNr;i++) { 02827 #ifdef DEBUG_RANGES 02828 xmlXPathDebugDumpObject(stdout, oldset->locTab[i], 0); 02829 #endif 02830 02831 xmlXPtrGetStartPoint(oldset->locTab[i], &start, &startindex); 02832 xmlXPtrGetEndPoint(oldset->locTab[i], &end, &endindex); 02833 xmlXPtrAdvanceChar(&start, &startindex, 0); 02834 xmlXPtrGetLastChar(&end, &endindex); 02835 02836 #ifdef DEBUG_RANGES 02837 xmlGenericError(xmlGenericErrorContext, 02838 "from index %d of ->", startindex); 02839 xmlDebugDumpString(stdout, start->content); 02840 xmlGenericError(xmlGenericErrorContext, "\n"); 02841 xmlGenericError(xmlGenericErrorContext, 02842 "to index %d of ->", endindex); 02843 xmlDebugDumpString(stdout, end->content); 02844 xmlGenericError(xmlGenericErrorContext, "\n"); 02845 #endif 02846 do { 02847 fend = end; 02848 fendindex = endindex; 02849 found = xmlXPtrSearchString(string->stringval, &start, &startindex, 02850 &fend, &fendindex); 02851 if (found == 1) { 02852 if (position == NULL) { 02853 xmlXPtrLocationSetAdd(newset, 02854 xmlXPtrNewRange(start, startindex, fend, fendindex)); 02855 } else if (xmlXPtrAdvanceChar(&start, &startindex, 02856 pos - 1) == 0) { 02857 if ((number != NULL) && (num > 0)) { 02858 int rindx; 02859 xmlNodePtr rend; 02860 rend = start; 02861 rindx = startindex - 1; 02862 if (xmlXPtrAdvanceChar(&rend, &rindx, 02863 num) == 0) { 02864 xmlXPtrLocationSetAdd(newset, 02865 xmlXPtrNewRange(start, startindex, 02866 rend, rindx)); 02867 } 02868 } else if ((number != NULL) && (num <= 0)) { 02869 xmlXPtrLocationSetAdd(newset, 02870 xmlXPtrNewRange(start, startindex, 02871 start, startindex)); 02872 } else { 02873 xmlXPtrLocationSetAdd(newset, 02874 xmlXPtrNewRange(start, startindex, 02875 fend, fendindex)); 02876 } 02877 } 02878 start = fend; 02879 startindex = fendindex; 02880 if (string->stringval[0] == 0) 02881 startindex++; 02882 } 02883 } while (found == 1); 02884 } 02885 02886 /* 02887 * Save the new value and cleanup 02888 */ 02889 error: 02890 valuePush(ctxt, xmlXPtrWrapLocationSet(newset)); 02891 xmlXPathFreeObject(set); 02892 xmlXPathFreeObject(string); 02893 if (position) xmlXPathFreeObject(position); 02894 if (number) xmlXPathFreeObject(number); 02895 } 02896 02907 void 02908 xmlXPtrEvalRangePredicate(xmlXPathParserContextPtr ctxt) { 02909 const xmlChar *cur; 02910 xmlXPathObjectPtr res; 02911 xmlXPathObjectPtr obj, tmp; 02912 xmlLocationSetPtr newset = NULL; 02913 xmlLocationSetPtr oldset; 02914 int i; 02915 02916 if (ctxt == NULL) return; 02917 02918 SKIP_BLANKS; 02919 if (CUR != '[') { 02920 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); 02921 } 02922 NEXT; 02923 SKIP_BLANKS; 02924 02925 /* 02926 * Extract the old set, and then evaluate the result of the 02927 * expression for all the element in the set. use it to grow 02928 * up a new set. 02929 */ 02930 CHECK_TYPE(XPATH_LOCATIONSET); 02931 obj = valuePop(ctxt); 02932 oldset = obj->user; 02933 ctxt->context->node = NULL; 02934 02935 if ((oldset == NULL) || (oldset->locNr == 0)) { 02936 ctxt->context->contextSize = 0; 02937 ctxt->context->proximityPosition = 0; 02938 xmlXPathEvalExpr(ctxt); 02939 res = valuePop(ctxt); 02940 if (res != NULL) 02941 xmlXPathFreeObject(res); 02942 valuePush(ctxt, obj); 02943 CHECK_ERROR; 02944 } else { 02945 /* 02946 * Save the expression pointer since we will have to evaluate 02947 * it multiple times. Initialize the new set. 02948 */ 02949 cur = ctxt->cur; 02950 newset = xmlXPtrLocationSetCreate(NULL); 02951 02952 for (i = 0; i < oldset->locNr; i++) { 02953 ctxt->cur = cur; 02954 02955 /* 02956 * Run the evaluation with a node list made of a single item 02957 * in the nodeset. 02958 */ 02959 ctxt->context->node = oldset->locTab[i]->user; 02960 tmp = xmlXPathNewNodeSet(ctxt->context->node); 02961 valuePush(ctxt, tmp); 02962 ctxt->context->contextSize = oldset->locNr; 02963 ctxt->context->proximityPosition = i + 1; 02964 02965 xmlXPathEvalExpr(ctxt); 02966 CHECK_ERROR; 02967 02968 /* 02969 * The result of the evaluation need to be tested to 02970 * decided whether the filter succeeded or not 02971 */ 02972 res = valuePop(ctxt); 02973 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 02974 xmlXPtrLocationSetAdd(newset, 02975 xmlXPathObjectCopy(oldset->locTab[i])); 02976 } 02977 02978 /* 02979 * Cleanup 02980 */ 02981 if (res != NULL) 02982 xmlXPathFreeObject(res); 02983 if (ctxt->value == tmp) { 02984 res = valuePop(ctxt); 02985 xmlXPathFreeObject(res); 02986 } 02987 02988 ctxt->context->node = NULL; 02989 } 02990 02991 /* 02992 * The result is used as the new evaluation set. 02993 */ 02994 xmlXPathFreeObject(obj); 02995 ctxt->context->node = NULL; 02996 ctxt->context->contextSize = -1; 02997 ctxt->context->proximityPosition = -1; 02998 valuePush(ctxt, xmlXPtrWrapLocationSet(newset)); 02999 } 03000 if (CUR != ']') { 03001 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); 03002 } 03003 03004 NEXT; 03005 SKIP_BLANKS; 03006 } 03007 03008 #define bottom_xpointer 03009 #include "elfgcchack.h" 03010 #endif 03011 Generated on Sun May 27 2012 04:35:09 for ReactOS by
1.7.6.1
|