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