ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

xpointer.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.