(root)/
libxml2-2.12.3/
pattern.c
       1  /*
       2   * pattern.c: Implementation of selectors for nodes
       3   *
       4   * Reference:
       5   *   http://www.w3.org/TR/2001/REC-xmlschema-1-20010502/
       6   *   to some extent
       7   *   http://www.w3.org/TR/1999/REC-xml-19991116
       8   *
       9   * See Copyright for the status of this software.
      10   *
      11   * daniel@veillard.com
      12   */
      13  
      14  /*
      15   * TODO:
      16   * - compilation flags to check for specific syntaxes
      17   *   using flags of xmlPatterncompile()
      18   * - making clear how pattern starting with / or . need to be handled,
      19   *   currently push(NULL, NULL) means a reset of the streaming context
      20   *   and indicating we are on / (the document node), probably need
      21   *   something similar for .
      22   * - get rid of the "compile" starting with lowercase
      23   * - DONE (2006-05-16): get rid of the Strdup/Strndup in case of dictionary
      24   */
      25  
      26  #define IN_LIBXML
      27  #include "libxml.h"
      28  
      29  #include <string.h>
      30  #include <libxml/pattern.h>
      31  #include <libxml/xmlmemory.h>
      32  #include <libxml/tree.h>
      33  #include <libxml/dict.h>
      34  #include <libxml/xmlerror.h>
      35  #include <libxml/parserInternals.h>
      36  
      37  #ifdef LIBXML_PATTERN_ENABLED
      38  
      39  #ifdef ERROR
      40  #undef ERROR
      41  #endif
      42  #define ERROR(a, b, c, d)
      43  #define ERROR5(a, b, c, d, e)
      44  
      45  #define XML_STREAM_STEP_DESC	1
      46  #define XML_STREAM_STEP_FINAL	2
      47  #define XML_STREAM_STEP_ROOT	4
      48  #define XML_STREAM_STEP_ATTR	8
      49  #define XML_STREAM_STEP_NODE	16
      50  #define XML_STREAM_STEP_IN_SET	32
      51  
      52  /*
      53  * NOTE: Those private flags (XML_STREAM_xxx) are used
      54  *   in _xmlStreamCtxt->flag. They extend the public
      55  *   xmlPatternFlags, so be careful not to interfere with the
      56  *   reserved values for xmlPatternFlags.
      57  */
      58  #define XML_STREAM_FINAL_IS_ANY_NODE 1<<14
      59  #define XML_STREAM_FROM_ROOT 1<<15
      60  #define XML_STREAM_DESC 1<<16
      61  
      62  /*
      63  * XML_STREAM_ANY_NODE is used for comparison against
      64  * xmlElementType enums, to indicate a node of any type.
      65  */
      66  #define XML_STREAM_ANY_NODE 100
      67  
      68  #define XML_PATTERN_NOTPATTERN  (XML_PATTERN_XPATH | \
      69  				 XML_PATTERN_XSSEL | \
      70  				 XML_PATTERN_XSFIELD)
      71  
      72  #define XML_STREAM_XS_IDC(c) ((c)->flags & \
      73      (XML_PATTERN_XSSEL | XML_PATTERN_XSFIELD))
      74  
      75  #define XML_STREAM_XS_IDC_SEL(c) ((c)->flags & XML_PATTERN_XSSEL)
      76  
      77  #define XML_STREAM_XS_IDC_FIELD(c) ((c)->flags & XML_PATTERN_XSFIELD)
      78  
      79  #define XML_PAT_COPY_NSNAME(c, r, nsname) \
      80      if ((c)->comp->dict) \
      81  	r = (xmlChar *) xmlDictLookup((c)->comp->dict, BAD_CAST nsname, -1); \
      82      else r = xmlStrdup(BAD_CAST nsname);
      83  
      84  #define XML_PAT_FREE_STRING(c, r) if ((c)->comp->dict == NULL) xmlFree(r);
      85  
      86  typedef struct _xmlStreamStep xmlStreamStep;
      87  typedef xmlStreamStep *xmlStreamStepPtr;
      88  struct _xmlStreamStep {
      89      int flags;			/* properties of that step */
      90      const xmlChar *name;	/* first string value if NULL accept all */
      91      const xmlChar *ns;		/* second string value */
      92      int nodeType;		/* type of node */
      93  };
      94  
      95  typedef struct _xmlStreamComp xmlStreamComp;
      96  typedef xmlStreamComp *xmlStreamCompPtr;
      97  struct _xmlStreamComp {
      98      xmlDict *dict;		/* the dictionary if any */
      99      int nbStep;			/* number of steps in the automata */
     100      int maxStep;		/* allocated number of steps */
     101      xmlStreamStepPtr steps;	/* the array of steps */
     102      int flags;
     103  };
     104  
     105  struct _xmlStreamCtxt {
     106      struct _xmlStreamCtxt *next;/* link to next sub pattern if | */
     107      xmlStreamCompPtr comp;	/* the compiled stream */
     108      int nbState;		/* number of states in the automata */
     109      int maxState;		/* allocated number of states */
     110      int level;			/* how deep are we ? */
     111      int *states;		/* the array of step indexes */
     112      int flags;			/* validation options */
     113      int blockLevel;
     114  };
     115  
     116  static void xmlFreeStreamComp(xmlStreamCompPtr comp);
     117  
     118  /*
     119   * Types are private:
     120   */
     121  
     122  typedef enum {
     123      XML_OP_END=0,
     124      XML_OP_ROOT,
     125      XML_OP_ELEM,
     126      XML_OP_CHILD,
     127      XML_OP_ATTR,
     128      XML_OP_PARENT,
     129      XML_OP_ANCESTOR,
     130      XML_OP_NS,
     131      XML_OP_ALL
     132  } xmlPatOp;
     133  
     134  
     135  typedef struct _xmlStepState xmlStepState;
     136  typedef xmlStepState *xmlStepStatePtr;
     137  struct _xmlStepState {
     138      int step;
     139      xmlNodePtr node;
     140  };
     141  
     142  typedef struct _xmlStepStates xmlStepStates;
     143  typedef xmlStepStates *xmlStepStatesPtr;
     144  struct _xmlStepStates {
     145      int nbstates;
     146      int maxstates;
     147      xmlStepStatePtr states;
     148  };
     149  
     150  typedef struct _xmlStepOp xmlStepOp;
     151  typedef xmlStepOp *xmlStepOpPtr;
     152  struct _xmlStepOp {
     153      xmlPatOp op;
     154      const xmlChar *value;
     155      const xmlChar *value2; /* The namespace name */
     156  };
     157  
     158  #define PAT_FROM_ROOT	(1<<8)
     159  #define PAT_FROM_CUR	(1<<9)
     160  
     161  struct _xmlPattern {
     162      void *data;		/* the associated template */
     163      xmlDictPtr dict;		/* the optional dictionary */
     164      struct _xmlPattern *next;	/* next pattern if | is used */
     165      const xmlChar *pattern;	/* the pattern */
     166      int flags;			/* flags */
     167      int nbStep;
     168      int maxStep;
     169      xmlStepOpPtr steps;        /* ops for computation */
     170      xmlStreamCompPtr stream;	/* the streaming data if any */
     171  };
     172  
     173  typedef struct _xmlPatParserContext xmlPatParserContext;
     174  typedef xmlPatParserContext *xmlPatParserContextPtr;
     175  struct _xmlPatParserContext {
     176      const xmlChar *cur;			/* the current char being parsed */
     177      const xmlChar *base;		/* the full expression */
     178      int	           error;		/* error code */
     179      xmlDictPtr     dict;		/* the dictionary if any */
     180      xmlPatternPtr  comp;		/* the result */
     181      xmlNodePtr     elem;		/* the current node if any */
     182      const xmlChar **namespaces;		/* the namespaces definitions */
     183      int   nb_namespaces;		/* the number of namespaces */
     184  };
     185  
     186  /************************************************************************
     187   *									*
     188   *			Type functions					*
     189   *									*
     190   ************************************************************************/
     191  
     192  /**
     193   * xmlNewPattern:
     194   *
     195   * Create a new XSLT Pattern
     196   *
     197   * Returns the newly allocated xmlPatternPtr or NULL in case of error
     198   */
     199  static xmlPatternPtr
     200  xmlNewPattern(void) {
     201      xmlPatternPtr cur;
     202  
     203      cur = (xmlPatternPtr) xmlMalloc(sizeof(xmlPattern));
     204      if (cur == NULL) {
     205  	ERROR(NULL, NULL, NULL,
     206  		"xmlNewPattern : malloc failed\n");
     207  	return(NULL);
     208      }
     209      memset(cur, 0, sizeof(xmlPattern));
     210      cur->maxStep = 10;
     211      cur->steps = (xmlStepOpPtr) xmlMalloc(cur->maxStep * sizeof(xmlStepOp));
     212      if (cur->steps == NULL) {
     213          xmlFree(cur);
     214  	ERROR(NULL, NULL, NULL,
     215  		"xmlNewPattern : malloc failed\n");
     216  	return(NULL);
     217      }
     218      return(cur);
     219  }
     220  
     221  /**
     222   * xmlFreePattern:
     223   * @comp:  an XSLT comp
     224   *
     225   * Free up the memory allocated by @comp
     226   */
     227  void
     228  xmlFreePattern(xmlPatternPtr comp) {
     229      xmlFreePatternList(comp);
     230  }
     231  
     232  static void
     233  xmlFreePatternInternal(xmlPatternPtr comp) {
     234      xmlStepOpPtr op;
     235      int i;
     236  
     237      if (comp == NULL)
     238  	return;
     239      if (comp->stream != NULL)
     240          xmlFreeStreamComp(comp->stream);
     241      if (comp->pattern != NULL)
     242  	xmlFree((xmlChar *)comp->pattern);
     243      if (comp->steps != NULL) {
     244          if (comp->dict == NULL) {
     245  	    for (i = 0;i < comp->nbStep;i++) {
     246  		op = &comp->steps[i];
     247  		if (op->value != NULL)
     248  		    xmlFree((xmlChar *) op->value);
     249  		if (op->value2 != NULL)
     250  		    xmlFree((xmlChar *) op->value2);
     251  	    }
     252  	}
     253  	xmlFree(comp->steps);
     254      }
     255      if (comp->dict != NULL)
     256          xmlDictFree(comp->dict);
     257  
     258      memset(comp, -1, sizeof(xmlPattern));
     259      xmlFree(comp);
     260  }
     261  
     262  /**
     263   * xmlFreePatternList:
     264   * @comp:  an XSLT comp list
     265   *
     266   * Free up the memory allocated by all the elements of @comp
     267   */
     268  void
     269  xmlFreePatternList(xmlPatternPtr comp) {
     270      xmlPatternPtr cur;
     271  
     272      while (comp != NULL) {
     273  	cur = comp;
     274  	comp = comp->next;
     275  	cur->next = NULL;
     276  	xmlFreePatternInternal(cur);
     277      }
     278  }
     279  
     280  /**
     281   * xmlNewPatParserContext:
     282   * @pattern:  the pattern context
     283   * @dict:  the inherited dictionary or NULL
     284   * @namespaces: the prefix definitions, array of [URI, prefix] terminated
     285   *              with [NULL, NULL] or NULL if no namespace is used
     286   *
     287   * Create a new XML pattern parser context
     288   *
     289   * Returns the newly allocated xmlPatParserContextPtr or NULL in case of error
     290   */
     291  static xmlPatParserContextPtr
     292  xmlNewPatParserContext(const xmlChar *pattern, xmlDictPtr dict,
     293                         const xmlChar **namespaces) {
     294      xmlPatParserContextPtr cur;
     295  
     296      if (pattern == NULL)
     297          return(NULL);
     298  
     299      cur = (xmlPatParserContextPtr) xmlMalloc(sizeof(xmlPatParserContext));
     300      if (cur == NULL) {
     301  	ERROR(NULL, NULL, NULL,
     302  		"xmlNewPatParserContext : malloc failed\n");
     303  	return(NULL);
     304      }
     305      memset(cur, 0, sizeof(xmlPatParserContext));
     306      cur->dict = dict;
     307      cur->cur = pattern;
     308      cur->base = pattern;
     309      if (namespaces != NULL) {
     310          int i;
     311          for (i = 0;namespaces[2 * i] != NULL;i++)
     312              ;
     313          cur->nb_namespaces = i;
     314      } else {
     315          cur->nb_namespaces = 0;
     316      }
     317      cur->namespaces = namespaces;
     318      return(cur);
     319  }
     320  
     321  /**
     322   * xmlFreePatParserContext:
     323   * @ctxt:  an XSLT parser context
     324   *
     325   * Free up the memory allocated by @ctxt
     326   */
     327  static void
     328  xmlFreePatParserContext(xmlPatParserContextPtr ctxt) {
     329      if (ctxt == NULL)
     330  	return;
     331      memset(ctxt, -1, sizeof(xmlPatParserContext));
     332      xmlFree(ctxt);
     333  }
     334  
     335  /**
     336   * xmlPatternAdd:
     337   * @comp:  the compiled match expression
     338   * @op:  an op
     339   * @value:  the first value
     340   * @value2:  the second value
     341   *
     342   * Add a step to an XSLT Compiled Match
     343   *
     344   * Returns -1 in case of failure, 0 otherwise.
     345   */
     346  static int
     347  xmlPatternAdd(xmlPatParserContextPtr ctxt ATTRIBUTE_UNUSED,
     348                  xmlPatternPtr comp,
     349                  xmlPatOp op, xmlChar * value, xmlChar * value2)
     350  {
     351      if (comp->nbStep >= comp->maxStep) {
     352          xmlStepOpPtr temp;
     353  	temp = (xmlStepOpPtr) xmlRealloc(comp->steps, comp->maxStep * 2 *
     354  	                                 sizeof(xmlStepOp));
     355          if (temp == NULL) {
     356  	    ERROR(ctxt, NULL, NULL,
     357  			     "xmlPatternAdd: realloc failed\n");
     358  	    return (-1);
     359  	}
     360  	comp->steps = temp;
     361  	comp->maxStep *= 2;
     362      }
     363      comp->steps[comp->nbStep].op = op;
     364      comp->steps[comp->nbStep].value = value;
     365      comp->steps[comp->nbStep].value2 = value2;
     366      comp->nbStep++;
     367      return (0);
     368  }
     369  
     370  #if 0
     371  /**
     372   * xsltSwapTopPattern:
     373   * @comp:  the compiled match expression
     374   *
     375   * reverse the two top steps.
     376   */
     377  static void
     378  xsltSwapTopPattern(xmlPatternPtr comp) {
     379      int i;
     380      int j = comp->nbStep - 1;
     381  
     382      if (j > 0) {
     383  	register const xmlChar *tmp;
     384  	register xmlPatOp op;
     385  	i = j - 1;
     386  	tmp = comp->steps[i].value;
     387  	comp->steps[i].value = comp->steps[j].value;
     388  	comp->steps[j].value = tmp;
     389  	tmp = comp->steps[i].value2;
     390  	comp->steps[i].value2 = comp->steps[j].value2;
     391  	comp->steps[j].value2 = tmp;
     392  	op = comp->steps[i].op;
     393  	comp->steps[i].op = comp->steps[j].op;
     394  	comp->steps[j].op = op;
     395      }
     396  }
     397  #endif
     398  
     399  /**
     400   * xmlReversePattern:
     401   * @comp:  the compiled match expression
     402   *
     403   * reverse all the stack of expressions
     404   *
     405   * returns 0 in case of success and -1 in case of error.
     406   */
     407  static int
     408  xmlReversePattern(xmlPatternPtr comp) {
     409      int i, j;
     410  
     411      /*
     412       * remove the leading // for //a or .//a
     413       */
     414      if ((comp->nbStep > 0) && (comp->steps[0].op == XML_OP_ANCESTOR)) {
     415          for (i = 0, j = 1;j < comp->nbStep;i++,j++) {
     416  	    comp->steps[i].value = comp->steps[j].value;
     417  	    comp->steps[i].value2 = comp->steps[j].value2;
     418  	    comp->steps[i].op = comp->steps[j].op;
     419  	}
     420  	comp->nbStep--;
     421      }
     422      if (comp->nbStep >= comp->maxStep) {
     423          xmlStepOpPtr temp;
     424  	temp = (xmlStepOpPtr) xmlRealloc(comp->steps, comp->maxStep * 2 *
     425  	                                 sizeof(xmlStepOp));
     426          if (temp == NULL) {
     427  	    ERROR(ctxt, NULL, NULL,
     428  			     "xmlReversePattern: realloc failed\n");
     429  	    return (-1);
     430  	}
     431  	comp->steps = temp;
     432  	comp->maxStep *= 2;
     433      }
     434      i = 0;
     435      j = comp->nbStep - 1;
     436      while (j > i) {
     437  	register const xmlChar *tmp;
     438  	register xmlPatOp op;
     439  	tmp = comp->steps[i].value;
     440  	comp->steps[i].value = comp->steps[j].value;
     441  	comp->steps[j].value = tmp;
     442  	tmp = comp->steps[i].value2;
     443  	comp->steps[i].value2 = comp->steps[j].value2;
     444  	comp->steps[j].value2 = tmp;
     445  	op = comp->steps[i].op;
     446  	comp->steps[i].op = comp->steps[j].op;
     447  	comp->steps[j].op = op;
     448  	j--;
     449  	i++;
     450      }
     451      comp->steps[comp->nbStep].value = NULL;
     452      comp->steps[comp->nbStep].value2 = NULL;
     453      comp->steps[comp->nbStep++].op = XML_OP_END;
     454      return(0);
     455  }
     456  
     457  /************************************************************************
     458   *									*
     459   *		The interpreter for the precompiled patterns		*
     460   *									*
     461   ************************************************************************/
     462  
     463  static int
     464  xmlPatPushState(xmlStepStates *states, int step, xmlNodePtr node) {
     465      if ((states->states == NULL) || (states->maxstates <= 0)) {
     466          states->maxstates = 4;
     467  	states->nbstates = 0;
     468  	states->states = xmlMalloc(4 * sizeof(xmlStepState));
     469      }
     470      else if (states->maxstates <= states->nbstates) {
     471          xmlStepState *tmp;
     472  
     473  	tmp = (xmlStepStatePtr) xmlRealloc(states->states,
     474  			       2 * states->maxstates * sizeof(xmlStepState));
     475  	if (tmp == NULL)
     476  	    return(-1);
     477  	states->states = tmp;
     478  	states->maxstates *= 2;
     479      }
     480      states->states[states->nbstates].step = step;
     481      states->states[states->nbstates++].node = node;
     482  #if 0
     483      fprintf(stderr, "Push: %d, %s\n", step, node->name);
     484  #endif
     485      return(0);
     486  }
     487  
     488  /**
     489   * xmlPatMatch:
     490   * @comp: the precompiled pattern
     491   * @node: a node
     492   *
     493   * Test whether the node matches the pattern
     494   *
     495   * Returns 1 if it matches, 0 if it doesn't and -1 in case of failure
     496   */
     497  static int
     498  xmlPatMatch(xmlPatternPtr comp, xmlNodePtr node) {
     499      int i;
     500      xmlStepOpPtr step;
     501      xmlStepStates states = {0, 0, NULL}; /* // may require backtrack */
     502  
     503      if ((comp == NULL) || (node == NULL)) return(-1);
     504      i = 0;
     505  restart:
     506      for (;i < comp->nbStep;i++) {
     507  	step = &comp->steps[i];
     508  	switch (step->op) {
     509              case XML_OP_END:
     510  		goto found;
     511              case XML_OP_ROOT:
     512  		if (node->type == XML_NAMESPACE_DECL)
     513  		    goto rollback;
     514  		node = node->parent;
     515  		if ((node->type == XML_DOCUMENT_NODE) ||
     516  		    (node->type == XML_HTML_DOCUMENT_NODE))
     517  		    continue;
     518  		goto rollback;
     519              case XML_OP_ELEM:
     520  		if (node->type != XML_ELEMENT_NODE)
     521  		    goto rollback;
     522  		if (step->value == NULL)
     523  		    continue;
     524  		if (step->value[0] != node->name[0])
     525  		    goto rollback;
     526  		if (!xmlStrEqual(step->value, node->name))
     527  		    goto rollback;
     528  
     529  		/* Namespace test */
     530  		if (node->ns == NULL) {
     531  		    if (step->value2 != NULL)
     532  			goto rollback;
     533  		} else if (node->ns->href != NULL) {
     534  		    if (step->value2 == NULL)
     535  			goto rollback;
     536  		    if (!xmlStrEqual(step->value2, node->ns->href))
     537  			goto rollback;
     538  		}
     539  		continue;
     540              case XML_OP_CHILD: {
     541  		xmlNodePtr lst;
     542  
     543  		if ((node->type != XML_ELEMENT_NODE) &&
     544  		    (node->type != XML_DOCUMENT_NODE) &&
     545  		    (node->type != XML_HTML_DOCUMENT_NODE))
     546  		    goto rollback;
     547  
     548  		lst = node->children;
     549  
     550  		if (step->value != NULL) {
     551  		    while (lst != NULL) {
     552  			if ((lst->type == XML_ELEMENT_NODE) &&
     553  			    (step->value[0] == lst->name[0]) &&
     554  			    (xmlStrEqual(step->value, lst->name)))
     555  			    break;
     556  			lst = lst->next;
     557  		    }
     558  		    if (lst != NULL)
     559  			continue;
     560  		}
     561  		goto rollback;
     562  	    }
     563              case XML_OP_ATTR:
     564  		if (node->type != XML_ATTRIBUTE_NODE)
     565  		    goto rollback;
     566  		if (step->value != NULL) {
     567  		    if (step->value[0] != node->name[0])
     568  			goto rollback;
     569  		    if (!xmlStrEqual(step->value, node->name))
     570  			goto rollback;
     571  		}
     572  		/* Namespace test */
     573  		if (node->ns == NULL) {
     574  		    if (step->value2 != NULL)
     575  			goto rollback;
     576  		} else if (step->value2 != NULL) {
     577  		    if (!xmlStrEqual(step->value2, node->ns->href))
     578  			goto rollback;
     579  		}
     580  		continue;
     581              case XML_OP_PARENT:
     582  		if ((node->type == XML_DOCUMENT_NODE) ||
     583  		    (node->type == XML_HTML_DOCUMENT_NODE) ||
     584  		    (node->type == XML_NAMESPACE_DECL))
     585  		    goto rollback;
     586  		node = node->parent;
     587  		if (node == NULL)
     588  		    goto rollback;
     589  		if (step->value == NULL)
     590  		    continue;
     591  		if (step->value[0] != node->name[0])
     592  		    goto rollback;
     593  		if (!xmlStrEqual(step->value, node->name))
     594  		    goto rollback;
     595  		/* Namespace test */
     596  		if (node->ns == NULL) {
     597  		    if (step->value2 != NULL)
     598  			goto rollback;
     599  		} else if (node->ns->href != NULL) {
     600  		    if (step->value2 == NULL)
     601  			goto rollback;
     602  		    if (!xmlStrEqual(step->value2, node->ns->href))
     603  			goto rollback;
     604  		}
     605  		continue;
     606              case XML_OP_ANCESTOR:
     607  		/* TODO: implement coalescing of ANCESTOR/NODE ops */
     608  		if (step->value == NULL) {
     609  		    i++;
     610  		    step = &comp->steps[i];
     611  		    if (step->op == XML_OP_ROOT)
     612  			goto found;
     613  		    if (step->op != XML_OP_ELEM)
     614  			goto rollback;
     615  		    if (step->value == NULL)
     616  			return(-1);
     617  		}
     618  		if (node == NULL)
     619  		    goto rollback;
     620  		if ((node->type == XML_DOCUMENT_NODE) ||
     621  		    (node->type == XML_HTML_DOCUMENT_NODE) ||
     622  		    (node->type == XML_NAMESPACE_DECL))
     623  		    goto rollback;
     624  		node = node->parent;
     625  		while (node != NULL) {
     626  		    if ((node->type == XML_ELEMENT_NODE) &&
     627  			(step->value[0] == node->name[0]) &&
     628  			(xmlStrEqual(step->value, node->name))) {
     629  			/* Namespace test */
     630  			if (node->ns == NULL) {
     631  			    if (step->value2 == NULL)
     632  				break;
     633  			} else if (node->ns->href != NULL) {
     634  			    if ((step->value2 != NULL) &&
     635  			        (xmlStrEqual(step->value2, node->ns->href)))
     636  				break;
     637  			}
     638  		    }
     639  		    node = node->parent;
     640  		}
     641  		if (node == NULL)
     642  		    goto rollback;
     643  		/*
     644  		 * prepare a potential rollback from here
     645  		 * for ancestors of that node.
     646  		 */
     647  		if (step->op == XML_OP_ANCESTOR)
     648  		    xmlPatPushState(&states, i, node);
     649  		else
     650  		    xmlPatPushState(&states, i - 1, node);
     651  		continue;
     652              case XML_OP_NS:
     653  		if (node->type != XML_ELEMENT_NODE)
     654  		    goto rollback;
     655  		if (node->ns == NULL) {
     656  		    if (step->value != NULL)
     657  			goto rollback;
     658  		} else if (node->ns->href != NULL) {
     659  		    if (step->value == NULL)
     660  			goto rollback;
     661  		    if (!xmlStrEqual(step->value, node->ns->href))
     662  			goto rollback;
     663  		}
     664  		break;
     665              case XML_OP_ALL:
     666  		if (node->type != XML_ELEMENT_NODE)
     667  		    goto rollback;
     668  		break;
     669  	}
     670      }
     671  found:
     672      if (states.states != NULL) {
     673          /* Free the rollback states */
     674  	xmlFree(states.states);
     675      }
     676      return(1);
     677  rollback:
     678      /* got an error try to rollback */
     679      if (states.states == NULL)
     680  	return(0);
     681      if (states.nbstates <= 0) {
     682  	xmlFree(states.states);
     683  	return(0);
     684      }
     685      states.nbstates--;
     686      i = states.states[states.nbstates].step;
     687      node = states.states[states.nbstates].node;
     688  #if 0
     689      fprintf(stderr, "Pop: %d, %s\n", i, node->name);
     690  #endif
     691      goto restart;
     692  }
     693  
     694  /************************************************************************
     695   *									*
     696   *			Dedicated parser for templates			*
     697   *									*
     698   ************************************************************************/
     699  
     700  #define TODO								\
     701      xmlGenericError(xmlGenericErrorContext,				\
     702  	    "Unimplemented block at %s:%d\n",				\
     703              __FILE__, __LINE__);
     704  #define CUR (*ctxt->cur)
     705  #define SKIP(val) ctxt->cur += (val)
     706  #define NXT(val) ctxt->cur[(val)]
     707  #define PEEKPREV(val) ctxt->cur[-(val)]
     708  #define CUR_PTR ctxt->cur
     709  
     710  #define SKIP_BLANKS							\
     711      while (IS_BLANK_CH(CUR)) NEXT
     712  
     713  #define CURRENT (*ctxt->cur)
     714  #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
     715  
     716  
     717  #define PUSH(op, val, val2)						\
     718      if (xmlPatternAdd(ctxt, ctxt->comp, (op), (val), (val2))) goto error;
     719  
     720  #define XSLT_ERROR(X)							\
     721      { xsltError(ctxt, __FILE__, __LINE__, X);				\
     722        ctxt->error = (X); return; }
     723  
     724  #define XSLT_ERROR0(X)							\
     725      { xsltError(ctxt, __FILE__, __LINE__, X);				\
     726        ctxt->error = (X); return(0); }
     727  
     728  #if 0
     729  /**
     730   * xmlPatScanLiteral:
     731   * @ctxt:  the XPath Parser context
     732   *
     733   * Parse an XPath Literal:
     734   *
     735   * [29] Literal ::= '"' [^"]* '"'
     736   *                | "'" [^']* "'"
     737   *
     738   * Returns the Literal parsed or NULL
     739   */
     740  
     741  static xmlChar *
     742  xmlPatScanLiteral(xmlPatParserContextPtr ctxt) {
     743      const xmlChar *q, *cur;
     744      xmlChar *ret = NULL;
     745      int val, len;
     746  
     747      SKIP_BLANKS;
     748      if (CUR == '"') {
     749          NEXT;
     750  	cur = q = CUR_PTR;
     751  	val = xmlStringCurrentChar(NULL, cur, &len);
     752  	while ((IS_CHAR(val)) && (val != '"')) {
     753  	    cur += len;
     754  	    val = xmlStringCurrentChar(NULL, cur, &len);
     755  	}
     756  	if (!IS_CHAR(val)) {
     757  	    ctxt->error = 1;
     758  	    return(NULL);
     759  	} else {
     760  	    if (ctxt->dict)
     761  		ret = (xmlChar *) xmlDictLookup(ctxt->dict, q, cur - q);
     762  	    else
     763  		ret = xmlStrndup(q, cur - q);
     764          }
     765  	cur += len;
     766  	CUR_PTR = cur;
     767      } else if (CUR == '\'') {
     768          NEXT;
     769  	cur = q = CUR_PTR;
     770  	val = xmlStringCurrentChar(NULL, cur, &len);
     771  	while ((IS_CHAR(val)) && (val != '\'')) {
     772  	    cur += len;
     773  	    val = xmlStringCurrentChar(NULL, cur, &len);
     774  	}
     775  	if (!IS_CHAR(val)) {
     776  	    ctxt->error = 1;
     777  	    return(NULL);
     778  	} else {
     779  	    if (ctxt->dict)
     780  		ret = (xmlChar *) xmlDictLookup(ctxt->dict, q, cur - q);
     781  	    else
     782  		ret = xmlStrndup(q, cur - q);
     783          }
     784  	cur += len;
     785  	CUR_PTR = cur;
     786      } else {
     787  	/* XP_ERROR(XPATH_START_LITERAL_ERROR); */
     788  	ctxt->error = 1;
     789  	return(NULL);
     790      }
     791      return(ret);
     792  }
     793  #endif
     794  
     795  /**
     796   * xmlPatScanName:
     797   * @ctxt:  the XPath Parser context
     798   *
     799   * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' |
     800   *                  CombiningChar | Extender
     801   *
     802   * [5] Name ::= (Letter | '_' | ':') (NameChar)*
     803   *
     804   * [6] Names ::= Name (S Name)*
     805   *
     806   * Returns the Name parsed or NULL
     807   */
     808  
     809  static xmlChar *
     810  xmlPatScanName(xmlPatParserContextPtr ctxt) {
     811      const xmlChar *q, *cur;
     812      xmlChar *ret = NULL;
     813      int val, len;
     814  
     815      SKIP_BLANKS;
     816  
     817      cur = q = CUR_PTR;
     818      val = xmlStringCurrentChar(NULL, cur, &len);
     819      if (!IS_LETTER(val) && (val != '_') && (val != ':'))
     820  	return(NULL);
     821  
     822      while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
     823             (val == '.') || (val == '-') ||
     824  	   (val == '_') ||
     825  	   (IS_COMBINING(val)) ||
     826  	   (IS_EXTENDER(val))) {
     827  	cur += len;
     828  	val = xmlStringCurrentChar(NULL, cur, &len);
     829      }
     830      if (ctxt->dict)
     831  	ret = (xmlChar *) xmlDictLookup(ctxt->dict, q, cur - q);
     832      else
     833  	ret = xmlStrndup(q, cur - q);
     834      CUR_PTR = cur;
     835      return(ret);
     836  }
     837  
     838  /**
     839   * xmlPatScanNCName:
     840   * @ctxt:  the XPath Parser context
     841   *
     842   * Parses a non qualified name
     843   *
     844   * Returns the Name parsed or NULL
     845   */
     846  
     847  static xmlChar *
     848  xmlPatScanNCName(xmlPatParserContextPtr ctxt) {
     849      const xmlChar *q, *cur;
     850      xmlChar *ret = NULL;
     851      int val, len;
     852  
     853      SKIP_BLANKS;
     854  
     855      cur = q = CUR_PTR;
     856      val = xmlStringCurrentChar(NULL, cur, &len);
     857      if (!IS_LETTER(val) && (val != '_'))
     858  	return(NULL);
     859  
     860      while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
     861             (val == '.') || (val == '-') ||
     862  	   (val == '_') ||
     863  	   (IS_COMBINING(val)) ||
     864  	   (IS_EXTENDER(val))) {
     865  	cur += len;
     866  	val = xmlStringCurrentChar(NULL, cur, &len);
     867      }
     868      if (ctxt->dict)
     869  	ret = (xmlChar *) xmlDictLookup(ctxt->dict, q, cur - q);
     870      else
     871  	ret = xmlStrndup(q, cur - q);
     872      CUR_PTR = cur;
     873      return(ret);
     874  }
     875  
     876  #if 0
     877  /**
     878   * xmlPatScanQName:
     879   * @ctxt:  the XPath Parser context
     880   * @prefix:  the place to store the prefix
     881   *
     882   * Parse a qualified name
     883   *
     884   * Returns the Name parsed or NULL
     885   */
     886  
     887  static xmlChar *
     888  xmlPatScanQName(xmlPatParserContextPtr ctxt, xmlChar **prefix) {
     889      xmlChar *ret = NULL;
     890  
     891      *prefix = NULL;
     892      ret = xmlPatScanNCName(ctxt);
     893      if (CUR == ':') {
     894          *prefix = ret;
     895  	NEXT;
     896  	ret = xmlPatScanNCName(ctxt);
     897      }
     898      return(ret);
     899  }
     900  #endif
     901  
     902  /**
     903   * xmlCompileAttributeTest:
     904   * @ctxt:  the compilation context
     905   *
     906   * Compile an attribute test.
     907   */
     908  static void
     909  xmlCompileAttributeTest(xmlPatParserContextPtr ctxt) {
     910      xmlChar *token = NULL;
     911      xmlChar *name = NULL;
     912      xmlChar *URL = NULL;
     913  
     914      SKIP_BLANKS;
     915      name = xmlPatScanNCName(ctxt);
     916      if (name == NULL) {
     917  	if (CUR == '*') {
     918  	    PUSH(XML_OP_ATTR, NULL, NULL);
     919  	    NEXT;
     920  	} else {
     921  	    ERROR(NULL, NULL, NULL,
     922  		"xmlCompileAttributeTest : Name expected\n");
     923  	    ctxt->error = 1;
     924  	}
     925  	return;
     926      }
     927      if (CUR == ':') {
     928  	int i;
     929  	xmlChar *prefix = name;
     930  
     931  	NEXT;
     932  
     933  	if (IS_BLANK_CH(CUR)) {
     934  	    ERROR5(NULL, NULL, NULL, "Invalid QName.\n", NULL);
     935  	    ctxt->error = 1;
     936  	    goto error;
     937  	}
     938  	/*
     939  	* This is a namespace match
     940  	*/
     941  	token = xmlPatScanName(ctxt);
     942  	if ((prefix[0] == 'x') &&
     943  	    (prefix[1] == 'm') &&
     944  	    (prefix[2] == 'l') &&
     945  	    (prefix[3] == 0))
     946  	{
     947  	    XML_PAT_COPY_NSNAME(ctxt, URL, XML_XML_NAMESPACE);
     948  	} else {
     949  	    for (i = 0;i < ctxt->nb_namespaces;i++) {
     950  		if (xmlStrEqual(ctxt->namespaces[2 * i + 1], prefix)) {
     951  		    XML_PAT_COPY_NSNAME(ctxt, URL, ctxt->namespaces[2 * i])
     952  		    break;
     953  		}
     954  	    }
     955  	    if (i >= ctxt->nb_namespaces) {
     956  		ERROR5(NULL, NULL, NULL,
     957  		    "xmlCompileAttributeTest : no namespace bound to prefix %s\n",
     958  		    prefix);
     959  		ctxt->error = 1;
     960  		goto error;
     961  	    }
     962  	}
     963          XML_PAT_FREE_STRING(ctxt, name);
     964          name = NULL;
     965  	if (token == NULL) {
     966  	    if (CUR == '*') {
     967  		NEXT;
     968  		PUSH(XML_OP_ATTR, NULL, URL);
     969  	    } else {
     970  		ERROR(NULL, NULL, NULL,
     971  		    "xmlCompileAttributeTest : Name expected\n");
     972  		ctxt->error = 1;
     973  		goto error;
     974  	    }
     975  	} else {
     976  	    PUSH(XML_OP_ATTR, token, URL);
     977  	}
     978      } else {
     979  	PUSH(XML_OP_ATTR, name, NULL);
     980      }
     981      return;
     982  error:
     983      if (name != NULL)
     984  	XML_PAT_FREE_STRING(ctxt, name);
     985      if (URL != NULL)
     986  	XML_PAT_FREE_STRING(ctxt, URL)
     987      if (token != NULL)
     988  	XML_PAT_FREE_STRING(ctxt, token);
     989  }
     990  
     991  /**
     992   * xmlCompileStepPattern:
     993   * @ctxt:  the compilation context
     994   *
     995   * Compile the Step Pattern and generates a precompiled
     996   * form suitable for fast matching.
     997   *
     998   * [3]    Step    ::=    '.' | NameTest
     999   * [4]    NameTest    ::=    QName | '*' | NCName ':' '*'
    1000   */
    1001  
    1002  static void
    1003  xmlCompileStepPattern(xmlPatParserContextPtr ctxt) {
    1004      xmlChar *token = NULL;
    1005      xmlChar *name = NULL;
    1006      xmlChar *URL = NULL;
    1007      int hasBlanks = 0;
    1008  
    1009      SKIP_BLANKS;
    1010      if (CUR == '.') {
    1011  	/*
    1012  	* Context node.
    1013  	*/
    1014  	NEXT;
    1015  	PUSH(XML_OP_ELEM, NULL, NULL);
    1016  	return;
    1017      }
    1018      if (CUR == '@') {
    1019  	/*
    1020  	* Attribute test.
    1021  	*/
    1022  	if (XML_STREAM_XS_IDC_SEL(ctxt->comp)) {
    1023  	    ERROR5(NULL, NULL, NULL,
    1024  		"Unexpected attribute axis in '%s'.\n", ctxt->base);
    1025  	    ctxt->error = 1;
    1026  	    return;
    1027  	}
    1028  	NEXT;
    1029  	xmlCompileAttributeTest(ctxt);
    1030  	if (ctxt->error != 0)
    1031  	    goto error;
    1032  	return;
    1033      }
    1034      name = xmlPatScanNCName(ctxt);
    1035      if (name == NULL) {
    1036  	if (CUR == '*') {
    1037  	    NEXT;
    1038  	    PUSH(XML_OP_ALL, NULL, NULL);
    1039  	    return;
    1040  	} else {
    1041  	    ERROR(NULL, NULL, NULL,
    1042  		    "xmlCompileStepPattern : Name expected\n");
    1043  	    ctxt->error = 1;
    1044  	    return;
    1045  	}
    1046      }
    1047      if (IS_BLANK_CH(CUR)) {
    1048  	hasBlanks = 1;
    1049  	SKIP_BLANKS;
    1050      }
    1051      if (CUR == ':') {
    1052  	NEXT;
    1053  	if (CUR != ':') {
    1054  	    xmlChar *prefix = name;
    1055  	    int i;
    1056  
    1057  	    if (hasBlanks || IS_BLANK_CH(CUR)) {
    1058  		ERROR5(NULL, NULL, NULL, "Invalid QName.\n", NULL);
    1059  		ctxt->error = 1;
    1060  		goto error;
    1061  	    }
    1062  	    /*
    1063  	     * This is a namespace match
    1064  	     */
    1065  	    token = xmlPatScanName(ctxt);
    1066  	    if ((prefix[0] == 'x') &&
    1067  		(prefix[1] == 'm') &&
    1068  		(prefix[2] == 'l') &&
    1069  		(prefix[3] == 0))
    1070  	    {
    1071  		XML_PAT_COPY_NSNAME(ctxt, URL, XML_XML_NAMESPACE)
    1072  	    } else {
    1073  		for (i = 0;i < ctxt->nb_namespaces;i++) {
    1074  		    if (xmlStrEqual(ctxt->namespaces[2 * i + 1], prefix)) {
    1075  			XML_PAT_COPY_NSNAME(ctxt, URL, ctxt->namespaces[2 * i])
    1076  			break;
    1077  		    }
    1078  		}
    1079  		if (i >= ctxt->nb_namespaces) {
    1080  		    ERROR5(NULL, NULL, NULL,
    1081  			"xmlCompileStepPattern : no namespace bound to prefix %s\n",
    1082  			prefix);
    1083  		    ctxt->error = 1;
    1084  		    goto error;
    1085  		}
    1086  	    }
    1087  	    XML_PAT_FREE_STRING(ctxt, prefix);
    1088  	    name = NULL;
    1089  	    if (token == NULL) {
    1090  		if (CUR == '*') {
    1091  		    NEXT;
    1092  		    PUSH(XML_OP_NS, URL, NULL);
    1093  		} else {
    1094  		    ERROR(NULL, NULL, NULL,
    1095  			    "xmlCompileStepPattern : Name expected\n");
    1096  		    ctxt->error = 1;
    1097  		    goto error;
    1098  		}
    1099  	    } else {
    1100  		PUSH(XML_OP_ELEM, token, URL);
    1101  	    }
    1102  	} else {
    1103  	    NEXT;
    1104  	    if (xmlStrEqual(name, (const xmlChar *) "child")) {
    1105  		XML_PAT_FREE_STRING(ctxt, name);
    1106  		name = xmlPatScanName(ctxt);
    1107  		if (name == NULL) {
    1108  		    if (CUR == '*') {
    1109  			NEXT;
    1110  			PUSH(XML_OP_ALL, NULL, NULL);
    1111  			return;
    1112  		    } else {
    1113  			ERROR(NULL, NULL, NULL,
    1114  			    "xmlCompileStepPattern : QName expected\n");
    1115  			ctxt->error = 1;
    1116  			goto error;
    1117  		    }
    1118  		}
    1119  		if (CUR == ':') {
    1120  		    xmlChar *prefix = name;
    1121  		    int i;
    1122  
    1123  		    NEXT;
    1124  		    if (IS_BLANK_CH(CUR)) {
    1125  			ERROR5(NULL, NULL, NULL, "Invalid QName.\n", NULL);
    1126  			ctxt->error = 1;
    1127  			goto error;
    1128  		    }
    1129  		    /*
    1130  		    * This is a namespace match
    1131  		    */
    1132  		    token = xmlPatScanName(ctxt);
    1133  		    if ((prefix[0] == 'x') &&
    1134  			(prefix[1] == 'm') &&
    1135  			(prefix[2] == 'l') &&
    1136  			(prefix[3] == 0))
    1137  		    {
    1138  			XML_PAT_COPY_NSNAME(ctxt, URL, XML_XML_NAMESPACE)
    1139  		    } else {
    1140  			for (i = 0;i < ctxt->nb_namespaces;i++) {
    1141  			    if (xmlStrEqual(ctxt->namespaces[2 * i + 1], prefix)) {
    1142  				XML_PAT_COPY_NSNAME(ctxt, URL, ctxt->namespaces[2 * i])
    1143  				break;
    1144  			    }
    1145  			}
    1146  			if (i >= ctxt->nb_namespaces) {
    1147  			    ERROR5(NULL, NULL, NULL,
    1148  				"xmlCompileStepPattern : no namespace bound "
    1149  				"to prefix %s\n", prefix);
    1150  			    ctxt->error = 1;
    1151  			    goto error;
    1152  			}
    1153  		    }
    1154  		    XML_PAT_FREE_STRING(ctxt, prefix);
    1155  		    name = NULL;
    1156  		    if (token == NULL) {
    1157  			if (CUR == '*') {
    1158  			    NEXT;
    1159  			    PUSH(XML_OP_NS, URL, NULL);
    1160  			} else {
    1161  			    ERROR(NULL, NULL, NULL,
    1162  				"xmlCompileStepPattern : Name expected\n");
    1163  			    ctxt->error = 1;
    1164  			    goto error;
    1165  			}
    1166  		    } else {
    1167  			PUSH(XML_OP_CHILD, token, URL);
    1168  		    }
    1169  		} else
    1170  		    PUSH(XML_OP_CHILD, name, NULL);
    1171  		return;
    1172  	    } else if (xmlStrEqual(name, (const xmlChar *) "attribute")) {
    1173  		XML_PAT_FREE_STRING(ctxt, name)
    1174  		name = NULL;
    1175  		if (XML_STREAM_XS_IDC_SEL(ctxt->comp)) {
    1176  		    ERROR5(NULL, NULL, NULL,
    1177  			"Unexpected attribute axis in '%s'.\n", ctxt->base);
    1178  		    ctxt->error = 1;
    1179  		    goto error;
    1180  		}
    1181  		xmlCompileAttributeTest(ctxt);
    1182  		if (ctxt->error != 0)
    1183  		    goto error;
    1184  		return;
    1185  	    } else {
    1186  		ERROR5(NULL, NULL, NULL,
    1187  		    "The 'element' or 'attribute' axis is expected.\n", NULL);
    1188  		ctxt->error = 1;
    1189  		goto error;
    1190  	    }
    1191  	}
    1192      } else if (CUR == '*') {
    1193          if (name != NULL) {
    1194  	    ctxt->error = 1;
    1195  	    goto error;
    1196  	}
    1197  	NEXT;
    1198  	PUSH(XML_OP_ALL, token, NULL);
    1199      } else {
    1200  	PUSH(XML_OP_ELEM, name, NULL);
    1201      }
    1202      return;
    1203  error:
    1204      if (URL != NULL)
    1205  	XML_PAT_FREE_STRING(ctxt, URL)
    1206      if (token != NULL)
    1207  	XML_PAT_FREE_STRING(ctxt, token)
    1208      if (name != NULL)
    1209  	XML_PAT_FREE_STRING(ctxt, name)
    1210  }
    1211  
    1212  /**
    1213   * xmlCompilePathPattern:
    1214   * @ctxt:  the compilation context
    1215   *
    1216   * Compile the Path Pattern and generates a precompiled
    1217   * form suitable for fast matching.
    1218   *
    1219   * [5]    Path    ::=    ('.//')? ( Step '/' )* ( Step | '@' NameTest )
    1220   */
    1221  static void
    1222  xmlCompilePathPattern(xmlPatParserContextPtr ctxt) {
    1223      SKIP_BLANKS;
    1224      if (CUR == '/') {
    1225          ctxt->comp->flags |= PAT_FROM_ROOT;
    1226      } else if ((CUR == '.') || (ctxt->comp->flags & XML_PATTERN_NOTPATTERN)) {
    1227          ctxt->comp->flags |= PAT_FROM_CUR;
    1228      }
    1229  
    1230      if ((CUR == '/') && (NXT(1) == '/')) {
    1231  	PUSH(XML_OP_ANCESTOR, NULL, NULL);
    1232  	NEXT;
    1233  	NEXT;
    1234      } else if ((CUR == '.') && (NXT(1) == '/') && (NXT(2) == '/')) {
    1235  	PUSH(XML_OP_ANCESTOR, NULL, NULL);
    1236  	NEXT;
    1237  	NEXT;
    1238  	NEXT;
    1239  	/* Check for incompleteness. */
    1240  	SKIP_BLANKS;
    1241  	if (CUR == 0) {
    1242  	    ERROR5(NULL, NULL, NULL,
    1243  	       "Incomplete expression '%s'.\n", ctxt->base);
    1244  	    ctxt->error = 1;
    1245  	    goto error;
    1246  	}
    1247      }
    1248      if (CUR == '@') {
    1249  	NEXT;
    1250  	xmlCompileAttributeTest(ctxt);
    1251  	SKIP_BLANKS;
    1252  	/* TODO: check for incompleteness */
    1253  	if (CUR != 0) {
    1254  	    xmlCompileStepPattern(ctxt);
    1255  	    if (ctxt->error != 0)
    1256  		goto error;
    1257  	}
    1258      } else {
    1259          if (CUR == '/') {
    1260  	    PUSH(XML_OP_ROOT, NULL, NULL);
    1261  	    NEXT;
    1262  	    /* Check for incompleteness. */
    1263  	    SKIP_BLANKS;
    1264  	    if (CUR == 0) {
    1265  		ERROR5(NULL, NULL, NULL,
    1266  		    "Incomplete expression '%s'.\n", ctxt->base);
    1267  		ctxt->error = 1;
    1268  		goto error;
    1269  	    }
    1270  	}
    1271  	xmlCompileStepPattern(ctxt);
    1272  	if (ctxt->error != 0)
    1273  	    goto error;
    1274  	SKIP_BLANKS;
    1275  	while (CUR == '/') {
    1276  	    if (NXT(1) == '/') {
    1277  	        PUSH(XML_OP_ANCESTOR, NULL, NULL);
    1278  		NEXT;
    1279  		NEXT;
    1280  		SKIP_BLANKS;
    1281  		xmlCompileStepPattern(ctxt);
    1282  		if (ctxt->error != 0)
    1283  		    goto error;
    1284  	    } else {
    1285  	        PUSH(XML_OP_PARENT, NULL, NULL);
    1286  		NEXT;
    1287  		SKIP_BLANKS;
    1288  		if (CUR == 0) {
    1289  		    ERROR5(NULL, NULL, NULL,
    1290  		    "Incomplete expression '%s'.\n", ctxt->base);
    1291  		    ctxt->error = 1;
    1292  		    goto error;
    1293  		}
    1294  		xmlCompileStepPattern(ctxt);
    1295  		if (ctxt->error != 0)
    1296  		    goto error;
    1297  	    }
    1298  	}
    1299      }
    1300      if (CUR != 0) {
    1301  	ERROR5(NULL, NULL, NULL,
    1302  	       "Failed to compile pattern %s\n", ctxt->base);
    1303  	ctxt->error = 1;
    1304      }
    1305  error:
    1306      return;
    1307  }
    1308  
    1309  /**
    1310   * xmlCompileIDCXPathPath:
    1311   * @ctxt:  the compilation context
    1312   *
    1313   * Compile the Path Pattern and generates a precompiled
    1314   * form suitable for fast matching.
    1315   *
    1316   * [5]    Path    ::=    ('.//')? ( Step '/' )* ( Step | '@' NameTest )
    1317   */
    1318  static void
    1319  xmlCompileIDCXPathPath(xmlPatParserContextPtr ctxt) {
    1320      SKIP_BLANKS;
    1321      if (CUR == '/') {
    1322  	ERROR5(NULL, NULL, NULL,
    1323  	    "Unexpected selection of the document root in '%s'.\n",
    1324  	    ctxt->base);
    1325  	goto error;
    1326      }
    1327      ctxt->comp->flags |= PAT_FROM_CUR;
    1328  
    1329      if (CUR == '.') {
    1330  	/* "." - "self::node()" */
    1331  	NEXT;
    1332  	SKIP_BLANKS;
    1333  	if (CUR == 0) {
    1334  	    /*
    1335  	    * Selection of the context node.
    1336  	    */
    1337  	    PUSH(XML_OP_ELEM, NULL, NULL);
    1338  	    return;
    1339  	}
    1340  	if (CUR != '/') {
    1341  	    /* TODO: A more meaningful error message. */
    1342  	    ERROR5(NULL, NULL, NULL,
    1343  	    "Unexpected token after '.' in '%s'.\n", ctxt->base);
    1344  	    goto error;
    1345  	}
    1346  	/* "./" - "self::node()/" */
    1347  	NEXT;
    1348  	SKIP_BLANKS;
    1349  	if (CUR == '/') {
    1350  	    if (IS_BLANK_CH(PEEKPREV(1))) {
    1351  		/*
    1352  		* Disallow "./ /"
    1353  		*/
    1354  		ERROR5(NULL, NULL, NULL,
    1355  		    "Unexpected '/' token in '%s'.\n", ctxt->base);
    1356  		goto error;
    1357  	    }
    1358  	    /* ".//" - "self:node()/descendant-or-self::node()/" */
    1359  	    PUSH(XML_OP_ANCESTOR, NULL, NULL);
    1360  	    NEXT;
    1361  	    SKIP_BLANKS;
    1362  	}
    1363  	if (CUR == 0)
    1364  	    goto error_unfinished;
    1365      }
    1366      /*
    1367      * Process steps.
    1368      */
    1369      do {
    1370  	xmlCompileStepPattern(ctxt);
    1371  	if (ctxt->error != 0)
    1372  	    goto error;
    1373  	SKIP_BLANKS;
    1374  	if (CUR != '/')
    1375  	    break;
    1376  	PUSH(XML_OP_PARENT, NULL, NULL);
    1377  	NEXT;
    1378  	SKIP_BLANKS;
    1379  	if (CUR == '/') {
    1380  	    /*
    1381  	    * Disallow subsequent '//'.
    1382  	    */
    1383  	    ERROR5(NULL, NULL, NULL,
    1384  		"Unexpected subsequent '//' in '%s'.\n",
    1385  		ctxt->base);
    1386  	    goto error;
    1387  	}
    1388  	if (CUR == 0)
    1389  	    goto error_unfinished;
    1390  
    1391      } while (CUR != 0);
    1392  
    1393      if (CUR != 0) {
    1394  	ERROR5(NULL, NULL, NULL,
    1395  	    "Failed to compile expression '%s'.\n", ctxt->base);
    1396  	ctxt->error = 1;
    1397      }
    1398      return;
    1399  error:
    1400      ctxt->error = 1;
    1401      return;
    1402  
    1403  error_unfinished:
    1404      ctxt->error = 1;
    1405      ERROR5(NULL, NULL, NULL,
    1406  	"Unfinished expression '%s'.\n", ctxt->base);
    1407      return;
    1408  }
    1409  
    1410  /************************************************************************
    1411   *									*
    1412   *			The streaming code				*
    1413   *									*
    1414   ************************************************************************/
    1415  
    1416  /**
    1417   * xmlNewStreamComp:
    1418   * @size: the number of expected steps
    1419   *
    1420   * build a new compiled pattern for streaming
    1421   *
    1422   * Returns the new structure or NULL in case of error.
    1423   */
    1424  static xmlStreamCompPtr
    1425  xmlNewStreamComp(int size) {
    1426      xmlStreamCompPtr cur;
    1427  
    1428      if (size < 4)
    1429          size  = 4;
    1430  
    1431      cur = (xmlStreamCompPtr) xmlMalloc(sizeof(xmlStreamComp));
    1432      if (cur == NULL) {
    1433  	ERROR(NULL, NULL, NULL,
    1434  		"xmlNewStreamComp: malloc failed\n");
    1435  	return(NULL);
    1436      }
    1437      memset(cur, 0, sizeof(xmlStreamComp));
    1438      cur->steps = (xmlStreamStepPtr) xmlMalloc(size * sizeof(xmlStreamStep));
    1439      if (cur->steps == NULL) {
    1440  	xmlFree(cur);
    1441  	ERROR(NULL, NULL, NULL,
    1442  	      "xmlNewStreamComp: malloc failed\n");
    1443  	return(NULL);
    1444      }
    1445      cur->nbStep = 0;
    1446      cur->maxStep = size;
    1447      return(cur);
    1448  }
    1449  
    1450  /**
    1451   * xmlFreeStreamComp:
    1452   * @comp: the compiled pattern for streaming
    1453   *
    1454   * Free the compiled pattern for streaming
    1455   */
    1456  static void
    1457  xmlFreeStreamComp(xmlStreamCompPtr comp) {
    1458      if (comp != NULL) {
    1459          if (comp->steps != NULL)
    1460  	    xmlFree(comp->steps);
    1461  	if (comp->dict != NULL)
    1462  	    xmlDictFree(comp->dict);
    1463          xmlFree(comp);
    1464      }
    1465  }
    1466  
    1467  /**
    1468   * xmlStreamCompAddStep:
    1469   * @comp: the compiled pattern for streaming
    1470   * @name: the first string, the name, or NULL for *
    1471   * @ns: the second step, the namespace name
    1472   * @flags: the flags for that step
    1473   *
    1474   * Add a new step to the compiled pattern
    1475   *
    1476   * Returns -1 in case of error or the step index if successful
    1477   */
    1478  static int
    1479  xmlStreamCompAddStep(xmlStreamCompPtr comp, const xmlChar *name,
    1480                       const xmlChar *ns, int nodeType, int flags) {
    1481      xmlStreamStepPtr cur;
    1482  
    1483      if (comp->nbStep >= comp->maxStep) {
    1484  	cur = (xmlStreamStepPtr) xmlRealloc(comp->steps,
    1485  				 comp->maxStep * 2 * sizeof(xmlStreamStep));
    1486  	if (cur == NULL) {
    1487  	    ERROR(NULL, NULL, NULL,
    1488  		  "xmlNewStreamComp: malloc failed\n");
    1489  	    return(-1);
    1490  	}
    1491  	comp->steps = cur;
    1492          comp->maxStep *= 2;
    1493      }
    1494      cur = &comp->steps[comp->nbStep++];
    1495      cur->flags = flags;
    1496      cur->name = name;
    1497      cur->ns = ns;
    1498      cur->nodeType = nodeType;
    1499      return(comp->nbStep - 1);
    1500  }
    1501  
    1502  /**
    1503   * xmlStreamCompile:
    1504   * @comp: the precompiled pattern
    1505   *
    1506   * Tries to stream compile a pattern
    1507   *
    1508   * Returns -1 in case of failure and 0 in case of success.
    1509   */
    1510  static int
    1511  xmlStreamCompile(xmlPatternPtr comp) {
    1512      xmlStreamCompPtr stream;
    1513      int i, s = 0, root = 0, flags = 0, prevs = -1;
    1514      xmlStepOp step;
    1515  
    1516      if ((comp == NULL) || (comp->steps == NULL))
    1517          return(-1);
    1518      /*
    1519       * special case for .
    1520       */
    1521      if ((comp->nbStep == 1) &&
    1522          (comp->steps[0].op == XML_OP_ELEM) &&
    1523  	(comp->steps[0].value == NULL) &&
    1524  	(comp->steps[0].value2 == NULL)) {
    1525  	stream = xmlNewStreamComp(0);
    1526  	if (stream == NULL)
    1527  	    return(-1);
    1528  	/* Note that the stream will have no steps in this case. */
    1529  	stream->flags |= XML_STREAM_FINAL_IS_ANY_NODE;
    1530  	comp->stream = stream;
    1531  	return(0);
    1532      }
    1533  
    1534      stream = xmlNewStreamComp((comp->nbStep / 2) + 1);
    1535      if (stream == NULL)
    1536          return(-1);
    1537      if (comp->dict != NULL) {
    1538          stream->dict = comp->dict;
    1539  	xmlDictReference(stream->dict);
    1540      }
    1541  
    1542      i = 0;
    1543      if (comp->flags & PAT_FROM_ROOT)
    1544  	stream->flags |= XML_STREAM_FROM_ROOT;
    1545  
    1546      for (;i < comp->nbStep;i++) {
    1547  	step = comp->steps[i];
    1548          switch (step.op) {
    1549  	    case XML_OP_END:
    1550  	        break;
    1551  	    case XML_OP_ROOT:
    1552  	        if (i != 0)
    1553  		    goto error;
    1554  		root = 1;
    1555  		break;
    1556  	    case XML_OP_NS:
    1557  		s = xmlStreamCompAddStep(stream, NULL, step.value,
    1558  		    XML_ELEMENT_NODE, flags);
    1559  		if (s < 0)
    1560  		    goto error;
    1561  		prevs = s;
    1562  		flags = 0;
    1563  		break;
    1564  	    case XML_OP_ATTR:
    1565  		flags |= XML_STREAM_STEP_ATTR;
    1566  		prevs = -1;
    1567  		s = xmlStreamCompAddStep(stream,
    1568  		    step.value, step.value2, XML_ATTRIBUTE_NODE, flags);
    1569  		flags = 0;
    1570  		if (s < 0)
    1571  		    goto error;
    1572  		break;
    1573  	    case XML_OP_ELEM:
    1574  	        if ((step.value == NULL) && (step.value2 == NULL)) {
    1575  		    /*
    1576  		    * We have a "." or "self::node()" here.
    1577  		    * Eliminate redundant self::node() tests like in "/./."
    1578  		    * or "//./"
    1579  		    * The only case we won't eliminate is "//.", i.e. if
    1580  		    * self::node() is the last node test and we had
    1581  		    * continuation somewhere beforehand.
    1582  		    */
    1583  		    if ((comp->nbStep == i + 1) &&
    1584  			(flags & XML_STREAM_STEP_DESC)) {
    1585  			/*
    1586  			* Mark the special case where the expression resolves
    1587  			* to any type of node.
    1588  			*/
    1589  			if (comp->nbStep == i + 1) {
    1590  			    stream->flags |= XML_STREAM_FINAL_IS_ANY_NODE;
    1591  			}
    1592  			flags |= XML_STREAM_STEP_NODE;
    1593  			s = xmlStreamCompAddStep(stream, NULL, NULL,
    1594  			    XML_STREAM_ANY_NODE, flags);
    1595  			if (s < 0)
    1596  			    goto error;
    1597  			flags = 0;
    1598  			/*
    1599  			* If there was a previous step, mark it to be added to
    1600  			* the result node-set; this is needed since only
    1601  			* the last step will be marked as "final" and only
    1602  			* "final" nodes are added to the resulting set.
    1603  			*/
    1604  			if (prevs != -1) {
    1605  			    stream->steps[prevs].flags |= XML_STREAM_STEP_IN_SET;
    1606  			    prevs = -1;
    1607  			}
    1608  			break;
    1609  
    1610  		    } else {
    1611  			/* Just skip this one. */
    1612  			continue;
    1613  		    }
    1614  		}
    1615  		/* An element node. */
    1616  	        s = xmlStreamCompAddStep(stream, step.value, step.value2,
    1617  		    XML_ELEMENT_NODE, flags);
    1618  		if (s < 0)
    1619  		    goto error;
    1620  		prevs = s;
    1621  		flags = 0;
    1622  		break;
    1623  	    case XML_OP_CHILD:
    1624  		/* An element node child. */
    1625  	        s = xmlStreamCompAddStep(stream, step.value, step.value2,
    1626  		    XML_ELEMENT_NODE, flags);
    1627  		if (s < 0)
    1628  		    goto error;
    1629  		prevs = s;
    1630  		flags = 0;
    1631  		break;
    1632  	    case XML_OP_ALL:
    1633  	        s = xmlStreamCompAddStep(stream, NULL, NULL,
    1634  		    XML_ELEMENT_NODE, flags);
    1635  		if (s < 0)
    1636  		    goto error;
    1637  		prevs = s;
    1638  		flags = 0;
    1639  		break;
    1640  	    case XML_OP_PARENT:
    1641  	        break;
    1642  	    case XML_OP_ANCESTOR:
    1643  		/* Skip redundant continuations. */
    1644  		if (flags & XML_STREAM_STEP_DESC)
    1645  		    break;
    1646  	        flags |= XML_STREAM_STEP_DESC;
    1647  		/*
    1648  		* Mark the expression as having "//".
    1649  		*/
    1650  		if ((stream->flags & XML_STREAM_DESC) == 0)
    1651  		    stream->flags |= XML_STREAM_DESC;
    1652  		break;
    1653  	}
    1654      }
    1655      if ((! root) && (comp->flags & XML_PATTERN_NOTPATTERN) == 0) {
    1656  	/*
    1657  	* If this should behave like a real pattern, we will mark
    1658  	* the first step as having "//", to be reentrant on every
    1659  	* tree level.
    1660  	*/
    1661  	if ((stream->flags & XML_STREAM_DESC) == 0)
    1662  	    stream->flags |= XML_STREAM_DESC;
    1663  
    1664  	if (stream->nbStep > 0) {
    1665  	    if ((stream->steps[0].flags & XML_STREAM_STEP_DESC) == 0)
    1666  		stream->steps[0].flags |= XML_STREAM_STEP_DESC;
    1667  	}
    1668      }
    1669      if (stream->nbStep <= s)
    1670  	goto error;
    1671      stream->steps[s].flags |= XML_STREAM_STEP_FINAL;
    1672      if (root)
    1673  	stream->steps[0].flags |= XML_STREAM_STEP_ROOT;
    1674      comp->stream = stream;
    1675      return(0);
    1676  error:
    1677      xmlFreeStreamComp(stream);
    1678      return(0);
    1679  }
    1680  
    1681  /**
    1682   * xmlNewStreamCtxt:
    1683   * @size: the number of expected states
    1684   *
    1685   * build a new stream context
    1686   *
    1687   * Returns the new structure or NULL in case of error.
    1688   */
    1689  static xmlStreamCtxtPtr
    1690  xmlNewStreamCtxt(xmlStreamCompPtr stream) {
    1691      xmlStreamCtxtPtr cur;
    1692  
    1693      cur = (xmlStreamCtxtPtr) xmlMalloc(sizeof(xmlStreamCtxt));
    1694      if (cur == NULL) {
    1695  	ERROR(NULL, NULL, NULL,
    1696  		"xmlNewStreamCtxt: malloc failed\n");
    1697  	return(NULL);
    1698      }
    1699      memset(cur, 0, sizeof(xmlStreamCtxt));
    1700      cur->states = (int *) xmlMalloc(4 * 2 * sizeof(int));
    1701      if (cur->states == NULL) {
    1702  	xmlFree(cur);
    1703  	ERROR(NULL, NULL, NULL,
    1704  	      "xmlNewStreamCtxt: malloc failed\n");
    1705  	return(NULL);
    1706      }
    1707      cur->nbState = 0;
    1708      cur->maxState = 4;
    1709      cur->level = 0;
    1710      cur->comp = stream;
    1711      cur->blockLevel = -1;
    1712      return(cur);
    1713  }
    1714  
    1715  /**
    1716   * xmlFreeStreamCtxt:
    1717   * @stream: the stream context
    1718   *
    1719   * Free the stream context
    1720   */
    1721  void
    1722  xmlFreeStreamCtxt(xmlStreamCtxtPtr stream) {
    1723      xmlStreamCtxtPtr next;
    1724  
    1725      while (stream != NULL) {
    1726          next = stream->next;
    1727          if (stream->states != NULL)
    1728  	    xmlFree(stream->states);
    1729          xmlFree(stream);
    1730  	stream = next;
    1731      }
    1732  }
    1733  
    1734  /**
    1735   * xmlStreamCtxtAddState:
    1736   * @comp: the stream context
    1737   * @idx: the step index for that streaming state
    1738   *
    1739   * Add a new state to the stream context
    1740   *
    1741   * Returns -1 in case of error or the state index if successful
    1742   */
    1743  static int
    1744  xmlStreamCtxtAddState(xmlStreamCtxtPtr comp, int idx, int level) {
    1745      int i;
    1746      for (i = 0;i < comp->nbState;i++) {
    1747          if (comp->states[2 * i] < 0) {
    1748  	    comp->states[2 * i] = idx;
    1749  	    comp->states[2 * i + 1] = level;
    1750  	    return(i);
    1751  	}
    1752      }
    1753      if (comp->nbState >= comp->maxState) {
    1754          int *cur;
    1755  
    1756  	cur = (int *) xmlRealloc(comp->states,
    1757  				 comp->maxState * 4 * sizeof(int));
    1758  	if (cur == NULL) {
    1759  	    ERROR(NULL, NULL, NULL,
    1760  		  "xmlNewStreamCtxt: malloc failed\n");
    1761  	    return(-1);
    1762  	}
    1763  	comp->states = cur;
    1764          comp->maxState *= 2;
    1765      }
    1766      comp->states[2 * comp->nbState] = idx;
    1767      comp->states[2 * comp->nbState++ + 1] = level;
    1768      return(comp->nbState - 1);
    1769  }
    1770  
    1771  /**
    1772   * xmlStreamPushInternal:
    1773   * @stream: the stream context
    1774   * @name: the current name
    1775   * @ns: the namespace name
    1776   * @nodeType: the type of the node
    1777   *
    1778   * Push new data onto the stream. NOTE: if the call xmlPatterncompile()
    1779   * indicated a dictionary, then strings for name and ns will be expected
    1780   * to come from the dictionary.
    1781   * Both @name and @ns being NULL means the / i.e. the root of the document.
    1782   * This can also act as a reset.
    1783   *
    1784   * Returns: -1 in case of error, 1 if the current state in the stream is a
    1785   *    match and 0 otherwise.
    1786   */
    1787  static int
    1788  xmlStreamPushInternal(xmlStreamCtxtPtr stream,
    1789  		      const xmlChar *name, const xmlChar *ns,
    1790  		      int nodeType) {
    1791      int ret = 0, err = 0, final = 0, tmp, i, m, match, stepNr, desc;
    1792      xmlStreamCompPtr comp;
    1793      xmlStreamStep step;
    1794  
    1795      if ((stream == NULL) || (stream->nbState < 0))
    1796          return(-1);
    1797  
    1798      while (stream != NULL) {
    1799  	comp = stream->comp;
    1800  
    1801  	if ((nodeType == XML_ELEMENT_NODE) &&
    1802  	    (name == NULL) && (ns == NULL)) {
    1803  	    /* We have a document node here (or a reset). */
    1804  	    stream->nbState = 0;
    1805  	    stream->level = 0;
    1806  	    stream->blockLevel = -1;
    1807  	    if (comp->flags & XML_STREAM_FROM_ROOT) {
    1808  		if (comp->nbStep == 0) {
    1809  		    /* TODO: We have a "/." here? */
    1810  		    ret = 1;
    1811  		} else {
    1812  		    if ((comp->nbStep == 1) &&
    1813  			(comp->steps[0].nodeType == XML_STREAM_ANY_NODE) &&
    1814  			(comp->steps[0].flags & XML_STREAM_STEP_DESC))
    1815  		    {
    1816  			/*
    1817  			* In the case of "//." the document node will match
    1818  			* as well.
    1819  			*/
    1820  			ret = 1;
    1821  		    } else if (comp->steps[0].flags & XML_STREAM_STEP_ROOT) {
    1822  			/* TODO: Do we need this ? */
    1823  			tmp = xmlStreamCtxtAddState(stream, 0, 0);
    1824  			if (tmp < 0)
    1825  			    err++;
    1826  		    }
    1827  		}
    1828  	    }
    1829  	    stream = stream->next;
    1830  	    continue; /* while */
    1831  	}
    1832  
    1833  	/*
    1834  	* Fast check for ".".
    1835  	*/
    1836  	if (comp->nbStep == 0) {
    1837  	    /*
    1838  	     * / and . are handled at the XPath node set creation
    1839  	     * level by checking min depth
    1840  	     */
    1841  	    if (stream->flags & XML_PATTERN_XPATH) {
    1842  		stream = stream->next;
    1843  		continue; /* while */
    1844  	    }
    1845  	    /*
    1846  	    * For non-pattern like evaluation like XML Schema IDCs
    1847  	    * or traditional XPath expressions, this will match if
    1848  	    * we are at the first level only, otherwise on every level.
    1849  	    */
    1850  	    if ((nodeType != XML_ATTRIBUTE_NODE) &&
    1851  		(((stream->flags & XML_PATTERN_NOTPATTERN) == 0) ||
    1852  		(stream->level == 0))) {
    1853  		    ret = 1;
    1854  	    }
    1855  	    stream->level++;
    1856  	    goto stream_next;
    1857  	}
    1858  	if (stream->blockLevel != -1) {
    1859  	    /*
    1860  	    * Skip blocked expressions.
    1861  	    */
    1862  	    stream->level++;
    1863  	    goto stream_next;
    1864  	}
    1865  
    1866  	if ((nodeType != XML_ELEMENT_NODE) &&
    1867  	    (nodeType != XML_ATTRIBUTE_NODE) &&
    1868  	    ((comp->flags & XML_STREAM_FINAL_IS_ANY_NODE) == 0)) {
    1869  	    /*
    1870  	    * No need to process nodes of other types if we don't
    1871  	    * resolve to those types.
    1872  	    * TODO: Do we need to block the context here?
    1873  	    */
    1874  	    stream->level++;
    1875  	    goto stream_next;
    1876  	}
    1877  
    1878  	/*
    1879  	 * Check evolution of existing states
    1880  	 */
    1881  	i = 0;
    1882  	m = stream->nbState;
    1883  	while (i < m) {
    1884  	    if ((comp->flags & XML_STREAM_DESC) == 0) {
    1885  		/*
    1886  		* If there is no "//", then only the last
    1887  		* added state is of interest.
    1888  		*/
    1889  		stepNr = stream->states[2 * (stream->nbState -1)];
    1890  		/*
    1891  		* TODO: Security check, should not happen, remove it.
    1892  		*/
    1893  		if (stream->states[(2 * (stream->nbState -1)) + 1] <
    1894  		    stream->level) {
    1895  		    return (-1);
    1896  		}
    1897  		desc = 0;
    1898  		/* loop-stopper */
    1899  		i = m;
    1900  	    } else {
    1901  		/*
    1902  		* If there are "//", then we need to process every "//"
    1903  		* occurring in the states, plus any other state for this
    1904  		* level.
    1905  		*/
    1906  		stepNr = stream->states[2 * i];
    1907  
    1908  		/* TODO: should not happen anymore: dead states */
    1909  		if (stepNr < 0)
    1910  		    goto next_state;
    1911  
    1912  		tmp = stream->states[(2 * i) + 1];
    1913  
    1914  		/* skip new states just added */
    1915  		if (tmp > stream->level)
    1916  		    goto next_state;
    1917  
    1918  		/* skip states at ancestor levels, except if "//" */
    1919  		desc = comp->steps[stepNr].flags & XML_STREAM_STEP_DESC;
    1920  		if ((tmp < stream->level) && (!desc))
    1921  		    goto next_state;
    1922  	    }
    1923  	    /*
    1924  	    * Check for correct node-type.
    1925  	    */
    1926  	    step = comp->steps[stepNr];
    1927  	    if (step.nodeType != nodeType) {
    1928  		if (step.nodeType == XML_ATTRIBUTE_NODE) {
    1929  		    /*
    1930  		    * Block this expression for deeper evaluation.
    1931  		    */
    1932  		    if ((comp->flags & XML_STREAM_DESC) == 0)
    1933  			stream->blockLevel = stream->level +1;
    1934  		    goto next_state;
    1935  		} else if (step.nodeType != XML_STREAM_ANY_NODE)
    1936  		    goto next_state;
    1937  	    }
    1938  	    /*
    1939  	    * Compare local/namespace-name.
    1940  	    */
    1941  	    match = 0;
    1942  	    if (step.nodeType == XML_STREAM_ANY_NODE) {
    1943  		match = 1;
    1944  	    } else if (step.name == NULL) {
    1945  		if (step.ns == NULL) {
    1946  		    /*
    1947  		    * This lets through all elements/attributes.
    1948  		    */
    1949  		    match = 1;
    1950  		} else if (ns != NULL)
    1951  		    match = xmlStrEqual(step.ns, ns);
    1952  	    } else if (((step.ns != NULL) == (ns != NULL)) &&
    1953  		(name != NULL) &&
    1954  		(step.name[0] == name[0]) &&
    1955  		xmlStrEqual(step.name, name) &&
    1956  		((step.ns == ns) || xmlStrEqual(step.ns, ns)))
    1957  	    {
    1958  		match = 1;
    1959  	    }
    1960  #if 0
    1961  /*
    1962  * TODO: Pointer comparison won't work, since not guaranteed that the given
    1963  *  values are in the same dict; especially if it's the namespace name,
    1964  *  normally coming from ns->href. We need a namespace dict mechanism !
    1965  */
    1966  	    } else if (comp->dict) {
    1967  		if (step.name == NULL) {
    1968  		    if (step.ns == NULL)
    1969  			match = 1;
    1970  		    else
    1971  			match = (step.ns == ns);
    1972  		} else {
    1973  		    match = ((step.name == name) && (step.ns == ns));
    1974  		}
    1975  #endif /* if 0 ------------------------------------------------------- */
    1976  	    if (match) {
    1977  		final = step.flags & XML_STREAM_STEP_FINAL;
    1978                  if (final) {
    1979                      ret = 1;
    1980                  } else {
    1981                      xmlStreamCtxtAddState(stream, stepNr + 1,
    1982                                            stream->level + 1);
    1983                  }
    1984  		if ((ret != 1) && (step.flags & XML_STREAM_STEP_IN_SET)) {
    1985  		    /*
    1986  		    * Check if we have a special case like "foo/bar//.", where
    1987  		    * "foo" is selected as well.
    1988  		    */
    1989  		    ret = 1;
    1990  		}
    1991  	    }
    1992  	    if (((comp->flags & XML_STREAM_DESC) == 0) &&
    1993  		((! match) || final))  {
    1994  		/*
    1995  		* Mark this expression as blocked for any evaluation at
    1996  		* deeper levels. Note that this includes "/foo"
    1997  		* expressions if the *pattern* behaviour is used.
    1998  		*/
    1999  		stream->blockLevel = stream->level +1;
    2000  	    }
    2001  next_state:
    2002  	    i++;
    2003  	}
    2004  
    2005  	stream->level++;
    2006  
    2007  	/*
    2008  	* Re/enter the expression.
    2009  	* Don't reenter if it's an absolute expression like "/foo",
    2010  	*   except "//foo".
    2011  	*/
    2012  	step = comp->steps[0];
    2013  	if (step.flags & XML_STREAM_STEP_ROOT)
    2014  	    goto stream_next;
    2015  
    2016  	desc = step.flags & XML_STREAM_STEP_DESC;
    2017  	if (stream->flags & XML_PATTERN_NOTPATTERN) {
    2018  	    /*
    2019  	    * Re/enter the expression if it is a "descendant" one,
    2020  	    * or if we are at the 1st level of evaluation.
    2021  	    */
    2022  
    2023  	    if (stream->level == 1) {
    2024  		if (XML_STREAM_XS_IDC(stream)) {
    2025  		    /*
    2026  		    * XS-IDC: The missing "self::node()" will always
    2027  		    * match the first given node.
    2028  		    */
    2029  		    goto stream_next;
    2030  		} else
    2031  		    goto compare;
    2032  	    }
    2033  	    /*
    2034  	    * A "//" is always reentrant.
    2035  	    */
    2036  	    if (desc)
    2037  		goto compare;
    2038  
    2039  	    /*
    2040  	    * XS-IDC: Process the 2nd level, since the missing
    2041  	    * "self::node()" is responsible for the 2nd level being
    2042  	    * the real start level.
    2043  	    */
    2044  	    if ((stream->level == 2) && XML_STREAM_XS_IDC(stream))
    2045  		goto compare;
    2046  
    2047  	    goto stream_next;
    2048  	}
    2049  
    2050  compare:
    2051  	/*
    2052  	* Check expected node-type.
    2053  	*/
    2054  	if (step.nodeType != nodeType) {
    2055  	    if (nodeType == XML_ATTRIBUTE_NODE)
    2056  		goto stream_next;
    2057  	    else if (step.nodeType != XML_STREAM_ANY_NODE)
    2058  		goto stream_next;
    2059  	}
    2060  	/*
    2061  	* Compare local/namespace-name.
    2062  	*/
    2063  	match = 0;
    2064  	if (step.nodeType == XML_STREAM_ANY_NODE) {
    2065  	    match = 1;
    2066  	} else if (step.name == NULL) {
    2067  	    if (step.ns == NULL) {
    2068  		/*
    2069  		* This lets through all elements/attributes.
    2070  		*/
    2071  		match = 1;
    2072  	    } else if (ns != NULL)
    2073  		match = xmlStrEqual(step.ns, ns);
    2074  	} else if (((step.ns != NULL) == (ns != NULL)) &&
    2075  	    (name != NULL) &&
    2076  	    (step.name[0] == name[0]) &&
    2077  	    xmlStrEqual(step.name, name) &&
    2078  	    ((step.ns == ns) || xmlStrEqual(step.ns, ns)))
    2079  	{
    2080  	    match = 1;
    2081  	}
    2082  	final = step.flags & XML_STREAM_STEP_FINAL;
    2083  	if (match) {
    2084  	    if (final)
    2085  		ret = 1;
    2086  	    else
    2087  		xmlStreamCtxtAddState(stream, 1, stream->level);
    2088  	    if ((ret != 1) && (step.flags & XML_STREAM_STEP_IN_SET)) {
    2089  		/*
    2090  		* Check if we have a special case like "foo//.", where
    2091  		* "foo" is selected as well.
    2092  		*/
    2093  		ret = 1;
    2094  	    }
    2095  	}
    2096  	if (((comp->flags & XML_STREAM_DESC) == 0) &&
    2097  	    ((! match) || final))  {
    2098  	    /*
    2099  	    * Mark this expression as blocked for any evaluation at
    2100  	    * deeper levels.
    2101  	    */
    2102  	    stream->blockLevel = stream->level;
    2103  	}
    2104  
    2105  stream_next:
    2106          stream = stream->next;
    2107      } /* while stream != NULL */
    2108  
    2109      if (err > 0)
    2110          ret = -1;
    2111      return(ret);
    2112  }
    2113  
    2114  /**
    2115   * xmlStreamPush:
    2116   * @stream: the stream context
    2117   * @name: the current name
    2118   * @ns: the namespace name
    2119   *
    2120   * Push new data onto the stream. NOTE: if the call xmlPatterncompile()
    2121   * indicated a dictionary, then strings for name and ns will be expected
    2122   * to come from the dictionary.
    2123   * Both @name and @ns being NULL means the / i.e. the root of the document.
    2124   * This can also act as a reset.
    2125   * Otherwise the function will act as if it has been given an element-node.
    2126   *
    2127   * Returns: -1 in case of error, 1 if the current state in the stream is a
    2128   *    match and 0 otherwise.
    2129   */
    2130  int
    2131  xmlStreamPush(xmlStreamCtxtPtr stream,
    2132                const xmlChar *name, const xmlChar *ns) {
    2133      return (xmlStreamPushInternal(stream, name, ns, XML_ELEMENT_NODE));
    2134  }
    2135  
    2136  /**
    2137   * xmlStreamPushNode:
    2138   * @stream: the stream context
    2139   * @name: the current name
    2140   * @ns: the namespace name
    2141   * @nodeType: the type of the node being pushed
    2142   *
    2143   * Push new data onto the stream. NOTE: if the call xmlPatterncompile()
    2144   * indicated a dictionary, then strings for name and ns will be expected
    2145   * to come from the dictionary.
    2146   * Both @name and @ns being NULL means the / i.e. the root of the document.
    2147   * This can also act as a reset.
    2148   * Different from xmlStreamPush() this function can be fed with nodes of type:
    2149   * element-, attribute-, text-, cdata-section-, comment- and
    2150   * processing-instruction-node.
    2151   *
    2152   * Returns: -1 in case of error, 1 if the current state in the stream is a
    2153   *    match and 0 otherwise.
    2154   */
    2155  int
    2156  xmlStreamPushNode(xmlStreamCtxtPtr stream,
    2157  		  const xmlChar *name, const xmlChar *ns,
    2158  		  int nodeType)
    2159  {
    2160      return (xmlStreamPushInternal(stream, name, ns,
    2161  	nodeType));
    2162  }
    2163  
    2164  /**
    2165  * xmlStreamPushAttr:
    2166  * @stream: the stream context
    2167  * @name: the current name
    2168  * @ns: the namespace name
    2169  *
    2170  * Push new attribute data onto the stream. NOTE: if the call xmlPatterncompile()
    2171  * indicated a dictionary, then strings for name and ns will be expected
    2172  * to come from the dictionary.
    2173  * Both @name and @ns being NULL means the / i.e. the root of the document.
    2174  * This can also act as a reset.
    2175  * Otherwise the function will act as if it has been given an attribute-node.
    2176  *
    2177  * Returns: -1 in case of error, 1 if the current state in the stream is a
    2178  *    match and 0 otherwise.
    2179  */
    2180  int
    2181  xmlStreamPushAttr(xmlStreamCtxtPtr stream,
    2182  		  const xmlChar *name, const xmlChar *ns) {
    2183      return (xmlStreamPushInternal(stream, name, ns, XML_ATTRIBUTE_NODE));
    2184  }
    2185  
    2186  /**
    2187   * xmlStreamPop:
    2188   * @stream: the stream context
    2189   *
    2190   * push one level from the stream.
    2191   *
    2192   * Returns: -1 in case of error, 0 otherwise.
    2193   */
    2194  int
    2195  xmlStreamPop(xmlStreamCtxtPtr stream) {
    2196      int i, lev;
    2197  
    2198      if (stream == NULL)
    2199          return(-1);
    2200      while (stream != NULL) {
    2201  	/*
    2202  	* Reset block-level.
    2203  	*/
    2204  	if (stream->blockLevel == stream->level)
    2205  	    stream->blockLevel = -1;
    2206  
    2207  	/*
    2208  	 *  stream->level can be zero when XML_FINAL_IS_ANY_NODE is set
    2209  	 *  (see the thread at
    2210  	 *  http://mail.gnome.org/archives/xslt/2008-July/msg00027.html)
    2211  	 */
    2212  	if (stream->level)
    2213  	    stream->level--;
    2214  	/*
    2215  	 * Check evolution of existing states
    2216  	 */
    2217  	for (i = stream->nbState -1; i >= 0; i--) {
    2218  	    /* discard obsoleted states */
    2219  	    lev = stream->states[(2 * i) + 1];
    2220  	    if (lev > stream->level)
    2221  		stream->nbState--;
    2222  	    if (lev <= stream->level)
    2223  		break;
    2224  	}
    2225  	stream = stream->next;
    2226      }
    2227      return(0);
    2228  }
    2229  
    2230  /**
    2231   * xmlStreamWantsAnyNode:
    2232   * @streamCtxt: the stream context
    2233   *
    2234   * Query if the streaming pattern additionally needs to be fed with
    2235   * text-, cdata-section-, comment- and processing-instruction-nodes.
    2236   * If the result is 0 then only element-nodes and attribute-nodes
    2237   * need to be pushed.
    2238   *
    2239   * Returns: 1 in case of need of nodes of the above described types,
    2240   *          0 otherwise. -1 on API errors.
    2241   */
    2242  int
    2243  xmlStreamWantsAnyNode(xmlStreamCtxtPtr streamCtxt)
    2244  {
    2245      if (streamCtxt == NULL)
    2246  	return(-1);
    2247      while (streamCtxt != NULL) {
    2248  	if (streamCtxt->comp->flags & XML_STREAM_FINAL_IS_ANY_NODE)
    2249  	    return(1);
    2250  	streamCtxt = streamCtxt->next;
    2251      }
    2252      return(0);
    2253  }
    2254  
    2255  /************************************************************************
    2256   *									*
    2257   *			The public interfaces				*
    2258   *									*
    2259   ************************************************************************/
    2260  
    2261  /**
    2262   * xmlPatterncompile:
    2263   * @pattern: the pattern to compile
    2264   * @dict: an optional dictionary for interned strings
    2265   * @flags: compilation flags, see xmlPatternFlags
    2266   * @namespaces: the prefix definitions, array of [URI, prefix] or NULL
    2267   *
    2268   * Compile a pattern.
    2269   *
    2270   * Returns the compiled form of the pattern or NULL in case of error
    2271   */
    2272  xmlPatternPtr
    2273  xmlPatterncompile(const xmlChar *pattern, xmlDict *dict, int flags,
    2274                    const xmlChar **namespaces) {
    2275      xmlPatternPtr ret = NULL, cur;
    2276      xmlPatParserContextPtr ctxt = NULL;
    2277      const xmlChar *or, *start;
    2278      xmlChar *tmp = NULL;
    2279      int type = 0;
    2280      int streamable = 1;
    2281  
    2282      if (pattern == NULL)
    2283          return(NULL);
    2284  
    2285      start = pattern;
    2286      or = start;
    2287      while (*or != 0) {
    2288  	tmp = NULL;
    2289  	while ((*or != 0) && (*or != '|')) or++;
    2290          if (*or == 0)
    2291  	    ctxt = xmlNewPatParserContext(start, dict, namespaces);
    2292  	else {
    2293  	    tmp = xmlStrndup(start, or - start);
    2294  	    if (tmp != NULL) {
    2295  		ctxt = xmlNewPatParserContext(tmp, dict, namespaces);
    2296  	    }
    2297  	    or++;
    2298  	}
    2299  	if (ctxt == NULL) goto error;
    2300  	cur = xmlNewPattern();
    2301  	if (cur == NULL) goto error;
    2302  	/*
    2303  	* Assign string dict.
    2304  	*/
    2305  	if (dict) {
    2306  	    cur->dict = dict;
    2307  	    xmlDictReference(dict);
    2308  	}
    2309  	if (ret == NULL)
    2310  	    ret = cur;
    2311  	else {
    2312  	    cur->next = ret->next;
    2313  	    ret->next = cur;
    2314  	}
    2315  	cur->flags = flags;
    2316  	ctxt->comp = cur;
    2317  
    2318  	if (XML_STREAM_XS_IDC(cur))
    2319  	    xmlCompileIDCXPathPath(ctxt);
    2320  	else
    2321  	    xmlCompilePathPattern(ctxt);
    2322  	if (ctxt->error != 0)
    2323  	    goto error;
    2324  	xmlFreePatParserContext(ctxt);
    2325  	ctxt = NULL;
    2326  
    2327  
    2328          if (streamable) {
    2329  	    if (type == 0) {
    2330  	        type = cur->flags & (PAT_FROM_ROOT | PAT_FROM_CUR);
    2331  	    } else if (type == PAT_FROM_ROOT) {
    2332  	        if (cur->flags & PAT_FROM_CUR)
    2333  		    streamable = 0;
    2334  	    } else if (type == PAT_FROM_CUR) {
    2335  	        if (cur->flags & PAT_FROM_ROOT)
    2336  		    streamable = 0;
    2337  	    }
    2338  	}
    2339  	if (streamable)
    2340  	    xmlStreamCompile(cur);
    2341  	if (xmlReversePattern(cur) < 0)
    2342  	    goto error;
    2343  	if (tmp != NULL) {
    2344  	    xmlFree(tmp);
    2345  	    tmp = NULL;
    2346  	}
    2347  	start = or;
    2348      }
    2349      if (streamable == 0) {
    2350          cur = ret;
    2351  	while (cur != NULL) {
    2352  	    if (cur->stream != NULL) {
    2353  		xmlFreeStreamComp(cur->stream);
    2354  		cur->stream = NULL;
    2355  	    }
    2356  	    cur = cur->next;
    2357  	}
    2358      }
    2359  
    2360      return(ret);
    2361  error:
    2362      if (ctxt != NULL) xmlFreePatParserContext(ctxt);
    2363      if (ret != NULL) xmlFreePattern(ret);
    2364      if (tmp != NULL) xmlFree(tmp);
    2365      return(NULL);
    2366  }
    2367  
    2368  /**
    2369   * xmlPatternMatch:
    2370   * @comp: the precompiled pattern
    2371   * @node: a node
    2372   *
    2373   * Test whether the node matches the pattern
    2374   *
    2375   * Returns 1 if it matches, 0 if it doesn't and -1 in case of failure
    2376   */
    2377  int
    2378  xmlPatternMatch(xmlPatternPtr comp, xmlNodePtr node)
    2379  {
    2380      int ret = 0;
    2381  
    2382      if ((comp == NULL) || (node == NULL))
    2383          return(-1);
    2384  
    2385      while (comp != NULL) {
    2386          ret = xmlPatMatch(comp, node);
    2387  	if (ret != 0)
    2388  	    return(ret);
    2389  	comp = comp->next;
    2390      }
    2391      return(ret);
    2392  }
    2393  
    2394  /**
    2395   * xmlPatternGetStreamCtxt:
    2396   * @comp: the precompiled pattern
    2397   *
    2398   * Get a streaming context for that pattern
    2399   * Use xmlFreeStreamCtxt to free the context.
    2400   *
    2401   * Returns a pointer to the context or NULL in case of failure
    2402   */
    2403  xmlStreamCtxtPtr
    2404  xmlPatternGetStreamCtxt(xmlPatternPtr comp)
    2405  {
    2406      xmlStreamCtxtPtr ret = NULL, cur;
    2407  
    2408      if ((comp == NULL) || (comp->stream == NULL))
    2409          return(NULL);
    2410  
    2411      while (comp != NULL) {
    2412          if (comp->stream == NULL)
    2413  	    goto failed;
    2414  	cur = xmlNewStreamCtxt(comp->stream);
    2415  	if (cur == NULL)
    2416  	    goto failed;
    2417  	if (ret == NULL)
    2418  	    ret = cur;
    2419  	else {
    2420  	    cur->next = ret->next;
    2421  	    ret->next = cur;
    2422  	}
    2423  	cur->flags = comp->flags;
    2424  	comp = comp->next;
    2425      }
    2426      return(ret);
    2427  failed:
    2428      xmlFreeStreamCtxt(ret);
    2429      return(NULL);
    2430  }
    2431  
    2432  /**
    2433   * xmlPatternStreamable:
    2434   * @comp: the precompiled pattern
    2435   *
    2436   * Check if the pattern is streamable i.e. xmlPatternGetStreamCtxt()
    2437   * should work.
    2438   *
    2439   * Returns 1 if streamable, 0 if not and -1 in case of error.
    2440   */
    2441  int
    2442  xmlPatternStreamable(xmlPatternPtr comp) {
    2443      if (comp == NULL)
    2444          return(-1);
    2445      while (comp != NULL) {
    2446          if (comp->stream == NULL)
    2447  	    return(0);
    2448  	comp = comp->next;
    2449      }
    2450      return(1);
    2451  }
    2452  
    2453  /**
    2454   * xmlPatternMaxDepth:
    2455   * @comp: the precompiled pattern
    2456   *
    2457   * Check the maximum depth reachable by a pattern
    2458   *
    2459   * Returns -2 if no limit (using //), otherwise the depth,
    2460   *         and -1 in case of error
    2461   */
    2462  int
    2463  xmlPatternMaxDepth(xmlPatternPtr comp) {
    2464      int ret = 0, i;
    2465      if (comp == NULL)
    2466          return(-1);
    2467      while (comp != NULL) {
    2468          if (comp->stream == NULL)
    2469  	    return(-1);
    2470  	for (i = 0;i < comp->stream->nbStep;i++)
    2471  	    if (comp->stream->steps[i].flags & XML_STREAM_STEP_DESC)
    2472  	        return(-2);
    2473  	if (comp->stream->nbStep > ret)
    2474  	    ret = comp->stream->nbStep;
    2475  	comp = comp->next;
    2476      }
    2477      return(ret);
    2478  }
    2479  
    2480  /**
    2481   * xmlPatternMinDepth:
    2482   * @comp: the precompiled pattern
    2483   *
    2484   * Check the minimum depth reachable by a pattern, 0 mean the / or . are
    2485   * part of the set.
    2486   *
    2487   * Returns -1 in case of error otherwise the depth,
    2488   *
    2489   */
    2490  int
    2491  xmlPatternMinDepth(xmlPatternPtr comp) {
    2492      int ret = 12345678;
    2493      if (comp == NULL)
    2494          return(-1);
    2495      while (comp != NULL) {
    2496          if (comp->stream == NULL)
    2497  	    return(-1);
    2498  	if (comp->stream->nbStep < ret)
    2499  	    ret = comp->stream->nbStep;
    2500  	if (ret == 0)
    2501  	    return(0);
    2502  	comp = comp->next;
    2503      }
    2504      return(ret);
    2505  }
    2506  
    2507  /**
    2508   * xmlPatternFromRoot:
    2509   * @comp: the precompiled pattern
    2510   *
    2511   * Check if the pattern must be looked at from the root.
    2512   *
    2513   * Returns 1 if true, 0 if false and -1 in case of error
    2514   */
    2515  int
    2516  xmlPatternFromRoot(xmlPatternPtr comp) {
    2517      if (comp == NULL)
    2518          return(-1);
    2519      while (comp != NULL) {
    2520          if (comp->stream == NULL)
    2521  	    return(-1);
    2522  	if (comp->flags & PAT_FROM_ROOT)
    2523  	    return(1);
    2524  	comp = comp->next;
    2525      }
    2526      return(0);
    2527  
    2528  }
    2529  
    2530  #endif /* LIBXML_PATTERN_ENABLED */