ReactOS  0.4.14-dev-114-gc8cbd56
pattern.c
Go to the documentation of this file.
1 /*
2  * pattern.c: Implemetation of the template match compilation and lookup
3  *
4  * Reference:
5  * http://www.w3.org/TR/1999/REC-xslt-19991116
6  *
7  * See Copyright for the status of this software.
8  *
9  * daniel@veillard.com
10  */
11 
12 /*
13  * TODO: handle pathological cases like *[*[@a="b"]]
14  * TODO: detect [number] at compilation, optimize accordingly
15  */
16 
17 #include "precomp.h"
18 
19 #ifdef WITH_XSLT_DEBUG
20 #define WITH_XSLT_DEBUG_PATTERN
21 #endif
22 
23 /*
24  * Types are private:
25  */
26 
27 typedef enum {
43 } xsltOp;
44 
45 typedef enum {
48 } xsltAxis;
49 
53  int step;
55 };
56 
60  int nbstates;
61  int maxstates;
63 };
64 
65 typedef struct _xsltStepOp xsltStepOp;
67 struct _xsltStepOp {
72  xmlXPathCompExprPtr comp;
73  /*
74  * Optimisations for count
75  */
78  int lenExtra;
79 };
80 
82  struct _xsltCompMatch *next; /* siblings in the name hash */
83  float priority; /* the priority */
84  const xmlChar *pattern; /* the pattern */
85  const xmlChar *mode; /* the mode */
86  const xmlChar *modeURI; /* the mode URI */
87  xsltTemplatePtr template; /* the associated template */
88  xmlNodePtr node; /* the containing element */
89 
90  int direct;
91  /* TODO fix the statically allocated size steps[] */
92  int nbStep;
93  int maxStep;
94  xmlNsPtr *nsList; /* the namespaces in scope */
95  int nsNr; /* the number of namespaces in scope */
96  xsltStepOpPtr steps; /* ops for computation */
97  int novar; /* doesn't contain variables */
98 };
99 
103  xsltStylesheetPtr style; /* the stylesheet */
104  xsltTransformContextPtr ctxt; /* the transformation or NULL */
105  const xmlChar *cur; /* the current char being parsed */
106  const xmlChar *base; /* the full expression */
107  xmlDocPtr doc; /* the source document */
108  xmlNodePtr elem; /* the source element */
109  int error; /* error code */
110  xsltCompMatchPtr comp; /* the result */
111 };
112 
113 /************************************************************************
114  * *
115  * Type functions *
116  * *
117  ************************************************************************/
118 
126 static xsltCompMatchPtr
128  xsltCompMatchPtr cur;
129 
130  cur = (xsltCompMatchPtr) xmlMalloc(sizeof(xsltCompMatch));
131  if (cur == NULL) {
133  "xsltNewCompMatch : out of memory error\n");
134  return(NULL);
135  }
136  memset(cur, 0, sizeof(xsltCompMatch));
137  cur->maxStep = 10;
138  cur->nbStep = 0;
139  cur-> steps = (xsltStepOpPtr) xmlMalloc(sizeof(xsltStepOp) *
140  cur->maxStep);
141  if (cur->steps == NULL) {
143  "xsltNewCompMatch : out of memory error\n");
144  xmlFree(cur);
145  return(NULL);
146  }
147  cur->nsNr = 0;
148  cur->nsList = NULL;
149  cur->direct = 0;
150  return(cur);
151 }
152 
159 static void
162  int i;
163 
164  if (comp == NULL)
165  return;
166  if (comp->pattern != NULL)
167  xmlFree((xmlChar *)comp->pattern);
168  if (comp->nsList != NULL)
169  xmlFree(comp->nsList);
170  for (i = 0;i < comp->nbStep;i++) {
171  op = &comp->steps[i];
172  if (op->value != NULL)
173  xmlFree(op->value);
174  if (op->value2 != NULL)
175  xmlFree(op->value2);
176  if (op->value3 != NULL)
177  xmlFree(op->value3);
178  if (op->comp != NULL)
179  xmlXPathFreeCompExpr(op->comp);
180  }
181  xmlFree(comp->steps);
182  memset(comp, -1, sizeof(xsltCompMatch));
183  xmlFree(comp);
184 }
185 
192 void
194  xsltCompMatchPtr cur;
195 
196  while (comp != NULL) {
197  cur = comp;
198  comp = comp->next;
199  xsltFreeCompMatch(cur);
200  }
201 }
202 
203 static void
205  const xmlChar *name ATTRIBUTE_UNUSED) {
207 }
208 
218 void xsltNormalizeCompSteps(void *payload,
219  void *data, const xmlChar *name ATTRIBUTE_UNUSED) {
220  xsltCompMatchPtr comp = payload;
222  int ix;
223 
224  for (ix = 0; ix < comp->nbStep; ix++) {
225  comp->steps[ix].previousExtra += style->extrasNr;
226  comp->steps[ix].indexExtra += style->extrasNr;
227  comp->steps[ix].lenExtra += style->extrasNr;
228  }
229 }
230 
243 
245  if (cur == NULL) {
247  "xsltNewParserContext : malloc failed\n");
248  return(NULL);
249  }
250  memset(cur, 0, sizeof(xsltParserContext));
251  cur->style = style;
252  cur->ctxt = ctxt;
253  return(cur);
254 }
255 
262 static void
264  if (ctxt == NULL)
265  return;
266  memset(ctxt, -1, sizeof(xsltParserContext));
267  xmlFree(ctxt);
268 }
269 
282 static int
284  xsltOp op, xmlChar * value, xmlChar * value2, int novar)
285 {
286  if (comp->nbStep >= comp->maxStep) {
287  xsltStepOpPtr tmp;
288 
289  tmp = (xsltStepOpPtr) xmlRealloc(comp->steps, comp->maxStep * 2 *
290  sizeof(xsltStepOp));
291  if (tmp == NULL) {
293  "xsltCompMatchAdd: memory re-allocation failure.\n");
294  if (ctxt->style != NULL)
295  ctxt->style->errors++;
296  if (value)
297  xmlFree(value);
298  if (value2)
299  xmlFree(value2);
300  return (-1);
301  }
302  comp->maxStep *= 2;
303  comp->steps = tmp;
304  }
305  comp->steps[comp->nbStep].op = op;
306  comp->steps[comp->nbStep].value = value;
307  comp->steps[comp->nbStep].value2 = value2;
308  comp->steps[comp->nbStep].value3 = NULL;
309  comp->steps[comp->nbStep].comp = NULL;
310  if (ctxt->ctxt != NULL) {
311  comp->steps[comp->nbStep].previousExtra =
313  comp->steps[comp->nbStep].indexExtra =
315  comp->steps[comp->nbStep].lenExtra =
317  } else {
318  comp->steps[comp->nbStep].previousExtra =
319  xsltAllocateExtra(ctxt->style);
320  comp->steps[comp->nbStep].indexExtra =
321  xsltAllocateExtra(ctxt->style);
322  comp->steps[comp->nbStep].lenExtra =
323  xsltAllocateExtra(ctxt->style);
324  }
325  if (op == XSLT_OP_PREDICATE) {
326  xmlXPathContextPtr xctxt;
327 
328  if (ctxt->style != NULL)
329  xctxt = xmlXPathNewContext(ctxt->style->doc);
330  else
331  xctxt = xmlXPathNewContext(NULL);
332 #ifdef XML_XPATH_NOVAR
333  if (novar != 0)
334  xctxt->flags = XML_XPATH_NOVAR;
335 #endif
336  if (ctxt->style != NULL)
337  xctxt->dict = ctxt->style->dict;
338  comp->steps[comp->nbStep].comp = xmlXPathCtxtCompile(xctxt, value);
339  xmlXPathFreeContext(xctxt);
340  if (comp->steps[comp->nbStep].comp == NULL) {
341  xsltTransformError(NULL, ctxt->style, ctxt->elem,
342  "Failed to compile predicate\n");
343  if (ctxt->style != NULL)
344  ctxt->style->errors++;
345  }
346  }
347  comp->nbStep++;
348  return (0);
349 }
350 
357 static void
359  int i;
360  int j = comp->nbStep - 1;
361 
362  if (j > 0) {
363  register xmlChar *tmp;
364  register xsltOp op;
365  register xmlXPathCompExprPtr expr;
366  register int t;
367  i = j - 1;
368  tmp = comp->steps[i].value;
369  comp->steps[i].value = comp->steps[j].value;
370  comp->steps[j].value = tmp;
371  tmp = comp->steps[i].value2;
372  comp->steps[i].value2 = comp->steps[j].value2;
373  comp->steps[j].value2 = tmp;
374  tmp = comp->steps[i].value3;
375  comp->steps[i].value3 = comp->steps[j].value3;
376  comp->steps[j].value3 = tmp;
377  op = comp->steps[i].op;
378  comp->steps[i].op = comp->steps[j].op;
379  comp->steps[j].op = op;
380  expr = comp->steps[i].comp;
381  comp->steps[i].comp = comp->steps[j].comp;
382  comp->steps[j].comp = expr;
383  t = comp->steps[i].previousExtra;
384  comp->steps[i].previousExtra = comp->steps[j].previousExtra;
385  comp->steps[j].previousExtra = t;
386  t = comp->steps[i].indexExtra;
387  comp->steps[i].indexExtra = comp->steps[j].indexExtra;
388  comp->steps[j].indexExtra = t;
389  t = comp->steps[i].lenExtra;
390  comp->steps[i].lenExtra = comp->steps[j].lenExtra;
391  comp->steps[j].lenExtra = t;
392  }
393 }
394 
402 static void
404  int i = 0;
405  int j = comp->nbStep - 1;
406 
407  while (j > i) {
408  register xmlChar *tmp;
409  register xsltOp op;
410  register xmlXPathCompExprPtr expr;
411  register int t;
412 
413  tmp = comp->steps[i].value;
414  comp->steps[i].value = comp->steps[j].value;
415  comp->steps[j].value = tmp;
416  tmp = comp->steps[i].value2;
417  comp->steps[i].value2 = comp->steps[j].value2;
418  comp->steps[j].value2 = tmp;
419  tmp = comp->steps[i].value3;
420  comp->steps[i].value3 = comp->steps[j].value3;
421  comp->steps[j].value3 = tmp;
422  op = comp->steps[i].op;
423  comp->steps[i].op = comp->steps[j].op;
424  comp->steps[j].op = op;
425  expr = comp->steps[i].comp;
426  comp->steps[i].comp = comp->steps[j].comp;
427  comp->steps[j].comp = expr;
428  t = comp->steps[i].previousExtra;
429  comp->steps[i].previousExtra = comp->steps[j].previousExtra;
430  comp->steps[j].previousExtra = t;
431  t = comp->steps[i].indexExtra;
432  comp->steps[i].indexExtra = comp->steps[j].indexExtra;
433  comp->steps[j].indexExtra = t;
434  t = comp->steps[i].lenExtra;
435  comp->steps[i].lenExtra = comp->steps[j].lenExtra;
436  comp->steps[j].lenExtra = t;
437  j--;
438  i++;
439  }
440  xsltCompMatchAdd(ctxt, comp, XSLT_OP_END, NULL, NULL, 0);
441 
442  /*
443  * Detect consecutive XSLT_OP_PREDICATE and predicates on ops which
444  * haven't been optimized yet indicating a direct matching should be done.
445  */
446  for (i = 0;i < comp->nbStep - 1;i++) {
447  xsltOp op = comp->steps[i].op;
448 
449  if ((op != XSLT_OP_ELEM) &&
450  (op != XSLT_OP_ALL) &&
451  (comp->steps[i + 1].op == XSLT_OP_PREDICATE)) {
452 
453  comp->direct = 1;
454  if (comp->pattern[0] != '/') {
455  xmlChar *query;
456 
457  query = xmlStrdup((const xmlChar *)"//");
458  query = xmlStrcat(query, comp->pattern);
459 
460  xmlFree((xmlChar *) comp->pattern);
461  comp->pattern = query;
462  }
463  break;
464  }
465  }
466 }
467 
468 /************************************************************************
469  * *
470  * The interpreter for the precompiled patterns *
471  * *
472  ************************************************************************/
473 
474 static int
476  int step, xmlNodePtr node) {
477  if ((states->states == NULL) || (states->maxstates <= 0)) {
478  states->maxstates = 4;
479  states->nbstates = 0;
480  states->states = xmlMalloc(4 * sizeof(xsltStepState));
481  }
482  else if (states->maxstates <= states->nbstates) {
483  xsltStepState *tmp;
484 
485  tmp = (xsltStepStatePtr) xmlRealloc(states->states,
486  2 * states->maxstates * sizeof(xsltStepState));
487  if (tmp == NULL) {
489  "xsltPatPushState: memory re-allocation failure.\n");
490  ctxt->state = XSLT_STATE_STOPPED;
491  return(-1);
492  }
493  states->states = tmp;
494  states->maxstates *= 2;
495  }
496  states->states[states->nbstates].step = step;
497  states->states[states->nbstates++].node = node;
498 #if 0
499  fprintf(stderr, "Push: %d, %s\n", step, node->name);
500 #endif
501  return(0);
502 }
503 
504 static void
506  xmlXPathFreeObject((xmlXPathObjectPtr) obj);
507 }
508 
522 static int
525  xsltStepOpPtr sel = NULL;
526  xmlDocPtr prevdoc;
527  xmlDocPtr doc;
528  xmlXPathObjectPtr list;
529  int ix, j;
530  int nocache = 0;
531  int isRVT;
532 
533  doc = node->doc;
534  if (XSLT_IS_RES_TREE_FRAG(doc))
535  isRVT = 1;
536  else
537  isRVT = 0;
538  sel = &comp->steps[0]; /* store extra in first step arbitrarily */
539 
540  prevdoc = (xmlDocPtr)
541  XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr);
542  ix = XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival);
543  list = (xmlXPathObjectPtr)
544  XSLT_RUNTIME_EXTRA_LST(ctxt, sel->lenExtra);
545 
546  if ((list == NULL) || (prevdoc != doc)) {
547  xmlXPathObjectPtr newlist;
548  xmlNodePtr parent = node->parent;
549  xmlDocPtr olddoc;
550  xmlNodePtr oldnode;
551  int oldNsNr, oldContextSize, oldProximityPosition;
552  xmlNsPtr *oldNamespaces;
553 
554  oldnode = ctxt->xpathCtxt->node;
555  olddoc = ctxt->xpathCtxt->doc;
556  oldNsNr = ctxt->xpathCtxt->nsNr;
557  oldNamespaces = ctxt->xpathCtxt->namespaces;
558  oldContextSize = ctxt->xpathCtxt->contextSize;
559  oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
560  ctxt->xpathCtxt->node = node;
561  ctxt->xpathCtxt->doc = doc;
562  ctxt->xpathCtxt->namespaces = nsList;
563  ctxt->xpathCtxt->nsNr = nsNr;
564  newlist = xmlXPathEval(comp->pattern, ctxt->xpathCtxt);
565  ctxt->xpathCtxt->node = oldnode;
566  ctxt->xpathCtxt->doc = olddoc;
567  ctxt->xpathCtxt->namespaces = oldNamespaces;
568  ctxt->xpathCtxt->nsNr = oldNsNr;
569  ctxt->xpathCtxt->contextSize = oldContextSize;
570  ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
571  if (newlist == NULL)
572  return(-1);
573  if (newlist->type != XPATH_NODESET) {
574  xmlXPathFreeObject(newlist);
575  return(-1);
576  }
577  ix = 0;
578 
579  if ((parent == NULL) || (node->doc == NULL) || isRVT ||
580  (comp->novar == 0))
581  nocache = 1;
582 
583  if (nocache == 0) {
584  if (list != NULL)
585  xmlXPathFreeObject(list);
586  list = newlist;
587 
588  XSLT_RUNTIME_EXTRA_LST(ctxt, sel->lenExtra) =
589  (void *) list;
590  XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) =
591  (void *) doc;
592  XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) =
593  0;
594  XSLT_RUNTIME_EXTRA_FREE(ctxt, sel->lenExtra) =
596  } else
597  list = newlist;
598  }
599  if ((list->nodesetval == NULL) ||
600  (list->nodesetval->nodeNr <= 0)) {
601  if (nocache == 1)
602  xmlXPathFreeObject(list);
603  return(0);
604  }
605  /* TODO: store the index and use it for the scan */
606  if (ix == 0) {
607  for (j = 0;j < list->nodesetval->nodeNr;j++) {
608  if (list->nodesetval->nodeTab[j] == node) {
609  if (nocache == 1)
610  xmlXPathFreeObject(list);
611  return(1);
612  }
613  }
614  } else {
615  }
616  if (nocache == 1)
617  xmlXPathFreeObject(list);
618  return(0);
619 }
620 
633 static int
636  xsltStepOpPtr sel) {
637  xmlNodePtr oldNode;
638  xmlDocPtr doc;
639  int oldCS, oldCP;
640  int pos = 0, len = 0;
641  int isRVT;
642  int match;
643 
644  if (step->value == NULL)
645  return(0);
646  if (step->comp == NULL)
647  return(0);
648 
649  doc = node->doc;
650  if (XSLT_IS_RES_TREE_FRAG(doc))
651  isRVT = 1;
652  else
653  isRVT = 0;
654 
655  /*
656  * Recompute contextSize and proximityPosition.
657  *
658  * TODO: Make this work for additional ops. Currently, only XSLT_OP_ELEM
659  * and XSLT_OP_ALL are supported.
660  */
661  oldCS = ctxt->xpathCtxt->contextSize;
662  oldCP = ctxt->xpathCtxt->proximityPosition;
663  if ((sel != NULL) &&
664  (sel->op == XSLT_OP_ELEM) &&
665  (sel->value != NULL) &&
666  (node->type == XML_ELEMENT_NODE) &&
667  (node->parent != NULL)) {
668  xmlNodePtr previous;
669  int nocache = 0;
670 
671  previous = (xmlNodePtr)
672  XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr);
673  if ((previous != NULL) &&
674  (previous->parent == node->parent)) {
675  /*
676  * just walk back to adjust the index
677  */
678  int indx = 0;
679  xmlNodePtr sibling = node;
680 
681  while (sibling != NULL) {
682  if (sibling == previous)
683  break;
684  if ((sibling->type == XML_ELEMENT_NODE) &&
685  (previous->name != NULL) &&
686  (sibling->name != NULL) &&
687  (previous->name[0] == sibling->name[0]) &&
688  (xmlStrEqual(previous->name, sibling->name)))
689  {
690  if ((sel->value2 == NULL) ||
691  ((sibling->ns != NULL) &&
692  (xmlStrEqual(sel->value2, sibling->ns->href))))
693  indx++;
694  }
695  sibling = sibling->prev;
696  }
697  if (sibling == NULL) {
698  /* hum going backward in document order ... */
699  indx = 0;
700  sibling = node;
701  while (sibling != NULL) {
702  if (sibling == previous)
703  break;
704  if ((sibling->type == XML_ELEMENT_NODE) &&
705  (previous->name != NULL) &&
706  (sibling->name != NULL) &&
707  (previous->name[0] == sibling->name[0]) &&
708  (xmlStrEqual(previous->name, sibling->name)))
709  {
710  if ((sel->value2 == NULL) ||
711  ((sibling->ns != NULL) &&
712  (xmlStrEqual(sel->value2,
713  sibling->ns->href))))
714  {
715  indx--;
716  }
717  }
718  sibling = sibling->next;
719  }
720  }
721  if (sibling != NULL) {
722  pos = XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) + indx;
723  /*
724  * If the node is in a Value Tree we need to
725  * save len, but cannot cache the node!
726  * (bugs 153137 and 158840)
727  */
728  if (node->doc != NULL) {
729  len = XSLT_RUNTIME_EXTRA(ctxt, sel->lenExtra, ival);
730  if (!isRVT) {
731  XSLT_RUNTIME_EXTRA(ctxt,
732  sel->previousExtra, ptr) = node;
733  XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) = pos;
734  }
735  }
736  } else
737  pos = 0;
738  } else {
739  /*
740  * recompute the index
741  */
742  xmlNodePtr parent = node->parent;
743  xmlNodePtr siblings = NULL;
744 
745  if (parent) siblings = parent->children;
746 
747  while (siblings != NULL) {
748  if (siblings->type == XML_ELEMENT_NODE) {
749  if (siblings == node) {
750  len++;
751  pos = len;
752  } else if ((node->name != NULL) &&
753  (siblings->name != NULL) &&
754  (node->name[0] == siblings->name[0]) &&
755  (xmlStrEqual(node->name, siblings->name))) {
756  if ((sel->value2 == NULL) ||
757  ((siblings->ns != NULL) &&
758  (xmlStrEqual(sel->value2, siblings->ns->href))))
759  len++;
760  }
761  }
762  siblings = siblings->next;
763  }
764  if ((parent == NULL) || (node->doc == NULL))
765  nocache = 1;
766  else {
767  while (parent->parent != NULL)
768  parent = parent->parent;
769  if (((parent->type != XML_DOCUMENT_NODE) &&
770  (parent->type != XML_HTML_DOCUMENT_NODE)) ||
771  (parent != (xmlNodePtr) node->doc))
772  nocache = 1;
773  }
774  }
775  if (pos != 0) {
776  ctxt->xpathCtxt->contextSize = len;
777  ctxt->xpathCtxt->proximityPosition = pos;
778  /*
779  * If the node is in a Value Tree we cannot
780  * cache it !
781  */
782  if ((!isRVT) && (node->doc != NULL) &&
783  (nocache == 0)) {
784  XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) = node;
785  XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) = pos;
786  XSLT_RUNTIME_EXTRA(ctxt, sel->lenExtra, ival) = len;
787  }
788  }
789  } else if ((sel != NULL) && (sel->op == XSLT_OP_ALL) &&
790  (node->type == XML_ELEMENT_NODE)) {
791  xmlNodePtr previous;
792  int nocache = 0;
793 
794  previous = (xmlNodePtr)
795  XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr);
796  if ((previous != NULL) &&
797  (previous->parent == node->parent)) {
798  /*
799  * just walk back to adjust the index
800  */
801  int indx = 0;
802  xmlNodePtr sibling = node;
803 
804  while (sibling != NULL) {
805  if (sibling == previous)
806  break;
807  if (sibling->type == XML_ELEMENT_NODE)
808  indx++;
809  sibling = sibling->prev;
810  }
811  if (sibling == NULL) {
812  /* hum going backward in document order ... */
813  indx = 0;
814  sibling = node;
815  while (sibling != NULL) {
816  if (sibling == previous)
817  break;
818  if (sibling->type == XML_ELEMENT_NODE)
819  indx--;
820  sibling = sibling->next;
821  }
822  }
823  if (sibling != NULL) {
824  pos = XSLT_RUNTIME_EXTRA(ctxt,
825  sel->indexExtra, ival) + indx;
826  /*
827  * If the node is in a Value Tree we cannot
828  * cache it !
829  */
830  if ((node->doc != NULL) && !isRVT) {
831  len = XSLT_RUNTIME_EXTRA(ctxt, sel->lenExtra, ival);
832  XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) = node;
833  XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) = pos;
834  }
835  } else
836  pos = 0;
837  } else {
838  /*
839  * recompute the index
840  */
841  xmlNodePtr parent = node->parent;
842  xmlNodePtr siblings = NULL;
843 
844  if (parent) siblings = parent->children;
845 
846  while (siblings != NULL) {
847  if (siblings->type == XML_ELEMENT_NODE) {
848  len++;
849  if (siblings == node) {
850  pos = len;
851  }
852  }
853  siblings = siblings->next;
854  }
855  if ((parent == NULL) || (node->doc == NULL))
856  nocache = 1;
857  else {
858  while (parent->parent != NULL)
859  parent = parent->parent;
860  if (((parent->type != XML_DOCUMENT_NODE) &&
861  (parent->type != XML_HTML_DOCUMENT_NODE)) ||
862  (parent != (xmlNodePtr) node->doc))
863  nocache = 1;
864  }
865  }
866  if (pos != 0) {
867  ctxt->xpathCtxt->contextSize = len;
868  ctxt->xpathCtxt->proximityPosition = pos;
869  /*
870  * If the node is in a Value Tree we cannot
871  * cache it !
872  */
873  if ((node->doc != NULL) && (nocache == 0) && !isRVT) {
874  XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) = node;
875  XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) = pos;
876  XSLT_RUNTIME_EXTRA(ctxt, sel->lenExtra, ival) = len;
877  }
878  }
879  }
880 
881  oldNode = ctxt->node;
882  ctxt->node = node;
883 
884  match = xsltEvalXPathPredicate(ctxt, step->comp, comp->nsList, comp->nsNr);
885 
886  if (pos != 0) {
887  ctxt->xpathCtxt->contextSize = oldCS;
888  ctxt->xpathCtxt->proximityPosition = oldCP;
889  }
890  ctxt->node = oldNode;
891 
892  return match;
893 }
894 
907 static int
909  xmlNodePtr matchNode, const xmlChar *mode,
910  const xmlChar *modeURI) {
911  int i;
912  int found = 0;
913  xmlNodePtr node = matchNode;
914  xmlNodePtr oldInst;
915  xsltStepOpPtr step, sel = NULL;
916  xsltStepStates states = {0, 0, NULL}; /* // may require backtrack */
917 
918  if ((comp == NULL) || (node == NULL) || (ctxt == NULL)) {
920  "xsltTestCompMatch: null arg\n");
921  return(-1);
922  }
923  if (mode != NULL) {
924  if (comp->mode == NULL)
925  return(0);
926  /*
927  * both mode strings must be interned on the stylesheet dictionary
928  */
929  if (comp->mode != mode)
930  return(0);
931  } else {
932  if (comp->mode != NULL)
933  return(0);
934  }
935  if (modeURI != NULL) {
936  if (comp->modeURI == NULL)
937  return(0);
938  /*
939  * both modeURI strings must be interned on the stylesheet dictionary
940  */
941  if (comp->modeURI != modeURI)
942  return(0);
943  } else {
944  if (comp->modeURI != NULL)
945  return(0);
946  }
947 
948  /* Some XPath functions rely on inst being set correctly. */
949  oldInst = ctxt->inst;
950  ctxt->inst = comp->node;
951 
952  i = 0;
953 restart:
954  for (;i < comp->nbStep;i++) {
955  step = &comp->steps[i];
956  if (step->op != XSLT_OP_PREDICATE)
957  sel = step;
958  switch (step->op) {
959  case XSLT_OP_END:
960  goto found;
961  case XSLT_OP_ROOT:
962  if ((node->type == XML_DOCUMENT_NODE) ||
963 #ifdef LIBXML_DOCB_ENABLED
964  (node->type == XML_DOCB_DOCUMENT_NODE) ||
965 #endif
966  (node->type == XML_HTML_DOCUMENT_NODE))
967  continue;
968  if ((node->type == XML_ELEMENT_NODE) && (node->name[0] == ' '))
969  continue;
970  goto rollback;
971  case XSLT_OP_ELEM:
972  if (node->type != XML_ELEMENT_NODE)
973  goto rollback;
974  if (step->value == NULL)
975  continue;
976  if (step->value[0] != node->name[0])
977  goto rollback;
978  if (!xmlStrEqual(step->value, node->name))
979  goto rollback;
980 
981  /* Namespace test */
982  if (node->ns == NULL) {
983  if (step->value2 != NULL)
984  goto rollback;
985  } else if (node->ns->href != NULL) {
986  if (step->value2 == NULL)
987  goto rollback;
988  if (!xmlStrEqual(step->value2, node->ns->href))
989  goto rollback;
990  }
991  continue;
992  case XSLT_OP_ATTR:
993  if (node->type != XML_ATTRIBUTE_NODE)
994  goto rollback;
995  if (step->value != NULL) {
996  if (step->value[0] != node->name[0])
997  goto rollback;
998  if (!xmlStrEqual(step->value, node->name))
999  goto rollback;
1000  }
1001  /* Namespace test */
1002  if (node->ns == NULL) {
1003  if (step->value2 != NULL)
1004  goto rollback;
1005  } else if (step->value2 != NULL) {
1006  if (!xmlStrEqual(step->value2, node->ns->href))
1007  goto rollback;
1008  }
1009  continue;
1010  case XSLT_OP_PARENT:
1011  if ((node->type == XML_DOCUMENT_NODE) ||
1012  (node->type == XML_HTML_DOCUMENT_NODE) ||
1013 #ifdef LIBXML_DOCB_ENABLED
1014  (node->type == XML_DOCB_DOCUMENT_NODE) ||
1015 #endif
1016  (node->type == XML_NAMESPACE_DECL))
1017  goto rollback;
1018  node = node->parent;
1019  if (node == NULL)
1020  goto rollback;
1021  if (step->value == NULL)
1022  continue;
1023  if (step->value[0] != node->name[0])
1024  goto rollback;
1025  if (!xmlStrEqual(step->value, node->name))
1026  goto rollback;
1027  /* Namespace test */
1028  if (node->ns == NULL) {
1029  if (step->value2 != NULL)
1030  goto rollback;
1031  } else if (node->ns->href != NULL) {
1032  if (step->value2 == NULL)
1033  goto rollback;
1034  if (!xmlStrEqual(step->value2, node->ns->href))
1035  goto rollback;
1036  }
1037  continue;
1038  case XSLT_OP_ANCESTOR:
1039  /* TODO: implement coalescing of ANCESTOR/NODE ops */
1040  if (step->value == NULL) {
1041  step = &comp->steps[i+1];
1042  if (step->op == XSLT_OP_ROOT)
1043  goto found;
1044  /* added NS, ID and KEY as a result of bug 168208 */
1045  if ((step->op != XSLT_OP_ELEM) &&
1046  (step->op != XSLT_OP_ALL) &&
1047  (step->op != XSLT_OP_NS) &&
1048  (step->op != XSLT_OP_ID) &&
1049  (step->op != XSLT_OP_KEY))
1050  goto rollback;
1051  }
1052  if (node == NULL)
1053  goto rollback;
1054  if ((node->type == XML_DOCUMENT_NODE) ||
1055  (node->type == XML_HTML_DOCUMENT_NODE) ||
1056 #ifdef LIBXML_DOCB_ENABLED
1057  (node->type == XML_DOCB_DOCUMENT_NODE) ||
1058 #endif
1059  (node->type == XML_NAMESPACE_DECL))
1060  goto rollback;
1061  node = node->parent;
1062  if ((step->op != XSLT_OP_ELEM) && step->op != XSLT_OP_ALL) {
1063  xsltPatPushState(ctxt, &states, i, node);
1064  continue;
1065  }
1066  i++;
1067  if (step->value == NULL) {
1068  xsltPatPushState(ctxt, &states, i - 1, node);
1069  continue;
1070  }
1071  while (node != NULL) {
1072  if ((node->type == XML_ELEMENT_NODE) &&
1073  (step->value[0] == node->name[0]) &&
1074  (xmlStrEqual(step->value, node->name))) {
1075  /* Namespace test */
1076  if (node->ns == NULL) {
1077  if (step->value2 == NULL)
1078  break;
1079  } else if (node->ns->href != NULL) {
1080  if ((step->value2 != NULL) &&
1081  (xmlStrEqual(step->value2, node->ns->href)))
1082  break;
1083  }
1084  }
1085  node = node->parent;
1086  }
1087  if (node == NULL)
1088  goto rollback;
1089  xsltPatPushState(ctxt, &states, i - 1, node);
1090  continue;
1091  case XSLT_OP_ID: {
1092  /* TODO Handle IDs decently, must be done differently */
1093  xmlAttrPtr id;
1094 
1095  if (node->type != XML_ELEMENT_NODE)
1096  goto rollback;
1097 
1098  id = xmlGetID(node->doc, step->value);
1099  if ((id == NULL) || (id->parent != node))
1100  goto rollback;
1101  break;
1102  }
1103  case XSLT_OP_KEY: {
1104  xmlNodeSetPtr list;
1105  int indx;
1106 
1107  list = xsltGetKey(ctxt, step->value,
1108  step->value3, step->value2);
1109  if (list == NULL)
1110  goto rollback;
1111  for (indx = 0;indx < list->nodeNr;indx++)
1112  if (list->nodeTab[indx] == node)
1113  break;
1114  if (indx >= list->nodeNr)
1115  goto rollback;
1116  break;
1117  }
1118  case XSLT_OP_NS:
1119  if (node->type != XML_ELEMENT_NODE)
1120  goto rollback;
1121  if (node->ns == NULL) {
1122  if (step->value != NULL)
1123  goto rollback;
1124  } else if (node->ns->href != NULL) {
1125  if (step->value == NULL)
1126  goto rollback;
1127  if (!xmlStrEqual(step->value, node->ns->href))
1128  goto rollback;
1129  }
1130  break;
1131  case XSLT_OP_ALL:
1132  if (node->type != XML_ELEMENT_NODE)
1133  goto rollback;
1134  break;
1135  case XSLT_OP_PREDICATE: {
1136  /*
1137  * When there is cascading XSLT_OP_PREDICATE or a predicate
1138  * after an op which hasn't been optimized yet, then use a
1139  * direct computation approach. It's not done directly
1140  * at the beginning of the routine to filter out as much
1141  * as possible this costly computation.
1142  */
1143  if (comp->direct) {
1144  found = xsltTestCompMatchDirect(ctxt, comp, matchNode,
1145  comp->nsList, comp->nsNr);
1146  goto exit;
1147  }
1148 
1149  if (!xsltTestPredicateMatch(ctxt, comp, node, step, sel))
1150  goto rollback;
1151 
1152  break;
1153  }
1154  case XSLT_OP_PI:
1155  if (node->type != XML_PI_NODE)
1156  goto rollback;
1157  if (step->value != NULL) {
1158  if (!xmlStrEqual(step->value, node->name))
1159  goto rollback;
1160  }
1161  break;
1162  case XSLT_OP_COMMENT:
1163  if (node->type != XML_COMMENT_NODE)
1164  goto rollback;
1165  break;
1166  case XSLT_OP_TEXT:
1167  if ((node->type != XML_TEXT_NODE) &&
1168  (node->type != XML_CDATA_SECTION_NODE))
1169  goto rollback;
1170  break;
1171  case XSLT_OP_NODE:
1172  switch (node->type) {
1173  case XML_ELEMENT_NODE:
1175  case XML_PI_NODE:
1176  case XML_COMMENT_NODE:
1177  case XML_TEXT_NODE:
1178  break;
1179  default:
1180  goto rollback;
1181  }
1182  break;
1183  }
1184  }
1185 found:
1186  found = 1;
1187 exit:
1188  ctxt->inst = oldInst;
1189  if (states.states != NULL) {
1190  /* Free the rollback states */
1191  xmlFree(states.states);
1192  }
1193  return found;
1194 rollback:
1195  /* got an error try to rollback */
1196  if (states.states == NULL || states.nbstates <= 0) {
1197  found = 0;
1198  goto exit;
1199  }
1200  states.nbstates--;
1201  i = states.states[states.nbstates].step;
1202  node = states.states[states.nbstates].node;
1203 #if 0
1204  fprintf(stderr, "Pop: %d, %s\n", i, node->name);
1205 #endif
1206  goto restart;
1207 }
1208 
1219 int
1221  xsltCompMatchPtr comp) {
1222  int ret;
1223 
1224  if ((ctxt == NULL) || (node == NULL))
1225  return(-1);
1226  while (comp != NULL) {
1227  ret = xsltTestCompMatch(ctxt, comp, node, NULL, NULL);
1228  if (ret == 1)
1229  return(1);
1230  comp = comp->next;
1231  }
1232  return(0);
1233 }
1234 
1235 /************************************************************************
1236  * *
1237  * Dedicated parser for templates *
1238  * *
1239  ************************************************************************/
1240 
1241 #define CUR (*ctxt->cur)
1242 #define SKIP(val) ctxt->cur += (val)
1243 #define NXT(val) ctxt->cur[(val)]
1244 #define CUR_PTR ctxt->cur
1245 
1246 #define SKIP_BLANKS \
1247  while (IS_BLANK_CH(CUR)) NEXT
1248 
1249 #define CURRENT (*ctxt->cur)
1250 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1251 
1252 
1253 #define PUSH(op, val, val2, novar) \
1254  if (xsltCompMatchAdd(ctxt, ctxt->comp, (op), (val), (val2), (novar))) goto error;
1255 
1256 #define SWAP() \
1257  xsltSwapTopCompMatch(ctxt->comp);
1258 
1259 #define XSLT_ERROR(X) \
1260  { xsltError(ctxt, __FILE__, __LINE__, X); \
1261  ctxt->error = (X); return; }
1262 
1263 #define XSLT_ERROR0(X) \
1264  { xsltError(ctxt, __FILE__, __LINE__, X); \
1265  ctxt->error = (X); return(0); }
1266 
1279 static xmlChar *
1281  const xmlChar *q, *cur;
1282  xmlChar *ret = NULL;
1283  int val, len;
1284 
1285  SKIP_BLANKS;
1286  if (CUR == '"') {
1287  NEXT;
1288  cur = q = CUR_PTR;
1289  val = xmlStringCurrentChar(NULL, cur, &len);
1290  while ((IS_CHAR(val)) && (val != '"')) {
1291  cur += len;
1292  val = xmlStringCurrentChar(NULL, cur, &len);
1293  }
1294  if (!IS_CHAR(val)) {
1295  ctxt->error = 1;
1296  return(NULL);
1297  } else {
1298  ret = xmlStrndup(q, cur - q);
1299  }
1300  cur += len;
1301  CUR_PTR = cur;
1302  } else if (CUR == '\'') {
1303  NEXT;
1304  cur = q = CUR_PTR;
1305  val = xmlStringCurrentChar(NULL, cur, &len);
1306  while ((IS_CHAR(val)) && (val != '\'')) {
1307  cur += len;
1308  val = xmlStringCurrentChar(NULL, cur, &len);
1309  }
1310  if (!IS_CHAR(val)) {
1311  ctxt->error = 1;
1312  return(NULL);
1313  } else {
1314  ret = xmlStrndup(q, cur - q);
1315  }
1316  cur += len;
1317  CUR_PTR = cur;
1318  } else {
1319  /* XP_ERROR(XPATH_START_LITERAL_ERROR); */
1320  ctxt->error = 1;
1321  return(NULL);
1322  }
1323  return(ret);
1324 }
1325 
1335 static xmlChar *
1337  const xmlChar *q, *cur;
1338  xmlChar *ret = NULL;
1339  int val, len;
1340 
1341  SKIP_BLANKS;
1342 
1343  cur = q = CUR_PTR;
1344  val = xmlStringCurrentChar(NULL, cur, &len);
1345  if (!IS_LETTER(val) && (val != '_'))
1346  return(NULL);
1347 
1348  while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
1349  (val == '.') || (val == '-') ||
1350  (val == '_') ||
1351  (IS_COMBINING(val)) ||
1352  (IS_EXTENDER(val))) {
1353  cur += len;
1354  val = xmlStringCurrentChar(NULL, cur, &len);
1355  }
1356  ret = xmlStrndup(q, cur - q);
1357  CUR_PTR = cur;
1358  return(ret);
1359 }
1360 
1361 /*
1362  * xsltCompileIdKeyPattern:
1363  * @ctxt: the compilation context
1364  * @name: a preparsed name
1365  * @aid: whether id/key are allowed there
1366  * @novar: flag to prohibit xslt var
1367  *
1368  * Compile the XSLT LocationIdKeyPattern
1369  * [3] IdKeyPattern ::= 'id' '(' Literal ')'
1370  * | 'key' '(' Literal ',' Literal ')'
1371  *
1372  * also handle NodeType and PI from:
1373  *
1374  * [7] NodeTest ::= NameTest
1375  * | NodeType '(' ')'
1376  * | 'processing-instruction' '(' Literal ')'
1377  */
1378 static void
1380  int aid, int novar, xsltAxis axis) {
1381  xmlChar *lit = NULL;
1382  xmlChar *lit2 = NULL;
1383 
1384  if (CUR != '(') {
1386  "xsltCompileIdKeyPattern : ( expected\n");
1387  ctxt->error = 1;
1388  return;
1389  }
1390  if ((aid) && (xmlStrEqual(name, (const xmlChar *)"id"))) {
1391  if (axis != 0) {
1393  "xsltCompileIdKeyPattern : NodeTest expected\n");
1394  ctxt->error = 1;
1395  return;
1396  }
1397  NEXT;
1398  SKIP_BLANKS;
1399  lit = xsltScanLiteral(ctxt);
1400  if (ctxt->error) {
1402  "xsltCompileIdKeyPattern : Literal expected\n");
1403  return;
1404  }
1405  SKIP_BLANKS;
1406  if (CUR != ')') {
1408  "xsltCompileIdKeyPattern : ) expected\n");
1409  xmlFree(lit);
1410  ctxt->error = 1;
1411  return;
1412  }
1413  NEXT;
1414  PUSH(XSLT_OP_ID, lit, NULL, novar);
1415  lit = NULL;
1416  } else if ((aid) && (xmlStrEqual(name, (const xmlChar *)"key"))) {
1417  if (axis != 0) {
1419  "xsltCompileIdKeyPattern : NodeTest expected\n");
1420  ctxt->error = 1;
1421  return;
1422  }
1423  NEXT;
1424  SKIP_BLANKS;
1425  lit = xsltScanLiteral(ctxt);
1426  if (ctxt->error) {
1428  "xsltCompileIdKeyPattern : Literal expected\n");
1429  return;
1430  }
1431  SKIP_BLANKS;
1432  if (CUR != ',') {
1434  "xsltCompileIdKeyPattern : , expected\n");
1435  xmlFree(lit);
1436  ctxt->error = 1;
1437  return;
1438  }
1439  NEXT;
1440  SKIP_BLANKS;
1441  lit2 = xsltScanLiteral(ctxt);
1442  if (ctxt->error) {
1444  "xsltCompileIdKeyPattern : Literal expected\n");
1445  xmlFree(lit);
1446  return;
1447  }
1448  SKIP_BLANKS;
1449  if (CUR != ')') {
1451  "xsltCompileIdKeyPattern : ) expected\n");
1452  xmlFree(lit);
1453  xmlFree(lit2);
1454  ctxt->error = 1;
1455  return;
1456  }
1457  NEXT;
1458  /* URGENT TODO: support namespace in keys */
1459  PUSH(XSLT_OP_KEY, lit, lit2, novar);
1460  lit = NULL;
1461  lit2 = NULL;
1462  } else if (xmlStrEqual(name, (const xmlChar *)"processing-instruction")) {
1463  NEXT;
1464  SKIP_BLANKS;
1465  if (CUR != ')') {
1466  lit = xsltScanLiteral(ctxt);
1467  if (ctxt->error) {
1469  "xsltCompileIdKeyPattern : Literal expected\n");
1470  return;
1471  }
1472  SKIP_BLANKS;
1473  if (CUR != ')') {
1475  "xsltCompileIdKeyPattern : ) expected\n");
1476  ctxt->error = 1;
1477  xmlFree(lit);
1478  return;
1479  }
1480  }
1481  NEXT;
1482  PUSH(XSLT_OP_PI, lit, NULL, novar);
1483  lit = NULL;
1484  } else if (xmlStrEqual(name, (const xmlChar *)"text")) {
1485  NEXT;
1486  SKIP_BLANKS;
1487  if (CUR != ')') {
1489  "xsltCompileIdKeyPattern : ) expected\n");
1490  ctxt->error = 1;
1491  return;
1492  }
1493  NEXT;
1495  } else if (xmlStrEqual(name, (const xmlChar *)"comment")) {
1496  NEXT;
1497  SKIP_BLANKS;
1498  if (CUR != ')') {
1500  "xsltCompileIdKeyPattern : ) expected\n");
1501  ctxt->error = 1;
1502  return;
1503  }
1504  NEXT;
1506  } else if (xmlStrEqual(name, (const xmlChar *)"node")) {
1507  NEXT;
1508  SKIP_BLANKS;
1509  if (CUR != ')') {
1511  "xsltCompileIdKeyPattern : ) expected\n");
1512  ctxt->error = 1;
1513  return;
1514  }
1515  NEXT;
1516  if (axis == AXIS_ATTRIBUTE) {
1518  }
1519  else {
1521  }
1522  } else if (aid) {
1524  "xsltCompileIdKeyPattern : expecting 'key' or 'id' or node type\n");
1525  ctxt->error = 1;
1526  return;
1527  } else {
1529  "xsltCompileIdKeyPattern : node type\n");
1530  ctxt->error = 1;
1531  return;
1532  }
1533 error:
1534  return;
1535 }
1536 
1559 static void
1561  xmlChar *name = NULL;
1562  const xmlChar *URI = NULL;
1563  xmlChar *URL = NULL;
1564  int level;
1565  xsltAxis axis = 0;
1566 
1567  SKIP_BLANKS;
1568  if ((token == NULL) && (CUR == '@')) {
1569  NEXT;
1570  axis = AXIS_ATTRIBUTE;
1571  }
1572 parse_node_test:
1573  if (token == NULL)
1574  token = xsltScanNCName(ctxt);
1575  if (token == NULL) {
1576  if (CUR == '*') {
1577  NEXT;
1578  if (axis == AXIS_ATTRIBUTE) {
1580  }
1581  else {
1583  }
1584  goto parse_predicate;
1585  } else {
1587  "xsltCompileStepPattern : Name expected\n");
1588  ctxt->error = 1;
1589  goto error;
1590  }
1591  }
1592 
1593 
1594  SKIP_BLANKS;
1595  if (CUR == '(') {
1596  xsltCompileIdKeyPattern(ctxt, token, 0, novar, axis);
1597  xmlFree(token);
1598  token = NULL;
1599  if (ctxt->error)
1600  goto error;
1601  } else if (CUR == ':') {
1602  NEXT;
1603  if (CUR != ':') {
1604  xmlChar *prefix = token;
1605  xmlNsPtr ns;
1606 
1607  /*
1608  * This is a namespace match
1609  */
1610  token = xsltScanNCName(ctxt);
1611  ns = xmlSearchNs(ctxt->doc, ctxt->elem, prefix);
1612  if (ns == NULL) {
1614  "xsltCompileStepPattern : no namespace bound to prefix %s\n",
1615  prefix);
1616  xmlFree(prefix);
1617  prefix=NULL;
1618  ctxt->error = 1;
1619  goto error;
1620  } else {
1621  URL = xmlStrdup(ns->href);
1622  }
1623  xmlFree(prefix);
1624  prefix=NULL;
1625  if (token == NULL) {
1626  if (CUR == '*') {
1627  NEXT;
1628  if (axis == AXIS_ATTRIBUTE) {
1629  PUSH(XSLT_OP_ATTR, NULL, URL, novar);
1630  URL = NULL;
1631  }
1632  else {
1633  PUSH(XSLT_OP_NS, URL, NULL, novar);
1634  URL = NULL;
1635  }
1636  } else {
1638  "xsltCompileStepPattern : Name expected\n");
1639  ctxt->error = 1;
1640  xmlFree(URL);
1641  goto error;
1642  }
1643  } else {
1644  if (axis == AXIS_ATTRIBUTE) {
1645  PUSH(XSLT_OP_ATTR, token, URL, novar);
1646  token = NULL;
1647  URL = NULL;
1648  }
1649  else {
1650  PUSH(XSLT_OP_ELEM, token, URL, novar);
1651  token = NULL;
1652  URL = NULL;
1653  }
1654  }
1655  } else {
1656  if (axis != 0) {
1658  "xsltCompileStepPattern : NodeTest expected\n");
1659  ctxt->error = 1;
1660  goto error;
1661  }
1662  NEXT;
1663  if (xmlStrEqual(token, (const xmlChar *) "child")) {
1664  axis = AXIS_CHILD;
1665  } else if (xmlStrEqual(token, (const xmlChar *) "attribute")) {
1666  axis = AXIS_ATTRIBUTE;
1667  } else {
1669  "xsltCompileStepPattern : 'child' or 'attribute' expected\n");
1670  ctxt->error = 1;
1671  goto error;
1672  }
1673  xmlFree(token);
1674  token = NULL;
1675  SKIP_BLANKS;
1676  token = xsltScanNCName(ctxt);
1677  goto parse_node_test;
1678  }
1679  } else {
1680  URI = xsltGetQNameURI(ctxt->elem, &token);
1681  if (token == NULL) {
1682  ctxt->error = 1;
1683  goto error;
1684  }
1685  if (URI != NULL)
1686  URL = xmlStrdup(URI);
1687  if (axis == AXIS_ATTRIBUTE) {
1688  PUSH(XSLT_OP_ATTR, token, URL, novar);
1689  token = NULL;
1690  URL = NULL;
1691  }
1692  else {
1693  PUSH(XSLT_OP_ELEM, token, URL, novar);
1694  token = NULL;
1695  URL = NULL;
1696  }
1697  }
1698 parse_predicate:
1699  SKIP_BLANKS;
1700  level = 0;
1701  while (CUR == '[') {
1702  const xmlChar *q;
1703  xmlChar *ret = NULL;
1704 
1705  level++;
1706  NEXT;
1707  q = CUR_PTR;
1708  while (CUR != 0) {
1709  /* Skip over nested predicates */
1710  if (CUR == '[')
1711  level++;
1712  else if (CUR == ']') {
1713  level--;
1714  if (level == 0)
1715  break;
1716  } else if (CUR == '"') {
1717  NEXT;
1718  while ((CUR != 0) && (CUR != '"'))
1719  NEXT;
1720  } else if (CUR == '\'') {
1721  NEXT;
1722  while ((CUR != 0) && (CUR != '\''))
1723  NEXT;
1724  }
1725  NEXT;
1726  }
1727  if (CUR == 0) {
1729  "xsltCompileStepPattern : ']' expected\n");
1730  ctxt->error = 1;
1731  return;
1732  }
1733  ret = xmlStrndup(q, CUR_PTR - q);
1735  ret = NULL;
1736  /* push the predicate lower than local test */
1737  SWAP();
1738  NEXT;
1739  SKIP_BLANKS;
1740  }
1741  return;
1742 error:
1743  if (token != NULL)
1744  xmlFree(token);
1745  if (name != NULL)
1746  xmlFree(name);
1747 }
1748 
1762 static void
1765  if (ctxt->error)
1766  goto error;
1767  SKIP_BLANKS;
1768  while ((CUR != 0) && (CUR != '|')) {
1769  if ((CUR == '/') && (NXT(1) == '/')) {
1771  NEXT;
1772  NEXT;
1773  SKIP_BLANKS;
1775  } else if (CUR == '/') {
1777  NEXT;
1778  SKIP_BLANKS;
1779  if ((CUR != 0) && (CUR != '|')) {
1781  }
1782  } else {
1783  ctxt->error = 1;
1784  }
1785  if (ctxt->error)
1786  goto error;
1787  SKIP_BLANKS;
1788  }
1789 error:
1790  return;
1791 }
1792 
1805 static void
1807  SKIP_BLANKS;
1808  if ((CUR == '/') && (NXT(1) == '/')) {
1809  /*
1810  * since we reverse the query
1811  * a leading // can be safely ignored
1812  */
1813  NEXT;
1814  NEXT;
1815  ctxt->comp->priority = 0.5; /* '//' means not 0 priority */
1817  } else if (CUR == '/') {
1818  /*
1819  * We need to find root as the parent
1820  */
1821  NEXT;
1822  SKIP_BLANKS;
1824  if ((CUR != 0) && (CUR != '|')) {
1827  }
1828  } else if (CUR == '*') {
1830  } else if (CUR == '@') {
1832  } else {
1833  xmlChar *name;
1834  name = xsltScanNCName(ctxt);
1835  if (name == NULL) {
1837  "xsltCompileLocationPathPattern : Name expected\n");
1838  ctxt->error = 1;
1839  return;
1840  }
1841  SKIP_BLANKS;
1842  if ((CUR == '(') && !xmlXPathIsNodeType(name)) {
1843  xsltCompileIdKeyPattern(ctxt, name, 1, novar, 0);
1844  xmlFree(name);
1845  name = NULL;
1846  if ((CUR == '/') && (NXT(1) == '/')) {
1848  NEXT;
1849  NEXT;
1850  SKIP_BLANKS;
1852  } else if (CUR == '/') {
1854  NEXT;
1855  SKIP_BLANKS;
1857  }
1858  return;
1859  }
1861  }
1862 error:
1863  return;
1864 }
1865 
1883 static xsltCompMatchPtr
1886  xsltTransformContextPtr runtime, int novar) {
1887  xsltParserContextPtr ctxt = NULL;
1888  xsltCompMatchPtr element, first = NULL, previous = NULL;
1889  int current, start, end, level, j;
1890 
1891  if (pattern == NULL) {
1893  "xsltCompilePattern : NULL pattern\n");
1894  return(NULL);
1895  }
1896 
1897  ctxt = xsltNewParserContext(style, runtime);
1898  if (ctxt == NULL)
1899  return(NULL);
1900  ctxt->doc = doc;
1901  ctxt->elem = node;
1902  current = end = 0;
1903  while (pattern[current] != 0) {
1904  start = current;
1905  while (IS_BLANK_CH(pattern[current]))
1906  current++;
1907  end = current;
1908  level = 0;
1909  while ((pattern[end] != 0) && ((pattern[end] != '|') || (level != 0))) {
1910  if (pattern[end] == '[')
1911  level++;
1912  else if (pattern[end] == ']')
1913  level--;
1914  else if (pattern[end] == '\'') {
1915  end++;
1916  while ((pattern[end] != 0) && (pattern[end] != '\''))
1917  end++;
1918  } else if (pattern[end] == '"') {
1919  end++;
1920  while ((pattern[end] != 0) && (pattern[end] != '"'))
1921  end++;
1922  }
1923  if (pattern[end] == 0)
1924  break;
1925  end++;
1926  }
1927  if (current == end) {
1929  "xsltCompilePattern : NULL pattern\n");
1930  goto error;
1931  }
1933  if (element == NULL) {
1934  goto error;
1935  }
1936  if (first == NULL)
1937  first = element;
1938  else if (previous != NULL)
1939  previous->next = element;
1940  previous = element;
1941 
1942  ctxt->comp = element;
1943  ctxt->base = xmlStrndup(&pattern[start], end - start);
1944  if (ctxt->base == NULL)
1945  goto error;
1946  ctxt->cur = &(ctxt->base)[current - start];
1947  element->pattern = ctxt->base;
1948  element->node = node;
1949  element->nsList = xmlGetNsList(doc, node);
1950  j = 0;
1951  if (element->nsList != NULL) {
1952  while (element->nsList[j] != NULL)
1953  j++;
1954  }
1955  element->nsNr = j;
1956  element->novar = novar;
1957 
1958 
1959 #ifdef WITH_XSLT_DEBUG_PATTERN
1961  "xsltCompilePattern : parsing '%s'\n",
1962  element->pattern);
1963 #endif
1964  /*
1965  Preset default priority to be zero.
1966  This may be changed by xsltCompileLocationPathPattern.
1967  */
1968  element->priority = 0;
1970  if (ctxt->error) {
1972  "xsltCompilePattern : failed to compile '%s'\n",
1973  element->pattern);
1974  if (style != NULL) style->errors++;
1975  goto error;
1976  }
1977 
1978  /*
1979  * Reverse for faster interpretation.
1980  */
1982 
1983  /*
1984  * Set-up the priority
1985  */
1986  if (element->priority == 0) { /* if not yet determined */
1987  if (((element->steps[0].op == XSLT_OP_ELEM) ||
1988  (element->steps[0].op == XSLT_OP_ATTR) ||
1989  (element->steps[0].op == XSLT_OP_PI)) &&
1990  (element->steps[0].value != NULL) &&
1991  (element->steps[1].op == XSLT_OP_END)) {
1992  ; /* previously preset */
1993  } else if ((element->steps[0].op == XSLT_OP_ATTR) &&
1994  (element->steps[0].value2 != NULL) &&
1995  (element->steps[1].op == XSLT_OP_END)) {
1996  element->priority = -0.25;
1997  } else if ((element->steps[0].op == XSLT_OP_NS) &&
1998  (element->steps[0].value != NULL) &&
1999  (element->steps[1].op == XSLT_OP_END)) {
2000  element->priority = -0.25;
2001  } else if ((element->steps[0].op == XSLT_OP_ATTR) &&
2002  (element->steps[0].value == NULL) &&
2003  (element->steps[0].value2 == NULL) &&
2004  (element->steps[1].op == XSLT_OP_END)) {
2005  element->priority = -0.5;
2006  } else if (((element->steps[0].op == XSLT_OP_PI) ||
2007  (element->steps[0].op == XSLT_OP_TEXT) ||
2008  (element->steps[0].op == XSLT_OP_ALL) ||
2009  (element->steps[0].op == XSLT_OP_NODE) ||
2010  (element->steps[0].op == XSLT_OP_COMMENT)) &&
2011  (element->steps[1].op == XSLT_OP_END)) {
2012  element->priority = -0.5;
2013  } else {
2014  element->priority = 0.5;
2015  }
2016  }
2017 #ifdef WITH_XSLT_DEBUG_PATTERN
2019  "xsltCompilePattern : parsed %s, default priority %f\n",
2020  element->pattern, element->priority);
2021 #endif
2022  if (pattern[end] == '|')
2023  end++;
2024  current = end;
2025  }
2026  if (end == 0) {
2028  "xsltCompilePattern : NULL pattern\n");
2029  if (style != NULL) style->errors++;
2030  goto error;
2031  }
2032 
2033  xsltFreeParserContext(ctxt);
2034  return(first);
2035 
2036 error:
2037  if (ctxt != NULL)
2038  xsltFreeParserContext(ctxt);
2039  if (first != NULL)
2041  return(NULL);
2042 }
2043 
2063  xsltTransformContextPtr runtime) {
2064  return (xsltCompilePatternInternal(pattern, doc, node, style, runtime, 0));
2065 }
2066 
2067 /************************************************************************
2068  * *
2069  * Module interfaces *
2070  * *
2071  ************************************************************************/
2072 
2084 int
2086  const xmlChar *mode, const xmlChar *modeURI) {
2087  xsltCompMatchPtr pat, list, next;
2088  /*
2089  * 'top' will point to style->xxxMatch ptr - declaring as 'void'
2090  * avoids gcc 'type-punned pointer' warning.
2091  */
2092  void **top = NULL;
2093  const xmlChar *name = NULL;
2094  float priority; /* the priority */
2095 
2096  if ((style == NULL) || (cur == NULL))
2097  return(-1);
2098 
2099  /* Register named template */
2100  if (cur->name != NULL) {
2101  if (style->namedTemplates == NULL) {
2102  style->namedTemplates = xmlHashCreate(10);
2103  if (style->namedTemplates == NULL)
2104  return(-1);
2105  }
2106  else {
2107  void *dup = xmlHashLookup2(style->namedTemplates, cur->name,
2108  cur->nameURI);
2109  if (dup != NULL) {
2111  "xsl:template: error duplicate name '%s'\n",
2112  cur->name);
2113  style->errors++;
2114  return(-1);
2115  }
2116  }
2117 
2118  xmlHashAddEntry2(style->namedTemplates, cur->name, cur->nameURI, cur);
2119  }
2120 
2121  if (cur->match == NULL)
2122  return(0);
2123 
2124  priority = cur->priority;
2125  pat = xsltCompilePatternInternal(cur->match, style->doc, cur->elem,
2126  style, NULL, 1);
2127  if (pat == NULL)
2128  return(-1);
2129  while (pat) {
2130  next = pat->next;
2131  pat->next = NULL;
2132  name = NULL;
2133 
2134  pat->template = cur;
2135  if (mode != NULL)
2136  pat->mode = xmlDictLookup(style->dict, mode, -1);
2137  if (modeURI != NULL)
2138  pat->modeURI = xmlDictLookup(style->dict, modeURI, -1);
2140  pat->priority = priority;
2141 
2142  /*
2143  * insert it in the hash table list corresponding to its lookup name
2144  */
2145  switch (pat->steps[0].op) {
2146  case XSLT_OP_ATTR:
2147  if (pat->steps[0].value != NULL)
2148  name = pat->steps[0].value;
2149  else
2150  top = &(style->attrMatch);
2151  break;
2152  case XSLT_OP_PARENT:
2153  case XSLT_OP_ANCESTOR:
2154  top = &(style->elemMatch);
2155  break;
2156  case XSLT_OP_ROOT:
2157  top = &(style->rootMatch);
2158  break;
2159  case XSLT_OP_KEY:
2160  top = &(style->keyMatch);
2161  break;
2162  case XSLT_OP_ID:
2163  /* TODO optimize ID !!! */
2164  case XSLT_OP_NS:
2165  case XSLT_OP_ALL:
2166  top = &(style->elemMatch);
2167  break;
2168  case XSLT_OP_END:
2169  case XSLT_OP_PREDICATE:
2171  "xsltAddTemplate: invalid compiled pattern\n");
2172  xsltFreeCompMatch(pat);
2173  return(-1);
2174  /*
2175  * TODO: some flags at the top level about type based patterns
2176  * would be faster than inclusion in the hash table.
2177  */
2178  case XSLT_OP_PI:
2179  if (pat->steps[0].value != NULL)
2180  name = pat->steps[0].value;
2181  else
2182  top = &(style->piMatch);
2183  break;
2184  case XSLT_OP_COMMENT:
2185  top = &(style->commentMatch);
2186  break;
2187  case XSLT_OP_TEXT:
2188  top = &(style->textMatch);
2189  break;
2190  case XSLT_OP_ELEM:
2191  case XSLT_OP_NODE:
2192  if (pat->steps[0].value != NULL)
2193  name = pat->steps[0].value;
2194  else
2195  top = &(style->elemMatch);
2196  break;
2197  }
2198  if (name != NULL) {
2199  if (style->templatesHash == NULL) {
2200  style->templatesHash = xmlHashCreate(1024);
2201  if (style->templatesHash == NULL) {
2202  xsltFreeCompMatch(pat);
2203  return(-1);
2204  }
2205  xmlHashAddEntry3(style->templatesHash, name, mode, modeURI, pat);
2206  } else {
2207  list = (xsltCompMatchPtr) xmlHashLookup3(style->templatesHash,
2208  name, mode, modeURI);
2209  if (list == NULL) {
2210  xmlHashAddEntry3(style->templatesHash, name,
2211  mode, modeURI, pat);
2212  } else {
2213  /*
2214  * Note '<=' since one must choose among the matching
2215  * template rules that are left, the one that occurs
2216  * last in the stylesheet
2217  */
2218  if (list->priority <= pat->priority) {
2219  pat->next = list;
2220  xmlHashUpdateEntry3(style->templatesHash, name,
2221  mode, modeURI, pat, NULL);
2222  } else {
2223  while (list->next != NULL) {
2224  if (list->next->priority <= pat->priority)
2225  break;
2226  list = list->next;
2227  }
2228  pat->next = list->next;
2229  list->next = pat;
2230  }
2231  }
2232  }
2233  } else if (top != NULL) {
2234  list = *top;
2235  if (list == NULL) {
2236  *top = pat;
2237  pat->next = NULL;
2238  } else if (list->priority <= pat->priority) {
2239  pat->next = list;
2240  *top = pat;
2241  } else {
2242  while (list->next != NULL) {
2243  if (list->next->priority <= pat->priority)
2244  break;
2245  list = list->next;
2246  }
2247  pat->next = list->next;
2248  list->next = pat;
2249  }
2250  } else {
2252  "xsltAddTemplate: invalid compiled pattern\n");
2253  xsltFreeCompMatch(pat);
2254  return(-1);
2255  }
2256 #ifdef WITH_XSLT_DEBUG_PATTERN
2257  if (mode)
2259  "added pattern : '%s' mode '%s' priority %f\n",
2260  pat->pattern, pat->mode, pat->priority);
2261  else
2263  "added pattern : '%s' priority %f\n",
2264  pat->pattern, pat->priority);
2265 #endif
2266 
2267  pat = next;
2268  }
2269  return(0);
2270 }
2271 
2272 static int
2274 {
2275  if ((ctxt == NULL) || (contextNode == NULL)) {
2276  xsltTransformError(ctxt, NULL, ctxt->inst,
2277  "Internal error in xsltComputeAllKeys(): "
2278  "Bad arguments.\n");
2279  return(-1);
2280  }
2281 
2282  if (ctxt->document == NULL) {
2283  /*
2284  * The document info will only be NULL if we have a RTF.
2285  */
2286  if (contextNode->doc->_private != NULL)
2287  goto doc_info_mismatch;
2288  /*
2289  * On-demand creation of the document info (needed for keys).
2290  */
2291  ctxt->document = xsltNewDocument(ctxt, contextNode->doc);
2292  if (ctxt->document == NULL)
2293  return(-1);
2294  }
2295  return xsltInitAllDocKeys(ctxt);
2296 
2297 doc_info_mismatch:
2298  xsltTransformError(ctxt, NULL, ctxt->inst,
2299  "Internal error in xsltComputeAllKeys(): "
2300  "The context's document info doesn't match the "
2301  "document info of the current result tree.\n");
2302  ctxt->state = XSLT_STATE_STOPPED;
2303  return(-1);
2304 }
2305 
2320 {
2321  xsltStylesheetPtr curstyle;
2323  const xmlChar *name = NULL;
2325  float priority;
2326  int keyed = 0;
2327 
2328  if ((ctxt == NULL) || (node == NULL))
2329  return(NULL);
2330 
2331  if (style == NULL) {
2332  curstyle = ctxt->style;
2333  } else {
2334  curstyle = xsltNextImport(style);
2335  }
2336 
2337  while ((curstyle != NULL) && (curstyle != style)) {
2339  /* TODO : handle IDs/keys here ! */
2340  if (curstyle->templatesHash != NULL) {
2341  /*
2342  * Use the top name as selector
2343  */
2344  switch (node->type) {
2345  case XML_ELEMENT_NODE:
2346  if (node->name[0] == ' ')
2347  break;
2348  case XML_ATTRIBUTE_NODE:
2349  case XML_PI_NODE:
2350  name = node->name;
2351  break;
2352  case XML_DOCUMENT_NODE:
2354  case XML_TEXT_NODE:
2356  case XML_COMMENT_NODE:
2357  case XML_ENTITY_REF_NODE:
2358  case XML_ENTITY_NODE:
2361  case XML_NOTATION_NODE:
2362  case XML_DTD_NODE:
2363  case XML_ELEMENT_DECL:
2364  case XML_ATTRIBUTE_DECL:
2365  case XML_ENTITY_DECL:
2366  case XML_NAMESPACE_DECL:
2367  case XML_XINCLUDE_START:
2368  case XML_XINCLUDE_END:
2369  break;
2370  default:
2371  return(NULL);
2372 
2373  }
2374  }
2375  if (name != NULL) {
2376  /*
2377  * find the list of applicable expressions based on the name
2378  */
2380  name, ctxt->mode, ctxt->modeURI);
2381  } else
2382  list = NULL;
2383  while (list != NULL) {
2384  if (xsltTestCompMatch(ctxt, list, node,
2385  ctxt->mode, ctxt->modeURI)) {
2386  ret = list->template;
2387  priority = list->priority;
2388  break;
2389  }
2390  list = list->next;
2391  }
2392  list = NULL;
2393 
2394  /*
2395  * find alternate generic matches
2396  */
2397  switch (node->type) {
2398  case XML_ELEMENT_NODE:
2399  if (node->name[0] == ' ')
2400  list = curstyle->rootMatch;
2401  else
2402  list = curstyle->elemMatch;
2403  if (node->psvi != NULL) keyed = 1;
2404  break;
2405  case XML_ATTRIBUTE_NODE: {
2406  xmlAttrPtr attr;
2407 
2408  list = curstyle->attrMatch;
2409  attr = (xmlAttrPtr) node;
2410  if (attr->psvi != NULL) keyed = 1;
2411  break;
2412  }
2413  case XML_PI_NODE:
2414  list = curstyle->piMatch;
2415  if (node->psvi != NULL) keyed = 1;
2416  break;
2417  case XML_DOCUMENT_NODE:
2418  case XML_HTML_DOCUMENT_NODE: {
2419  xmlDocPtr doc;
2420 
2421  list = curstyle->rootMatch;
2422  doc = (xmlDocPtr) node;
2423  if (doc->psvi != NULL) keyed = 1;
2424  break;
2425  }
2426  case XML_TEXT_NODE:
2428  list = curstyle->textMatch;
2429  if (node->psvi != NULL) keyed = 1;
2430  break;
2431  case XML_COMMENT_NODE:
2432  list = curstyle->commentMatch;
2433  if (node->psvi != NULL) keyed = 1;
2434  break;
2435  case XML_ENTITY_REF_NODE:
2436  case XML_ENTITY_NODE:
2439  case XML_NOTATION_NODE:
2440  case XML_DTD_NODE:
2441  case XML_ELEMENT_DECL:
2442  case XML_ATTRIBUTE_DECL:
2443  case XML_ENTITY_DECL:
2444  case XML_NAMESPACE_DECL:
2445  case XML_XINCLUDE_START:
2446  case XML_XINCLUDE_END:
2447  break;
2448  default:
2449  break;
2450  }
2451  while ((list != NULL) &&
2452  ((ret == NULL) || (list->priority > priority))) {
2453  if (xsltTestCompMatch(ctxt, list, node,
2454  ctxt->mode, ctxt->modeURI)) {
2455  ret = list->template;
2456  priority = list->priority;
2457  break;
2458  }
2459  list = list->next;
2460  }
2461  /*
2462  * Some of the tests for elements can also apply to documents
2463  */
2464  if ((node->type == XML_DOCUMENT_NODE) ||
2465  (node->type == XML_HTML_DOCUMENT_NODE) ||
2466  (node->type == XML_TEXT_NODE)) {
2467  list = curstyle->elemMatch;
2468  while ((list != NULL) &&
2469  ((ret == NULL) || (list->priority > priority))) {
2470  if (xsltTestCompMatch(ctxt, list, node,
2471  ctxt->mode, ctxt->modeURI)) {
2472  ret = list->template;
2473  priority = list->priority;
2474  break;
2475  }
2476  list = list->next;
2477  }
2478  } else if ((node->type == XML_PI_NODE) ||
2479  (node->type == XML_COMMENT_NODE)) {
2480  list = curstyle->elemMatch;
2481  while ((list != NULL) &&
2482  ((ret == NULL) || (list->priority > priority))) {
2483  if (xsltTestCompMatch(ctxt, list, node,
2484  ctxt->mode, ctxt->modeURI)) {
2485  ret = list->template;
2486  priority = list->priority;
2487  break;
2488  }
2489  list = list->next;
2490  }
2491  }
2492 
2493 keyed_match:
2494  if (keyed) {
2495  list = curstyle->keyMatch;
2496  while ((list != NULL) &&
2497  ((ret == NULL) || (list->priority > priority))) {
2498  if (xsltTestCompMatch(ctxt, list, node,
2499  ctxt->mode, ctxt->modeURI)) {
2500  ret = list->template;
2501  priority = list->priority;
2502  break;
2503  }
2504  list = list->next;
2505  }
2506  }
2507  else if (ctxt->hasTemplKeyPatterns &&
2508  ((ctxt->document == NULL) ||
2509  (ctxt->document->nbKeysComputed < ctxt->nbKeys)))
2510  {
2511  /*
2512  * Compute all remaining keys for this document.
2513  *
2514  * REVISIT TODO: I think this could be further optimized.
2515  */
2516  if (xsltComputeAllKeys(ctxt, node) == -1)
2517  goto error;
2518 
2519  switch (node->type) {
2520  case XML_ELEMENT_NODE:
2521  if (node->psvi != NULL) keyed = 1;
2522  break;
2523  case XML_ATTRIBUTE_NODE:
2524  if (((xmlAttrPtr) node)->psvi != NULL) keyed = 1;
2525  break;
2526  case XML_TEXT_NODE:
2528  case XML_COMMENT_NODE:
2529  case XML_PI_NODE:
2530  if (node->psvi != NULL) keyed = 1;
2531  break;
2532  case XML_DOCUMENT_NODE:
2534  if (((xmlDocPtr) node)->psvi != NULL) keyed = 1;
2535  break;
2536  default:
2537  break;
2538  }
2539  if (keyed)
2540  goto keyed_match;
2541  }
2542  if (ret != NULL)
2543  return(ret);
2544 
2545  /*
2546  * Cycle on next curstylesheet import.
2547  */
2548  curstyle = xsltNextImport(curstyle);
2549  }
2550 
2551 error:
2552  return(NULL);
2553 }
2554 
2562 void
2564 }
2565 
2572 void
2574  if (style->templatesHash != NULL)
2575  xmlHashFree((xmlHashTablePtr) style->templatesHash,
2577  if (style->rootMatch != NULL)
2578  xsltFreeCompMatchList(style->rootMatch);
2579  if (style->keyMatch != NULL)
2580  xsltFreeCompMatchList(style->keyMatch);
2581  if (style->elemMatch != NULL)
2582  xsltFreeCompMatchList(style->elemMatch);
2583  if (style->attrMatch != NULL)
2584  xsltFreeCompMatchList(style->attrMatch);
2585  if (style->parentMatch != NULL)
2586  xsltFreeCompMatchList(style->parentMatch);
2587  if (style->textMatch != NULL)
2588  xsltFreeCompMatchList(style->textMatch);
2589  if (style->piMatch != NULL)
2590  xsltFreeCompMatchList(style->piMatch);
2591  if (style->commentMatch != NULL)
2592  xsltFreeCompMatchList(style->commentMatch);
2593  if (style->namedTemplates != NULL)
2594  xmlHashFree(style->namedTemplates, NULL);
2595 }
2596 
XMLPUBFUN int XMLCALL xmlHashAddEntry3(xmlHashTablePtr table, const xmlChar *name, const xmlChar *name2, const xmlChar *name3, void *userdata)
Definition: hash.c:529
static int xsltPatPushState(xsltTransformContextPtr ctxt, xsltStepStates *states, int step, xmlNodePtr node)
Definition: pattern.c:475
xsltOp
Definition: pattern.c:27
int indexExtra
Definition: pattern.c:77
GLint level
Definition: gl.h:1546
#define IS_EXTENDER(c)
xmlChar * value2
Definition: pattern.c:70
void xsltFreeCompMatchList(xsltCompMatchPtr comp)
Definition: pattern.c:193
const xmlChar * name
xsltOp op
Definition: pattern.c:68
LOCAL int expr(arg_t *ap, int *altp)
Definition: match.c:512
#define NXT(val)
Definition: pattern.c:1243
struct _xmlNode * prev
Definition: tree.h:497
#define error(str)
Definition: mkdosfs.c:1605
const xmlChar * name
Definition: tree.h:492
xmlNodePtr elem
Definition: pattern.c:108
xsltStepStates * xsltStepStatesPtr
Definition: pattern.c:58
Definition: match.c:28
Definition: tree.h:389
XMLPUBFUN xmlChar *XMLCALL xmlStrndup(const xmlChar *cur, int len)
Definition: xmlstring.c:41
xsltStylesheetPtr xsltNextImport(xsltStylesheetPtr cur)
Definition: imports.c:250
XMLPUBFUN int XMLCALL xmlHashAddEntry2(xmlHashTablePtr table, const xmlChar *name, const xmlChar *name2, void *userdata)
Definition: hash.c:404
int xsltAddTemplate(xsltStylesheetPtr style, xsltTemplatePtr cur, const xmlChar *mode, const xmlChar *modeURI)
Definition: pattern.c:2085
void xsltNormalizeCompSteps(void *payload, void *data, const xmlChar *name ATTRIBUTE_UNUSED)
Definition: pattern.c:218
xsltStepState * xsltStepStatePtr
Definition: pattern.c:51
const GLint * first
Definition: glext.h:5794
#define XSLT_PAT_NO_PRIORITY
static int xsltCompMatchAdd(xsltParserContextPtr ctxt, xsltCompMatchPtr comp, xsltOp op, xmlChar *value, xmlChar *value2, int novar)
Definition: pattern.c:283
const xmlChar * mode
Definition: pattern.c:85
static xmlChar * xsltScanLiteral(xsltParserContextPtr ctxt)
Definition: pattern.c:1280
GLdouble GLdouble t
Definition: gl.h:2047
xmlNodePtr elem
int xsltEvalXPathPredicate(xsltTransformContextPtr ctxt, xmlXPathCompExprPtr comp, xmlNsPtr *nsList, int nsNr)
Definition: templates.c:39
static void xsltFreeCompMatch(xsltCompMatchPtr comp)
Definition: pattern.c:160
GLuint GLuint end
Definition: gl.h:1545
#define CUR
Definition: pattern.c:1241
xmlDocPtr doc
Definition: pattern.c:107
static int xsltTestCompMatchDirect(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp, xmlNodePtr node, xmlNsPtr *nsList, int nsNr)
Definition: pattern.c:523
XMLPUBFUN int XMLCALL xmlStringCurrentChar(xmlParserCtxtPtr ctxt, const xmlChar *cur, int *len)
xmlNodePtr node
Definition: pattern.c:88
XMLPUBFUN void *XMLCALL xmlHashLookup2(xmlHashTablePtr table, const xmlChar *name, const xmlChar *name2)
Definition: hash.c:474
Definition: query.h:86
XMLPUBFUN xmlAttrPtr XMLCALL xmlGetID(xmlDocPtr doc, const xmlChar *ID)
Definition: valid.c:2803
const xmlChar * nameURI
static void xsltCompileIdKeyPattern(xsltParserContextPtr ctxt, xmlChar *name, int aid, int novar, xsltAxis axis)
Definition: pattern.c:1379
struct _xmlDoc * doc
Definition: tree.h:498
xmlXPathCompExprPtr comp
Definition: pattern.c:72
xsltCompMatchPtr comp
Definition: pattern.c:110
static int xsltTestPredicateMatch(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp, xmlNodePtr node, xsltStepOpPtr step, xsltStepOpPtr sel)
Definition: pattern.c:634
struct _xsltParserContext xsltParserContext
Definition: pattern.c:100
#define PUSH(op, val, val2, novar)
Definition: pattern.c:1253
struct node node
#define IS_COMBINING(c)
void xsltFreeTemplateHashes(xsltStylesheetPtr style)
Definition: pattern.c:2573
xsltTemplatePtr xsltGetTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node, xsltStylesheetPtr style)
Definition: pattern.c:2318
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
static void xmlXPathFreeObjectWrapper(void *obj)
Definition: pattern.c:505
static xmlChar * xsltScanNCName(xsltParserContextPtr ctxt)
Definition: pattern.c:1336
xsltParserContext * xsltParserContextPtr
Definition: pattern.c:101
XMLPUBFUN void XMLCALL xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f)
Definition: hash.c:320
#define XSLT_RUNTIME_EXTRA_LST(ctxt, nr)
xmlGenericErrorFunc xsltGenericError
Definition: xsltutils.c:502
_Check_return_opt_ _CRTIMP int __cdecl fprintf(_Inout_ FILE *_File, _In_z_ _Printf_format_string_ const char *_Format,...)
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
XMLPUBFUN xmlChar *XMLCALL xmlStrcat(xmlChar *cur, const xmlChar *add)
Definition: xmlstring.c:526
#define IS_BLANK_CH(c)
xsltTransformState state
#define IS_CHAR(c)
static PVOID ptr
Definition: dispmode.c:27
XMLPUBFUN xmlNsPtr XMLCALL xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace)
static DWORD DWORD DWORD DWORD * steps
Definition: cursoricon.c:1521
smooth NULL
Definition: ftsmooth.c:416
xmlChar * value
Definition: pattern.c:69
struct _xsltCompMatch * next
Definition: pattern.c:82
static void xsltCompileStepPattern(xsltParserContextPtr ctxt, xmlChar *token, int novar)
Definition: pattern.c:1560
xmlNode * xmlNodePtr
Definition: tree.h:488
xsltDocumentPtr document
struct match match
Definition: match.c:33
xmlXPathContextPtr xpathCtxt
static int xsltTestCompMatch(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp, xmlNodePtr matchNode, const xmlChar *mode, const xmlChar *modeURI)
Definition: pattern.c:908
XMLPUBFUN void *XMLCALL xmlHashLookup3(xmlHashTablePtr table, const xmlChar *name, const xmlChar *name2, const xmlChar *name3)
Definition: hash.c:767
XMLPUBVAR xmlReallocFunc xmlRealloc
Definition: globals.h:249
const xmlChar * modeURI
Definition: pattern.c:86
GLuint GLfloat * val
Definition: glext.h:7180
struct _xmlNode * parent
Definition: tree.h:495
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
const xmlChar * modeURI
int xsltTestCompMatchList(xsltTransformContextPtr ctxt, xmlNodePtr node, xsltCompMatchPtr comp)
Definition: pattern.c:1220
void * psvi
Definition: tree.h:581
void * xsltGenericDebugContext
Definition: xsltutils.c:549
xmlNodeSetPtr xsltGetKey(xsltTransformContextPtr ctxt, const xmlChar *name, const xmlChar *nameURI, const xmlChar *value)
Definition: keys.c:415
r parent
Definition: btrfs.c:2897
static void xsltCompileRelativePathPattern(xsltParserContextPtr ctxt, xmlChar *token, int novar)
Definition: pattern.c:1763
static xsltCompMatchPtr xsltCompilePatternInternal(const xmlChar *pattern, xmlDocPtr doc, xmlNodePtr node, xsltStylesheetPtr style, xsltTransformContextPtr runtime, int novar)
Definition: pattern.c:1884
static void xsltSwapTopCompMatch(xsltCompMatchPtr comp)
Definition: pattern.c:358
struct list * next
Definition: list.h:38
XMLPUBVAR xmlFreeFunc xmlFree
Definition: globals.h:250
XMLPUBFUN const xmlChar *XMLCALL xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len)
Definition: dict.c:858
Definition: cookie.c:170
GLdouble GLdouble GLdouble GLdouble q
Definition: gl.h:2063
#define CUR_PTR
Definition: pattern.c:1244
float priority
Definition: pattern.c:83
xmlGenericErrorFunc xsltGenericDebug
Definition: xsltutils.c:548
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
static void xsltFreeParserContext(xsltParserContextPtr ctxt)
Definition: pattern.c:263
const xmlChar * pattern
Definition: pattern.c:84
xsltCompMatch * xsltCompMatchPtr
Definition: pattern.h:29
XMLPUBFUN xmlHashTablePtr XMLCALL xmlHashCreate(int size)
Definition: hash.c:174
void * xsltGenericErrorContext
Definition: xsltutils.c:503
static xsltParserContextPtr xsltNewParserContext(xsltStylesheetPtr style, xsltTransformContextPtr ctxt)
Definition: pattern.c:241
Definition: tree.h:489
XMLPUBFUN int XMLCALL xmlHashUpdateEntry3(xmlHashTablePtr table, const xmlChar *name, const xmlChar *name2, const xmlChar *name3, void *userdata, xmlHashDeallocator f)
Definition: hash.c:645
int ret
xmlAttr * xmlAttrPtr
Definition: tree.h:433
xmlNodePtr node
Definition: pattern.c:54
#define ATTRIBUTE_UNUSED
Definition: win32config.h:132
#define XSLT_RUNTIME_EXTRA(ctxt, nr, typ)
__u8 attr
Definition: mkdosfs.c:359
Definition: mxnamespace.c:44
xsltStepOpPtr steps
Definition: pattern.c:96
unsigned char xmlChar
Definition: xmlstring.h:28
GLenum GLsizei len
Definition: glext.h:6722
Definition: _list.h:228
#define LIBXML_DOCB_ENABLED
Definition: xmlversion.h:241
xsltStepOp * xsltStepOpPtr
Definition: pattern.c:66
GLenum mode
Definition: glext.h:6217
xsltTransformContextPtr ctxt
Definition: pattern.c:104
xsltAxis
Definition: pattern.c:45
GLsizei const GLfloat * value
Definition: glext.h:6069
#define XSLT_RUNTIME_EXTRA_FREE(ctxt, nr)
xmlElementType type
Definition: tree.h:491
#define SWAP()
Definition: pattern.c:1256
int xsltAllocateExtraCtxt(xsltTransformContextPtr ctxt)
Definition: xslt.c:809
int lenExtra
Definition: pattern.c:78
#define IS_LETTER(c)
xmlDoc * xmlDocPtr
Definition: tree.h:550
const xmlChar * base
Definition: pattern.c:106
const xmlChar * cur
Definition: pattern.c:105
xsltStylesheetPtr style
static unsigned __int64 next
Definition: rand_nt.c:6
static int xsltComputeAllKeys(xsltTransformContextPtr ctxt, xmlNodePtr contextNode)
Definition: pattern.c:2273
int xsltInitAllDocKeys(xsltTransformContextPtr ctxt)
Definition: keys.c:533
xsltStylesheetPtr style
Definition: pattern.c:103
#define XSLT_IS_RES_TREE_FRAG(n)
Definition: xsltInternals.h:56
const xmlChar * mode
xmlChar * value3
Definition: pattern.c:71
struct _xmlNode * next
Definition: tree.h:496
GLuint start
Definition: gl.h:1545
static void xsltFreeCompMatchListEntry(void *payload, const xmlChar *name ATTRIBUTE_UNUSED)
Definition: pattern.c:204
int xsltAllocateExtra(xsltStylesheetPtr style)
Definition: xslt.c:793
#define list
Definition: rosglue.h:35
xsltCompMatchPtr xsltCompilePattern(const xmlChar *pattern, xmlDocPtr doc, xmlNodePtr node, xsltStylesheetPtr style, xsltTransformContextPtr runtime)
Definition: pattern.c:2061
_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:1301
XMLPUBVAR xmlMallocFunc xmlMalloc
Definition: globals.h:247
Definition: tree.h:551
#define IS_DIGIT(c)
void xsltCleanupTemplates(xsltStylesheetPtr style ATTRIBUTE_UNUSED)
Definition: pattern.c:2563
Definition: tree.h:434
Definition: name.c:36
_Check_return_ _CRTIMP int __cdecl dup(_In_ int _FileHandle)
xmlNsPtr * nsList
Definition: pattern.c:94
GLenum GLuint id
Definition: glext.h:5579
FILE * stderr
static int priority
Definition: timer.c:163
UINT op
Definition: effect.c:223
static void xsltCompileLocationPathPattern(xsltParserContextPtr ctxt, int novar)
Definition: pattern.c:1806
static void xsltReverseCompMatch(xsltParserContextPtr ctxt, xsltCompMatchPtr comp)
Definition: pattern.c:403
xmlNs * ns
Definition: tree.h:501
GLdouble GLdouble GLdouble GLdouble top
Definition: glext.h:10859
xsltTemplatePtr template
Definition: pattern.c:87
xmlChar * match
XMLPUBFUN int XMLCALL xmlStrEqual(const xmlChar *str1, const xmlChar *str2)
Definition: xmlstring.c:157
void exit(int exitcode)
Definition: _exit.c:33
#define NEXT
Definition: pattern.c:1250
void xsltTransformError(xsltTransformContextPtr ctxt, xsltStylesheetPtr style, xmlNodePtr node, const char *msg,...)
Definition: xsltutils.c:678
xsltStepStatePtr states
Definition: pattern.c:62
Arabic default style
Definition: afstyles.h:93
const xmlChar * href
Definition: tree.h:392
#define memset(x, y, z)
Definition: compat.h:39
int previousExtra
Definition: pattern.c:76
GLenum query
Definition: glext.h:7781
XMLPUBFUN xmlChar *XMLCALL xmlStrdup(const xmlChar *cur)
Definition: xmlstring.c:66
#define SKIP_BLANKS
Definition: pattern.c:1246
xsltDocumentPtr xsltNewDocument(xsltTransformContextPtr ctxt, xmlDocPtr doc)
Definition: documents.c:127
struct task_struct * current
Definition: linux.c:32
static xsltCompMatchPtr xsltNewCompMatch(void)
Definition: pattern.c:127
GLubyte * pattern
Definition: glext.h:7787
Definition: dlist.c:348
GLuint const GLchar * name
Definition: glext.h:6031
const xmlChar * xsltGetQNameURI(xmlNodePtr node, xmlChar **name)
Definition: xsltutils.c:753