Coverage Report

Created: 2024-01-17 17:02

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