ReactOS  0.4.15-dev-506-ga3ec01c
pattern.c
Go to the documentation of this file.
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/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 careful 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;
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 
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 
230 void
231 xmlFreePattern(xmlPatternPtr comp) {
232  xmlFreePatternList(comp);
233 }
234 
235 static void
236 xmlFreePatternInternal(xmlPatternPtr comp) {
237  xmlStepOpPtr op;
238  int i;
239 
240  if (comp == NULL)
241  return;
242  if (comp->stream != NULL)
243  xmlFreeStreamComp(comp->stream);
244  if (comp->pattern != NULL)
245  xmlFree((xmlChar *)comp->pattern);
246  if (comp->steps != NULL) {
247  if (comp->dict == NULL) {
248  for (i = 0;i < comp->nbStep;i++) {
249  op = &comp->steps[i];
250  if (op->value != NULL)
251  xmlFree((xmlChar *) op->value);
252  if (op->value2 != NULL)
253  xmlFree((xmlChar *) op->value2);
254  }
255  }
256  xmlFree(comp->steps);
257  }
258  if (comp->dict != NULL)
259  xmlDictFree(comp->dict);
260 
261  memset(comp, -1, sizeof(xmlPattern));
262  xmlFree(comp);
263 }
264 
271 void
272 xmlFreePatternList(xmlPatternPtr comp) {
273  xmlPatternPtr cur;
274 
275  while (comp != NULL) {
276  cur = comp;
277  comp = comp->next;
278  cur->next = NULL;
279  xmlFreePatternInternal(cur);
280  }
281 }
282 
294 static xmlPatParserContextPtr
295 xmlNewPatParserContext(const xmlChar *pattern, xmlDictPtr dict,
296  const xmlChar **namespaces) {
297  xmlPatParserContextPtr cur;
298 
299  if (pattern == NULL)
300  return(NULL);
301 
302  cur = (xmlPatParserContextPtr) xmlMalloc(sizeof(xmlPatParserContext));
303  if (cur == NULL) {
304  ERROR(NULL, NULL, NULL,
305  "xmlNewPatParserContext : malloc failed\n");
306  return(NULL);
307  }
308  memset(cur, 0, sizeof(xmlPatParserContext));
309  cur->dict = dict;
310  cur->cur = pattern;
311  cur->base = pattern;
312  if (namespaces != NULL) {
313  int i;
314  for (i = 0;namespaces[2 * i] != NULL;i++)
315  ;
316  cur->nb_namespaces = i;
317  } else {
318  cur->nb_namespaces = 0;
319  }
320  cur->namespaces = namespaces;
321  return(cur);
322 }
323 
330 static void
331 xmlFreePatParserContext(xmlPatParserContextPtr ctxt) {
332  if (ctxt == NULL)
333  return;
334  memset(ctxt, -1, sizeof(xmlPatParserContext));
335  xmlFree(ctxt);
336 }
337 
349 static int
350 xmlPatternAdd(xmlPatParserContextPtr ctxt ATTRIBUTE_UNUSED,
351  xmlPatternPtr comp,
352  xmlPatOp op, xmlChar * value, xmlChar * value2)
353 {
354  if (comp->nbStep >= comp->maxStep) {
355  xmlStepOpPtr temp;
356  temp = (xmlStepOpPtr) xmlRealloc(comp->steps, comp->maxStep * 2 *
357  sizeof(xmlStepOp));
358  if (temp == NULL) {
359  ERROR(ctxt, NULL, NULL,
360  "xmlPatternAdd: realloc failed\n");
361  return (-1);
362  }
363  comp->steps = temp;
364  comp->maxStep *= 2;
365  }
366  comp->steps[comp->nbStep].op = op;
367  comp->steps[comp->nbStep].value = value;
368  comp->steps[comp->nbStep].value2 = value2;
369  comp->nbStep++;
370  return (0);
371 }
372 
373 #if 0
374 
380 static void
381 xsltSwapTopPattern(xmlPatternPtr comp) {
382  int i;
383  int j = comp->nbStep - 1;
384 
385  if (j > 0) {
386  register const xmlChar *tmp;
387  register xmlPatOp op;
388  i = j - 1;
389  tmp = comp->steps[i].value;
390  comp->steps[i].value = comp->steps[j].value;
391  comp->steps[j].value = tmp;
392  tmp = comp->steps[i].value2;
393  comp->steps[i].value2 = comp->steps[j].value2;
394  comp->steps[j].value2 = tmp;
395  op = comp->steps[i].op;
396  comp->steps[i].op = comp->steps[j].op;
397  comp->steps[j].op = op;
398  }
399 }
400 #endif
401 
410 static int
411 xmlReversePattern(xmlPatternPtr comp) {
412  int i, j;
413 
414  /*
415  * remove the leading // for //a or .//a
416  */
417  if ((comp->nbStep > 0) && (comp->steps[0].op == XML_OP_ANCESTOR)) {
418  for (i = 0, j = 1;j < comp->nbStep;i++,j++) {
419  comp->steps[i].value = comp->steps[j].value;
420  comp->steps[i].value2 = comp->steps[j].value2;
421  comp->steps[i].op = comp->steps[j].op;
422  }
423  comp->nbStep--;
424  }
425  if (comp->nbStep >= comp->maxStep) {
426  xmlStepOpPtr temp;
427  temp = (xmlStepOpPtr) xmlRealloc(comp->steps, comp->maxStep * 2 *
428  sizeof(xmlStepOp));
429  if (temp == NULL) {
430  ERROR(ctxt, NULL, NULL,
431  "xmlReversePattern: realloc failed\n");
432  return (-1);
433  }
434  comp->steps = temp;
435  comp->maxStep *= 2;
436  }
437  i = 0;
438  j = comp->nbStep - 1;
439  while (j > i) {
440  register const xmlChar *tmp;
441  register xmlPatOp op;
442  tmp = comp->steps[i].value;
443  comp->steps[i].value = comp->steps[j].value;
444  comp->steps[j].value = tmp;
445  tmp = comp->steps[i].value2;
446  comp->steps[i].value2 = comp->steps[j].value2;
447  comp->steps[j].value2 = tmp;
448  op = comp->steps[i].op;
449  comp->steps[i].op = comp->steps[j].op;
450  comp->steps[j].op = op;
451  j--;
452  i++;
453  }
454  comp->steps[comp->nbStep].value = NULL;
455  comp->steps[comp->nbStep].value2 = NULL;
456  comp->steps[comp->nbStep++].op = XML_OP_END;
457  return(0);
458 }
459 
460 /************************************************************************
461  * *
462  * The interpreter for the precompiled patterns *
463  * *
464  ************************************************************************/
465 
466 static int
467 xmlPatPushState(xmlStepStates *states, int step, xmlNodePtr node) {
468  if ((states->states == NULL) || (states->maxstates <= 0)) {
469  states->maxstates = 4;
470  states->nbstates = 0;
471  states->states = xmlMalloc(4 * sizeof(xmlStepState));
472  }
473  else if (states->maxstates <= states->nbstates) {
474  xmlStepState *tmp;
475 
476  tmp = (xmlStepStatePtr) xmlRealloc(states->states,
477  2 * states->maxstates * sizeof(xmlStepState));
478  if (tmp == NULL)
479  return(-1);
480  states->states = tmp;
481  states->maxstates *= 2;
482  }
483  states->states[states->nbstates].step = step;
484  states->states[states->nbstates++].node = node;
485 #if 0
486  fprintf(stderr, "Push: %d, %s\n", step, node->name);
487 #endif
488  return(0);
489 }
490 
500 static int
501 xmlPatMatch(xmlPatternPtr comp, xmlNodePtr node) {
502  int i;
503  xmlStepOpPtr step;
504  xmlStepStates states = {0, 0, NULL}; /* // may require backtrack */
505 
506  if ((comp == NULL) || (node == NULL)) return(-1);
507  i = 0;
508 restart:
509  for (;i < comp->nbStep;i++) {
510  step = &comp->steps[i];
511  switch (step->op) {
512  case XML_OP_END:
513  goto found;
514  case XML_OP_ROOT:
515  if (node->type == XML_NAMESPACE_DECL)
516  goto rollback;
517  node = node->parent;
518  if ((node->type == XML_DOCUMENT_NODE) ||
519 #ifdef LIBXML_DOCB_ENABLED
520  (node->type == XML_DOCB_DOCUMENT_NODE) ||
521 #endif
522  (node->type == XML_HTML_DOCUMENT_NODE))
523  continue;
524  goto rollback;
525  case XML_OP_ELEM:
526  if (node->type != XML_ELEMENT_NODE)
527  goto rollback;
528  if (step->value == NULL)
529  continue;
530  if (step->value[0] != node->name[0])
531  goto rollback;
532  if (!xmlStrEqual(step->value, node->name))
533  goto rollback;
534 
535  /* Namespace test */
536  if (node->ns == NULL) {
537  if (step->value2 != NULL)
538  goto rollback;
539  } else if (node->ns->href != NULL) {
540  if (step->value2 == NULL)
541  goto rollback;
542  if (!xmlStrEqual(step->value2, node->ns->href))
543  goto rollback;
544  }
545  continue;
546  case XML_OP_CHILD: {
547  xmlNodePtr lst;
548 
549  if ((node->type != XML_ELEMENT_NODE) &&
550  (node->type != XML_DOCUMENT_NODE) &&
551 #ifdef LIBXML_DOCB_ENABLED
552  (node->type != XML_DOCB_DOCUMENT_NODE) &&
553 #endif
554  (node->type != XML_HTML_DOCUMENT_NODE))
555  goto rollback;
556 
557  lst = node->children;
558 
559  if (step->value != NULL) {
560  while (lst != NULL) {
561  if ((lst->type == XML_ELEMENT_NODE) &&
562  (step->value[0] == lst->name[0]) &&
563  (xmlStrEqual(step->value, lst->name)))
564  break;
565  lst = lst->next;
566  }
567  if (lst != NULL)
568  continue;
569  }
570  goto rollback;
571  }
572  case XML_OP_ATTR:
573  if (node->type != XML_ATTRIBUTE_NODE)
574  goto rollback;
575  if (step->value != NULL) {
576  if (step->value[0] != node->name[0])
577  goto rollback;
578  if (!xmlStrEqual(step->value, node->name))
579  goto rollback;
580  }
581  /* Namespace test */
582  if (node->ns == NULL) {
583  if (step->value2 != NULL)
584  goto rollback;
585  } else if (step->value2 != NULL) {
586  if (!xmlStrEqual(step->value2, node->ns->href))
587  goto rollback;
588  }
589  continue;
590  case XML_OP_PARENT:
591  if ((node->type == XML_DOCUMENT_NODE) ||
592  (node->type == XML_HTML_DOCUMENT_NODE) ||
593 #ifdef LIBXML_DOCB_ENABLED
594  (node->type == XML_DOCB_DOCUMENT_NODE) ||
595 #endif
596  (node->type == XML_NAMESPACE_DECL))
597  goto rollback;
598  node = node->parent;
599  if (node == NULL)
600  goto rollback;
601  if (step->value == NULL)
602  continue;
603  if (step->value[0] != node->name[0])
604  goto rollback;
605  if (!xmlStrEqual(step->value, node->name))
606  goto rollback;
607  /* Namespace test */
608  if (node->ns == NULL) {
609  if (step->value2 != NULL)
610  goto rollback;
611  } else if (node->ns->href != NULL) {
612  if (step->value2 == NULL)
613  goto rollback;
614  if (!xmlStrEqual(step->value2, node->ns->href))
615  goto rollback;
616  }
617  continue;
618  case XML_OP_ANCESTOR:
619  /* TODO: implement coalescing of ANCESTOR/NODE ops */
620  if (step->value == NULL) {
621  i++;
622  step = &comp->steps[i];
623  if (step->op == XML_OP_ROOT)
624  goto found;
625  if (step->op != XML_OP_ELEM)
626  goto rollback;
627  if (step->value == NULL)
628  return(-1);
629  }
630  if (node == NULL)
631  goto rollback;
632  if ((node->type == XML_DOCUMENT_NODE) ||
633  (node->type == XML_HTML_DOCUMENT_NODE) ||
634 #ifdef LIBXML_DOCB_ENABLED
635  (node->type == XML_DOCB_DOCUMENT_NODE) ||
636 #endif
637  (node->type == XML_NAMESPACE_DECL))
638  goto rollback;
639  node = node->parent;
640  while (node != NULL) {
641  if ((node->type == XML_ELEMENT_NODE) &&
642  (step->value[0] == node->name[0]) &&
643  (xmlStrEqual(step->value, node->name))) {
644  /* Namespace test */
645  if (node->ns == NULL) {
646  if (step->value2 == NULL)
647  break;
648  } else if (node->ns->href != NULL) {
649  if ((step->value2 != NULL) &&
650  (xmlStrEqual(step->value2, node->ns->href)))
651  break;
652  }
653  }
654  node = node->parent;
655  }
656  if (node == NULL)
657  goto rollback;
658  /*
659  * prepare a potential rollback from here
660  * for ancestors of that node.
661  */
662  if (step->op == XML_OP_ANCESTOR)
663  xmlPatPushState(&states, i, node);
664  else
665  xmlPatPushState(&states, i - 1, node);
666  continue;
667  case XML_OP_NS:
668  if (node->type != XML_ELEMENT_NODE)
669  goto rollback;
670  if (node->ns == NULL) {
671  if (step->value != NULL)
672  goto rollback;
673  } else if (node->ns->href != NULL) {
674  if (step->value == NULL)
675  goto rollback;
676  if (!xmlStrEqual(step->value, node->ns->href))
677  goto rollback;
678  }
679  break;
680  case XML_OP_ALL:
681  if (node->type != XML_ELEMENT_NODE)
682  goto rollback;
683  break;
684  }
685  }
686 found:
687  if (states.states != NULL) {
688  /* Free the rollback states */
689  xmlFree(states.states);
690  }
691  return(1);
692 rollback:
693  /* got an error try to rollback */
694  if (states.states == NULL)
695  return(0);
696  if (states.nbstates <= 0) {
697  xmlFree(states.states);
698  return(0);
699  }
700  states.nbstates--;
701  i = states.states[states.nbstates].step;
702  node = states.states[states.nbstates].node;
703 #if 0
704  fprintf(stderr, "Pop: %d, %s\n", i, node->name);
705 #endif
706  goto restart;
707 }
708 
709 /************************************************************************
710  * *
711  * Dedicated parser for templates *
712  * *
713  ************************************************************************/
714 
715 #define TODO \
716  xmlGenericError(xmlGenericErrorContext, \
717  "Unimplemented block at %s:%d\n", \
718  __FILE__, __LINE__);
719 #define CUR (*ctxt->cur)
720 #define SKIP(val) ctxt->cur += (val)
721 #define NXT(val) ctxt->cur[(val)]
722 #define PEEKPREV(val) ctxt->cur[-(val)]
723 #define CUR_PTR ctxt->cur
724 
725 #define SKIP_BLANKS \
726  while (IS_BLANK_CH(CUR)) NEXT
727 
728 #define CURRENT (*ctxt->cur)
729 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
730 
731 
732 #define PUSH(op, val, val2) \
733  if (xmlPatternAdd(ctxt, ctxt->comp, (op), (val), (val2))) goto error;
734 
735 #define XSLT_ERROR(X) \
736  { xsltError(ctxt, __FILE__, __LINE__, X); \
737  ctxt->error = (X); return; }
738 
739 #define XSLT_ERROR0(X) \
740  { xsltError(ctxt, __FILE__, __LINE__, X); \
741  ctxt->error = (X); return(0); }
742 
743 #if 0
744 
756 static xmlChar *
757 xmlPatScanLiteral(xmlPatParserContextPtr ctxt) {
758  const xmlChar *q, *cur;
759  xmlChar *ret = NULL;
760  int val, len;
761 
762  SKIP_BLANKS;
763  if (CUR == '"') {
764  NEXT;
765  cur = q = CUR_PTR;
766  val = xmlStringCurrentChar(NULL, cur, &len);
767  while ((IS_CHAR(val)) && (val != '"')) {
768  cur += len;
769  val = xmlStringCurrentChar(NULL, cur, &len);
770  }
771  if (!IS_CHAR(val)) {
772  ctxt->error = 1;
773  return(NULL);
774  } else {
775  if (ctxt->dict)
776  ret = (xmlChar *) xmlDictLookup(ctxt->dict, q, cur - q);
777  else
778  ret = xmlStrndup(q, cur - q);
779  }
780  cur += len;
781  CUR_PTR = cur;
782  } else if (CUR == '\'') {
783  NEXT;
784  cur = q = CUR_PTR;
785  val = xmlStringCurrentChar(NULL, cur, &len);
786  while ((IS_CHAR(val)) && (val != '\'')) {
787  cur += len;
788  val = xmlStringCurrentChar(NULL, cur, &len);
789  }
790  if (!IS_CHAR(val)) {
791  ctxt->error = 1;
792  return(NULL);
793  } else {
794  if (ctxt->dict)
795  ret = (xmlChar *) xmlDictLookup(ctxt->dict, q, cur - q);
796  else
797  ret = xmlStrndup(q, cur - q);
798  }
799  cur += len;
800  CUR_PTR = cur;
801  } else {
802  /* XP_ERROR(XPATH_START_LITERAL_ERROR); */
803  ctxt->error = 1;
804  return(NULL);
805  }
806  return(ret);
807 }
808 #endif
809 
824 static xmlChar *
825 xmlPatScanName(xmlPatParserContextPtr ctxt) {
826  const xmlChar *q, *cur;
827  xmlChar *ret = NULL;
828  int val, len;
829 
830  SKIP_BLANKS;
831 
832  cur = q = CUR_PTR;
833  val = xmlStringCurrentChar(NULL, cur, &len);
834  if (!IS_LETTER(val) && (val != '_') && (val != ':'))
835  return(NULL);
836 
837  while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
838  (val == '.') || (val == '-') ||
839  (val == '_') ||
840  (IS_COMBINING(val)) ||
841  (IS_EXTENDER(val))) {
842  cur += len;
843  val = xmlStringCurrentChar(NULL, cur, &len);
844  }
845  if (ctxt->dict)
846  ret = (xmlChar *) xmlDictLookup(ctxt->dict, q, cur - q);
847  else
848  ret = xmlStrndup(q, cur - q);
849  CUR_PTR = cur;
850  return(ret);
851 }
852 
862 static xmlChar *
863 xmlPatScanNCName(xmlPatParserContextPtr ctxt) {
864  const xmlChar *q, *cur;
865  xmlChar *ret = NULL;
866  int val, len;
867 
868  SKIP_BLANKS;
869 
870  cur = q = CUR_PTR;
871  val = xmlStringCurrentChar(NULL, cur, &len);
872  if (!IS_LETTER(val) && (val != '_'))
873  return(NULL);
874 
875  while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
876  (val == '.') || (val == '-') ||
877  (val == '_') ||
878  (IS_COMBINING(val)) ||
879  (IS_EXTENDER(val))) {
880  cur += len;
881  val = xmlStringCurrentChar(NULL, cur, &len);
882  }
883  if (ctxt->dict)
884  ret = (xmlChar *) xmlDictLookup(ctxt->dict, q, cur - q);
885  else
886  ret = xmlStrndup(q, cur - q);
887  CUR_PTR = cur;
888  return(ret);
889 }
890 
891 #if 0
892 
902 static xmlChar *
903 xmlPatScanQName(xmlPatParserContextPtr ctxt, xmlChar **prefix) {
904  xmlChar *ret = NULL;
905 
906  *prefix = NULL;
907  ret = xmlPatScanNCName(ctxt);
908  if (CUR == ':') {
909  *prefix = ret;
910  NEXT;
911  ret = xmlPatScanNCName(ctxt);
912  }
913  return(ret);
914 }
915 #endif
916 
923 static void
924 xmlCompileAttributeTest(xmlPatParserContextPtr ctxt) {
925  xmlChar *token = NULL;
926  xmlChar *name = NULL;
927  xmlChar *URL = NULL;
928 
929  SKIP_BLANKS;
930  name = xmlPatScanNCName(ctxt);
931  if (name == NULL) {
932  if (CUR == '*') {
933  PUSH(XML_OP_ATTR, NULL, NULL);
934  NEXT;
935  } else {
936  ERROR(NULL, NULL, NULL,
937  "xmlCompileAttributeTest : Name expected\n");
938  ctxt->error = 1;
939  }
940  return;
941  }
942  if (CUR == ':') {
943  int i;
944  xmlChar *prefix = name;
945 
946  NEXT;
947 
948  if (IS_BLANK_CH(CUR)) {
949  ERROR5(NULL, NULL, NULL, "Invalid QName.\n", NULL);
950  XML_PAT_FREE_STRING(ctxt, prefix);
951  ctxt->error = 1;
952  goto error;
953  }
954  /*
955  * This is a namespace match
956  */
957  token = xmlPatScanName(ctxt);
958  if ((prefix[0] == 'x') &&
959  (prefix[1] == 'm') &&
960  (prefix[2] == 'l') &&
961  (prefix[3] == 0))
962  {
963  XML_PAT_COPY_NSNAME(ctxt, URL, XML_XML_NAMESPACE);
964  } else {
965  for (i = 0;i < ctxt->nb_namespaces;i++) {
966  if (xmlStrEqual(ctxt->namespaces[2 * i + 1], prefix)) {
967  XML_PAT_COPY_NSNAME(ctxt, URL, ctxt->namespaces[2 * i])
968  break;
969  }
970  }
971  if (i >= ctxt->nb_namespaces) {
972  ERROR5(NULL, NULL, NULL,
973  "xmlCompileAttributeTest : no namespace bound to prefix %s\n",
974  prefix);
975  XML_PAT_FREE_STRING(ctxt, prefix);
976  ctxt->error = 1;
977  goto error;
978  }
979  }
980  XML_PAT_FREE_STRING(ctxt, prefix);
981  if (token == NULL) {
982  if (CUR == '*') {
983  NEXT;
984  PUSH(XML_OP_ATTR, NULL, URL);
985  } else {
986  ERROR(NULL, NULL, NULL,
987  "xmlCompileAttributeTest : Name expected\n");
988  ctxt->error = 1;
989  goto error;
990  }
991  } else {
992  PUSH(XML_OP_ATTR, token, URL);
993  }
994  } else {
995  PUSH(XML_OP_ATTR, name, NULL);
996  }
997  return;
998 error:
999  if (URL != NULL)
1000  XML_PAT_FREE_STRING(ctxt, URL)
1001  if (token != NULL)
1002  XML_PAT_FREE_STRING(ctxt, token);
1003 }
1004 
1016 static void
1017 xmlCompileStepPattern(xmlPatParserContextPtr ctxt) {
1018  xmlChar *token = NULL;
1019  xmlChar *name = NULL;
1020  xmlChar *URL = NULL;
1021  int hasBlanks = 0;
1022 
1023  SKIP_BLANKS;
1024  if (CUR == '.') {
1025  /*
1026  * Context node.
1027  */
1028  NEXT;
1029  PUSH(XML_OP_ELEM, NULL, NULL);
1030  return;
1031  }
1032  if (CUR == '@') {
1033  /*
1034  * Attribute test.
1035  */
1036  if (XML_STREAM_XS_IDC_SEL(ctxt->comp)) {
1037  ERROR5(NULL, NULL, NULL,
1038  "Unexpected attribute axis in '%s'.\n", ctxt->base);
1039  ctxt->error = 1;
1040  return;
1041  }
1042  NEXT;
1043  xmlCompileAttributeTest(ctxt);
1044  if (ctxt->error != 0)
1045  goto error;
1046  return;
1047  }
1048  name = xmlPatScanNCName(ctxt);
1049  if (name == NULL) {
1050  if (CUR == '*') {
1051  NEXT;
1052  PUSH(XML_OP_ALL, NULL, NULL);
1053  return;
1054  } else {
1055  ERROR(NULL, NULL, NULL,
1056  "xmlCompileStepPattern : Name expected\n");
1057  ctxt->error = 1;
1058  return;
1059  }
1060  }
1061  if (IS_BLANK_CH(CUR)) {
1062  hasBlanks = 1;
1063  SKIP_BLANKS;
1064  }
1065  if (CUR == ':') {
1066  NEXT;
1067  if (CUR != ':') {
1068  xmlChar *prefix = name;
1069  int i;
1070 
1071  if (hasBlanks || IS_BLANK_CH(CUR)) {
1072  ERROR5(NULL, NULL, NULL, "Invalid QName.\n", NULL);
1073  ctxt->error = 1;
1074  goto error;
1075  }
1076  /*
1077  * This is a namespace match
1078  */
1079  token = xmlPatScanName(ctxt);
1080  if ((prefix[0] == 'x') &&
1081  (prefix[1] == 'm') &&
1082  (prefix[2] == 'l') &&
1083  (prefix[3] == 0))
1084  {
1085  XML_PAT_COPY_NSNAME(ctxt, URL, XML_XML_NAMESPACE)
1086  } else {
1087  for (i = 0;i < ctxt->nb_namespaces;i++) {
1088  if (xmlStrEqual(ctxt->namespaces[2 * i + 1], prefix)) {
1089  XML_PAT_COPY_NSNAME(ctxt, URL, ctxt->namespaces[2 * i])
1090  break;
1091  }
1092  }
1093  if (i >= ctxt->nb_namespaces) {
1094  ERROR5(NULL, NULL, NULL,
1095  "xmlCompileStepPattern : no namespace bound to prefix %s\n",
1096  prefix);
1097  ctxt->error = 1;
1098  goto error;
1099  }
1100  }
1101  XML_PAT_FREE_STRING(ctxt, prefix);
1102  name = NULL;
1103  if (token == NULL) {
1104  if (CUR == '*') {
1105  NEXT;
1106  PUSH(XML_OP_NS, URL, NULL);
1107  } else {
1108  ERROR(NULL, NULL, NULL,
1109  "xmlCompileStepPattern : Name expected\n");
1110  ctxt->error = 1;
1111  goto error;
1112  }
1113  } else {
1114  PUSH(XML_OP_ELEM, token, URL);
1115  }
1116  } else {
1117  NEXT;
1118  if (xmlStrEqual(name, (const xmlChar *) "child")) {
1119  XML_PAT_FREE_STRING(ctxt, name);
1120  name = xmlPatScanName(ctxt);
1121  if (name == NULL) {
1122  if (CUR == '*') {
1123  NEXT;
1124  PUSH(XML_OP_ALL, NULL, NULL);
1125  return;
1126  } else {
1127  ERROR(NULL, NULL, NULL,
1128  "xmlCompileStepPattern : QName expected\n");
1129  ctxt->error = 1;
1130  goto error;
1131  }
1132  }
1133  if (CUR == ':') {
1134  xmlChar *prefix = name;
1135  int i;
1136 
1137  NEXT;
1138  if (IS_BLANK_CH(CUR)) {
1139  ERROR5(NULL, NULL, NULL, "Invalid QName.\n", NULL);
1140  ctxt->error = 1;
1141  goto error;
1142  }
1143  /*
1144  * This is a namespace match
1145  */
1146  token = xmlPatScanName(ctxt);
1147  if ((prefix[0] == 'x') &&
1148  (prefix[1] == 'm') &&
1149  (prefix[2] == 'l') &&
1150  (prefix[3] == 0))
1151  {
1152  XML_PAT_COPY_NSNAME(ctxt, URL, XML_XML_NAMESPACE)
1153  } else {
1154  for (i = 0;i < ctxt->nb_namespaces;i++) {
1155  if (xmlStrEqual(ctxt->namespaces[2 * i + 1], prefix)) {
1156  XML_PAT_COPY_NSNAME(ctxt, URL, ctxt->namespaces[2 * i])
1157  break;
1158  }
1159  }
1160  if (i >= ctxt->nb_namespaces) {
1161  ERROR5(NULL, NULL, NULL,
1162  "xmlCompileStepPattern : no namespace bound "
1163  "to prefix %s\n", prefix);
1164  ctxt->error = 1;
1165  goto error;
1166  }
1167  }
1168  XML_PAT_FREE_STRING(ctxt, prefix);
1169  name = NULL;
1170  if (token == NULL) {
1171  if (CUR == '*') {
1172  NEXT;
1173  PUSH(XML_OP_NS, URL, NULL);
1174  } else {
1175  ERROR(NULL, NULL, NULL,
1176  "xmlCompileStepPattern : Name expected\n");
1177  ctxt->error = 1;
1178  goto error;
1179  }
1180  } else {
1181  PUSH(XML_OP_CHILD, token, URL);
1182  }
1183  } else
1184  PUSH(XML_OP_CHILD, name, NULL);
1185  return;
1186  } else if (xmlStrEqual(name, (const xmlChar *) "attribute")) {
1187  XML_PAT_FREE_STRING(ctxt, name)
1188  name = NULL;
1189  if (XML_STREAM_XS_IDC_SEL(ctxt->comp)) {
1190  ERROR5(NULL, NULL, NULL,
1191  "Unexpected attribute axis in '%s'.\n", ctxt->base);
1192  ctxt->error = 1;
1193  goto error;
1194  }
1195  xmlCompileAttributeTest(ctxt);
1196  if (ctxt->error != 0)
1197  goto error;
1198  return;
1199  } else {
1200  ERROR5(NULL, NULL, NULL,
1201  "The 'element' or 'attribute' axis is expected.\n", NULL);
1202  ctxt->error = 1;
1203  goto error;
1204  }
1205  }
1206  } else if (CUR == '*') {
1207  if (name != NULL) {
1208  ctxt->error = 1;
1209  goto error;
1210  }
1211  NEXT;
1212  PUSH(XML_OP_ALL, token, NULL);
1213  } else {
1214  PUSH(XML_OP_ELEM, name, NULL);
1215  }
1216  return;
1217 error:
1218  if (URL != NULL)
1219  XML_PAT_FREE_STRING(ctxt, URL)
1220  if (token != NULL)
1221  XML_PAT_FREE_STRING(ctxt, token)
1222  if (name != NULL)
1223  XML_PAT_FREE_STRING(ctxt, name)
1224 }
1225 
1235 static void
1236 xmlCompilePathPattern(xmlPatParserContextPtr ctxt) {
1237  SKIP_BLANKS;
1238  if (CUR == '/') {
1239  ctxt->comp->flags |= PAT_FROM_ROOT;
1240  } else if ((CUR == '.') || (ctxt->comp->flags & XML_PATTERN_NOTPATTERN)) {
1241  ctxt->comp->flags |= PAT_FROM_CUR;
1242  }
1243 
1244  if ((CUR == '/') && (NXT(1) == '/')) {
1245  PUSH(XML_OP_ANCESTOR, NULL, NULL);
1246  NEXT;
1247  NEXT;
1248  } else if ((CUR == '.') && (NXT(1) == '/') && (NXT(2) == '/')) {
1249  PUSH(XML_OP_ANCESTOR, NULL, NULL);
1250  NEXT;
1251  NEXT;
1252  NEXT;
1253  /* Check for incompleteness. */
1254  SKIP_BLANKS;
1255  if (CUR == 0) {
1256  ERROR5(NULL, NULL, NULL,
1257  "Incomplete expression '%s'.\n", ctxt->base);
1258  ctxt->error = 1;
1259  goto error;
1260  }
1261  }
1262  if (CUR == '@') {
1263  NEXT;
1264  xmlCompileAttributeTest(ctxt);
1265  SKIP_BLANKS;
1266  /* TODO: check for incompleteness */
1267  if (CUR != 0) {
1268  xmlCompileStepPattern(ctxt);
1269  if (ctxt->error != 0)
1270  goto error;
1271  }
1272  } else {
1273  if (CUR == '/') {
1274  PUSH(XML_OP_ROOT, NULL, NULL);
1275  NEXT;
1276  /* Check for incompleteness. */
1277  SKIP_BLANKS;
1278  if (CUR == 0) {
1279  ERROR5(NULL, NULL, NULL,
1280  "Incomplete expression '%s'.\n", ctxt->base);
1281  ctxt->error = 1;
1282  goto error;
1283  }
1284  }
1285  xmlCompileStepPattern(ctxt);
1286  if (ctxt->error != 0)
1287  goto error;
1288  SKIP_BLANKS;
1289  while (CUR == '/') {
1290  if (NXT(1) == '/') {
1291  PUSH(XML_OP_ANCESTOR, NULL, NULL);
1292  NEXT;
1293  NEXT;
1294  SKIP_BLANKS;
1295  xmlCompileStepPattern(ctxt);
1296  if (ctxt->error != 0)
1297  goto error;
1298  } else {
1299  PUSH(XML_OP_PARENT, NULL, NULL);
1300  NEXT;
1301  SKIP_BLANKS;
1302  if (CUR == 0) {
1303  ERROR5(NULL, NULL, NULL,
1304  "Incomplete expression '%s'.\n", ctxt->base);
1305  ctxt->error = 1;
1306  goto error;
1307  }
1308  xmlCompileStepPattern(ctxt);
1309  if (ctxt->error != 0)
1310  goto error;
1311  }
1312  }
1313  }
1314  if (CUR != 0) {
1315  ERROR5(NULL, NULL, NULL,
1316  "Failed to compile pattern %s\n", ctxt->base);
1317  ctxt->error = 1;
1318  }
1319 error:
1320  return;
1321 }
1322 
1332 static void
1333 xmlCompileIDCXPathPath(xmlPatParserContextPtr ctxt) {
1334  SKIP_BLANKS;
1335  if (CUR == '/') {
1336  ERROR5(NULL, NULL, NULL,
1337  "Unexpected selection of the document root in '%s'.\n",
1338  ctxt->base);
1339  goto error;
1340  }
1341  ctxt->comp->flags |= PAT_FROM_CUR;
1342 
1343  if (CUR == '.') {
1344  /* "." - "self::node()" */
1345  NEXT;
1346  SKIP_BLANKS;
1347  if (CUR == 0) {
1348  /*
1349  * Selection of the context node.
1350  */
1351  PUSH(XML_OP_ELEM, NULL, NULL);
1352  return;
1353  }
1354  if (CUR != '/') {
1355  /* TODO: A more meaningful error message. */
1356  ERROR5(NULL, NULL, NULL,
1357  "Unexpected token after '.' in '%s'.\n", ctxt->base);
1358  goto error;
1359  }
1360  /* "./" - "self::node()/" */
1361  NEXT;
1362  SKIP_BLANKS;
1363  if (CUR == '/') {
1364  if (IS_BLANK_CH(PEEKPREV(1))) {
1365  /*
1366  * Disallow "./ /"
1367  */
1368  ERROR5(NULL, NULL, NULL,
1369  "Unexpected '/' token in '%s'.\n", ctxt->base);
1370  goto error;
1371  }
1372  /* ".//" - "self:node()/descendant-or-self::node()/" */
1373  PUSH(XML_OP_ANCESTOR, NULL, NULL);
1374  NEXT;
1375  SKIP_BLANKS;
1376  }
1377  if (CUR == 0)
1378  goto error_unfinished;
1379  }
1380  /*
1381  * Process steps.
1382  */
1383  do {
1384  xmlCompileStepPattern(ctxt);
1385  if (ctxt->error != 0)
1386  goto error;
1387  SKIP_BLANKS;
1388  if (CUR != '/')
1389  break;
1390  PUSH(XML_OP_PARENT, NULL, NULL);
1391  NEXT;
1392  SKIP_BLANKS;
1393  if (CUR == '/') {
1394  /*
1395  * Disallow subsequent '//'.
1396  */
1397  ERROR5(NULL, NULL, NULL,
1398  "Unexpected subsequent '//' in '%s'.\n",
1399  ctxt->base);
1400  goto error;
1401  }
1402  if (CUR == 0)
1403  goto error_unfinished;
1404 
1405  } while (CUR != 0);
1406 
1407  if (CUR != 0) {
1408  ERROR5(NULL, NULL, NULL,
1409  "Failed to compile expression '%s'.\n", ctxt->base);
1410  ctxt->error = 1;
1411  }
1412  return;
1413 error:
1414  ctxt->error = 1;
1415  return;
1416 
1417 error_unfinished:
1418  ctxt->error = 1;
1419  ERROR5(NULL, NULL, NULL,
1420  "Unfinished expression '%s'.\n", ctxt->base);
1421  return;
1422 }
1423 
1424 /************************************************************************
1425  * *
1426  * The streaming code *
1427  * *
1428  ************************************************************************/
1429 
1430 #ifdef DEBUG_STREAMING
1431 static void
1432 xmlDebugStreamComp(xmlStreamCompPtr stream) {
1433  int i;
1434 
1435  if (stream == NULL) {
1436  printf("Stream: NULL\n");
1437  return;
1438  }
1439  printf("Stream: %d steps\n", stream->nbStep);
1440  for (i = 0;i < stream->nbStep;i++) {
1441  if (stream->steps[i].ns != NULL) {
1442  printf("{%s}", stream->steps[i].ns);
1443  }
1444  if (stream->steps[i].name == NULL) {
1445  printf("* ");
1446  } else {
1447  printf("%s ", stream->steps[i].name);
1448  }
1449  if (stream->steps[i].flags & XML_STREAM_STEP_ROOT)
1450  printf("root ");
1451  if (stream->steps[i].flags & XML_STREAM_STEP_DESC)
1452  printf("// ");
1453  if (stream->steps[i].flags & XML_STREAM_STEP_FINAL)
1454  printf("final ");
1455  printf("\n");
1456  }
1457 }
1458 static void
1459 xmlDebugStreamCtxt(xmlStreamCtxtPtr ctxt, int match) {
1460  int i;
1461 
1462  if (ctxt == NULL) {
1463  printf("Stream: NULL\n");
1464  return;
1465  }
1466  printf("Stream: level %d, %d states: ", ctxt->level, ctxt->nbState);
1467  if (match)
1468  printf("matches\n");
1469  else
1470  printf("\n");
1471  for (i = 0;i < ctxt->nbState;i++) {
1472  if (ctxt->states[2 * i] < 0)
1473  printf(" %d: free\n", i);
1474  else {
1475  printf(" %d: step %d, level %d", i, ctxt->states[2 * i],
1476  ctxt->states[(2 * i) + 1]);
1477  if (ctxt->comp->steps[ctxt->states[2 * i]].flags &
1478  XML_STREAM_STEP_DESC)
1479  printf(" //\n");
1480  else
1481  printf("\n");
1482  }
1483  }
1484 }
1485 #endif
1486 
1494 static xmlStreamCompPtr
1495 xmlNewStreamComp(int size) {
1496  xmlStreamCompPtr cur;
1497 
1498  if (size < 4)
1499  size = 4;
1500 
1501  cur = (xmlStreamCompPtr) xmlMalloc(sizeof(xmlStreamComp));
1502  if (cur == NULL) {
1503  ERROR(NULL, NULL, NULL,
1504  "xmlNewStreamComp: malloc failed\n");
1505  return(NULL);
1506  }
1507  memset(cur, 0, sizeof(xmlStreamComp));
1508  cur->steps = (xmlStreamStepPtr) xmlMalloc(size * sizeof(xmlStreamStep));
1509  if (cur->steps == NULL) {
1510  xmlFree(cur);
1511  ERROR(NULL, NULL, NULL,
1512  "xmlNewStreamComp: malloc failed\n");
1513  return(NULL);
1514  }
1515  cur->nbStep = 0;
1516  cur->maxStep = size;
1517  return(cur);
1518 }
1519 
1526 static void
1527 xmlFreeStreamComp(xmlStreamCompPtr comp) {
1528  if (comp != NULL) {
1529  if (comp->steps != NULL)
1530  xmlFree(comp->steps);
1531  if (comp->dict != NULL)
1532  xmlDictFree(comp->dict);
1533  xmlFree(comp);
1534  }
1535 }
1536 
1548 static int
1549 xmlStreamCompAddStep(xmlStreamCompPtr comp, const xmlChar *name,
1550  const xmlChar *ns, int nodeType, int flags) {
1551  xmlStreamStepPtr cur;
1552 
1553  if (comp->nbStep >= comp->maxStep) {
1554  cur = (xmlStreamStepPtr) xmlRealloc(comp->steps,
1555  comp->maxStep * 2 * sizeof(xmlStreamStep));
1556  if (cur == NULL) {
1557  ERROR(NULL, NULL, NULL,
1558  "xmlNewStreamComp: malloc failed\n");
1559  return(-1);
1560  }
1561  comp->steps = cur;
1562  comp->maxStep *= 2;
1563  }
1564  cur = &comp->steps[comp->nbStep++];
1565  cur->flags = flags;
1566  cur->name = name;
1567  cur->ns = ns;
1568  cur->nodeType = nodeType;
1569  return(comp->nbStep - 1);
1570 }
1571 
1580 static int
1581 xmlStreamCompile(xmlPatternPtr comp) {
1582  xmlStreamCompPtr stream;
1583  int i, s = 0, root = 0, flags = 0, prevs = -1;
1584  xmlStepOp step;
1585 
1586  if ((comp == NULL) || (comp->steps == NULL))
1587  return(-1);
1588  /*
1589  * special case for .
1590  */
1591  if ((comp->nbStep == 1) &&
1592  (comp->steps[0].op == XML_OP_ELEM) &&
1593  (comp->steps[0].value == NULL) &&
1594  (comp->steps[0].value2 == NULL)) {
1595  stream = xmlNewStreamComp(0);
1596  if (stream == NULL)
1597  return(-1);
1598  /* Note that the stream will have no steps in this case. */
1599  stream->flags |= XML_STREAM_FINAL_IS_ANY_NODE;
1600  comp->stream = stream;
1601  return(0);
1602  }
1603 
1604  stream = xmlNewStreamComp((comp->nbStep / 2) + 1);
1605  if (stream == NULL)
1606  return(-1);
1607  if (comp->dict != NULL) {
1608  stream->dict = comp->dict;
1609  xmlDictReference(stream->dict);
1610  }
1611 
1612  i = 0;
1613  if (comp->flags & PAT_FROM_ROOT)
1614  stream->flags |= XML_STREAM_FROM_ROOT;
1615 
1616  for (;i < comp->nbStep;i++) {
1617  step = comp->steps[i];
1618  switch (step.op) {
1619  case XML_OP_END:
1620  break;
1621  case XML_OP_ROOT:
1622  if (i != 0)
1623  goto error;
1624  root = 1;
1625  break;
1626  case XML_OP_NS:
1627  s = xmlStreamCompAddStep(stream, NULL, step.value,
1629  if (s < 0)
1630  goto error;
1631  prevs = s;
1632  flags = 0;
1633  break;
1634  case XML_OP_ATTR:
1635  flags |= XML_STREAM_STEP_ATTR;
1636  prevs = -1;
1637  s = xmlStreamCompAddStep(stream,
1638  step.value, step.value2, XML_ATTRIBUTE_NODE, flags);
1639  flags = 0;
1640  if (s < 0)
1641  goto error;
1642  break;
1643  case XML_OP_ELEM:
1644  if ((step.value == NULL) && (step.value2 == NULL)) {
1645  /*
1646  * We have a "." or "self::node()" here.
1647  * Eliminate redundant self::node() tests like in "/./."
1648  * or "//./"
1649  * The only case we won't eliminate is "//.", i.e. if
1650  * self::node() is the last node test and we had
1651  * continuation somewhere beforehand.
1652  */
1653  if ((comp->nbStep == i + 1) &&
1654  (flags & XML_STREAM_STEP_DESC)) {
1655  /*
1656  * Mark the special case where the expression resolves
1657  * to any type of node.
1658  */
1659  if (comp->nbStep == i + 1) {
1660  stream->flags |= XML_STREAM_FINAL_IS_ANY_NODE;
1661  }
1662  flags |= XML_STREAM_STEP_NODE;
1663  s = xmlStreamCompAddStep(stream, NULL, NULL,
1664  XML_STREAM_ANY_NODE, flags);
1665  if (s < 0)
1666  goto error;
1667  flags = 0;
1668  /*
1669  * If there was a previous step, mark it to be added to
1670  * the result node-set; this is needed since only
1671  * the last step will be marked as "final" and only
1672  * "final" nodes are added to the resulting set.
1673  */
1674  if (prevs != -1) {
1675  stream->steps[prevs].flags |= XML_STREAM_STEP_IN_SET;
1676  prevs = -1;
1677  }
1678  break;
1679 
1680  } else {
1681  /* Just skip this one. */
1682  continue;
1683  }
1684  }
1685  /* An element node. */
1686  s = xmlStreamCompAddStep(stream, step.value, step.value2,
1688  if (s < 0)
1689  goto error;
1690  prevs = s;
1691  flags = 0;
1692  break;
1693  case XML_OP_CHILD:
1694  /* An element node child. */
1695  s = xmlStreamCompAddStep(stream, step.value, step.value2,
1697  if (s < 0)
1698  goto error;
1699  prevs = s;
1700  flags = 0;
1701  break;
1702  case XML_OP_ALL:
1703  s = xmlStreamCompAddStep(stream, NULL, NULL,
1705  if (s < 0)
1706  goto error;
1707  prevs = s;
1708  flags = 0;
1709  break;
1710  case XML_OP_PARENT:
1711  break;
1712  case XML_OP_ANCESTOR:
1713  /* Skip redundant continuations. */
1714  if (flags & XML_STREAM_STEP_DESC)
1715  break;
1716  flags |= XML_STREAM_STEP_DESC;
1717  /*
1718  * Mark the expression as having "//".
1719  */
1720  if ((stream->flags & XML_STREAM_DESC) == 0)
1721  stream->flags |= XML_STREAM_DESC;
1722  break;
1723  }
1724  }
1725  if ((! root) && (comp->flags & XML_PATTERN_NOTPATTERN) == 0) {
1726  /*
1727  * If this should behave like a real pattern, we will mark
1728  * the first step as having "//", to be reentrant on every
1729  * tree level.
1730  */
1731  if ((stream->flags & XML_STREAM_DESC) == 0)
1732  stream->flags |= XML_STREAM_DESC;
1733 
1734  if (stream->nbStep > 0) {
1735  if ((stream->steps[0].flags & XML_STREAM_STEP_DESC) == 0)
1736  stream->steps[0].flags |= XML_STREAM_STEP_DESC;
1737  }
1738  }
1739  if (stream->nbStep <= s)
1740  goto error;
1741  stream->steps[s].flags |= XML_STREAM_STEP_FINAL;
1742  if (root)
1743  stream->steps[0].flags |= XML_STREAM_STEP_ROOT;
1744 #ifdef DEBUG_STREAMING
1745  xmlDebugStreamComp(stream);
1746 #endif
1747  comp->stream = stream;
1748  return(0);
1749 error:
1750  xmlFreeStreamComp(stream);
1751  return(0);
1752 }
1753 
1762 static xmlStreamCtxtPtr
1763 xmlNewStreamCtxt(xmlStreamCompPtr stream) {
1764  xmlStreamCtxtPtr cur;
1765 
1766  cur = (xmlStreamCtxtPtr) xmlMalloc(sizeof(xmlStreamCtxt));
1767  if (cur == NULL) {
1768  ERROR(NULL, NULL, NULL,
1769  "xmlNewStreamCtxt: malloc failed\n");
1770  return(NULL);
1771  }
1772  memset(cur, 0, sizeof(xmlStreamCtxt));
1773  cur->states = (int *) xmlMalloc(4 * 2 * sizeof(int));
1774  if (cur->states == NULL) {
1775  xmlFree(cur);
1776  ERROR(NULL, NULL, NULL,
1777  "xmlNewStreamCtxt: malloc failed\n");
1778  return(NULL);
1779  }
1780  cur->nbState = 0;
1781  cur->maxState = 4;
1782  cur->level = 0;
1783  cur->comp = stream;
1784  cur->blockLevel = -1;
1785  return(cur);
1786 }
1787 
1794 void
1795 xmlFreeStreamCtxt(xmlStreamCtxtPtr stream) {
1796  xmlStreamCtxtPtr next;
1797 
1798  while (stream != NULL) {
1799  next = stream->next;
1800  if (stream->states != NULL)
1801  xmlFree(stream->states);
1802  xmlFree(stream);
1803  stream = next;
1804  }
1805 }
1806 
1816 static int
1817 xmlStreamCtxtAddState(xmlStreamCtxtPtr comp, int idx, int level) {
1818  int i;
1819  for (i = 0;i < comp->nbState;i++) {
1820  if (comp->states[2 * i] < 0) {
1821  comp->states[2 * i] = idx;
1822  comp->states[2 * i + 1] = level;
1823  return(i);
1824  }
1825  }
1826  if (comp->nbState >= comp->maxState) {
1827  int *cur;
1828 
1829  cur = (int *) xmlRealloc(comp->states,
1830  comp->maxState * 4 * sizeof(int));
1831  if (cur == NULL) {
1832  ERROR(NULL, NULL, NULL,
1833  "xmlNewStreamCtxt: malloc failed\n");
1834  return(-1);
1835  }
1836  comp->states = cur;
1837  comp->maxState *= 2;
1838  }
1839  comp->states[2 * comp->nbState] = idx;
1840  comp->states[2 * comp->nbState++ + 1] = level;
1841  return(comp->nbState - 1);
1842 }
1843 
1860 static int
1861 xmlStreamPushInternal(xmlStreamCtxtPtr stream,
1862  const xmlChar *name, const xmlChar *ns,
1863  int nodeType) {
1864  int ret = 0, err = 0, final = 0, tmp, i, m, match, stepNr, desc;
1865  xmlStreamCompPtr comp;
1866  xmlStreamStep step;
1867 #ifdef DEBUG_STREAMING
1868  xmlStreamCtxtPtr orig = stream;
1869 #endif
1870 
1871  if ((stream == NULL) || (stream->nbState < 0))
1872  return(-1);
1873 
1874  while (stream != NULL) {
1875  comp = stream->comp;
1876 
1877  if ((nodeType == XML_ELEMENT_NODE) &&
1878  (name == NULL) && (ns == NULL)) {
1879  /* We have a document node here (or a reset). */
1880  stream->nbState = 0;
1881  stream->level = 0;
1882  stream->blockLevel = -1;
1883  if (comp->flags & XML_STREAM_FROM_ROOT) {
1884  if (comp->nbStep == 0) {
1885  /* TODO: We have a "/." here? */
1886  ret = 1;
1887  } else {
1888  if ((comp->nbStep == 1) &&
1889  (comp->steps[0].nodeType == XML_STREAM_ANY_NODE) &&
1890  (comp->steps[0].flags & XML_STREAM_STEP_DESC))
1891  {
1892  /*
1893  * In the case of "//." the document node will match
1894  * as well.
1895  */
1896  ret = 1;
1897  } else if (comp->steps[0].flags & XML_STREAM_STEP_ROOT) {
1898  /* TODO: Do we need this ? */
1899  tmp = xmlStreamCtxtAddState(stream, 0, 0);
1900  if (tmp < 0)
1901  err++;
1902  }
1903  }
1904  }
1905  stream = stream->next;
1906  continue; /* while */
1907  }
1908 
1909  /*
1910  * Fast check for ".".
1911  */
1912  if (comp->nbStep == 0) {
1913  /*
1914  * / and . are handled at the XPath node set creation
1915  * level by checking min depth
1916  */
1917  if (stream->flags & XML_PATTERN_XPATH) {
1918  stream = stream->next;
1919  continue; /* while */
1920  }
1921  /*
1922  * For non-pattern like evaluation like XML Schema IDCs
1923  * or traditional XPath expressions, this will match if
1924  * we are at the first level only, otherwise on every level.
1925  */
1926  if ((nodeType != XML_ATTRIBUTE_NODE) &&
1927  (((stream->flags & XML_PATTERN_NOTPATTERN) == 0) ||
1928  (stream->level == 0))) {
1929  ret = 1;
1930  }
1931  stream->level++;
1932  goto stream_next;
1933  }
1934  if (stream->blockLevel != -1) {
1935  /*
1936  * Skip blocked expressions.
1937  */
1938  stream->level++;
1939  goto stream_next;
1940  }
1941 
1942  if ((nodeType != XML_ELEMENT_NODE) &&
1943  (nodeType != XML_ATTRIBUTE_NODE) &&
1944  ((comp->flags & XML_STREAM_FINAL_IS_ANY_NODE) == 0)) {
1945  /*
1946  * No need to process nodes of other types if we don't
1947  * resolve to those types.
1948  * TODO: Do we need to block the context here?
1949  */
1950  stream->level++;
1951  goto stream_next;
1952  }
1953 
1954  /*
1955  * Check evolution of existing states
1956  */
1957  i = 0;
1958  m = stream->nbState;
1959  while (i < m) {
1960  if ((comp->flags & XML_STREAM_DESC) == 0) {
1961  /*
1962  * If there is no "//", then only the last
1963  * added state is of interest.
1964  */
1965  stepNr = stream->states[2 * (stream->nbState -1)];
1966  /*
1967  * TODO: Security check, should not happen, remove it.
1968  */
1969  if (stream->states[(2 * (stream->nbState -1)) + 1] <
1970  stream->level) {
1971  return (-1);
1972  }
1973  desc = 0;
1974  /* loop-stopper */
1975  i = m;
1976  } else {
1977  /*
1978  * If there are "//", then we need to process every "//"
1979  * occurring in the states, plus any other state for this
1980  * level.
1981  */
1982  stepNr = stream->states[2 * i];
1983 
1984  /* TODO: should not happen anymore: dead states */
1985  if (stepNr < 0)
1986  goto next_state;
1987 
1988  tmp = stream->states[(2 * i) + 1];
1989 
1990  /* skip new states just added */
1991  if (tmp > stream->level)
1992  goto next_state;
1993 
1994  /* skip states at ancestor levels, except if "//" */
1995  desc = comp->steps[stepNr].flags & XML_STREAM_STEP_DESC;
1996  if ((tmp < stream->level) && (!desc))
1997  goto next_state;
1998  }
1999  /*
2000  * Check for correct node-type.
2001  */
2002  step = comp->steps[stepNr];
2003  if (step.nodeType != nodeType) {
2004  if (step.nodeType == XML_ATTRIBUTE_NODE) {
2005  /*
2006  * Block this expression for deeper evaluation.
2007  */
2008  if ((comp->flags & XML_STREAM_DESC) == 0)
2009  stream->blockLevel = stream->level +1;
2010  goto next_state;
2011  } else if (step.nodeType != XML_STREAM_ANY_NODE)
2012  goto next_state;
2013  }
2014  /*
2015  * Compare local/namespace-name.
2016  */
2017  match = 0;
2018  if (step.nodeType == XML_STREAM_ANY_NODE) {
2019  match = 1;
2020  } else if (step.name == NULL) {
2021  if (step.ns == NULL) {
2022  /*
2023  * This lets through all elements/attributes.
2024  */
2025  match = 1;
2026  } else if (ns != NULL)
2027  match = xmlStrEqual(step.ns, ns);
2028  } else if (((step.ns != NULL) == (ns != NULL)) &&
2029  (name != NULL) &&
2030  (step.name[0] == name[0]) &&
2031  xmlStrEqual(step.name, name) &&
2032  ((step.ns == ns) || xmlStrEqual(step.ns, ns)))
2033  {
2034  match = 1;
2035  }
2036 #if 0
2037 /*
2038 * TODO: Pointer comparison won't work, since not guaranteed that the given
2039 * values are in the same dict; especially if it's the namespace name,
2040 * normally coming from ns->href. We need a namespace dict mechanism !
2041 */
2042  } else if (comp->dict) {
2043  if (step.name == NULL) {
2044  if (step.ns == NULL)
2045  match = 1;
2046  else
2047  match = (step.ns == ns);
2048  } else {
2049  match = ((step.name == name) && (step.ns == ns));
2050  }
2051 #endif /* if 0 ------------------------------------------------------- */
2052  if (match) {
2053  final = step.flags & XML_STREAM_STEP_FINAL;
2054  if (desc) {
2055  if (final) {
2056  ret = 1;
2057  } else {
2058  /* descending match create a new state */
2059  xmlStreamCtxtAddState(stream, stepNr + 1,
2060  stream->level + 1);
2061  }
2062  } else {
2063  if (final) {
2064  ret = 1;
2065  } else {
2066  xmlStreamCtxtAddState(stream, stepNr + 1,
2067  stream->level + 1);
2068  }
2069  }
2070  if ((ret != 1) && (step.flags & XML_STREAM_STEP_IN_SET)) {
2071  /*
2072  * Check if we have a special case like "foo/bar//.", where
2073  * "foo" is selected as well.
2074  */
2075  ret = 1;
2076  }
2077  }
2078  if (((comp->flags & XML_STREAM_DESC) == 0) &&
2079  ((! match) || final)) {
2080  /*
2081  * Mark this expression as blocked for any evaluation at
2082  * deeper levels. Note that this includes "/foo"
2083  * expressions if the *pattern* behaviour is used.
2084  */
2085  stream->blockLevel = stream->level +1;
2086  }
2087 next_state:
2088  i++;
2089  }
2090 
2091  stream->level++;
2092 
2093  /*
2094  * Re/enter the expression.
2095  * Don't reenter if it's an absolute expression like "/foo",
2096  * except "//foo".
2097  */
2098  step = comp->steps[0];
2099  if (step.flags & XML_STREAM_STEP_ROOT)
2100  goto stream_next;
2101 
2102  desc = step.flags & XML_STREAM_STEP_DESC;
2103  if (stream->flags & XML_PATTERN_NOTPATTERN) {
2104  /*
2105  * Re/enter the expression if it is a "descendant" one,
2106  * or if we are at the 1st level of evaluation.
2107  */
2108 
2109  if (stream->level == 1) {
2110  if (XML_STREAM_XS_IDC(stream)) {
2111  /*
2112  * XS-IDC: The missing "self::node()" will always
2113  * match the first given node.
2114  */
2115  goto stream_next;
2116  } else
2117  goto compare;
2118  }
2119  /*
2120  * A "//" is always reentrant.
2121  */
2122  if (desc)
2123  goto compare;
2124 
2125  /*
2126  * XS-IDC: Process the 2nd level, since the missing
2127  * "self::node()" is responsible for the 2nd level being
2128  * the real start level.
2129  */
2130  if ((stream->level == 2) && XML_STREAM_XS_IDC(stream))
2131  goto compare;
2132 
2133  goto stream_next;
2134  }
2135 
2136 compare:
2137  /*
2138  * Check expected node-type.
2139  */
2140  if (step.nodeType != nodeType) {
2141  if (nodeType == XML_ATTRIBUTE_NODE)
2142  goto stream_next;
2143  else if (step.nodeType != XML_STREAM_ANY_NODE)
2144  goto stream_next;
2145  }
2146  /*
2147  * Compare local/namespace-name.
2148  */
2149  match = 0;
2150  if (step.nodeType == XML_STREAM_ANY_NODE) {
2151  match = 1;
2152  } else if (step.name == NULL) {
2153  if (step.ns == NULL) {
2154  /*
2155  * This lets through all elements/attributes.
2156  */
2157  match = 1;
2158  } else if (ns != NULL)
2159  match = xmlStrEqual(step.ns, ns);
2160  } else if (((step.ns != NULL) == (ns != NULL)) &&
2161  (name != NULL) &&
2162  (step.name[0] == name[0]) &&
2163  xmlStrEqual(step.name, name) &&
2164  ((step.ns == ns) || xmlStrEqual(step.ns, ns)))
2165  {
2166  match = 1;
2167  }
2168  final = step.flags & XML_STREAM_STEP_FINAL;
2169  if (match) {
2170  if (final)
2171  ret = 1;
2172  else
2173  xmlStreamCtxtAddState(stream, 1, stream->level);
2174  if ((ret != 1) && (step.flags & XML_STREAM_STEP_IN_SET)) {
2175  /*
2176  * Check if we have a special case like "foo//.", where
2177  * "foo" is selected as well.
2178  */
2179  ret = 1;
2180  }
2181  }
2182  if (((comp->flags & XML_STREAM_DESC) == 0) &&
2183  ((! match) || final)) {
2184  /*
2185  * Mark this expression as blocked for any evaluation at
2186  * deeper levels.
2187  */
2188  stream->blockLevel = stream->level;
2189  }
2190 
2191 stream_next:
2192  stream = stream->next;
2193  } /* while stream != NULL */
2194 
2195  if (err > 0)
2196  ret = -1;
2197 #ifdef DEBUG_STREAMING
2198  xmlDebugStreamCtxt(orig, ret);
2199 #endif
2200  return(ret);
2201 }
2202 
2219 int
2220 xmlStreamPush(xmlStreamCtxtPtr stream,
2221  const xmlChar *name, const xmlChar *ns) {
2222  return (xmlStreamPushInternal(stream, name, ns, (int) XML_ELEMENT_NODE));
2223 }
2224 
2244 int
2245 xmlStreamPushNode(xmlStreamCtxtPtr stream,
2246  const xmlChar *name, const xmlChar *ns,
2247  int nodeType)
2248 {
2249  return (xmlStreamPushInternal(stream, name, ns,
2250  nodeType));
2251 }
2252 
2269 int
2270 xmlStreamPushAttr(xmlStreamCtxtPtr stream,
2271  const xmlChar *name, const xmlChar *ns) {
2272  return (xmlStreamPushInternal(stream, name, ns, (int) XML_ATTRIBUTE_NODE));
2273 }
2274 
2283 int
2284 xmlStreamPop(xmlStreamCtxtPtr stream) {
2285  int i, lev;
2286 
2287  if (stream == NULL)
2288  return(-1);
2289  while (stream != NULL) {
2290  /*
2291  * Reset block-level.
2292  */
2293  if (stream->blockLevel == stream->level)
2294  stream->blockLevel = -1;
2295 
2296  /*
2297  * stream->level can be zero when XML_FINAL_IS_ANY_NODE is set
2298  * (see the thread at
2299  * http://mail.gnome.org/archives/xslt/2008-July/msg00027.html)
2300  */
2301  if (stream->level)
2302  stream->level--;
2303  /*
2304  * Check evolution of existing states
2305  */
2306  for (i = stream->nbState -1; i >= 0; i--) {
2307  /* discard obsoleted states */
2308  lev = stream->states[(2 * i) + 1];
2309  if (lev > stream->level)
2310  stream->nbState--;
2311  if (lev <= stream->level)
2312  break;
2313  }
2314  stream = stream->next;
2315  }
2316  return(0);
2317 }
2318 
2331 int
2332 xmlStreamWantsAnyNode(xmlStreamCtxtPtr streamCtxt)
2333 {
2334  if (streamCtxt == NULL)
2335  return(-1);
2336  while (streamCtxt != NULL) {
2337  if (streamCtxt->comp->flags & XML_STREAM_FINAL_IS_ANY_NODE)
2338  return(1);
2339  streamCtxt = streamCtxt->next;
2340  }
2341  return(0);
2342 }
2343 
2344 /************************************************************************
2345  * *
2346  * The public interfaces *
2347  * *
2348  ************************************************************************/
2349 
2361 xmlPatternPtr
2362 xmlPatterncompile(const xmlChar *pattern, xmlDict *dict, int flags,
2363  const xmlChar **namespaces) {
2364  xmlPatternPtr ret = NULL, cur;
2365  xmlPatParserContextPtr ctxt = NULL;
2366  const xmlChar *or, *start;
2367  xmlChar *tmp = NULL;
2368  int type = 0;
2369  int streamable = 1;
2370 
2371  if (pattern == NULL)
2372  return(NULL);
2373 
2374  start = pattern;
2375  or = start;
2376  while (*or != 0) {
2377  tmp = NULL;
2378  while ((*or != 0) && (*or != '|')) or++;
2379  if (*or == 0)
2380  ctxt = xmlNewPatParserContext(start, dict, namespaces);
2381  else {
2382  tmp = xmlStrndup(start, or - start);
2383  if (tmp != NULL) {
2384  ctxt = xmlNewPatParserContext(tmp, dict, namespaces);
2385  }
2386  or++;
2387  }
2388  if (ctxt == NULL) goto error;
2389  cur = xmlNewPattern();
2390  if (cur == NULL) goto error;
2391  /*
2392  * Assign string dict.
2393  */
2394  if (dict) {
2395  cur->dict = dict;
2396  xmlDictReference(dict);
2397  }
2398  if (ret == NULL)
2399  ret = cur;
2400  else {
2401  cur->next = ret->next;
2402  ret->next = cur;
2403  }
2404  cur->flags = flags;
2405  ctxt->comp = cur;
2406 
2407  if (XML_STREAM_XS_IDC(cur))
2408  xmlCompileIDCXPathPath(ctxt);
2409  else
2410  xmlCompilePathPattern(ctxt);
2411  if (ctxt->error != 0)
2412  goto error;
2413  xmlFreePatParserContext(ctxt);
2414  ctxt = NULL;
2415 
2416 
2417  if (streamable) {
2418  if (type == 0) {
2419  type = cur->flags & (PAT_FROM_ROOT | PAT_FROM_CUR);
2420  } else if (type == PAT_FROM_ROOT) {
2421  if (cur->flags & PAT_FROM_CUR)
2422  streamable = 0;
2423  } else if (type == PAT_FROM_CUR) {
2424  if (cur->flags & PAT_FROM_ROOT)
2425  streamable = 0;
2426  }
2427  }
2428  if (streamable)
2429  xmlStreamCompile(cur);
2430  if (xmlReversePattern(cur) < 0)
2431  goto error;
2432  if (tmp != NULL) {
2433  xmlFree(tmp);
2434  tmp = NULL;
2435  }
2436  start = or;
2437  }
2438  if (streamable == 0) {
2439  cur = ret;
2440  while (cur != NULL) {
2441  if (cur->stream != NULL) {
2442  xmlFreeStreamComp(cur->stream);
2443  cur->stream = NULL;
2444  }
2445  cur = cur->next;
2446  }
2447  }
2448 
2449  return(ret);
2450 error:
2451  if (ctxt != NULL) xmlFreePatParserContext(ctxt);
2452  if (ret != NULL) xmlFreePattern(ret);
2453  if (tmp != NULL) xmlFree(tmp);
2454  return(NULL);
2455 }
2456 
2466 int
2467 xmlPatternMatch(xmlPatternPtr comp, xmlNodePtr node)
2468 {
2469  int ret = 0;
2470 
2471  if ((comp == NULL) || (node == NULL))
2472  return(-1);
2473 
2474  while (comp != NULL) {
2475  ret = xmlPatMatch(comp, node);
2476  if (ret != 0)
2477  return(ret);
2478  comp = comp->next;
2479  }
2480  return(ret);
2481 }
2482 
2492 xmlStreamCtxtPtr
2493 xmlPatternGetStreamCtxt(xmlPatternPtr comp)
2494 {
2495  xmlStreamCtxtPtr ret = NULL, cur;
2496 
2497  if ((comp == NULL) || (comp->stream == NULL))
2498  return(NULL);
2499 
2500  while (comp != NULL) {
2501  if (comp->stream == NULL)
2502  goto failed;
2503  cur = xmlNewStreamCtxt(comp->stream);
2504  if (cur == NULL)
2505  goto failed;
2506  if (ret == NULL)
2507  ret = cur;
2508  else {
2509  cur->next = ret->next;
2510  ret->next = cur;
2511  }
2512  cur->flags = comp->flags;
2513  comp = comp->next;
2514  }
2515  return(ret);
2516 failed:
2517  xmlFreeStreamCtxt(ret);
2518  return(NULL);
2519 }
2520 
2530 int
2531 xmlPatternStreamable(xmlPatternPtr comp) {
2532  if (comp == NULL)
2533  return(-1);
2534  while (comp != NULL) {
2535  if (comp->stream == NULL)
2536  return(0);
2537  comp = comp->next;
2538  }
2539  return(1);
2540 }
2541 
2551 int
2552 xmlPatternMaxDepth(xmlPatternPtr comp) {
2553  int ret = 0, i;
2554  if (comp == NULL)
2555  return(-1);
2556  while (comp != NULL) {
2557  if (comp->stream == NULL)
2558  return(-1);
2559  for (i = 0;i < comp->stream->nbStep;i++)
2560  if (comp->stream->steps[i].flags & XML_STREAM_STEP_DESC)
2561  return(-2);
2562  if (comp->stream->nbStep > ret)
2563  ret = comp->stream->nbStep;
2564  comp = comp->next;
2565  }
2566  return(ret);
2567 }
2568 
2579 int
2580 xmlPatternMinDepth(xmlPatternPtr comp) {
2581  int ret = 12345678;
2582  if (comp == NULL)
2583  return(-1);
2584  while (comp != NULL) {
2585  if (comp->stream == NULL)
2586  return(-1);
2587  if (comp->stream->nbStep < ret)
2588  ret = comp->stream->nbStep;
2589  if (ret == 0)
2590  return(0);
2591  comp = comp->next;
2592  }
2593  return(ret);
2594 }
2595 
2604 int
2605 xmlPatternFromRoot(xmlPatternPtr comp) {
2606  if (comp == NULL)
2607  return(-1);
2608  while (comp != NULL) {
2609  if (comp->stream == NULL)
2610  return(-1);
2611  if (comp->flags & PAT_FROM_ROOT)
2612  return(1);
2613  comp = comp->next;
2614  }
2615  return(0);
2616 
2617 }
2618 
2619 #define bottom_pattern
2620 #include "elfgcchack.h"
2621 #endif /* LIBXML_PATTERN_ENABLED */
GLint level
Definition: gl.h:1546
XMLPUBFUN int XMLCALL xmlDictReference(xmlDictPtr dict)
Definition: dict.c:645
#define IS_EXTENDER(c)
#define NXT(val)
Definition: pattern.c:1263
#define error(str)
Definition: mkdosfs.c:1605
const xmlChar * name
Definition: tree.h:492
Definition: match.c:28
XMLPUBFUN xmlChar *XMLCALL xmlStrndup(const xmlChar *cur, int len)
Definition: xmlstring.c:41
#define ERROR(name)
Definition: error_private.h:53
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
#define CUR
Definition: pattern.c:1261
XMLPUBFUN int XMLCALL xmlStringCurrentChar(xmlParserCtxtPtr ctxt, const xmlChar *cur, int *len)
const GLfloat * m
Definition: glext.h:10848
#define PUSH(op, val, val2, novar)
Definition: pattern.c:1273
struct node node
#define IS_COMBINING(c)
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
GLuint base
Definition: 3dtext.c:35
_Check_return_opt_ _CRTIMP int __cdecl fprintf(_Inout_ FILE *_File, _In_z_ _Printf_format_string_ const char *_Format,...)
static const WCHAR desc[]
Definition: protectdata.c:36
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat token
Definition: glfuncs.h:210
#define IS_BLANK_CH(c)
static size_t elem
Definition: string.c:68
#define IS_CHAR(c)
unsigned int idx
Definition: utils.c:41
static DWORD DWORD DWORD DWORD * steps
Definition: cursoricon.c:1638
smooth NULL
Definition: ftsmooth.c:416
#define XML_XML_NAMESPACE
Definition: tree.h:140
struct match match
Definition: match.c:33
Definition: dict.c:116
XMLPUBVAR xmlReallocFunc xmlRealloc
Definition: globals.h:249
GLuint GLfloat * val
Definition: glext.h:7180
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
void restart(int argc, const char *argv[])
Definition: cmds.c:2115
GLsizeiptr size
Definition: glext.h:5919
UINT op
Definition: effect.c:224
XMLPUBVAR xmlFreeFunc xmlFree
Definition: globals.h:250
XMLPUBFUN const xmlChar *XMLCALL xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len)
Definition: dict.c:865
GLdouble GLdouble GLdouble GLdouble q
Definition: gl.h:2063
#define CUR_PTR
Definition: pattern.c:1264
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
GLbitfield flags
Definition: glext.h:7161
Definition: tree.h:489
int ret
#define ATTRIBUTE_UNUSED
Definition: win32config.h:132
Definition: mxnamespace.c:44
Definition: parse.h:22
GLuint GLuint stream
Definition: glext.h:7522
unsigned char xmlChar
Definition: xmlstring.h:28
XMLPUBFUN void XMLCALL xmlDictFree(xmlDictPtr dict)
Definition: dict.c:800
GLenum GLsizei len
Definition: glext.h:6722
GLdouble s
Definition: gl.h:2039
#define err(...)
#define LIBXML_DOCB_ENABLED
Definition: xmlversion.h:238
GLsizei const GLfloat * value
Definition: glext.h:6069
xmlElementType type
Definition: tree.h:491
#define IS_LETTER(c)
static unsigned __int64 next
Definition: rand_nt.c:6
struct _xmlNode * next
Definition: tree.h:496
static calc_node_t temp
Definition: rpn_ieee.c:38
GLuint start
Definition: gl.h:1545
_In_ fcb _In_ chunk _In_ uint64_t _In_ uint64_t _In_ bool _In_opt_ void _In_opt_ PIRP _In_ LIST_ENTRY * rollback
Definition: btrfs_drv.h:1357
XMLPUBVAR xmlMallocFunc xmlMalloc
Definition: globals.h:247
#define IS_DIGIT(c)
Definition: name.c:38
#define compare
FILE * stderr
XMLPUBFUN int XMLCALL xmlStrEqual(const xmlChar *str1, const xmlChar *str2)
Definition: xmlstring.c:157
#define NEXT
Definition: pattern.c:1270
#define memset(x, y, z)
Definition: compat.h:39
#define SKIP_BLANKS
Definition: pattern.c:1266
GLubyte * pattern
Definition: glext.h:7787
#define printf
Definition: config.h:203
Definition: dlist.c:348
GLuint const GLchar * name
Definition: glext.h:6031