2003-12-03 01:32:15 +03:00
/*
2019-09-30 18:04:54 +03:00
* pattern . c : Implementation of selectors for nodes
2003-12-03 01:32:15 +03:00
*
* Reference :
* http : //www.w3.org/TR/2001/REC-xmlschema-1-20010502/
2012-09-11 09:26:36 +04:00
* to some extent
2003-12-03 01:32:15 +03:00
* http : //www.w3.org/TR/1999/REC-xml-19991116
*
* See Copyright for the status of this software .
*
* daniel @ veillard . com
*/
2005-01-31 01:36:30 +03:00
/*
* TODO :
* - compilation flags to check for specific syntaxes
* using flags of xmlPatterncompile ( )
* - making clear how pattern starting with / or . need to be handled ,
* currently push ( NULL , NULL ) means a reset of the streaming context
* and indicating we are on / ( the document node ) , probably need
* something similar for .
2005-02-04 01:24:10 +03:00
* - get rid of the " compile " starting with lowercase
2006-05-16 19:13:37 +04:00
* - DONE ( 2006 - 05 - 16 ) : get rid of the Strdup / Strndup in case of dictionary
2005-01-31 01:36:30 +03:00
*/
2003-12-03 01:32:15 +03:00
# define IN_LIBXML
# include "libxml.h"
# include <string.h>
2023-09-21 01:44:50 +03:00
# include <libxml/pattern.h>
2003-12-03 01:32:15 +03:00
# include <libxml/xmlmemory.h>
# include <libxml/tree.h>
# include <libxml/dict.h>
# include <libxml/xmlerror.h>
# include <libxml/parserInternals.h>
2005-02-04 01:24:10 +03:00
# ifdef LIBXML_PATTERN_ENABLED
2003-12-03 01:32:15 +03:00
2012-05-10 16:24:00 +04:00
# ifdef ERROR
# undef ERROR
# endif
2003-12-03 01:32:15 +03:00
# define ERROR(a, b, c, d)
# define ERROR5(a, b, c, d, e)
2005-01-30 21:42:55 +03:00
# define XML_STREAM_STEP_DESC 1
# define XML_STREAM_STEP_FINAL 2
# define XML_STREAM_STEP_ROOT 4
2005-02-18 00:34:45 +03:00
# define XML_STREAM_STEP_ATTR 8
2006-01-05 15:30:43 +03:00
# define XML_STREAM_STEP_NODE 16
2006-01-05 17:44:45 +03:00
# define XML_STREAM_STEP_IN_SET 32
2005-01-30 21:42:55 +03:00
2005-06-14 23:24:47 +04:00
/*
2006-01-05 15:30:43 +03:00
* NOTE : Those private flags ( XML_STREAM_xxx ) are used
* in _xmlStreamCtxt - > flag . They extend the public
2019-09-30 18:04:54 +03:00
* xmlPatternFlags , so be careful not to interfere with the
2012-09-11 09:26:36 +04:00
* reserved values for xmlPatternFlags .
2005-06-14 23:24:47 +04:00
*/
2006-01-05 15:30:43 +03:00
# define XML_STREAM_FINAL_IS_ANY_NODE 1<<14
# define XML_STREAM_FROM_ROOT 1<<15
2005-06-14 23:24:47 +04:00
# define XML_STREAM_DESC 1<<16
2006-01-05 15:30:43 +03:00
/*
* XML_STREAM_ANY_NODE is used for comparison against
* xmlElementType enums , to indicate a node of any type .
*/
# define XML_STREAM_ANY_NODE 100
2005-06-09 22:12:28 +04:00
# define XML_PATTERN_NOTPATTERN (XML_PATTERN_XPATH | \
XML_PATTERN_XSSEL | \
XML_PATTERN_XSFIELD )
2005-06-14 23:24:47 +04:00
2005-10-19 21:00:53 +04:00
# define XML_STREAM_XS_IDC(c) ((c)->flags & \
2005-06-14 23:24:47 +04:00
( XML_PATTERN_XSSEL | XML_PATTERN_XSFIELD ) )
2005-03-04 21:04:59 +03:00
2005-10-19 21:00:53 +04:00
# define XML_STREAM_XS_IDC_SEL(c) ((c)->flags & XML_PATTERN_XSSEL)
# define XML_STREAM_XS_IDC_FIELD(c) ((c)->flags & XML_PATTERN_XSFIELD)
2006-05-16 19:13:37 +04:00
# define XML_PAT_COPY_NSNAME(c, r, nsname) \
if ( ( c ) - > comp - > dict ) \
r = ( xmlChar * ) xmlDictLookup ( ( c ) - > comp - > dict , BAD_CAST nsname , - 1 ) ; \
else r = xmlStrdup ( BAD_CAST nsname ) ;
# define XML_PAT_FREE_STRING(c, r) if ((c)->comp->dict == NULL) xmlFree(r);
2005-01-30 21:42:55 +03:00
typedef struct _xmlStreamStep xmlStreamStep ;
typedef xmlStreamStep * xmlStreamStepPtr ;
struct _xmlStreamStep {
int flags ; /* properties of that step */
const xmlChar * name ; /* first string value if NULL accept all */
const xmlChar * ns ; /* second string value */
2006-01-05 15:30:43 +03:00
int nodeType ; /* type of node */
2005-01-30 21:42:55 +03:00
} ;
typedef struct _xmlStreamComp xmlStreamComp ;
typedef xmlStreamComp * xmlStreamCompPtr ;
struct _xmlStreamComp {
2005-06-06 17:49:18 +04:00
xmlDict * dict ; /* the dictionary if any */
2005-01-30 21:42:55 +03:00
int nbStep ; /* number of steps in the automata */
int maxStep ; /* allocated number of steps */
xmlStreamStepPtr steps ; /* the array of steps */
2005-06-14 23:24:47 +04:00
int flags ;
2005-01-30 21:42:55 +03:00
} ;
struct _xmlStreamCtxt {
2005-02-05 19:35:04 +03:00
struct _xmlStreamCtxt * next ; /* link to next sub pattern if | */
2005-01-30 21:42:55 +03:00
xmlStreamCompPtr comp ; /* the compiled stream */
2005-06-06 17:49:18 +04:00
int nbState ; /* number of states in the automata */
int maxState ; /* allocated number of states */
2005-01-30 21:42:55 +03:00
int level ; /* how deep are we ? */
int * states ; /* the array of step indexes */
2005-03-04 21:04:59 +03:00
int flags ; /* validation options */
2005-06-14 23:24:47 +04:00
int blockLevel ;
2005-01-30 21:42:55 +03:00
} ;
static void xmlFreeStreamComp ( xmlStreamCompPtr comp ) ;
2003-12-03 01:32:15 +03:00
/*
* Types are private :
*/
typedef enum {
XML_OP_END = 0 ,
XML_OP_ROOT ,
XML_OP_ELEM ,
XML_OP_CHILD ,
XML_OP_ATTR ,
XML_OP_PARENT ,
XML_OP_ANCESTOR ,
XML_OP_NS ,
XML_OP_ALL
} xmlPatOp ;
2005-02-04 01:24:10 +03:00
typedef struct _xmlStepState xmlStepState ;
typedef xmlStepState * xmlStepStatePtr ;
struct _xmlStepState {
int step ;
xmlNodePtr node ;
} ;
typedef struct _xmlStepStates xmlStepStates ;
typedef xmlStepStates * xmlStepStatesPtr ;
struct _xmlStepStates {
int nbstates ;
int maxstates ;
xmlStepStatePtr states ;
} ;
2003-12-03 01:32:15 +03:00
typedef struct _xmlStepOp xmlStepOp ;
typedef xmlStepOp * xmlStepOpPtr ;
struct _xmlStepOp {
xmlPatOp op ;
const xmlChar * value ;
2006-05-16 19:13:37 +04:00
const xmlChar * value2 ; /* The namespace name */
2003-12-03 01:32:15 +03:00
} ;
2005-06-09 22:12:28 +04:00
# define PAT_FROM_ROOT (1<<8)
# define PAT_FROM_CUR (1<<9)
2005-02-16 03:22:29 +03:00
2003-12-03 01:32:15 +03:00
struct _xmlPattern {
2012-09-11 09:26:36 +04:00
void * data ; /* the associated template */
2005-06-06 17:49:18 +04:00
xmlDictPtr dict ; /* the optional dictionary */
2005-02-05 19:35:04 +03:00
struct _xmlPattern * next ; /* next pattern if | is used */
2003-12-03 01:32:15 +03:00
const xmlChar * pattern ; /* the pattern */
2005-09-03 17:43:20 +04:00
int flags ; /* flags */
2003-12-03 01:32:15 +03:00
int nbStep ;
int maxStep ;
2005-01-13 00:04:15 +03:00
xmlStepOpPtr steps ; /* ops for computation */
2005-01-30 21:42:55 +03:00
xmlStreamCompPtr stream ; /* the streaming data if any */
2003-12-03 01:32:15 +03:00
} ;
typedef struct _xmlPatParserContext xmlPatParserContext ;
typedef xmlPatParserContext * xmlPatParserContextPtr ;
struct _xmlPatParserContext {
const xmlChar * cur ; /* the current char being parsed */
const xmlChar * base ; /* the full expression */
int error ; /* error code */
2005-06-06 17:49:18 +04:00
xmlDictPtr dict ; /* the dictionary if any */
2003-12-03 01:32:15 +03:00
xmlPatternPtr comp ; /* the result */
2012-09-11 09:26:36 +04:00
xmlNodePtr elem ; /* the current node if any */
2003-12-05 19:10:21 +03:00
const xmlChar * * namespaces ; /* the namespaces definitions */
int nb_namespaces ; /* the number of namespaces */
2003-12-03 01:32:15 +03:00
} ;
/************************************************************************
2012-09-11 09:26:36 +04:00
* *
* Type functions *
* *
2003-12-03 01:32:15 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* xmlNewPattern :
*
* Create a new XSLT Pattern
*
* Returns the newly allocated xmlPatternPtr or NULL in case of error
*/
static xmlPatternPtr
xmlNewPattern ( void ) {
xmlPatternPtr cur ;
cur = ( xmlPatternPtr ) xmlMalloc ( sizeof ( xmlPattern ) ) ;
if ( cur = = NULL ) {
ERROR ( NULL , NULL , NULL ,
" xmlNewPattern : malloc failed \n " ) ;
return ( NULL ) ;
}
memset ( cur , 0 , sizeof ( xmlPattern ) ) ;
cur - > maxStep = 10 ;
2005-01-13 00:04:15 +03:00
cur - > steps = ( xmlStepOpPtr ) xmlMalloc ( cur - > maxStep * sizeof ( xmlStepOp ) ) ;
if ( cur - > steps = = NULL ) {
xmlFree ( cur ) ;
ERROR ( NULL , NULL , NULL ,
" xmlNewPattern : malloc failed \n " ) ;
return ( NULL ) ;
}
2003-12-03 01:32:15 +03:00
return ( cur ) ;
}
/**
* xmlFreePattern :
* @ comp : an XSLT comp
*
* Free up the memory allocated by @ comp
*/
void
xmlFreePattern ( xmlPatternPtr comp ) {
2019-04-25 12:34:08 +03:00
xmlFreePatternList ( comp ) ;
}
static void
xmlFreePatternInternal ( xmlPatternPtr comp ) {
2003-12-03 01:32:15 +03:00
xmlStepOpPtr op ;
int i ;
if ( comp = = NULL )
return ;
2005-01-30 21:42:55 +03:00
if ( comp - > stream ! = NULL )
xmlFreeStreamComp ( comp - > stream ) ;
2003-12-03 01:32:15 +03:00
if ( comp - > pattern ! = NULL )
xmlFree ( ( xmlChar * ) comp - > pattern ) ;
2005-01-13 00:04:15 +03:00
if ( comp - > steps ! = NULL ) {
2005-01-30 21:42:55 +03:00
if ( comp - > dict = = NULL ) {
for ( i = 0 ; i < comp - > nbStep ; i + + ) {
op = & comp - > steps [ i ] ;
if ( op - > value ! = NULL )
xmlFree ( ( xmlChar * ) op - > value ) ;
if ( op - > value2 ! = NULL )
xmlFree ( ( xmlChar * ) op - > value2 ) ;
}
2005-01-13 00:04:15 +03:00
}
xmlFree ( comp - > steps ) ;
2003-12-03 01:32:15 +03:00
}
2005-01-30 21:42:55 +03:00
if ( comp - > dict ! = NULL )
xmlDictFree ( comp - > dict ) ;
2003-12-03 01:32:15 +03:00
memset ( comp , - 1 , sizeof ( xmlPattern ) ) ;
xmlFree ( comp ) ;
}
/**
* xmlFreePatternList :
* @ comp : an XSLT comp list
*
* Free up the memory allocated by all the elements of @ comp
*/
void
xmlFreePatternList ( xmlPatternPtr comp ) {
xmlPatternPtr cur ;
while ( comp ! = NULL ) {
cur = comp ;
comp = comp - > next ;
2005-02-21 13:44:36 +03:00
cur - > next = NULL ;
2019-04-25 12:34:08 +03:00
xmlFreePatternInternal ( cur ) ;
2003-12-03 01:32:15 +03:00
}
}
/**
* xmlNewPatParserContext :
* @ pattern : the pattern context
2005-06-06 17:49:18 +04:00
* @ dict : the inherited dictionary or NULL
2005-01-30 21:42:55 +03:00
* @ namespaces : the prefix definitions , array of [ URI , prefix ] terminated
* with [ NULL , NULL ] or NULL if no namespace is used
2003-12-03 01:32:15 +03:00
*
* Create a new XML pattern parser context
*
* Returns the newly allocated xmlPatParserContextPtr or NULL in case of error
*/
static xmlPatParserContextPtr
2003-12-05 19:10:21 +03:00
xmlNewPatParserContext ( const xmlChar * pattern , xmlDictPtr dict ,
const xmlChar * * namespaces ) {
2003-12-03 01:32:15 +03:00
xmlPatParserContextPtr cur ;
if ( pattern = = NULL )
return ( NULL ) ;
cur = ( xmlPatParserContextPtr ) xmlMalloc ( sizeof ( xmlPatParserContext ) ) ;
if ( cur = = NULL ) {
ERROR ( NULL , NULL , NULL ,
" xmlNewPatParserContext : malloc failed \n " ) ;
return ( NULL ) ;
}
memset ( cur , 0 , sizeof ( xmlPatParserContext ) ) ;
cur - > dict = dict ;
cur - > cur = pattern ;
cur - > base = pattern ;
2003-12-05 19:10:21 +03:00
if ( namespaces ! = NULL ) {
int i ;
2012-03-05 12:36:59 +04:00
for ( i = 0 ; namespaces [ 2 * i ] ! = NULL ; i + + )
;
2003-12-05 19:10:21 +03:00
cur - > nb_namespaces = i ;
} else {
cur - > nb_namespaces = 0 ;
}
cur - > namespaces = namespaces ;
2003-12-03 01:32:15 +03:00
return ( cur ) ;
}
/**
* xmlFreePatParserContext :
* @ ctxt : an XSLT parser context
*
* Free up the memory allocated by @ ctxt
*/
static void
xmlFreePatParserContext ( xmlPatParserContextPtr ctxt ) {
if ( ctxt = = NULL )
2012-09-11 09:26:36 +04:00
return ;
2003-12-03 01:32:15 +03:00
memset ( ctxt , - 1 , sizeof ( xmlPatParserContext ) ) ;
xmlFree ( ctxt ) ;
}
/**
* xmlPatternAdd :
* @ comp : the compiled match expression
* @ op : an op
* @ value : the first value
* @ value2 : the second value
*
2005-06-06 17:49:18 +04:00
* Add a step to an XSLT Compiled Match
2003-12-03 01:32:15 +03:00
*
* Returns - 1 in case of failure , 0 otherwise .
*/
static int
2023-12-10 17:30:47 +03:00
xmlPatternAdd ( xmlPatParserContextPtr ctxt , xmlPatternPtr comp ,
xmlPatOp op , xmlChar * value , xmlChar * value2 )
2003-12-03 01:32:15 +03:00
{
2005-01-13 00:04:15 +03:00
if ( comp - > nbStep > = comp - > maxStep ) {
xmlStepOpPtr temp ;
temp = ( xmlStepOpPtr ) xmlRealloc ( comp - > steps , comp - > maxStep * 2 *
sizeof ( xmlStepOp ) ) ;
if ( temp = = NULL ) {
ERROR ( ctxt , NULL , NULL ,
" xmlPatternAdd: realloc failed \n " ) ;
2023-12-10 17:30:47 +03:00
ctxt - > error = - 1 ;
2005-01-13 00:04:15 +03:00
return ( - 1 ) ;
}
comp - > steps = temp ;
comp - > maxStep * = 2 ;
2003-12-03 01:32:15 +03:00
}
comp - > steps [ comp - > nbStep ] . op = op ;
comp - > steps [ comp - > nbStep ] . value = value ;
comp - > steps [ comp - > nbStep ] . value2 = value2 ;
comp - > nbStep + + ;
return ( 0 ) ;
}
#if 0
/**
* xsltSwapTopPattern :
* @ comp : the compiled match expression
*
* reverse the two top steps .
*/
static void
xsltSwapTopPattern ( xmlPatternPtr comp ) {
int i ;
int j = comp - > nbStep - 1 ;
if ( j > 0 ) {
register const xmlChar * tmp ;
register xmlPatOp op ;
i = j - 1 ;
tmp = comp - > steps [ i ] . value ;
comp - > steps [ i ] . value = comp - > steps [ j ] . value ;
comp - > steps [ j ] . value = tmp ;
tmp = comp - > steps [ i ] . value2 ;
comp - > steps [ i ] . value2 = comp - > steps [ j ] . value2 ;
comp - > steps [ j ] . value2 = tmp ;
op = comp - > steps [ i ] . op ;
comp - > steps [ i ] . op = comp - > steps [ j ] . op ;
comp - > steps [ j ] . op = op ;
}
}
# endif
/**
* xmlReversePattern :
* @ comp : the compiled match expression
*
* reverse all the stack of expressions
2005-01-13 00:04:15 +03:00
*
* returns 0 in case of success and - 1 in case of error .
2003-12-03 01:32:15 +03:00
*/
2005-01-13 00:04:15 +03:00
static int
2003-12-03 01:32:15 +03:00
xmlReversePattern ( xmlPatternPtr comp ) {
2005-02-16 03:22:29 +03:00
int i , j ;
/*
* remove the leading // for //a or .//a
*/
if ( ( comp - > nbStep > 0 ) & & ( comp - > steps [ 0 ] . op = = XML_OP_ANCESTOR ) ) {
for ( i = 0 , j = 1 ; j < comp - > nbStep ; i + + , j + + ) {
comp - > steps [ i ] . value = comp - > steps [ j ] . value ;
comp - > steps [ i ] . value2 = comp - > steps [ j ] . value2 ;
comp - > steps [ i ] . op = comp - > steps [ j ] . op ;
}
comp - > nbStep - - ;
}
2005-01-13 00:04:15 +03:00
if ( comp - > nbStep > = comp - > maxStep ) {
xmlStepOpPtr temp ;
temp = ( xmlStepOpPtr ) xmlRealloc ( comp - > steps , comp - > maxStep * 2 *
sizeof ( xmlStepOp ) ) ;
if ( temp = = NULL ) {
ERROR ( ctxt , NULL , NULL ,
" xmlReversePattern: realloc failed \n " ) ;
return ( - 1 ) ;
}
comp - > steps = temp ;
comp - > maxStep * = 2 ;
}
2005-02-16 03:22:29 +03:00
i = 0 ;
j = comp - > nbStep - 1 ;
2003-12-03 01:32:15 +03:00
while ( j > i ) {
register const xmlChar * tmp ;
register xmlPatOp op ;
tmp = comp - > steps [ i ] . value ;
comp - > steps [ i ] . value = comp - > steps [ j ] . value ;
comp - > steps [ j ] . value = tmp ;
tmp = comp - > steps [ i ] . value2 ;
comp - > steps [ i ] . value2 = comp - > steps [ j ] . value2 ;
comp - > steps [ j ] . value2 = tmp ;
op = comp - > steps [ i ] . op ;
comp - > steps [ i ] . op = comp - > steps [ j ] . op ;
comp - > steps [ j ] . op = op ;
j - - ;
i + + ;
}
2005-01-13 00:04:15 +03:00
comp - > steps [ comp - > nbStep ] . value = NULL ;
comp - > steps [ comp - > nbStep ] . value2 = NULL ;
2003-12-03 01:32:15 +03:00
comp - > steps [ comp - > nbStep + + ] . op = XML_OP_END ;
2005-01-13 00:04:15 +03:00
return ( 0 ) ;
2003-12-03 01:32:15 +03:00
}
/************************************************************************
2012-09-11 09:26:36 +04:00
* *
* The interpreter for the precompiled patterns *
* *
2003-12-03 01:32:15 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-02-04 01:24:10 +03:00
static int
xmlPatPushState ( xmlStepStates * states , int step , xmlNodePtr node ) {
if ( ( states - > states = = NULL ) | | ( states - > maxstates < = 0 ) ) {
states - > maxstates = 4 ;
states - > nbstates = 0 ;
states - > states = xmlMalloc ( 4 * sizeof ( xmlStepState ) ) ;
}
else if ( states - > maxstates < = states - > nbstates ) {
xmlStepState * tmp ;
tmp = ( xmlStepStatePtr ) xmlRealloc ( states - > states ,
2 * states - > maxstates * sizeof ( xmlStepState ) ) ;
if ( tmp = = NULL )
return ( - 1 ) ;
states - > states = tmp ;
states - > maxstates * = 2 ;
}
states - > states [ states - > nbstates ] . step = step ;
states - > states [ states - > nbstates + + ] . node = node ;
#if 0
fprintf ( stderr , " Push: %d, %s \n " , step , node - > name ) ;
# endif
return ( 0 ) ;
}
2003-12-03 01:32:15 +03:00
/**
* xmlPatMatch :
* @ comp : the precompiled pattern
* @ node : a node
*
2005-06-06 17:49:18 +04:00
* Test whether the node matches the pattern
2003-12-03 01:32:15 +03:00
*
* Returns 1 if it matches , 0 if it doesn ' t and - 1 in case of failure
*/
static int
xmlPatMatch ( xmlPatternPtr comp , xmlNodePtr node ) {
int i ;
xmlStepOpPtr step ;
2005-02-04 01:24:10 +03:00
xmlStepStates states = { 0 , 0 , NULL } ; /* // may require backtrack */
2003-12-03 01:32:15 +03:00
if ( ( comp = = NULL ) | | ( node = = NULL ) ) return ( - 1 ) ;
2005-02-04 01:24:10 +03:00
i = 0 ;
restart :
for ( ; i < comp - > nbStep ; i + + ) {
2003-12-03 01:32:15 +03:00
step = & comp - > steps [ i ] ;
switch ( step - > op ) {
case XML_OP_END :
2005-02-04 01:24:10 +03:00
goto found ;
2003-12-03 01:32:15 +03:00
case XML_OP_ROOT :
2005-01-30 21:42:55 +03:00
if ( node - > type = = XML_NAMESPACE_DECL )
2005-02-04 01:24:10 +03:00
goto rollback ;
2005-01-30 21:42:55 +03:00
node = node - > parent ;
2003-12-03 01:32:15 +03:00
if ( ( node - > type = = XML_DOCUMENT_NODE ) | |
( node - > type = = XML_HTML_DOCUMENT_NODE ) )
continue ;
2005-02-04 01:24:10 +03:00
goto rollback ;
2003-12-03 01:32:15 +03:00
case XML_OP_ELEM :
if ( node - > type ! = XML_ELEMENT_NODE )
2005-02-04 01:24:10 +03:00
goto rollback ;
2003-12-03 01:32:15 +03:00
if ( step - > value = = NULL )
continue ;
if ( step - > value [ 0 ] ! = node - > name [ 0 ] )
2005-02-04 01:24:10 +03:00
goto rollback ;
2003-12-03 01:32:15 +03:00
if ( ! xmlStrEqual ( step - > value , node - > name ) )
2005-02-04 01:24:10 +03:00
goto rollback ;
2003-12-03 01:32:15 +03:00
/* Namespace test */
if ( node - > ns = = NULL ) {
if ( step - > value2 ! = NULL )
2005-02-04 01:24:10 +03:00
goto rollback ;
2003-12-03 01:32:15 +03:00
} else if ( node - > ns - > href ! = NULL ) {
if ( step - > value2 = = NULL )
2005-02-04 01:24:10 +03:00
goto rollback ;
2003-12-03 01:32:15 +03:00
if ( ! xmlStrEqual ( step - > value2 , node - > ns - > href ) )
2005-02-04 01:24:10 +03:00
goto rollback ;
2003-12-03 01:32:15 +03:00
}
continue ;
case XML_OP_CHILD : {
xmlNodePtr lst ;
if ( ( node - > type ! = XML_ELEMENT_NODE ) & &
( node - > type ! = XML_DOCUMENT_NODE ) & &
( node - > type ! = XML_HTML_DOCUMENT_NODE ) )
2005-02-04 01:24:10 +03:00
goto rollback ;
2003-12-03 01:32:15 +03:00
lst = node - > children ;
if ( step - > value ! = NULL ) {
while ( lst ! = NULL ) {
if ( ( lst - > type = = XML_ELEMENT_NODE ) & &
( step - > value [ 0 ] = = lst - > name [ 0 ] ) & &
( xmlStrEqual ( step - > value , lst - > name ) ) )
break ;
lst = lst - > next ;
}
if ( lst ! = NULL )
continue ;
}
2005-02-04 01:24:10 +03:00
goto rollback ;
2003-12-03 01:32:15 +03:00
}
case XML_OP_ATTR :
if ( node - > type ! = XML_ATTRIBUTE_NODE )
2005-02-04 01:24:10 +03:00
goto rollback ;
2003-12-03 01:32:15 +03:00
if ( step - > value ! = NULL ) {
if ( step - > value [ 0 ] ! = node - > name [ 0 ] )
2005-02-04 01:24:10 +03:00
goto rollback ;
2003-12-03 01:32:15 +03:00
if ( ! xmlStrEqual ( step - > value , node - > name ) )
2005-02-04 01:24:10 +03:00
goto rollback ;
2003-12-03 01:32:15 +03:00
}
/* Namespace test */
if ( node - > ns = = NULL ) {
if ( step - > value2 ! = NULL )
2005-02-04 01:24:10 +03:00
goto rollback ;
2003-12-03 01:32:15 +03:00
} else if ( step - > value2 ! = NULL ) {
if ( ! xmlStrEqual ( step - > value2 , node - > ns - > href ) )
2005-02-04 01:24:10 +03:00
goto rollback ;
2003-12-03 01:32:15 +03:00
}
continue ;
case XML_OP_PARENT :
if ( ( node - > type = = XML_DOCUMENT_NODE ) | |
( node - > type = = XML_HTML_DOCUMENT_NODE ) | |
( node - > type = = XML_NAMESPACE_DECL ) )
2005-02-04 01:24:10 +03:00
goto rollback ;
2003-12-03 01:32:15 +03:00
node = node - > parent ;
if ( node = = NULL )
2005-02-04 01:24:10 +03:00
goto rollback ;
2003-12-03 01:32:15 +03:00
if ( step - > value = = NULL )
continue ;
if ( step - > value [ 0 ] ! = node - > name [ 0 ] )
2005-02-04 01:24:10 +03:00
goto rollback ;
2003-12-03 01:32:15 +03:00
if ( ! xmlStrEqual ( step - > value , node - > name ) )
2005-02-04 01:24:10 +03:00
goto rollback ;
2003-12-03 01:32:15 +03:00
/* Namespace test */
if ( node - > ns = = NULL ) {
if ( step - > value2 ! = NULL )
2005-02-04 01:24:10 +03:00
goto rollback ;
2003-12-03 01:32:15 +03:00
} else if ( node - > ns - > href ! = NULL ) {
if ( step - > value2 = = NULL )
2005-02-04 01:24:10 +03:00
goto rollback ;
2003-12-03 01:32:15 +03:00
if ( ! xmlStrEqual ( step - > value2 , node - > ns - > href ) )
2005-02-04 01:24:10 +03:00
goto rollback ;
2003-12-03 01:32:15 +03:00
}
continue ;
case XML_OP_ANCESTOR :
/* TODO: implement coalescing of ANCESTOR/NODE ops */
if ( step - > value = = NULL ) {
i + + ;
step = & comp - > steps [ i ] ;
if ( step - > op = = XML_OP_ROOT )
2005-02-04 01:24:10 +03:00
goto found ;
2003-12-03 01:32:15 +03:00
if ( step - > op ! = XML_OP_ELEM )
2005-02-04 01:24:10 +03:00
goto rollback ;
2003-12-03 01:32:15 +03:00
if ( step - > value = = NULL )
return ( - 1 ) ;
}
if ( node = = NULL )
2005-02-04 01:24:10 +03:00
goto rollback ;
2003-12-03 01:32:15 +03:00
if ( ( node - > type = = XML_DOCUMENT_NODE ) | |
( node - > type = = XML_HTML_DOCUMENT_NODE ) | |
( node - > type = = XML_NAMESPACE_DECL ) )
2005-02-04 01:24:10 +03:00
goto rollback ;
2003-12-03 01:32:15 +03:00
node = node - > parent ;
while ( node ! = NULL ) {
if ( ( node - > type = = XML_ELEMENT_NODE ) & &
( step - > value [ 0 ] = = node - > name [ 0 ] ) & &
( xmlStrEqual ( step - > value , node - > name ) ) ) {
/* Namespace test */
if ( node - > ns = = NULL ) {
if ( step - > value2 = = NULL )
break ;
} else if ( node - > ns - > href ! = NULL ) {
if ( ( step - > value2 ! = NULL ) & &
( xmlStrEqual ( step - > value2 , node - > ns - > href ) ) )
break ;
}
}
node = node - > parent ;
}
if ( node = = NULL )
2005-02-04 01:24:10 +03:00
goto rollback ;
/*
* prepare a potential rollback from here
* for ancestors of that node .
*/
if ( step - > op = = XML_OP_ANCESTOR )
xmlPatPushState ( & states , i , node ) ;
else
xmlPatPushState ( & states , i - 1 , node ) ;
2003-12-03 01:32:15 +03:00
continue ;
case XML_OP_NS :
if ( node - > type ! = XML_ELEMENT_NODE )
2005-02-04 01:24:10 +03:00
goto rollback ;
2003-12-03 01:32:15 +03:00
if ( node - > ns = = NULL ) {
if ( step - > value ! = NULL )
2005-02-04 01:24:10 +03:00
goto rollback ;
2003-12-03 01:32:15 +03:00
} else if ( node - > ns - > href ! = NULL ) {
if ( step - > value = = NULL )
2005-02-04 01:24:10 +03:00
goto rollback ;
2003-12-03 01:32:15 +03:00
if ( ! xmlStrEqual ( step - > value , node - > ns - > href ) )
2005-02-04 01:24:10 +03:00
goto rollback ;
2003-12-03 01:32:15 +03:00
}
break ;
case XML_OP_ALL :
if ( node - > type ! = XML_ELEMENT_NODE )
2005-02-04 01:24:10 +03:00
goto rollback ;
2003-12-03 01:32:15 +03:00
break ;
}
}
2005-02-04 01:24:10 +03:00
found :
if ( states . states ! = NULL ) {
/* Free the rollback states */
xmlFree ( states . states ) ;
}
2003-12-03 01:32:15 +03:00
return ( 1 ) ;
2005-02-04 01:24:10 +03:00
rollback :
/* got an error try to rollback */
if ( states . states = = NULL )
return ( 0 ) ;
if ( states . nbstates < = 0 ) {
xmlFree ( states . states ) ;
return ( 0 ) ;
}
states . nbstates - - ;
i = states . states [ states . nbstates ] . step ;
node = states . states [ states . nbstates ] . node ;
#if 0
fprintf ( stderr , " Pop: %d, %s \n " , i , node - > name ) ;
# endif
goto restart ;
2003-12-03 01:32:15 +03:00
}
/************************************************************************
* *
* Dedicated parser for templates *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# define CUR (*ctxt->cur)
# define SKIP(val) ctxt->cur += (val)
# define NXT(val) ctxt->cur[(val)]
2005-10-19 21:00:53 +04:00
# define PEEKPREV(val) ctxt->cur[-(val)]
2003-12-03 01:32:15 +03:00
# define CUR_PTR ctxt->cur
2012-09-11 09:26:36 +04:00
# define SKIP_BLANKS \
2003-12-10 13:42:59 +03:00
while ( IS_BLANK_CH ( CUR ) ) NEXT
2003-12-03 01:32:15 +03:00
# define CURRENT (*ctxt->cur)
# define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
2012-09-11 09:26:36 +04:00
# define PUSH(op, val, val2) \
2003-12-03 01:32:15 +03:00
if ( xmlPatternAdd ( ctxt , ctxt - > comp , ( op ) , ( val ) , ( val2 ) ) ) goto error ;
#if 0
/**
* xmlPatScanLiteral :
* @ ctxt : the XPath Parser context
*
2019-09-30 18:04:54 +03:00
* Parse an XPath Literal :
2003-12-03 01:32:15 +03:00
*
* [ 29 ] Literal : : = ' " ' [ ^ " ]* ' " '
* | " ' " [ ^ ' ] * " ' "
*
* Returns the Literal parsed or NULL
*/
static xmlChar *
xmlPatScanLiteral ( xmlPatParserContextPtr ctxt ) {
const xmlChar * q , * cur ;
xmlChar * ret = NULL ;
int val , len ;
SKIP_BLANKS ;
if ( CUR = = ' " ' ) {
NEXT ;
cur = q = CUR_PTR ;
val = xmlStringCurrentChar ( NULL , cur , & len ) ;
while ( ( IS_CHAR ( val ) ) & & ( val ! = ' " ' ) ) {
cur + = len ;
val = xmlStringCurrentChar ( NULL , cur , & len ) ;
}
if ( ! IS_CHAR ( val ) ) {
ctxt - > error = 1 ;
return ( NULL ) ;
} else {
2006-05-16 19:13:37 +04:00
if ( ctxt - > dict )
ret = ( xmlChar * ) xmlDictLookup ( ctxt - > dict , q , cur - q ) ;
else
2012-09-11 09:26:36 +04:00
ret = xmlStrndup ( q , cur - q ) ;
2003-12-03 01:32:15 +03:00
}
cur + = len ;
CUR_PTR = cur ;
} else if ( CUR = = ' \' ' ) {
NEXT ;
cur = q = CUR_PTR ;
val = xmlStringCurrentChar ( NULL , cur , & len ) ;
while ( ( IS_CHAR ( val ) ) & & ( val ! = ' \' ' ) ) {
cur + = len ;
val = xmlStringCurrentChar ( NULL , cur , & len ) ;
}
if ( ! IS_CHAR ( val ) ) {
ctxt - > error = 1 ;
return ( NULL ) ;
} else {
2006-05-16 19:13:37 +04:00
if ( ctxt - > dict )
ret = ( xmlChar * ) xmlDictLookup ( ctxt - > dict , q , cur - q ) ;
else
2012-09-11 09:26:36 +04:00
ret = xmlStrndup ( q , cur - q ) ;
2003-12-03 01:32:15 +03:00
}
cur + = len ;
CUR_PTR = cur ;
} else {
/* XP_ERROR(XPATH_START_LITERAL_ERROR); */
ctxt - > error = 1 ;
return ( NULL ) ;
}
return ( ret ) ;
}
# endif
/**
* xmlPatScanName :
* @ ctxt : the XPath Parser context
*
2012-09-11 09:26:36 +04:00
* [ 4 ] NameChar : : = Letter | Digit | ' . ' | ' - ' | ' _ ' |
2003-12-03 01:32:15 +03:00
* CombiningChar | Extender
*
* [ 5 ] Name : : = ( Letter | ' _ ' | ' : ' ) ( NameChar ) *
*
* [ 6 ] Names : : = Name ( S Name ) *
*
* Returns the Name parsed or NULL
*/
static xmlChar *
xmlPatScanName ( xmlPatParserContextPtr ctxt ) {
const xmlChar * q , * cur ;
xmlChar * ret = NULL ;
int val , len ;
SKIP_BLANKS ;
cur = q = CUR_PTR ;
val = xmlStringCurrentChar ( NULL , cur , & len ) ;
if ( ! IS_LETTER ( val ) & & ( val ! = ' _ ' ) & & ( val ! = ' : ' ) )
return ( NULL ) ;
while ( ( IS_LETTER ( val ) ) | | ( IS_DIGIT ( val ) ) | |
( val = = ' . ' ) | | ( val = = ' - ' ) | |
2012-09-11 09:26:36 +04:00
( val = = ' _ ' ) | |
2003-12-03 01:32:15 +03:00
( IS_COMBINING ( val ) ) | |
( IS_EXTENDER ( val ) ) ) {
cur + = len ;
val = xmlStringCurrentChar ( NULL , cur , & len ) ;
}
2006-05-16 19:13:37 +04:00
if ( ctxt - > dict )
ret = ( xmlChar * ) xmlDictLookup ( ctxt - > dict , q , cur - q ) ;
else
2012-09-11 09:26:36 +04:00
ret = xmlStrndup ( q , cur - q ) ;
2003-12-03 01:32:15 +03:00
CUR_PTR = cur ;
return ( ret ) ;
}
/**
* xmlPatScanNCName :
* @ ctxt : the XPath Parser context
*
* Parses a non qualified name
*
* Returns the Name parsed or NULL
*/
static xmlChar *
xmlPatScanNCName ( xmlPatParserContextPtr ctxt ) {
const xmlChar * q , * cur ;
xmlChar * ret = NULL ;
int val , len ;
SKIP_BLANKS ;
cur = q = CUR_PTR ;
val = xmlStringCurrentChar ( NULL , cur , & len ) ;
if ( ! IS_LETTER ( val ) & & ( val ! = ' _ ' ) )
return ( NULL ) ;
while ( ( IS_LETTER ( val ) ) | | ( IS_DIGIT ( val ) ) | |
( val = = ' . ' ) | | ( val = = ' - ' ) | |
( val = = ' _ ' ) | |
( IS_COMBINING ( val ) ) | |
( IS_EXTENDER ( val ) ) ) {
cur + = len ;
val = xmlStringCurrentChar ( NULL , cur , & len ) ;
}
2006-05-16 19:13:37 +04:00
if ( ctxt - > dict )
ret = ( xmlChar * ) xmlDictLookup ( ctxt - > dict , q , cur - q ) ;
else
ret = xmlStrndup ( q , cur - q ) ;
2023-12-10 17:30:47 +03:00
if ( ret = = NULL )
ctxt - > error = - 1 ;
2003-12-03 01:32:15 +03:00
CUR_PTR = cur ;
return ( ret ) ;
}
#if 0
/**
* xmlPatScanQName :
* @ ctxt : the XPath Parser context
* @ prefix : the place to store the prefix
*
* Parse a qualified name
*
* Returns the Name parsed or NULL
*/
static xmlChar *
xmlPatScanQName ( xmlPatParserContextPtr ctxt , xmlChar * * prefix ) {
xmlChar * ret = NULL ;
* prefix = NULL ;
ret = xmlPatScanNCName ( ctxt ) ;
if ( CUR = = ' : ' ) {
* prefix = ret ;
NEXT ;
ret = xmlPatScanNCName ( ctxt ) ;
}
return ( ret ) ;
}
# endif
2005-02-18 00:34:45 +03:00
/**
* xmlCompileAttributeTest :
* @ ctxt : the compilation context
*
* Compile an attribute test .
*/
static void
xmlCompileAttributeTest ( xmlPatParserContextPtr ctxt ) {
xmlChar * token = NULL ;
xmlChar * name = NULL ;
xmlChar * URL = NULL ;
2012-09-11 09:26:36 +04:00
2005-10-19 21:00:53 +04:00
SKIP_BLANKS ;
2005-02-18 00:34:45 +03:00
name = xmlPatScanNCName ( ctxt ) ;
2023-12-10 17:30:47 +03:00
if ( ctxt - > error < 0 )
return ;
2005-02-18 00:34:45 +03:00
if ( name = = NULL ) {
if ( CUR = = ' * ' ) {
PUSH ( XML_OP_ATTR , NULL , NULL ) ;
2005-06-14 23:24:47 +04:00
NEXT ;
2005-02-18 00:34:45 +03:00
} else {
ERROR ( NULL , NULL , NULL ,
" xmlCompileAttributeTest : Name expected \n " ) ;
ctxt - > error = 1 ;
}
return ;
}
if ( CUR = = ' : ' ) {
int i ;
xmlChar * prefix = name ;
2012-09-11 09:26:36 +04:00
2005-02-18 00:34:45 +03:00
NEXT ;
2005-10-19 21:00:53 +04:00
2012-09-11 09:26:36 +04:00
if ( IS_BLANK_CH ( CUR ) ) {
2005-10-19 21:00:53 +04:00
ERROR5 ( NULL , NULL , NULL , " Invalid QName. \n " , NULL ) ;
ctxt - > error = 1 ;
goto error ;
}
2005-02-18 00:34:45 +03:00
/*
* This is a namespace match
*/
token = xmlPatScanName ( ctxt ) ;
2005-07-23 02:37:35 +04:00
if ( ( prefix [ 0 ] = = ' x ' ) & &
( prefix [ 1 ] = = ' m ' ) & &
( prefix [ 2 ] = = ' l ' ) & &
2006-05-16 19:13:37 +04:00
( prefix [ 3 ] = = 0 ) )
{
2012-09-11 09:26:36 +04:00
XML_PAT_COPY_NSNAME ( ctxt , URL , XML_XML_NAMESPACE ) ;
2005-07-23 02:37:35 +04:00
} else {
for ( i = 0 ; i < ctxt - > nb_namespaces ; i + + ) {
if ( xmlStrEqual ( ctxt - > namespaces [ 2 * i + 1 ] , prefix ) ) {
2012-09-11 09:26:36 +04:00
XML_PAT_COPY_NSNAME ( ctxt , URL , ctxt - > namespaces [ 2 * i ] )
2005-07-23 02:37:35 +04:00
break ;
}
}
if ( i > = ctxt - > nb_namespaces ) {
ERROR5 ( NULL , NULL , NULL ,
" xmlCompileAttributeTest : no namespace bound to prefix %s \n " ,
prefix ) ;
2012-09-11 09:26:36 +04:00
ctxt - > error = 1 ;
2005-07-23 02:37:35 +04:00
goto error ;
2005-02-18 00:34:45 +03:00
}
}
2023-07-21 15:50:30 +03:00
XML_PAT_FREE_STRING ( ctxt , name ) ;
name = NULL ;
2005-02-18 00:34:45 +03:00
if ( token = = NULL ) {
if ( CUR = = ' * ' ) {
NEXT ;
PUSH ( XML_OP_ATTR , NULL , URL ) ;
} else {
ERROR ( NULL , NULL , NULL ,
" xmlCompileAttributeTest : Name expected \n " ) ;
ctxt - > error = 1 ;
goto error ;
2012-09-11 09:26:36 +04:00
}
2005-02-18 00:34:45 +03:00
} else {
PUSH ( XML_OP_ATTR , token , URL ) ;
}
} else {
PUSH ( XML_OP_ATTR , name , NULL ) ;
}
return ;
error :
2023-07-21 15:50:30 +03:00
if ( name ! = NULL )
XML_PAT_FREE_STRING ( ctxt , name ) ;
2005-02-18 00:34:45 +03:00
if ( URL ! = NULL )
2012-09-11 09:26:36 +04:00
XML_PAT_FREE_STRING ( ctxt , URL )
2005-02-18 00:34:45 +03:00
if ( token ! = NULL )
2006-05-16 19:13:37 +04:00
XML_PAT_FREE_STRING ( ctxt , token ) ;
2005-02-18 00:34:45 +03:00
}
2003-12-03 01:32:15 +03:00
/**
* xmlCompileStepPattern :
* @ ctxt : the compilation context
*
* Compile the Step Pattern and generates a precompiled
* form suitable for fast matching .
*
* [ 3 ] Step : : = ' . ' | NameTest
2012-09-11 09:26:36 +04:00
* [ 4 ] NameTest : : = QName | ' * ' | NCName ' : ' ' * '
2003-12-03 01:32:15 +03:00
*/
static void
xmlCompileStepPattern ( xmlPatParserContextPtr ctxt ) {
xmlChar * token = NULL ;
xmlChar * name = NULL ;
xmlChar * URL = NULL ;
2005-10-19 21:00:53 +04:00
int hasBlanks = 0 ;
2003-12-03 01:32:15 +03:00
SKIP_BLANKS ;
if ( CUR = = ' . ' ) {
2005-10-19 21:00:53 +04:00
/*
* Context node .
*/
2003-12-03 01:32:15 +03:00
NEXT ;
PUSH ( XML_OP_ELEM , NULL , NULL ) ;
return ;
}
2005-10-19 21:00:53 +04:00
if ( CUR = = ' @ ' ) {
/*
* Attribute test .
*/
if ( XML_STREAM_XS_IDC_SEL ( ctxt - > comp ) ) {
ERROR5 ( NULL , NULL , NULL ,
" Unexpected attribute axis in '%s'. \n " , ctxt - > base ) ;
ctxt - > error = 1 ;
return ;
}
NEXT ;
xmlCompileAttributeTest ( ctxt ) ;
2012-09-11 09:26:36 +04:00
if ( ctxt - > error ! = 0 )
2005-10-19 21:00:53 +04:00
goto error ;
return ;
}
2003-12-03 01:32:15 +03:00
name = xmlPatScanNCName ( ctxt ) ;
2023-12-10 17:30:47 +03:00
if ( ctxt - > error < 0 )
return ;
2003-12-03 01:32:15 +03:00
if ( name = = NULL ) {
if ( CUR = = ' * ' ) {
NEXT ;
PUSH ( XML_OP_ALL , NULL , NULL ) ;
return ;
} else {
ERROR ( NULL , NULL , NULL ,
" xmlCompileStepPattern : Name expected \n " ) ;
ctxt - > error = 1 ;
return ;
}
}
2005-10-19 21:00:53 +04:00
if ( IS_BLANK_CH ( CUR ) ) {
hasBlanks = 1 ;
SKIP_BLANKS ;
}
2003-12-03 01:32:15 +03:00
if ( CUR = = ' : ' ) {
NEXT ;
if ( CUR ! = ' : ' ) {
xmlChar * prefix = name ;
2012-09-11 09:26:36 +04:00
int i ;
2003-12-03 01:32:15 +03:00
2005-10-19 21:00:53 +04:00
if ( hasBlanks | | IS_BLANK_CH ( CUR ) ) {
ERROR5 ( NULL , NULL , NULL , " Invalid QName. \n " , NULL ) ;
ctxt - > error = 1 ;
goto error ;
}
2003-12-03 01:32:15 +03:00
/*
* This is a namespace match
*/
token = xmlPatScanName ( ctxt ) ;
2005-07-23 02:37:35 +04:00
if ( ( prefix [ 0 ] = = ' x ' ) & &
( prefix [ 1 ] = = ' m ' ) & &
( prefix [ 2 ] = = ' l ' ) & &
2006-05-16 19:13:37 +04:00
( prefix [ 3 ] = = 0 ) )
{
XML_PAT_COPY_NSNAME ( ctxt , URL , XML_XML_NAMESPACE )
2005-07-23 02:37:35 +04:00
} else {
for ( i = 0 ; i < ctxt - > nb_namespaces ; i + + ) {
if ( xmlStrEqual ( ctxt - > namespaces [ 2 * i + 1 ] , prefix ) ) {
2006-05-16 19:13:37 +04:00
XML_PAT_COPY_NSNAME ( ctxt , URL , ctxt - > namespaces [ 2 * i ] )
2005-07-23 02:37:35 +04:00
break ;
}
}
if ( i > = ctxt - > nb_namespaces ) {
ERROR5 ( NULL , NULL , NULL ,
" xmlCompileStepPattern : no namespace bound to prefix %s \n " ,
prefix ) ;
ctxt - > error = 1 ;
goto error ;
2005-02-04 01:24:10 +03:00
}
2003-12-03 01:32:15 +03:00
}
2006-05-16 19:13:37 +04:00
XML_PAT_FREE_STRING ( ctxt , prefix ) ;
2007-12-06 13:08:52 +03:00
name = NULL ;
2003-12-03 01:32:15 +03:00
if ( token = = NULL ) {
if ( CUR = = ' * ' ) {
NEXT ;
PUSH ( XML_OP_NS , URL , NULL ) ;
} else {
ERROR ( NULL , NULL , NULL ,
" xmlCompileStepPattern : Name expected \n " ) ;
ctxt - > error = 1 ;
goto error ;
}
} else {
PUSH ( XML_OP_ELEM , token , URL ) ;
}
} else {
NEXT ;
2012-09-11 09:26:36 +04:00
if ( xmlStrEqual ( name , ( const xmlChar * ) " child " ) ) {
2006-05-16 19:13:37 +04:00
XML_PAT_FREE_STRING ( ctxt , name ) ;
2005-02-18 00:34:45 +03:00
name = xmlPatScanName ( ctxt ) ;
if ( name = = NULL ) {
if ( CUR = = ' * ' ) {
NEXT ;
PUSH ( XML_OP_ALL , NULL , NULL ) ;
return ;
} else {
ERROR ( NULL , NULL , NULL ,
2003-12-03 01:32:15 +03:00
" xmlCompileStepPattern : QName expected \n " ) ;
2005-02-18 00:34:45 +03:00
ctxt - > error = 1 ;
goto error ;
2003-12-03 01:32:15 +03:00
}
}
2005-02-18 00:34:45 +03:00
if ( CUR = = ' : ' ) {
xmlChar * prefix = name ;
int i ;
2012-09-11 09:26:36 +04:00
2005-02-18 00:34:45 +03:00
NEXT ;
2005-10-19 21:00:53 +04:00
if ( IS_BLANK_CH ( CUR ) ) {
ERROR5 ( NULL , NULL , NULL , " Invalid QName. \n " , NULL ) ;
ctxt - > error = 1 ;
goto error ;
}
2005-02-18 00:34:45 +03:00
/*
* This is a namespace match
*/
token = xmlPatScanName ( ctxt ) ;
2005-07-23 02:37:35 +04:00
if ( ( prefix [ 0 ] = = ' x ' ) & &
( prefix [ 1 ] = = ' m ' ) & &
( prefix [ 2 ] = = ' l ' ) & &
2006-05-16 19:13:37 +04:00
( prefix [ 3 ] = = 0 ) )
{
2012-09-11 09:26:36 +04:00
XML_PAT_COPY_NSNAME ( ctxt , URL , XML_XML_NAMESPACE )
2005-07-23 02:37:35 +04:00
} else {
for ( i = 0 ; i < ctxt - > nb_namespaces ; i + + ) {
if ( xmlStrEqual ( ctxt - > namespaces [ 2 * i + 1 ] , prefix ) ) {
2012-09-11 09:26:36 +04:00
XML_PAT_COPY_NSNAME ( ctxt , URL , ctxt - > namespaces [ 2 * i ] )
2005-07-23 02:37:35 +04:00
break ;
}
}
if ( i > = ctxt - > nb_namespaces ) {
ERROR5 ( NULL , NULL , NULL ,
" xmlCompileStepPattern : no namespace bound "
" to prefix %s \n " , prefix ) ;
ctxt - > error = 1 ;
goto error ;
2005-02-18 00:34:45 +03:00
}
}
2006-05-16 19:13:37 +04:00
XML_PAT_FREE_STRING ( ctxt , prefix ) ;
2007-12-06 13:08:52 +03:00
name = NULL ;
2005-02-18 00:34:45 +03:00
if ( token = = NULL ) {
if ( CUR = = ' * ' ) {
NEXT ;
PUSH ( XML_OP_NS , URL , NULL ) ;
} else {
ERROR ( NULL , NULL , NULL ,
" xmlCompileStepPattern : Name expected \n " ) ;
ctxt - > error = 1 ;
goto error ;
}
} else {
PUSH ( XML_OP_CHILD , token , URL ) ;
}
} else
PUSH ( XML_OP_CHILD , name , NULL ) ;
return ;
} else if ( xmlStrEqual ( name , ( const xmlChar * ) " attribute " ) ) {
2006-05-16 19:13:37 +04:00
XML_PAT_FREE_STRING ( ctxt , name )
2005-02-18 00:34:45 +03:00
name = NULL ;
2005-10-19 21:00:53 +04:00
if ( XML_STREAM_XS_IDC_SEL ( ctxt - > comp ) ) {
ERROR5 ( NULL , NULL , NULL ,
" Unexpected attribute axis in '%s'. \n " , ctxt - > base ) ;
ctxt - > error = 1 ;
goto error ;
}
2005-02-18 00:34:45 +03:00
xmlCompileAttributeTest ( ctxt ) ;
if ( ctxt - > error ! = 0 )
2003-12-03 01:32:15 +03:00
goto error ;
2005-02-18 00:34:45 +03:00
return ;
2003-12-03 01:32:15 +03:00
} else {
2005-10-19 21:00:53 +04:00
ERROR5 ( NULL , NULL , NULL ,
" The 'element' or 'attribute' axis is expected. \n " , NULL ) ;
2003-12-03 01:32:15 +03:00
ctxt - > error = 1 ;
goto error ;
2012-09-11 09:26:36 +04:00
}
2003-12-03 01:32:15 +03:00
}
} else if ( CUR = = ' * ' ) {
2005-02-21 13:44:36 +03:00
if ( name ! = NULL ) {
ctxt - > error = 1 ;
goto error ;
}
2003-12-03 01:32:15 +03:00
NEXT ;
PUSH ( XML_OP_ALL , token , NULL ) ;
} else {
PUSH ( XML_OP_ELEM , name , NULL ) ;
}
return ;
error :
2005-02-18 00:34:45 +03:00
if ( URL ! = NULL )
2012-09-11 09:26:36 +04:00
XML_PAT_FREE_STRING ( ctxt , URL )
2003-12-03 01:32:15 +03:00
if ( token ! = NULL )
2006-05-16 19:13:37 +04:00
XML_PAT_FREE_STRING ( ctxt , token )
2003-12-03 01:32:15 +03:00
if ( name ! = NULL )
2006-05-16 19:13:37 +04:00
XML_PAT_FREE_STRING ( ctxt , name )
2003-12-03 01:32:15 +03:00
}
/**
* xmlCompilePathPattern :
* @ ctxt : the compilation context
*
* Compile the Path Pattern and generates a precompiled
* form suitable for fast matching .
*
2012-09-11 09:26:36 +04:00
* [ 5 ] Path : : = ( ' . //')? ( Step '/' )* ( Step | '@' NameTest )
2003-12-03 01:32:15 +03:00
*/
static void
xmlCompilePathPattern ( xmlPatParserContextPtr ctxt ) {
SKIP_BLANKS ;
2005-06-15 02:02:59 +04:00
if ( CUR = = ' / ' ) {
2005-02-16 03:22:29 +03:00
ctxt - > comp - > flags | = PAT_FROM_ROOT ;
2005-06-09 22:12:28 +04:00
} else if ( ( CUR = = ' . ' ) | | ( ctxt - > comp - > flags & XML_PATTERN_NOTPATTERN ) ) {
2005-02-16 03:22:29 +03:00
ctxt - > comp - > flags | = PAT_FROM_CUR ;
}
2012-09-11 09:26:36 +04:00
2003-12-03 01:32:15 +03:00
if ( ( CUR = = ' / ' ) & & ( NXT ( 1 ) = = ' / ' ) ) {
2005-02-16 03:22:29 +03:00
PUSH ( XML_OP_ANCESTOR , NULL , NULL ) ;
2003-12-03 01:32:15 +03:00
NEXT ;
NEXT ;
} else if ( ( CUR = = ' . ' ) & & ( NXT ( 1 ) = = ' / ' ) & & ( NXT ( 2 ) = = ' / ' ) ) {
2005-02-16 03:22:29 +03:00
PUSH ( XML_OP_ANCESTOR , NULL , NULL ) ;
2003-12-03 01:32:15 +03:00
NEXT ;
NEXT ;
NEXT ;
2006-01-05 15:30:43 +03:00
/* Check for incompleteness. */
SKIP_BLANKS ;
if ( CUR = = 0 ) {
ERROR5 ( NULL , NULL , NULL ,
" Incomplete expression '%s'. \n " , ctxt - > base ) ;
ctxt - > error = 1 ;
goto error ;
}
2003-12-03 01:32:15 +03:00
}
if ( CUR = = ' @ ' ) {
2005-02-18 00:34:45 +03:00
NEXT ;
xmlCompileAttributeTest ( ctxt ) ;
2024-05-10 12:21:11 +03:00
if ( ctxt - > error ! = 0 )
goto error ;
2005-02-18 00:34:45 +03:00
SKIP_BLANKS ;
2006-01-05 15:30:43 +03:00
/* TODO: check for incompleteness */
2005-06-06 17:49:18 +04:00
if ( CUR ! = 0 ) {
2005-02-18 00:34:45 +03:00
xmlCompileStepPattern ( ctxt ) ;
2006-01-05 15:30:43 +03:00
if ( ctxt - > error ! = 0 )
goto error ;
2005-02-18 00:34:45 +03:00
}
2003-12-03 01:32:15 +03:00
} else {
2005-01-30 21:42:55 +03:00
if ( CUR = = ' / ' ) {
PUSH ( XML_OP_ROOT , NULL , NULL ) ;
NEXT ;
2006-01-05 15:30:43 +03:00
/* Check for incompleteness. */
SKIP_BLANKS ;
if ( CUR = = 0 ) {
ERROR5 ( NULL , NULL , NULL ,
" Incomplete expression '%s'. \n " , ctxt - > base ) ;
ctxt - > error = 1 ;
goto error ;
}
2005-01-30 21:42:55 +03:00
}
2003-12-03 01:32:15 +03:00
xmlCompileStepPattern ( ctxt ) ;
2006-01-05 15:30:43 +03:00
if ( ctxt - > error ! = 0 )
goto error ;
2003-12-03 01:32:15 +03:00
SKIP_BLANKS ;
while ( CUR = = ' / ' ) {
2005-06-06 17:49:18 +04:00
if ( NXT ( 1 ) = = ' / ' ) {
2003-12-03 01:32:15 +03:00
PUSH ( XML_OP_ANCESTOR , NULL , NULL ) ;
NEXT ;
NEXT ;
SKIP_BLANKS ;
xmlCompileStepPattern ( ctxt ) ;
2006-01-05 15:30:43 +03:00
if ( ctxt - > error ! = 0 )
goto error ;
2003-12-03 01:32:15 +03:00
} else {
PUSH ( XML_OP_PARENT , NULL , NULL ) ;
NEXT ;
SKIP_BLANKS ;
2006-01-05 15:30:43 +03:00
if ( CUR = = 0 ) {
ERROR5 ( NULL , NULL , NULL ,
" Incomplete expression '%s'. \n " , ctxt - > base ) ;
ctxt - > error = 1 ;
2012-09-11 09:26:36 +04:00
goto error ;
2003-12-03 01:32:15 +03:00
}
2006-01-05 15:30:43 +03:00
xmlCompileStepPattern ( ctxt ) ;
if ( ctxt - > error ! = 0 )
goto error ;
2003-12-03 01:32:15 +03:00
}
}
}
2005-02-16 03:22:29 +03:00
if ( CUR ! = 0 ) {
ERROR5 ( NULL , NULL , NULL ,
" Failed to compile pattern %s \n " , ctxt - > base ) ;
ctxt - > error = 1 ;
}
2003-12-03 01:32:15 +03:00
error :
return ;
}
2005-01-30 21:42:55 +03:00
2005-10-19 21:00:53 +04:00
/**
* xmlCompileIDCXPathPath :
* @ ctxt : the compilation context
*
* Compile the Path Pattern and generates a precompiled
* form suitable for fast matching .
*
2012-09-11 09:26:36 +04:00
* [ 5 ] Path : : = ( ' . //')? ( Step '/' )* ( Step | '@' NameTest )
2005-10-19 21:00:53 +04:00
*/
static void
xmlCompileIDCXPathPath ( xmlPatParserContextPtr ctxt ) {
SKIP_BLANKS ;
if ( CUR = = ' / ' ) {
ERROR5 ( NULL , NULL , NULL ,
" Unexpected selection of the document root in '%s'. \n " ,
ctxt - > base ) ;
goto error ;
}
ctxt - > comp - > flags | = PAT_FROM_CUR ;
if ( CUR = = ' . ' ) {
/* "." - "self::node()" */
NEXT ;
SKIP_BLANKS ;
if ( CUR = = 0 ) {
/*
* Selection of the context node .
*/
PUSH ( XML_OP_ELEM , NULL , NULL ) ;
return ;
}
if ( CUR ! = ' / ' ) {
/* TODO: A more meaningful error message. */
ERROR5 ( NULL , NULL , NULL ,
" Unexpected token after '.' in '%s'. \n " , ctxt - > base ) ;
goto error ;
}
/* "./" - "self::node()/" */
NEXT ;
SKIP_BLANKS ;
if ( CUR = = ' / ' ) {
if ( IS_BLANK_CH ( PEEKPREV ( 1 ) ) ) {
/*
* Disallow " ./ / "
*/
ERROR5 ( NULL , NULL , NULL ,
" Unexpected '/' token in '%s'. \n " , ctxt - > base ) ;
goto error ;
}
/* ".//" - "self:node()/descendant-or-self::node()/" */
PUSH ( XML_OP_ANCESTOR , NULL , NULL ) ;
NEXT ;
SKIP_BLANKS ;
}
if ( CUR = = 0 )
goto error_unfinished ;
}
/*
* Process steps .
*/
do {
xmlCompileStepPattern ( ctxt ) ;
2012-09-11 09:26:36 +04:00
if ( ctxt - > error ! = 0 )
2005-10-19 21:00:53 +04:00
goto error ;
SKIP_BLANKS ;
if ( CUR ! = ' / ' )
break ;
PUSH ( XML_OP_PARENT , NULL , NULL ) ;
NEXT ;
SKIP_BLANKS ;
if ( CUR = = ' / ' ) {
/*
* Disallow subsequent ' //'.
*/
ERROR5 ( NULL , NULL , NULL ,
" Unexpected subsequent '//' in '%s'. \n " ,
ctxt - > base ) ;
goto error ;
}
if ( CUR = = 0 )
goto error_unfinished ;
2012-09-11 09:26:36 +04:00
2005-10-19 21:00:53 +04:00
} while ( CUR ! = 0 ) ;
if ( CUR ! = 0 ) {
ERROR5 ( NULL , NULL , NULL ,
" Failed to compile expression '%s'. \n " , ctxt - > base ) ;
ctxt - > error = 1 ;
}
return ;
error :
ctxt - > error = 1 ;
return ;
error_unfinished :
ctxt - > error = 1 ;
ERROR5 ( NULL , NULL , NULL ,
2012-09-11 09:26:36 +04:00
" Unfinished expression '%s'. \n " , ctxt - > base ) ;
2005-10-19 21:00:53 +04:00
return ;
}
2005-01-30 21:42:55 +03:00
/************************************************************************
* *
* The streaming code *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* xmlNewStreamComp :
* @ size : the number of expected steps
*
* build a new compiled pattern for streaming
*
* Returns the new structure or NULL in case of error .
*/
static xmlStreamCompPtr
xmlNewStreamComp ( int size ) {
xmlStreamCompPtr cur ;
if ( size < 4 )
size = 4 ;
cur = ( xmlStreamCompPtr ) xmlMalloc ( sizeof ( xmlStreamComp ) ) ;
if ( cur = = NULL ) {
ERROR ( NULL , NULL , NULL ,
" xmlNewStreamComp: malloc failed \n " ) ;
return ( NULL ) ;
}
memset ( cur , 0 , sizeof ( xmlStreamComp ) ) ;
cur - > steps = ( xmlStreamStepPtr ) xmlMalloc ( size * sizeof ( xmlStreamStep ) ) ;
if ( cur - > steps = = NULL ) {
xmlFree ( cur ) ;
ERROR ( NULL , NULL , NULL ,
" xmlNewStreamComp: malloc failed \n " ) ;
return ( NULL ) ;
}
cur - > nbStep = 0 ;
cur - > maxStep = size ;
return ( cur ) ;
}
/**
* xmlFreeStreamComp :
* @ comp : the compiled pattern for streaming
*
* Free the compiled pattern for streaming
*/
static void
xmlFreeStreamComp ( xmlStreamCompPtr comp ) {
if ( comp ! = NULL ) {
if ( comp - > steps ! = NULL )
xmlFree ( comp - > steps ) ;
if ( comp - > dict ! = NULL )
xmlDictFree ( comp - > dict ) ;
xmlFree ( comp ) ;
}
}
/**
* xmlStreamCompAddStep :
* @ comp : the compiled pattern for streaming
* @ name : the first string , the name , or NULL for *
* @ ns : the second step , the namespace name
* @ flags : the flags for that step
*
* Add a new step to the compiled pattern
*
* Returns - 1 in case of error or the step index if successful
*/
static int
xmlStreamCompAddStep ( xmlStreamCompPtr comp , const xmlChar * name ,
2006-01-05 15:30:43 +03:00
const xmlChar * ns , int nodeType , int flags ) {
2005-01-30 21:42:55 +03:00
xmlStreamStepPtr cur ;
if ( comp - > nbStep > = comp - > maxStep ) {
cur = ( xmlStreamStepPtr ) xmlRealloc ( comp - > steps ,
comp - > maxStep * 2 * sizeof ( xmlStreamStep ) ) ;
if ( cur = = NULL ) {
ERROR ( NULL , NULL , NULL ,
" xmlNewStreamComp: malloc failed \n " ) ;
return ( - 1 ) ;
}
comp - > steps = cur ;
comp - > maxStep * = 2 ;
}
cur = & comp - > steps [ comp - > nbStep + + ] ;
cur - > flags = flags ;
cur - > name = name ;
cur - > ns = ns ;
2006-01-05 15:30:43 +03:00
cur - > nodeType = nodeType ;
2005-01-30 21:42:55 +03:00
return ( comp - > nbStep - 1 ) ;
}
/**
* xmlStreamCompile :
* @ comp : the precompiled pattern
2012-09-11 09:26:36 +04:00
*
2005-01-30 21:42:55 +03:00
* Tries to stream compile a pattern
*
* Returns - 1 in case of failure and 0 in case of success .
*/
static int
xmlStreamCompile ( xmlPatternPtr comp ) {
xmlStreamCompPtr stream ;
2006-01-05 17:44:45 +03:00
int i , s = 0 , root = 0 , flags = 0 , prevs = - 1 ;
2006-01-05 15:30:43 +03:00
xmlStepOp step ;
2005-01-30 21:42:55 +03:00
if ( ( comp = = NULL ) | | ( comp - > steps = = NULL ) )
return ( - 1 ) ;
2005-02-16 03:22:29 +03:00
/*
* special case for .
*/
if ( ( comp - > nbStep = = 1 ) & &
( comp - > steps [ 0 ] . op = = XML_OP_ELEM ) & &
( comp - > steps [ 0 ] . value = = NULL ) & &
( comp - > steps [ 0 ] . value2 = = NULL ) ) {
stream = xmlNewStreamComp ( 0 ) ;
if ( stream = = NULL )
return ( - 1 ) ;
2006-01-05 15:30:43 +03:00
/* Note that the stream will have no steps in this case. */
stream - > flags | = XML_STREAM_FINAL_IS_ANY_NODE ;
2005-02-16 03:22:29 +03:00
comp - > stream = stream ;
return ( 0 ) ;
}
2005-01-30 21:42:55 +03:00
stream = xmlNewStreamComp ( ( comp - > nbStep / 2 ) + 1 ) ;
if ( stream = = NULL )
return ( - 1 ) ;
if ( comp - > dict ! = NULL ) {
stream - > dict = comp - > dict ;
xmlDictReference ( stream - > dict ) ;
}
2005-02-21 13:44:36 +03:00
2012-09-11 09:26:36 +04:00
i = 0 ;
2006-01-05 15:30:43 +03:00
if ( comp - > flags & PAT_FROM_ROOT )
stream - > flags | = XML_STREAM_FROM_ROOT ;
2005-02-21 13:44:36 +03:00
for ( ; i < comp - > nbStep ; i + + ) {
2006-01-05 15:30:43 +03:00
step = comp - > steps [ i ] ;
switch ( step . op ) {
2005-01-30 21:42:55 +03:00
case XML_OP_END :
break ;
case XML_OP_ROOT :
if ( i ! = 0 )
goto error ;
root = 1 ;
break ;
case XML_OP_NS :
2006-01-05 15:30:43 +03:00
s = xmlStreamCompAddStep ( stream , NULL , step . value ,
2012-09-11 09:26:36 +04:00
XML_ELEMENT_NODE , flags ) ;
2005-02-18 00:34:45 +03:00
if ( s < 0 )
goto error ;
2006-01-05 17:44:45 +03:00
prevs = s ;
2012-09-11 09:26:36 +04:00
flags = 0 ;
break ;
2005-02-18 00:34:45 +03:00
case XML_OP_ATTR :
flags | = XML_STREAM_STEP_ATTR ;
2006-01-05 17:44:45 +03:00
prevs = - 1 ;
2006-01-05 15:30:43 +03:00
s = xmlStreamCompAddStep ( stream ,
step . value , step . value2 , XML_ATTRIBUTE_NODE , flags ) ;
2005-02-18 00:34:45 +03:00
flags = 0 ;
if ( s < 0 )
goto error ;
break ;
2012-09-11 09:26:36 +04:00
case XML_OP_ELEM :
2006-01-05 15:30:43 +03:00
if ( ( step . value = = NULL ) & & ( step . value2 = = NULL ) ) {
/*
* We have a " . " or " self::node() " here .
* Eliminate redundant self : : node ( ) tests like in " /./. "
* or " //./ "
* The only case we won ' t eliminate is " //. " , i . e . if
* self : : node ( ) is the last node test and we had
* continuation somewhere beforehand .
*/
if ( ( comp - > nbStep = = i + 1 ) & &
( flags & XML_STREAM_STEP_DESC ) ) {
/*
* Mark the special case where the expression resolves
* to any type of node .
*/
if ( comp - > nbStep = = i + 1 ) {
stream - > flags | = XML_STREAM_FINAL_IS_ANY_NODE ;
}
2012-09-11 09:26:36 +04:00
flags | = XML_STREAM_STEP_NODE ;
2006-01-05 15:30:43 +03:00
s = xmlStreamCompAddStep ( stream , NULL , NULL ,
XML_STREAM_ANY_NODE , flags ) ;
if ( s < 0 )
goto error ;
2006-01-05 17:44:45 +03:00
flags = 0 ;
/*
* If there was a previous step , mark it to be added to
* the result node - set ; this is needed since only
* the last step will be marked as " final " and only
* " final " nodes are added to the resulting set .
*/
if ( prevs ! = - 1 ) {
stream - > steps [ prevs ] . flags | = XML_STREAM_STEP_IN_SET ;
prevs = - 1 ;
}
2012-09-11 09:26:36 +04:00
break ;
2006-01-05 15:30:43 +03:00
} else {
/* Just skip this one. */
continue ;
}
}
2012-09-11 09:26:36 +04:00
/* An element node. */
2006-01-05 15:30:43 +03:00
s = xmlStreamCompAddStep ( stream , step . value , step . value2 ,
2012-09-11 09:26:36 +04:00
XML_ELEMENT_NODE , flags ) ;
2006-01-05 15:30:43 +03:00
if ( s < 0 )
goto error ;
2006-01-05 17:44:45 +03:00
prevs = s ;
2012-09-11 09:26:36 +04:00
flags = 0 ;
break ;
2005-02-21 13:44:36 +03:00
case XML_OP_CHILD :
2006-01-05 15:30:43 +03:00
/* An element node child. */
s = xmlStreamCompAddStep ( stream , step . value , step . value2 ,
2012-09-11 09:26:36 +04:00
XML_ELEMENT_NODE , flags ) ;
2005-01-30 21:42:55 +03:00
if ( s < 0 )
goto error ;
2006-01-05 17:44:45 +03:00
prevs = s ;
flags = 0 ;
2012-09-11 09:26:36 +04:00
break ;
2005-01-30 21:42:55 +03:00
case XML_OP_ALL :
2006-01-05 15:30:43 +03:00
s = xmlStreamCompAddStep ( stream , NULL , NULL ,
2012-09-11 09:26:36 +04:00
XML_ELEMENT_NODE , flags ) ;
2005-01-30 21:42:55 +03:00
if ( s < 0 )
goto error ;
2006-01-05 17:44:45 +03:00
prevs = s ;
flags = 0 ;
2005-01-30 21:42:55 +03:00
break ;
2012-09-11 09:26:36 +04:00
case XML_OP_PARENT :
2005-01-30 21:42:55 +03:00
break ;
case XML_OP_ANCESTOR :
2006-01-05 15:30:43 +03:00
/* Skip redundant continuations. */
if ( flags & XML_STREAM_STEP_DESC )
break ;
2005-02-18 00:34:45 +03:00
flags | = XML_STREAM_STEP_DESC ;
2005-06-14 23:24:47 +04:00
/*
* Mark the expression as having " // " .
*/
if ( ( stream - > flags & XML_STREAM_DESC ) = = 0 )
stream - > flags | = XML_STREAM_DESC ;
2005-01-30 21:42:55 +03:00
break ;
}
2012-09-11 09:26:36 +04:00
}
2005-06-14 23:24:47 +04:00
if ( ( ! root ) & & ( comp - > flags & XML_PATTERN_NOTPATTERN ) = = 0 ) {
/*
* If this should behave like a real pattern , we will mark
* the first step as having " // " , to be reentrant on every
* tree level .
*/
if ( ( stream - > flags & XML_STREAM_DESC ) = = 0 )
stream - > flags | = XML_STREAM_DESC ;
if ( stream - > nbStep > 0 ) {
if ( ( stream - > steps [ 0 ] . flags & XML_STREAM_STEP_DESC ) = = 0 )
2012-09-11 09:26:36 +04:00
stream - > steps [ 0 ] . flags | = XML_STREAM_STEP_DESC ;
2005-06-14 23:24:47 +04:00
}
2005-01-30 21:42:55 +03:00
}
2006-01-05 15:30:43 +03:00
if ( stream - > nbStep < = s )
goto error ;
2005-01-30 21:42:55 +03:00
stream - > steps [ s ] . flags | = XML_STREAM_STEP_FINAL ;
if ( root )
stream - > steps [ 0 ] . flags | = XML_STREAM_STEP_ROOT ;
comp - > stream = stream ;
return ( 0 ) ;
error :
xmlFreeStreamComp ( stream ) ;
return ( 0 ) ;
}
/**
* xmlNewStreamCtxt :
* @ size : the number of expected states
*
* build a new stream context
*
* Returns the new structure or NULL in case of error .
*/
static xmlStreamCtxtPtr
xmlNewStreamCtxt ( xmlStreamCompPtr stream ) {
xmlStreamCtxtPtr cur ;
cur = ( xmlStreamCtxtPtr ) xmlMalloc ( sizeof ( xmlStreamCtxt ) ) ;
if ( cur = = NULL ) {
ERROR ( NULL , NULL , NULL ,
" xmlNewStreamCtxt: malloc failed \n " ) ;
return ( NULL ) ;
}
memset ( cur , 0 , sizeof ( xmlStreamCtxt ) ) ;
cur - > states = ( int * ) xmlMalloc ( 4 * 2 * sizeof ( int ) ) ;
if ( cur - > states = = NULL ) {
xmlFree ( cur ) ;
ERROR ( NULL , NULL , NULL ,
" xmlNewStreamCtxt: malloc failed \n " ) ;
return ( NULL ) ;
}
cur - > nbState = 0 ;
cur - > maxState = 4 ;
cur - > level = 0 ;
cur - > comp = stream ;
2005-06-14 23:24:47 +04:00
cur - > blockLevel = - 1 ;
2005-01-30 21:42:55 +03:00
return ( cur ) ;
}
/**
* xmlFreeStreamCtxt :
* @ stream : the stream context
*
* Free the stream context
*/
void
xmlFreeStreamCtxt ( xmlStreamCtxtPtr stream ) {
2005-02-06 02:20:22 +03:00
xmlStreamCtxtPtr next ;
while ( stream ! = NULL ) {
next = stream - > next ;
2005-01-30 21:42:55 +03:00
if ( stream - > states ! = NULL )
xmlFree ( stream - > states ) ;
xmlFree ( stream ) ;
2005-02-06 02:20:22 +03:00
stream = next ;
2005-01-30 21:42:55 +03:00
}
}
/**
* xmlStreamCtxtAddState :
* @ comp : the stream context
* @ idx : the step index for that streaming state
*
* Add a new state to the stream context
*
* Returns - 1 in case of error or the state index if successful
*/
static int
xmlStreamCtxtAddState ( xmlStreamCtxtPtr comp , int idx , int level ) {
int i ;
for ( i = 0 ; i < comp - > nbState ; i + + ) {
if ( comp - > states [ 2 * i ] < 0 ) {
comp - > states [ 2 * i ] = idx ;
comp - > states [ 2 * i + 1 ] = level ;
return ( i ) ;
}
}
if ( comp - > nbState > = comp - > maxState ) {
int * cur ;
cur = ( int * ) xmlRealloc ( comp - > states ,
comp - > maxState * 4 * sizeof ( int ) ) ;
if ( cur = = NULL ) {
ERROR ( NULL , NULL , NULL ,
" xmlNewStreamCtxt: malloc failed \n " ) ;
return ( - 1 ) ;
}
comp - > states = cur ;
comp - > maxState * = 2 ;
}
comp - > states [ 2 * comp - > nbState ] = idx ;
comp - > states [ 2 * comp - > nbState + + + 1 ] = level ;
return ( comp - > nbState - 1 ) ;
}
/**
2005-02-18 00:34:45 +03:00
* xmlStreamPushInternal :
2005-01-30 21:42:55 +03:00
* @ stream : the stream context
* @ name : the current name
* @ ns : the namespace name
2005-02-18 00:34:45 +03:00
* @ nodeType : the type of the node
2005-01-30 21:42:55 +03:00
*
2005-06-06 17:49:18 +04:00
* Push new data onto the stream . NOTE : if the call xmlPatterncompile ( )
* indicated a dictionary , then strings for name and ns will be expected
2005-01-30 21:42:55 +03:00
* to come from the dictionary .
* Both @ name and @ ns being NULL means the / i . e . the root of the document .
* This can also act as a reset .
*
* Returns : - 1 in case of error , 1 if the current state in the stream is a
* match and 0 otherwise .
*/
2005-02-18 00:34:45 +03:00
static int
xmlStreamPushInternal ( xmlStreamCtxtPtr stream ,
const xmlChar * name , const xmlChar * ns ,
2006-01-05 15:30:43 +03:00
int nodeType ) {
2023-12-10 17:30:47 +03:00
int ret = 0 , final = 0 , tmp , i , m , match , stepNr , desc ;
2005-01-30 21:42:55 +03:00
xmlStreamCompPtr comp ;
2006-05-16 19:13:37 +04:00
xmlStreamStep step ;
2005-01-30 21:42:55 +03:00
if ( ( stream = = NULL ) | | ( stream - > nbState < 0 ) )
return ( - 1 ) ;
2005-02-05 19:35:04 +03:00
while ( stream ! = NULL ) {
comp = stream - > comp ;
2006-01-05 15:30:43 +03:00
if ( ( nodeType = = XML_ELEMENT_NODE ) & &
( name = = NULL ) & & ( ns = = NULL ) ) {
/* We have a document node here (or a reset). */
2005-02-05 19:35:04 +03:00
stream - > nbState = 0 ;
stream - > level = 0 ;
2005-06-14 23:24:47 +04:00
stream - > blockLevel = - 1 ;
2006-01-05 15:30:43 +03:00
if ( comp - > flags & XML_STREAM_FROM_ROOT ) {
if ( comp - > nbStep = = 0 ) {
/* TODO: We have a "/." here? */
2005-02-05 19:35:04 +03:00
ret = 1 ;
2006-01-05 15:30:43 +03:00
} else {
if ( ( comp - > nbStep = = 1 ) & &
( comp - > steps [ 0 ] . nodeType = = XML_STREAM_ANY_NODE ) & &
( comp - > steps [ 0 ] . flags & XML_STREAM_STEP_DESC ) )
{
/*
* In the case of " //. " the document node will match
* as well .
*/
ret = 1 ;
} else if ( comp - > steps [ 0 ] . flags & XML_STREAM_STEP_ROOT ) {
2023-12-10 17:30:47 +03:00
if ( xmlStreamCtxtAddState ( stream , 0 , 0 ) < 0 )
return ( - 1 ) ;
2006-01-05 15:30:43 +03:00
}
}
2005-01-30 21:42:55 +03:00
}
2005-02-06 02:20:22 +03:00
stream = stream - > next ;
2005-02-05 19:35:04 +03:00
continue ; /* while */
2005-01-30 21:42:55 +03:00
}
2005-02-18 00:34:45 +03:00
/*
* Fast check for " . " .
*/
if ( comp - > nbStep = = 0 ) {
2005-09-04 16:01:57 +04:00
/*
* / and . are handled at the XPath node set creation
* level by checking min depth
*/
if ( stream - > flags & XML_PATTERN_XPATH ) {
stream = stream - > next ;
continue ; /* while */
}
2005-05-09 20:01:05 +04:00
/*
2005-06-09 22:12:28 +04:00
* For non - pattern like evaluation like XML Schema IDCs
* or traditional XPath expressions , this will match if
* we are at the first level only , otherwise on every level .
2005-05-09 20:01:05 +04:00
*/
2006-01-05 15:30:43 +03:00
if ( ( nodeType ! = XML_ATTRIBUTE_NODE ) & &
2005-05-09 20:01:05 +04:00
( ( ( stream - > flags & XML_PATTERN_NOTPATTERN ) = = 0 ) | |
( stream - > level = = 0 ) ) ) {
2012-09-11 09:26:36 +04:00
ret = 1 ;
2005-05-09 20:01:05 +04:00
}
stream - > level + + ;
2005-02-18 00:34:45 +03:00
goto stream_next ;
}
2005-06-14 23:24:47 +04:00
if ( stream - > blockLevel ! = - 1 ) {
/*
* Skip blocked expressions .
*/
2012-09-11 09:26:36 +04:00
stream - > level + + ;
2005-06-14 23:24:47 +04:00
goto stream_next ;
2005-06-09 22:12:28 +04:00
}
2006-01-05 15:30:43 +03:00
if ( ( nodeType ! = XML_ELEMENT_NODE ) & &
( nodeType ! = XML_ATTRIBUTE_NODE ) & &
( ( comp - > flags & XML_STREAM_FINAL_IS_ANY_NODE ) = = 0 ) ) {
/*
* No need to process nodes of other types if we don ' t
* resolve to those types .
* TODO : Do we need to block the context here ?
*/
stream - > level + + ;
goto stream_next ;
}
2005-02-05 19:35:04 +03:00
/*
* Check evolution of existing states
*/
2005-06-14 23:24:47 +04:00
i = 0 ;
2005-02-05 19:35:04 +03:00
m = stream - > nbState ;
2005-06-14 23:24:47 +04:00
while ( i < m ) {
if ( ( comp - > flags & XML_STREAM_DESC ) = = 0 ) {
/*
* If there is no " // " , then only the last
* added state is of interest .
*/
2006-05-16 19:13:37 +04:00
stepNr = stream - > states [ 2 * ( stream - > nbState - 1 ) ] ;
2005-06-14 23:24:47 +04:00
/*
* TODO : Security check , should not happen , remove it .
*/
if ( stream - > states [ ( 2 * ( stream - > nbState - 1 ) ) + 1 ] <
stream - > level ) {
return ( - 1 ) ;
}
desc = 0 ;
/* loop-stopper */
i = m ;
} else {
/*
* If there are " // " , then we need to process every " // "
2019-09-30 18:04:54 +03:00
* occurring in the states , plus any other state for this
2005-06-14 23:24:47 +04:00
* level .
2012-09-11 09:26:36 +04:00
*/
2006-05-16 19:13:37 +04:00
stepNr = stream - > states [ 2 * i ] ;
2005-06-14 23:24:47 +04:00
/* TODO: should not happen anymore: dead states */
2006-05-16 19:13:37 +04:00
if ( stepNr < 0 )
2005-06-14 23:24:47 +04:00
goto next_state ;
tmp = stream - > states [ ( 2 * i ) + 1 ] ;
/* skip new states just added */
if ( tmp > stream - > level )
goto next_state ;
/* skip states at ancestor levels, except if "//" */
2006-05-16 19:13:37 +04:00
desc = comp - > steps [ stepNr ] . flags & XML_STREAM_STEP_DESC ;
2005-06-14 23:24:47 +04:00
if ( ( tmp < stream - > level ) & & ( ! desc ) )
goto next_state ;
}
2012-09-11 09:26:36 +04:00
/*
2005-02-18 00:34:45 +03:00
* Check for correct node - type .
*/
2006-05-16 19:13:37 +04:00
step = comp - > steps [ stepNr ] ;
if ( step . nodeType ! = nodeType ) {
if ( step . nodeType = = XML_ATTRIBUTE_NODE ) {
2005-10-19 21:00:53 +04:00
/*
* Block this expression for deeper evaluation .
*/
if ( ( comp - > flags & XML_STREAM_DESC ) = = 0 )
stream - > blockLevel = stream - > level + 1 ;
2005-10-14 18:33:48 +04:00
goto next_state ;
2006-05-16 19:13:37 +04:00
} else if ( step . nodeType ! = XML_STREAM_ANY_NODE )
2005-10-14 18:33:48 +04:00
goto next_state ;
2012-09-11 09:26:36 +04:00
}
2005-06-14 23:24:47 +04:00
/*
* Compare local / namespace - name .
*/
match = 0 ;
2006-05-16 19:13:37 +04:00
if ( step . nodeType = = XML_STREAM_ANY_NODE ) {
2006-01-05 15:30:43 +03:00
match = 1 ;
2006-05-16 19:13:37 +04:00
} else if ( step . name = = NULL ) {
if ( step . ns = = NULL ) {
/*
* This lets through all elements / attributes .
*/
match = 1 ;
} else if ( ns ! = NULL )
match = xmlStrEqual ( step . ns , ns ) ;
} else if ( ( ( step . ns ! = NULL ) = = ( ns ! = NULL ) ) & &
( name ! = NULL ) & &
( step . name [ 0 ] = = name [ 0 ] ) & &
xmlStrEqual ( step . name , name ) & &
( ( step . ns = = ns ) | | xmlStrEqual ( step . ns , ns ) ) )
{
2012-09-11 09:26:36 +04:00
match = 1 ;
}
#if 0
2006-05-16 19:13:37 +04:00
/*
* TODO : Pointer comparison won ' t work , since not guaranteed that the given
* values are in the same dict ; especially if it ' s the namespace name ,
* normally coming from ns - > href . We need a namespace dict mechanism !
*/
2006-01-05 15:30:43 +03:00
} else if ( comp - > dict ) {
2006-05-16 19:13:37 +04:00
if ( step . name = = NULL ) {
if ( step . ns = = NULL )
2005-02-05 19:35:04 +03:00
match = 1 ;
else
2006-05-16 19:13:37 +04:00
match = ( step . ns = = ns ) ;
2005-01-30 21:42:55 +03:00
} else {
2006-05-16 19:13:37 +04:00
match = ( ( step . name = = name ) & & ( step . ns = = ns ) ) ;
2005-01-30 21:42:55 +03:00
}
2012-09-11 09:26:36 +04:00
# endif /* if 0 ------------------------------------------------------- */
if ( match ) {
2006-05-16 19:13:37 +04:00
final = step . flags & XML_STREAM_STEP_FINAL ;
2023-02-21 17:35:57 +03:00
if ( final ) {
ret = 1 ;
2023-12-10 17:30:47 +03:00
} else if ( xmlStreamCtxtAddState ( stream , stepNr + 1 ,
stream - > level + 1 ) < 0 ) {
return ( - 1 ) ;
2023-02-21 17:35:57 +03:00
}
2006-05-16 19:13:37 +04:00
if ( ( ret ! = 1 ) & & ( step . flags & XML_STREAM_STEP_IN_SET ) ) {
2006-01-05 17:44:45 +03:00
/*
* Check if we have a special case like " foo/bar//. " , where
* " foo " is selected as well .
*/
ret = 1 ;
}
2012-09-11 09:26:36 +04:00
}
2005-06-14 23:24:47 +04:00
if ( ( ( comp - > flags & XML_STREAM_DESC ) = = 0 ) & &
( ( ! match ) | | final ) ) {
/*
* Mark this expression as blocked for any evaluation at
* deeper levels . Note that this includes " /foo "
* expressions if the * pattern * behaviour is used .
*/
stream - > blockLevel = stream - > level + 1 ;
}
next_state :
i + + ;
2005-01-30 21:42:55 +03:00
}
2005-02-05 19:35:04 +03:00
stream - > level + + ;
2005-06-14 23:24:47 +04:00
2005-02-18 00:34:45 +03:00
/*
2005-06-14 23:24:47 +04:00
* Re / enter the expression .
2006-01-05 15:30:43 +03:00
* Don ' t reenter if it ' s an absolute expression like " /foo " ,
* except " //foo " .
2005-02-18 00:34:45 +03:00
*/
2006-05-16 19:13:37 +04:00
step = comp - > steps [ 0 ] ;
if ( step . flags & XML_STREAM_STEP_ROOT )
2005-06-14 23:24:47 +04:00
goto stream_next ;
2006-05-16 19:13:37 +04:00
desc = step . flags & XML_STREAM_STEP_DESC ;
2005-06-14 23:24:47 +04:00
if ( stream - > flags & XML_PATTERN_NOTPATTERN ) {
/*
* Re / enter the expression if it is a " descendant " one ,
* or if we are at the 1 st level of evaluation .
*/
2012-09-11 09:26:36 +04:00
2005-06-14 23:24:47 +04:00
if ( stream - > level = = 1 ) {
if ( XML_STREAM_XS_IDC ( stream ) ) {
/*
* XS - IDC : The missing " self::node() " will always
* match the first given node .
*/
goto stream_next ;
} else
goto compare ;
2012-09-11 09:26:36 +04:00
}
2005-06-14 23:24:47 +04:00
/*
* A " // " is always reentrant .
*/
if ( desc )
goto compare ;
2005-03-04 21:04:59 +03:00
2005-06-14 23:24:47 +04:00
/*
* XS - IDC : Process the 2 nd level , since the missing
* " self::node() " is responsible for the 2 nd level being
2012-09-11 09:26:36 +04:00
* the real start level .
*/
2005-06-14 23:24:47 +04:00
if ( ( stream - > level = = 2 ) & & XML_STREAM_XS_IDC ( stream ) )
goto compare ;
2005-03-04 21:04:59 +03:00
2005-06-14 23:24:47 +04:00
goto stream_next ;
}
2012-09-11 09:26:36 +04:00
2005-06-14 23:24:47 +04:00
compare :
/*
* Check expected node - type .
2005-03-04 21:04:59 +03:00
*/
2006-05-16 19:13:37 +04:00
if ( step . nodeType ! = nodeType ) {
2006-01-05 15:30:43 +03:00
if ( nodeType = = XML_ATTRIBUTE_NODE )
2005-10-14 18:33:48 +04:00
goto stream_next ;
2006-05-16 19:13:37 +04:00
else if ( step . nodeType ! = XML_STREAM_ANY_NODE )
2012-09-11 09:26:36 +04:00
goto stream_next ;
2005-10-14 18:33:48 +04:00
}
2005-06-14 23:24:47 +04:00
/*
* Compare local / namespace - name .
*/
match = 0 ;
2006-05-16 19:13:37 +04:00
if ( step . nodeType = = XML_STREAM_ANY_NODE ) {
2006-01-05 15:30:43 +03:00
match = 1 ;
2006-05-16 19:13:37 +04:00
} else if ( step . name = = NULL ) {
if ( step . ns = = NULL ) {
/*
* This lets through all elements / attributes .
*/
2005-06-14 23:24:47 +04:00
match = 1 ;
2006-05-16 19:13:37 +04:00
} else if ( ns ! = NULL )
match = xmlStrEqual ( step . ns , ns ) ;
} else if ( ( ( step . ns ! = NULL ) = = ( ns ! = NULL ) ) & &
( name ! = NULL ) & &
( step . name [ 0 ] = = name [ 0 ] ) & &
xmlStrEqual ( step . name , name ) & &
( ( step . ns = = ns ) | | xmlStrEqual ( step . ns , ns ) ) )
{
2012-09-11 09:26:36 +04:00
match = 1 ;
}
2006-05-16 19:13:37 +04:00
final = step . flags & XML_STREAM_STEP_FINAL ;
2012-09-11 09:26:36 +04:00
if ( match ) {
2023-12-10 17:30:47 +03:00
if ( final ) {
2005-06-14 23:24:47 +04:00
ret = 1 ;
2023-12-10 17:30:47 +03:00
} else if ( xmlStreamCtxtAddState ( stream , 1 , stream - > level ) < 0 ) {
return ( - 1 ) ;
}
2006-05-16 19:13:37 +04:00
if ( ( ret ! = 1 ) & & ( step . flags & XML_STREAM_STEP_IN_SET ) ) {
2006-01-05 17:44:45 +03:00
/*
* Check if we have a special case like " foo//. " , where
* " foo " is selected as well .
*/
ret = 1 ;
}
2005-06-14 23:24:47 +04:00
}
if ( ( ( comp - > flags & XML_STREAM_DESC ) = = 0 ) & &
( ( ! match ) | | final ) ) {
/*
* Mark this expression as blocked for any evaluation at
* deeper levels .
*/
stream - > blockLevel = stream - > level ;
}
2005-10-19 21:00:53 +04:00
2005-02-18 00:34:45 +03:00
stream_next :
2005-02-05 19:35:04 +03:00
stream = stream - > next ;
} /* while stream != NULL */
2012-09-11 09:26:36 +04:00
2005-01-30 21:42:55 +03:00
return ( ret ) ;
}
2005-02-18 00:34:45 +03:00
/**
* xmlStreamPush :
* @ stream : the stream context
* @ name : the current name
* @ ns : the namespace name
*
2005-06-06 17:49:18 +04:00
* Push new data onto the stream . NOTE : if the call xmlPatterncompile ( )
* indicated a dictionary , then strings for name and ns will be expected
2005-02-18 00:34:45 +03:00
* to come from the dictionary .
* Both @ name and @ ns being NULL means the / i . e . the root of the document .
* This can also act as a reset .
2006-01-05 15:30:43 +03:00
* Otherwise the function will act as if it has been given an element - node .
2005-02-18 00:34:45 +03:00
*
* Returns : - 1 in case of error , 1 if the current state in the stream is a
* match and 0 otherwise .
*/
int
xmlStreamPush ( xmlStreamCtxtPtr stream ,
const xmlChar * name , const xmlChar * ns ) {
2022-09-01 02:18:30 +03:00
return ( xmlStreamPushInternal ( stream , name , ns , XML_ELEMENT_NODE ) ) ;
2006-01-05 15:30:43 +03:00
}
/**
2006-01-05 18:29:44 +03:00
* xmlStreamPushNode :
2006-01-05 15:30:43 +03:00
* @ stream : the stream context
* @ name : the current name
* @ ns : the namespace name
* @ nodeType : the type of the node being pushed
*
* Push new data onto the stream . NOTE : if the call xmlPatterncompile ( )
* indicated a dictionary , then strings for name and ns will be expected
* to come from the dictionary .
* Both @ name and @ ns being NULL means the / i . e . the root of the document .
* This can also act as a reset .
* Different from xmlStreamPush ( ) this function can be fed with nodes of type :
* element - , attribute - , text - , cdata - section - , comment - and
* processing - instruction - node .
*
* Returns : - 1 in case of error , 1 if the current state in the stream is a
* match and 0 otherwise .
*/
int
xmlStreamPushNode ( xmlStreamCtxtPtr stream ,
const xmlChar * name , const xmlChar * ns ,
int nodeType )
{
return ( xmlStreamPushInternal ( stream , name , ns ,
nodeType ) ) ;
2005-02-18 00:34:45 +03:00
}
/**
* xmlStreamPushAttr :
* @ stream : the stream context
* @ name : the current name
* @ ns : the namespace name
*
2005-06-06 17:49:18 +04:00
* Push new attribute data onto the stream . NOTE : if the call xmlPatterncompile ( )
* indicated a dictionary , then strings for name and ns will be expected
2005-02-18 00:34:45 +03:00
* to come from the dictionary .
* Both @ name and @ ns being NULL means the / i . e . the root of the document .
* This can also act as a reset .
2006-01-05 15:30:43 +03:00
* Otherwise the function will act as if it has been given an attribute - node .
2005-02-18 00:34:45 +03:00
*
* Returns : - 1 in case of error , 1 if the current state in the stream is a
* match and 0 otherwise .
*/
int
xmlStreamPushAttr ( xmlStreamCtxtPtr stream ,
const xmlChar * name , const xmlChar * ns ) {
2022-09-01 02:18:30 +03:00
return ( xmlStreamPushInternal ( stream , name , ns , XML_ATTRIBUTE_NODE ) ) ;
2005-02-18 00:34:45 +03:00
}
2005-01-30 21:42:55 +03:00
/**
* xmlStreamPop :
* @ stream : the stream context
*
* push one level from the stream .
*
* Returns : - 1 in case of error , 0 otherwise .
*/
int
xmlStreamPop ( xmlStreamCtxtPtr stream ) {
2005-06-14 23:24:47 +04:00
int i , lev ;
2012-09-11 09:26:36 +04:00
2005-01-30 21:42:55 +03:00
if ( stream = = NULL )
return ( - 1 ) ;
2005-02-05 19:35:04 +03:00
while ( stream ! = NULL ) {
2005-06-14 23:24:47 +04:00
/*
* Reset block - level .
*/
if ( stream - > blockLevel = = stream - > level )
stream - > blockLevel = - 1 ;
2008-07-17 09:29:16 +04:00
/*
* stream - > level can be zero when XML_FINAL_IS_ANY_NODE is set
* ( see the thread at
* http : //mail.gnome.org/archives/xslt/2008-July/msg00027.html)
*/
if ( stream - > level )
stream - > level - - ;
2005-02-05 19:35:04 +03:00
/*
* Check evolution of existing states
2012-09-11 09:26:36 +04:00
*/
2005-06-14 23:24:47 +04:00
for ( i = stream - > nbState - 1 ; i > = 0 ; i - - ) {
2005-02-05 19:35:04 +03:00
/* discard obsoleted states */
2005-06-14 23:24:47 +04:00
lev = stream - > states [ ( 2 * i ) + 1 ] ;
if ( lev > stream - > level )
stream - > nbState - - ;
if ( lev < = stream - > level )
break ;
2005-02-05 19:35:04 +03:00
}
stream = stream - > next ;
2005-02-01 19:21:43 +03:00
}
2005-01-30 21:42:55 +03:00
return ( 0 ) ;
}
2006-01-05 15:30:43 +03:00
/**
* xmlStreamWantsAnyNode :
2006-01-05 18:29:44 +03:00
* @ streamCtxt : the stream context
2006-01-05 15:30:43 +03:00
*
* Query if the streaming pattern additionally needs to be fed with
* text - , cdata - section - , comment - and processing - instruction - nodes .
* If the result is 0 then only element - nodes and attribute - nodes
* need to be pushed .
*
* Returns : 1 in case of need of nodes of the above described types ,
* 0 otherwise . - 1 on API errors .
*/
int
xmlStreamWantsAnyNode ( xmlStreamCtxtPtr streamCtxt )
2012-09-11 09:26:36 +04:00
{
2006-01-05 15:30:43 +03:00
if ( streamCtxt = = NULL )
return ( - 1 ) ;
while ( streamCtxt ! = NULL ) {
2012-09-11 09:26:36 +04:00
if ( streamCtxt - > comp - > flags & XML_STREAM_FINAL_IS_ANY_NODE )
2006-01-05 15:30:43 +03:00
return ( 1 ) ;
streamCtxt = streamCtxt - > next ;
}
return ( 0 ) ;
}
2003-12-03 01:32:15 +03:00
/************************************************************************
* *
* The public interfaces *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
2024-05-20 14:58:22 +03:00
* xmlPatternCompileSafe :
2003-12-03 01:32:15 +03:00
* @ pattern : the pattern to compile
2005-06-06 17:49:18 +04:00
* @ dict : an optional dictionary for interned strings
2005-07-23 19:00:22 +04:00
* @ flags : compilation flags , see xmlPatternFlags
2003-12-05 19:10:21 +03:00
* @ namespaces : the prefix definitions , array of [ URI , prefix ] or NULL
2023-12-10 17:30:47 +03:00
* @ patternOut : output pattern
2003-12-03 01:32:15 +03:00
*
2003-12-05 19:10:21 +03:00
* Compile a pattern .
2003-12-03 01:32:15 +03:00
*
2024-05-20 14:58:22 +03:00
* Available since 2.13 .0 .
*
2023-12-10 17:30:47 +03:00
* Returns 0 on success , 1 on error , - 1 if a memory allocation failed .
2003-12-03 01:32:15 +03:00
*/
2023-12-10 17:30:47 +03:00
int
xmlPatternCompileSafe ( const xmlChar * pattern , xmlDict * dict , int flags ,
const xmlChar * * namespaces , xmlPatternPtr * patternOut ) {
2005-02-05 19:35:04 +03:00
xmlPatternPtr ret = NULL , cur ;
2003-12-03 01:32:15 +03:00
xmlPatParserContextPtr ctxt = NULL ;
2005-02-05 19:35:04 +03:00
const xmlChar * or , * start ;
xmlChar * tmp = NULL ;
2005-02-21 13:44:36 +03:00
int type = 0 ;
int streamable = 1 ;
2023-12-10 17:30:47 +03:00
int error ;
2005-02-05 19:35:04 +03:00
2024-06-12 14:32:32 +03:00
if ( patternOut = = NULL )
return ( 1 ) ;
2023-12-10 17:30:47 +03:00
if ( pattern = = NULL ) {
error = 1 ;
goto error ;
}
2005-02-05 19:35:04 +03:00
start = pattern ;
2005-02-06 02:20:22 +03:00
or = start ;
2005-02-05 19:35:04 +03:00
while ( * or ! = 0 ) {
tmp = NULL ;
while ( ( * or ! = 0 ) & & ( * or ! = ' | ' ) ) or + + ;
if ( * or = = 0 )
ctxt = xmlNewPatParserContext ( start , dict , namespaces ) ;
else {
tmp = xmlStrndup ( start , or - start ) ;
if ( tmp ! = NULL ) {
ctxt = xmlNewPatParserContext ( tmp , dict , namespaces ) ;
}
or + + ;
}
2023-12-10 17:30:47 +03:00
if ( ctxt = = NULL ) {
error = - 1 ;
goto error ;
}
2005-02-05 19:35:04 +03:00
cur = xmlNewPattern ( ) ;
2023-12-10 17:30:47 +03:00
if ( cur = = NULL ) {
error = - 1 ;
goto error ;
}
2006-05-16 19:13:37 +04:00
/*
* Assign string dict .
*/
2012-09-11 09:26:36 +04:00
if ( dict ) {
2006-05-16 19:13:37 +04:00
cur - > dict = dict ;
xmlDictReference ( dict ) ;
}
2005-02-05 19:35:04 +03:00
if ( ret = = NULL )
ret = cur ;
else {
cur - > next = ret - > next ;
ret - > next = cur ;
}
2005-03-04 21:04:59 +03:00
cur - > flags = flags ;
2005-02-05 19:35:04 +03:00
ctxt - > comp = cur ;
2003-12-03 01:32:15 +03:00
2005-10-19 21:00:53 +04:00
if ( XML_STREAM_XS_IDC ( cur ) )
xmlCompileIDCXPathPath ( ctxt ) ;
else
xmlCompilePathPattern ( ctxt ) ;
2023-12-10 17:30:47 +03:00
if ( ctxt - > error ! = 0 ) {
error = ctxt - > error ;
2005-02-16 03:22:29 +03:00
goto error ;
2023-12-10 17:30:47 +03:00
}
2005-02-05 19:35:04 +03:00
xmlFreePatParserContext ( ctxt ) ;
2005-06-06 17:49:18 +04:00
ctxt = NULL ;
2003-12-03 01:32:15 +03:00
2005-02-21 13:44:36 +03:00
if ( streamable ) {
if ( type = = 0 ) {
type = cur - > flags & ( PAT_FROM_ROOT | PAT_FROM_CUR ) ;
} else if ( type = = PAT_FROM_ROOT ) {
if ( cur - > flags & PAT_FROM_CUR )
streamable = 0 ;
} else if ( type = = PAT_FROM_CUR ) {
if ( cur - > flags & PAT_FROM_ROOT )
streamable = 0 ;
}
}
2023-12-10 17:30:47 +03:00
if ( streamable ) {
error = xmlStreamCompile ( cur ) ;
if ( error ! = 0 )
goto error ;
}
error = xmlReversePattern ( cur ) ;
if ( error ! = 0 )
2005-02-05 19:35:04 +03:00
goto error ;
2005-06-09 22:12:28 +04:00
if ( tmp ! = NULL ) {
2005-02-05 19:35:04 +03:00
xmlFree ( tmp ) ;
2005-06-09 22:12:28 +04:00
tmp = NULL ;
}
2005-02-06 02:20:22 +03:00
start = or ;
2005-02-05 19:35:04 +03:00
}
2005-02-21 13:44:36 +03:00
if ( streamable = = 0 ) {
cur = ret ;
while ( cur ! = NULL ) {
if ( cur - > stream ! = NULL ) {
xmlFreeStreamComp ( cur - > stream ) ;
cur - > stream = NULL ;
}
cur = cur - > next ;
}
}
2005-03-04 21:04:59 +03:00
2023-12-10 17:30:47 +03:00
* patternOut = ret ;
return ( 0 ) ;
2003-12-03 01:32:15 +03:00
error :
if ( ctxt ! = NULL ) xmlFreePatParserContext ( ctxt ) ;
if ( ret ! = NULL ) xmlFreePattern ( ret ) ;
2005-02-05 19:35:04 +03:00
if ( tmp ! = NULL ) xmlFree ( tmp ) ;
2023-12-10 17:30:47 +03:00
* patternOut = NULL ;
return ( error ) ;
}
/**
* xmlPatterncompile :
* @ pattern : the pattern to compile
* @ dict : an optional dictionary for interned strings
* @ flags : compilation flags , see xmlPatternFlags
* @ namespaces : the prefix definitions , array of [ URI , prefix ] or NULL
*
* Compile a pattern .
*
* Returns the compiled form of the pattern or NULL in case of error
*/
xmlPatternPtr
xmlPatterncompile ( const xmlChar * pattern , xmlDict * dict , int flags ,
const xmlChar * * namespaces ) {
xmlPatternPtr ret ;
xmlPatternCompileSafe ( pattern , dict , flags , namespaces , & ret ) ;
return ( ret ) ;
2003-12-03 01:32:15 +03:00
}
/**
* xmlPatternMatch :
* @ comp : the precompiled pattern
* @ node : a node
*
2005-06-06 17:49:18 +04:00
* Test whether the node matches the pattern
2003-12-03 01:32:15 +03:00
*
* Returns 1 if it matches , 0 if it doesn ' t and - 1 in case of failure
*/
int
xmlPatternMatch ( xmlPatternPtr comp , xmlNodePtr node )
{
2005-02-05 19:35:04 +03:00
int ret = 0 ;
2003-12-03 01:32:15 +03:00
if ( ( comp = = NULL ) | | ( node = = NULL ) )
return ( - 1 ) ;
2005-02-05 19:35:04 +03:00
while ( comp ! = NULL ) {
ret = xmlPatMatch ( comp , node ) ;
if ( ret ! = 0 )
return ( ret ) ;
comp = comp - > next ;
}
return ( ret ) ;
2003-12-03 01:32:15 +03:00
}
2005-01-30 21:42:55 +03:00
/**
* xmlPatternGetStreamCtxt :
* @ comp : the precompiled pattern
*
* Get a streaming context for that pattern
* Use xmlFreeStreamCtxt to free the context .
*
* Returns a pointer to the context or NULL in case of failure
*/
xmlStreamCtxtPtr
xmlPatternGetStreamCtxt ( xmlPatternPtr comp )
{
2005-02-05 19:35:04 +03:00
xmlStreamCtxtPtr ret = NULL , cur ;
2005-01-30 21:42:55 +03:00
if ( ( comp = = NULL ) | | ( comp - > stream = = NULL ) )
return ( NULL ) ;
2005-02-05 19:35:04 +03:00
while ( comp ! = NULL ) {
if ( comp - > stream = = NULL )
goto failed ;
cur = xmlNewStreamCtxt ( comp - > stream ) ;
if ( cur = = NULL )
goto failed ;
if ( ret = = NULL )
ret = cur ;
else {
cur - > next = ret - > next ;
ret - > next = cur ;
}
2005-03-04 21:04:59 +03:00
cur - > flags = comp - > flags ;
2005-02-05 19:35:04 +03:00
comp = comp - > next ;
}
return ( ret ) ;
failed :
xmlFreeStreamCtxt ( ret ) ;
return ( NULL ) ;
2005-01-30 21:42:55 +03:00
}
2005-02-16 03:22:29 +03:00
/**
* xmlPatternStreamable :
* @ comp : the precompiled pattern
*
* Check if the pattern is streamable i . e . xmlPatternGetStreamCtxt ( )
* should work .
*
* Returns 1 if streamable , 0 if not and - 1 in case of error .
*/
int
xmlPatternStreamable ( xmlPatternPtr comp ) {
if ( comp = = NULL )
return ( - 1 ) ;
while ( comp ! = NULL ) {
if ( comp - > stream = = NULL )
return ( 0 ) ;
comp = comp - > next ;
}
return ( 1 ) ;
}
/**
* xmlPatternMaxDepth :
* @ comp : the precompiled pattern
*
* Check the maximum depth reachable by a pattern
*
* Returns - 2 if no limit ( using //), otherwise the depth,
* and - 1 in case of error
*/
int
xmlPatternMaxDepth ( xmlPatternPtr comp ) {
int ret = 0 , i ;
if ( comp = = NULL )
return ( - 1 ) ;
while ( comp ! = NULL ) {
if ( comp - > stream = = NULL )
return ( - 1 ) ;
for ( i = 0 ; i < comp - > stream - > nbStep ; i + + )
if ( comp - > stream - > steps [ i ] . flags & XML_STREAM_STEP_DESC )
return ( - 2 ) ;
if ( comp - > stream - > nbStep > ret )
ret = comp - > stream - > nbStep ;
comp = comp - > next ;
}
return ( ret ) ;
2005-09-04 16:01:57 +04:00
}
2005-02-16 03:22:29 +03:00
2005-09-04 16:01:57 +04:00
/**
* xmlPatternMinDepth :
* @ comp : the precompiled pattern
*
* Check the minimum depth reachable by a pattern , 0 mean the / or . are
* part of the set .
*
* Returns - 1 in case of error otherwise the depth ,
2012-09-11 09:26:36 +04:00
*
2005-09-04 16:01:57 +04:00
*/
int
xmlPatternMinDepth ( xmlPatternPtr comp ) {
int ret = 12345678 ;
if ( comp = = NULL )
return ( - 1 ) ;
while ( comp ! = NULL ) {
if ( comp - > stream = = NULL )
return ( - 1 ) ;
if ( comp - > stream - > nbStep < ret )
ret = comp - > stream - > nbStep ;
if ( ret = = 0 )
return ( 0 ) ;
comp = comp - > next ;
}
return ( ret ) ;
2005-02-16 03:22:29 +03:00
}
/**
* xmlPatternFromRoot :
* @ comp : the precompiled pattern
*
* Check if the pattern must be looked at from the root .
*
* Returns 1 if true , 0 if false and - 1 in case of error
*/
int
xmlPatternFromRoot ( xmlPatternPtr comp ) {
if ( comp = = NULL )
return ( - 1 ) ;
while ( comp ! = NULL ) {
if ( comp - > stream = = NULL )
return ( - 1 ) ;
if ( comp - > flags & PAT_FROM_ROOT )
return ( 1 ) ;
comp = comp - > next ;
}
return ( 0 ) ;
}
2005-02-18 00:34:45 +03:00
2003-12-03 01:32:15 +03:00
# endif /* LIBXML_PATTERN_ENABLED */