2001-02-23 20:55:21 +03:00
/*
* xpointer . c : Code to handle XML Pointer
*
2003-02-13 18:52:58 +03:00
* Base implementation was made accordingly to
* W3C Candidate Recommendation 7 June 2000
2001-02-23 20:55:21 +03:00
* http : //www.w3.org/TR/2000/CR-xptr-20000607
*
2003-02-13 18:52:58 +03:00
* Added support for the element ( ) scheme described in :
* W3C Proposed Recommendation 13 November 2002
* http : //www.w3.org/TR/2002/PR-xptr-element-20021113/
*
2001-02-23 20:55:21 +03:00
* See Copyright for the status of this software .
*
2001-06-24 16:13:24 +04:00
* daniel @ veillard . com
2001-02-23 20:55:21 +03:00
*/
2002-03-18 22:37:11 +03:00
# define IN_LIBXML
2001-04-21 20:57:29 +04:00
# include "libxml.h"
2001-02-23 20:55:21 +03:00
2001-05-19 17:24:56 +04:00
/*
2001-02-23 20:55:21 +03:00
* TODO : better handling of error cases , the full expression should
* be parsed beforehand instead of a progressive evaluation
* TODO : Access into entities references are not supported now . . .
* need a start to be able to pop out of entities refs since
* parent is the endity declaration , not the ref .
*/
# include <string.h>
# include <libxml/xpointer.h>
# include <libxml/xmlmemory.h>
# include <libxml/parserInternals.h>
# include <libxml/uri.h>
# include <libxml/xpath.h>
# include <libxml/xpathInternals.h>
# include <libxml/xmlerror.h>
2001-10-17 19:58:35 +04:00
# include <libxml/globals.h>
2001-02-23 20:55:21 +03:00
# ifdef LIBXML_XPTR_ENABLED
/* Add support of the xmlns() xpointer scheme to initialize the namespaces */
# define XPTR_XMLNS_SCHEME
/* #define DEBUG_RANGES */
2001-06-21 15:20:21 +04:00
# ifdef DEBUG_RANGES
# ifdef LIBXML_DEBUG_ENABLED
# include <libxml/debugXML.h>
# endif
# endif
2001-02-23 20:55:21 +03:00
# define TODO \
xmlGenericError ( xmlGenericErrorContext , \
" Unimplemented block at %s:%d \n " , \
__FILE__ , __LINE__ ) ;
# define STRANGE \
xmlGenericError ( xmlGenericErrorContext , \
" Internal error at %s:%d \n " , \
__FILE__ , __LINE__ ) ;
2003-10-10 15:42:17 +04:00
/************************************************************************
* *
* Some factorized error routines *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* xmlXPtrErrMemory :
* @ extra : extra informations
*
* Handle a redefinition of attribute error
*/
static void
xmlXPtrErrMemory ( const char * extra )
{
2003-10-10 18:10:40 +04:00
__xmlRaiseError ( NULL , NULL , NULL , NULL , NULL , XML_FROM_XPOINTER ,
2003-10-10 15:42:17 +04:00
XML_ERR_NO_MEMORY , XML_ERR_ERROR , NULL , 0 , extra ,
NULL , NULL , 0 , 0 ,
" Memory allocation failed : %s \n " , extra ) ;
}
/**
* xmlXPtrErr :
* @ ctxt : an XPTR evaluation context
* @ extra : extra informations
*
* Handle a redefinition of attribute error
*/
static void
xmlXPtrErr ( xmlXPathParserContextPtr ctxt , int error ,
const char * msg , const xmlChar * extra )
{
if ( ctxt ! = NULL )
ctxt - > error = error ;
if ( ( ctxt = = NULL ) | | ( ctxt - > context = = NULL ) ) {
2003-10-10 18:10:40 +04:00
__xmlRaiseError ( NULL , NULL , NULL ,
2003-10-10 15:42:17 +04:00
NULL , NULL , XML_FROM_XPOINTER , error ,
XML_ERR_ERROR , NULL , 0 ,
( const char * ) extra , NULL , NULL , 0 , 0 ,
msg , extra ) ;
return ;
}
ctxt - > context - > lastError . domain = XML_FROM_XPOINTER ;
ctxt - > context - > lastError . code = error ;
ctxt - > context - > lastError . level = XML_ERR_ERROR ;
ctxt - > context - > lastError . str1 = ( char * ) xmlStrdup ( ctxt - > base ) ;
ctxt - > context - > lastError . int1 = ctxt - > cur - ctxt - > base ;
ctxt - > context - > lastError . node = ctxt - > context - > debugNode ;
if ( ctxt - > context - > error ! = NULL ) {
ctxt - > context - > error ( ctxt - > context - > userData ,
& ctxt - > context - > lastError ) ;
} else {
2003-10-10 18:10:40 +04:00
__xmlRaiseError ( NULL , NULL , NULL ,
2003-10-10 15:42:17 +04:00
NULL , ctxt - > context - > debugNode , XML_FROM_XPOINTER ,
error , XML_ERR_ERROR , NULL , 0 ,
( const char * ) extra , ( const char * ) ctxt - > base , NULL ,
ctxt - > cur - ctxt - > base , 0 ,
msg , extra ) ;
}
}
2001-02-23 20:55:21 +03:00
/************************************************************************
* *
* A few helper functions for child sequences *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-12-31 10:59:17 +03:00
/* xmlXPtrAdvanceNode is a private function, but used by xinclude.c */
xmlNodePtr xmlXPtrAdvanceNode ( xmlNodePtr cur , int * level ) ;
2001-02-23 20:55:21 +03:00
/**
* xmlXPtrGetArity :
* @ cur : the node
*
* Returns the number of child for an element , - 1 in case of error
*/
2001-03-24 20:00:36 +03:00
static int
2001-02-23 20:55:21 +03:00
xmlXPtrGetArity ( xmlNodePtr cur ) {
int i ;
if ( cur = = NULL )
return ( - 1 ) ;
cur = cur - > children ;
for ( i = 0 ; cur ! = NULL ; cur = cur - > next ) {
if ( ( cur - > type = = XML_ELEMENT_NODE ) | |
( cur - > type = = XML_DOCUMENT_NODE ) | |
( cur - > type = = XML_HTML_DOCUMENT_NODE ) ) {
i + + ;
}
}
return ( i ) ;
}
/**
* xmlXPtrGetIndex :
* @ cur : the node
*
* Returns the index of the node in its parent children list , - 1
* in case of error
*/
2001-03-24 20:00:36 +03:00
static int
2001-02-23 20:55:21 +03:00
xmlXPtrGetIndex ( xmlNodePtr cur ) {
int i ;
if ( cur = = NULL )
return ( - 1 ) ;
for ( i = 1 ; cur ! = NULL ; cur = cur - > prev ) {
if ( ( cur - > type = = XML_ELEMENT_NODE ) | |
( cur - > type = = XML_DOCUMENT_NODE ) | |
( cur - > type = = XML_HTML_DOCUMENT_NODE ) ) {
i + + ;
}
}
return ( i ) ;
}
/**
* xmlXPtrGetNthChild :
* @ cur : the node
* @ no : the child number
*
* Returns the @ no ' th element child of @ cur or NULL
*/
2001-03-24 20:00:36 +03:00
static xmlNodePtr
2001-02-23 20:55:21 +03:00
xmlXPtrGetNthChild ( xmlNodePtr cur , int no ) {
int i ;
if ( cur = = NULL )
return ( cur ) ;
cur = cur - > children ;
for ( i = 0 ; i < = no ; cur = cur - > next ) {
if ( cur = = NULL )
return ( cur ) ;
if ( ( cur - > type = = XML_ELEMENT_NODE ) | |
( cur - > type = = XML_DOCUMENT_NODE ) | |
( cur - > type = = XML_HTML_DOCUMENT_NODE ) ) {
i + + ;
if ( i = = no )
break ;
}
}
return ( cur ) ;
}
/************************************************************************
* *
* Handling of XPointer specific types *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* xmlXPtrCmpPoints :
* @ node1 : the first node
* @ index1 : the first index
* @ node2 : the second node
* @ index2 : the second index
*
* Compare two points w . r . t document order
*
* Returns - 2 in case of error 1 if first point < second point , 0 if
* that ' s the same point , - 1 otherwise
*/
2001-03-24 20:00:36 +03:00
static int
2001-02-23 20:55:21 +03:00
xmlXPtrCmpPoints ( xmlNodePtr node1 , int index1 , xmlNodePtr node2 , int index2 ) {
if ( ( node1 = = NULL ) | | ( node2 = = NULL ) )
return ( - 2 ) ;
/*
* a couple of optimizations which will avoid computations in most cases
*/
if ( node1 = = node2 ) {
if ( index1 < index2 )
return ( 1 ) ;
if ( index1 > index2 )
return ( - 1 ) ;
return ( 0 ) ;
}
return ( xmlXPathCmpNodes ( node1 , node2 ) ) ;
}
/**
* xmlXPtrNewPoint :
* @ node : the xmlNodePtr
2001-03-24 20:00:36 +03:00
* @ indx : the indx within the node
2001-02-23 20:55:21 +03:00
*
* Create a new xmlXPathObjectPtr of type point
*
* Returns the newly created object .
*/
2001-03-24 20:00:36 +03:00
static xmlXPathObjectPtr
xmlXPtrNewPoint ( xmlNodePtr node , int indx ) {
2001-02-23 20:55:21 +03:00
xmlXPathObjectPtr ret ;
if ( node = = NULL )
return ( NULL ) ;
2001-03-24 20:00:36 +03:00
if ( indx < 0 )
2001-02-23 20:55:21 +03:00
return ( NULL ) ;
ret = ( xmlXPathObjectPtr ) xmlMalloc ( sizeof ( xmlXPathObject ) ) ;
if ( ret = = NULL ) {
2003-10-10 15:42:17 +04:00
xmlXPtrErrMemory ( " allocating point " ) ;
2001-02-23 20:55:21 +03:00
return ( NULL ) ;
}
memset ( ret , 0 , ( size_t ) sizeof ( xmlXPathObject ) ) ;
ret - > type = XPATH_POINT ;
ret - > user = ( void * ) node ;
2001-03-24 20:00:36 +03:00
ret - > index = indx ;
2001-02-23 20:55:21 +03:00
return ( ret ) ;
}
/**
* xmlXPtrRangeCheckOrder :
* @ range : an object range
*
* Make sure the points in the range are in the right order
*/
2001-03-24 20:00:36 +03:00
static void
2001-02-23 20:55:21 +03:00
xmlXPtrRangeCheckOrder ( xmlXPathObjectPtr range ) {
int tmp ;
xmlNodePtr tmp2 ;
if ( range = = NULL )
return ;
if ( range - > type ! = XPATH_RANGE )
return ;
if ( range - > user2 = = NULL )
return ;
tmp = xmlXPtrCmpPoints ( range - > user , range - > index ,
range - > user2 , range - > index2 ) ;
if ( tmp = = - 1 ) {
tmp2 = range - > user ;
range - > user = range - > user2 ;
range - > user2 = tmp2 ;
tmp = range - > index ;
range - > index = range - > index2 ;
range - > index2 = tmp ;
}
}
/**
* xmlXPtrRangesEqual :
* @ range1 : the first range
* @ range2 : the second range
*
* Compare two ranges
*
2001-12-31 19:16:02 +03:00
* Returns 1 if equal , 0 otherwise
2001-02-23 20:55:21 +03:00
*/
2001-03-24 20:00:36 +03:00
static int
2001-02-23 20:55:21 +03:00
xmlXPtrRangesEqual ( xmlXPathObjectPtr range1 , xmlXPathObjectPtr range2 ) {
if ( range1 = = range2 )
return ( 1 ) ;
if ( ( range1 = = NULL ) | | ( range2 = = NULL ) )
return ( 0 ) ;
if ( range1 - > type ! = range2 - > type )
return ( 0 ) ;
if ( range1 - > type ! = XPATH_RANGE )
return ( 0 ) ;
if ( range1 - > user ! = range2 - > user )
return ( 0 ) ;
if ( range1 - > index ! = range2 - > index )
return ( 0 ) ;
if ( range1 - > user2 ! = range2 - > user2 )
return ( 0 ) ;
if ( range1 - > index2 ! = range2 - > index2 )
return ( 0 ) ;
return ( 1 ) ;
}
/**
* xmlXPtrNewRange :
* @ start : the starting node
* @ startindex : the start index
* @ end : the ending point
* @ endindex : the ending index
*
* Create a new xmlXPathObjectPtr of type range
*
* Returns the newly created object .
*/
xmlXPathObjectPtr
xmlXPtrNewRange ( xmlNodePtr start , int startindex ,
xmlNodePtr end , int endindex ) {
xmlXPathObjectPtr ret ;
if ( start = = NULL )
return ( NULL ) ;
if ( end = = NULL )
return ( NULL ) ;
if ( startindex < 0 )
return ( NULL ) ;
if ( endindex < 0 )
return ( NULL ) ;
ret = ( xmlXPathObjectPtr ) xmlMalloc ( sizeof ( xmlXPathObject ) ) ;
if ( ret = = NULL ) {
2003-10-10 15:42:17 +04:00
xmlXPtrErrMemory ( " allocating range " ) ;
2001-02-23 20:55:21 +03:00
return ( NULL ) ;
}
memset ( ret , 0 , ( size_t ) sizeof ( xmlXPathObject ) ) ;
ret - > type = XPATH_RANGE ;
ret - > user = start ;
ret - > index = startindex ;
ret - > user2 = end ;
ret - > index2 = endindex ;
xmlXPtrRangeCheckOrder ( ret ) ;
return ( ret ) ;
}
/**
* xmlXPtrNewRangePoints :
* @ start : the starting point
* @ end : the ending point
*
* Create a new xmlXPathObjectPtr of type range using 2 Points
*
* Returns the newly created object .
*/
xmlXPathObjectPtr
xmlXPtrNewRangePoints ( xmlXPathObjectPtr start , xmlXPathObjectPtr end ) {
xmlXPathObjectPtr ret ;
if ( start = = NULL )
return ( NULL ) ;
if ( end = = NULL )
return ( NULL ) ;
if ( start - > type ! = XPATH_POINT )
return ( NULL ) ;
if ( end - > type ! = XPATH_POINT )
return ( NULL ) ;
ret = ( xmlXPathObjectPtr ) xmlMalloc ( sizeof ( xmlXPathObject ) ) ;
if ( ret = = NULL ) {
2003-10-10 15:42:17 +04:00
xmlXPtrErrMemory ( " allocating range " ) ;
2001-02-23 20:55:21 +03:00
return ( NULL ) ;
}
memset ( ret , 0 , ( size_t ) sizeof ( xmlXPathObject ) ) ;
ret - > type = XPATH_RANGE ;
ret - > user = start - > user ;
ret - > index = start - > index ;
ret - > user2 = end - > user ;
ret - > index2 = end - > index ;
xmlXPtrRangeCheckOrder ( ret ) ;
return ( ret ) ;
}
/**
* xmlXPtrNewRangePointNode :
* @ start : the starting point
* @ end : the ending node
*
* Create a new xmlXPathObjectPtr of type range from a point to a node
*
* Returns the newly created object .
*/
xmlXPathObjectPtr
xmlXPtrNewRangePointNode ( xmlXPathObjectPtr start , xmlNodePtr end ) {
xmlXPathObjectPtr ret ;
if ( start = = NULL )
return ( NULL ) ;
if ( end = = NULL )
return ( NULL ) ;
if ( start - > type ! = XPATH_POINT )
return ( NULL ) ;
ret = ( xmlXPathObjectPtr ) xmlMalloc ( sizeof ( xmlXPathObject ) ) ;
if ( ret = = NULL ) {
2003-10-10 15:42:17 +04:00
xmlXPtrErrMemory ( " allocating range " ) ;
2001-02-23 20:55:21 +03:00
return ( NULL ) ;
}
memset ( ret , 0 , ( size_t ) sizeof ( xmlXPathObject ) ) ;
ret - > type = XPATH_RANGE ;
ret - > user = start - > user ;
ret - > index = start - > index ;
ret - > user2 = end ;
ret - > index2 = - 1 ;
xmlXPtrRangeCheckOrder ( ret ) ;
return ( ret ) ;
}
/**
* xmlXPtrNewRangeNodePoint :
* @ start : the starting node
* @ end : the ending point
*
* Create a new xmlXPathObjectPtr of type range from a node to a point
*
* Returns the newly created object .
*/
xmlXPathObjectPtr
xmlXPtrNewRangeNodePoint ( xmlNodePtr start , xmlXPathObjectPtr end ) {
xmlXPathObjectPtr ret ;
if ( start = = NULL )
return ( NULL ) ;
if ( end = = NULL )
return ( NULL ) ;
if ( start - > type ! = XPATH_POINT )
return ( NULL ) ;
if ( end - > type ! = XPATH_POINT )
return ( NULL ) ;
ret = ( xmlXPathObjectPtr ) xmlMalloc ( sizeof ( xmlXPathObject ) ) ;
if ( ret = = NULL ) {
2003-10-10 15:42:17 +04:00
xmlXPtrErrMemory ( " allocating range " ) ;
2001-02-23 20:55:21 +03:00
return ( NULL ) ;
}
memset ( ret , 0 , ( size_t ) sizeof ( xmlXPathObject ) ) ;
ret - > type = XPATH_RANGE ;
ret - > user = start ;
ret - > index = - 1 ;
ret - > user2 = end - > user ;
ret - > index2 = end - > index ;
xmlXPtrRangeCheckOrder ( ret ) ;
return ( ret ) ;
}
/**
* xmlXPtrNewRangeNodes :
* @ start : the starting node
* @ end : the ending node
*
* Create a new xmlXPathObjectPtr of type range using 2 nodes
*
* Returns the newly created object .
*/
xmlXPathObjectPtr
xmlXPtrNewRangeNodes ( xmlNodePtr start , xmlNodePtr end ) {
xmlXPathObjectPtr ret ;
if ( start = = NULL )
return ( NULL ) ;
if ( end = = NULL )
return ( NULL ) ;
ret = ( xmlXPathObjectPtr ) xmlMalloc ( sizeof ( xmlXPathObject ) ) ;
if ( ret = = NULL ) {
2003-10-10 15:42:17 +04:00
xmlXPtrErrMemory ( " allocating range " ) ;
2001-02-23 20:55:21 +03:00
return ( NULL ) ;
}
memset ( ret , 0 , ( size_t ) sizeof ( xmlXPathObject ) ) ;
ret - > type = XPATH_RANGE ;
ret - > user = start ;
ret - > index = - 1 ;
ret - > user2 = end ;
ret - > index2 = - 1 ;
xmlXPtrRangeCheckOrder ( ret ) ;
return ( ret ) ;
}
/**
* xmlXPtrNewCollapsedRange :
* @ start : the starting and ending node
*
* Create a new xmlXPathObjectPtr of type range using a single nodes
*
* Returns the newly created object .
*/
xmlXPathObjectPtr
xmlXPtrNewCollapsedRange ( xmlNodePtr start ) {
xmlXPathObjectPtr ret ;
if ( start = = NULL )
return ( NULL ) ;
ret = ( xmlXPathObjectPtr ) xmlMalloc ( sizeof ( xmlXPathObject ) ) ;
if ( ret = = NULL ) {
2003-10-10 15:42:17 +04:00
xmlXPtrErrMemory ( " allocating range " ) ;
2001-02-23 20:55:21 +03:00
return ( NULL ) ;
}
memset ( ret , 0 , ( size_t ) sizeof ( xmlXPathObject ) ) ;
ret - > type = XPATH_RANGE ;
ret - > user = start ;
ret - > index = - 1 ;
ret - > user2 = NULL ;
ret - > index2 = - 1 ;
return ( ret ) ;
}
/**
* xmlXPtrNewRangeNodeObject :
* @ start : the starting node
* @ end : the ending object
*
* Create a new xmlXPathObjectPtr of type range from a not to an object
*
* Returns the newly created object .
*/
xmlXPathObjectPtr
xmlXPtrNewRangeNodeObject ( xmlNodePtr start , xmlXPathObjectPtr end ) {
xmlXPathObjectPtr ret ;
if ( start = = NULL )
return ( NULL ) ;
if ( end = = NULL )
return ( NULL ) ;
switch ( end - > type ) {
case XPATH_POINT :
2003-12-30 11:30:19 +03:00
case XPATH_RANGE :
2001-02-23 20:55:21 +03:00
break ;
case XPATH_NODESET :
/*
* Empty set . . .
*/
if ( end - > nodesetval - > nodeNr < = 0 )
return ( NULL ) ;
break ;
default :
2004-11-04 13:49:00 +03:00
/* TODO */
2001-02-23 20:55:21 +03:00
return ( NULL ) ;
}
ret = ( xmlXPathObjectPtr ) xmlMalloc ( sizeof ( xmlXPathObject ) ) ;
if ( ret = = NULL ) {
2003-10-10 15:42:17 +04:00
xmlXPtrErrMemory ( " allocating range " ) ;
2001-02-23 20:55:21 +03:00
return ( NULL ) ;
}
memset ( ret , 0 , ( size_t ) sizeof ( xmlXPathObject ) ) ;
ret - > type = XPATH_RANGE ;
ret - > user = start ;
ret - > index = - 1 ;
switch ( end - > type ) {
case XPATH_POINT :
ret - > user2 = end - > user ;
ret - > index2 = end - > index ;
2003-12-30 11:30:19 +03:00
break ;
case XPATH_RANGE :
ret - > user2 = end - > user2 ;
ret - > index2 = end - > index2 ;
break ;
2001-02-23 20:55:21 +03:00
case XPATH_NODESET : {
ret - > user2 = end - > nodesetval - > nodeTab [ end - > nodesetval - > nodeNr - 1 ] ;
ret - > index2 = - 1 ;
break ;
}
default :
STRANGE
return ( NULL ) ;
}
xmlXPtrRangeCheckOrder ( ret ) ;
return ( ret ) ;
}
# define XML_RANGESET_DEFAULT 10
/**
* xmlXPtrLocationSetCreate :
* @ val : an initial xmlXPathObjectPtr , or NULL
*
* Create a new xmlLocationSetPtr of type double and of value @ val
*
* Returns the newly created object .
*/
xmlLocationSetPtr
xmlXPtrLocationSetCreate ( xmlXPathObjectPtr val ) {
xmlLocationSetPtr ret ;
ret = ( xmlLocationSetPtr ) xmlMalloc ( sizeof ( xmlLocationSet ) ) ;
if ( ret = = NULL ) {
2003-10-10 15:42:17 +04:00
xmlXPtrErrMemory ( " allocating locationset " ) ;
2001-02-23 20:55:21 +03:00
return ( NULL ) ;
}
memset ( ret , 0 , ( size_t ) sizeof ( xmlLocationSet ) ) ;
if ( val ! = NULL ) {
ret - > locTab = ( xmlXPathObjectPtr * ) xmlMalloc ( XML_RANGESET_DEFAULT *
sizeof ( xmlXPathObjectPtr ) ) ;
if ( ret - > locTab = = NULL ) {
2003-10-10 15:42:17 +04:00
xmlXPtrErrMemory ( " allocating locationset " ) ;
xmlFree ( ret ) ;
2001-02-23 20:55:21 +03:00
return ( NULL ) ;
}
memset ( ret - > locTab , 0 ,
XML_RANGESET_DEFAULT * ( size_t ) sizeof ( xmlXPathObjectPtr ) ) ;
ret - > locMax = XML_RANGESET_DEFAULT ;
ret - > locTab [ ret - > locNr + + ] = val ;
}
return ( ret ) ;
}
/**
* xmlXPtrLocationSetAdd :
* @ cur : the initial range set
* @ val : a new xmlXPathObjectPtr
*
2001-12-31 19:16:02 +03:00
* add a new xmlXPathObjectPtr to an existing LocationSet
2001-02-23 20:55:21 +03:00
* If the location already exist in the set @ val is freed .
*/
void
xmlXPtrLocationSetAdd ( xmlLocationSetPtr cur , xmlXPathObjectPtr val ) {
int i ;
2004-11-05 20:22:25 +03:00
if ( ( cur = = NULL ) | | ( val = = NULL ) ) return ;
2001-02-23 20:55:21 +03:00
/*
* check against doublons
*/
for ( i = 0 ; i < cur - > locNr ; i + + ) {
if ( xmlXPtrRangesEqual ( cur - > locTab [ i ] , val ) ) {
xmlXPathFreeObject ( val ) ;
return ;
}
}
/*
* grow the locTab if needed
*/
if ( cur - > locMax = = 0 ) {
cur - > locTab = ( xmlXPathObjectPtr * ) xmlMalloc ( XML_RANGESET_DEFAULT *
sizeof ( xmlXPathObjectPtr ) ) ;
if ( cur - > locTab = = NULL ) {
2003-10-10 15:42:17 +04:00
xmlXPtrErrMemory ( " adding location to set " ) ;
2001-02-23 20:55:21 +03:00
return ;
}
memset ( cur - > locTab , 0 ,
XML_RANGESET_DEFAULT * ( size_t ) sizeof ( xmlXPathObjectPtr ) ) ;
cur - > locMax = XML_RANGESET_DEFAULT ;
} else if ( cur - > locNr = = cur - > locMax ) {
xmlXPathObjectPtr * temp ;
cur - > locMax * = 2 ;
temp = ( xmlXPathObjectPtr * ) xmlRealloc ( cur - > locTab , cur - > locMax *
sizeof ( xmlXPathObjectPtr ) ) ;
if ( temp = = NULL ) {
2003-10-10 15:42:17 +04:00
xmlXPtrErrMemory ( " adding location to set " ) ;
2001-02-23 20:55:21 +03:00
return ;
}
cur - > locTab = temp ;
}
cur - > locTab [ cur - > locNr + + ] = val ;
}
/**
* xmlXPtrLocationSetMerge :
* @ val1 : the first LocationSet
* @ val2 : the second LocationSet
*
* Merges two rangesets , all ranges from @ val2 are added to @ val1
*
* Returns val1 once extended or NULL in case of error .
*/
xmlLocationSetPtr
xmlXPtrLocationSetMerge ( xmlLocationSetPtr val1 , xmlLocationSetPtr val2 ) {
int i ;
if ( val1 = = NULL ) return ( NULL ) ;
if ( val2 = = NULL ) return ( val1 ) ;
/*
* ! ! ! ! ! this can be optimized a lot , knowing that both
* val1 and val2 already have unicity of their values .
*/
for ( i = 0 ; i < val2 - > locNr ; i + + )
xmlXPtrLocationSetAdd ( val1 , val2 - > locTab [ i ] ) ;
return ( val1 ) ;
}
/**
* xmlXPtrLocationSetDel :
* @ cur : the initial range set
* @ val : an xmlXPathObjectPtr
*
* Removes an xmlXPathObjectPtr from an existing LocationSet
*/
void
xmlXPtrLocationSetDel ( xmlLocationSetPtr cur , xmlXPathObjectPtr val ) {
int i ;
if ( cur = = NULL ) return ;
if ( val = = NULL ) return ;
/*
* check against doublons
*/
for ( i = 0 ; i < cur - > locNr ; i + + )
if ( cur - > locTab [ i ] = = val ) break ;
if ( i > = cur - > locNr ) {
# ifdef DEBUG
xmlGenericError ( xmlGenericErrorContext ,
2001-11-28 17:53:53 +03:00
" xmlXPtrLocationSetDel: Range wasn't found in RangeList \n " ) ;
2001-02-23 20:55:21 +03:00
# endif
return ;
}
cur - > locNr - - ;
for ( ; i < cur - > locNr ; i + + )
cur - > locTab [ i ] = cur - > locTab [ i + 1 ] ;
cur - > locTab [ cur - > locNr ] = NULL ;
}
/**
* xmlXPtrLocationSetRemove :
* @ cur : the initial range set
* @ val : the index to remove
*
* Removes an entry from an existing LocationSet list .
*/
void
xmlXPtrLocationSetRemove ( xmlLocationSetPtr cur , int val ) {
if ( cur = = NULL ) return ;
if ( val > = cur - > locNr ) return ;
cur - > locNr - - ;
for ( ; val < cur - > locNr ; val + + )
cur - > locTab [ val ] = cur - > locTab [ val + 1 ] ;
cur - > locTab [ cur - > locNr ] = NULL ;
}
/**
* xmlXPtrFreeLocationSet :
* @ obj : the xmlLocationSetPtr to free
*
* Free the LocationSet compound ( not the actual ranges ! ) .
*/
void
xmlXPtrFreeLocationSet ( xmlLocationSetPtr obj ) {
int i ;
if ( obj = = NULL ) return ;
if ( obj - > locTab ! = NULL ) {
for ( i = 0 ; i < obj - > locNr ; i + + ) {
xmlXPathFreeObject ( obj - > locTab [ i ] ) ;
}
xmlFree ( obj - > locTab ) ;
}
xmlFree ( obj ) ;
}
/**
* xmlXPtrNewLocationSetNodes :
* @ start : the start NodePtr value
* @ end : the end NodePtr value or NULL
*
* Create a new xmlXPathObjectPtr of type LocationSet and initialize
* it with the single range made of the two nodes @ start and @ end
*
* Returns the newly created object .
*/
xmlXPathObjectPtr
xmlXPtrNewLocationSetNodes ( xmlNodePtr start , xmlNodePtr end ) {
xmlXPathObjectPtr ret ;
ret = ( xmlXPathObjectPtr ) xmlMalloc ( sizeof ( xmlXPathObject ) ) ;
if ( ret = = NULL ) {
2003-10-10 15:42:17 +04:00
xmlXPtrErrMemory ( " allocating locationset " ) ;
2001-02-23 20:55:21 +03:00
return ( NULL ) ;
}
memset ( ret , 0 , ( size_t ) sizeof ( xmlXPathObject ) ) ;
ret - > type = XPATH_LOCATIONSET ;
if ( end = = NULL )
ret - > user = xmlXPtrLocationSetCreate ( xmlXPtrNewCollapsedRange ( start ) ) ;
else
ret - > user = xmlXPtrLocationSetCreate ( xmlXPtrNewRangeNodes ( start , end ) ) ;
return ( ret ) ;
}
/**
* xmlXPtrNewLocationSetNodeSet :
* @ set : a node set
*
* Create a new xmlXPathObjectPtr of type LocationSet and initialize
* it with all the nodes from @ set
*
* Returns the newly created object .
*/
xmlXPathObjectPtr
xmlXPtrNewLocationSetNodeSet ( xmlNodeSetPtr set ) {
xmlXPathObjectPtr ret ;
ret = ( xmlXPathObjectPtr ) xmlMalloc ( sizeof ( xmlXPathObject ) ) ;
if ( ret = = NULL ) {
2003-10-10 15:42:17 +04:00
xmlXPtrErrMemory ( " allocating locationset " ) ;
2001-02-23 20:55:21 +03:00
return ( NULL ) ;
}
memset ( ret , 0 , ( size_t ) sizeof ( xmlXPathObject ) ) ;
ret - > type = XPATH_LOCATIONSET ;
if ( set ! = NULL ) {
int i ;
xmlLocationSetPtr newset ;
newset = xmlXPtrLocationSetCreate ( NULL ) ;
if ( newset = = NULL )
return ( ret ) ;
for ( i = 0 ; i < set - > nodeNr ; i + + )
xmlXPtrLocationSetAdd ( newset ,
xmlXPtrNewCollapsedRange ( set - > nodeTab [ i ] ) ) ;
ret - > user = ( void * ) newset ;
}
return ( ret ) ;
}
/**
* xmlXPtrWrapLocationSet :
* @ val : the LocationSet value
*
* Wrap the LocationSet @ val in a new xmlXPathObjectPtr
*
* Returns the newly created object .
*/
xmlXPathObjectPtr
xmlXPtrWrapLocationSet ( xmlLocationSetPtr val ) {
xmlXPathObjectPtr ret ;
ret = ( xmlXPathObjectPtr ) xmlMalloc ( sizeof ( xmlXPathObject ) ) ;
if ( ret = = NULL ) {
2003-10-10 15:42:17 +04:00
xmlXPtrErrMemory ( " allocating locationset " ) ;
2001-02-23 20:55:21 +03:00
return ( NULL ) ;
}
memset ( ret , 0 , ( size_t ) sizeof ( xmlXPathObject ) ) ;
ret - > type = XPATH_LOCATIONSET ;
ret - > user = ( void * ) val ;
return ( ret ) ;
}
/************************************************************************
* *
* The parser *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-02-13 18:52:58 +03:00
static void xmlXPtrEvalChildSeq ( xmlXPathParserContextPtr ctxt , xmlChar * name ) ;
2001-02-23 20:55:21 +03:00
/*
* Macros for accessing the content . Those should be used only by the parser ,
* and not exported .
*
* Dirty macros , i . e . one need to make assumption on the context to use them
*
* CUR_PTR return the current pointer to the xmlChar to be parsed .
* CUR returns the current xmlChar value , i . e . a 8 bit value
* in ISO - Latin or UTF - 8.
* This should be used internally by the parser
* only to compare to ASCII values otherwise it would break when
* running with UTF - 8 encoding .
* NXT ( n ) returns the n ' th next xmlChar . Same as CUR is should be used only
* to compare on ASCII based substring .
* SKIP ( n ) Skip n xmlChar , and must also be used only to skip ASCII defined
* strings within the parser .
* CURRENT Returns the current char value , with the full decoding of
* UTF - 8 if we are using this mode . It returns an int .
* NEXT Skip to the next character , this does the proper decoding
* in UTF - 8 mode . It also pop - up unfinished entities on the fly .
* It returns the pointer to the current xmlChar .
*/
# define CUR (*ctxt->cur)
# define SKIP(val) ctxt->cur += (val)
# define NXT(val) ctxt->cur[(val)]
# define CUR_PTR ctxt->cur
# define SKIP_BLANKS \
2003-11-14 19:20:34 +03:00
while ( IS_BLANK_CH ( * ( ctxt - > cur ) ) ) NEXT
2001-02-23 20:55:21 +03:00
# define CURRENT (*ctxt->cur)
# define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
/*
* xmlXPtrGetChildNo :
* @ ctxt : the XPointer Parser context
* @ index : the child number
*
* Move the current node of the nodeset on the stack to the
* given child if found
*/
2001-03-24 20:00:36 +03:00
static void
xmlXPtrGetChildNo ( xmlXPathParserContextPtr ctxt , int indx ) {
2001-02-23 20:55:21 +03:00
xmlNodePtr cur = NULL ;
xmlXPathObjectPtr obj ;
xmlNodeSetPtr oldset ;
CHECK_TYPE ( XPATH_NODESET ) ;
obj = valuePop ( ctxt ) ;
oldset = obj - > nodesetval ;
2001-03-24 20:00:36 +03:00
if ( ( indx < = 0 ) | | ( oldset = = NULL ) | | ( oldset - > nodeNr ! = 1 ) ) {
2001-02-23 20:55:21 +03:00
xmlXPathFreeObject ( obj ) ;
valuePush ( ctxt , xmlXPathNewNodeSet ( NULL ) ) ;
return ;
}
2001-03-24 20:00:36 +03:00
cur = xmlXPtrGetNthChild ( oldset - > nodeTab [ 0 ] , indx ) ;
2001-02-23 20:55:21 +03:00
if ( cur = = NULL ) {
xmlXPathFreeObject ( obj ) ;
valuePush ( ctxt , xmlXPathNewNodeSet ( NULL ) ) ;
return ;
}
oldset - > nodeTab [ 0 ] = cur ;
valuePush ( ctxt , obj ) ;
}
/**
* xmlXPtrEvalXPtrPart :
* @ ctxt : the XPointer Parser context
* @ name : the preparsed Scheme for the XPtrPart
*
* XPtrPart : : = ' xpointer ' ' ( ' XPtrExpr ' ) '
* | Scheme ' ( ' SchemeSpecificExpr ' ) '
*
* Scheme : : = NCName - ' xpointer ' [ VC : Non - XPointer schemes ]
*
* SchemeSpecificExpr : : = StringWithBalancedParens
*
* StringWithBalancedParens : : =
* [ ^ ( ) ] * ( ' ( ' StringWithBalancedParens ' ) ' [ ^ ( ) ] * ) *
* [ VC : Parenthesis escaping ]
*
* XPtrExpr : : = Expr [ VC : Parenthesis escaping ]
*
* VC : Parenthesis escaping :
* The end of an XPointer part is signaled by the right parenthesis " ) "
* character that is balanced with the left parenthesis " ( " character
* that began the part . Any unbalanced parenthesis character inside the
* expression , even within literals , must be escaped with a circumflex ( ^ )
* character preceding it . If the expression contains any literal
* occurrences of the circumflex , each must be escaped with an additional
* circumflex ( that is , ^ ^ ) . If the unescaped parentheses in the expression
* are not balanced , a syntax error results .
*
* Parse and evaluate an XPtrPart . Basically it generates the unescaped
2001-12-31 19:16:02 +03:00
* string and if the scheme is ' xpointer ' it will call the XPath interpreter .
2001-02-23 20:55:21 +03:00
*
* TODO : there is no new scheme registration mechanism
*/
2001-03-24 20:00:36 +03:00
static void
2001-02-23 20:55:21 +03:00
xmlXPtrEvalXPtrPart ( xmlXPathParserContextPtr ctxt , xmlChar * name ) {
xmlChar * buffer , * cur ;
int len ;
int level ;
if ( name = = NULL )
name = xmlXPathParseName ( ctxt ) ;
if ( name = = NULL )
XP_ERROR ( XPATH_EXPR_ERROR ) ;
if ( CUR ! = ' ( ' )
XP_ERROR ( XPATH_EXPR_ERROR ) ;
NEXT ;
level = 1 ;
len = xmlStrlen ( ctxt - > cur ) ;
len + + ;
2003-04-19 04:07:51 +04:00
buffer = ( xmlChar * ) xmlMallocAtomic ( len * sizeof ( xmlChar ) ) ;
2001-02-23 20:55:21 +03:00
if ( buffer = = NULL ) {
2003-10-10 15:42:17 +04:00
xmlXPtrErrMemory ( " allocating buffer " ) ;
2001-02-23 20:55:21 +03:00
return ;
}
cur = buffer ;
while ( CUR ! = 0 ) {
if ( CUR = = ' ) ' ) {
level - - ;
if ( level = = 0 ) {
NEXT ;
break ;
}
* cur + + = CUR ;
} else if ( CUR = = ' ( ' ) {
level + + ;
* cur + + = CUR ;
} else if ( CUR = = ' ^ ' ) {
NEXT ;
if ( ( CUR = = ' ) ' ) | | ( CUR = = ' ( ' ) | | ( CUR = = ' ^ ' ) ) {
* cur + + = CUR ;
} else {
* cur + + = ' ^ ' ;
* cur + + = CUR ;
}
} else {
* cur + + = CUR ;
}
NEXT ;
}
* cur = 0 ;
if ( ( level ! = 0 ) & & ( CUR = = 0 ) ) {
xmlFree ( buffer ) ;
XP_ERROR ( XPTR_SYNTAX_ERROR ) ;
}
if ( xmlStrEqual ( name , ( xmlChar * ) " xpointer " ) ) {
const xmlChar * left = CUR_PTR ;
CUR_PTR = buffer ;
2003-12-30 11:30:19 +03:00
/*
* To evaluate an xpointer scheme element ( 4.3 ) we need :
* context initialized to the root
* context position initalized to 1
* context size initialized to 1
*/
ctxt - > context - > node = ( xmlNodePtr ) ctxt - > context - > doc ;
ctxt - > context - > proximityPosition = 1 ;
ctxt - > context - > contextSize = 1 ;
2001-02-23 20:55:21 +03:00
xmlXPathEvalExpr ( ctxt ) ;
CUR_PTR = left ;
2003-02-13 18:52:58 +03:00
} else if ( xmlStrEqual ( name , ( xmlChar * ) " element " ) ) {
const xmlChar * left = CUR_PTR ;
xmlChar * name2 ;
CUR_PTR = buffer ;
if ( buffer [ 0 ] = = ' / ' ) {
xmlXPathRoot ( ctxt ) ;
xmlXPtrEvalChildSeq ( ctxt , NULL ) ;
} else {
name2 = xmlXPathParseName ( ctxt ) ;
if ( name2 = = NULL ) {
CUR_PTR = left ;
xmlFree ( buffer ) ;
XP_ERROR ( XPATH_EXPR_ERROR ) ;
}
xmlXPtrEvalChildSeq ( ctxt , name2 ) ;
}
CUR_PTR = left ;
2001-02-23 20:55:21 +03:00
# ifdef XPTR_XMLNS_SCHEME
} else if ( xmlStrEqual ( name , ( xmlChar * ) " xmlns " ) ) {
const xmlChar * left = CUR_PTR ;
xmlChar * prefix ;
xmlChar * URI ;
xmlURIPtr value ;
CUR_PTR = buffer ;
prefix = xmlXPathParseNCName ( ctxt ) ;
if ( prefix = = NULL ) {
xmlFree ( buffer ) ;
xmlFree ( name ) ;
XP_ERROR ( XPTR_SYNTAX_ERROR ) ;
}
SKIP_BLANKS ;
if ( CUR ! = ' = ' ) {
xmlFree ( prefix ) ;
xmlFree ( buffer ) ;
xmlFree ( name ) ;
XP_ERROR ( XPTR_SYNTAX_ERROR ) ;
}
NEXT ;
SKIP_BLANKS ;
/* @@ check escaping in the XPointer WD */
value = xmlParseURI ( ( const char * ) ctxt - > cur ) ;
if ( value = = NULL ) {
xmlFree ( prefix ) ;
xmlFree ( buffer ) ;
xmlFree ( name ) ;
XP_ERROR ( XPTR_SYNTAX_ERROR ) ;
}
URI = xmlSaveUri ( value ) ;
xmlFreeURI ( value ) ;
if ( URI = = NULL ) {
xmlFree ( prefix ) ;
xmlFree ( buffer ) ;
xmlFree ( name ) ;
XP_ERROR ( XPATH_MEMORY_ERROR ) ;
}
xmlXPathRegisterNs ( ctxt - > context , prefix , URI ) ;
CUR_PTR = left ;
2002-11-06 18:49:46 +03:00
xmlFree ( URI ) ;
xmlFree ( prefix ) ;
2001-02-23 20:55:21 +03:00
# endif /* XPTR_XMLNS_SCHEME */
} else {
2003-10-10 15:42:17 +04:00
xmlXPtrErr ( ctxt , XML_XPTR_UNKNOWN_SCHEME ,
" unsupported scheme '%s' \n " , name ) ;
2001-02-23 20:55:21 +03:00
}
xmlFree ( buffer ) ;
xmlFree ( name ) ;
}
/**
* xmlXPtrEvalFullXPtr :
* @ ctxt : the XPointer Parser context
* @ name : the preparsed Scheme for the first XPtrPart
*
* FullXPtr : : = XPtrPart ( S ? XPtrPart ) *
*
* As the specs says :
* - - - - - - - - - - -
* When multiple XPtrParts are provided , they must be evaluated in
* left - to - right order . If evaluation of one part fails , the nexti
* is evaluated . The following conditions cause XPointer part failure :
*
* - An unknown scheme
* - A scheme that does not locate any sub - resource present in the resource
* - A scheme that is not applicable to the media type of the resource
*
* The XPointer application must consume a failed XPointer part and
* attempt to evaluate the next one , if any . The result of the first
* XPointer part whose evaluation succeeds is taken to be the fragment
* located by the XPointer as a whole . If all the parts fail , the result
* for the XPointer as a whole is a sub - resource error .
* - - - - - - - - - - -
*
* Parse and evaluate a Full XPtr i . e . possibly a cascade of XPath based
2001-12-31 19:16:02 +03:00
* expressions or other schemes .
2001-02-23 20:55:21 +03:00
*/
2001-03-24 20:00:36 +03:00
static void
2001-02-23 20:55:21 +03:00
xmlXPtrEvalFullXPtr ( xmlXPathParserContextPtr ctxt , xmlChar * name ) {
if ( name = = NULL )
name = xmlXPathParseName ( ctxt ) ;
if ( name = = NULL )
XP_ERROR ( XPATH_EXPR_ERROR ) ;
while ( name ! = NULL ) {
xmlXPtrEvalXPtrPart ( ctxt , name ) ;
/* in case of syntax error, break here */
if ( ctxt - > error ! = XPATH_EXPRESSION_OK )
return ;
/*
* If the returned value is a non - empty nodeset
* or location set , return here .
*/
if ( ctxt - > value ! = NULL ) {
xmlXPathObjectPtr obj = ctxt - > value ;
switch ( obj - > type ) {
case XPATH_LOCATIONSET : {
xmlLocationSetPtr loc = ctxt - > value - > user ;
if ( ( loc ! = NULL ) & & ( loc - > locNr > 0 ) )
return ;
break ;
}
case XPATH_NODESET : {
xmlNodeSetPtr loc = ctxt - > value - > nodesetval ;
if ( ( loc ! = NULL ) & & ( loc - > nodeNr > 0 ) )
return ;
break ;
}
default :
break ;
}
/*
* Evaluating to improper values is equivalent to
* a sub - resource error , clean - up the stack
*/
do {
obj = valuePop ( ctxt ) ;
if ( obj ! = NULL ) {
xmlXPathFreeObject ( obj ) ;
}
} while ( obj ! = NULL ) ;
}
/*
2001-12-31 19:16:02 +03:00
* Is there another XPointer part .
2001-02-23 20:55:21 +03:00
*/
SKIP_BLANKS ;
name = xmlXPathParseName ( ctxt ) ;
}
}
/**
* xmlXPtrEvalChildSeq :
* @ ctxt : the XPointer Parser context
* @ name : a possible ID name of the child sequence
*
* ChildSeq : : = ' / 1 ' ( ' / ' [ 0 - 9 ] * ) *
* | Name ( ' / ' [ 0 - 9 ] * ) +
*
* Parse and evaluate a Child Sequence . This routine also handle the
* case of a Bare Name used to get a document ID .
*/
2001-03-24 20:00:36 +03:00
static void
2001-02-23 20:55:21 +03:00
xmlXPtrEvalChildSeq ( xmlXPathParserContextPtr ctxt , xmlChar * name ) {
/*
2001-12-31 19:16:02 +03:00
* XPointer don ' t allow by syntax to address in mutirooted trees
2001-02-23 20:55:21 +03:00
* this might prove useful in some cases , warn about it .
*/
if ( ( name = = NULL ) & & ( CUR = = ' / ' ) & & ( NXT ( 1 ) ! = ' 1 ' ) ) {
2003-10-10 15:42:17 +04:00
xmlXPtrErr ( ctxt , XML_XPTR_CHILDSEQ_START ,
" warning: ChildSeq not starting by /1 \n " , NULL ) ;
2001-02-23 20:55:21 +03:00
}
if ( name ! = NULL ) {
valuePush ( ctxt , xmlXPathNewString ( name ) ) ;
xmlFree ( name ) ;
xmlXPathIdFunction ( ctxt , 1 ) ;
CHECK_ERROR ;
}
while ( CUR = = ' / ' ) {
int child = 0 ;
NEXT ;
while ( ( CUR > = ' 0 ' ) & & ( CUR < = ' 9 ' ) ) {
child = child * 10 + ( CUR - ' 0 ' ) ;
NEXT ;
}
xmlXPtrGetChildNo ( ctxt , child ) ;
}
}
/**
* xmlXPtrEvalXPointer :
* @ ctxt : the XPointer Parser context
*
* XPointer : : = Name
* | ChildSeq
* | FullXPtr
*
* Parse and evaluate an XPointer
*/
2001-03-24 20:00:36 +03:00
static void
2001-02-23 20:55:21 +03:00
xmlXPtrEvalXPointer ( xmlXPathParserContextPtr ctxt ) {
2001-03-19 02:17:47 +03:00
if ( ctxt - > valueTab = = NULL ) {
/* Allocate the value stack */
ctxt - > valueTab = ( xmlXPathObjectPtr * )
xmlMalloc ( 10 * sizeof ( xmlXPathObjectPtr ) ) ;
if ( ctxt - > valueTab = = NULL ) {
2003-10-10 15:42:17 +04:00
xmlXPtrErrMemory ( " allocating evaluation context " ) ;
2001-03-19 02:17:47 +03:00
return ;
}
ctxt - > valueNr = 0 ;
ctxt - > valueMax = 10 ;
ctxt - > value = NULL ;
}
2001-02-23 20:55:21 +03:00
SKIP_BLANKS ;
if ( CUR = = ' / ' ) {
xmlXPathRoot ( ctxt ) ;
xmlXPtrEvalChildSeq ( ctxt , NULL ) ;
} else {
xmlChar * name ;
name = xmlXPathParseName ( ctxt ) ;
if ( name = = NULL )
XP_ERROR ( XPATH_EXPR_ERROR ) ;
if ( CUR = = ' ( ' ) {
xmlXPtrEvalFullXPtr ( ctxt , name ) ;
/* Short evaluation */
return ;
} else {
/* this handle both Bare Names and Child Sequences */
xmlXPtrEvalChildSeq ( ctxt , name ) ;
}
}
SKIP_BLANKS ;
if ( CUR ! = 0 )
XP_ERROR ( XPATH_EXPR_ERROR ) ;
}
/************************************************************************
* *
* General routines *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void xmlXPtrStringRangeFunction ( xmlXPathParserContextPtr ctxt , int nargs ) ;
void xmlXPtrStartPointFunction ( xmlXPathParserContextPtr ctxt , int nargs ) ;
void xmlXPtrEndPointFunction ( xmlXPathParserContextPtr ctxt , int nargs ) ;
void xmlXPtrHereFunction ( xmlXPathParserContextPtr ctxt , int nargs ) ;
void xmlXPtrOriginFunction ( xmlXPathParserContextPtr ctxt , int nargs ) ;
void xmlXPtrRangeInsideFunction ( xmlXPathParserContextPtr ctxt , int nargs ) ;
void xmlXPtrRangeFunction ( xmlXPathParserContextPtr ctxt , int nargs ) ;
/**
* xmlXPtrNewContext :
* @ doc : the XML document
* @ here : the node that directly contains the XPointer being evaluated or NULL
* @ origin : the element from which a user or program initiated traversal of
* the link , or NULL .
*
* Create a new XPointer context
*
* Returns the xmlXPathContext just allocated .
*/
xmlXPathContextPtr
xmlXPtrNewContext ( xmlDocPtr doc , xmlNodePtr here , xmlNodePtr origin ) {
xmlXPathContextPtr ret ;
ret = xmlXPathNewContext ( doc ) ;
if ( ret = = NULL )
return ( ret ) ;
ret - > xptr = 1 ;
ret - > here = here ;
ret - > origin = origin ;
xmlXPathRegisterFunc ( ret , ( xmlChar * ) " range-to " ,
xmlXPtrRangeToFunction ) ;
xmlXPathRegisterFunc ( ret , ( xmlChar * ) " range " ,
xmlXPtrRangeFunction ) ;
xmlXPathRegisterFunc ( ret , ( xmlChar * ) " range-inside " ,
xmlXPtrRangeInsideFunction ) ;
xmlXPathRegisterFunc ( ret , ( xmlChar * ) " string-range " ,
xmlXPtrStringRangeFunction ) ;
xmlXPathRegisterFunc ( ret , ( xmlChar * ) " start-point " ,
xmlXPtrStartPointFunction ) ;
xmlXPathRegisterFunc ( ret , ( xmlChar * ) " end-point " ,
xmlXPtrEndPointFunction ) ;
xmlXPathRegisterFunc ( ret , ( xmlChar * ) " here " ,
xmlXPtrHereFunction ) ;
xmlXPathRegisterFunc ( ret , ( xmlChar * ) " origin " ,
xmlXPtrOriginFunction ) ;
return ( ret ) ;
}
/**
* xmlXPtrEval :
* @ str : the XPointer expression
* @ ctx : the XPointer context
*
* Evaluate the XPath Location Path in the given context .
*
2001-12-31 19:16:02 +03:00
* Returns the xmlXPathObjectPtr resulting from the evaluation or NULL .
2001-02-23 20:55:21 +03:00
* the caller has to free the object .
*/
xmlXPathObjectPtr
xmlXPtrEval ( const xmlChar * str , xmlXPathContextPtr ctx ) {
xmlXPathParserContextPtr ctxt ;
xmlXPathObjectPtr res = NULL , tmp ;
xmlXPathObjectPtr init = NULL ;
int stack = 0 ;
xmlXPathInit ( ) ;
if ( ( ctx = = NULL ) | | ( str = = NULL ) )
return ( NULL ) ;
ctxt = xmlXPathNewParserContext ( str , ctx ) ;
2001-03-19 18:58:54 +03:00
ctxt - > xptr = 1 ;
2001-02-23 20:55:21 +03:00
xmlXPtrEvalXPointer ( ctxt ) ;
if ( ( ctxt - > value ! = NULL ) & &
( ctxt - > value - > type ! = XPATH_NODESET ) & &
( ctxt - > value - > type ! = XPATH_LOCATIONSET ) ) {
2003-10-10 15:42:17 +04:00
xmlXPtrErr ( ctxt , XML_XPTR_EVAL_FAILED ,
" xmlXPtrEval: evaluation failed to return a node set \n " ,
NULL ) ;
2001-02-23 20:55:21 +03:00
} else {
res = valuePop ( ctxt ) ;
}
do {
tmp = valuePop ( ctxt ) ;
if ( tmp ! = NULL ) {
if ( tmp ! = init ) {
if ( tmp - > type = = XPATH_NODESET ) {
/*
* Evaluation may push a root nodeset which is unused
*/
xmlNodeSetPtr set ;
set = tmp - > nodesetval ;
if ( ( set - > nodeNr ! = 1 ) | |
( set - > nodeTab [ 0 ] ! = ( xmlNodePtr ) ctx - > doc ) )
stack + + ;
} else
stack + + ;
}
xmlXPathFreeObject ( tmp ) ;
}
} while ( tmp ! = NULL ) ;
if ( stack ! = 0 ) {
2003-10-10 15:42:17 +04:00
xmlXPtrErr ( ctxt , XML_XPTR_EXTRA_OBJECTS ,
" xmlXPtrEval: object(s) left on the eval stack \n " ,
NULL ) ;
2001-02-23 20:55:21 +03:00
}
if ( ctxt - > error ! = XPATH_EXPRESSION_OK ) {
xmlXPathFreeObject ( res ) ;
res = NULL ;
}
xmlXPathFreeParserContext ( ctxt ) ;
return ( res ) ;
}
/**
* xmlXPtrBuildRangeNodeList :
* @ range : a range object
*
* Build a node list tree copy of the range
*
* Returns an xmlNodePtr list or NULL .
* the caller has to free the node tree .
*/
2001-03-24 20:00:36 +03:00
static xmlNodePtr
2001-02-23 20:55:21 +03:00
xmlXPtrBuildRangeNodeList ( xmlXPathObjectPtr range ) {
/* pointers to generated nodes */
xmlNodePtr list = NULL , last = NULL , parent = NULL , tmp ;
/* pointers to traversal nodes */
xmlNodePtr start , cur , end ;
2001-03-24 20:00:36 +03:00
int index1 , index2 ;
2001-02-23 20:55:21 +03:00
if ( range = = NULL )
return ( NULL ) ;
if ( range - > type ! = XPATH_RANGE )
return ( NULL ) ;
start = ( xmlNodePtr ) range - > user ;
if ( start = = NULL )
return ( NULL ) ;
end = range - > user2 ;
if ( end = = NULL )
return ( xmlCopyNode ( start , 1 ) ) ;
cur = start ;
2001-03-24 20:00:36 +03:00
index1 = range - > index ;
2001-02-23 20:55:21 +03:00
index2 = range - > index2 ;
while ( cur ! = NULL ) {
if ( cur = = end ) {
if ( cur - > type = = XML_TEXT_NODE ) {
const xmlChar * content = cur - > content ;
int len ;
if ( content = = NULL ) {
tmp = xmlNewTextLen ( NULL , 0 ) ;
} else {
len = index2 ;
2001-03-24 20:00:36 +03:00
if ( ( cur = = start ) & & ( index1 > 1 ) ) {
content + = ( index1 - 1 ) ;
len - = ( index1 - 1 ) ;
index1 = 0 ;
2001-02-23 20:55:21 +03:00
} else {
len = index2 ;
}
tmp = xmlNewTextLen ( content , len ) ;
}
/* single sub text node selection */
if ( list = = NULL )
return ( tmp ) ;
/* prune and return full set */
if ( last ! = NULL )
xmlAddNextSibling ( last , tmp ) ;
else
xmlAddChild ( parent , tmp ) ;
return ( list ) ;
} else {
tmp = xmlCopyNode ( cur , 0 ) ;
if ( list = = NULL )
list = tmp ;
else {
if ( last ! = NULL )
xmlAddNextSibling ( last , tmp ) ;
else
xmlAddChild ( parent , tmp ) ;
}
last = NULL ;
parent = tmp ;
if ( index2 > 1 ) {
end = xmlXPtrGetNthChild ( cur , index2 - 1 ) ;
index2 = 0 ;
}
2001-03-24 20:00:36 +03:00
if ( ( cur = = start ) & & ( index1 > 1 ) ) {
cur = xmlXPtrGetNthChild ( cur , index1 - 1 ) ;
index1 = 0 ;
2001-02-23 20:55:21 +03:00
} else {
cur = cur - > children ;
}
/*
* Now gather the remaining nodes from cur to end
*/
continue ; /* while */
}
} else if ( ( cur = = start ) & &
( list = = NULL ) /* looks superfluous but ... */ ) {
2001-07-12 05:20:08 +04:00
if ( ( cur - > type = = XML_TEXT_NODE ) | |
( cur - > type = = XML_CDATA_SECTION_NODE ) ) {
2001-02-23 20:55:21 +03:00
const xmlChar * content = cur - > content ;
if ( content = = NULL ) {
tmp = xmlNewTextLen ( NULL , 0 ) ;
} else {
2001-03-24 20:00:36 +03:00
if ( index1 > 1 ) {
content + = ( index1 - 1 ) ;
2001-02-23 20:55:21 +03:00
}
tmp = xmlNewText ( content ) ;
}
last = list = tmp ;
} else {
2001-03-24 20:00:36 +03:00
if ( ( cur = = start ) & & ( index1 > 1 ) ) {
2001-02-23 20:55:21 +03:00
tmp = xmlCopyNode ( cur , 0 ) ;
list = tmp ;
parent = tmp ;
last = NULL ;
2001-03-24 20:00:36 +03:00
cur = xmlXPtrGetNthChild ( cur , index1 - 1 ) ;
index1 = 0 ;
2001-02-23 20:55:21 +03:00
/*
* Now gather the remaining nodes from cur to end
*/
continue ; /* while */
}
tmp = xmlCopyNode ( cur , 1 ) ;
list = tmp ;
parent = NULL ;
last = tmp ;
}
} else {
tmp = NULL ;
switch ( cur - > type ) {
case XML_DTD_NODE :
case XML_ELEMENT_DECL :
case XML_ATTRIBUTE_DECL :
case XML_ENTITY_NODE :
/* Do not copy DTD informations */
break ;
case XML_ENTITY_DECL :
2001-12-31 19:16:02 +03:00
TODO /* handle crossing entities -> stack needed */
2001-02-23 20:55:21 +03:00
break ;
case XML_XINCLUDE_START :
case XML_XINCLUDE_END :
/* don't consider it part of the tree content */
break ;
case XML_ATTRIBUTE_NODE :
/* Humm, should not happen ! */
STRANGE
break ;
default :
tmp = xmlCopyNode ( cur , 1 ) ;
break ;
}
if ( tmp ! = NULL ) {
if ( ( list = = NULL ) | | ( ( last = = NULL ) & & ( parent = = NULL ) ) ) {
STRANGE
return ( NULL ) ;
}
if ( last ! = NULL )
xmlAddNextSibling ( last , tmp ) ;
else {
xmlAddChild ( parent , tmp ) ;
last = tmp ;
}
}
}
/*
* Skip to next node in document order
*/
if ( ( list = = NULL ) | | ( ( last = = NULL ) & & ( parent = = NULL ) ) ) {
STRANGE
return ( NULL ) ;
}
2003-12-31 10:59:17 +03:00
cur = xmlXPtrAdvanceNode ( cur , NULL ) ;
2001-02-23 20:55:21 +03:00
}
return ( list ) ;
}
/**
* xmlXPtrBuildNodeList :
* @ obj : the XPointer result from the evaluation .
*
* Build a node list tree copy of the XPointer result .
2001-06-19 22:09:42 +04:00
* This will drop Attributes and Namespace declarations .
2001-02-23 20:55:21 +03:00
*
* Returns an xmlNodePtr list or NULL .
* the caller has to free the node tree .
*/
xmlNodePtr
xmlXPtrBuildNodeList ( xmlXPathObjectPtr obj ) {
xmlNodePtr list = NULL , last = NULL ;
int i ;
if ( obj = = NULL )
return ( NULL ) ;
switch ( obj - > type ) {
case XPATH_NODESET : {
xmlNodeSetPtr set = obj - > nodesetval ;
if ( set = = NULL )
return ( NULL ) ;
for ( i = 0 ; i < set - > nodeNr ; i + + ) {
2001-06-19 22:09:42 +04:00
if ( set - > nodeTab [ i ] = = NULL )
continue ;
switch ( set - > nodeTab [ i ] - > type ) {
case XML_TEXT_NODE :
case XML_CDATA_SECTION_NODE :
case XML_ELEMENT_NODE :
case XML_ENTITY_REF_NODE :
case XML_ENTITY_NODE :
case XML_PI_NODE :
case XML_COMMENT_NODE :
case XML_DOCUMENT_NODE :
case XML_HTML_DOCUMENT_NODE :
# ifdef LIBXML_DOCB_ENABLED
case XML_DOCB_DOCUMENT_NODE :
# endif
case XML_XINCLUDE_START :
case XML_XINCLUDE_END :
break ;
case XML_ATTRIBUTE_NODE :
case XML_NAMESPACE_DECL :
case XML_DOCUMENT_TYPE_NODE :
case XML_DOCUMENT_FRAG_NODE :
case XML_NOTATION_NODE :
case XML_DTD_NODE :
case XML_ELEMENT_DECL :
case XML_ATTRIBUTE_DECL :
case XML_ENTITY_DECL :
continue ; /* for */
}
2001-02-23 20:55:21 +03:00
if ( last = = NULL )
list = last = xmlCopyNode ( set - > nodeTab [ i ] , 1 ) ;
else {
xmlAddNextSibling ( last , xmlCopyNode ( set - > nodeTab [ i ] , 1 ) ) ;
if ( last - > next ! = NULL )
last = last - > next ;
}
}
break ;
}
case XPATH_LOCATIONSET : {
xmlLocationSetPtr set = ( xmlLocationSetPtr ) obj - > user ;
if ( set = = NULL )
return ( NULL ) ;
for ( i = 0 ; i < set - > locNr ; i + + ) {
if ( last = = NULL )
list = last = xmlXPtrBuildNodeList ( set - > locTab [ i ] ) ;
else
xmlAddNextSibling ( last ,
xmlXPtrBuildNodeList ( set - > locTab [ i ] ) ) ;
if ( last ! = NULL ) {
while ( last - > next ! = NULL )
last = last - > next ;
}
}
break ;
}
case XPATH_RANGE :
return ( xmlXPtrBuildRangeNodeList ( obj ) ) ;
case XPATH_POINT :
return ( xmlCopyNode ( obj - > user , 0 ) ) ;
default :
break ;
}
return ( list ) ;
}
/************************************************************************
* *
* XPointer functions *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* xmlXPtrNbLocChildren :
* @ node : an xmlNodePtr
*
2001-10-10 13:45:09 +04:00
* Count the number of location children of @ node or the length of the
2001-02-23 20:55:21 +03:00
* string value in case of text / PI / Comments nodes
*
* Returns the number of location children
*/
2001-03-24 20:00:36 +03:00
static int
2001-02-23 20:55:21 +03:00
xmlXPtrNbLocChildren ( xmlNodePtr node ) {
int ret = 0 ;
if ( node = = NULL )
return ( - 1 ) ;
switch ( node - > type ) {
case XML_HTML_DOCUMENT_NODE :
case XML_DOCUMENT_NODE :
case XML_ELEMENT_NODE :
node = node - > children ;
while ( node ! = NULL ) {
if ( node - > type = = XML_ELEMENT_NODE )
ret + + ;
node = node - > next ;
}
break ;
case XML_ATTRIBUTE_NODE :
return ( - 1 ) ;
case XML_PI_NODE :
case XML_COMMENT_NODE :
case XML_TEXT_NODE :
case XML_CDATA_SECTION_NODE :
case XML_ENTITY_REF_NODE :
ret = xmlStrlen ( node - > content ) ;
break ;
default :
return ( - 1 ) ;
}
return ( ret ) ;
}
/**
* xmlXPtrHereFunction :
* @ ctxt : the XPointer Parser context
2001-03-24 20:00:36 +03:00
* @ nargs : the number of args
2001-02-23 20:55:21 +03:00
*
* Function implementing here ( ) operation
* as described in 5.4 .3
*/
void
xmlXPtrHereFunction ( xmlXPathParserContextPtr ctxt , int nargs ) {
2001-03-24 20:00:36 +03:00
CHECK_ARITY ( 0 ) ;
2001-02-23 20:55:21 +03:00
if ( ctxt - > context - > here = = NULL )
XP_ERROR ( XPTR_SYNTAX_ERROR ) ;
valuePush ( ctxt , xmlXPtrNewLocationSetNodes ( ctxt - > context - > here , NULL ) ) ;
}
/**
* xmlXPtrOriginFunction :
* @ ctxt : the XPointer Parser context
2001-03-24 20:00:36 +03:00
* @ nargs : the number of args
2001-02-23 20:55:21 +03:00
*
* Function implementing origin ( ) operation
* as described in 5.4 .3
*/
void
xmlXPtrOriginFunction ( xmlXPathParserContextPtr ctxt , int nargs ) {
2001-03-24 20:00:36 +03:00
CHECK_ARITY ( 0 ) ;
2001-02-23 20:55:21 +03:00
if ( ctxt - > context - > origin = = NULL )
XP_ERROR ( XPTR_SYNTAX_ERROR ) ;
valuePush ( ctxt , xmlXPtrNewLocationSetNodes ( ctxt - > context - > origin , NULL ) ) ;
}
/**
* xmlXPtrStartPointFunction :
* @ ctxt : the XPointer Parser context
2001-03-24 20:00:36 +03:00
* @ nargs : the number of args
2001-02-23 20:55:21 +03:00
*
* Function implementing start - point ( ) operation
* as described in 5.4 .3
* - - - - - - - - - - - - - - - -
* location - set start - point ( location - set )
*
* For each location x in the argument location - set , start - point adds a
* location of type point to the result location - set . That point represents
* the start point of location x and is determined by the following rules :
*
* - If x is of type point , the start point is x .
* - If x is of type range , the start point is the start point of x .
* - If x is of type root , element , text , comment , or processing instruction ,
* - the container node of the start point is x and the index is 0.
* - If x is of type attribute or namespace , the function must signal a
* syntax error .
* - - - - - - - - - - - - - - - -
*
*/
void
xmlXPtrStartPointFunction ( xmlXPathParserContextPtr ctxt , int nargs ) {
xmlXPathObjectPtr tmp , obj , point ;
xmlLocationSetPtr newset = NULL ;
xmlLocationSetPtr oldset = NULL ;
CHECK_ARITY ( 1 ) ;
if ( ( ctxt - > value = = NULL ) | |
( ( ctxt - > value - > type ! = XPATH_LOCATIONSET ) & &
( ctxt - > value - > type ! = XPATH_NODESET ) ) )
XP_ERROR ( XPATH_INVALID_TYPE )
obj = valuePop ( ctxt ) ;
if ( obj - > type = = XPATH_NODESET ) {
/*
* First convert to a location set
*/
tmp = xmlXPtrNewLocationSetNodeSet ( obj - > nodesetval ) ;
xmlXPathFreeObject ( obj ) ;
obj = tmp ;
}
newset = xmlXPtrLocationSetCreate ( NULL ) ;
if ( newset = = NULL ) {
xmlXPathFreeObject ( obj ) ;
XP_ERROR ( XPATH_MEMORY_ERROR ) ;
}
oldset = ( xmlLocationSetPtr ) obj - > user ;
if ( oldset ! = NULL ) {
int i ;
for ( i = 0 ; i < oldset - > locNr ; i + + ) {
tmp = oldset - > locTab [ i ] ;
if ( tmp = = NULL )
continue ;
point = NULL ;
switch ( tmp - > type ) {
case XPATH_POINT :
point = xmlXPtrNewPoint ( tmp - > user , tmp - > index ) ;
break ;
case XPATH_RANGE : {
xmlNodePtr node = tmp - > user ;
if ( node ! = NULL ) {
if ( node - > type = = XML_ATTRIBUTE_NODE ) {
/* TODO: Namespace Nodes ??? */
xmlXPathFreeObject ( obj ) ;
xmlXPtrFreeLocationSet ( newset ) ;
XP_ERROR ( XPTR_SYNTAX_ERROR ) ;
}
point = xmlXPtrNewPoint ( node , tmp - > index ) ;
}
break ;
}
default :
/*** Should we raise an error ?
xmlXPathFreeObject ( obj ) ;
xmlXPathFreeObject ( newset ) ;
XP_ERROR ( XPATH_INVALID_TYPE )
* * */
break ;
}
if ( point ! = NULL )
xmlXPtrLocationSetAdd ( newset , point ) ;
}
}
xmlXPathFreeObject ( obj ) ;
valuePush ( ctxt , xmlXPtrWrapLocationSet ( newset ) ) ;
}
/**
* xmlXPtrEndPointFunction :
* @ ctxt : the XPointer Parser context
2001-03-24 20:00:36 +03:00
* @ nargs : the number of args
2001-02-23 20:55:21 +03:00
*
* Function implementing end - point ( ) operation
* as described in 5.4 .3
* - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* location - set end - point ( location - set )
*
* For each location x in the argument location - set , end - point adds a
2001-12-31 19:16:02 +03:00
* location of type point to the result location - set . That point represents
2001-02-23 20:55:21 +03:00
* the end point of location x and is determined by the following rules :
*
* - If x is of type point , the resulting point is x .
* - If x is of type range , the resulting point is the end point of x .
* - If x is of type root or element , the container node of the resulting
* point is x and the index is the number of location children of x .
* - If x is of type text , comment , or processing instruction , the container
2001-12-31 19:16:02 +03:00
* node of the resulting point is x and the index is the length of the
2001-02-23 20:55:21 +03:00
* string - value of x .
* - If x is of type attribute or namespace , the function must signal a
* syntax error .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
void
xmlXPtrEndPointFunction ( xmlXPathParserContextPtr ctxt , int nargs ) {
xmlXPathObjectPtr tmp , obj , point ;
xmlLocationSetPtr newset = NULL ;
xmlLocationSetPtr oldset = NULL ;
CHECK_ARITY ( 1 ) ;
if ( ( ctxt - > value = = NULL ) | |
( ( ctxt - > value - > type ! = XPATH_LOCATIONSET ) & &
( ctxt - > value - > type ! = XPATH_NODESET ) ) )
XP_ERROR ( XPATH_INVALID_TYPE )
obj = valuePop ( ctxt ) ;
if ( obj - > type = = XPATH_NODESET ) {
/*
* First convert to a location set
*/
tmp = xmlXPtrNewLocationSetNodeSet ( obj - > nodesetval ) ;
xmlXPathFreeObject ( obj ) ;
obj = tmp ;
}
newset = xmlXPtrLocationSetCreate ( NULL ) ;
oldset = ( xmlLocationSetPtr ) obj - > user ;
if ( oldset ! = NULL ) {
int i ;
for ( i = 0 ; i < oldset - > locNr ; i + + ) {
tmp = oldset - > locTab [ i ] ;
if ( tmp = = NULL )
continue ;
point = NULL ;
switch ( tmp - > type ) {
case XPATH_POINT :
point = xmlXPtrNewPoint ( tmp - > user , tmp - > index ) ;
break ;
case XPATH_RANGE : {
xmlNodePtr node = tmp - > user2 ;
if ( node ! = NULL ) {
if ( node - > type = = XML_ATTRIBUTE_NODE ) {
/* TODO: Namespace Nodes ??? */
xmlXPathFreeObject ( obj ) ;
xmlXPtrFreeLocationSet ( newset ) ;
XP_ERROR ( XPTR_SYNTAX_ERROR ) ;
}
point = xmlXPtrNewPoint ( node , tmp - > index2 ) ;
} else if ( tmp - > user = = NULL ) {
point = xmlXPtrNewPoint ( node ,
xmlXPtrNbLocChildren ( node ) ) ;
}
break ;
}
default :
/*** Should we raise an error ?
xmlXPathFreeObject ( obj ) ;
xmlXPathFreeObject ( newset ) ;
XP_ERROR ( XPATH_INVALID_TYPE )
* * */
break ;
}
if ( point ! = NULL )
xmlXPtrLocationSetAdd ( newset , point ) ;
}
}
xmlXPathFreeObject ( obj ) ;
valuePush ( ctxt , xmlXPtrWrapLocationSet ( newset ) ) ;
}
/**
* xmlXPtrCoveringRange :
* @ ctxt : the XPointer Parser context
* @ loc : the location for which the covering range must be computed
*
* A covering range is a range that wholly encompasses a location
* Section 5.3 .3 . Covering Ranges for All Location Types
* http : //www.w3.org/TR/xptr#N2267
*
* Returns a new location or NULL in case of error
*/
2001-03-24 20:00:36 +03:00
static xmlXPathObjectPtr
2001-02-23 20:55:21 +03:00
xmlXPtrCoveringRange ( xmlXPathParserContextPtr ctxt , xmlXPathObjectPtr loc ) {
if ( loc = = NULL )
return ( NULL ) ;
if ( ( ctxt = = NULL ) | | ( ctxt - > context = = NULL ) | |
( ctxt - > context - > doc = = NULL ) )
return ( NULL ) ;
switch ( loc - > type ) {
case XPATH_POINT :
return ( xmlXPtrNewRange ( loc - > user , loc - > index ,
loc - > user , loc - > index ) ) ;
case XPATH_RANGE :
if ( loc - > user2 ! = NULL ) {
return ( xmlXPtrNewRange ( loc - > user , loc - > index ,
loc - > user2 , loc - > index2 ) ) ;
} else {
xmlNodePtr node = ( xmlNodePtr ) loc - > user ;
if ( node = = ( xmlNodePtr ) ctxt - > context - > doc ) {
return ( xmlXPtrNewRange ( node , 0 , node ,
xmlXPtrGetArity ( node ) ) ) ;
} else {
switch ( node - > type ) {
case XML_ATTRIBUTE_NODE :
/* !!! our model is slightly different than XPath */
return ( xmlXPtrNewRange ( node , 0 , node ,
xmlXPtrGetArity ( node ) ) ) ;
case XML_ELEMENT_NODE :
case XML_TEXT_NODE :
case XML_CDATA_SECTION_NODE :
case XML_ENTITY_REF_NODE :
case XML_PI_NODE :
case XML_COMMENT_NODE :
case XML_DOCUMENT_NODE :
case XML_NOTATION_NODE :
case XML_HTML_DOCUMENT_NODE : {
2001-03-24 20:00:36 +03:00
int indx = xmlXPtrGetIndex ( node ) ;
2001-02-23 20:55:21 +03:00
node = node - > parent ;
2001-03-24 20:00:36 +03:00
return ( xmlXPtrNewRange ( node , indx - 1 ,
node , indx + 1 ) ) ;
2001-02-23 20:55:21 +03:00
}
default :
return ( NULL ) ;
}
}
}
default :
TODO /* missed one case ??? */
}
return ( NULL ) ;
}
/**
* xmlXPtrRangeFunction :
* @ ctxt : the XPointer Parser context
2001-03-24 20:00:36 +03:00
* @ nargs : the number of args
2001-02-23 20:55:21 +03:00
*
* Function implementing the range ( ) function 5.4 .3
* location - set range ( location - set )
*
* The range function returns ranges covering the locations in
* the argument location - set . For each location x in the argument
* location - set , a range location representing the covering range of
* x is added to the result location - set .
*/
void
xmlXPtrRangeFunction ( xmlXPathParserContextPtr ctxt , int nargs ) {
int i ;
xmlXPathObjectPtr set ;
xmlLocationSetPtr oldset ;
xmlLocationSetPtr newset ;
CHECK_ARITY ( 1 ) ;
if ( ( ctxt - > value = = NULL ) | |
( ( ctxt - > value - > type ! = XPATH_LOCATIONSET ) & &
( ctxt - > value - > type ! = XPATH_NODESET ) ) )
XP_ERROR ( XPATH_INVALID_TYPE )
set = valuePop ( ctxt ) ;
if ( set - > type = = XPATH_NODESET ) {
xmlXPathObjectPtr tmp ;
/*
* First convert to a location set
*/
tmp = xmlXPtrNewLocationSetNodeSet ( set - > nodesetval ) ;
xmlXPathFreeObject ( set ) ;
set = tmp ;
}
oldset = ( xmlLocationSetPtr ) set - > user ;
/*
* The loop is to compute the covering range for each item and add it
*/
newset = xmlXPtrLocationSetCreate ( NULL ) ;
for ( i = 0 ; i < oldset - > locNr ; i + + ) {
xmlXPtrLocationSetAdd ( newset ,
xmlXPtrCoveringRange ( ctxt , oldset - > locTab [ i ] ) ) ;
}
/*
* Save the new value and cleanup
*/
valuePush ( ctxt , xmlXPtrWrapLocationSet ( newset ) ) ;
xmlXPathFreeObject ( set ) ;
}
/**
* xmlXPtrInsideRange :
* @ ctxt : the XPointer Parser context
* @ loc : the location for which the inside range must be computed
*
* A inside range is a range described in the range - inside ( ) description
*
* Returns a new location or NULL in case of error
*/
2001-03-24 20:00:36 +03:00
static xmlXPathObjectPtr
2001-02-23 20:55:21 +03:00
xmlXPtrInsideRange ( xmlXPathParserContextPtr ctxt , xmlXPathObjectPtr loc ) {
if ( loc = = NULL )
return ( NULL ) ;
if ( ( ctxt = = NULL ) | | ( ctxt - > context = = NULL ) | |
( ctxt - > context - > doc = = NULL ) )
return ( NULL ) ;
switch ( loc - > type ) {
case XPATH_POINT : {
xmlNodePtr node = ( xmlNodePtr ) loc - > user ;
switch ( node - > type ) {
case XML_PI_NODE :
case XML_COMMENT_NODE :
case XML_TEXT_NODE :
case XML_CDATA_SECTION_NODE : {
if ( node - > content = = NULL ) {
return ( xmlXPtrNewRange ( node , 0 , node , 0 ) ) ;
} else {
return ( xmlXPtrNewRange ( node , 0 , node ,
xmlStrlen ( node - > content ) ) ) ;
}
}
case XML_ATTRIBUTE_NODE :
case XML_ELEMENT_NODE :
case XML_ENTITY_REF_NODE :
case XML_DOCUMENT_NODE :
case XML_NOTATION_NODE :
case XML_HTML_DOCUMENT_NODE : {
return ( xmlXPtrNewRange ( node , 0 , node ,
xmlXPtrGetArity ( node ) ) ) ;
}
default :
2001-10-12 02:55:55 +04:00
break ;
2001-02-23 20:55:21 +03:00
}
return ( NULL ) ;
}
case XPATH_RANGE : {
xmlNodePtr node = ( xmlNodePtr ) loc - > user ;
if ( loc - > user2 ! = NULL ) {
return ( xmlXPtrNewRange ( node , loc - > index ,
loc - > user2 , loc - > index2 ) ) ;
} else {
switch ( node - > type ) {
case XML_PI_NODE :
case XML_COMMENT_NODE :
case XML_TEXT_NODE :
case XML_CDATA_SECTION_NODE : {
if ( node - > content = = NULL ) {
return ( xmlXPtrNewRange ( node , 0 , node , 0 ) ) ;
} else {
return ( xmlXPtrNewRange ( node , 0 , node ,
xmlStrlen ( node - > content ) ) ) ;
}
}
case XML_ATTRIBUTE_NODE :
case XML_ELEMENT_NODE :
case XML_ENTITY_REF_NODE :
case XML_DOCUMENT_NODE :
case XML_NOTATION_NODE :
case XML_HTML_DOCUMENT_NODE : {
return ( xmlXPtrNewRange ( node , 0 , node ,
xmlXPtrGetArity ( node ) ) ) ;
}
default :
2001-10-12 02:55:55 +04:00
break ;
2001-02-23 20:55:21 +03:00
}
return ( NULL ) ;
}
}
default :
TODO /* missed one case ??? */
}
return ( NULL ) ;
}
/**
* xmlXPtrRangeInsideFunction :
* @ ctxt : the XPointer Parser context
2001-03-24 20:00:36 +03:00
* @ nargs : the number of args
2001-02-23 20:55:21 +03:00
*
* Function implementing the range - inside ( ) function 5.4 .3
* location - set range - inside ( location - set )
*
* The range - inside function returns ranges covering the contents of
* the locations in the argument location - set . For each location x in
* the argument location - set , a range location is added to the result
* location - set . If x is a range location , then x is added to the
* result location - set . If x is not a range location , then x is used
* as the container location of the start and end points of the range
* location to be added ; the index of the start point of the range is
* zero ; if the end point is a character point then its index is the
* length of the string - value of x , and otherwise is the number of
* location children of x .
*
*/
void
xmlXPtrRangeInsideFunction ( xmlXPathParserContextPtr ctxt , int nargs ) {
int i ;
xmlXPathObjectPtr set ;
xmlLocationSetPtr oldset ;
xmlLocationSetPtr newset ;
CHECK_ARITY ( 1 ) ;
if ( ( ctxt - > value = = NULL ) | |
( ( ctxt - > value - > type ! = XPATH_LOCATIONSET ) & &
( ctxt - > value - > type ! = XPATH_NODESET ) ) )
XP_ERROR ( XPATH_INVALID_TYPE )
set = valuePop ( ctxt ) ;
if ( set - > type = = XPATH_NODESET ) {
xmlXPathObjectPtr tmp ;
/*
* First convert to a location set
*/
tmp = xmlXPtrNewLocationSetNodeSet ( set - > nodesetval ) ;
xmlXPathFreeObject ( set ) ;
set = tmp ;
}
oldset = ( xmlLocationSetPtr ) set - > user ;
/*
* The loop is to compute the covering range for each item and add it
*/
newset = xmlXPtrLocationSetCreate ( NULL ) ;
for ( i = 0 ; i < oldset - > locNr ; i + + ) {
xmlXPtrLocationSetAdd ( newset ,
xmlXPtrInsideRange ( ctxt , oldset - > locTab [ i ] ) ) ;
}
/*
* Save the new value and cleanup
*/
valuePush ( ctxt , xmlXPtrWrapLocationSet ( newset ) ) ;
xmlXPathFreeObject ( set ) ;
}
/**
* xmlXPtrRangeToFunction :
* @ ctxt : the XPointer Parser context
2001-03-24 20:00:36 +03:00
* @ nargs : the number of args
2001-02-23 20:55:21 +03:00
*
* Implement the range - to ( ) XPointer function
*/
void
xmlXPtrRangeToFunction ( xmlXPathParserContextPtr ctxt , int nargs ) {
xmlXPathObjectPtr range ;
const xmlChar * cur ;
xmlXPathObjectPtr res , obj ;
xmlXPathObjectPtr tmp ;
xmlLocationSetPtr newset = NULL ;
xmlNodeSetPtr oldset ;
int i ;
2004-11-05 20:22:25 +03:00
if ( ctxt = = NULL ) return ;
2001-02-23 20:55:21 +03:00
CHECK_ARITY ( 1 ) ;
/*
* Save the expression pointer since we will have to evaluate
* it multiple times . Initialize the new set .
*/
CHECK_TYPE ( XPATH_NODESET ) ;
obj = valuePop ( ctxt ) ;
oldset = obj - > nodesetval ;
ctxt - > context - > node = NULL ;
cur = ctxt - > cur ;
newset = xmlXPtrLocationSetCreate ( NULL ) ;
for ( i = 0 ; i < oldset - > nodeNr ; i + + ) {
ctxt - > cur = cur ;
/*
* Run the evaluation with a node list made of a single item
* in the nodeset .
*/
ctxt - > context - > node = oldset - > nodeTab [ i ] ;
tmp = xmlXPathNewNodeSet ( ctxt - > context - > node ) ;
valuePush ( ctxt , tmp ) ;
xmlXPathEvalExpr ( ctxt ) ;
CHECK_ERROR ;
/*
* The result of the evaluation need to be tested to
* decided whether the filter succeeded or not
*/
res = valuePop ( ctxt ) ;
range = xmlXPtrNewRangeNodeObject ( oldset - > nodeTab [ i ] , res ) ;
if ( range ! = NULL ) {
xmlXPtrLocationSetAdd ( newset , range ) ;
}
/*
* Cleanup
*/
if ( res ! = NULL )
xmlXPathFreeObject ( res ) ;
if ( ctxt - > value = = tmp ) {
res = valuePop ( ctxt ) ;
xmlXPathFreeObject ( res ) ;
}
ctxt - > context - > node = NULL ;
}
/*
* The result is used as the new evaluation set .
*/
xmlXPathFreeObject ( obj ) ;
ctxt - > context - > node = NULL ;
ctxt - > context - > contextSize = - 1 ;
ctxt - > context - > proximityPosition = - 1 ;
valuePush ( ctxt , xmlXPtrWrapLocationSet ( newset ) ) ;
}
/**
* xmlXPtrAdvanceNode :
* @ cur : the node
2004-01-22 05:47:18 +03:00
* @ level : incremented / decremented to show level in tree
2001-02-23 20:55:21 +03:00
*
* Advance to the next element or text node in document order
* TODO : add a stack for entering / exiting entities
*
* Returns - 1 in case of failure , 0 otherwise
*/
xmlNodePtr
2003-12-31 10:59:17 +03:00
xmlXPtrAdvanceNode ( xmlNodePtr cur , int * level ) {
2001-02-23 20:55:21 +03:00
next :
if ( cur = = NULL )
return ( NULL ) ;
if ( cur - > children ! = NULL ) {
cur = cur - > children ;
2003-12-31 10:59:17 +03:00
if ( level ! = NULL )
( * level ) + + ;
2001-02-23 20:55:21 +03:00
goto found ;
}
2004-03-08 17:42:31 +03:00
skip : /* This label should only be needed if something is wrong! */
2001-02-23 20:55:21 +03:00
if ( cur - > next ! = NULL ) {
cur = cur - > next ;
goto found ;
}
do {
cur = cur - > parent ;
2003-12-31 10:59:17 +03:00
if ( level ! = NULL )
( * level ) - - ;
2001-02-23 20:55:21 +03:00
if ( cur = = NULL ) return ( NULL ) ;
if ( cur - > next ! = NULL ) {
cur = cur - > next ;
goto found ;
}
} while ( cur ! = NULL ) ;
found :
if ( ( cur - > type ! = XML_ELEMENT_NODE ) & &
( cur - > type ! = XML_TEXT_NODE ) & &
( cur - > type ! = XML_DOCUMENT_NODE ) & &
( cur - > type ! = XML_HTML_DOCUMENT_NODE ) & &
2004-03-08 17:42:31 +03:00
( cur - > type ! = XML_CDATA_SECTION_NODE ) ) {
if ( cur - > type = = XML_ENTITY_REF_NODE ) { /* Shouldn't happen */
TODO
goto skip ;
}
goto next ;
}
2001-02-23 20:55:21 +03:00
return ( cur ) ;
}
/**
* xmlXPtrAdvanceChar :
* @ node : the node
2001-03-24 20:00:36 +03:00
* @ indx : the indx
2001-02-23 20:55:21 +03:00
* @ bytes : the number of bytes
*
* Advance a point of the associated number of bytes ( not UTF8 chars )
*
* Returns - 1 in case of failure , 0 otherwise
*/
2001-03-24 20:00:36 +03:00
static int
xmlXPtrAdvanceChar ( xmlNodePtr * node , int * indx , int bytes ) {
2001-02-23 20:55:21 +03:00
xmlNodePtr cur ;
int pos ;
int len ;
2001-03-24 20:00:36 +03:00
if ( ( node = = NULL ) | | ( indx = = NULL ) )
2001-02-23 20:55:21 +03:00
return ( - 1 ) ;
cur = * node ;
if ( cur = = NULL )
return ( - 1 ) ;
2001-03-24 20:00:36 +03:00
pos = * indx ;
2001-02-23 20:55:21 +03:00
while ( bytes > = 0 ) {
/*
* First position to the beginning of the first text node
* corresponding to this point
*/
while ( ( cur ! = NULL ) & &
( ( cur - > type = = XML_ELEMENT_NODE ) | |
( cur - > type = = XML_DOCUMENT_NODE ) | |
( cur - > type = = XML_HTML_DOCUMENT_NODE ) ) ) {
if ( pos > 0 ) {
cur = xmlXPtrGetNthChild ( cur , pos ) ;
pos = 0 ;
} else {
2003-12-31 10:59:17 +03:00
cur = xmlXPtrAdvanceNode ( cur , NULL ) ;
2001-02-23 20:55:21 +03:00
pos = 0 ;
}
}
if ( cur = = NULL ) {
* node = NULL ;
2001-03-24 20:00:36 +03:00
* indx = 0 ;
2001-02-23 20:55:21 +03:00
return ( - 1 ) ;
}
/*
* if there is no move needed return the current value .
*/
if ( pos = = 0 ) pos = 1 ;
if ( bytes = = 0 ) {
* node = cur ;
2001-03-24 20:00:36 +03:00
* indx = pos ;
2001-02-23 20:55:21 +03:00
return ( 0 ) ;
}
/*
* We should have a text ( or cdata ) node . . .
*/
len = 0 ;
2001-07-12 05:20:08 +04:00
if ( ( cur - > type ! = XML_ELEMENT_NODE ) & &
( cur - > content ! = NULL ) ) {
2001-02-23 20:55:21 +03:00
len = xmlStrlen ( cur - > content ) ;
}
if ( pos > len ) {
2001-03-24 20:00:36 +03:00
/* Strange, the indx in the text node is greater than it's len */
2001-02-23 20:55:21 +03:00
STRANGE
pos = len ;
}
if ( pos + bytes > = len ) {
bytes - = ( len - pos ) ;
2003-12-31 10:59:17 +03:00
cur = xmlXPtrAdvanceNode ( cur , NULL ) ;
2001-02-23 20:55:21 +03:00
cur = 0 ;
} else if ( pos + bytes < len ) {
pos + = bytes ;
* node = cur ;
2001-03-24 20:00:36 +03:00
* indx = pos ;
2001-02-23 20:55:21 +03:00
return ( 0 ) ;
}
}
return ( - 1 ) ;
}
/**
* xmlXPtrMatchString :
* @ string : the string to search
* @ start : the start textnode
* @ startindex : the start index
* @ end : the end textnode IN / OUT
* @ endindex : the end index IN / OUT
*
* Check whether the document contains @ string at the position
* ( @ start , @ startindex ) and limited by the ( @ end , @ endindex ) point
*
* Returns - 1 in case of failure , 0 if not found , 1 if found in which case
* ( @ start , @ startindex ) will indicate the position of the beginning
2001-12-31 19:16:02 +03:00
* of the range and ( @ end , @ endindex ) will indicate the end
2001-02-23 20:55:21 +03:00
* of the range
*/
2001-03-24 20:00:36 +03:00
static int
2001-02-23 20:55:21 +03:00
xmlXPtrMatchString ( const xmlChar * string , xmlNodePtr start , int startindex ,
xmlNodePtr * end , int * endindex ) {
xmlNodePtr cur ;
int pos ; /* 0 based */
int len ; /* in bytes */
int stringlen ; /* in bytes */
int match ;
if ( string = = NULL )
return ( - 1 ) ;
if ( start = = NULL )
return ( - 1 ) ;
if ( ( end = = NULL ) | | ( endindex = = NULL ) )
return ( - 1 ) ;
cur = start ;
if ( cur = = NULL )
return ( - 1 ) ;
pos = startindex - 1 ;
stringlen = xmlStrlen ( string ) ;
while ( stringlen > 0 ) {
if ( ( cur = = * end ) & & ( pos + stringlen > * endindex ) )
return ( 0 ) ;
2001-07-12 05:20:08 +04:00
if ( ( cur - > type ! = XML_ELEMENT_NODE ) & & ( cur - > content ! = NULL ) ) {
2001-02-23 20:55:21 +03:00
len = xmlStrlen ( cur - > content ) ;
if ( len > = pos + stringlen ) {
match = ( ! xmlStrncmp ( & cur - > content [ pos ] , string , stringlen ) ) ;
if ( match ) {
# ifdef DEBUG_RANGES
xmlGenericError ( xmlGenericErrorContext ,
" found range %d bytes at index %d of -> " ,
stringlen , pos + 1 ) ;
xmlDebugDumpString ( stdout , cur - > content ) ;
xmlGenericError ( xmlGenericErrorContext , " \n " ) ;
# endif
* end = cur ;
* endindex = pos + stringlen ;
return ( 1 ) ;
} else {
return ( 0 ) ;
}
} else {
int sub = len - pos ;
match = ( ! xmlStrncmp ( & cur - > content [ pos ] , string , sub ) ) ;
if ( match ) {
# ifdef DEBUG_RANGES
xmlGenericError ( xmlGenericErrorContext ,
" found subrange %d bytes at index %d of -> " ,
sub , pos + 1 ) ;
xmlDebugDumpString ( stdout , cur - > content ) ;
xmlGenericError ( xmlGenericErrorContext , " \n " ) ;
# endif
string = & string [ sub ] ;
stringlen - = sub ;
} else {
return ( 0 ) ;
}
}
}
2003-12-31 10:59:17 +03:00
cur = xmlXPtrAdvanceNode ( cur , NULL ) ;
2001-02-23 20:55:21 +03:00
if ( cur = = NULL )
return ( 0 ) ;
pos = 0 ;
}
return ( 1 ) ;
}
/**
* xmlXPtrSearchString :
* @ string : the string to search
* @ start : the start textnode IN / OUT
* @ startindex : the start index IN / OUT
* @ end : the end textnode
* @ endindex : the end index
*
2001-12-31 19:16:02 +03:00
* Search the next occurrence of @ string within the document content
2001-02-23 20:55:21 +03:00
* until the ( @ end , @ endindex ) point is reached
*
* Returns - 1 in case of failure , 0 if not found , 1 if found in which case
* ( @ start , @ startindex ) will indicate the position of the beginning
2001-12-31 19:16:02 +03:00
* of the range and ( @ end , @ endindex ) will indicate the end
2001-02-23 20:55:21 +03:00
* of the range
*/
2001-03-24 20:00:36 +03:00
static int
2001-02-23 20:55:21 +03:00
xmlXPtrSearchString ( const xmlChar * string , xmlNodePtr * start , int * startindex ,
xmlNodePtr * end , int * endindex ) {
xmlNodePtr cur ;
const xmlChar * str ;
int pos ; /* 0 based */
int len ; /* in bytes */
xmlChar first ;
if ( string = = NULL )
return ( - 1 ) ;
if ( ( start = = NULL ) | | ( startindex = = NULL ) )
return ( - 1 ) ;
if ( ( end = = NULL ) | | ( endindex = = NULL ) )
return ( - 1 ) ;
cur = * start ;
if ( cur = = NULL )
return ( - 1 ) ;
pos = * startindex - 1 ;
first = string [ 0 ] ;
while ( cur ! = NULL ) {
2001-07-12 05:20:08 +04:00
if ( ( cur - > type ! = XML_ELEMENT_NODE ) & & ( cur - > content ! = NULL ) ) {
2001-02-23 20:55:21 +03:00
len = xmlStrlen ( cur - > content ) ;
while ( pos < = len ) {
if ( first ! = 0 ) {
str = xmlStrchr ( & cur - > content [ pos ] , first ) ;
if ( str ! = NULL ) {
pos = ( str - ( xmlChar * ) ( cur - > content ) ) ;
# ifdef DEBUG_RANGES
xmlGenericError ( xmlGenericErrorContext ,
" found '%c' at index %d of -> " ,
first , pos + 1 ) ;
xmlDebugDumpString ( stdout , cur - > content ) ;
xmlGenericError ( xmlGenericErrorContext , " \n " ) ;
# endif
if ( xmlXPtrMatchString ( string , cur , pos + 1 ,
end , endindex ) ) {
* start = cur ;
* startindex = pos + 1 ;
return ( 1 ) ;
}
pos + + ;
} else {
pos = len + 1 ;
}
} else {
/*
* An empty string is considered to match before each
* character of the string - value and after the final
* character .
*/
# ifdef DEBUG_RANGES
xmlGenericError ( xmlGenericErrorContext ,
" found '' at index %d of -> " ,
pos + 1 ) ;
xmlDebugDumpString ( stdout , cur - > content ) ;
xmlGenericError ( xmlGenericErrorContext , " \n " ) ;
# endif
* start = cur ;
* startindex = pos + 1 ;
* end = cur ;
* endindex = pos + 1 ;
return ( 1 ) ;
}
}
}
if ( ( cur = = * end ) & & ( pos > = * endindex ) )
return ( 0 ) ;
2003-12-31 10:59:17 +03:00
cur = xmlXPtrAdvanceNode ( cur , NULL ) ;
2001-02-23 20:55:21 +03:00
if ( cur = = NULL )
return ( 0 ) ;
pos = 1 ;
}
return ( 0 ) ;
}
/**
* xmlXPtrGetLastChar :
* @ node : the node
* @ index : the index
*
* Computes the point coordinates of the last char of this point
*
* Returns - 1 in case of failure , 0 otherwise
*/
2001-03-24 20:00:36 +03:00
static int
xmlXPtrGetLastChar ( xmlNodePtr * node , int * indx ) {
2001-02-23 20:55:21 +03:00
xmlNodePtr cur ;
int pos , len = 0 ;
2001-03-24 20:00:36 +03:00
if ( ( node = = NULL ) | | ( indx = = NULL ) )
2001-02-23 20:55:21 +03:00
return ( - 1 ) ;
cur = * node ;
2001-03-24 20:00:36 +03:00
pos = * indx ;
2001-02-23 20:55:21 +03:00
if ( cur = = NULL )
return ( - 1 ) ;
if ( ( cur - > type = = XML_ELEMENT_NODE ) | |
( cur - > type = = XML_DOCUMENT_NODE ) | |
( cur - > type = = XML_HTML_DOCUMENT_NODE ) ) {
if ( pos > 0 ) {
cur = xmlXPtrGetNthChild ( cur , pos ) ;
pos = 0 ;
}
}
while ( cur ! = NULL ) {
if ( cur - > last ! = NULL )
cur = cur - > last ;
2001-07-12 05:20:08 +04:00
else if ( ( cur - > type ! = XML_ELEMENT_NODE ) & &
( cur - > content ! = NULL ) ) {
2001-02-23 20:55:21 +03:00
len = xmlStrlen ( cur - > content ) ;
break ;
} else {
return ( - 1 ) ;
}
}
if ( cur = = NULL )
return ( - 1 ) ;
* node = cur ;
2001-03-24 20:00:36 +03:00
* indx = len ;
2001-02-23 20:55:21 +03:00
return ( 0 ) ;
}
/**
* xmlXPtrGetStartPoint :
* @ obj : an range
* @ node : the resulting node
2001-03-24 20:00:36 +03:00
* @ indx : the resulting index
2001-02-23 20:55:21 +03:00
*
* read the object and return the start point coordinates .
*
* Returns - 1 in case of failure , 0 otherwise
*/
2001-03-24 20:00:36 +03:00
static int
xmlXPtrGetStartPoint ( xmlXPathObjectPtr obj , xmlNodePtr * node , int * indx ) {
if ( ( obj = = NULL ) | | ( node = = NULL ) | | ( indx = = NULL ) )
2001-02-23 20:55:21 +03:00
return ( - 1 ) ;
switch ( obj - > type ) {
case XPATH_POINT :
* node = obj - > user ;
if ( obj - > index < = 0 )
2001-03-24 20:00:36 +03:00
* indx = 0 ;
2001-02-23 20:55:21 +03:00
else
2001-03-24 20:00:36 +03:00
* indx = obj - > index ;
2001-02-23 20:55:21 +03:00
return ( 0 ) ;
case XPATH_RANGE :
* node = obj - > user ;
if ( obj - > index < = 0 )
2001-03-24 20:00:36 +03:00
* indx = 0 ;
2001-02-23 20:55:21 +03:00
else
2001-03-24 20:00:36 +03:00
* indx = obj - > index ;
2001-02-23 20:55:21 +03:00
return ( 0 ) ;
default :
2001-10-12 02:55:55 +04:00
break ;
2001-02-23 20:55:21 +03:00
}
return ( - 1 ) ;
}
/**
* xmlXPtrGetEndPoint :
* @ obj : an range
* @ node : the resulting node
2001-03-24 20:00:36 +03:00
* @ indx : the resulting indx
2001-02-23 20:55:21 +03:00
*
* read the object and return the end point coordinates .
*
* Returns - 1 in case of failure , 0 otherwise
*/
2001-03-24 20:00:36 +03:00
static int
xmlXPtrGetEndPoint ( xmlXPathObjectPtr obj , xmlNodePtr * node , int * indx ) {
if ( ( obj = = NULL ) | | ( node = = NULL ) | | ( indx = = NULL ) )
2001-02-23 20:55:21 +03:00
return ( - 1 ) ;
switch ( obj - > type ) {
case XPATH_POINT :
* node = obj - > user ;
if ( obj - > index < = 0 )
2001-03-24 20:00:36 +03:00
* indx = 0 ;
2001-02-23 20:55:21 +03:00
else
2001-03-24 20:00:36 +03:00
* indx = obj - > index ;
2001-02-23 20:55:21 +03:00
return ( 0 ) ;
case XPATH_RANGE :
* node = obj - > user ;
if ( obj - > index < = 0 )
2001-03-24 20:00:36 +03:00
* indx = 0 ;
2001-02-23 20:55:21 +03:00
else
2001-03-24 20:00:36 +03:00
* indx = obj - > index ;
2001-02-23 20:55:21 +03:00
return ( 0 ) ;
default :
2001-10-12 02:55:55 +04:00
break ;
2001-02-23 20:55:21 +03:00
}
return ( - 1 ) ;
}
/**
* xmlXPtrStringRangeFunction :
* @ ctxt : the XPointer Parser context
2001-03-24 20:00:36 +03:00
* @ nargs : the number of args
2001-02-23 20:55:21 +03:00
*
* Function implementing the string - range ( ) function
* range as described in 5.4 .2
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* [ Definition : For each location in the location - set argument ,
* string - range returns a set of string ranges , a set of substrings in a
* string . Specifically , the string - value of the location is searched for
* substrings that match the string argument , and the resulting location - set
* will contain a range location for each non - overlapping match . ]
* An empty string is considered to match before each character of the
* string - value and after the final character . Whitespace in a string
* is matched literally , with no normalization except that provided by
* XML for line ends . The third argument gives the position of the first
* character to be in the resulting range , relative to the start of the
* match . The default value is 1 , which makes the range start immediately
* before the first character of the matched string . The fourth argument
* gives the number of characters in the range ; the default is that the
* range extends to the end of the matched string .
*
* Element boundaries , as well as entire embedded nodes such as processing
* instructions and comments , are ignored as defined in [ XPath ] .
*
* If the string in the second argument is not found in the string - value
* of the location , or if a value in the third or fourth argument indicates
* a string that is beyond the beginning or end of the document , the
* expression fails .
*
* The points of the range - locations in the returned location - set will
* all be character points .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
void
xmlXPtrStringRangeFunction ( xmlXPathParserContextPtr ctxt , int nargs ) {
int i , startindex , endindex , fendindex ;
xmlNodePtr start , end , fend ;
xmlXPathObjectPtr set ;
xmlLocationSetPtr oldset ;
xmlLocationSetPtr newset ;
xmlXPathObjectPtr string ;
xmlXPathObjectPtr position = NULL ;
xmlXPathObjectPtr number = NULL ;
2001-03-24 20:00:36 +03:00
int found , pos = 0 , num = 0 ;
2001-02-23 20:55:21 +03:00
/*
* Grab the arguments
*/
if ( ( nargs < 2 ) | | ( nargs > 4 ) )
XP_ERROR ( XPATH_INVALID_ARITY ) ;
if ( nargs > = 4 ) {
CHECK_TYPE ( XPATH_NUMBER ) ;
number = valuePop ( ctxt ) ;
if ( number ! = NULL )
2001-06-28 16:54:16 +04:00
num = ( int ) number - > floatval ;
2001-02-23 20:55:21 +03:00
}
if ( nargs > = 3 ) {
CHECK_TYPE ( XPATH_NUMBER ) ;
position = valuePop ( ctxt ) ;
if ( position ! = NULL )
2001-06-28 16:54:16 +04:00
pos = ( int ) position - > floatval ;
2001-02-23 20:55:21 +03:00
}
CHECK_TYPE ( XPATH_STRING ) ;
string = valuePop ( ctxt ) ;
if ( ( ctxt - > value = = NULL ) | |
( ( ctxt - > value - > type ! = XPATH_LOCATIONSET ) & &
( ctxt - > value - > type ! = XPATH_NODESET ) ) )
XP_ERROR ( XPATH_INVALID_TYPE )
set = valuePop ( ctxt ) ;
2003-12-29 05:52:11 +03:00
newset = xmlXPtrLocationSetCreate ( NULL ) ;
if ( set - > nodesetval = = NULL ) {
goto error ;
}
2001-02-23 20:55:21 +03:00
if ( set - > type = = XPATH_NODESET ) {
xmlXPathObjectPtr tmp ;
/*
* First convert to a location set
*/
tmp = xmlXPtrNewLocationSetNodeSet ( set - > nodesetval ) ;
xmlXPathFreeObject ( set ) ;
set = tmp ;
}
oldset = ( xmlLocationSetPtr ) set - > user ;
/*
* The loop is to search for each element in the location set
* the list of location set corresponding to that search
*/
for ( i = 0 ; i < oldset - > locNr ; i + + ) {
# ifdef DEBUG_RANGES
xmlXPathDebugDumpObject ( stdout , oldset - > locTab [ i ] , 0 ) ;
# endif
xmlXPtrGetStartPoint ( oldset - > locTab [ i ] , & start , & startindex ) ;
xmlXPtrGetEndPoint ( oldset - > locTab [ i ] , & end , & endindex ) ;
xmlXPtrAdvanceChar ( & start , & startindex , 0 ) ;
xmlXPtrGetLastChar ( & end , & endindex ) ;
# ifdef DEBUG_RANGES
xmlGenericError ( xmlGenericErrorContext ,
" from index %d of -> " , startindex ) ;
xmlDebugDumpString ( stdout , start - > content ) ;
xmlGenericError ( xmlGenericErrorContext , " \n " ) ;
xmlGenericError ( xmlGenericErrorContext ,
" to index %d of -> " , endindex ) ;
xmlDebugDumpString ( stdout , end - > content ) ;
xmlGenericError ( xmlGenericErrorContext , " \n " ) ;
# endif
do {
fend = end ;
fendindex = endindex ;
found = xmlXPtrSearchString ( string - > stringval , & start , & startindex ,
& fend , & fendindex ) ;
if ( found = = 1 ) {
if ( position = = NULL ) {
xmlXPtrLocationSetAdd ( newset ,
xmlXPtrNewRange ( start , startindex , fend , fendindex ) ) ;
} else if ( xmlXPtrAdvanceChar ( & start , & startindex ,
pos - 1 ) = = 0 ) {
if ( ( number ! = NULL ) & & ( num > 0 ) ) {
2001-03-24 20:00:36 +03:00
int rindx ;
2001-02-23 20:55:21 +03:00
xmlNodePtr rend ;
rend = start ;
2001-03-24 20:00:36 +03:00
rindx = startindex - 1 ;
if ( xmlXPtrAdvanceChar ( & rend , & rindx ,
2001-02-23 20:55:21 +03:00
num ) = = 0 ) {
xmlXPtrLocationSetAdd ( newset ,
xmlXPtrNewRange ( start , startindex ,
2001-03-24 20:00:36 +03:00
rend , rindx ) ) ;
2001-02-23 20:55:21 +03:00
}
} else if ( ( number ! = NULL ) & & ( num < = 0 ) ) {
xmlXPtrLocationSetAdd ( newset ,
xmlXPtrNewRange ( start , startindex ,
start , startindex ) ) ;
} else {
xmlXPtrLocationSetAdd ( newset ,
xmlXPtrNewRange ( start , startindex ,
fend , fendindex ) ) ;
}
}
start = fend ;
startindex = fendindex ;
if ( string - > stringval [ 0 ] = = 0 )
startindex + + ;
}
} while ( found = = 1 ) ;
}
/*
* Save the new value and cleanup
*/
2003-12-29 05:52:11 +03:00
error :
2001-02-23 20:55:21 +03:00
valuePush ( ctxt , xmlXPtrWrapLocationSet ( newset ) ) ;
xmlXPathFreeObject ( set ) ;
xmlXPathFreeObject ( string ) ;
if ( position ) xmlXPathFreeObject ( position ) ;
if ( number ) xmlXPathFreeObject ( number ) ;
}
/**
* xmlXPtrEvalRangePredicate :
* @ ctxt : the XPointer Parser context
*
* [ 8 ] Predicate : : = ' [ ' PredicateExpr ' ] '
* [ 9 ] PredicateExpr : : = Expr
*
* Evaluate a predicate as in xmlXPathEvalPredicate ( ) but for
* a Location Set instead of a node set
*/
void
xmlXPtrEvalRangePredicate ( xmlXPathParserContextPtr ctxt ) {
const xmlChar * cur ;
xmlXPathObjectPtr res ;
xmlXPathObjectPtr obj , tmp ;
xmlLocationSetPtr newset = NULL ;
xmlLocationSetPtr oldset ;
int i ;
2004-11-05 20:22:25 +03:00
if ( ctxt = = NULL ) return ;
2001-02-23 20:55:21 +03:00
SKIP_BLANKS ;
if ( CUR ! = ' [ ' ) {
XP_ERROR ( XPATH_INVALID_PREDICATE_ERROR ) ;
}
NEXT ;
SKIP_BLANKS ;
/*
* Extract the old set , and then evaluate the result of the
* expression for all the element in the set . use it to grow
* up a new set .
*/
CHECK_TYPE ( XPATH_LOCATIONSET ) ;
obj = valuePop ( ctxt ) ;
oldset = obj - > user ;
ctxt - > context - > node = NULL ;
if ( ( oldset = = NULL ) | | ( oldset - > locNr = = 0 ) ) {
ctxt - > context - > contextSize = 0 ;
ctxt - > context - > proximityPosition = 0 ;
xmlXPathEvalExpr ( ctxt ) ;
res = valuePop ( ctxt ) ;
if ( res ! = NULL )
xmlXPathFreeObject ( res ) ;
valuePush ( ctxt , obj ) ;
CHECK_ERROR ;
} else {
/*
* Save the expression pointer since we will have to evaluate
* it multiple times . Initialize the new set .
*/
cur = ctxt - > cur ;
newset = xmlXPtrLocationSetCreate ( NULL ) ;
for ( i = 0 ; i < oldset - > locNr ; i + + ) {
ctxt - > cur = cur ;
/*
* Run the evaluation with a node list made of a single item
* in the nodeset .
*/
ctxt - > context - > node = oldset - > locTab [ i ] - > user ;
tmp = xmlXPathNewNodeSet ( ctxt - > context - > node ) ;
valuePush ( ctxt , tmp ) ;
ctxt - > context - > contextSize = oldset - > locNr ;
ctxt - > context - > proximityPosition = i + 1 ;
xmlXPathEvalExpr ( ctxt ) ;
CHECK_ERROR ;
/*
* The result of the evaluation need to be tested to
* decided whether the filter succeeded or not
*/
res = valuePop ( ctxt ) ;
if ( xmlXPathEvaluatePredicateResult ( ctxt , res ) ) {
xmlXPtrLocationSetAdd ( newset ,
xmlXPathObjectCopy ( oldset - > locTab [ i ] ) ) ;
}
/*
* Cleanup
*/
if ( res ! = NULL )
xmlXPathFreeObject ( res ) ;
if ( ctxt - > value = = tmp ) {
res = valuePop ( ctxt ) ;
xmlXPathFreeObject ( res ) ;
}
ctxt - > context - > node = NULL ;
}
/*
* The result is used as the new evaluation set .
*/
xmlXPathFreeObject ( obj ) ;
ctxt - > context - > node = NULL ;
ctxt - > context - > contextSize = - 1 ;
ctxt - > context - > proximityPosition = - 1 ;
valuePush ( ctxt , xmlXPtrWrapLocationSet ( newset ) ) ;
}
if ( CUR ! = ' ] ' ) {
XP_ERROR ( XPATH_INVALID_PREDICATE_ERROR ) ;
}
NEXT ;
SKIP_BLANKS ;
}
2005-04-01 17:11:58 +04:00
# define bottom_xpointer
# include "elfgcchack.h"
2001-02-23 20:55:21 +03:00
# endif