Coverage Report

Created: 2025-07-11 06:13

/src/libxslt/libxslt/transform.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * transform.c: Implementation of the XSL Transformation 1.0 engine
3
 *              transform part, i.e. applying a Stylesheet to a document
4
 *
5
 * References:
6
 *   http://www.w3.org/TR/1999/REC-xslt-19991116
7
 *
8
 *   Michael Kay "XSLT Programmer's Reference" pp 637-643
9
 *   Writing Multiple Output Files
10
 *
11
 *   XSLT-1.1 Working Draft
12
 *   http://www.w3.org/TR/xslt11#multiple-output
13
 *
14
 * See Copyright for the status of this software.
15
 *
16
 * daniel@veillard.com
17
 */
18
19
#define IN_LIBXSLT
20
#include "libxslt.h"
21
22
#include <limits.h>
23
#include <string.h>
24
#include <stdio.h>
25
#include <stddef.h>
26
27
#include <libxml/xmlmemory.h>
28
#include <libxml/parser.h>
29
#include <libxml/tree.h>
30
#include <libxml/valid.h>
31
#include <libxml/hash.h>
32
#include <libxml/encoding.h>
33
#include <libxml/xmlerror.h>
34
#include <libxml/xpath.h>
35
#include <libxml/parserInternals.h>
36
#include <libxml/xpathInternals.h>
37
#include <libxml/HTMLtree.h>
38
#include <libxml/debugXML.h>
39
#include <libxml/uri.h>
40
#include "xslt.h"
41
#include "xsltInternals.h"
42
#include "xsltutils.h"
43
#include "xsltlocale.h"
44
#include "pattern.h"
45
#include "transform.h"
46
#include "variables.h"
47
#include "numbersInternals.h"
48
#include "namespaces.h"
49
#include "attributes.h"
50
#include "templates.h"
51
#include "imports.h"
52
#include "keys.h"
53
#include "documents.h"
54
#include "extensions.h"
55
#include "extra.h"
56
#include "preproc.h"
57
#include "security.h"
58
59
#ifdef WITH_XSLT_DEBUG
60
#define WITH_XSLT_DEBUG_EXTRA
61
#define WITH_XSLT_DEBUG_PROCESS
62
#define WITH_XSLT_DEBUG_VARIABLE
63
#endif
64
65
#define XSLT_GENERATE_HTML_DOCTYPE
66
#ifdef XSLT_GENERATE_HTML_DOCTYPE
67
static int xsltGetHTMLIDs(const xmlChar *version, const xmlChar **publicID,
68
        const xmlChar **systemID);
69
#endif
70
71
int xsltMaxDepth = 3000;
72
int xsltMaxVars = 15000;
73
74
/*
75
 * Useful macros
76
 */
77
78
#ifndef FALSE
79
# define FALSE (0 == 1)
80
# define TRUE (!FALSE)
81
#endif
82
83
#define IS_BLANK_NODE(n)            \
84
64.9k
    (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
85
86
87
/*
88
* Forward declarations
89
*/
90
91
static xmlNsPtr
92
xsltCopyNamespaceListInternal(xmlNodePtr node, xmlNsPtr cur);
93
94
static xmlNodePtr
95
xsltCopyTree(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,
96
       xmlNodePtr node, xmlNodePtr insert, int isLRE,
97
       int topElemVisited);
98
99
static void
100
xsltApplySequenceConstructor(xsltTransformContextPtr ctxt,
101
           xmlNodePtr contextNode, xmlNodePtr list,
102
           xsltTemplatePtr templ);
103
104
static void
105
xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt,
106
          xmlNodePtr contextNode,
107
          xmlNodePtr list,
108
          xsltTemplatePtr templ,
109
          xsltStackElemPtr withParams);
110
111
/**
112
 * templPush:
113
 * @ctxt: the transformation context
114
 * @value:  the template to push on the stack
115
 *
116
 * Push a template on the stack
117
 *
118
 * Returns the new index in the stack or 0 in case of error
119
 */
120
static int
121
templPush(xsltTransformContextPtr ctxt, xsltTemplatePtr value)
122
523k
{
123
523k
    if (ctxt->templNr >= ctxt->templMax) {
124
5.23k
        xsltTemplatePtr *tmp;
125
5.23k
        int newMax = ctxt->templMax == 0 ? 4 : ctxt->templMax * 2;
126
127
5.23k
        tmp = (xsltTemplatePtr *) xmlRealloc(ctxt->templTab,
128
5.23k
                newMax * sizeof(*tmp));
129
5.23k
        if (tmp == NULL) {
130
15
            xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
131
15
            return (0);
132
15
        }
133
5.21k
        ctxt->templTab = tmp;
134
5.21k
        ctxt->templMax = newMax;
135
5.21k
    }
136
523k
    ctxt->templTab[ctxt->templNr] = value;
137
523k
    ctxt->templ = value;
138
523k
    return (ctxt->templNr++);
139
523k
}
140
/**
141
 * templPop:
142
 * @ctxt: the transformation context
143
 *
144
 * Pop a template value from the stack
145
 *
146
 * Returns the stored template value
147
 */
148
static xsltTemplatePtr
149
templPop(xsltTransformContextPtr ctxt)
150
523k
{
151
523k
    xsltTemplatePtr ret;
152
153
523k
    if (ctxt->templNr <= 0)
154
15
        return (0);
155
523k
    ctxt->templNr--;
156
523k
    if (ctxt->templNr > 0)
157
441k
        ctxt->templ = ctxt->templTab[ctxt->templNr - 1];
158
81.6k
    else
159
81.6k
        ctxt->templ = (xsltTemplatePtr) 0;
160
523k
    ret = ctxt->templTab[ctxt->templNr];
161
523k
    ctxt->templTab[ctxt->templNr] = 0;
162
523k
    return (ret);
163
523k
}
164
165
/**
166
 * xsltLocalVariablePop:
167
 * @ctxt: the transformation context
168
 * @limitNr: number of variables which should remain
169
 * @level: the depth in the xsl:template's tree
170
 *
171
 * Pops all variable values at the given @depth from the stack.
172
 *
173
 * Returns the stored variable value
174
 * **NOTE:**
175
 * This is an internal routine and should not be called by users!
176
 */
177
void
178
xsltLocalVariablePop(xsltTransformContextPtr ctxt, int limitNr, int level)
179
66.5k
{
180
66.5k
    xsltStackElemPtr variable;
181
182
66.5k
    if (ctxt->varsNr <= 0)
183
19.2k
        return;
184
185
91.8k
    do {
186
91.8k
  if (ctxt->varsNr <= limitNr)
187
39.0k
      break;
188
52.7k
  variable = ctxt->varsTab[ctxt->varsNr - 1];
189
52.7k
  if (variable->level <= level)
190
20
      break;
191
52.7k
  if (variable->level >= 0)
192
40.0k
      xsltFreeStackElemList(variable);
193
52.7k
  ctxt->varsNr--;
194
52.7k
    } while (ctxt->varsNr != 0);
195
47.3k
    if (ctxt->varsNr > 0)
196
39.1k
        ctxt->vars = ctxt->varsTab[ctxt->varsNr - 1];
197
8.18k
    else
198
8.18k
        ctxt->vars = NULL;
199
47.3k
}
200
201
/**
202
 * xsltTemplateParamsCleanup:
203
 *
204
 * Removes xsl:param and xsl:with-param items from the
205
 * variable-stack. Only xsl:with-param items are not freed.
206
 */
207
static void
208
xsltTemplateParamsCleanup(xsltTransformContextPtr ctxt)
209
4.29k
{
210
4.29k
    xsltStackElemPtr param;
211
212
12.4k
    for (; ctxt->varsNr > ctxt->varsBase; ctxt->varsNr--) {
213
8.14k
  param = ctxt->varsTab[ctxt->varsNr -1];
214
  /*
215
  * Free xsl:param items.
216
  * xsl:with-param items will have a level of -1 or -2.
217
  */
218
8.14k
  if (param->level >= 0) {
219
7.06k
      xsltFreeStackElemList(param);
220
7.06k
  }
221
8.14k
    }
222
4.29k
    if (ctxt->varsNr > 0)
223
3.91k
        ctxt->vars = ctxt->varsTab[ctxt->varsNr - 1];
224
374
    else
225
374
        ctxt->vars = NULL;
226
4.29k
}
227
228
#ifdef WITH_PROFILER
229
230
/**
231
 * profPush:
232
 * @ctxt: the transformation context
233
 * @value:  the profiling value to push on the stack
234
 *
235
 * Push a profiling value on the stack
236
 *
237
 * Returns the new index in the stack or 0 in case of error
238
 */
239
static int
240
profPush(xsltTransformContextPtr ctxt, long value)
241
{
242
    if (ctxt->profMax == 0) {
243
        ctxt->profMax = 4;
244
        ctxt->profTab =
245
            (long *) xmlMalloc(ctxt->profMax * sizeof(ctxt->profTab[0]));
246
        if (ctxt->profTab == NULL) {
247
            xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
248
            return (0);
249
        }
250
    }
251
    else if (ctxt->profNr >= ctxt->profMax) {
252
        ctxt->profMax *= 2;
253
        ctxt->profTab =
254
            (long *) xmlRealloc(ctxt->profTab,
255
                                ctxt->profMax * sizeof(ctxt->profTab[0]));
256
        if (ctxt->profTab == NULL) {
257
            xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
258
            return (0);
259
        }
260
    }
261
    ctxt->profTab[ctxt->profNr] = value;
262
    ctxt->prof = value;
263
    return (ctxt->profNr++);
264
}
265
/**
266
 * profPop:
267
 * @ctxt: the transformation context
268
 *
269
 * Pop a profiling value from the stack
270
 *
271
 * Returns the stored profiling value
272
 */
273
static long
274
profPop(xsltTransformContextPtr ctxt)
275
{
276
    long ret;
277
278
    if (ctxt->profNr <= 0)
279
        return (0);
280
    ctxt->profNr--;
281
    if (ctxt->profNr > 0)
282
        ctxt->prof = ctxt->profTab[ctxt->profNr - 1];
283
    else
284
        ctxt->prof = (long) 0;
285
    ret = ctxt->profTab[ctxt->profNr];
286
    ctxt->profTab[ctxt->profNr] = 0;
287
    return (ret);
288
}
289
290
static void
291
profCallgraphAdd(xsltTemplatePtr templ, xsltTemplatePtr parent)
292
{
293
    int i;
294
295
    if (templ->templMax == 0) {
296
        templ->templMax = 4;
297
        templ->templCalledTab =
298
            (xsltTemplatePtr *) xmlMalloc(templ->templMax *
299
                                          sizeof(templ->templCalledTab[0]));
300
        templ->templCountTab =
301
            (int *) xmlMalloc(templ->templMax *
302
                                          sizeof(templ->templCountTab[0]));
303
        if (templ->templCalledTab == NULL || templ->templCountTab == NULL) {
304
            xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
305
            return;
306
        }
307
    }
308
    else if (templ->templNr >= templ->templMax) {
309
        templ->templMax *= 2;
310
        templ->templCalledTab =
311
            (xsltTemplatePtr *) xmlRealloc(templ->templCalledTab,
312
                                           templ->templMax *
313
                                           sizeof(templ->templCalledTab[0]));
314
        templ->templCountTab =
315
            (int *) xmlRealloc(templ->templCountTab,
316
                                           templ->templMax *
317
                                           sizeof(templ->templCountTab[0]));
318
        if (templ->templCalledTab == NULL || templ->templCountTab == NULL) {
319
            xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
320
            return;
321
        }
322
    }
323
324
    for (i = 0; i < templ->templNr; i++) {
325
        if (templ->templCalledTab[i] == parent) {
326
            templ->templCountTab[i]++;
327
            break;
328
        }
329
    }
330
    if (i == templ->templNr) {
331
        /* not found, add new one */
332
        templ->templCalledTab[templ->templNr] = parent;
333
        templ->templCountTab[templ->templNr] = 1;
334
        templ->templNr++;
335
    }
336
}
337
338
#endif /* WITH_PROFILER */
339
340
/**
341
 * xsltPreCompEval:
342
 * @ctxt: transform context
343
 * @node: context node
344
 * @comp: precompiled expression
345
 *
346
 * Evaluate a precompiled XPath expression.
347
 */
348
static xmlXPathObjectPtr
349
xsltPreCompEval(xsltTransformContextPtr ctxt, xmlNodePtr node,
350
452k
                xsltStylePreCompPtr comp) {
351
452k
    xmlXPathObjectPtr res;
352
452k
    xmlXPathContextPtr xpctxt;
353
452k
    xmlNodePtr oldXPContextNode;
354
452k
    xmlNsPtr *oldXPNamespaces;
355
452k
    int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
356
357
452k
    xpctxt = ctxt->xpathCtxt;
358
452k
    oldXPContextNode = xpctxt->node;
359
452k
    oldXPProximityPosition = xpctxt->proximityPosition;
360
452k
    oldXPContextSize = xpctxt->contextSize;
361
452k
    oldXPNsNr = xpctxt->nsNr;
362
452k
    oldXPNamespaces = xpctxt->namespaces;
363
364
452k
    xpctxt->node = node;
365
#ifdef XSLT_REFACTORED
366
    if (comp->inScopeNs != NULL) {
367
        xpctxt->namespaces = comp->inScopeNs->list;
368
        xpctxt->nsNr = comp->inScopeNs->xpathNumber;
369
    } else {
370
        xpctxt->namespaces = NULL;
371
        xpctxt->nsNr = 0;
372
    }
373
#else
374
452k
    xpctxt->namespaces = comp->nsList;
375
452k
    xpctxt->nsNr = comp->nsNr;
376
452k
#endif
377
378
452k
    res = xmlXPathCompiledEval(comp->comp, xpctxt);
379
380
452k
    xpctxt->node = oldXPContextNode;
381
452k
    xpctxt->proximityPosition = oldXPProximityPosition;
382
452k
    xpctxt->contextSize = oldXPContextSize;
383
452k
    xpctxt->nsNr = oldXPNsNr;
384
452k
    xpctxt->namespaces = oldXPNamespaces;
385
386
452k
    return(res);
387
452k
}
388
389
/**
390
 * xsltPreCompEvalToBoolean:
391
 * @ctxt: transform context
392
 * @node: context node
393
 * @comp: precompiled expression
394
 *
395
 * Evaluate a precompiled XPath expression as boolean.
396
 */
397
static int
398
xsltPreCompEvalToBoolean(xsltTransformContextPtr ctxt, xmlNodePtr node,
399
20.0k
                         xsltStylePreCompPtr comp) {
400
20.0k
    int res;
401
20.0k
    xmlXPathContextPtr xpctxt;
402
20.0k
    xmlNodePtr oldXPContextNode;
403
20.0k
    xmlNsPtr *oldXPNamespaces;
404
20.0k
    int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
405
406
20.0k
    xpctxt = ctxt->xpathCtxt;
407
20.0k
    oldXPContextNode = xpctxt->node;
408
20.0k
    oldXPProximityPosition = xpctxt->proximityPosition;
409
20.0k
    oldXPContextSize = xpctxt->contextSize;
410
20.0k
    oldXPNsNr = xpctxt->nsNr;
411
20.0k
    oldXPNamespaces = xpctxt->namespaces;
412
413
20.0k
    xpctxt->node = node;
414
#ifdef XSLT_REFACTORED
415
    if (comp->inScopeNs != NULL) {
416
        xpctxt->namespaces = comp->inScopeNs->list;
417
        xpctxt->nsNr = comp->inScopeNs->xpathNumber;
418
    } else {
419
        xpctxt->namespaces = NULL;
420
        xpctxt->nsNr = 0;
421
    }
422
#else
423
20.0k
    xpctxt->namespaces = comp->nsList;
424
20.0k
    xpctxt->nsNr = comp->nsNr;
425
20.0k
#endif
426
427
20.0k
    res = xmlXPathCompiledEvalToBoolean(comp->comp, xpctxt);
428
429
20.0k
    xpctxt->node = oldXPContextNode;
430
20.0k
    xpctxt->proximityPosition = oldXPProximityPosition;
431
20.0k
    xpctxt->contextSize = oldXPContextSize;
432
20.0k
    xpctxt->nsNr = oldXPNsNr;
433
20.0k
    xpctxt->namespaces = oldXPNamespaces;
434
435
20.0k
    return(res);
436
20.0k
}
437
438
/************************************************************************
439
 *                  *
440
 *      XInclude default settings     *
441
 *                  *
442
 ************************************************************************/
443
444
static int xsltDoXIncludeDefault = 0;
445
446
/**
447
 * xsltSetXIncludeDefault:
448
 * @xinclude: whether to do XInclude processing
449
 *
450
 * Set whether XInclude should be processed on document being loaded by default
451
 */
452
void
453
0
xsltSetXIncludeDefault(int xinclude) {
454
0
    xsltDoXIncludeDefault = (xinclude != 0);
455
0
}
456
457
/**
458
 * xsltGetXIncludeDefault:
459
 *
460
 * Provides the default state for XInclude processing
461
 *
462
 * Returns 0 if there is no processing 1 otherwise
463
 */
464
int
465
17.1k
xsltGetXIncludeDefault(void) {
466
17.1k
    return(xsltDoXIncludeDefault);
467
17.1k
}
468
469
static unsigned long xsltDefaultTrace = (unsigned long) XSLT_TRACE_ALL;
470
471
/**
472
 * xsltDebugSetDefaultTrace:
473
 * @val: tracing level mask
474
 *
475
 * Set the default debug tracing level mask
476
 */
477
0
void xsltDebugSetDefaultTrace(xsltDebugTraceCodes val) {
478
0
  xsltDefaultTrace = val;
479
0
}
480
481
/**
482
 * xsltDebugGetDefaultTrace:
483
 *
484
 * Get the current default debug tracing level mask
485
 *
486
 * Returns the current default debug tracing level mask
487
 */
488
0
xsltDebugTraceCodes xsltDebugGetDefaultTrace(void) {
489
0
  return xsltDefaultTrace;
490
0
}
491
492
/************************************************************************
493
 *                  *
494
 *      Handling of Transformation Contexts   *
495
 *                  *
496
 ************************************************************************/
497
498
static xsltTransformCachePtr
499
xsltTransformCacheCreate(void)
500
17.2k
{
501
17.2k
    xsltTransformCachePtr ret;
502
503
17.2k
    ret = (xsltTransformCachePtr) xmlMalloc(sizeof(xsltTransformCache));
504
17.2k
    if (ret == NULL) {
505
2
  xsltTransformError(NULL, NULL, NULL,
506
2
      "xsltTransformCacheCreate : malloc failed\n");
507
2
  return(NULL);
508
2
    }
509
17.2k
    memset(ret, 0, sizeof(xsltTransformCache));
510
17.2k
    return(ret);
511
17.2k
}
512
513
static void
514
xsltTransformCacheFree(xsltTransformCachePtr cache)
515
17.2k
{
516
17.2k
    if (cache == NULL)
517
2
  return;
518
    /*
519
    * Free tree fragments.
520
    */
521
17.2k
    if (cache->RVT) {
522
4.13k
  xmlDocPtr tmp, cur = cache->RVT;
523
62.9k
  while (cur) {
524
58.8k
      tmp = cur;
525
58.8k
      cur = (xmlDocPtr) cur->next;
526
58.8k
      if (tmp->_private != NULL) {
527
    /*
528
    * Tree the document info.
529
    */
530
0
    xsltFreeDocumentKeys((xsltDocumentPtr) tmp->_private);
531
0
    xmlFree(tmp->_private);
532
0
      }
533
58.8k
      xmlFreeDoc(tmp);
534
58.8k
  }
535
4.13k
    }
536
    /*
537
    * Free vars/params.
538
    */
539
17.2k
    if (cache->stackItems) {
540
1.90k
  xsltStackElemPtr tmp, cur = cache->stackItems;
541
24.8k
  while (cur) {
542
22.9k
      tmp = cur;
543
22.9k
      cur = cur->next;
544
      /*
545
      * REVISIT TODO: Should be call a destruction-function
546
      * instead?
547
      */
548
22.9k
      xmlFree(tmp);
549
22.9k
  }
550
1.90k
    }
551
17.2k
    xmlFree(cache);
552
17.2k
}
553
554
/**
555
 * xsltNewTransformContext:
556
 * @style:  a parsed XSLT stylesheet
557
 * @doc:  the input document
558
 *
559
 * Create a new XSLT TransformContext
560
 *
561
 * Returns the newly allocated xsltTransformContextPtr or NULL in case of error
562
 */
563
xsltTransformContextPtr
564
17.3k
xsltNewTransformContext(xsltStylesheetPtr style, xmlDocPtr doc) {
565
17.3k
    xsltTransformContextPtr cur;
566
17.3k
    xsltDocumentPtr docu;
567
17.3k
    int i;
568
569
17.3k
    xsltInitGlobals();
570
571
17.3k
    cur = (xsltTransformContextPtr) xmlMalloc(sizeof(xsltTransformContext));
572
17.3k
    if (cur == NULL) {
573
78
  xsltTransformError(NULL, NULL, (xmlNodePtr)doc,
574
78
    "xsltNewTransformContext : malloc failed\n");
575
78
  return(NULL);
576
78
    }
577
17.2k
    memset(cur, 0, sizeof(xsltTransformContext));
578
579
17.2k
    cur->cache = xsltTransformCacheCreate();
580
17.2k
    if (cur->cache == NULL)
581
2
  goto internal_err;
582
    /*
583
     * setup of the dictionary must be done early as some of the
584
     * processing later like key handling may need it.
585
     */
586
17.2k
    cur->dict = xmlDictCreateSub(style->dict);
587
17.2k
    cur->internalized = ((style->internalized) && (cur->dict != NULL));
588
#ifdef WITH_XSLT_DEBUG
589
    xsltGenericDebug(xsltGenericDebugContext,
590
       "Creating sub-dictionary from stylesheet for transformation\n");
591
#endif
592
593
    /*
594
     * initialize the template stack
595
     */
596
17.2k
    cur->templTab = (xsltTemplatePtr *)
597
17.2k
          xmlMalloc(10 * sizeof(xsltTemplatePtr));
598
17.2k
    if (cur->templTab == NULL) {
599
4
  xsltTransformError(NULL, NULL, (xmlNodePtr) doc,
600
4
    "xsltNewTransformContext: out of memory\n");
601
4
  goto internal_err;
602
4
    }
603
17.2k
    cur->templNr = 0;
604
17.2k
    cur->templMax = 5;
605
17.2k
    cur->templ = NULL;
606
17.2k
    cur->maxTemplateDepth = xsltMaxDepth;
607
608
    /*
609
     * initialize the variables stack
610
     */
611
17.2k
    cur->varsTab = (xsltStackElemPtr *)
612
17.2k
          xmlMalloc(10 * sizeof(xsltStackElemPtr));
613
17.2k
    if (cur->varsTab == NULL) {
614
2
        xmlGenericError(xmlGenericErrorContext,
615
2
    "xsltNewTransformContext: out of memory\n");
616
2
  goto internal_err;
617
2
    }
618
17.2k
    cur->varsNr = 0;
619
17.2k
    cur->varsMax = 10;
620
17.2k
    cur->vars = NULL;
621
17.2k
    cur->varsBase = 0;
622
17.2k
    cur->maxTemplateVars = xsltMaxVars;
623
624
    /*
625
     * the profiling stack is not initialized by default
626
     */
627
17.2k
    cur->profTab = NULL;
628
17.2k
    cur->profNr = 0;
629
17.2k
    cur->profMax = 0;
630
17.2k
    cur->prof = 0;
631
632
17.2k
    cur->style = style;
633
17.2k
    cur->xpathCtxt = xmlXPathNewContext(doc);
634
17.2k
    if (cur->xpathCtxt == NULL) {
635
2
  xsltTransformError(NULL, NULL, (xmlNodePtr) doc,
636
2
    "xsltNewTransformContext : xmlXPathNewContext failed\n");
637
2
  goto internal_err;
638
2
    }
639
    /*
640
    * Create an XPath cache.
641
    */
642
17.2k
    if (xmlXPathContextSetCache(cur->xpathCtxt, 1, -1, 0) == -1)
643
1
  goto internal_err;
644
    /*
645
     * Initialize the extras array
646
     */
647
17.2k
    if (style->extrasNr != 0) {
648
17.1k
  cur->extrasMax = style->extrasNr + 20;
649
17.1k
  cur->extras = (xsltRuntimeExtraPtr)
650
17.1k
      xmlMalloc(cur->extrasMax * sizeof(xsltRuntimeExtra));
651
17.1k
  if (cur->extras == NULL) {
652
3
      xmlGenericError(xmlGenericErrorContext,
653
3
        "xsltNewTransformContext: out of memory\n");
654
3
      goto internal_err;
655
3
  }
656
17.1k
  cur->extrasNr = style->extrasNr;
657
580k
  for (i = 0;i < cur->extrasMax;i++) {
658
563k
      cur->extras[i].info = NULL;
659
563k
      cur->extras[i].deallocate = NULL;
660
563k
      cur->extras[i].val.ptr = NULL;
661
563k
  }
662
17.1k
    } else {
663
133
  cur->extras = NULL;
664
133
  cur->extrasNr = 0;
665
133
  cur->extrasMax = 0;
666
133
    }
667
668
17.2k
    XSLT_REGISTER_VARIABLE_LOOKUP(cur);
669
17.2k
    XSLT_REGISTER_FUNCTION_LOOKUP(cur);
670
17.2k
    cur->xpathCtxt->nsHash = style->nsHash;
671
    /*
672
     * Initialize the registered external modules
673
     */
674
17.2k
    xsltInitCtxtExts(cur);
675
    /*
676
     * Setup document element ordering for later efficiencies
677
     * (bug 133289)
678
     */
679
17.2k
    if (xslDebugStatus == XSLT_DEBUG_NONE)
680
17.2k
        xmlXPathOrderDocElems(doc);
681
    /*
682
     * Must set parserOptions before calling xsltNewDocument
683
     * (bug 164530)
684
     */
685
17.2k
    cur->parserOptions = XSLT_PARSE_OPTIONS;
686
17.2k
    docu = xsltNewDocument(cur, doc);
687
17.2k
    if (docu == NULL) {
688
108
  xsltTransformError(cur, NULL, (xmlNodePtr)doc,
689
108
    "xsltNewTransformContext : xsltNewDocument failed\n");
690
108
  goto internal_err;
691
108
    }
692
17.1k
    docu->main = 1;
693
17.1k
    cur->document = docu;
694
17.1k
    cur->inst = NULL;
695
17.1k
    cur->outputFile = NULL;
696
17.1k
    cur->sec = xsltGetDefaultSecurityPrefs();
697
17.1k
    cur->debugStatus = xslDebugStatus;
698
17.1k
    cur->traceCode = (unsigned long*) &xsltDefaultTrace;
699
17.1k
    cur->xinclude = xsltGetXIncludeDefault();
700
17.1k
    cur->keyInitLevel = 0;
701
702
17.1k
    cur->newLocale = xsltNewLocale;
703
17.1k
    cur->freeLocale = xsltFreeLocale;
704
17.1k
    cur->genSortKey = xsltStrxfrm;
705
706
17.1k
    return(cur);
707
708
122
internal_err:
709
122
    if (cur != NULL)
710
122
  xsltFreeTransformContext(cur);
711
122
    return(NULL);
712
17.2k
}
713
714
/**
715
 * xsltFreeTransformContext:
716
 * @ctxt:  an XSLT transform context
717
 *
718
 * Free up the memory allocated by @ctxt
719
 */
720
void
721
39.3k
xsltFreeTransformContext(xsltTransformContextPtr ctxt) {
722
39.3k
    if (ctxt == NULL)
723
22.1k
  return;
724
725
    /*
726
     * Shutdown the extension modules associated to the stylesheet
727
     * used if needed.
728
     */
729
17.2k
    xsltShutdownCtxtExts(ctxt);
730
731
17.2k
    if (ctxt->xpathCtxt != NULL) {
732
17.2k
  ctxt->xpathCtxt->nsHash = NULL;
733
17.2k
  xmlXPathFreeContext(ctxt->xpathCtxt);
734
17.2k
    }
735
17.2k
    if (ctxt->templTab != NULL)
736
17.2k
  xmlFree(ctxt->templTab);
737
17.2k
    if (ctxt->varsTab != NULL)
738
17.2k
  xmlFree(ctxt->varsTab);
739
17.2k
    if (ctxt->profTab != NULL)
740
0
  xmlFree(ctxt->profTab);
741
17.2k
    if ((ctxt->extrasNr > 0) && (ctxt->extras != NULL)) {
742
17.1k
  int i;
743
744
238k
  for (i = 0;i < ctxt->extrasNr;i++) {
745
221k
      if ((ctxt->extras[i].deallocate != NULL) &&
746
221k
    (ctxt->extras[i].info != NULL))
747
188
    ctxt->extras[i].deallocate(ctxt->extras[i].info);
748
221k
  }
749
17.1k
  xmlFree(ctxt->extras);
750
17.1k
    }
751
17.2k
    xsltFreeGlobalVariables(ctxt);
752
17.2k
    xsltFreeDocuments(ctxt);
753
17.2k
    xsltFreeCtxtExts(ctxt);
754
17.2k
    xsltFreeRVTs(ctxt);
755
17.2k
    xsltTransformCacheFree(ctxt->cache);
756
17.2k
    xmlDictFree(ctxt->dict);
757
#ifdef WITH_XSLT_DEBUG
758
    xsltGenericDebug(xsltGenericDebugContext,
759
                     "freeing transformation dictionary\n");
760
#endif
761
17.2k
    memset(ctxt, -1, sizeof(xsltTransformContext));
762
17.2k
    xmlFree(ctxt);
763
17.2k
}
764
765
/************************************************************************
766
 *                  *
767
 *      Copy of Nodes in an XSLT fashion    *
768
 *                  *
769
 ************************************************************************/
770
771
/**
772
 * xsltAddChild:
773
 * @parent:  the parent node
774
 * @cur:  the child node
775
 *
776
 * Wrapper version of xmlAddChild with a more consistent behaviour on
777
 * error. One expect the use to be child = xsltAddChild(parent, child);
778
 * and the routine will take care of not leaking on errors or node merge
779
 *
780
 * Returns the child is successfully attached or NULL if merged or freed
781
 */
782
static xmlNodePtr
783
2.30M
xsltAddChild(xmlNodePtr parent, xmlNodePtr cur) {
784
2.30M
   xmlNodePtr ret;
785
786
2.30M
   if (cur == NULL)
787
244
       return(NULL);
788
2.30M
   if (parent == NULL) {
789
0
       xmlFreeNode(cur);
790
0
       return(NULL);
791
0
   }
792
2.30M
   ret = xmlAddChild(parent, cur);
793
794
2.30M
   return(ret);
795
2.30M
}
796
797
/**
798
 * xsltAddTextString:
799
 * @ctxt:  a XSLT process context
800
 * @target:  the text node where the text will be attached
801
 * @string:  the text string
802
 * @len:  the string length in byte
803
 *
804
 * Extend the current text node with the new string, it handles coalescing
805
 *
806
 * Returns: the text node
807
 */
808
static xmlNodePtr
809
xsltAddTextString(xsltTransformContextPtr ctxt, xmlNodePtr target,
810
2.32M
      const xmlChar *string, int len) {
811
    /*
812
     * optimization
813
     */
814
2.32M
    if ((len <= 0) || (string == NULL) || (target == NULL))
815
4.86k
        return(target);
816
817
2.31M
    if (ctxt->lasttext == target->content) {
818
2.19M
        int minSize;
819
820
        /* Check for integer overflow accounting for NUL terminator. */
821
2.19M
        if (len >= INT_MAX - ctxt->lasttuse) {
822
0
            xsltTransformError(ctxt, NULL, target,
823
0
                "xsltCopyText: text allocation failed\n");
824
0
            return(NULL);
825
0
        }
826
2.19M
        minSize = ctxt->lasttuse + len + 1;
827
828
2.19M
        if (ctxt->lasttsize < minSize) {
829
159k
      xmlChar *newbuf;
830
159k
      int size;
831
159k
            int extra;
832
833
            /* Double buffer size but increase by at least 100 bytes. */
834
159k
            extra = minSize < 100 ? 100 : minSize;
835
836
            /* Check for integer overflow. */
837
159k
            if (extra > INT_MAX - ctxt->lasttsize) {
838
0
                size = INT_MAX;
839
0
            }
840
159k
            else {
841
159k
                size = ctxt->lasttsize + extra;
842
159k
            }
843
844
159k
      newbuf = (xmlChar *) xmlRealloc(target->content,size);
845
159k
      if (newbuf == NULL) {
846
2.02k
    xsltTransformError(ctxt, NULL, target,
847
2.02k
     "xsltCopyText: text allocation failed\n");
848
2.02k
    return(NULL);
849
2.02k
      }
850
157k
      ctxt->lasttsize = size;
851
157k
      ctxt->lasttext = newbuf;
852
157k
      target->content = newbuf;
853
157k
  }
854
2.19M
  memcpy(&(target->content[ctxt->lasttuse]), string, len);
855
2.19M
  ctxt->lasttuse += len;
856
2.19M
  target->content[ctxt->lasttuse] = 0;
857
2.19M
    } else {
858
126k
  xmlNodeAddContent(target, string);
859
126k
  ctxt->lasttext = target->content;
860
126k
  len = xmlStrlen(target->content);
861
126k
  ctxt->lasttsize = len;
862
126k
  ctxt->lasttuse = len;
863
126k
    }
864
2.31M
    return(target);
865
2.31M
}
866
867
/**
868
 * xsltCopyTextString:
869
 * @ctxt:  a XSLT process context
870
 * @target:  the element where the text will be attached
871
 * @string:  the text string
872
 * @noescape:  should disable-escaping be activated for this text node.
873
 *
874
 * Adds @string to a newly created or an existent text node child of
875
 * @target.
876
 *
877
 * Returns: the text node, where the text content of @cur is copied to.
878
 *          NULL in case of API or internal errors.
879
 */
880
xmlNodePtr
881
xsltCopyTextString(xsltTransformContextPtr ctxt, xmlNodePtr target,
882
             const xmlChar *string, int noescape)
883
915k
{
884
915k
    xmlNodePtr copy;
885
915k
    int len;
886
887
915k
    if (string == NULL)
888
0
  return(NULL);
889
890
#ifdef WITH_XSLT_DEBUG_PROCESS
891
    XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext,
892
         "xsltCopyTextString: copy text %s\n",
893
         string));
894
#endif
895
896
    /*
897
    * Play safe and reset the merging mechanism for every new
898
    * target node.
899
    */
900
915k
    if ((target == NULL) || (target->children == NULL)) {
901
275k
  ctxt->lasttext = NULL;
902
275k
    }
903
904
    /* handle coalescing of text nodes here */
905
915k
    len = xmlStrlen(string);
906
915k
    if ((ctxt->type == XSLT_OUTPUT_XML) &&
907
915k
  (ctxt->style->cdataSection != NULL) &&
908
915k
  (target != NULL) &&
909
915k
  (target->type == XML_ELEMENT_NODE) &&
910
915k
  (((target->ns == NULL) &&
911
5.77k
    (xmlHashLookup2(ctxt->style->cdataSection,
912
4.62k
              target->name, NULL) != NULL)) ||
913
5.77k
   ((target->ns != NULL) &&
914
2.56k
    (xmlHashLookup2(ctxt->style->cdataSection,
915
1.15k
                    target->name, target->ns->href) != NULL))))
916
3.64k
    {
917
  /*
918
  * Process "cdata-section-elements".
919
  */
920
3.64k
  if ((target->last != NULL) &&
921
3.64k
      (target->last->type == XML_CDATA_SECTION_NODE))
922
612
  {
923
612
      return(xsltAddTextString(ctxt, target->last, string, len));
924
612
  }
925
3.03k
  copy = xmlNewCDataBlock(ctxt->output, string, len);
926
911k
    } else if (noescape) {
927
  /*
928
  * Process "disable-output-escaping".
929
  */
930
0
  if ((target != NULL) && (target->last != NULL) &&
931
0
      (target->last->type == XML_TEXT_NODE) &&
932
0
      (target->last->name == xmlStringTextNoenc))
933
0
  {
934
0
      return(xsltAddTextString(ctxt, target->last, string, len));
935
0
  }
936
0
  copy = xmlNewTextLen(string, len);
937
0
  if (copy != NULL)
938
0
      copy->name = xmlStringTextNoenc;
939
911k
    } else {
940
  /*
941
  * Default processing.
942
  */
943
911k
  if ((target != NULL) && (target->last != NULL) &&
944
911k
      (target->last->type == XML_TEXT_NODE) &&
945
911k
      (target->last->name == xmlStringText)) {
946
307k
      return(xsltAddTextString(ctxt, target->last, string, len));
947
307k
  }
948
604k
  copy = xmlNewTextLen(string, len);
949
604k
    }
950
607k
    if (copy != NULL && target != NULL)
951
605k
  copy = xsltAddChild(target, copy);
952
607k
    if (copy != NULL) {
953
605k
  ctxt->lasttext = copy->content;
954
605k
  ctxt->lasttsize = len;
955
605k
  ctxt->lasttuse = len;
956
605k
    } else {
957
1.35k
  xsltTransformError(ctxt, NULL, target,
958
1.35k
       "xsltCopyTextString: text copy failed\n");
959
1.35k
  ctxt->lasttext = NULL;
960
1.35k
    }
961
607k
    return(copy);
962
915k
}
963
964
/**
965
 * xsltCopyText:
966
 * @ctxt:  a XSLT process context
967
 * @target:  the element where the text will be attached
968
 * @cur:  the text or CDATA node
969
 * @interned:  the string is in the target doc dictionary
970
 *
971
 * Copy the text content of @cur and append it to @target's children.
972
 *
973
 * Returns: the text node, where the text content of @cur is copied to.
974
 *          NULL in case of API or internal errors.
975
 */
976
static xmlNodePtr
977
xsltCopyText(xsltTransformContextPtr ctxt, xmlNodePtr target,
978
       xmlNodePtr cur, int interned)
979
2.48M
{
980
2.48M
    xmlNodePtr copy;
981
982
2.48M
    if ((cur->type != XML_TEXT_NODE) &&
983
2.48M
  (cur->type != XML_CDATA_SECTION_NODE))
984
0
  return(NULL);
985
2.48M
    if (cur->content == NULL)
986
0
  return(NULL);
987
988
#ifdef WITH_XSLT_DEBUG_PROCESS
989
    if (cur->type == XML_CDATA_SECTION_NODE) {
990
  XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext,
991
       "xsltCopyText: copy CDATA text %s\n",
992
       cur->content));
993
    } else if (cur->name == xmlStringTextNoenc) {
994
  XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext,
995
         "xsltCopyText: copy unescaped text %s\n",
996
       cur->content));
997
    } else {
998
  XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext,
999
       "xsltCopyText: copy text %s\n",
1000
       cur->content));
1001
    }
1002
#endif
1003
1004
    /*
1005
    * Play save and reset the merging mechanism for every new
1006
    * target node.
1007
    */
1008
2.48M
    if ((target == NULL) || (target->children == NULL)) {
1009
178k
  ctxt->lasttext = NULL;
1010
178k
    }
1011
1012
2.48M
    if ((ctxt->style->cdataSection != NULL) &&
1013
2.48M
  (ctxt->type == XSLT_OUTPUT_XML) &&
1014
2.48M
  (target != NULL) &&
1015
2.48M
  (target->type == XML_ELEMENT_NODE) &&
1016
2.48M
  (((target->ns == NULL) &&
1017
10.1k
    (xmlHashLookup2(ctxt->style->cdataSection,
1018
1.66k
              target->name, NULL) != NULL)) ||
1019
10.1k
   ((target->ns != NULL) &&
1020
9.41k
    (xmlHashLookup2(ctxt->style->cdataSection,
1021
8.50k
                    target->name, target->ns->href) != NULL))))
1022
4.01k
    {
1023
  /*
1024
  * Process "cdata-section-elements".
1025
  */
1026
  /*
1027
  * OPTIMIZE TODO: xsltCopyText() is also used for attribute content.
1028
  */
1029
  /*
1030
  * TODO: Since this doesn't merge adjacent CDATA-section nodes,
1031
  * we'll get: <![CDATA[x]]><!CDATA[y]]>.
1032
  * TODO: Reported in #321505.
1033
  */
1034
4.01k
  if ((target->last != NULL) &&
1035
4.01k
       (target->last->type == XML_CDATA_SECTION_NODE))
1036
1.17k
  {
1037
      /*
1038
      * Append to existing CDATA-section node.
1039
      */
1040
1.17k
      copy = xsltAddTextString(ctxt, target->last, cur->content,
1041
1.17k
    xmlStrlen(cur->content));
1042
1.17k
      goto exit;
1043
2.84k
  } else {
1044
2.84k
      unsigned int len;
1045
1046
2.84k
      len = xmlStrlen(cur->content);
1047
2.84k
      copy = xmlNewCDataBlock(ctxt->output, cur->content, len);
1048
2.84k
      if (copy == NULL)
1049
12
    goto exit;
1050
2.83k
      ctxt->lasttext = copy->content;
1051
2.83k
      ctxt->lasttsize = len;
1052
2.83k
      ctxt->lasttuse = len;
1053
2.83k
  }
1054
2.48M
    } else if ((target != NULL) &&
1055
2.48M
  (target->last != NULL) &&
1056
  /* both escaped or both non-escaped text-nodes */
1057
2.48M
  (((target->last->type == XML_TEXT_NODE) &&
1058
2.30M
  (target->last->name == cur->name)) ||
1059
        /* non-escaped text nodes and CDATA-section nodes */
1060
2.30M
  (((target->last->type == XML_CDATA_SECTION_NODE) &&
1061
288k
  (cur->name == xmlStringTextNoenc)))))
1062
2.01M
    {
1063
  /*
1064
   * we are appending to an existing text node
1065
   */
1066
2.01M
  copy = xsltAddTextString(ctxt, target->last, cur->content,
1067
2.01M
      xmlStrlen(cur->content));
1068
2.01M
  goto exit;
1069
2.01M
    } else if ((interned) && (target != NULL) &&
1070
466k
  (target->doc != NULL) &&
1071
466k
  (target->doc->dict == ctxt->dict))
1072
423k
    {
1073
  /*
1074
  * TODO: DO we want to use this also for "text" output?
1075
  */
1076
423k
        copy = xmlNewTextLen(NULL, 0);
1077
423k
  if (copy == NULL)
1078
1.11k
      goto exit;
1079
421k
  if (cur->name == xmlStringTextNoenc)
1080
14
      copy->name = xmlStringTextNoenc;
1081
1082
  /*
1083
   * Must confirm that content is in dict (bug 302821)
1084
   * TODO: This check should be not needed for text coming
1085
   * from the stylesheets
1086
   */
1087
421k
  if (xmlDictOwns(ctxt->dict, cur->content))
1088
421k
      copy->content = cur->content;
1089
647
  else {
1090
647
      if ((copy->content = xmlStrdup(cur->content)) == NULL) {
1091
4
                xmlFreeNode(copy);
1092
4
    return NULL;
1093
4
            }
1094
647
  }
1095
1096
421k
  ctxt->lasttext = NULL;
1097
421k
    } else {
1098
        /*
1099
   * normal processing. keep counters to extend the text node
1100
   * in xsltAddTextString if needed.
1101
   */
1102
43.1k
        unsigned int len;
1103
1104
43.1k
  len = xmlStrlen(cur->content);
1105
43.1k
  copy = xmlNewTextLen(cur->content, len);
1106
43.1k
  if (copy == NULL)
1107
2.56k
      goto exit;
1108
40.6k
  if (cur->name == xmlStringTextNoenc)
1109
0
      copy->name = xmlStringTextNoenc;
1110
40.6k
  ctxt->lasttext = copy->content;
1111
40.6k
  ctxt->lasttsize = len;
1112
40.6k
  ctxt->lasttuse = len;
1113
40.6k
    }
1114
465k
    if (copy != NULL) {
1115
465k
  if (target != NULL) {
1116
465k
      copy->doc = target->doc;
1117
      /*
1118
      * MAYBE TODO: Maybe we should reset the ctxt->lasttext here
1119
      *  to ensure that the optimized text-merging mechanism
1120
      *  won't interfere with normal node-merging in any case.
1121
      */
1122
465k
      copy = xsltAddChild(target, copy);
1123
465k
  }
1124
465k
    } else {
1125
0
  xsltTransformError(ctxt, NULL, target,
1126
0
       "xsltCopyText: text copy failed\n");
1127
0
    }
1128
1129
2.48M
exit:
1130
2.48M
    if ((copy == NULL) || (copy->content == NULL)) {
1131
5.55k
  xsltTransformError(ctxt, NULL, target,
1132
5.55k
      "Internal error in xsltCopyText(): "
1133
5.55k
      "Failed to copy the string.\n");
1134
5.55k
  ctxt->state = XSLT_STATE_STOPPED;
1135
5.55k
    }
1136
2.48M
    return(copy);
1137
465k
}
1138
1139
/**
1140
 * xsltShallowCopyAttr:
1141
 * @ctxt:  a XSLT process context
1142
 * @invocNode: responsible node in the stylesheet; used for error reports
1143
 * @target:  the element where the attribute will be grafted
1144
 * @attr: the attribute to be copied
1145
 *
1146
 * Do a copy of an attribute.
1147
 * Called by:
1148
 *  - xsltCopyTree()
1149
 *  - xsltCopyOf()
1150
 *  - xsltCopy()
1151
 *
1152
 * Returns: a new xmlAttrPtr, or NULL in case of error.
1153
 */
1154
static xmlAttrPtr
1155
xsltShallowCopyAttr(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,
1156
       xmlNodePtr target, xmlAttrPtr attr)
1157
46.9k
{
1158
46.9k
    xmlAttrPtr copy;
1159
46.9k
    xmlChar *value;
1160
1161
46.9k
    if (attr == NULL)
1162
0
  return(NULL);
1163
1164
46.9k
    if (target->type != XML_ELEMENT_NODE) {
1165
278
  xsltTransformError(ctxt, NULL, invocNode,
1166
278
      "Cannot add an attribute node to a non-element node.\n");
1167
278
  return(NULL);
1168
278
    }
1169
1170
46.6k
    if (target->children != NULL) {
1171
8.48k
  xsltTransformError(ctxt, NULL, invocNode,
1172
8.48k
      "Attribute nodes must be added before "
1173
8.48k
      "any child nodes to an element.\n");
1174
8.48k
  return(NULL);
1175
8.48k
    }
1176
1177
38.1k
    value = xmlNodeListGetString(attr->doc, attr->children, 1);
1178
38.1k
    if (attr->ns != NULL) {
1179
14.3k
  xmlNsPtr ns;
1180
1181
14.3k
  ns = xsltGetSpecialNamespace(ctxt, invocNode,
1182
14.3k
      attr->ns->href, attr->ns->prefix, target);
1183
14.3k
  if (ns == NULL) {
1184
80
      xsltTransformError(ctxt, NULL, invocNode,
1185
80
    "Namespace fixup error: Failed to acquire an in-scope "
1186
80
    "namespace binding of the copied attribute '{%s}%s'.\n",
1187
80
    attr->ns->href, attr->name);
1188
      /*
1189
      * TODO: Should we just stop here?
1190
      */
1191
80
  }
1192
  /*
1193
  * Note that xmlSetNsProp() will take care of duplicates
1194
  * and assigns the new namespace even to a duplicate.
1195
  */
1196
14.3k
  copy = xmlSetNsProp(target, ns, attr->name, value);
1197
23.8k
    } else {
1198
23.8k
  copy = xmlSetNsProp(target, NULL, attr->name, value);
1199
23.8k
    }
1200
38.1k
    if (value != NULL)
1201
37.4k
  xmlFree(value);
1202
1203
38.1k
    if (copy == NULL)
1204
437
  return(NULL);
1205
1206
#if 0
1207
    /*
1208
    * NOTE: This was optimized according to bug #342695.
1209
    * TODO: Can this further be optimized, if source and target
1210
    *  share the same dict and attr->children is just 1 text node
1211
    *  which is in the dict? How probable is such a case?
1212
    */
1213
    /*
1214
    * TODO: Do we need to create an empty text node if the value
1215
    *  is the empty string?
1216
    */
1217
    value = xmlNodeListGetString(attr->doc, attr->children, 1);
1218
    if (value != NULL) {
1219
  txtNode = xmlNewDocText(target->doc, NULL);
1220
  if (txtNode == NULL)
1221
      return(NULL);
1222
  if ((target->doc != NULL) &&
1223
      (target->doc->dict != NULL))
1224
  {
1225
      txtNode->content =
1226
    (xmlChar *) xmlDictLookup(target->doc->dict,
1227
        BAD_CAST value, -1);
1228
      xmlFree(value);
1229
  } else
1230
      txtNode->content = value;
1231
  copy->children = txtNode;
1232
    }
1233
#endif
1234
1235
37.7k
    return(copy);
1236
38.1k
}
1237
1238
/**
1239
 * xsltCopyAttrListNoOverwrite:
1240
 * @ctxt:  a XSLT process context
1241
 * @invocNode: responsible node in the stylesheet; used for error reports
1242
 * @target:  the element where the new attributes will be grafted
1243
 * @attr:  the first attribute in the list to be copied
1244
 *
1245
 * Copies a list of attribute nodes, starting with @attr, over to the
1246
 * @target element node.
1247
 *
1248
 * Called by:
1249
 *  - xsltCopyTree()
1250
 *
1251
 * Returns 0 on success and -1 on errors and internal errors.
1252
 */
1253
static int
1254
xsltCopyAttrListNoOverwrite(xsltTransformContextPtr ctxt,
1255
          xmlNodePtr invocNode,
1256
          xmlNodePtr target, xmlAttrPtr attr)
1257
418k
{
1258
418k
    xmlAttrPtr copy;
1259
418k
    xmlNsPtr origNs = NULL, copyNs = NULL;
1260
418k
    xmlChar *value;
1261
1262
    /*
1263
    * Don't use xmlCopyProp() here, since it will try to
1264
    * reconciliate namespaces.
1265
    */
1266
988k
    while (attr != NULL) {
1267
  /*
1268
  * Find a namespace node in the tree of @target.
1269
  * Avoid searching for the same ns.
1270
  */
1271
570k
  if (attr->ns != origNs) {
1272
17.1k
      origNs = attr->ns;
1273
17.1k
      if (attr->ns != NULL) {
1274
8.88k
    copyNs = xsltGetSpecialNamespace(ctxt, invocNode,
1275
8.88k
        attr->ns->href, attr->ns->prefix, target);
1276
8.88k
    if (copyNs == NULL)
1277
1
        return(-1);
1278
8.88k
      } else
1279
8.29k
    copyNs = NULL;
1280
17.1k
  }
1281
  /*
1282
   * If attribute has a value, we need to copy it (watching out
1283
   * for possible entities)
1284
   */
1285
570k
  if ((attr->children) && (attr->children->type == XML_TEXT_NODE) &&
1286
570k
            (attr->children->next == NULL)) {
1287
570k
            copy = xmlNewNsProp(target, copyNs, attr->name,
1288
570k
                                attr->children->content);
1289
570k
        } else if (attr->children != NULL) {
1290
0
      value = xmlNodeListGetString(attr->doc, attr->children, 1);
1291
0
            copy = xmlNewNsProp(target, copyNs, attr->name, BAD_CAST value);
1292
0
      xmlFree(value);
1293
0
        } else {
1294
0
            copy = xmlNewNsProp(target, copyNs, attr->name, NULL);
1295
0
        }
1296
1297
570k
  if (copy == NULL)
1298
22
      return(-1);
1299
1300
570k
  attr = attr->next;
1301
570k
    }
1302
418k
    return(0);
1303
418k
}
1304
1305
/**
1306
 * xsltShallowCopyElem:
1307
 * @ctxt:  the XSLT process context
1308
 * @node:  the element node in the source tree
1309
 *         or the Literal Result Element
1310
 * @insert:  the parent in the result tree
1311
 * @isLRE: if @node is a Literal Result Element
1312
 *
1313
 * Make a copy of the element node @node
1314
 * and insert it as last child of @insert.
1315
 *
1316
 * URGENT TODO: The problem with this one (for the non-refactored code)
1317
 * is that it is used for both, Literal Result Elements *and*
1318
 * copying input nodes.
1319
 *
1320
 * BIG NOTE: This is only called for XML_ELEMENT_NODEs.
1321
 *
1322
 * Called from:
1323
 *   xsltApplySequenceConstructor()
1324
 *    (for Literal Result Elements - which is a problem)
1325
 *   xsltCopy() (for shallow-copying elements via xsl:copy)
1326
 *
1327
 * Returns a pointer to the new node, or NULL in case of error
1328
 */
1329
static xmlNodePtr
1330
xsltShallowCopyElem(xsltTransformContextPtr ctxt, xmlNodePtr node,
1331
        xmlNodePtr insert, int isLRE)
1332
525k
{
1333
525k
    xmlNodePtr copy;
1334
1335
525k
    if ((node->type == XML_DTD_NODE) || (insert == NULL))
1336
0
  return(NULL);
1337
525k
    if ((node->type == XML_TEXT_NODE) ||
1338
525k
  (node->type == XML_CDATA_SECTION_NODE))
1339
0
  return(xsltCopyText(ctxt, insert, node, 0));
1340
1341
525k
    copy = xmlDocCopyNode(node, insert->doc, 0);
1342
525k
    if (copy != NULL) {
1343
521k
  copy->doc = ctxt->output;
1344
521k
  copy = xsltAddChild(insert, copy);
1345
521k
        if (copy == NULL) {
1346
0
             xsltTransformError(ctxt, NULL, node,
1347
0
                "xsltShallowCopyElem: copy failed\n");
1348
0
             return (copy);
1349
0
        }
1350
1351
521k
  if (node->type == XML_ELEMENT_NODE) {
1352
      /*
1353
       * Add namespaces as they are needed
1354
       */
1355
521k
      if (node->nsDef != NULL) {
1356
    /*
1357
    * TODO: Remove the LRE case in the refactored code
1358
    * gets enabled.
1359
    */
1360
34.1k
    if (isLRE)
1361
13.4k
        xsltCopyNamespaceList(ctxt, copy, node->nsDef);
1362
20.6k
    else
1363
20.6k
        xsltCopyNamespaceListInternal(copy, node->nsDef);
1364
34.1k
      }
1365
1366
      /*
1367
      * URGENT TODO: The problem with this is that it does not
1368
      *  copy over all namespace nodes in scope.
1369
      *  The damn thing about this is, that we would need to
1370
      *  use the xmlGetNsList(), for every single node; this is
1371
      *  also done in xsltCopyTree(), but only for the top node.
1372
      */
1373
521k
      if (node->ns != NULL) {
1374
124k
    if (isLRE) {
1375
        /*
1376
        * REVISIT TODO: Since the non-refactored code still does
1377
        *  ns-aliasing, we need to call xsltGetNamespace() here.
1378
        *  Remove this when ready.
1379
        */
1380
102k
        copy->ns = xsltGetNamespace(ctxt, node, node->ns, copy);
1381
102k
    } else {
1382
21.9k
        copy->ns = xsltGetSpecialNamespace(ctxt,
1383
21.9k
      node, node->ns->href, node->ns->prefix, copy);
1384
1385
21.9k
    }
1386
396k
      } else if ((insert->type == XML_ELEMENT_NODE) &&
1387
396k
           (insert->ns != NULL))
1388
21.9k
      {
1389
    /*
1390
    * "Undeclare" the default namespace.
1391
    */
1392
21.9k
    xsltGetSpecialNamespace(ctxt, node, NULL, NULL, copy);
1393
21.9k
      }
1394
521k
  }
1395
521k
    } else {
1396
3.79k
  xsltTransformError(ctxt, NULL, node,
1397
3.79k
    "xsltShallowCopyElem: copy %s failed\n", node->name);
1398
3.79k
    }
1399
525k
    return(copy);
1400
525k
}
1401
1402
/**
1403
 * xsltCopyTreeList:
1404
 * @ctxt:  a XSLT process context
1405
 * @invocNode: responsible node in the stylesheet; used for error reports
1406
 * @list:  the list of element nodes in the source tree.
1407
 * @insert:  the parent in the result tree.
1408
 * @isLRE:  is this a literal result element list
1409
 * @topElemVisited: indicates if a top-most element was already processed
1410
 *
1411
 * Make a copy of the full list of tree @list
1412
 * and insert it as last children of @insert
1413
 *
1414
 * NOTE: Not to be used for Literal Result Elements.
1415
 *
1416
 * Used by:
1417
 *  - xsltCopyOf()
1418
 *
1419
 * Returns a pointer to the new list, or NULL in case of error
1420
 */
1421
static xmlNodePtr
1422
xsltCopyTreeList(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,
1423
     xmlNodePtr list,
1424
     xmlNodePtr insert, int isLRE, int topElemVisited)
1425
235k
{
1426
235k
    xmlNodePtr copy, ret = NULL;
1427
1428
1.29M
    while (list != NULL) {
1429
1.05M
  copy = xsltCopyTree(ctxt, invocNode,
1430
1.05M
      list, insert, isLRE, topElemVisited);
1431
1.05M
  if (copy != NULL) {
1432
1.05M
      if (ret == NULL) {
1433
235k
    ret = copy;
1434
235k
      }
1435
1.05M
  }
1436
1.05M
  list = list->next;
1437
1.05M
    }
1438
235k
    return(ret);
1439
235k
}
1440
1441
/**
1442
 * xsltCopyNamespaceListInternal:
1443
 * @node:  the target node
1444
 * @cur:  the first namespace
1445
 *
1446
 * Do a copy of a namespace list. If @node is non-NULL the
1447
 * new namespaces are added automatically.
1448
 * Called by:
1449
 *   xsltCopyTree()
1450
 *
1451
 * QUESTION: What is the exact difference between this function
1452
 *  and xsltCopyNamespaceList() in "namespaces.c"?
1453
 * ANSWER: xsltCopyNamespaceList() tries to apply ns-aliases.
1454
 *
1455
 * Returns: a new xmlNsPtr, or NULL in case of error.
1456
 */
1457
static xmlNsPtr
1458
201k
xsltCopyNamespaceListInternal(xmlNodePtr elem, xmlNsPtr ns) {
1459
201k
    xmlNsPtr ret = NULL;
1460
201k
    xmlNsPtr p = NULL, q, luNs;
1461
1462
201k
    if (ns == NULL)
1463
0
  return(NULL);
1464
    /*
1465
     * One can add namespaces only on element nodes
1466
     */
1467
201k
    if ((elem != NULL) && (elem->type != XML_ELEMENT_NODE))
1468
0
  elem = NULL;
1469
1470
734k
    do {
1471
734k
  if (ns->type != XML_NAMESPACE_DECL)
1472
0
      break;
1473
  /*
1474
   * Avoid duplicating namespace declarations on the tree.
1475
   */
1476
734k
  if (elem != NULL) {
1477
734k
      if ((elem->ns != NULL) &&
1478
734k
    xmlStrEqual(elem->ns->prefix, ns->prefix) &&
1479
734k
    xmlStrEqual(elem->ns->href, ns->href))
1480
0
      {
1481
0
    ns = ns->next;
1482
0
    continue;
1483
0
      }
1484
734k
      luNs = xmlSearchNs(elem->doc, elem, ns->prefix);
1485
734k
      if ((luNs != NULL) && (xmlStrEqual(luNs->href, ns->href)))
1486
127k
      {
1487
127k
    ns = ns->next;
1488
127k
    continue;
1489
127k
      }
1490
734k
  }
1491
607k
  q = xmlNewNs(elem, ns->href, ns->prefix);
1492
607k
  if (p == NULL) {
1493
180k
      ret = p = q;
1494
426k
  } else if (q != NULL) {
1495
426k
      p->next = q;
1496
426k
      p = q;
1497
426k
  }
1498
607k
  ns = ns->next;
1499
734k
    } while (ns != NULL);
1500
0
    return(ret);
1501
201k
}
1502
1503
/**
1504
 * xsltShallowCopyNsNode:
1505
 * @ctxt:  the XSLT transformation context
1506
 * @invocNode: responsible node in the stylesheet; used for error reports
1507
 * @insert:  the target element node in the result tree
1508
 * @ns: the namespace node
1509
 *
1510
 * This is used for copying ns-nodes with xsl:copy-of and xsl:copy.
1511
 *
1512
 * Returns a new/existing ns-node, or NULL.
1513
 */
1514
static xmlNsPtr
1515
xsltShallowCopyNsNode(xsltTransformContextPtr ctxt,
1516
          xmlNodePtr invocNode,
1517
          xmlNodePtr insert,
1518
          xmlNsPtr ns)
1519
407k
{
1520
    /*
1521
     * TODO: Contrary to header comments, this is declared as int.
1522
     * be modified to return a node pointer, or NULL if any error
1523
     */
1524
407k
    xmlNsPtr tmpns;
1525
1526
407k
    if ((insert == NULL) || (insert->type != XML_ELEMENT_NODE))
1527
349
  return(NULL);
1528
1529
406k
    if (insert->children != NULL) {
1530
1.33k
  xsltTransformError(ctxt, NULL, invocNode,
1531
1.33k
      "Namespace nodes must be added before "
1532
1.33k
      "any child nodes are added to an element.\n");
1533
1.33k
  return(NULL);
1534
1.33k
    }
1535
    /*
1536
     * BIG NOTE: Xalan-J simply overwrites any ns-decls with
1537
     * an equal prefix. We definitively won't do that.
1538
     *
1539
     * MSXML 4.0 and the .NET ignores ns-decls for which an
1540
     * equal prefix is already in use.
1541
     *
1542
     * Saxon raises an error like:
1543
     * "net.sf.saxon.xpath.DynamicError: Cannot create two namespace
1544
     * nodes with the same name".
1545
     *
1546
     * NOTE: We'll currently follow MSXML here.
1547
     * REVISIT TODO: Check if it's better to follow Saxon here.
1548
     */
1549
405k
    if (ns->prefix == NULL) {
1550
  /*
1551
  * If we are adding ns-nodes to an element using e.g.
1552
  * <xsl:copy-of select="/foo/namespace::*">, then we need
1553
  * to ensure that we don't incorrectly declare a default
1554
  * namespace on an element in no namespace, which otherwise
1555
  * would move the element incorrectly into a namespace, if
1556
  * the node tree is serialized.
1557
  */
1558
61.6k
  if (insert->ns == NULL)
1559
26.5k
      goto occupied;
1560
343k
    } else if ((ns->prefix[0] == 'x') &&
1561
343k
  xmlStrEqual(ns->prefix, BAD_CAST "xml"))
1562
64.1k
    {
1563
  /*
1564
  * The XML namespace is built in.
1565
  */
1566
64.1k
  return(NULL);
1567
64.1k
    }
1568
1569
314k
    if (insert->nsDef != NULL) {
1570
313k
  tmpns = insert->nsDef;
1571
1.93M
  do {
1572
1.93M
      if ((tmpns->prefix == NULL) == (ns->prefix == NULL)) {
1573
1.72M
    if ((tmpns->prefix == ns->prefix) ||
1574
1.72M
        xmlStrEqual(tmpns->prefix, ns->prefix))
1575
308k
    {
1576
        /*
1577
        * Same prefix.
1578
        */
1579
308k
        if (xmlStrEqual(tmpns->href, ns->href))
1580
286k
      return(NULL);
1581
21.4k
        goto occupied;
1582
308k
    }
1583
1.72M
      }
1584
1.62M
      tmpns = tmpns->next;
1585
1.62M
  } while (tmpns != NULL);
1586
313k
    }
1587
6.34k
    tmpns = xmlSearchNs(insert->doc, insert, ns->prefix);
1588
6.34k
    if ((tmpns != NULL) && xmlStrEqual(tmpns->href, ns->href))
1589
1.45k
  return(NULL);
1590
    /*
1591
    * Declare a new namespace.
1592
    * TODO: The problem (wrt efficiency) with this xmlNewNs() is
1593
    * that it will again search the already declared namespaces
1594
    * for a duplicate :-/
1595
    */
1596
4.88k
    return(xmlNewNs(insert, ns->href, ns->prefix));
1597
1598
48.0k
occupied:
1599
    /*
1600
    * TODO: We could as well raise an error here (like Saxon does),
1601
    * or at least generate a warning.
1602
    */
1603
48.0k
    return(NULL);
1604
6.34k
}
1605
1606
/**
1607
 * xsltCopyTree:
1608
 * @ctxt:  the XSLT transformation context
1609
 * @invocNode: responsible node in the stylesheet; used for error reports
1610
 * @node:  the element node in the source tree
1611
 * @insert:  the parent in the result tree
1612
 * @isLRE:  indicates if @node is a Literal Result Element
1613
 * @topElemVisited: indicates if a top-most element was already processed
1614
 *
1615
 * Make a copy of the full tree under the element node @node
1616
 * and insert it as last child of @insert
1617
 *
1618
 * NOTE: Not to be used for Literal Result Elements.
1619
 *
1620
 * Used by:
1621
 *  - xsltCopyOf()
1622
 *
1623
 * Returns a pointer to the new tree, or NULL in case of error
1624
 */
1625
static xmlNodePtr
1626
xsltCopyTree(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,
1627
       xmlNodePtr node, xmlNodePtr insert, int isLRE,
1628
       int topElemVisited)
1629
1.67M
{
1630
1.67M
    xmlNodePtr copy;
1631
1632
1.67M
    if (node == NULL)
1633
0
  return(NULL);
1634
1.67M
    switch (node->type) {
1635
656k
        case XML_ELEMENT_NODE:
1636
656k
        case XML_ENTITY_REF_NODE:
1637
656k
        case XML_ENTITY_NODE:
1638
661k
        case XML_PI_NODE:
1639
680k
        case XML_COMMENT_NODE:
1640
680k
        case XML_DOCUMENT_NODE:
1641
680k
        case XML_HTML_DOCUMENT_NODE:
1642
#ifdef LIBXML_DOCB_ENABLED
1643
        case XML_DOCB_DOCUMENT_NODE:
1644
#endif
1645
680k
      break;
1646
591k
        case XML_TEXT_NODE: {
1647
591k
      int noenc = (node->name == xmlStringTextNoenc);
1648
591k
      return(xsltCopyTextString(ctxt, insert, node->content, noenc));
1649
680k
      }
1650
0
        case XML_CDATA_SECTION_NODE:
1651
0
      return(xsltCopyTextString(ctxt, insert, node->content, 0));
1652
0
        case XML_ATTRIBUTE_NODE:
1653
0
      return((xmlNodePtr)
1654
0
    xsltShallowCopyAttr(ctxt, invocNode, insert, (xmlAttrPtr) node));
1655
406k
        case XML_NAMESPACE_DECL:
1656
406k
      return((xmlNodePtr) xsltShallowCopyNsNode(ctxt, invocNode,
1657
406k
    insert, (xmlNsPtr) node));
1658
1659
0
        case XML_DOCUMENT_TYPE_NODE:
1660
0
        case XML_DOCUMENT_FRAG_NODE:
1661
0
        case XML_NOTATION_NODE:
1662
0
        case XML_DTD_NODE:
1663
0
        case XML_ELEMENT_DECL:
1664
0
        case XML_ATTRIBUTE_DECL:
1665
0
        case XML_ENTITY_DECL:
1666
0
        case XML_XINCLUDE_START:
1667
0
        case XML_XINCLUDE_END:
1668
0
            return(NULL);
1669
1.67M
    }
1670
680k
    if (XSLT_IS_RES_TREE_FRAG(node)) {
1671
0
  if (node->children != NULL)
1672
0
      copy = xsltCopyTreeList(ctxt, invocNode,
1673
0
    node->children, insert, 0, 0);
1674
0
  else
1675
0
      copy = NULL;
1676
0
  return(copy);
1677
0
    }
1678
680k
    copy = xmlDocCopyNode(node, insert->doc, 0);
1679
680k
    if (copy != NULL) {
1680
678k
  copy->doc = ctxt->output;
1681
678k
  copy = xsltAddChild(insert, copy);
1682
678k
        if (copy == NULL) {
1683
0
            xsltTransformError(ctxt, NULL, invocNode,
1684
0
            "xsltCopyTree: Copying of '%s' failed.\n", node->name);
1685
0
            return (copy);
1686
0
        }
1687
  /*
1688
   * The node may have been coalesced into another text node.
1689
   */
1690
678k
  if (insert->last != copy)
1691
0
      return(insert->last);
1692
678k
  copy->next = NULL;
1693
1694
678k
  if (node->type == XML_ELEMENT_NODE) {
1695
      /*
1696
      * Copy in-scope namespace nodes.
1697
      *
1698
      * REVISIT: Since we try to reuse existing in-scope ns-decls by
1699
      *  using xmlSearchNsByHref(), this will eventually change
1700
      *  the prefix of an original ns-binding; thus it might
1701
      *  break QNames in element/attribute content.
1702
      * OPTIMIZE TODO: If we had a xmlNsPtr * on the transformation
1703
      *  context, plus a ns-lookup function, which writes directly
1704
      *  to a given list, then we wouldn't need to create/free the
1705
      *  nsList every time.
1706
      */
1707
654k
      if ((topElemVisited == 0) &&
1708
654k
    (node->parent != NULL) &&
1709
654k
    (node->parent->type != XML_DOCUMENT_NODE) &&
1710
654k
    (node->parent->type != XML_HTML_DOCUMENT_NODE))
1711
132k
      {
1712
132k
    xmlNsPtr *nsList, *curns, ns;
1713
1714
    /*
1715
    * If this is a top-most element in a tree to be
1716
    * copied, then we need to ensure that all in-scope
1717
    * namespaces are copied over. For nodes deeper in the
1718
    * tree, it is sufficient to reconcile only the ns-decls
1719
    * (node->nsDef entries).
1720
    */
1721
1722
132k
    nsList = xmlGetNsList(node->doc, node);
1723
132k
    if (nsList != NULL) {
1724
131k
        curns = nsList;
1725
798k
        do {
1726
      /*
1727
      * Search by prefix first in order to break as less
1728
      * QNames in element/attribute content as possible.
1729
      */
1730
798k
      ns = xmlSearchNs(insert->doc, insert,
1731
798k
          (*curns)->prefix);
1732
1733
798k
      if ((ns == NULL) ||
1734
798k
          (! xmlStrEqual(ns->href, (*curns)->href)))
1735
478k
      {
1736
478k
          ns = NULL;
1737
          /*
1738
          * Search by namespace name.
1739
          * REVISIT TODO: Currently disabled.
1740
          */
1741
#if 0
1742
          ns = xmlSearchNsByHref(insert->doc,
1743
        insert, (*curns)->href);
1744
#endif
1745
478k
      }
1746
798k
      if (ns == NULL) {
1747
          /*
1748
          * Declare a new namespace on the copied element.
1749
          */
1750
478k
          ns = xmlNewNs(copy, (*curns)->href,
1751
478k
        (*curns)->prefix);
1752
          /* TODO: Handle errors */
1753
478k
      }
1754
798k
      if (node->ns == *curns) {
1755
          /*
1756
          * If this was the original's namespace then set
1757
          * the generated counterpart on the copy.
1758
          */
1759
85.7k
          copy->ns = ns;
1760
85.7k
      }
1761
798k
      curns++;
1762
798k
        } while (*curns != NULL);
1763
131k
        xmlFree(nsList);
1764
131k
    }
1765
521k
      } else if (node->nsDef != NULL) {
1766
    /*
1767
    * Copy over all namespace declaration attributes.
1768
    */
1769
181k
    if (node->nsDef != NULL) {
1770
181k
        if (isLRE)
1771
0
      xsltCopyNamespaceList(ctxt, copy, node->nsDef);
1772
181k
        else
1773
181k
      xsltCopyNamespaceListInternal(copy, node->nsDef);
1774
181k
    }
1775
181k
      }
1776
      /*
1777
      * Set the namespace.
1778
      */
1779
654k
      if (node->ns != NULL) {
1780
405k
    if (copy->ns == NULL) {
1781
        /*
1782
        * This will map copy->ns to one of the newly created
1783
        * in-scope ns-decls, OR create a new ns-decl on @copy.
1784
        */
1785
319k
        copy->ns = xsltGetSpecialNamespace(ctxt, invocNode,
1786
319k
      node->ns->href, node->ns->prefix, copy);
1787
319k
    }
1788
405k
      } else if ((insert->type == XML_ELEMENT_NODE) &&
1789
248k
    (insert->ns != NULL))
1790
152k
      {
1791
    /*
1792
    * "Undeclare" the default namespace on @copy with xmlns="".
1793
    */
1794
152k
    xsltGetSpecialNamespace(ctxt, invocNode, NULL, NULL, copy);
1795
152k
      }
1796
      /*
1797
      * Copy attribute nodes.
1798
      */
1799
654k
      if (node->properties != NULL) {
1800
418k
    xsltCopyAttrListNoOverwrite(ctxt, invocNode,
1801
418k
        copy, node->properties);
1802
418k
      }
1803
654k
      if (topElemVisited == 0)
1804
154k
    topElemVisited = 1;
1805
654k
  }
1806
  /*
1807
  * Copy the subtree.
1808
  */
1809
678k
  if (node->children != NULL) {
1810
231k
      xsltCopyTreeList(ctxt, invocNode,
1811
231k
    node->children, copy, isLRE, topElemVisited);
1812
231k
  }
1813
678k
    } else {
1814
2.01k
  xsltTransformError(ctxt, NULL, invocNode,
1815
2.01k
      "xsltCopyTree: Copying of '%s' failed.\n", node->name);
1816
2.01k
    }
1817
680k
    return(copy);
1818
680k
}
1819
1820
/************************************************************************
1821
 *                  *
1822
 *    Error/fallback processing       *
1823
 *                  *
1824
 ************************************************************************/
1825
1826
/**
1827
 * xsltApplyFallbacks:
1828
 * @ctxt:  a XSLT process context
1829
 * @node:  the node in the source tree.
1830
 * @inst:  the node generating the error
1831
 *
1832
 * Process possible xsl:fallback nodes present under @inst
1833
 *
1834
 * Returns the number of xsl:fallback element found and processed
1835
 */
1836
static int
1837
xsltApplyFallbacks(xsltTransformContextPtr ctxt, xmlNodePtr node,
1838
71.2k
             xmlNodePtr inst) {
1839
1840
71.2k
    xmlNodePtr child;
1841
71.2k
    int ret = 0;
1842
1843
71.2k
    if ((ctxt == NULL) || (node == NULL) || (inst == NULL) ||
1844
71.2k
  (inst->children == NULL))
1845
70.2k
  return(0);
1846
1847
976
    child = inst->children;
1848
6.79k
    while (child != NULL) {
1849
5.81k
        if ((IS_XSLT_ELEM(child)) &&
1850
5.81k
            (xmlStrEqual(child->name, BAD_CAST "fallback"))) {
1851
#ifdef WITH_XSLT_DEBUG_PARSING
1852
      xsltGenericDebug(xsltGenericDebugContext,
1853
           "applying xsl:fallback\n");
1854
#endif
1855
446
      ret++;
1856
446
      xsltApplySequenceConstructor(ctxt, node, child->children,
1857
446
    NULL);
1858
446
  }
1859
5.81k
  child = child->next;
1860
5.81k
    }
1861
976
    return(ret);
1862
71.2k
}
1863
1864
/************************************************************************
1865
 *                  *
1866
 *      Default processing        *
1867
 *                  *
1868
 ************************************************************************/
1869
1870
/**
1871
 * xsltDefaultProcessOneNode:
1872
 * @ctxt:  a XSLT process context
1873
 * @node:  the node in the source tree.
1874
 * @params: extra parameters passed to the template if any
1875
 *
1876
 * Process the source node with the default built-in template rule:
1877
 * <xsl:template match="*|/">
1878
 *   <xsl:apply-templates/>
1879
 * </xsl:template>
1880
 *
1881
 * and
1882
 *
1883
 * <xsl:template match="text()|@*">
1884
 *   <xsl:value-of select="."/>
1885
 * </xsl:template>
1886
 *
1887
 * Note also that namespace declarations are copied directly:
1888
 *
1889
 * the built-in template rule is the only template rule that is applied
1890
 * for namespace nodes.
1891
 */
1892
static void
1893
xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node,
1894
1.36M
        xsltStackElemPtr params) {
1895
1.36M
    xmlNodePtr copy;
1896
1.36M
    xmlNodePtr cur;
1897
1.36M
    int nbchild = 0, oldSize;
1898
1.36M
    int childno = 0, oldPos;
1899
1.36M
    xsltTemplatePtr template;
1900
1901
1.36M
    CHECK_STOPPED;
1902
    /*
1903
     * Handling of leaves
1904
     */
1905
1.15M
    switch (node->type) {
1906
22.5k
  case XML_DOCUMENT_NODE:
1907
22.5k
  case XML_HTML_DOCUMENT_NODE:
1908
486k
  case XML_ELEMENT_NODE:
1909
486k
      break;
1910
0
  case XML_CDATA_SECTION_NODE:
1911
#ifdef WITH_XSLT_DEBUG_PROCESS
1912
      XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
1913
       "xsltDefaultProcessOneNode: copy CDATA %s\n",
1914
    node->content));
1915
#endif
1916
0
      copy = xsltCopyText(ctxt, ctxt->insert, node, 0);
1917
0
      if (copy == NULL) {
1918
0
    xsltTransformError(ctxt, NULL, node,
1919
0
     "xsltDefaultProcessOneNode: cdata copy failed\n");
1920
0
      }
1921
0
      return;
1922
665k
  case XML_TEXT_NODE:
1923
#ifdef WITH_XSLT_DEBUG_PROCESS
1924
      if (node->content == NULL) {
1925
    XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
1926
     "xsltDefaultProcessOneNode: copy empty text\n"));
1927
    return;
1928
      } else {
1929
    XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
1930
     "xsltDefaultProcessOneNode: copy text %s\n",
1931
      node->content));
1932
            }
1933
#endif
1934
665k
      copy = xsltCopyText(ctxt, ctxt->insert, node, 0);
1935
665k
      if (copy == NULL) {
1936
49
    xsltTransformError(ctxt, NULL, node,
1937
49
     "xsltDefaultProcessOneNode: text copy failed\n");
1938
49
      }
1939
665k
      return;
1940
1.45k
  case XML_ATTRIBUTE_NODE:
1941
1.45k
      cur = node->children;
1942
1.45k
      while ((cur != NULL) && (cur->type != XML_TEXT_NODE))
1943
0
    cur = cur->next;
1944
1.45k
      if (cur == NULL) {
1945
0
    xsltTransformError(ctxt, NULL, node,
1946
0
     "xsltDefaultProcessOneNode: no text for attribute\n");
1947
1.45k
      } else {
1948
#ifdef WITH_XSLT_DEBUG_PROCESS
1949
    if (cur->content == NULL) {
1950
        XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
1951
         "xsltDefaultProcessOneNode: copy empty text\n"));
1952
    } else {
1953
        XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
1954
         "xsltDefaultProcessOneNode: copy text %s\n",
1955
      cur->content));
1956
                }
1957
#endif
1958
1.45k
    copy = xsltCopyText(ctxt, ctxt->insert, cur, 0);
1959
1.45k
    if (copy == NULL) {
1960
4
        xsltTransformError(ctxt, NULL, node,
1961
4
         "xsltDefaultProcessOneNode: text copy failed\n");
1962
4
    }
1963
1.45k
      }
1964
1.45k
      return;
1965
4.10k
  default:
1966
4.10k
      return;
1967
1.15M
    }
1968
    /*
1969
     * Handling of Elements: first pass, counting
1970
     */
1971
486k
    cur = node->children;
1972
1.01M
    while (cur != NULL) {
1973
529k
  if (IS_XSLT_REAL_NODE(cur))
1974
529k
      nbchild++;
1975
529k
  cur = cur->next;
1976
529k
    }
1977
1978
    /*
1979
     * Handling of Elements: second pass, actual processing
1980
     *
1981
     * Note that params are passed to the next template. This matches
1982
     * XSLT 2.0 behavior but doesn't conform to XSLT 1.0.
1983
     */
1984
486k
    oldSize = ctxt->xpathCtxt->contextSize;
1985
486k
    oldPos = ctxt->xpathCtxt->proximityPosition;
1986
486k
    cur = node->children;
1987
1.01M
    while (cur != NULL) {
1988
529k
  childno++;
1989
529k
  switch (cur->type) {
1990
0
      case XML_DOCUMENT_NODE:
1991
0
      case XML_HTML_DOCUMENT_NODE:
1992
334k
      case XML_ELEMENT_NODE:
1993
334k
    ctxt->xpathCtxt->contextSize = nbchild;
1994
334k
    ctxt->xpathCtxt->proximityPosition = childno;
1995
1996
334k
                if (ctxt->depth >= ctxt->maxTemplateDepth) {
1997
60
                    xsltTransformError(ctxt, NULL, cur,
1998
60
                        "xsltDefaultProcessOneNode: Maximum template depth "
1999
60
                        "exceeded.\n"
2000
60
                        "You can adjust xsltMaxDepth (--maxdepth) in order to "
2001
60
                        "raise the maximum number of nested template calls and "
2002
60
                        "variables/params (currently set to %d).\n",
2003
60
                        ctxt->maxTemplateDepth);
2004
60
                    ctxt->state = XSLT_STATE_STOPPED;
2005
60
                    return;
2006
60
                }
2007
334k
                ctxt->depth++;
2008
334k
    xsltProcessOneNode(ctxt, cur, params);
2009
334k
                ctxt->depth--;
2010
334k
    break;
2011
0
      case XML_CDATA_SECTION_NODE:
2012
0
    template = xsltGetTemplate(ctxt, cur, NULL);
2013
0
    if (template) {
2014
#ifdef WITH_XSLT_DEBUG_PROCESS
2015
        XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2016
     "xsltDefaultProcessOneNode: applying template for CDATA %s\n",
2017
             cur->content));
2018
#endif
2019
        /*
2020
        * Instantiate the xsl:template.
2021
        */
2022
0
        xsltApplyXSLTTemplate(ctxt, cur, template->content,
2023
0
      template, params);
2024
0
    } else /* if (ctxt->mode == NULL) */ {
2025
#ifdef WITH_XSLT_DEBUG_PROCESS
2026
        XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2027
         "xsltDefaultProcessOneNode: copy CDATA %s\n",
2028
             cur->content));
2029
#endif
2030
0
        copy = xsltCopyText(ctxt, ctxt->insert, cur, 0);
2031
0
        if (copy == NULL) {
2032
0
      xsltTransformError(ctxt, NULL, cur,
2033
0
          "xsltDefaultProcessOneNode: cdata copy failed\n");
2034
0
        }
2035
0
    }
2036
0
    break;
2037
182k
      case XML_TEXT_NODE:
2038
182k
    template = xsltGetTemplate(ctxt, cur, NULL);
2039
182k
    if (template) {
2040
#ifdef WITH_XSLT_DEBUG_PROCESS
2041
        XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2042
       "xsltDefaultProcessOneNode: applying template for text %s\n",
2043
             cur->content));
2044
#endif
2045
34.4k
        ctxt->xpathCtxt->contextSize = nbchild;
2046
34.4k
        ctxt->xpathCtxt->proximityPosition = childno;
2047
        /*
2048
        * Instantiate the xsl:template.
2049
        */
2050
34.4k
        xsltApplyXSLTTemplate(ctxt, cur, template->content,
2051
34.4k
      template, params);
2052
147k
    } else /* if (ctxt->mode == NULL) */ {
2053
#ifdef WITH_XSLT_DEBUG_PROCESS
2054
        if (cur->content == NULL) {
2055
      XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2056
       "xsltDefaultProcessOneNode: copy empty text\n"));
2057
        } else {
2058
      XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2059
         "xsltDefaultProcessOneNode: copy text %s\n",
2060
           cur->content));
2061
                    }
2062
#endif
2063
147k
        copy = xsltCopyText(ctxt, ctxt->insert, cur, 0);
2064
147k
        if (copy == NULL) {
2065
4.14k
      xsltTransformError(ctxt, NULL, cur,
2066
4.14k
          "xsltDefaultProcessOneNode: text copy failed\n");
2067
4.14k
        }
2068
147k
    }
2069
182k
    break;
2070
3.39k
      case XML_PI_NODE:
2071
12.4k
      case XML_COMMENT_NODE:
2072
12.4k
    template = xsltGetTemplate(ctxt, cur, NULL);
2073
12.4k
    if (template) {
2074
#ifdef WITH_XSLT_DEBUG_PROCESS
2075
        if (cur->type == XML_PI_NODE) {
2076
      XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2077
         "xsltDefaultProcessOneNode: template found for PI %s\n",
2078
                       cur->name));
2079
        } else if (cur->type == XML_COMMENT_NODE) {
2080
      XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2081
         "xsltDefaultProcessOneNode: template found for comment\n"));
2082
                    }
2083
#endif
2084
3.68k
        ctxt->xpathCtxt->contextSize = nbchild;
2085
3.68k
        ctxt->xpathCtxt->proximityPosition = childno;
2086
        /*
2087
        * Instantiate the xsl:template.
2088
        */
2089
3.68k
        xsltApplyXSLTTemplate(ctxt, cur, template->content,
2090
3.68k
      template, params);
2091
3.68k
    }
2092
12.4k
    break;
2093
0
      default:
2094
0
    break;
2095
529k
  }
2096
529k
  cur = cur->next;
2097
529k
    }
2098
486k
    ctxt->xpathCtxt->contextSize = oldSize;
2099
486k
    ctxt->xpathCtxt->proximityPosition = oldPos;
2100
486k
}
2101
2102
/**
2103
 * xsltProcessOneNode:
2104
 * @ctxt:  a XSLT process context
2105
 * @contextNode:  the "current node" in the source tree
2106
 * @withParams:  extra parameters (e.g. xsl:with-param) passed to the
2107
 *               template if any
2108
 *
2109
 * Process the source node.
2110
 */
2111
void
2112
xsltProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
2113
             xsltStackElemPtr withParams)
2114
1.89M
{
2115
1.89M
    xsltTemplatePtr templ;
2116
1.89M
    xmlNodePtr oldNode;
2117
2118
1.89M
    templ = xsltGetTemplate(ctxt, contextNode, NULL);
2119
    /*
2120
     * If no template is found, apply the default rule.
2121
     */
2122
1.89M
    if (templ == NULL) {
2123
#ifdef WITH_XSLT_DEBUG_PROCESS
2124
  if (contextNode->type == XML_DOCUMENT_NODE) {
2125
      XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2126
       "xsltProcessOneNode: no template found for /\n"));
2127
  } else if (contextNode->type == XML_CDATA_SECTION_NODE) {
2128
      XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2129
       "xsltProcessOneNode: no template found for CDATA\n"));
2130
  } else if (contextNode->type == XML_ATTRIBUTE_NODE) {
2131
      XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2132
       "xsltProcessOneNode: no template found for attribute %s\n",
2133
                       ((xmlAttrPtr) contextNode)->name));
2134
  } else  {
2135
      XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2136
       "xsltProcessOneNode: no template found for %s\n", contextNode->name));
2137
        }
2138
#endif
2139
1.36M
  oldNode = ctxt->node;
2140
1.36M
  ctxt->node = contextNode;
2141
1.36M
  xsltDefaultProcessOneNode(ctxt, contextNode, withParams);
2142
1.36M
  ctxt->node = oldNode;
2143
1.36M
  return;
2144
1.36M
    }
2145
2146
539k
    if (contextNode->type == XML_ATTRIBUTE_NODE) {
2147
3.15k
  xsltTemplatePtr oldCurTempRule = ctxt->currentTemplateRule;
2148
  /*
2149
  * Set the "current template rule".
2150
  */
2151
3.15k
  ctxt->currentTemplateRule = templ;
2152
2153
#ifdef WITH_XSLT_DEBUG_PROCESS
2154
  XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2155
       "xsltProcessOneNode: applying template '%s' for attribute %s\n",
2156
                   templ->match, contextNode->name));
2157
#endif
2158
3.15k
  xsltApplyXSLTTemplate(ctxt, contextNode, templ->content, templ, withParams);
2159
2160
3.15k
  ctxt->currentTemplateRule = oldCurTempRule;
2161
536k
    } else {
2162
536k
  xsltTemplatePtr oldCurTempRule = ctxt->currentTemplateRule;
2163
  /*
2164
  * Set the "current template rule".
2165
  */
2166
536k
  ctxt->currentTemplateRule = templ;
2167
2168
#ifdef WITH_XSLT_DEBUG_PROCESS
2169
  if (contextNode->type == XML_DOCUMENT_NODE) {
2170
      XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2171
       "xsltProcessOneNode: applying template '%s' for /\n",
2172
                       templ->match));
2173
  } else {
2174
      XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2175
       "xsltProcessOneNode: applying template '%s' for %s\n",
2176
                       templ->match, contextNode->name));
2177
        }
2178
#endif
2179
536k
  xsltApplyXSLTTemplate(ctxt, contextNode, templ->content, templ, withParams);
2180
2181
536k
  ctxt->currentTemplateRule = oldCurTempRule;
2182
536k
    }
2183
539k
}
2184
2185
#ifdef WITH_DEBUGGER
2186
static xmlNodePtr
2187
xsltDebuggerStartSequenceConstructor(xsltTransformContextPtr ctxt,
2188
             xmlNodePtr contextNode,
2189
             xmlNodePtr list,
2190
             xsltTemplatePtr templ,
2191
             int *addCallResult)
2192
{
2193
    xmlNodePtr debugedNode = NULL;
2194
2195
    if (ctxt->debugStatus != XSLT_DEBUG_NONE) {
2196
        if (templ) {
2197
            *addCallResult = xslAddCall(templ, templ->elem);
2198
        } else {
2199
            *addCallResult = xslAddCall(NULL, list);
2200
        }
2201
        switch (ctxt->debugStatus) {
2202
            case XSLT_DEBUG_RUN_RESTART:
2203
            case XSLT_DEBUG_QUIT:
2204
                if (*addCallResult)
2205
                    xslDropCall();
2206
                return(NULL);
2207
        }
2208
        if (templ) {
2209
            xslHandleDebugger(templ->elem, contextNode, templ, ctxt);
2210
            debugedNode = templ->elem;
2211
        } else if (list) {
2212
            xslHandleDebugger(list, contextNode, templ, ctxt);
2213
            debugedNode = list;
2214
        } else if (ctxt->inst) {
2215
            xslHandleDebugger(ctxt->inst, contextNode, templ, ctxt);
2216
            debugedNode = ctxt->inst;
2217
        }
2218
    }
2219
    return(debugedNode);
2220
}
2221
#endif /* WITH_DEBUGGER */
2222
2223
/**
2224
 * xsltLocalVariablePush:
2225
 * @ctxt: the transformation context
2226
 * @variable: variable to be pushed to the variable stack
2227
 * @level: new value for variable's level
2228
 *
2229
 * Places the variable onto the local variable stack
2230
 *
2231
 * Returns: 0 for success, -1 for any error
2232
 * **NOTE:**
2233
 * This is an internal routine and should not be called by users!
2234
 */
2235
int
2236
xsltLocalVariablePush(xsltTransformContextPtr ctxt,
2237
          xsltStackElemPtr variable,
2238
          int level)
2239
13.8k
{
2240
13.8k
    if (ctxt->varsNr >= ctxt->varsMax) {
2241
311
        xsltStackElemPtr *tmp;
2242
311
        int newMax = ctxt->varsMax == 0 ? 10 : 2 * ctxt->varsMax;
2243
2244
311
  tmp = (xsltStackElemPtr *) xmlRealloc(ctxt->varsTab,
2245
311
                newMax * sizeof(*tmp));
2246
311
  if (tmp == NULL) {
2247
2
      xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
2248
2
      return (-1);
2249
2
  }
2250
309
        ctxt->varsTab = tmp;
2251
309
        ctxt->varsMax = newMax;
2252
309
    }
2253
13.8k
    ctxt->varsTab[ctxt->varsNr++] = variable;
2254
13.8k
    ctxt->vars = variable;
2255
13.8k
    variable->level = level;
2256
13.8k
    return(0);
2257
13.8k
}
2258
2259
/**
2260
 * xsltReleaseLocalRVTs:
2261
 *
2262
 * Fragments which are results of extension instructions
2263
 * are preserved; all other fragments are freed/cached.
2264
 */
2265
static void
2266
xsltReleaseLocalRVTs(xsltTransformContextPtr ctxt, xmlDocPtr base)
2267
30.0k
{
2268
30.0k
    xmlDocPtr cur = ctxt->localRVT, tmp;
2269
2270
30.0k
    if (cur == base)
2271
17.1k
        return;
2272
12.9k
    if (cur->prev != NULL)
2273
0
        xsltTransformError(ctxt, NULL, NULL, "localRVT not head of list\n");
2274
2275
    /* Reset localRVT early because some RVTs might be registered again. */
2276
12.9k
    ctxt->localRVT = base;
2277
12.9k
    if (base != NULL)
2278
967
        base->prev = NULL;
2279
2280
291k
    do {
2281
291k
        tmp = cur;
2282
291k
        cur = (xmlDocPtr) cur->next;
2283
291k
        if (tmp->compression == XSLT_RVT_LOCAL) {
2284
290k
            xsltReleaseRVT(ctxt, tmp);
2285
290k
        } else if (tmp->compression == XSLT_RVT_GLOBAL) {
2286
0
            xsltRegisterPersistRVT(ctxt, tmp);
2287
1.18k
        } else if (tmp->compression == XSLT_RVT_FUNC_RESULT) {
2288
            /*
2289
             * This will either register the RVT again or move it to the
2290
             * context variable.
2291
             */
2292
1.18k
            xsltRegisterLocalRVT(ctxt, tmp);
2293
1.18k
            tmp->compression = XSLT_RVT_FUNC_RESULT;
2294
1.18k
        } else {
2295
0
            xmlGenericError(xmlGenericErrorContext,
2296
0
                    "xsltReleaseLocalRVTs: Unexpected RVT flag %p\n",
2297
0
                    tmp->psvi);
2298
0
        }
2299
291k
    } while (cur != base);
2300
12.9k
}
2301
2302
/**
2303
 * xsltApplySequenceConstructor:
2304
 * @ctxt:  a XSLT process context
2305
 * @contextNode:  the "current node" in the source tree
2306
 * @list:  the nodes of a sequence constructor;
2307
 *         (plus leading xsl:param elements)
2308
 * @templ: the compiled xsl:template (optional)
2309
 *
2310
 * Processes a sequence constructor.
2311
 *
2312
 * NOTE: ctxt->currentTemplateRule was introduced to reflect the
2313
 * semantics of "current template rule". I.e. the field ctxt->templ
2314
 * is not intended to reflect this, thus always pushed onto the
2315
 * template stack.
2316
 */
2317
static void
2318
xsltApplySequenceConstructor(xsltTransformContextPtr ctxt,
2319
           xmlNodePtr contextNode, xmlNodePtr list,
2320
           xsltTemplatePtr templ)
2321
692k
{
2322
692k
    xmlNodePtr oldInsert, oldInst, oldCurInst, oldContextNode;
2323
692k
    xmlNodePtr cur, insert, copy = NULL;
2324
692k
    int level = 0, oldVarsNr;
2325
692k
    xmlDocPtr oldLocalFragmentTop;
2326
2327
#ifdef XSLT_REFACTORED
2328
    xsltStylePreCompPtr info;
2329
#endif
2330
2331
#ifdef WITH_DEBUGGER
2332
    int addCallResult = 0;
2333
    xmlNodePtr debuggedNode = NULL;
2334
#endif
2335
2336
692k
    if (ctxt == NULL)
2337
0
  return;
2338
2339
#ifdef WITH_DEBUGGER
2340
    if (ctxt->debugStatus != XSLT_DEBUG_NONE) {
2341
  debuggedNode =
2342
      xsltDebuggerStartSequenceConstructor(ctxt, contextNode,
2343
    list, templ, &addCallResult);
2344
  if (debuggedNode == NULL)
2345
      return;
2346
    }
2347
#endif
2348
2349
692k
    if (list == NULL)
2350
876
        return;
2351
1.37M
    CHECK_STOPPED;
2352
2353
    /*
2354
    * Check for infinite recursion: stop if the maximum of nested templates
2355
    * is excceeded. Adjust xsltMaxDepth if you need more.
2356
    */
2357
1.37M
    if (ctxt->depth >= ctxt->maxTemplateDepth) {
2358
400
        xsltTransformError(ctxt, NULL, list,
2359
400
      "xsltApplySequenceConstructor: A potential infinite template "
2360
400
            "recursion was detected.\n"
2361
400
      "You can adjust xsltMaxDepth (--maxdepth) in order to "
2362
400
      "raise the maximum number of nested template calls and "
2363
400
      "variables/params (currently set to %d).\n",
2364
400
      ctxt->maxTemplateDepth);
2365
400
        xsltDebug(ctxt, contextNode, list, NULL);
2366
400
  ctxt->state = XSLT_STATE_STOPPED;
2367
400
        return;
2368
400
    }
2369
684k
    ctxt->depth++;
2370
2371
684k
    oldLocalFragmentTop = ctxt->localRVT;
2372
684k
    oldInsert = insert = ctxt->insert;
2373
684k
    oldInst = oldCurInst = ctxt->inst;
2374
684k
    oldContextNode = ctxt->node;
2375
    /*
2376
    * Save current number of variables on the stack; new vars are popped when
2377
    * exiting.
2378
    */
2379
684k
    oldVarsNr = ctxt->varsNr;
2380
    /*
2381
    * Process the sequence constructor.
2382
    */
2383
684k
    cur = list;
2384
4.29M
    while (cur != NULL) {
2385
3.69M
        if (ctxt->opLimit != 0) {
2386
3.69M
            if (ctxt->opCount >= ctxt->opLimit) {
2387
13
    xsltTransformError(ctxt, NULL, cur,
2388
13
        "xsltApplySequenceConstructor: "
2389
13
                    "Operation limit exceeded\n");
2390
13
          ctxt->state = XSLT_STATE_STOPPED;
2391
13
                goto error;
2392
13
            }
2393
3.69M
            ctxt->opCount += 1;
2394
3.69M
        }
2395
2396
3.69M
        ctxt->inst = cur;
2397
2398
#ifdef WITH_DEBUGGER
2399
        switch (ctxt->debugStatus) {
2400
            case XSLT_DEBUG_RUN_RESTART:
2401
            case XSLT_DEBUG_QUIT:
2402
                break;
2403
2404
        }
2405
#endif
2406
        /*
2407
         * Test; we must have a valid insertion point.
2408
         */
2409
3.69M
        if (insert == NULL) {
2410
2411
#ifdef WITH_XSLT_DEBUG_PROCESS
2412
            XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
2413
    "xsltApplySequenceConstructor: insert == NULL !\n"));
2414
#endif
2415
561
            goto error;
2416
561
        }
2417
2418
#ifdef WITH_DEBUGGER
2419
        if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (debuggedNode != cur))
2420
            xslHandleDebugger(cur, contextNode, templ, ctxt);
2421
#endif
2422
2423
#ifdef XSLT_REFACTORED
2424
  if (cur->type == XML_ELEMENT_NODE) {
2425
      info = (xsltStylePreCompPtr) cur->psvi;
2426
      /*
2427
      * We expect a compiled representation on:
2428
      * 1) XSLT instructions of this XSLT version (1.0)
2429
      *    (with a few exceptions)
2430
      * 2) Literal result elements
2431
      * 3) Extension instructions
2432
      * 4) XSLT instructions of future XSLT versions
2433
      *    (forwards-compatible mode).
2434
      */
2435
      if (info == NULL) {
2436
    /*
2437
    * Handle the rare cases where we don't expect a compiled
2438
    * representation on an XSLT element.
2439
    */
2440
    if (IS_XSLT_ELEM_FAST(cur) && IS_XSLT_NAME(cur, "message")) {
2441
        xsltMessage(ctxt, contextNode, cur);
2442
        goto skip_children;
2443
    }
2444
    /*
2445
    * Something really went wrong:
2446
    */
2447
    xsltTransformError(ctxt, NULL, cur,
2448
        "Internal error in xsltApplySequenceConstructor(): "
2449
        "The element '%s' in the stylesheet has no compiled "
2450
        "representation.\n",
2451
        cur->name);
2452
                goto skip_children;
2453
            }
2454
2455
      if (info->type == XSLT_FUNC_LITERAL_RESULT_ELEMENT) {
2456
    xsltStyleItemLRElementInfoPtr lrInfo =
2457
        (xsltStyleItemLRElementInfoPtr) info;
2458
    /*
2459
    * Literal result elements
2460
    * --------------------------------------------------------
2461
    */
2462
#ifdef WITH_XSLT_DEBUG_PROCESS
2463
    XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,
2464
        xsltGenericDebug(xsltGenericDebugContext,
2465
        "xsltApplySequenceConstructor: copy literal result "
2466
        "element '%s'\n", cur->name));
2467
#endif
2468
    /*
2469
    * Copy the raw element-node.
2470
    * OLD: if ((copy = xsltShallowCopyElem(ctxt, cur, insert))
2471
    *     == NULL)
2472
    *   goto error;
2473
    */
2474
    copy = xmlDocCopyNode(cur, insert->doc, 0);
2475
    if (copy == NULL) {
2476
        xsltTransformError(ctxt, NULL, cur,
2477
      "Internal error in xsltApplySequenceConstructor(): "
2478
      "Failed to copy literal result element '%s'.\n",
2479
      cur->name);
2480
        goto error;
2481
    } else {
2482
        /*
2483
        * Add the element-node to the result tree.
2484
        */
2485
        copy->doc = ctxt->output;
2486
        copy = xsltAddChild(insert, copy);
2487
        /*
2488
        * Create effective namespaces declarations.
2489
        * OLD: xsltCopyNamespaceList(ctxt, copy, cur->nsDef);
2490
        */
2491
        if (lrInfo->effectiveNs != NULL) {
2492
      xsltEffectiveNsPtr effNs = lrInfo->effectiveNs;
2493
      xmlNsPtr ns, lastns = NULL;
2494
2495
      while (effNs != NULL) {
2496
          /*
2497
          * Avoid generating redundant namespace
2498
          * declarations; thus lookup if there is already
2499
          * such a ns-decl in the result.
2500
          */
2501
          ns = xmlSearchNs(copy->doc, copy, effNs->prefix);
2502
          if ((ns != NULL) &&
2503
        (xmlStrEqual(ns->href, effNs->nsName)))
2504
          {
2505
        effNs = effNs->next;
2506
        continue;
2507
          }
2508
          ns = xmlNewNs(copy, effNs->nsName, effNs->prefix);
2509
          if (ns == NULL) {
2510
        xsltTransformError(ctxt, NULL, cur,
2511
            "Internal error in "
2512
            "xsltApplySequenceConstructor(): "
2513
            "Failed to copy a namespace "
2514
            "declaration.\n");
2515
        goto error;
2516
          }
2517
2518
          if (lastns == NULL)
2519
        copy->nsDef = ns;
2520
          else
2521
        lastns->next =ns;
2522
          lastns = ns;
2523
2524
          effNs = effNs->next;
2525
      }
2526
2527
        }
2528
        /*
2529
        * NOTE that we don't need to apply ns-alising: this was
2530
        *  already done at compile-time.
2531
        */
2532
        if (cur->ns != NULL) {
2533
      /*
2534
      * If there's no such ns-decl in the result tree,
2535
      * then xsltGetSpecialNamespace() will
2536
      * create a ns-decl on the copied node.
2537
      */
2538
      copy->ns = xsltGetSpecialNamespace(ctxt, cur,
2539
          cur->ns->href, cur->ns->prefix, copy);
2540
        } else {
2541
      /*
2542
      * Undeclare the default namespace if needed.
2543
      * This can be skipped, if the result element has
2544
      *  no ns-decls, in which case the result element
2545
      *  obviously does not declare a default namespace;
2546
      *  AND there's either no parent, or the parent
2547
      *  element is in no namespace; this means there's no
2548
      *  default namespace is scope to care about.
2549
      *
2550
      * REVISIT: This might result in massive
2551
      *  generation of ns-decls if nodes in a default
2552
      *  namespaces are mixed with nodes in no namespace.
2553
      *
2554
      */
2555
      if (copy->nsDef ||
2556
          ((insert != NULL) &&
2557
           (insert->type == XML_ELEMENT_NODE) &&
2558
           (insert->ns != NULL)))
2559
      {
2560
          xsltGetSpecialNamespace(ctxt, cur,
2561
        NULL, NULL, copy);
2562
      }
2563
        }
2564
    }
2565
    /*
2566
    * SPEC XSLT 2.0 "Each attribute of the literal result
2567
    *  element, other than an attribute in the XSLT namespace,
2568
    *  is processed to produce an attribute for the element in
2569
    *  the result tree."
2570
    * NOTE: See bug #341325.
2571
    */
2572
    if (cur->properties != NULL) {
2573
        xsltAttrListTemplateProcess(ctxt, copy, cur->properties);
2574
    }
2575
      } else if (IS_XSLT_ELEM_FAST(cur)) {
2576
    /*
2577
    * XSLT instructions
2578
    * --------------------------------------------------------
2579
    */
2580
    if (info->type == XSLT_FUNC_UNKOWN_FORWARDS_COMPAT) {
2581
        /*
2582
        * We hit an unknown XSLT element.
2583
        * Try to apply one of the fallback cases.
2584
        */
2585
        ctxt->insert = insert;
2586
        if (!xsltApplyFallbacks(ctxt, contextNode, cur)) {
2587
      xsltTransformError(ctxt, NULL, cur,
2588
          "The is no fallback behaviour defined for "
2589
          "the unknown XSLT element '%s'.\n",
2590
          cur->name);
2591
        }
2592
        ctxt->insert = oldInsert;
2593
    } else if (info->func != NULL) {
2594
        /*
2595
        * Execute the XSLT instruction.
2596
        */
2597
        ctxt->insert = insert;
2598
2599
        info->func(ctxt, contextNode, cur,
2600
      (xsltElemPreCompPtr) info);
2601
2602
        /*
2603
        * Cleanup temporary tree fragments.
2604
        */
2605
        if (oldLocalFragmentTop != ctxt->localRVT)
2606
      xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
2607
2608
        ctxt->insert = oldInsert;
2609
    } else if (info->type == XSLT_FUNC_VARIABLE) {
2610
        xsltStackElemPtr tmpvar = ctxt->vars;
2611
2612
        xsltParseStylesheetVariable(ctxt, cur);
2613
2614
        if (tmpvar != ctxt->vars) {
2615
      /*
2616
      * TODO: Using a @tmpvar is an annoying workaround, but
2617
      *  the current mechanisms do not provide any other way
2618
      *  of knowing if the var was really pushed onto the
2619
      *  stack.
2620
      */
2621
      ctxt->vars->level = level;
2622
        }
2623
    } else if (info->type == XSLT_FUNC_MESSAGE) {
2624
        /*
2625
        * TODO: Won't be hit, since we don't compile xsl:message.
2626
        */
2627
        xsltMessage(ctxt, contextNode, cur);
2628
    } else {
2629
        xsltTransformError(ctxt, NULL, cur,
2630
      "Unexpected XSLT element '%s'.\n", cur->name);
2631
    }
2632
    goto skip_children;
2633
2634
      } else {
2635
    xsltTransformFunction func;
2636
    /*
2637
    * Extension intructions (elements)
2638
    * --------------------------------------------------------
2639
    */
2640
    if (cur->psvi == xsltExtMarker) {
2641
        /*
2642
        * The xsltExtMarker was set during the compilation
2643
        * of extension instructions if there was no registered
2644
        * handler for this specific extension function at
2645
        * compile-time.
2646
        * Libxslt will now lookup if a handler is
2647
        * registered in the context of this transformation.
2648
        */
2649
        func = xsltExtElementLookup(ctxt, cur->name,
2650
                                                cur->ns->href);
2651
    } else
2652
        func = ((xsltElemPreCompPtr) cur->psvi)->func;
2653
2654
    if (func == NULL) {
2655
        /*
2656
        * No handler available.
2657
        * Try to execute fallback behaviour via xsl:fallback.
2658
        */
2659
#ifdef WITH_XSLT_DEBUG_PROCESS
2660
        XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,
2661
      xsltGenericDebug(xsltGenericDebugContext,
2662
          "xsltApplySequenceConstructor: unknown extension %s\n",
2663
          cur->name));
2664
#endif
2665
        ctxt->insert = insert;
2666
        if (!xsltApplyFallbacks(ctxt, contextNode, cur)) {
2667
      xsltTransformError(ctxt, NULL, cur,
2668
          "Unknown extension instruction '{%s}%s'.\n",
2669
          cur->ns->href, cur->name);
2670
        }
2671
        ctxt->insert = oldInsert;
2672
    } else {
2673
        /*
2674
        * Execute the handler-callback.
2675
        */
2676
#ifdef WITH_XSLT_DEBUG_PROCESS
2677
        XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
2678
      "xsltApplySequenceConstructor: extension construct %s\n",
2679
      cur->name));
2680
#endif
2681
                    /*
2682
                     * Disable the xsltCopyTextString optimization for
2683
                     * extension elements. Extensions could append text using
2684
                     * xmlAddChild which will free the buffer pointed to by
2685
                     * 'lasttext'. This buffer could later be reallocated with
2686
                     * a different size than recorded in 'lasttsize'. See bug
2687
                     * #777432.
2688
                     */
2689
                    if (cur->psvi == xsltExtMarker) {
2690
                        ctxt->lasttext = NULL;
2691
                    }
2692
2693
        ctxt->insert = insert;
2694
2695
        func(ctxt, contextNode, cur, cur->psvi);
2696
2697
        /*
2698
        * Cleanup temporary tree fragments.
2699
        */
2700
        if (oldLocalFragmentTop != ctxt->localRVT)
2701
      xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
2702
2703
        ctxt->insert = oldInsert;
2704
    }
2705
    goto skip_children;
2706
      }
2707
2708
  } else if (XSLT_IS_TEXT_NODE(cur)) {
2709
      /*
2710
      * Text
2711
      * ------------------------------------------------------------
2712
      */
2713
#ifdef WITH_XSLT_DEBUG_PROCESS
2714
            if (cur->name == xmlStringTextNoenc) {
2715
                XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,
2716
        xsltGenericDebug(xsltGenericDebugContext,
2717
        "xsltApplySequenceConstructor: copy unescaped text '%s'\n",
2718
        cur->content));
2719
            } else {
2720
                XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,
2721
        xsltGenericDebug(xsltGenericDebugContext,
2722
        "xsltApplySequenceConstructor: copy text '%s'\n",
2723
        cur->content));
2724
            }
2725
#endif
2726
            if (xsltCopyText(ctxt, insert, cur, ctxt->internalized) == NULL)
2727
    goto error;
2728
  }
2729
2730
#else /* XSLT_REFACTORED */
2731
2732
3.69M
        if (IS_XSLT_ELEM(cur)) {
2733
            /*
2734
             * This is an XSLT node
2735
             */
2736
1.52M
            xsltStylePreCompPtr info = (xsltStylePreCompPtr) cur->psvi;
2737
2738
1.52M
            if (info == NULL) {
2739
71.7k
                if (IS_XSLT_NAME(cur, "message")) {
2740
488
                    xsltMessage(ctxt, contextNode, cur);
2741
71.2k
                } else {
2742
                    /*
2743
                     * That's an error try to apply one of the fallback cases
2744
                     */
2745
71.2k
                    ctxt->insert = insert;
2746
71.2k
                    if (!xsltApplyFallbacks(ctxt, contextNode, cur)) {
2747
70.7k
                        xsltGenericError(xsltGenericErrorContext,
2748
70.7k
          "xsltApplySequenceConstructor: %s was not compiled\n",
2749
70.7k
          cur->name);
2750
70.7k
                    }
2751
71.2k
                    ctxt->insert = oldInsert;
2752
71.2k
                }
2753
71.7k
                goto skip_children;
2754
71.7k
            }
2755
2756
1.45M
            if (info->func != NULL) {
2757
1.41M
    oldCurInst = ctxt->inst;
2758
1.41M
    ctxt->inst = cur;
2759
1.41M
                ctxt->insert = insert;
2760
2761
1.41M
                info->func(ctxt, contextNode, cur, (xsltElemPreCompPtr) info);
2762
2763
    /*
2764
    * Cleanup temporary tree fragments.
2765
    */
2766
1.41M
    if (oldLocalFragmentTop != ctxt->localRVT)
2767
12.4k
        xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
2768
2769
1.41M
                ctxt->insert = oldInsert;
2770
1.41M
    ctxt->inst = oldCurInst;
2771
1.41M
                goto skip_children;
2772
1.41M
            }
2773
2774
42.8k
            if (IS_XSLT_NAME(cur, "variable")) {
2775
41.0k
    xsltStackElemPtr tmpvar = ctxt->vars;
2776
2777
41.0k
    oldCurInst = ctxt->inst;
2778
41.0k
    ctxt->inst = cur;
2779
2780
41.0k
    xsltParseStylesheetVariable(ctxt, cur);
2781
2782
41.0k
    ctxt->inst = oldCurInst;
2783
2784
41.0k
    if (tmpvar != ctxt->vars) {
2785
        /*
2786
        * TODO: Using a @tmpvar is an annoying workaround, but
2787
        *  the current mechanisms do not provide any other way
2788
        *  of knowing if the var was really pushed onto the
2789
        *  stack.
2790
        */
2791
40.0k
        ctxt->vars->level = level;
2792
40.0k
    }
2793
41.0k
            } else if (IS_XSLT_NAME(cur, "message")) {
2794
0
                xsltMessage(ctxt, contextNode, cur);
2795
1.73k
            } else {
2796
1.73k
    xsltTransformError(ctxt, NULL, cur,
2797
1.73k
        "Unexpected XSLT element '%s'.\n", cur->name);
2798
1.73k
            }
2799
42.8k
            goto skip_children;
2800
2.16M
        } else if ((cur->type == XML_TEXT_NODE) ||
2801
2.16M
                   (cur->type == XML_CDATA_SECTION_NODE)) {
2802
2803
            /*
2804
             * This text comes from the stylesheet
2805
             * For stylesheets, the set of whitespace-preserving
2806
             * element names consists of just xsl:text.
2807
             */
2808
#ifdef WITH_XSLT_DEBUG_PROCESS
2809
            if (cur->type == XML_CDATA_SECTION_NODE) {
2810
                XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
2811
                                 "xsltApplySequenceConstructor: copy CDATA text %s\n",
2812
                                 cur->content));
2813
            } else if (cur->name == xmlStringTextNoenc) {
2814
                XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
2815
                                 "xsltApplySequenceConstructor: copy unescaped text %s\n",
2816
                                 cur->content));
2817
            } else {
2818
                XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
2819
                                 "xsltApplySequenceConstructor: copy text %s\n",
2820
                                 cur->content));
2821
            }
2822
#endif
2823
1.65M
            if (xsltCopyText(ctxt, insert, cur, ctxt->internalized) == NULL)
2824
1.33k
    goto error;
2825
1.65M
        } else if ((cur->type == XML_ELEMENT_NODE) &&
2826
513k
                   (cur->ns != NULL) && (cur->psvi != NULL)) {
2827
34.5k
            xsltTransformFunction function;
2828
2829
34.5k
      oldCurInst = ctxt->inst;
2830
34.5k
      ctxt->inst = cur;
2831
            /*
2832
             * Flagged as an extension element
2833
             */
2834
34.5k
            if (cur->psvi == xsltExtMarker)
2835
1.74k
                function = xsltExtElementLookup(ctxt, cur->name,
2836
1.74k
                                                cur->ns->href);
2837
32.7k
            else
2838
32.7k
                function = ((xsltElemPreCompPtr) cur->psvi)->func;
2839
2840
34.5k
            if (function == NULL) {
2841
1.74k
                xmlNodePtr child;
2842
1.74k
                int found = 0;
2843
2844
#ifdef WITH_XSLT_DEBUG_PROCESS
2845
                XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
2846
        "xsltApplySequenceConstructor: unknown extension %s\n",
2847
                    cur->name));
2848
#endif
2849
                /*
2850
                 * Search if there are fallbacks
2851
                 */
2852
1.74k
                ctxt->insert = insert;
2853
1.74k
                child = cur->children;
2854
5.57k
                while (child != NULL) {
2855
3.82k
                    if ((IS_XSLT_ELEM(child)) &&
2856
3.82k
                        (IS_XSLT_NAME(child, "fallback")))
2857
5
        {
2858
5
                        found = 1;
2859
5
                        xsltApplySequenceConstructor(ctxt, contextNode,
2860
5
          child->children, NULL);
2861
5
                    }
2862
3.82k
                    child = child->next;
2863
3.82k
                }
2864
1.74k
                ctxt->insert = oldInsert;
2865
2866
1.74k
                if (!found) {
2867
1.74k
                    xsltTransformError(ctxt, NULL, cur,
2868
1.74k
      "xsltApplySequenceConstructor: failed to find extension %s\n",
2869
1.74k
      cur->name);
2870
1.74k
                }
2871
32.7k
            } else {
2872
#ifdef WITH_XSLT_DEBUG_PROCESS
2873
                XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
2874
        "xsltApplySequenceConstructor: extension construct %s\n",
2875
                    cur->name));
2876
#endif
2877
2878
                /*
2879
                 * Disable the xsltCopyTextString optimization for
2880
                 * extension elements. Extensions could append text using
2881
                 * xmlAddChild which will free the buffer pointed to by
2882
                 * 'lasttext'. This buffer could later be reallocated with
2883
                 * a different size than recorded in 'lasttsize'. See bug
2884
                 * #777432.
2885
                 */
2886
32.7k
                if (cur->psvi == xsltExtMarker) {
2887
0
              ctxt->lasttext = NULL;
2888
0
                }
2889
2890
32.7k
                ctxt->insert = insert;
2891
2892
32.7k
                function(ctxt, contextNode, cur, cur->psvi);
2893
    /*
2894
    * Cleanup temporary tree fragments.
2895
    */
2896
32.7k
    if (oldLocalFragmentTop != ctxt->localRVT)
2897
231
        xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
2898
2899
32.7k
                ctxt->insert = oldInsert;
2900
2901
32.7k
            }
2902
34.5k
      ctxt->inst = oldCurInst;
2903
34.5k
            goto skip_children;
2904
478k
        } else if (cur->type == XML_ELEMENT_NODE) {
2905
#ifdef WITH_XSLT_DEBUG_PROCESS
2906
            XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
2907
    "xsltApplySequenceConstructor: copy node %s\n",
2908
                cur->name));
2909
#endif
2910
477k
      oldCurInst = ctxt->inst;
2911
477k
      ctxt->inst = cur;
2912
2913
477k
            if ((copy = xsltShallowCopyElem(ctxt, cur, insert, 1)) == NULL)
2914
3.23k
    goto error;
2915
            /*
2916
             * Add extra namespaces inherited from the current template
2917
             * if we are in the first level children and this is a
2918
       * "real" template.
2919
             */
2920
474k
            if ((templ != NULL) && (oldInsert == insert) &&
2921
474k
                (ctxt->templ != NULL) && (ctxt->templ->inheritedNs != NULL)) {
2922
245k
                int i;
2923
245k
                xmlNsPtr ns, ret;
2924
2925
2.44M
                for (i = 0; i < ctxt->templ->inheritedNsNr; i++) {
2926
2.19M
        const xmlChar *URI = NULL;
2927
2.19M
        xsltStylesheetPtr style;
2928
2.19M
                    ns = ctxt->templ->inheritedNs[i];
2929
2930
        /* Note that the XSLT namespace was already excluded
2931
        * in xsltGetInheritedNsList().
2932
        */
2933
#if 0
2934
        if (xmlStrEqual(ns->href, XSLT_NAMESPACE))
2935
      continue;
2936
#endif
2937
2.19M
        style = ctxt->style;
2938
4.41M
        while (style != NULL) {
2939
2.21M
      if (style->nsAliases != NULL)
2940
1.70k
          URI = (const xmlChar *)
2941
1.70k
        xmlHashLookup(style->nsAliases, ns->href);
2942
2.21M
      if (URI != NULL)
2943
159
          break;
2944
2945
2.21M
      style = xsltNextImport(style);
2946
2.21M
        }
2947
2.19M
        if (URI == UNDEFINED_DEFAULT_NS)
2948
0
      continue;
2949
2.19M
        if (URI == NULL)
2950
2.19M
      URI = ns->href;
2951
        /*
2952
        * TODO: The following will still be buggy for the
2953
        * non-refactored code.
2954
        */
2955
2.19M
        ret = xmlSearchNs(copy->doc, copy, ns->prefix);
2956
2.19M
        if ((ret == NULL) || (!xmlStrEqual(ret->href, URI)))
2957
823k
        {
2958
823k
      xmlNewNs(copy, URI, ns->prefix);
2959
823k
        }
2960
2.19M
                }
2961
245k
    if (copy->ns != NULL) {
2962
        /*
2963
         * Fix the node namespace if needed
2964
         */
2965
71.3k
        copy->ns = xsltGetNamespace(ctxt, cur, copy->ns, copy);
2966
71.3k
    }
2967
245k
            }
2968
      /*
2969
             * all the attributes are directly inherited
2970
             */
2971
474k
            if (cur->properties != NULL) {
2972
149k
                xsltAttrListTemplateProcess(ctxt, copy, cur->properties);
2973
149k
            }
2974
474k
      ctxt->inst = oldCurInst;
2975
474k
        }
2976
2.12M
#endif /* else of XSLT_REFACTORED */
2977
2978
        /*
2979
         * Descend into content in document order.
2980
         */
2981
2.12M
        if (cur->children != NULL) {
2982
275k
            if (cur->children->type != XML_ENTITY_DECL) {
2983
275k
                cur = cur->children;
2984
275k
    level++;
2985
275k
                if (copy != NULL)
2986
275k
                    insert = copy;
2987
275k
                continue;
2988
275k
            }
2989
275k
        }
2990
2991
3.41M
skip_children:
2992
  /*
2993
  * If xslt:message was just processed, we might have hit a
2994
  * terminate='yes'; if so, then break the loop and clean up.
2995
  * TODO: Do we need to check this also before trying to descend
2996
  *  into the content?
2997
  */
2998
3.41M
  if (ctxt->state == XSLT_STATE_STOPPED)
2999
80.2k
      break;
3000
3.33M
        if (cur->next != NULL) {
3001
2.63M
            cur = cur->next;
3002
2.63M
            continue;
3003
2.63M
        }
3004
3005
815k
        do {
3006
815k
            cur = cur->parent;
3007
815k
      level--;
3008
      /*
3009
      * Pop variables/params (xsl:variable and xsl:param).
3010
      */
3011
815k
      if ((ctxt->varsNr > oldVarsNr) && (ctxt->vars->level > level)) {
3012
14.7k
    xsltLocalVariablePop(ctxt, oldVarsNr, level);
3013
14.7k
      }
3014
3015
815k
            insert = insert->parent;
3016
815k
            if (cur == NULL)
3017
0
                break;
3018
815k
            if (cur == list->parent) {
3019
599k
                cur = NULL;
3020
599k
                break;
3021
599k
            }
3022
216k
            if (cur->next != NULL) {
3023
102k
                cur = cur->next;
3024
102k
                break;
3025
102k
            }
3026
216k
        } while (cur != NULL);
3027
701k
    }
3028
3029
684k
error:
3030
    /*
3031
    * In case of errors: pop remaining variables.
3032
    */
3033
684k
    if (ctxt->varsNr > oldVarsNr)
3034
19.8k
  xsltLocalVariablePop(ctxt, oldVarsNr, -1);
3035
3036
684k
    ctxt->node = oldContextNode;
3037
684k
    ctxt->inst = oldInst;
3038
684k
    ctxt->insert = oldInsert;
3039
3040
684k
    ctxt->depth--;
3041
3042
#ifdef WITH_DEBUGGER
3043
    if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (addCallResult)) {
3044
        xslDropCall();
3045
    }
3046
#endif
3047
684k
}
3048
3049
/*
3050
* xsltApplyXSLTTemplate:
3051
* @ctxt:  a XSLT transformation context
3052
* @contextNode:  the node in the source tree.
3053
* @list:  the nodes of a sequence constructor;
3054
*         (plus leading xsl:param elements)
3055
* @templ: the compiled xsl:template declaration;
3056
*         NULL if a sequence constructor
3057
* @withParams:  a set of caller-parameters (xsl:with-param) or NULL
3058
*
3059
* Called by:
3060
* - xsltApplyImports()
3061
* - xsltCallTemplate()
3062
* - xsltDefaultProcessOneNode()
3063
* - xsltProcessOneNode()
3064
*/
3065
static void
3066
xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt,
3067
          xmlNodePtr contextNode,
3068
          xmlNodePtr list,
3069
          xsltTemplatePtr templ,
3070
          xsltStackElemPtr withParams)
3071
579k
{
3072
579k
    int oldVarsBase = 0;
3073
579k
    xmlNodePtr cur;
3074
579k
    xsltStackElemPtr tmpParam = NULL;
3075
579k
    xmlDocPtr oldUserFragmentTop;
3076
#ifdef WITH_PROFILER
3077
    long start = 0;
3078
#endif
3079
3080
#ifdef XSLT_REFACTORED
3081
    xsltStyleItemParamPtr iparam;
3082
#else
3083
579k
    xsltStylePreCompPtr iparam;
3084
579k
#endif
3085
3086
#ifdef WITH_DEBUGGER
3087
    int addCallResult = 0;
3088
#endif
3089
3090
579k
    if (ctxt == NULL)
3091
0
  return;
3092
579k
    if (templ == NULL) {
3093
0
  xsltTransformError(ctxt, NULL, list,
3094
0
      "xsltApplyXSLTTemplate: Bad arguments; @templ is mandatory.\n");
3095
0
  return;
3096
0
    }
3097
3098
#ifdef WITH_DEBUGGER
3099
    if (ctxt->debugStatus != XSLT_DEBUG_NONE) {
3100
  if (xsltDebuggerStartSequenceConstructor(ctxt, contextNode,
3101
    list, templ, &addCallResult) == NULL)
3102
      return;
3103
    }
3104
#endif
3105
3106
579k
    if (list == NULL)
3107
269
        return;
3108
1.10M
    CHECK_STOPPED;
3109
3110
1.10M
    if (ctxt->varsNr >= ctxt->maxTemplateVars)
3111
0
  {
3112
0
        xsltTransformError(ctxt, NULL, list,
3113
0
      "xsltApplyXSLTTemplate: A potential infinite template recursion "
3114
0
      "was detected.\n"
3115
0
      "You can adjust maxTemplateVars (--maxvars) in order to "
3116
0
      "raise the maximum number of variables/params (currently set to %d).\n",
3117
0
      ctxt->maxTemplateVars);
3118
0
        xsltDebug(ctxt, contextNode, list, NULL);
3119
0
  ctxt->state = XSLT_STATE_STOPPED;
3120
0
        return;
3121
0
  }
3122
3123
523k
    oldUserFragmentTop = ctxt->tmpRVT;
3124
523k
    ctxt->tmpRVT = NULL;
3125
3126
    /*
3127
    * Initiate a distinct scope of local params/variables.
3128
    */
3129
523k
    oldVarsBase = ctxt->varsBase;
3130
523k
    ctxt->varsBase = ctxt->varsNr;
3131
3132
523k
    ctxt->node = contextNode;
3133
3134
#ifdef WITH_PROFILER
3135
    if (ctxt->profile) {
3136
  templ->nbCalls++;
3137
  start = xsltTimestamp();
3138
  profPush(ctxt, 0);
3139
  profCallgraphAdd(templ, ctxt->templ);
3140
    }
3141
#endif
3142
3143
    /*
3144
    * Push the xsl:template declaration onto the stack.
3145
    */
3146
523k
    templPush(ctxt, templ);
3147
3148
#ifdef WITH_XSLT_DEBUG_PROCESS
3149
    if (templ->name != NULL)
3150
  XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
3151
  "applying xsl:template '%s'\n", templ->name));
3152
#endif
3153
    /*
3154
    * Process xsl:param instructions and skip those elements for
3155
    * further processing.
3156
    */
3157
523k
    cur = list;
3158
918k
    do {
3159
918k
  if (cur->type == XML_TEXT_NODE) {
3160
384k
      cur = cur->next;
3161
384k
      continue;
3162
384k
  }
3163
533k
  if ((cur->type != XML_ELEMENT_NODE) ||
3164
533k
      (cur->name[0] != 'p') ||
3165
533k
      (cur->psvi == NULL) ||
3166
533k
      (! xmlStrEqual(cur->name, BAD_CAST "param")) ||
3167
533k
      (! IS_XSLT_ELEM(cur)))
3168
520k
  {
3169
520k
      break;
3170
520k
  }
3171
3172
12.6k
  list = cur->next;
3173
3174
#ifdef XSLT_REFACTORED
3175
  iparam = (xsltStyleItemParamPtr) cur->psvi;
3176
#else
3177
12.6k
  iparam = (xsltStylePreCompPtr) cur->psvi;
3178
12.6k
#endif
3179
3180
  /*
3181
  * Substitute xsl:param for a given xsl:with-param.
3182
  * Since the XPath expression will reference the params/vars
3183
  * by index, we need to slot the xsl:with-params in the
3184
  * order of encountered xsl:params to keep the sequence of
3185
  * params/variables in the stack exactly as it was at
3186
  * compile time,
3187
  */
3188
12.6k
  tmpParam = NULL;
3189
12.6k
  if (withParams) {
3190
1.73k
      tmpParam = withParams;
3191
1.92k
      do {
3192
1.92k
    if ((tmpParam->name == (iparam->name)) &&
3193
1.92k
        (tmpParam->nameURI == (iparam->ns)))
3194
1.08k
    {
3195
        /*
3196
        * Push the caller-parameter.
3197
        */
3198
1.08k
        xsltLocalVariablePush(ctxt, tmpParam, -1);
3199
1.08k
        break;
3200
1.08k
    }
3201
836
    tmpParam = tmpParam->next;
3202
836
      } while (tmpParam != NULL);
3203
1.73k
  }
3204
  /*
3205
  * Push the xsl:param.
3206
  */
3207
12.6k
  if (tmpParam == NULL) {
3208
      /*
3209
      * Note that we must assume that the added parameter
3210
      * has a @depth of 0.
3211
      */
3212
11.5k
      xsltParseStylesheetParam(ctxt, cur);
3213
11.5k
  }
3214
12.6k
  cur = cur->next;
3215
397k
    } while (cur != NULL);
3216
    /*
3217
    * Process the sequence constructor.
3218
    */
3219
0
    xsltApplySequenceConstructor(ctxt, contextNode, list, templ);
3220
3221
    /*
3222
    * Remove remaining xsl:param and xsl:with-param items from
3223
    * the stack. Don't free xsl:with-param items.
3224
    */
3225
523k
    if (ctxt->varsNr > ctxt->varsBase)
3226
4.29k
  xsltTemplateParamsCleanup(ctxt);
3227
523k
    ctxt->varsBase = oldVarsBase;
3228
3229
    /*
3230
    * Release user-created fragments stored in the scope
3231
    * of xsl:template. Note that this mechanism is deprecated:
3232
    * user code should now use xsltRegisterLocalRVT() instead
3233
    * of the obsolete xsltRegisterTmpRVT().
3234
    */
3235
523k
    if (ctxt->tmpRVT) {
3236
0
  xmlDocPtr curdoc = ctxt->tmpRVT, tmp;
3237
3238
0
  while (curdoc != NULL) {
3239
0
      tmp = curdoc;
3240
0
      curdoc = (xmlDocPtr) curdoc->next;
3241
0
      xsltReleaseRVT(ctxt, tmp);
3242
0
  }
3243
0
    }
3244
523k
    ctxt->tmpRVT = oldUserFragmentTop;
3245
3246
    /*
3247
    * Pop the xsl:template declaration from the stack.
3248
    */
3249
523k
    templPop(ctxt);
3250
3251
#ifdef WITH_PROFILER
3252
    if (ctxt->profile) {
3253
  long spent, child, total, end;
3254
3255
  end = xsltTimestamp();
3256
  child = profPop(ctxt);
3257
  total = end - start;
3258
  spent = total - child;
3259
  if (spent <= 0) {
3260
      /*
3261
      * Not possible unless the original calibration failed
3262
      * we can try to correct it on the fly.
3263
      */
3264
      xsltCalibrateAdjust(spent);
3265
      spent = 0;
3266
  }
3267
3268
  templ->time += spent;
3269
  if (ctxt->profNr > 0)
3270
      ctxt->profTab[ctxt->profNr - 1] += total;
3271
    }
3272
#endif
3273
3274
#ifdef WITH_DEBUGGER
3275
    if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (addCallResult)) {
3276
        xslDropCall();
3277
    }
3278
#endif
3279
523k
}
3280
3281
3282
/**
3283
 * xsltApplyOneTemplate:
3284
 * @ctxt:  a XSLT process context
3285
 * @contextNode:  the node in the source tree.
3286
 * @list:  the nodes of a sequence constructor
3287
 * @templ: not used
3288
 * @params:  a set of parameters (xsl:param) or NULL
3289
 *
3290
 * Processes a sequence constructor on the current node in the source tree.
3291
 *
3292
 * @params are the already computed variable stack items; this function
3293
 * pushes them on the variable stack, and pops them before exiting; it's
3294
 * left to the caller to free or reuse @params afterwards. The initial
3295
 * states of the variable stack will always be restored before this
3296
 * function exits.
3297
 * NOTE that this does *not* initiate a new distinct variable scope; i.e.
3298
 * variables already on the stack are visible to the process. The caller's
3299
 * side needs to start a new variable scope if needed (e.g. in exsl:function).
3300
 *
3301
 * @templ is obsolete and not used anymore (e.g. <exslt:function> does not
3302
 * provide a @templ); a non-NULL @templ might raise an error in the future.
3303
 *
3304
 * BIG NOTE: This function is not intended to process the content of an
3305
 * xsl:template; it does not expect xsl:param instructions in @list and
3306
 * will report errors if found.
3307
 *
3308
 * Called by:
3309
 *  - xsltEvalVariable() (variables.c)
3310
 *  - exsltFuncFunctionFunction() (libexsl/functions.c)
3311
 */
3312
void
3313
xsltApplyOneTemplate(xsltTransformContextPtr ctxt,
3314
         xmlNodePtr contextNode,
3315
                     xmlNodePtr list,
3316
         xsltTemplatePtr templ ATTRIBUTE_UNUSED,
3317
                     xsltStackElemPtr params)
3318
54.4k
{
3319
54.4k
    if ((ctxt == NULL) || (list == NULL))
3320
86
  return;
3321
108k
    CHECK_STOPPED;
3322
3323
108k
    if (params) {
3324
  /*
3325
   * This code should be obsolete - was previously used
3326
   * by libexslt/functions.c, but due to bug 381319 the
3327
   * logic there was changed.
3328
   */
3329
0
  int oldVarsNr = ctxt->varsNr;
3330
3331
  /*
3332
  * Push the given xsl:param(s) onto the variable stack.
3333
  */
3334
0
  while (params != NULL) {
3335
0
      xsltLocalVariablePush(ctxt, params, -1);
3336
0
      params = params->next;
3337
0
  }
3338
0
  xsltApplySequenceConstructor(ctxt, contextNode, list, templ);
3339
  /*
3340
  * Pop the given xsl:param(s) from the stack but don't free them.
3341
  */
3342
0
  xsltLocalVariablePop(ctxt, oldVarsNr, -2);
3343
0
    } else
3344
53.9k
  xsltApplySequenceConstructor(ctxt, contextNode, list, templ);
3345
108k
}
3346
3347
/************************************************************************
3348
 *                  *
3349
 *        XSLT-1.1 extensions         *
3350
 *                  *
3351
 ************************************************************************/
3352
3353
/**
3354
 * xsltDocumentElem:
3355
 * @ctxt:  an XSLT processing context
3356
 * @node:  The current node
3357
 * @inst:  the instruction in the stylesheet
3358
 * @castedComp:  precomputed information
3359
 *
3360
 * Process an EXSLT/XSLT-1.1 document element
3361
 */
3362
void
3363
xsltDocumentElem(xsltTransformContextPtr ctxt, xmlNodePtr node,
3364
                 xmlNodePtr inst, xsltElemPreCompPtr castedComp)
3365
681
{
3366
#ifdef XSLT_REFACTORED
3367
    xsltStyleItemDocumentPtr comp = (xsltStyleItemDocumentPtr) castedComp;
3368
#else
3369
681
    xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
3370
681
#endif
3371
681
    xsltStylesheetPtr style = NULL;
3372
681
    int ret;
3373
681
    xmlChar *filename = NULL, *prop, *elements;
3374
681
    xmlChar *element, *end;
3375
681
    xmlDocPtr res = NULL;
3376
681
    xmlDocPtr oldOutput;
3377
681
    xmlNodePtr oldInsert, root;
3378
681
    const char *oldOutputFile;
3379
681
    xsltOutputType oldType;
3380
681
    xmlChar *URL = NULL;
3381
681
    const xmlChar *method;
3382
681
    const xmlChar *doctypePublic;
3383
681
    const xmlChar *doctypeSystem;
3384
681
    const xmlChar *version;
3385
681
    const xmlChar *encoding;
3386
681
    int redirect_write_append = 0;
3387
3388
681
    if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL))
3389
0
        return;
3390
3391
681
    if (comp->filename == NULL) {
3392
3393
224
        if (xmlStrEqual(inst->name, (const xmlChar *) "output")) {
3394
      /*
3395
      * The element "output" is in the namespace XSLT_SAXON_NAMESPACE
3396
      *   (http://icl.com/saxon)
3397
      * The @file is in no namespace.
3398
      */
3399
#ifdef WITH_XSLT_DEBUG_EXTRA
3400
            xsltGenericDebug(xsltGenericDebugContext,
3401
                             "Found saxon:output extension\n");
3402
#endif
3403
0
            URL = xsltEvalAttrValueTemplate(ctxt, inst,
3404
0
                                                 (const xmlChar *) "file",
3405
0
                                                 XSLT_SAXON_NAMESPACE);
3406
3407
0
      if (URL == NULL)
3408
0
    URL = xsltEvalAttrValueTemplate(ctxt, inst,
3409
0
                                                 (const xmlChar *) "href",
3410
0
                                                 XSLT_SAXON_NAMESPACE);
3411
224
        } else if (xmlStrEqual(inst->name, (const xmlChar *) "write")) {
3412
#ifdef WITH_XSLT_DEBUG_EXTRA
3413
            xsltGenericDebug(xsltGenericDebugContext,
3414
                             "Found xalan:write extension\n");
3415
#endif
3416
0
            URL = xsltEvalAttrValueTemplate(ctxt, inst,
3417
0
                                                 (const xmlChar *)
3418
0
                                                 "select",
3419
0
                                                 XSLT_XALAN_NAMESPACE);
3420
0
      if (URL != NULL) {
3421
0
    xmlXPathCompExprPtr cmp;
3422
0
    xmlChar *val;
3423
3424
    /*
3425
     * Trying to handle bug #59212
3426
     * The value of the "select" attribute is an
3427
     * XPath expression.
3428
     * (see http://xml.apache.org/xalan-j/extensionslib.html#redirect)
3429
     */
3430
0
    cmp = xmlXPathCtxtCompile(ctxt->xpathCtxt, URL);
3431
0
                val = xsltEvalXPathString(ctxt, cmp);
3432
0
    xmlXPathFreeCompExpr(cmp);
3433
0
    xmlFree(URL);
3434
0
    URL = val;
3435
0
      }
3436
0
      if (URL == NULL)
3437
0
    URL = xsltEvalAttrValueTemplate(ctxt, inst,
3438
0
                 (const xmlChar *)
3439
0
                 "file",
3440
0
                 XSLT_XALAN_NAMESPACE);
3441
0
      if (URL == NULL)
3442
0
    URL = xsltEvalAttrValueTemplate(ctxt, inst,
3443
0
                 (const xmlChar *)
3444
0
                 "href",
3445
0
                 XSLT_XALAN_NAMESPACE);
3446
224
        } else if (xmlStrEqual(inst->name, (const xmlChar *) "document")) {
3447
224
            URL = xsltEvalAttrValueTemplate(ctxt, inst,
3448
224
                                                 (const xmlChar *) "href",
3449
224
                                                 NULL);
3450
224
        }
3451
3452
457
    } else {
3453
457
        URL = xmlStrdup(comp->filename);
3454
457
    }
3455
3456
681
    if (URL == NULL) {
3457
226
  xsltTransformError(ctxt, NULL, inst,
3458
226
             "xsltDocumentElem: href/URI-Reference not found\n");
3459
226
  return;
3460
226
    }
3461
3462
    /*
3463
     * If the computation failed, it's likely that the URL wasn't escaped
3464
     */
3465
455
    filename = xmlBuildURI(URL, (const xmlChar *) ctxt->outputFile);
3466
455
    if (filename == NULL) {
3467
1
  xmlChar *escURL;
3468
3469
1
  escURL=xmlURIEscapeStr(URL, BAD_CAST ":/.?,");
3470
1
  if (escURL != NULL) {
3471
0
      filename = xmlBuildURI(escURL, (const xmlChar *) ctxt->outputFile);
3472
0
      xmlFree(escURL);
3473
0
  }
3474
1
    }
3475
3476
455
    if (filename == NULL) {
3477
1
  xsltTransformError(ctxt, NULL, inst,
3478
1
             "xsltDocumentElem: URL computation failed for %s\n",
3479
1
       URL);
3480
1
  xmlFree(URL);
3481
1
  return;
3482
1
    }
3483
3484
    /*
3485
     * Security checking: can we write to this resource
3486
     */
3487
454
    if (ctxt->sec != NULL) {
3488
454
  ret = xsltCheckWrite(ctxt->sec, ctxt, filename);
3489
454
  if (ret <= 0) {
3490
454
            if (ret == 0)
3491
451
                xsltTransformError(ctxt, NULL, inst,
3492
451
                     "xsltDocumentElem: write rights for %s denied\n",
3493
451
                                 filename);
3494
454
      xmlFree(URL);
3495
454
      xmlFree(filename);
3496
454
      return;
3497
454
  }
3498
454
    }
3499
3500
0
    oldOutputFile = ctxt->outputFile;
3501
0
    oldOutput = ctxt->output;
3502
0
    oldInsert = ctxt->insert;
3503
0
    oldType = ctxt->type;
3504
0
    ctxt->outputFile = (const char *) filename;
3505
3506
0
    style = xsltNewStylesheet();
3507
0
    if (style == NULL) {
3508
0
  xsltTransformError(ctxt, NULL, inst,
3509
0
                         "xsltDocumentElem: out of memory\n");
3510
0
        goto error;
3511
0
    }
3512
3513
    /*
3514
     * Version described in 1.1 draft allows full parameterization
3515
     * of the output.
3516
     */
3517
0
    prop = xsltEvalAttrValueTemplate(ctxt, inst,
3518
0
             (const xmlChar *) "version",
3519
0
             NULL);
3520
0
    if (prop != NULL) {
3521
0
  if (style->version != NULL)
3522
0
      xmlFree(style->version);
3523
0
  style->version = prop;
3524
0
    }
3525
0
    prop = xsltEvalAttrValueTemplate(ctxt, inst,
3526
0
             (const xmlChar *) "encoding",
3527
0
             NULL);
3528
0
    if (prop != NULL) {
3529
0
  if (style->encoding != NULL)
3530
0
      xmlFree(style->encoding);
3531
0
  style->encoding = prop;
3532
0
    }
3533
0
    prop = xsltEvalAttrValueTemplate(ctxt, inst,
3534
0
             (const xmlChar *) "method",
3535
0
             NULL);
3536
0
    if (prop != NULL) {
3537
0
  const xmlChar *URI;
3538
3539
0
  if (style->method != NULL)
3540
0
      xmlFree(style->method);
3541
0
  style->method = NULL;
3542
0
  if (style->methodURI != NULL)
3543
0
      xmlFree(style->methodURI);
3544
0
  style->methodURI = NULL;
3545
3546
0
  URI = xsltGetQNameURI(inst, &prop);
3547
0
  if (prop == NULL) {
3548
0
      if (style != NULL) style->errors++;
3549
0
  } else if (URI == NULL) {
3550
0
      if ((xmlStrEqual(prop, (const xmlChar *) "xml")) ||
3551
0
    (xmlStrEqual(prop, (const xmlChar *) "html")) ||
3552
0
    (xmlStrEqual(prop, (const xmlChar *) "text"))) {
3553
0
    style->method = prop;
3554
0
      } else {
3555
0
    xsltTransformError(ctxt, NULL, inst,
3556
0
         "invalid value for method: %s\n", prop);
3557
0
    if (style != NULL) style->warnings++;
3558
0
      }
3559
0
  } else {
3560
0
      style->method = prop;
3561
0
      style->methodURI = xmlStrdup(URI);
3562
0
  }
3563
0
    }
3564
0
    prop = xsltEvalAttrValueTemplate(ctxt, inst,
3565
0
             (const xmlChar *)
3566
0
             "doctype-system", NULL);
3567
0
    if (prop != NULL) {
3568
0
  if (style->doctypeSystem != NULL)
3569
0
      xmlFree(style->doctypeSystem);
3570
0
  style->doctypeSystem = prop;
3571
0
    }
3572
0
    prop = xsltEvalAttrValueTemplate(ctxt, inst,
3573
0
             (const xmlChar *)
3574
0
             "doctype-public", NULL);
3575
0
    if (prop != NULL) {
3576
0
  if (style->doctypePublic != NULL)
3577
0
      xmlFree(style->doctypePublic);
3578
0
  style->doctypePublic = prop;
3579
0
    }
3580
0
    prop = xsltEvalAttrValueTemplate(ctxt, inst,
3581
0
             (const xmlChar *) "standalone",
3582
0
             NULL);
3583
0
    if (prop != NULL) {
3584
0
  if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
3585
0
      style->standalone = 1;
3586
0
  } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
3587
0
      style->standalone = 0;
3588
0
  } else {
3589
0
      xsltTransformError(ctxt, NULL, inst,
3590
0
           "invalid value for standalone: %s\n",
3591
0
           prop);
3592
0
      if (style != NULL) style->warnings++;
3593
0
  }
3594
0
  xmlFree(prop);
3595
0
    }
3596
3597
0
    prop = xsltEvalAttrValueTemplate(ctxt, inst,
3598
0
             (const xmlChar *) "indent",
3599
0
             NULL);
3600
0
    if (prop != NULL) {
3601
0
  if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
3602
0
      style->indent = 1;
3603
0
  } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
3604
0
      style->indent = 0;
3605
0
  } else {
3606
0
      xsltTransformError(ctxt, NULL, inst,
3607
0
           "invalid value for indent: %s\n", prop);
3608
0
      if (style != NULL) style->warnings++;
3609
0
  }
3610
0
  xmlFree(prop);
3611
0
    }
3612
3613
0
    prop = xsltEvalAttrValueTemplate(ctxt, inst,
3614
0
             (const xmlChar *)
3615
0
             "omit-xml-declaration",
3616
0
             NULL);
3617
0
    if (prop != NULL) {
3618
0
  if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
3619
0
      style->omitXmlDeclaration = 1;
3620
0
  } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
3621
0
      style->omitXmlDeclaration = 0;
3622
0
  } else {
3623
0
      xsltTransformError(ctxt, NULL, inst,
3624
0
           "invalid value for omit-xml-declaration: %s\n",
3625
0
           prop);
3626
0
      if (style != NULL) style->warnings++;
3627
0
  }
3628
0
  xmlFree(prop);
3629
0
    }
3630
3631
0
    elements = xsltEvalAttrValueTemplate(ctxt, inst,
3632
0
           (const xmlChar *)
3633
0
           "cdata-section-elements",
3634
0
           NULL);
3635
0
    if (elements != NULL) {
3636
0
  if (style->stripSpaces == NULL)
3637
0
      style->stripSpaces = xmlHashCreate(10);
3638
0
  if (style->stripSpaces == NULL) {
3639
0
      xmlFree(elements);
3640
0
      return;
3641
0
  }
3642
3643
0
  element = elements;
3644
0
  while (*element != 0) {
3645
0
      while (xmlIsBlank_ch(*element))
3646
0
    element++;
3647
0
      if (*element == 0)
3648
0
    break;
3649
0
      end = element;
3650
0
      while ((*end != 0) && (!xmlIsBlank_ch(*end)))
3651
0
    end++;
3652
0
      element = xmlStrndup(element, end - element);
3653
0
      if (element) {
3654
0
    const xmlChar *URI;
3655
3656
#ifdef WITH_XSLT_DEBUG_PARSING
3657
    xsltGenericDebug(xsltGenericDebugContext,
3658
         "add cdata section output element %s\n",
3659
         element);
3660
#endif
3661
0
                URI = xsltGetQNameURI(inst, &element);
3662
3663
0
    xmlHashAddEntry2(style->stripSpaces, element, URI,
3664
0
              (xmlChar *) "cdata");
3665
0
    xmlFree(element);
3666
0
      }
3667
0
      element = end;
3668
0
  }
3669
0
  xmlFree(elements);
3670
0
    }
3671
3672
    /*
3673
     * Create a new document tree and process the element template
3674
     */
3675
0
    XSLT_GET_IMPORT_PTR(method, style, method)
3676
0
    XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
3677
0
    XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
3678
0
    XSLT_GET_IMPORT_PTR(version, style, version)
3679
0
    XSLT_GET_IMPORT_PTR(encoding, style, encoding)
3680
3681
0
    if ((method != NULL) &&
3682
0
  (!xmlStrEqual(method, (const xmlChar *) "xml"))) {
3683
0
  if (xmlStrEqual(method, (const xmlChar *) "html")) {
3684
0
      ctxt->type = XSLT_OUTPUT_HTML;
3685
0
      if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
3686
0
    res = htmlNewDoc(doctypeSystem, doctypePublic);
3687
0
      else {
3688
0
    if (version != NULL) {
3689
0
#ifdef XSLT_GENERATE_HTML_DOCTYPE
3690
0
        xsltGetHTMLIDs(version, &doctypePublic, &doctypeSystem);
3691
0
#endif
3692
0
                }
3693
0
    res = htmlNewDocNoDtD(doctypeSystem, doctypePublic);
3694
0
      }
3695
0
      if (res == NULL)
3696
0
    goto error;
3697
0
      res->dict = ctxt->dict;
3698
0
      xmlDictReference(res->dict);
3699
0
  } else if (xmlStrEqual(method, (const xmlChar *) "xhtml")) {
3700
0
      xsltTransformError(ctxt, NULL, inst,
3701
0
       "xsltDocumentElem: unsupported method xhtml\n");
3702
0
      ctxt->type = XSLT_OUTPUT_HTML;
3703
0
      res = htmlNewDocNoDtD(doctypeSystem, doctypePublic);
3704
0
      if (res == NULL)
3705
0
    goto error;
3706
0
      res->dict = ctxt->dict;
3707
0
      xmlDictReference(res->dict);
3708
0
  } else if (xmlStrEqual(method, (const xmlChar *) "text")) {
3709
0
      ctxt->type = XSLT_OUTPUT_TEXT;
3710
0
      res = xmlNewDoc(style->version);
3711
0
      if (res == NULL)
3712
0
    goto error;
3713
0
      res->dict = ctxt->dict;
3714
0
      xmlDictReference(res->dict);
3715
#ifdef WITH_XSLT_DEBUG
3716
      xsltGenericDebug(xsltGenericDebugContext,
3717
                     "reusing transformation dict for output\n");
3718
#endif
3719
0
  } else {
3720
0
      xsltTransformError(ctxt, NULL, inst,
3721
0
           "xsltDocumentElem: unsupported method (%s)\n",
3722
0
                 method);
3723
0
      goto error;
3724
0
  }
3725
0
    } else {
3726
0
  ctxt->type = XSLT_OUTPUT_XML;
3727
0
  res = xmlNewDoc(style->version);
3728
0
  if (res == NULL)
3729
0
      goto error;
3730
0
  res->dict = ctxt->dict;
3731
0
  xmlDictReference(res->dict);
3732
#ifdef WITH_XSLT_DEBUG
3733
  xsltGenericDebug(xsltGenericDebugContext,
3734
                     "reusing transformation dict for output\n");
3735
#endif
3736
0
    }
3737
0
    res->charset = XML_CHAR_ENCODING_UTF8;
3738
0
    if (encoding != NULL)
3739
0
  res->encoding = xmlStrdup(encoding);
3740
0
    ctxt->output = res;
3741
0
    ctxt->insert = (xmlNodePtr) res;
3742
0
    xsltApplySequenceConstructor(ctxt, node, inst->children, NULL);
3743
3744
    /*
3745
     * Do some post processing work depending on the generated output
3746
     */
3747
0
    root = xmlDocGetRootElement(res);
3748
0
    if (root != NULL) {
3749
0
        const xmlChar *doctype = NULL;
3750
3751
0
        if ((root->ns != NULL) && (root->ns->prefix != NULL))
3752
0
      doctype = xmlDictQLookup(ctxt->dict, root->ns->prefix, root->name);
3753
0
  if (doctype == NULL)
3754
0
      doctype = root->name;
3755
3756
        /*
3757
         * Apply the default selection of the method
3758
         */
3759
0
        if ((method == NULL) &&
3760
0
            (root->ns == NULL) &&
3761
0
            (!xmlStrcasecmp(root->name, (const xmlChar *) "html"))) {
3762
0
            xmlNodePtr tmp;
3763
3764
0
            tmp = res->children;
3765
0
            while ((tmp != NULL) && (tmp != root)) {
3766
0
                if (tmp->type == XML_ELEMENT_NODE)
3767
0
                    break;
3768
0
                if ((tmp->type == XML_TEXT_NODE) && (!xmlIsBlankNode(tmp)))
3769
0
                    break;
3770
0
    tmp = tmp->next;
3771
0
            }
3772
0
            if (tmp == root) {
3773
0
                ctxt->type = XSLT_OUTPUT_HTML;
3774
0
                res->type = XML_HTML_DOCUMENT_NODE;
3775
0
                if (((doctypePublic != NULL) || (doctypeSystem != NULL))) {
3776
0
                    res->intSubset = xmlCreateIntSubset(res, doctype,
3777
0
                                                        doctypePublic,
3778
0
                                                        doctypeSystem);
3779
0
#ifdef XSLT_GENERATE_HTML_DOCTYPE
3780
0
    } else if (version != NULL) {
3781
0
                    xsltGetHTMLIDs(version, &doctypePublic,
3782
0
                                   &doctypeSystem);
3783
0
                    if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
3784
0
                        res->intSubset =
3785
0
                            xmlCreateIntSubset(res, doctype,
3786
0
                                               doctypePublic,
3787
0
                                               doctypeSystem);
3788
0
#endif
3789
0
                }
3790
0
            }
3791
3792
0
        }
3793
0
        if (ctxt->type == XSLT_OUTPUT_XML) {
3794
0
            XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
3795
0
                XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
3796
0
                if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
3797
0
                res->intSubset = xmlCreateIntSubset(res, doctype,
3798
0
                                                    doctypePublic,
3799
0
                                                    doctypeSystem);
3800
0
        }
3801
0
    }
3802
3803
    /*
3804
     * Calls to redirect:write also take an optional attribute append.
3805
     * Attribute append="true|yes" which will attempt to simply append
3806
     * to an existing file instead of always opening a new file. The
3807
     * default behavior of always overwriting the file still happens
3808
     * if we do not specify append.
3809
     * Note that append use will forbid use of remote URI target.
3810
     */
3811
0
    prop = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *)"append",
3812
0
             NULL);
3813
0
    if (prop != NULL) {
3814
0
  if (xmlStrEqual(prop, (const xmlChar *) "true") ||
3815
0
      xmlStrEqual(prop, (const xmlChar *) "yes")) {
3816
0
      style->omitXmlDeclaration = 1;
3817
0
      redirect_write_append = 1;
3818
0
  } else
3819
0
      style->omitXmlDeclaration = 0;
3820
0
  xmlFree(prop);
3821
0
    }
3822
3823
0
    if (redirect_write_append) {
3824
0
        FILE *f;
3825
3826
0
  f = fopen((const char *) filename, "ab");
3827
0
  if (f == NULL) {
3828
0
      ret = -1;
3829
0
  } else {
3830
0
      ret = xsltSaveResultToFile(f, res, style);
3831
0
      fclose(f);
3832
0
  }
3833
0
    } else {
3834
0
  ret = xsltSaveResultToFilename((const char *) filename, res, style, 0);
3835
0
    }
3836
0
    if (ret < 0) {
3837
0
  xsltTransformError(ctxt, NULL, inst,
3838
0
                         "xsltDocumentElem: unable to save to %s\n",
3839
0
                         filename);
3840
#ifdef WITH_XSLT_DEBUG_EXTRA
3841
    } else {
3842
        xsltGenericDebug(xsltGenericDebugContext,
3843
                         "Wrote %d bytes to %s\n", ret, filename);
3844
#endif
3845
0
    }
3846
3847
0
  error:
3848
0
    ctxt->output = oldOutput;
3849
0
    ctxt->insert = oldInsert;
3850
0
    ctxt->type = oldType;
3851
0
    ctxt->outputFile = oldOutputFile;
3852
0
    if (URL != NULL)
3853
0
        xmlFree(URL);
3854
0
    if (filename != NULL)
3855
0
        xmlFree(filename);
3856
0
    if (style != NULL)
3857
0
        xsltFreeStylesheet(style);
3858
0
    if (res != NULL)
3859
0
        xmlFreeDoc(res);
3860
0
}
3861
3862
/************************************************************************
3863
 *                  *
3864
 *    Most of the XSLT-1.0 transformations      *
3865
 *                  *
3866
 ************************************************************************/
3867
3868
/**
3869
 * xsltSort:
3870
 * @ctxt:  a XSLT process context
3871
 * @node:  the node in the source tree.
3872
 * @inst:  the xslt sort node
3873
 * @comp:  precomputed information
3874
 *
3875
 * function attached to xsl:sort nodes, but this should not be
3876
 * called directly
3877
 */
3878
void
3879
xsltSort(xsltTransformContextPtr ctxt,
3880
  xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr inst,
3881
610
  xsltElemPreCompPtr comp) {
3882
610
    if (comp == NULL) {
3883
0
  xsltTransformError(ctxt, NULL, inst,
3884
0
       "xsl:sort : compilation failed\n");
3885
0
  return;
3886
0
    }
3887
610
    xsltTransformError(ctxt, NULL, inst,
3888
610
   "xsl:sort : improper use this should not be reached\n");
3889
610
}
3890
3891
/**
3892
 * xsltCopy:
3893
 * @ctxt:  an XSLT process context
3894
 * @node:  the node in the source tree
3895
 * @inst:  the element node of the XSLT-copy instruction
3896
 * @castedComp:  computed information of the XSLT-copy instruction
3897
 *
3898
 * Execute the XSLT-copy instruction on the source node.
3899
 */
3900
void
3901
xsltCopy(xsltTransformContextPtr ctxt, xmlNodePtr node,
3902
   xmlNodePtr inst, xsltElemPreCompPtr castedComp)
3903
74.6k
{
3904
#ifdef XSLT_REFACTORED
3905
    xsltStyleItemCopyPtr comp = (xsltStyleItemCopyPtr) castedComp;
3906
#else
3907
74.6k
    xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
3908
74.6k
#endif
3909
74.6k
    xmlNodePtr copy, oldInsert;
3910
3911
74.6k
    oldInsert = ctxt->insert;
3912
74.6k
    if (ctxt->insert != NULL) {
3913
74.6k
  switch (node->type) {
3914
17.0k
      case XML_TEXT_NODE:
3915
17.0k
      case XML_CDATA_SECTION_NODE:
3916
    /*
3917
     * This text comes from the stylesheet
3918
     * For stylesheets, the set of whitespace-preserving
3919
     * element names consists of just xsl:text.
3920
     */
3921
#ifdef WITH_XSLT_DEBUG_PROCESS
3922
    if (node->type == XML_CDATA_SECTION_NODE) {
3923
        XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
3924
       "xsltCopy: CDATA text %s\n", node->content));
3925
    } else {
3926
        XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
3927
       "xsltCopy: text %s\n", node->content));
3928
                }
3929
#endif
3930
17.0k
    xsltCopyText(ctxt, ctxt->insert, node, 0);
3931
17.0k
    break;
3932
110
      case XML_DOCUMENT_NODE:
3933
110
      case XML_HTML_DOCUMENT_NODE:
3934
110
    break;
3935
47.8k
      case XML_ELEMENT_NODE:
3936
    /*
3937
    * REVISIT NOTE: The "fake" is a doc-node, not an element node.
3938
    * REMOVED:
3939
    *   if (xmlStrEqual(node->name, BAD_CAST " fake node libxslt"))
3940
    *    return;
3941
    */
3942
3943
#ifdef WITH_XSLT_DEBUG_PROCESS
3944
    XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
3945
         "xsltCopy: node %s\n", node->name));
3946
#endif
3947
47.8k
    copy = xsltShallowCopyElem(ctxt, node, ctxt->insert, 0);
3948
47.8k
    ctxt->insert = copy;
3949
47.8k
    if (comp->use != NULL) {
3950
90
        xsltApplyAttributeSet(ctxt, node, inst, comp->use);
3951
90
    }
3952
47.8k
    break;
3953
2.93k
      case XML_ATTRIBUTE_NODE: {
3954
#ifdef WITH_XSLT_DEBUG_PROCESS
3955
    XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
3956
         "xsltCopy: attribute %s\n", node->name));
3957
#endif
3958
    /*
3959
    * REVISIT: We could also raise an error if the parent is not
3960
    * an element node.
3961
    * OPTIMIZE TODO: Can we set the value/children of the
3962
    * attribute without an intermediate copy of the string value?
3963
    */
3964
2.93k
    xsltShallowCopyAttr(ctxt, inst, ctxt->insert, (xmlAttrPtr) node);
3965
2.93k
    break;
3966
110
      }
3967
3.28k
      case XML_PI_NODE:
3968
#ifdef WITH_XSLT_DEBUG_PROCESS
3969
    XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
3970
         "xsltCopy: PI %s\n", node->name));
3971
#endif
3972
3.28k
    copy = xmlNewDocPI(ctxt->insert->doc, node->name,
3973
3.28k
                       node->content);
3974
3.28k
    copy = xsltAddChild(ctxt->insert, copy);
3975
3.28k
    break;
3976
2.50k
      case XML_COMMENT_NODE:
3977
#ifdef WITH_XSLT_DEBUG_PROCESS
3978
    XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
3979
         "xsltCopy: comment\n"));
3980
#endif
3981
2.50k
    copy = xmlNewComment(node->content);
3982
2.50k
    copy = xsltAddChild(ctxt->insert, copy);
3983
2.50k
    break;
3984
886
      case XML_NAMESPACE_DECL:
3985
#ifdef WITH_XSLT_DEBUG_PROCESS
3986
    XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
3987
         "xsltCopy: namespace declaration\n"));
3988
#endif
3989
886
    xsltShallowCopyNsNode(ctxt, inst, ctxt->insert, (xmlNsPtr)node);
3990
886
    break;
3991
0
      default:
3992
0
    break;
3993
3994
74.6k
  }
3995
74.6k
    }
3996
3997
74.6k
    switch (node->type) {
3998
110
  case XML_DOCUMENT_NODE:
3999
110
  case XML_HTML_DOCUMENT_NODE:
4000
47.9k
  case XML_ELEMENT_NODE:
4001
47.9k
      xsltApplySequenceConstructor(ctxt, ctxt->node, inst->children,
4002
47.9k
    NULL);
4003
47.9k
      break;
4004
26.6k
  default:
4005
26.6k
      break;
4006
74.6k
    }
4007
74.6k
    ctxt->insert = oldInsert;
4008
74.6k
}
4009
4010
/**
4011
 * xsltText:
4012
 * @ctxt:  a XSLT process context
4013
 * @node:  the node in the source tree.
4014
 * @inst:  the xslt text node
4015
 * @comp:  precomputed information
4016
 *
4017
 * Process the xslt text node on the source node
4018
 */
4019
void
4020
xsltText(xsltTransformContextPtr ctxt, xmlNodePtr node ATTRIBUTE_UNUSED,
4021
0
      xmlNodePtr inst, xsltElemPreCompPtr comp ATTRIBUTE_UNUSED) {
4022
0
    if ((inst->children != NULL) && (comp != NULL)) {
4023
0
  xmlNodePtr text = inst->children;
4024
0
  xmlNodePtr copy;
4025
4026
0
  while (text != NULL) {
4027
0
      if ((text->type != XML_TEXT_NODE) &&
4028
0
           (text->type != XML_CDATA_SECTION_NODE)) {
4029
0
    xsltTransformError(ctxt, NULL, inst,
4030
0
         "xsl:text content problem\n");
4031
0
    break;
4032
0
      }
4033
0
      copy = xmlNewDocText(ctxt->output, text->content);
4034
0
      if (text->type != XML_CDATA_SECTION_NODE) {
4035
#ifdef WITH_XSLT_DEBUG_PARSING
4036
    xsltGenericDebug(xsltGenericDebugContext,
4037
         "Disable escaping: %s\n", text->content);
4038
#endif
4039
0
    copy->name = xmlStringTextNoenc;
4040
0
      }
4041
0
      copy = xsltAddChild(ctxt->insert, copy);
4042
0
      text = text->next;
4043
0
  }
4044
0
    }
4045
0
}
4046
4047
/**
4048
 * xsltElement:
4049
 * @ctxt:  a XSLT process context
4050
 * @node:  the node in the source tree.
4051
 * @inst:  the xslt element node
4052
 * @castedComp:  precomputed information
4053
 *
4054
 * Process the xslt element node on the source node
4055
 */
4056
void
4057
xsltElement(xsltTransformContextPtr ctxt, xmlNodePtr node,
4058
27.4k
      xmlNodePtr inst, xsltElemPreCompPtr castedComp) {
4059
#ifdef XSLT_REFACTORED
4060
    xsltStyleItemElementPtr comp = (xsltStyleItemElementPtr) castedComp;
4061
#else
4062
27.4k
    xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
4063
27.4k
#endif
4064
27.4k
    xmlChar *prop = NULL;
4065
27.4k
    const xmlChar *name, *prefix = NULL, *nsName = NULL;
4066
27.4k
    xmlNodePtr copy;
4067
27.4k
    xmlNodePtr oldInsert;
4068
4069
27.4k
    if (ctxt->insert == NULL)
4070
0
  return;
4071
4072
    /*
4073
    * A comp->has_name == 0 indicates that we need to skip this instruction,
4074
    * since it was evaluated to be invalid already during compilation.
4075
    */
4076
27.4k
    if (!comp->has_name)
4077
105
        return;
4078
4079
    /*
4080
     * stack and saves
4081
     */
4082
27.3k
    oldInsert = ctxt->insert;
4083
4084
27.3k
    if (comp->name == NULL) {
4085
  /* TODO: fix attr acquisition wrt to the XSLT namespace */
4086
4.33k
        prop = xsltEvalAttrValueTemplate(ctxt, inst,
4087
4.33k
      (const xmlChar *) "name", XSLT_NAMESPACE);
4088
4.33k
        if (prop == NULL) {
4089
239
            xsltTransformError(ctxt, NULL, inst,
4090
239
    "xsl:element: The attribute 'name' is missing.\n");
4091
239
            goto error;
4092
239
        }
4093
4.09k
  if (xmlValidateQName(prop, 0)) {
4094
4.08k
      xsltTransformError(ctxt, NULL, inst,
4095
4.08k
    "xsl:element: The effective name '%s' is not a "
4096
4.08k
    "valid QName.\n", prop);
4097
      /* we fall through to catch any further errors, if possible */
4098
4.08k
  }
4099
4.09k
  name = xsltSplitQName(ctxt->dict, prop, &prefix);
4100
4.09k
  xmlFree(prop);
4101
23.0k
    } else {
4102
  /*
4103
  * The "name" value was static.
4104
  */
4105
#ifdef XSLT_REFACTORED
4106
  prefix = comp->nsPrefix;
4107
  name = comp->name;
4108
#else
4109
23.0k
  name = xsltSplitQName(ctxt->dict, comp->name, &prefix);
4110
23.0k
#endif
4111
23.0k
    }
4112
4113
    /*
4114
     * Create the new element
4115
     */
4116
27.1k
    if (ctxt->output->dict == ctxt->dict) {
4117
27.1k
  copy = xmlNewDocNodeEatName(ctxt->output, NULL, (xmlChar *)name, NULL);
4118
27.1k
    } else {
4119
0
  copy = xmlNewDocNode(ctxt->output, NULL, (xmlChar *)name, NULL);
4120
0
    }
4121
27.1k
    if (copy == NULL) {
4122
267
  xsltTransformError(ctxt, NULL, inst,
4123
267
      "xsl:element : creation of %s failed\n", name);
4124
267
  return;
4125
267
    }
4126
26.8k
    copy = xsltAddChild(ctxt->insert, copy);
4127
26.8k
    if (copy == NULL) {
4128
0
        xsltTransformError(ctxt, NULL, inst,
4129
0
            "xsl:element : xsltAddChild failed\n");
4130
0
        return;
4131
0
    }
4132
4133
    /*
4134
    * Namespace
4135
    * ---------
4136
    */
4137
26.8k
    if (comp->has_ns) {
4138
12.2k
  if (comp->ns != NULL) {
4139
      /*
4140
      * No AVT; just plain text for the namespace name.
4141
      */
4142
11.8k
      if (comp->ns[0] != 0)
4143
11.5k
    nsName = comp->ns;
4144
11.8k
  } else {
4145
405
      xmlChar *tmpNsName;
4146
      /*
4147
      * Eval the AVT.
4148
      */
4149
      /* TODO: check attr acquisition wrt to the XSLT namespace */
4150
405
      tmpNsName = xsltEvalAttrValueTemplate(ctxt, inst,
4151
405
    (const xmlChar *) "namespace", XSLT_NAMESPACE);
4152
      /*
4153
      * SPEC XSLT 1.0:
4154
      *  "If the string is empty, then the expanded-name of the
4155
      *  attribute has a null namespace URI."
4156
      */
4157
405
      if ((tmpNsName != NULL) && (tmpNsName[0] != 0))
4158
290
    nsName = xmlDictLookup(ctxt->dict, BAD_CAST tmpNsName, -1);
4159
405
      xmlFree(tmpNsName);
4160
405
  }
4161
4162
12.2k
        if (xmlStrEqual(nsName, BAD_CAST "http://www.w3.org/2000/xmlns/")) {
4163
95
            xsltTransformError(ctxt, NULL, inst,
4164
95
                "xsl:attribute: Namespace http://www.w3.org/2000/xmlns/ "
4165
95
                "forbidden.\n");
4166
95
            goto error;
4167
95
        }
4168
12.1k
        if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) {
4169
0
            prefix = BAD_CAST "xml";
4170
12.1k
        } else if (xmlStrEqual(prefix, BAD_CAST "xml")) {
4171
145
            prefix = NULL;
4172
145
        }
4173
14.6k
    } else {
4174
14.6k
  xmlNsPtr ns;
4175
  /*
4176
  * SPEC XSLT 1.0:
4177
  *  "If the namespace attribute is not present, then the QName is
4178
  *  expanded into an expanded-name using the namespace declarations
4179
  *  in effect for the xsl:element element, including any default
4180
  *  namespace declaration.
4181
  */
4182
14.6k
  ns = xmlSearchNs(inst->doc, inst, prefix);
4183
14.6k
  if (ns == NULL) {
4184
      /*
4185
      * TODO: Check this in the compilation layer in case it's a
4186
      * static value.
4187
      */
4188
13.3k
            if (prefix != NULL) {
4189
941
                xsltTransformError(ctxt, NULL, inst,
4190
941
                    "xsl:element: The QName '%s:%s' has no "
4191
941
                    "namespace binding in scope in the stylesheet; "
4192
941
                    "this is an error, since the namespace was not "
4193
941
                    "specified by the instruction itself.\n", prefix, name);
4194
941
            }
4195
13.3k
  } else
4196
1.21k
      nsName = ns->href;
4197
14.6k
    }
4198
    /*
4199
    * Find/create a matching ns-decl in the result tree.
4200
    */
4201
26.7k
    if (nsName != NULL) {
4202
12.9k
  if (xmlStrEqual(prefix, BAD_CAST "xmlns")) {
4203
            /* Don't use a prefix of "xmlns" */
4204
144
      xmlChar *pref = xmlStrdup(BAD_CAST "ns_1");
4205
4206
144
      copy->ns = xsltGetSpecialNamespace(ctxt, inst, nsName, pref, copy);
4207
4208
144
      xmlFree(pref);
4209
12.8k
  } else {
4210
12.8k
      copy->ns = xsltGetSpecialNamespace(ctxt, inst, nsName, prefix,
4211
12.8k
    copy);
4212
12.8k
  }
4213
13.8k
    } else if ((copy->parent != NULL) &&
4214
13.8k
  (copy->parent->type == XML_ELEMENT_NODE) &&
4215
13.8k
  (copy->parent->ns != NULL))
4216
468
    {
4217
  /*
4218
  * "Undeclare" the default namespace.
4219
  */
4220
468
  xsltGetSpecialNamespace(ctxt, inst, NULL, NULL, copy);
4221
468
    }
4222
4223
26.7k
    ctxt->insert = copy;
4224
4225
26.7k
    if (comp->has_use) {
4226
794
  if (comp->use != NULL) {
4227
260
      xsltApplyAttributeSet(ctxt, node, inst, comp->use);
4228
534
  } else {
4229
534
      xmlChar *attrSets = NULL;
4230
      /*
4231
      * BUG TODO: use-attribute-sets is not a value template.
4232
      *  use-attribute-sets = qnames
4233
      */
4234
534
      attrSets = xsltEvalAttrValueTemplate(ctxt, inst,
4235
534
    (const xmlChar *)"use-attribute-sets", NULL);
4236
534
      if (attrSets != NULL) {
4237
531
    xsltApplyAttributeSet(ctxt, node, inst, attrSets);
4238
531
    xmlFree(attrSets);
4239
531
      }
4240
534
  }
4241
794
    }
4242
    /*
4243
    * Instantiate the sequence constructor.
4244
    */
4245
26.7k
    if (inst->children != NULL)
4246
15.8k
  xsltApplySequenceConstructor(ctxt, ctxt->node, inst->children,
4247
15.8k
      NULL);
4248
4249
27.1k
error:
4250
27.1k
    ctxt->insert = oldInsert;
4251
27.1k
    return;
4252
26.7k
}
4253
4254
4255
/**
4256
 * xsltComment:
4257
 * @ctxt:  a XSLT process context
4258
 * @node:  the node in the source tree.
4259
 * @inst:  the xslt comment node
4260
 * @comp:  precomputed information
4261
 *
4262
 * Process the xslt comment node on the source node
4263
 */
4264
void
4265
xsltComment(xsltTransformContextPtr ctxt, xmlNodePtr node,
4266
461
             xmlNodePtr inst, xsltElemPreCompPtr comp ATTRIBUTE_UNUSED) {
4267
461
    xmlChar *value = NULL;
4268
461
    xmlNodePtr commentNode;
4269
461
    int len;
4270
4271
461
    value = xsltEvalTemplateString(ctxt, node, inst);
4272
    /* TODO: use or generate the compiled form */
4273
461
    len = xmlStrlen(value);
4274
461
    if (len > 0) {
4275
255
        if ((value[len-1] == '-') ||
4276
255
      (xmlStrstr(value, BAD_CAST "--"))) {
4277
94
      xsltTransformError(ctxt, NULL, inst,
4278
94
        "xsl:comment : '--' or ending '-' not allowed in comment\n");
4279
      /* fall through to try to catch further errors */
4280
94
  }
4281
255
    }
4282
#ifdef WITH_XSLT_DEBUG_PROCESS
4283
    if (value == NULL) {
4284
  XSLT_TRACE(ctxt,XSLT_TRACE_COMMENT,xsltGenericDebug(xsltGenericDebugContext,
4285
       "xsltComment: empty\n"));
4286
    } else {
4287
  XSLT_TRACE(ctxt,XSLT_TRACE_COMMENT,xsltGenericDebug(xsltGenericDebugContext,
4288
       "xsltComment: content %s\n", value));
4289
    }
4290
#endif
4291
4292
461
    commentNode = xmlNewComment(value);
4293
461
    commentNode = xsltAddChild(ctxt->insert, commentNode);
4294
4295
461
    if (value != NULL)
4296
257
  xmlFree(value);
4297
461
}
4298
4299
/**
4300
 * xsltProcessingInstruction:
4301
 * @ctxt:  a XSLT process context
4302
 * @node:  the node in the source tree.
4303
 * @inst:  the xslt processing-instruction node
4304
 * @castedComp:  precomputed information
4305
 *
4306
 * Process the xslt processing-instruction node on the source node
4307
 */
4308
void
4309
xsltProcessingInstruction(xsltTransformContextPtr ctxt, xmlNodePtr node,
4310
1.10k
             xmlNodePtr inst, xsltElemPreCompPtr castedComp) {
4311
#ifdef XSLT_REFACTORED
4312
    xsltStyleItemPIPtr comp = (xsltStyleItemPIPtr) castedComp;
4313
#else
4314
1.10k
    xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
4315
1.10k
#endif
4316
1.10k
    const xmlChar *name;
4317
1.10k
    xmlChar *value = NULL;
4318
1.10k
    xmlNodePtr pi;
4319
4320
4321
1.10k
    if (ctxt->insert == NULL)
4322
0
  return;
4323
1.10k
    if (comp->has_name == 0)
4324
122
  return;
4325
985
    if (comp->name == NULL) {
4326
114
  name = xsltEvalAttrValueTemplate(ctxt, inst,
4327
114
          (const xmlChar *)"name", NULL);
4328
114
  if (name == NULL) {
4329
13
      xsltTransformError(ctxt, NULL, inst,
4330
13
     "xsl:processing-instruction : name is missing\n");
4331
13
      goto error;
4332
13
  }
4333
871
    } else {
4334
871
  name = comp->name;
4335
871
    }
4336
    /* TODO: check that it's both an an NCName and a PITarget. */
4337
4338
4339
972
    value = xsltEvalTemplateString(ctxt, node, inst);
4340
972
    if (xmlStrstr(value, BAD_CAST "?>") != NULL) {
4341
96
  xsltTransformError(ctxt, NULL, inst,
4342
96
       "xsl:processing-instruction: '?>' not allowed within PI content\n");
4343
96
  goto error;
4344
96
    }
4345
#ifdef WITH_XSLT_DEBUG_PROCESS
4346
    if (value == NULL) {
4347
  XSLT_TRACE(ctxt,XSLT_TRACE_PI,xsltGenericDebug(xsltGenericDebugContext,
4348
       "xsltProcessingInstruction: %s empty\n", name));
4349
    } else {
4350
  XSLT_TRACE(ctxt,XSLT_TRACE_PI,xsltGenericDebug(xsltGenericDebugContext,
4351
       "xsltProcessingInstruction: %s content %s\n", name, value));
4352
    }
4353
#endif
4354
4355
876
    pi = xmlNewDocPI(ctxt->insert->doc, name, value);
4356
876
    pi = xsltAddChild(ctxt->insert, pi);
4357
4358
985
error:
4359
985
    if ((name != NULL) && (name != comp->name))
4360
101
        xmlFree((xmlChar *) name);
4361
985
    if (value != NULL)
4362
874
  xmlFree(value);
4363
985
}
4364
4365
/**
4366
 * xsltCopyOf:
4367
 * @ctxt:  an XSLT transformation context
4368
 * @node:  the current node in the source tree
4369
 * @inst:  the element node of the XSLT copy-of instruction
4370
 * @castedComp:  precomputed information of the XSLT copy-of instruction
4371
 *
4372
 * Process the XSLT copy-of instruction.
4373
 */
4374
void
4375
xsltCopyOf(xsltTransformContextPtr ctxt, xmlNodePtr node,
4376
20.6k
             xmlNodePtr inst, xsltElemPreCompPtr castedComp) {
4377
#ifdef XSLT_REFACTORED
4378
    xsltStyleItemCopyOfPtr comp = (xsltStyleItemCopyOfPtr) castedComp;
4379
#else
4380
20.6k
    xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
4381
20.6k
#endif
4382
20.6k
    xmlXPathObjectPtr res = NULL;
4383
20.6k
    xmlNodeSetPtr list = NULL;
4384
20.6k
    int i;
4385
4386
20.6k
    if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
4387
0
  return;
4388
20.6k
    if ((comp == NULL) || (comp->select == NULL) || (comp->comp == NULL)) {
4389
0
  xsltTransformError(ctxt, NULL, inst,
4390
0
       "xsl:copy-of : compilation failed\n");
4391
0
  return;
4392
0
    }
4393
4394
     /*
4395
    * SPEC XSLT 1.0:
4396
    *  "The xsl:copy-of element can be used to insert a result tree
4397
    *  fragment into the result tree, without first converting it to
4398
    *  a string as xsl:value-of does (see [7.6.1 Generating Text with
4399
    *  xsl:value-of]). The required select attribute contains an
4400
    *  expression. When the result of evaluating the expression is a
4401
    *  result tree fragment, the complete fragment is copied into the
4402
    *  result tree. When the result is a node-set, all the nodes in the
4403
    *  set are copied in document order into the result tree; copying
4404
    *  an element node copies the attribute nodes, namespace nodes and
4405
    *  children of the element node as well as the element node itself;
4406
    *  a root node is copied by copying its children. When the result
4407
    *  is neither a node-set nor a result tree fragment, the result is
4408
    *  converted to a string and then inserted into the result tree,
4409
    *  as with xsl:value-of.
4410
    */
4411
4412
#ifdef WITH_XSLT_DEBUG_PROCESS
4413
    XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext,
4414
   "xsltCopyOf: select %s\n", comp->select));
4415
#endif
4416
4417
    /*
4418
    * Evaluate the "select" expression.
4419
    */
4420
20.6k
    res = xsltPreCompEval(ctxt, node, comp);
4421
4422
20.6k
    if (res != NULL) {
4423
20.1k
  if (res->type == XPATH_NODESET) {
4424
      /*
4425
      * Node-set
4426
      * --------
4427
      */
4428
#ifdef WITH_XSLT_DEBUG_PROCESS
4429
      XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext,
4430
     "xsltCopyOf: result is a node set\n"));
4431
#endif
4432
16.2k
      list = res->nodesetval;
4433
16.2k
      if (list != NULL) {
4434
16.2k
    xmlNodePtr cur;
4435
    /*
4436
    * The list is already sorted in document order by XPath.
4437
    * Append everything in this order under ctxt->insert.
4438
    */
4439
685k
    for (i = 0;i < list->nodeNr;i++) {
4440
669k
        cur = list->nodeTab[i];
4441
669k
        if (cur == NULL)
4442
0
      continue;
4443
669k
        if ((cur->type == XML_DOCUMENT_NODE) ||
4444
669k
      (cur->type == XML_HTML_DOCUMENT_NODE))
4445
2.40k
        {
4446
2.40k
      xsltCopyTreeList(ctxt, inst,
4447
2.40k
          cur->children, ctxt->insert, 0, 0);
4448
666k
        } else if (cur->type == XML_ATTRIBUTE_NODE) {
4449
43.9k
      xsltShallowCopyAttr(ctxt, inst,
4450
43.9k
          ctxt->insert, (xmlAttrPtr) cur);
4451
622k
        } else {
4452
622k
      xsltCopyTree(ctxt, inst, cur, ctxt->insert, 0, 0);
4453
622k
        }
4454
669k
    }
4455
16.2k
      }
4456
16.2k
  } else if (res->type == XPATH_XSLT_TREE) {
4457
      /*
4458
      * Result tree fragment
4459
      * --------------------
4460
      * E.g. via <xsl:variable ...><foo/></xsl:variable>
4461
      * Note that the root node of such trees is an xmlDocPtr in Libxslt.
4462
      */
4463
#ifdef WITH_XSLT_DEBUG_PROCESS
4464
      XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext,
4465
     "xsltCopyOf: result is a result tree fragment\n"));
4466
#endif
4467
1.72k
      list = res->nodesetval;
4468
1.72k
      if ((list != NULL) && (list->nodeTab != NULL) &&
4469
1.72k
    (list->nodeTab[0] != NULL) &&
4470
1.72k
    (IS_XSLT_REAL_NODE(list->nodeTab[0])))
4471
1.72k
      {
4472
1.72k
    xsltCopyTreeList(ctxt, inst,
4473
1.72k
        list->nodeTab[0]->children, ctxt->insert, 0, 0);
4474
1.72k
      }
4475
2.13k
  } else {
4476
2.13k
      xmlChar *value = NULL;
4477
      /*
4478
      * Convert to a string.
4479
      */
4480
2.13k
      value = xmlXPathCastToString(res);
4481
2.13k
      if (value == NULL) {
4482
1
    xsltTransformError(ctxt, NULL, inst,
4483
1
        "Internal error in xsltCopyOf(): "
4484
1
        "failed to cast an XPath object to string.\n");
4485
1
    ctxt->state = XSLT_STATE_STOPPED;
4486
2.13k
      } else {
4487
2.13k
    if (value[0] != 0) {
4488
        /*
4489
        * Append content as text node.
4490
        */
4491
1.75k
        xsltCopyTextString(ctxt, ctxt->insert, value, 0);
4492
1.75k
    }
4493
2.13k
    xmlFree(value);
4494
4495
#ifdef WITH_XSLT_DEBUG_PROCESS
4496
    XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext,
4497
        "xsltCopyOf: result %s\n", res->stringval));
4498
#endif
4499
2.13k
      }
4500
2.13k
  }
4501
20.1k
    } else {
4502
536
  ctxt->state = XSLT_STATE_STOPPED;
4503
536
    }
4504
4505
20.6k
    if (res != NULL)
4506
20.1k
  xmlXPathFreeObject(res);
4507
20.6k
}
4508
4509
/**
4510
 * xsltValueOf:
4511
 * @ctxt:  a XSLT process context
4512
 * @node:  the node in the source tree.
4513
 * @inst:  the xslt value-of node
4514
 * @castedComp:  precomputed information
4515
 *
4516
 * Process the xslt value-of node on the source node
4517
 */
4518
void
4519
xsltValueOf(xsltTransformContextPtr ctxt, xmlNodePtr node,
4520
             xmlNodePtr inst, xsltElemPreCompPtr castedComp)
4521
335k
{
4522
#ifdef XSLT_REFACTORED
4523
    xsltStyleItemValueOfPtr comp = (xsltStyleItemValueOfPtr) castedComp;
4524
#else
4525
335k
    xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
4526
335k
#endif
4527
335k
    xmlXPathObjectPtr res = NULL;
4528
335k
    xmlChar *value = NULL;
4529
4530
335k
    if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
4531
0
  return;
4532
4533
335k
    if ((comp == NULL) || (comp->select == NULL) || (comp->comp == NULL)) {
4534
0
  xsltTransformError(ctxt, NULL, inst,
4535
0
      "Internal error in xsltValueOf(): "
4536
0
      "The XSLT 'value-of' instruction was not compiled.\n");
4537
0
  return;
4538
0
    }
4539
4540
#ifdef WITH_XSLT_DEBUG_PROCESS
4541
    XSLT_TRACE(ctxt,XSLT_TRACE_VALUE_OF,xsltGenericDebug(xsltGenericDebugContext,
4542
   "xsltValueOf: select %s\n", comp->select));
4543
#endif
4544
4545
335k
    res = xsltPreCompEval(ctxt, node, comp);
4546
4547
    /*
4548
    * Cast the XPath object to string.
4549
    */
4550
335k
    if (res != NULL) {
4551
334k
  value = xmlXPathCastToString(res);
4552
334k
  if (value == NULL) {
4553
1.29k
      xsltTransformError(ctxt, NULL, inst,
4554
1.29k
    "Internal error in xsltValueOf(): "
4555
1.29k
    "failed to cast an XPath object to string.\n");
4556
1.29k
      ctxt->state = XSLT_STATE_STOPPED;
4557
1.29k
      goto error;
4558
1.29k
  }
4559
332k
  if (value[0] != 0) {
4560
248k
      xsltCopyTextString(ctxt, ctxt->insert, value, comp->noescape);
4561
248k
  }
4562
332k
    } else {
4563
1.47k
  xsltTransformError(ctxt, NULL, inst,
4564
1.47k
      "XPath evaluation returned no result.\n");
4565
1.47k
  ctxt->state = XSLT_STATE_STOPPED;
4566
1.47k
  goto error;
4567
1.47k
    }
4568
4569
#ifdef WITH_XSLT_DEBUG_PROCESS
4570
    if (value) {
4571
  XSLT_TRACE(ctxt,XSLT_TRACE_VALUE_OF,xsltGenericDebug(xsltGenericDebugContext,
4572
       "xsltValueOf: result '%s'\n", value));
4573
    }
4574
#endif
4575
4576
335k
error:
4577
335k
    if (value != NULL)
4578
332k
  xmlFree(value);
4579
335k
    if (res != NULL)
4580
334k
  xmlXPathFreeObject(res);
4581
335k
}
4582
4583
/**
4584
 * xsltNumber:
4585
 * @ctxt:  a XSLT process context
4586
 * @node:  the node in the source tree.
4587
 * @inst:  the xslt number node
4588
 * @castedComp:  precomputed information
4589
 *
4590
 * Process the xslt number node on the source node
4591
 */
4592
void
4593
xsltNumber(xsltTransformContextPtr ctxt, xmlNodePtr node,
4594
     xmlNodePtr inst, xsltElemPreCompPtr castedComp)
4595
74.0k
{
4596
#ifdef XSLT_REFACTORED
4597
    xsltStyleItemNumberPtr comp = (xsltStyleItemNumberPtr) castedComp;
4598
#else
4599
74.0k
    xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
4600
74.0k
#endif
4601
74.0k
    xmlXPathContextPtr xpctxt;
4602
74.0k
    xmlNsPtr *oldXPNamespaces;
4603
74.0k
    int oldXPNsNr;
4604
4605
74.0k
    if (comp == NULL) {
4606
0
  xsltTransformError(ctxt, NULL, inst,
4607
0
       "xsl:number : compilation failed\n");
4608
0
  return;
4609
0
    }
4610
4611
74.0k
    if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL))
4612
0
  return;
4613
4614
74.0k
    comp->numdata.doc = inst->doc;
4615
74.0k
    comp->numdata.node = inst;
4616
4617
74.0k
    xpctxt = ctxt->xpathCtxt;
4618
74.0k
    oldXPNsNr = xpctxt->nsNr;
4619
74.0k
    oldXPNamespaces = xpctxt->namespaces;
4620
4621
#ifdef XSLT_REFACTORED
4622
    if (comp->inScopeNs != NULL) {
4623
        xpctxt->namespaces = comp->inScopeNs->list;
4624
        xpctxt->nsNr = comp->inScopeNs->xpathNumber;
4625
    } else {
4626
        xpctxt->namespaces = NULL;
4627
        xpctxt->nsNr = 0;
4628
    }
4629
#else
4630
74.0k
    xpctxt->namespaces = comp->nsList;
4631
74.0k
    xpctxt->nsNr = comp->nsNr;
4632
74.0k
#endif
4633
4634
74.0k
    xsltNumberFormat(ctxt, &comp->numdata, node);
4635
4636
74.0k
    xpctxt->nsNr = oldXPNsNr;
4637
74.0k
    xpctxt->namespaces = oldXPNamespaces;
4638
74.0k
}
4639
4640
/**
4641
 * xsltApplyImports:
4642
 * @ctxt:  an XSLT transformation context
4643
 * @contextNode:  the current node in the source tree.
4644
 * @inst:  the element node of the XSLT 'apply-imports' instruction
4645
 * @comp:  the compiled instruction
4646
 *
4647
 * Process the XSLT apply-imports element.
4648
 */
4649
void
4650
xsltApplyImports(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
4651
           xmlNodePtr inst,
4652
     xsltElemPreCompPtr comp ATTRIBUTE_UNUSED)
4653
6.74k
{
4654
6.74k
    xsltTemplatePtr templ;
4655
4656
6.74k
    if ((ctxt == NULL) || (inst == NULL))
4657
0
  return;
4658
4659
6.74k
    if (comp == NULL) {
4660
0
  xsltTransformError(ctxt, NULL, inst,
4661
0
      "Internal error in xsltApplyImports(): "
4662
0
      "The XSLT 'apply-imports' instruction was not compiled.\n");
4663
0
  return;
4664
0
    }
4665
    /*
4666
    * NOTE that ctxt->currentTemplateRule and ctxt->templ is not the
4667
    * same; the former is the "Current Template Rule" as defined by the
4668
    * XSLT spec, the latter is simply the template struct being
4669
    * currently processed.
4670
    */
4671
6.74k
    if (ctxt->currentTemplateRule == NULL) {
4672
  /*
4673
  * SPEC XSLT 2.0:
4674
  * "[ERR XTDE0560] It is a non-recoverable dynamic error if
4675
  *  xsl:apply-imports or xsl:next-match is evaluated when the
4676
  *  current template rule is null."
4677
  */
4678
46
  xsltTransformError(ctxt, NULL, inst,
4679
46
       "It is an error to call 'apply-imports' "
4680
46
       "when there's no current template rule.\n");
4681
46
  return;
4682
46
    }
4683
    /*
4684
    * TODO: Check if this is correct.
4685
    */
4686
6.70k
    templ = xsltGetTemplate(ctxt, contextNode,
4687
6.70k
  ctxt->currentTemplateRule->style);
4688
4689
6.70k
    if (templ != NULL) {
4690
1.01k
  xsltTemplatePtr oldCurTemplRule = ctxt->currentTemplateRule;
4691
  /*
4692
  * Set the current template rule.
4693
  */
4694
1.01k
  ctxt->currentTemplateRule = templ;
4695
  /*
4696
  * URGENT TODO: Need xsl:with-param be handled somehow here?
4697
  */
4698
1.01k
  xsltApplyXSLTTemplate(ctxt, contextNode, templ->content,
4699
1.01k
      templ, NULL);
4700
4701
1.01k
  ctxt->currentTemplateRule = oldCurTemplRule;
4702
1.01k
    }
4703
5.68k
    else {
4704
        /* Use built-in templates. */
4705
5.68k
        xsltDefaultProcessOneNode(ctxt, contextNode, NULL);
4706
5.68k
    }
4707
6.70k
}
4708
4709
/**
4710
 * xsltCallTemplate:
4711
 * @ctxt:  a XSLT transformation context
4712
 * @node:  the "current node" in the source tree
4713
 * @inst:  the XSLT 'call-template' instruction
4714
 * @castedComp:  the compiled information of the instruction
4715
 *
4716
 * Processes the XSLT call-template instruction on the source node.
4717
 */
4718
void
4719
xsltCallTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
4720
             xmlNodePtr inst, xsltElemPreCompPtr castedComp)
4721
3.32k
{
4722
#ifdef XSLT_REFACTORED
4723
    xsltStyleItemCallTemplatePtr comp =
4724
  (xsltStyleItemCallTemplatePtr) castedComp;
4725
#else
4726
3.32k
    xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
4727
3.32k
#endif
4728
3.32k
    xsltStackElemPtr withParams = NULL;
4729
4730
3.32k
    if (ctxt->insert == NULL)
4731
0
  return;
4732
3.32k
    if (comp == NULL) {
4733
0
  xsltTransformError(ctxt, NULL, inst,
4734
0
       "The XSLT 'call-template' instruction was not compiled.\n");
4735
0
  return;
4736
0
    }
4737
4738
    /*
4739
     * The template must have been precomputed
4740
     */
4741
3.32k
    if (comp->templ == NULL) {
4742
2.40k
  comp->templ = xsltFindTemplate(ctxt, comp->name, comp->ns);
4743
2.40k
  if (comp->templ == NULL) {
4744
2.19k
      if (comp->ns != NULL) {
4745
3
          xsltTransformError(ctxt, NULL, inst,
4746
3
      "The called template '{%s}%s' was not found.\n",
4747
3
      comp->ns, comp->name);
4748
2.19k
      } else {
4749
2.19k
          xsltTransformError(ctxt, NULL, inst,
4750
2.19k
      "The called template '%s' was not found.\n",
4751
2.19k
      comp->name);
4752
2.19k
      }
4753
2.19k
      return;
4754
2.19k
  }
4755
2.40k
    }
4756
4757
#ifdef WITH_XSLT_DEBUG_PROCESS
4758
    if ((comp != NULL) && (comp->name != NULL))
4759
  XSLT_TRACE(ctxt,XSLT_TRACE_CALL_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
4760
       "call-template: name %s\n", comp->name));
4761
#endif
4762
4763
1.13k
    if (inst->children) {
4764
0
  xmlNodePtr cur;
4765
0
  xsltStackElemPtr param;
4766
4767
0
  cur = inst->children;
4768
0
  while (cur != NULL) {
4769
#ifdef WITH_DEBUGGER
4770
      if (ctxt->debugStatus != XSLT_DEBUG_NONE)
4771
    xslHandleDebugger(cur, node, comp->templ, ctxt);
4772
#endif
4773
0
      if (ctxt->state == XSLT_STATE_STOPPED) break;
4774
      /*
4775
      * TODO: The "with-param"s could be part of the "call-template"
4776
      *   structure. Avoid to "search" for params dynamically
4777
      *   in the XML tree every time.
4778
      */
4779
0
      if (IS_XSLT_ELEM(cur)) {
4780
0
    if (IS_XSLT_NAME(cur, "with-param")) {
4781
0
        param = xsltParseStylesheetCallerParam(ctxt, cur);
4782
0
        if (param != NULL) {
4783
0
      param->next = withParams;
4784
0
      withParams = param;
4785
0
        }
4786
0
    } else {
4787
0
        xsltGenericError(xsltGenericErrorContext,
4788
0
      "xsl:call-template: misplaced xsl:%s\n", cur->name);
4789
0
    }
4790
0
      } else {
4791
0
    xsltGenericError(xsltGenericErrorContext,
4792
0
        "xsl:call-template: misplaced %s element\n", cur->name);
4793
0
      }
4794
0
      cur = cur->next;
4795
0
  }
4796
0
    }
4797
    /*
4798
     * Create a new frame using the params first
4799
     */
4800
1.13k
    xsltApplyXSLTTemplate(ctxt, node, comp->templ->content, comp->templ,
4801
1.13k
  withParams);
4802
1.13k
    if (withParams != NULL)
4803
0
  xsltFreeStackElemList(withParams);
4804
4805
#ifdef WITH_XSLT_DEBUG_PROCESS
4806
    if ((comp != NULL) && (comp->name != NULL))
4807
  XSLT_TRACE(ctxt,XSLT_TRACE_CALL_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
4808
       "call-template returned: name %s\n", comp->name));
4809
#endif
4810
1.13k
}
4811
4812
/**
4813
 * xsltApplyTemplates:
4814
 * @ctxt:  a XSLT transformation context
4815
 * @node:  the 'current node' in the source tree
4816
 * @inst:  the element node of an XSLT 'apply-templates' instruction
4817
 * @castedComp:  the compiled instruction
4818
 *
4819
 * Processes the XSLT 'apply-templates' instruction on the current node.
4820
 */
4821
void
4822
xsltApplyTemplates(xsltTransformContextPtr ctxt, xmlNodePtr node,
4823
             xmlNodePtr inst, xsltElemPreCompPtr castedComp)
4824
817k
{
4825
#ifdef XSLT_REFACTORED
4826
    xsltStyleItemApplyTemplatesPtr comp =
4827
  (xsltStyleItemApplyTemplatesPtr) castedComp;
4828
#else
4829
817k
    xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
4830
817k
#endif
4831
817k
    int i;
4832
817k
    xmlNodePtr cur, oldContextNode;
4833
817k
    xmlNodeSetPtr list = NULL, oldList;
4834
817k
    xsltStackElemPtr withParams = NULL;
4835
817k
    int oldXPProximityPosition, oldXPContextSize;
4836
817k
    const xmlChar *oldMode, *oldModeURI;
4837
817k
    xmlDocPtr oldXPDoc;
4838
817k
    xsltDocumentPtr oldDocInfo;
4839
817k
    xmlXPathContextPtr xpctxt;
4840
4841
817k
    if (comp == NULL) {
4842
0
  xsltTransformError(ctxt, NULL, inst,
4843
0
       "xsl:apply-templates : compilation failed\n");
4844
0
  return;
4845
0
    }
4846
817k
    if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL))
4847
0
  return;
4848
4849
#ifdef WITH_XSLT_DEBUG_PROCESS
4850
    if ((node != NULL) && (node->name != NULL))
4851
  XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
4852
       "xsltApplyTemplates: node: '%s'\n", node->name));
4853
#endif
4854
4855
817k
    xpctxt = ctxt->xpathCtxt;
4856
    /*
4857
    * Save context states.
4858
    */
4859
817k
    oldContextNode = ctxt->node;
4860
817k
    oldMode = ctxt->mode;
4861
817k
    oldModeURI = ctxt->modeURI;
4862
817k
    oldDocInfo = ctxt->document;
4863
817k
    oldList = ctxt->nodeList;
4864
4865
    /*
4866
     * The xpath context size and proximity position, as
4867
     * well as the xpath and context documents, may be changed
4868
     * so we save their initial state and will restore on exit
4869
     */
4870
817k
    oldXPContextSize = xpctxt->contextSize;
4871
817k
    oldXPProximityPosition = xpctxt->proximityPosition;
4872
817k
    oldXPDoc = xpctxt->doc;
4873
4874
    /*
4875
    * Set up contexts.
4876
    */
4877
817k
    ctxt->mode = comp->mode;
4878
817k
    ctxt->modeURI = comp->modeURI;
4879
4880
817k
    if (comp->select != NULL) {
4881
88.2k
  xmlXPathObjectPtr res = NULL;
4882
4883
88.2k
  if (comp->comp == NULL) {
4884
0
      xsltTransformError(ctxt, NULL, inst,
4885
0
     "xsl:apply-templates : compilation failed\n");
4886
0
      goto error;
4887
0
  }
4888
#ifdef WITH_XSLT_DEBUG_PROCESS
4889
  XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
4890
       "xsltApplyTemplates: select %s\n", comp->select));
4891
#endif
4892
4893
88.2k
  res = xsltPreCompEval(ctxt, node, comp);
4894
4895
88.2k
  if (res != NULL) {
4896
87.2k
      if (res->type == XPATH_NODESET) {
4897
87.2k
    list = res->nodesetval; /* consume the node set */
4898
87.2k
    res->nodesetval = NULL;
4899
87.2k
      } else {
4900
7
    xsltTransformError(ctxt, NULL, inst,
4901
7
        "The 'select' expression did not evaluate to a "
4902
7
        "node set.\n");
4903
7
    ctxt->state = XSLT_STATE_STOPPED;
4904
7
    xmlXPathFreeObject(res);
4905
7
    goto error;
4906
7
      }
4907
87.2k
      xmlXPathFreeObject(res);
4908
      /*
4909
      * Note: An xsl:apply-templates with a 'select' attribute,
4910
      * can change the current source doc.
4911
      */
4912
87.2k
  } else {
4913
962
      xsltTransformError(ctxt, NULL, inst,
4914
962
    "Failed to evaluate the 'select' expression.\n");
4915
962
      ctxt->state = XSLT_STATE_STOPPED;
4916
962
      goto error;
4917
962
  }
4918
87.2k
  if (list == NULL) {
4919
#ifdef WITH_XSLT_DEBUG_PROCESS
4920
      XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
4921
    "xsltApplyTemplates: select didn't evaluate to a node list\n"));
4922
#endif
4923
0
      goto exit;
4924
0
  }
4925
  /*
4926
  *
4927
  * NOTE: Previously a document info (xsltDocument) was
4928
  * created and attached to the Result Tree Fragment.
4929
  * But such a document info is created on demand in
4930
  * xsltKeyFunction() (functions.c), so we need to create
4931
  * it here beforehand.
4932
  * In order to take care of potential keys we need to
4933
  * do some extra work for the case when a Result Tree Fragment
4934
  * is converted into a nodeset (e.g. exslt:node-set()) :
4935
  * We attach a "pseudo-doc" (xsltDocument) to _private.
4936
  * This xsltDocument, together with the keyset, will be freed
4937
  * when the Result Tree Fragment is freed.
4938
  *
4939
  */
4940
#if 0
4941
  if ((ctxt->nbKeys > 0) &&
4942
      (list->nodeNr != 0) &&
4943
      (list->nodeTab[0]->doc != NULL) &&
4944
      XSLT_IS_RES_TREE_FRAG(list->nodeTab[0]->doc))
4945
  {
4946
      /*
4947
      * NOTE that it's also OK if @effectiveDocInfo will be
4948
      * set to NULL.
4949
      */
4950
      isRTF = 1;
4951
      effectiveDocInfo = list->nodeTab[0]->doc->_private;
4952
  }
4953
#endif
4954
729k
    } else {
4955
  /*
4956
   * Build an XPath node set with the children
4957
   */
4958
729k
  list = xmlXPathNodeSetCreate(NULL);
4959
729k
  if (list == NULL)
4960
253
      goto error;
4961
729k
  if (node->type != XML_NAMESPACE_DECL)
4962
728k
      cur = node->children;
4963
555
  else
4964
555
      cur = NULL;
4965
1.93M
  while (cur != NULL) {
4966
1.21M
            if (IS_XSLT_REAL_NODE(cur))
4967
1.21M
    xmlXPathNodeSetAddUnique(list, cur);
4968
1.21M
      cur = cur->next;
4969
1.21M
  }
4970
729k
    }
4971
4972
#ifdef WITH_XSLT_DEBUG_PROCESS
4973
    if (list != NULL)
4974
    XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
4975
  "xsltApplyTemplates: list of %d nodes\n", list->nodeNr));
4976
#endif
4977
4978
816k
    if ((list == NULL) || (list->nodeNr == 0))
4979
88.7k
  goto exit;
4980
4981
    /*
4982
    * Set the context's node set and size; this is also needed for
4983
    * for xsltDoSortFunction().
4984
    */
4985
727k
    ctxt->nodeList = list;
4986
    /*
4987
    * Process xsl:with-param and xsl:sort instructions.
4988
    * (The code became so verbose just to avoid the
4989
    *  xmlNodePtr sorts[XSLT_MAX_SORT] if there's no xsl:sort)
4990
    * BUG TODO: We are not using namespaced potentially defined on the
4991
    * xsl:sort or xsl:with-param elements; XPath expression might fail.
4992
    */
4993
727k
    if (inst->children) {
4994
23.5k
  xsltStackElemPtr param;
4995
4996
23.5k
  cur = inst->children;
4997
40.7k
  while (cur) {
4998
4999
#ifdef WITH_DEBUGGER
5000
      if (ctxt->debugStatus != XSLT_DEBUG_NONE)
5001
    xslHandleDebugger(cur, node, NULL, ctxt);
5002
#endif
5003
37.3k
      if (ctxt->state == XSLT_STATE_STOPPED)
5004
5
    break;
5005
37.3k
      if (cur->type == XML_TEXT_NODE) {
5006
13.5k
    cur = cur->next;
5007
13.5k
    continue;
5008
13.5k
      }
5009
23.7k
      if (! IS_XSLT_ELEM(cur))
5010
932
    break;
5011
22.7k
      if (IS_XSLT_NAME(cur, "with-param")) {
5012
1.69k
    param = xsltParseStylesheetCallerParam(ctxt, cur);
5013
1.69k
    if (param != NULL) {
5014
1.69k
        param->next = withParams;
5015
1.69k
        withParams = param;
5016
1.69k
    }
5017
1.69k
      }
5018
22.7k
      if (IS_XSLT_NAME(cur, "sort")) {
5019
19.1k
    xsltTemplatePtr oldCurTempRule =
5020
19.1k
        ctxt->currentTemplateRule;
5021
19.1k
    int nbsorts = 0;
5022
19.1k
    xmlNodePtr sorts[XSLT_MAX_SORT];
5023
5024
19.1k
    sorts[nbsorts++] = cur;
5025
19.1k
    cur = cur->next;
5026
5027
58.4k
    while (cur) {
5028
5029
#ifdef WITH_DEBUGGER
5030
        if (ctxt->debugStatus != XSLT_DEBUG_NONE)
5031
      xslHandleDebugger(cur, node, NULL, ctxt);
5032
#endif
5033
42.5k
        if (ctxt->state == XSLT_STATE_STOPPED)
5034
0
      break;
5035
5036
42.5k
        if (cur->type == XML_TEXT_NODE) {
5037
23.9k
      cur = cur->next;
5038
23.9k
      continue;
5039
23.9k
        }
5040
5041
18.5k
        if (! IS_XSLT_ELEM(cur))
5042
3.17k
      break;
5043
15.4k
        if (IS_XSLT_NAME(cur, "with-param")) {
5044
0
      param = xsltParseStylesheetCallerParam(ctxt, cur);
5045
0
      if (param != NULL) {
5046
0
          param->next = withParams;
5047
0
          withParams = param;
5048
0
      }
5049
0
        }
5050
15.4k
        if (IS_XSLT_NAME(cur, "sort")) {
5051
14.2k
      if (nbsorts >= XSLT_MAX_SORT) {
5052
0
          xsltTransformError(ctxt, NULL, cur,
5053
0
        "The number (%d) of xsl:sort instructions exceeds the "
5054
0
        "maximum allowed by this processor's settings.\n",
5055
0
        nbsorts);
5056
0
          ctxt->state = XSLT_STATE_STOPPED;
5057
0
          break;
5058
14.2k
      } else {
5059
14.2k
          sorts[nbsorts++] = cur;
5060
14.2k
      }
5061
14.2k
        }
5062
15.4k
        cur = cur->next;
5063
15.4k
    }
5064
    /*
5065
    * The "current template rule" is cleared for xsl:sort.
5066
    */
5067
19.1k
    ctxt->currentTemplateRule = NULL;
5068
    /*
5069
    * Sort.
5070
    */
5071
19.1k
    xsltDoSortFunction(ctxt, sorts, nbsorts);
5072
19.1k
    ctxt->currentTemplateRule = oldCurTempRule;
5073
19.1k
    break;
5074
19.1k
      }
5075
3.63k
      cur = cur->next;
5076
3.63k
  }
5077
23.5k
    }
5078
727k
    xpctxt->contextSize = list->nodeNr;
5079
    /*
5080
    * Apply templates for all selected source nodes.
5081
    */
5082
2.27M
    for (i = 0; i < list->nodeNr; i++) {
5083
1.54M
  cur = list->nodeTab[i];
5084
  /*
5085
  * The node becomes the "current node".
5086
  */
5087
1.54M
  ctxt->node = cur;
5088
  /*
5089
  * An xsl:apply-templates can change the current context doc.
5090
  * OPTIMIZE TODO: Get rid of the need to set the context doc.
5091
  */
5092
1.54M
  if ((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL))
5093
1.47M
      xpctxt->doc = cur->doc;
5094
5095
1.54M
  xpctxt->proximityPosition = i + 1;
5096
  /*
5097
  * Find and apply a template for this node.
5098
  */
5099
1.54M
  xsltProcessOneNode(ctxt, cur, withParams);
5100
1.54M
    }
5101
5102
816k
exit:
5103
817k
error:
5104
    /*
5105
    * Free the parameter list.
5106
    */
5107
817k
    if (withParams != NULL)
5108
1.45k
  xsltFreeStackElemList(withParams);
5109
817k
    if (list != NULL)
5110
816k
  xmlXPathFreeNodeSet(list);
5111
    /*
5112
    * Restore context states.
5113
    */
5114
817k
    xpctxt->doc = oldXPDoc;
5115
817k
    xpctxt->contextSize = oldXPContextSize;
5116
817k
    xpctxt->proximityPosition = oldXPProximityPosition;
5117
5118
817k
    ctxt->document = oldDocInfo;
5119
817k
    ctxt->nodeList = oldList;
5120
817k
    ctxt->node = oldContextNode;
5121
817k
    ctxt->mode = oldMode;
5122
817k
    ctxt->modeURI = oldModeURI;
5123
817k
}
5124
5125
5126
/**
5127
 * xsltChoose:
5128
 * @ctxt:  a XSLT process context
5129
 * @contextNode:  the current node in the source tree
5130
 * @inst:  the xsl:choose instruction
5131
 * @comp:  compiled information of the instruction
5132
 *
5133
 * Processes the xsl:choose instruction on the source node.
5134
 */
5135
void
5136
xsltChoose(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
5137
     xmlNodePtr inst, xsltElemPreCompPtr comp ATTRIBUTE_UNUSED)
5138
18.0k
{
5139
18.0k
    xmlNodePtr cur;
5140
5141
18.0k
    if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL))
5142
0
  return;
5143
5144
    /*
5145
    * TODO: Content model checks should be done only at compilation
5146
    * time.
5147
    */
5148
18.0k
    cur = inst->children;
5149
18.0k
    if (cur == NULL) {
5150
381
  xsltTransformError(ctxt, NULL, inst,
5151
381
      "xsl:choose: The instruction has no content.\n");
5152
381
  return;
5153
381
    }
5154
5155
#ifdef XSLT_REFACTORED
5156
    /*
5157
    * We don't check the content model during transformation.
5158
    */
5159
#else
5160
17.6k
    if ((! IS_XSLT_ELEM(cur)) || (! IS_XSLT_NAME(cur, "when"))) {
5161
2.51k
  xsltTransformError(ctxt, NULL, inst,
5162
2.51k
       "xsl:choose: xsl:when expected first\n");
5163
2.51k
  return;
5164
2.51k
    }
5165
15.1k
#endif
5166
5167
15.1k
    {
5168
15.1k
  int testRes = 0, res = 0;
5169
5170
#ifdef XSLT_REFACTORED
5171
  xsltStyleItemWhenPtr wcomp = NULL;
5172
#else
5173
15.1k
  xsltStylePreCompPtr wcomp = NULL;
5174
15.1k
#endif
5175
5176
  /*
5177
  * Process xsl:when ---------------------------------------------------
5178
  */
5179
25.7k
  while (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "when")) {
5180
16.1k
      wcomp = cur->psvi;
5181
5182
16.1k
      if ((wcomp == NULL) || (wcomp->test == NULL) ||
5183
16.1k
    (wcomp->comp == NULL))
5184
0
      {
5185
0
    xsltTransformError(ctxt, NULL, cur,
5186
0
        "Internal error in xsltChoose(): "
5187
0
        "The XSLT 'when' instruction was not compiled.\n");
5188
0
    goto error;
5189
0
      }
5190
5191
5192
#ifdef WITH_DEBUGGER
5193
      if (xslDebugStatus != XSLT_DEBUG_NONE) {
5194
    /*
5195
    * TODO: Isn't comp->templ always NULL for xsl:choose?
5196
    */
5197
    xslHandleDebugger(cur, contextNode, NULL, ctxt);
5198
      }
5199
#endif
5200
#ifdef WITH_XSLT_DEBUG_PROCESS
5201
      XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext,
5202
    "xsltChoose: test %s\n", wcomp->test));
5203
#endif
5204
5205
16.1k
#ifdef XSLT_FAST_IF
5206
16.1k
      res = xsltPreCompEvalToBoolean(ctxt, contextNode, wcomp);
5207
5208
16.1k
      if (res == -1) {
5209
330
    ctxt->state = XSLT_STATE_STOPPED;
5210
330
    goto error;
5211
330
      }
5212
15.8k
      testRes = (res == 1) ? 1 : 0;
5213
5214
#else /* XSLT_FAST_IF */
5215
5216
      res = xsltPreCompEval(ctxt, cotextNode, wcomp);
5217
5218
      if (res != NULL) {
5219
    if (res->type != XPATH_BOOLEAN)
5220
        res = xmlXPathConvertBoolean(res);
5221
    if (res->type == XPATH_BOOLEAN)
5222
        testRes = res->boolval;
5223
    else {
5224
#ifdef WITH_XSLT_DEBUG_PROCESS
5225
        XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext,
5226
      "xsltChoose: test didn't evaluate to a boolean\n"));
5227
#endif
5228
        goto error;
5229
    }
5230
    xmlXPathFreeObject(res);
5231
    res = NULL;
5232
      } else {
5233
    ctxt->state = XSLT_STATE_STOPPED;
5234
    goto error;
5235
      }
5236
5237
#endif /* else of XSLT_FAST_IF */
5238
5239
#ifdef WITH_XSLT_DEBUG_PROCESS
5240
      XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext,
5241
    "xsltChoose: test evaluate to %d\n", testRes));
5242
#endif
5243
15.8k
      if (testRes)
5244
5.28k
    goto test_is_true;
5245
5246
10.5k
      cur = cur->next;
5247
10.5k
  }
5248
5249
  /*
5250
  * Process xsl:otherwise ----------------------------------------------
5251
  */
5252
9.53k
  if (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "otherwise")) {
5253
5254
#ifdef WITH_DEBUGGER
5255
      if (xslDebugStatus != XSLT_DEBUG_NONE)
5256
    xslHandleDebugger(cur, contextNode, NULL, ctxt);
5257
#endif
5258
5259
#ifdef WITH_XSLT_DEBUG_PROCESS
5260
      XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext,
5261
    "evaluating xsl:otherwise\n"));
5262
#endif
5263
2.07k
      goto test_is_true;
5264
2.07k
  }
5265
7.46k
  goto exit;
5266
5267
7.46k
test_is_true:
5268
5269
7.35k
  goto process_sequence;
5270
9.53k
    }
5271
5272
7.46k
process_sequence:
5273
5274
    /*
5275
    * Instantiate the sequence constructor.
5276
    */
5277
7.35k
    xsltApplySequenceConstructor(ctxt, ctxt->node, cur->children,
5278
7.35k
  NULL);
5279
5280
14.8k
exit:
5281
15.1k
error:
5282
15.1k
    return;
5283
14.8k
}
5284
5285
/**
5286
 * xsltIf:
5287
 * @ctxt:  a XSLT process context
5288
 * @contextNode:  the current node in the source tree
5289
 * @inst:  the xsl:if instruction
5290
 * @castedComp:  compiled information of the instruction
5291
 *
5292
 * Processes the xsl:if instruction on the source node.
5293
 */
5294
void
5295
xsltIf(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
5296
             xmlNodePtr inst, xsltElemPreCompPtr castedComp)
5297
3.90k
{
5298
3.90k
    int res = 0;
5299
5300
#ifdef XSLT_REFACTORED
5301
    xsltStyleItemIfPtr comp = (xsltStyleItemIfPtr) castedComp;
5302
#else
5303
3.90k
    xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
5304
3.90k
#endif
5305
5306
3.90k
    if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL))
5307
0
  return;
5308
3.90k
    if ((comp == NULL) || (comp->test == NULL) || (comp->comp == NULL)) {
5309
0
  xsltTransformError(ctxt, NULL, inst,
5310
0
      "Internal error in xsltIf(): "
5311
0
      "The XSLT 'if' instruction was not compiled.\n");
5312
0
  return;
5313
0
    }
5314
5315
#ifdef WITH_XSLT_DEBUG_PROCESS
5316
    XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext,
5317
   "xsltIf: test %s\n", comp->test));
5318
#endif
5319
5320
3.90k
#ifdef XSLT_FAST_IF
5321
3.90k
    {
5322
3.90k
  xmlDocPtr oldLocalFragmentTop = ctxt->localRVT;
5323
5324
3.90k
  res = xsltPreCompEvalToBoolean(ctxt, contextNode, comp);
5325
5326
  /*
5327
  * Cleanup fragments created during evaluation of the
5328
  * "select" expression.
5329
  */
5330
3.90k
  if (oldLocalFragmentTop != ctxt->localRVT)
5331
252
      xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
5332
3.90k
    }
5333
5334
#ifdef WITH_XSLT_DEBUG_PROCESS
5335
    XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext,
5336
  "xsltIf: test evaluate to %d\n", res));
5337
#endif
5338
5339
3.90k
    if (res == -1) {
5340
31
  ctxt->state = XSLT_STATE_STOPPED;
5341
31
  goto error;
5342
31
    }
5343
3.87k
    if (res == 1) {
5344
  /*
5345
  * Instantiate the sequence constructor of xsl:if.
5346
  */
5347
1.56k
  xsltApplySequenceConstructor(ctxt,
5348
1.56k
      contextNode, inst->children, NULL);
5349
1.56k
    }
5350
5351
#else /* XSLT_FAST_IF */
5352
    {
5353
  /*
5354
  * OLD CODE:
5355
  */
5356
  xmlXPathObjectPtr xpobj = xsltPreCompEval(ctxt, contextNode, comp);
5357
  if (xpobj != NULL) {
5358
      if (xpobj->type != XPATH_BOOLEAN)
5359
    xpobj = xmlXPathConvertBoolean(xpobj);
5360
      if (xpobj->type == XPATH_BOOLEAN) {
5361
    res = xpobj->boolval;
5362
5363
#ifdef WITH_XSLT_DEBUG_PROCESS
5364
    XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext,
5365
        "xsltIf: test evaluate to %d\n", res));
5366
#endif
5367
    if (res) {
5368
        xsltApplySequenceConstructor(ctxt,
5369
      contextNode, inst->children, NULL);
5370
    }
5371
      } else {
5372
5373
#ifdef WITH_XSLT_DEBUG_PROCESS
5374
    XSLT_TRACE(ctxt, XSLT_TRACE_IF,
5375
        xsltGenericDebug(xsltGenericDebugContext,
5376
        "xsltIf: test didn't evaluate to a boolean\n"));
5377
#endif
5378
    ctxt->state = XSLT_STATE_STOPPED;
5379
      }
5380
      xmlXPathFreeObject(xpobj);
5381
  } else {
5382
      ctxt->state = XSLT_STATE_STOPPED;
5383
  }
5384
    }
5385
#endif /* else of XSLT_FAST_IF */
5386
5387
3.90k
error:
5388
3.90k
    return;
5389
3.87k
}
5390
5391
/**
5392
 * xsltForEach:
5393
 * @ctxt:  an XSLT transformation context
5394
 * @contextNode:  the "current node" in the source tree
5395
 * @inst:  the element node of the xsl:for-each instruction
5396
 * @castedComp:  the compiled information of the instruction
5397
 *
5398
 * Process the xslt for-each node on the source node
5399
 */
5400
void
5401
xsltForEach(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
5402
      xmlNodePtr inst, xsltElemPreCompPtr castedComp)
5403
8.51k
{
5404
#ifdef XSLT_REFACTORED
5405
    xsltStyleItemForEachPtr comp = (xsltStyleItemForEachPtr) castedComp;
5406
#else
5407
8.51k
    xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
5408
8.51k
#endif
5409
8.51k
    int i;
5410
8.51k
    xmlXPathObjectPtr res = NULL;
5411
8.51k
    xmlNodePtr cur, curInst;
5412
8.51k
    xmlNodeSetPtr list = NULL;
5413
8.51k
    xmlNodeSetPtr oldList;
5414
8.51k
    int oldXPProximityPosition, oldXPContextSize;
5415
8.51k
    xmlNodePtr oldContextNode;
5416
8.51k
    xsltTemplatePtr oldCurTemplRule;
5417
8.51k
    xmlDocPtr oldXPDoc;
5418
8.51k
    xsltDocumentPtr oldDocInfo;
5419
8.51k
    xmlXPathContextPtr xpctxt;
5420
5421
8.51k
    if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL)) {
5422
0
  xsltGenericError(xsltGenericErrorContext,
5423
0
      "xsltForEach(): Bad arguments.\n");
5424
0
  return;
5425
0
    }
5426
5427
8.51k
    if (comp == NULL) {
5428
0
        xsltTransformError(ctxt, NULL, inst,
5429
0
      "Internal error in xsltForEach(): "
5430
0
      "The XSLT 'for-each' instruction was not compiled.\n");
5431
0
        return;
5432
0
    }
5433
8.51k
    if ((comp->select == NULL) || (comp->comp == NULL)) {
5434
0
  xsltTransformError(ctxt, NULL, inst,
5435
0
      "Internal error in xsltForEach(): "
5436
0
      "The selecting expression of the XSLT 'for-each' "
5437
0
      "instruction was not compiled correctly.\n");
5438
0
  return;
5439
0
    }
5440
8.51k
    xpctxt = ctxt->xpathCtxt;
5441
5442
#ifdef WITH_XSLT_DEBUG_PROCESS
5443
    XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext,
5444
   "xsltForEach: select %s\n", comp->select));
5445
#endif
5446
5447
    /*
5448
    * Save context states.
5449
    */
5450
8.51k
    oldDocInfo = ctxt->document;
5451
8.51k
    oldList = ctxt->nodeList;
5452
8.51k
    oldContextNode = ctxt->node;
5453
    /*
5454
    * The "current template rule" is cleared for the instantiation of
5455
    * xsl:for-each.
5456
    */
5457
8.51k
    oldCurTemplRule = ctxt->currentTemplateRule;
5458
8.51k
    ctxt->currentTemplateRule = NULL;
5459
5460
8.51k
    oldXPDoc = xpctxt->doc;
5461
8.51k
    oldXPProximityPosition = xpctxt->proximityPosition;
5462
8.51k
    oldXPContextSize = xpctxt->contextSize;
5463
5464
    /*
5465
    * Evaluate the 'select' expression.
5466
    */
5467
8.51k
    res = xsltPreCompEval(ctxt, contextNode, comp);
5468
5469
8.51k
    if (res != NULL) {
5470
8.13k
  if (res->type == XPATH_NODESET)
5471
6.71k
      list = res->nodesetval;
5472
1.42k
  else {
5473
1.42k
      xsltTransformError(ctxt, NULL, inst,
5474
1.42k
    "The 'select' expression does not evaluate to a node set.\n");
5475
5476
#ifdef WITH_XSLT_DEBUG_PROCESS
5477
      XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext,
5478
    "xsltForEach: select didn't evaluate to a node list\n"));
5479
#endif
5480
1.42k
      goto error;
5481
1.42k
  }
5482
8.13k
    } else {
5483
380
  xsltTransformError(ctxt, NULL, inst,
5484
380
      "Failed to evaluate the 'select' expression.\n");
5485
380
  ctxt->state = XSLT_STATE_STOPPED;
5486
380
  goto error;
5487
380
    }
5488
5489
6.71k
    if ((list == NULL) || (list->nodeNr <= 0))
5490
3.26k
  goto exit;
5491
5492
#ifdef WITH_XSLT_DEBUG_PROCESS
5493
    XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext,
5494
  "xsltForEach: select evaluates to %d nodes\n", list->nodeNr));
5495
#endif
5496
5497
    /*
5498
    * Set the list; this has to be done already here for xsltDoSortFunction().
5499
    */
5500
3.45k
    ctxt->nodeList = list;
5501
    /*
5502
    * Handle xsl:sort instructions and skip them for further processing.
5503
    * BUG TODO: We are not using namespaced potentially defined on the
5504
    * xsl:sort element; XPath expression might fail.
5505
    */
5506
3.45k
    curInst = inst->children;
5507
3.45k
    if (IS_XSLT_ELEM(curInst) && IS_XSLT_NAME(curInst, "sort")) {
5508
209
  int nbsorts = 0;
5509
209
  xmlNodePtr sorts[XSLT_MAX_SORT];
5510
5511
209
  sorts[nbsorts++] = curInst;
5512
5513
#ifdef WITH_DEBUGGER
5514
  if (xslDebugStatus != XSLT_DEBUG_NONE)
5515
      xslHandleDebugger(curInst, contextNode, NULL, ctxt);
5516
#endif
5517
5518
209
  curInst = curInst->next;
5519
218
  while (IS_XSLT_ELEM(curInst) && IS_XSLT_NAME(curInst, "sort")) {
5520
9
      if (nbsorts >= XSLT_MAX_SORT) {
5521
0
    xsltTransformError(ctxt, NULL, curInst,
5522
0
        "The number of xsl:sort instructions exceeds the "
5523
0
        "maximum (%d) allowed by this processor.\n",
5524
0
        XSLT_MAX_SORT);
5525
0
    goto error;
5526
9
      } else {
5527
9
    sorts[nbsorts++] = curInst;
5528
9
      }
5529
5530
#ifdef WITH_DEBUGGER
5531
      if (xslDebugStatus != XSLT_DEBUG_NONE)
5532
    xslHandleDebugger(curInst, contextNode, NULL, ctxt);
5533
#endif
5534
9
      curInst = curInst->next;
5535
9
  }
5536
209
  xsltDoSortFunction(ctxt, sorts, nbsorts);
5537
209
    }
5538
3.45k
    xpctxt->contextSize = list->nodeNr;
5539
    /*
5540
    * Instantiate the sequence constructor for each selected node.
5541
    */
5542
44.9k
    for (i = 0; i < list->nodeNr; i++) {
5543
41.4k
  cur = list->nodeTab[i];
5544
  /*
5545
  * The selected node becomes the "current node".
5546
  */
5547
41.4k
  ctxt->node = cur;
5548
  /*
5549
  * An xsl:for-each can change the current context doc.
5550
  * OPTIMIZE TODO: Get rid of the need to set the context doc.
5551
  */
5552
41.4k
  if ((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL))
5553
39.1k
      xpctxt->doc = cur->doc;
5554
5555
41.4k
  xpctxt->proximityPosition = i + 1;
5556
5557
41.4k
  xsltApplySequenceConstructor(ctxt, cur, curInst, NULL);
5558
41.4k
    }
5559
5560
6.71k
exit:
5561
8.51k
error:
5562
8.51k
    if (res != NULL)
5563
8.13k
  xmlXPathFreeObject(res);
5564
    /*
5565
    * Restore old states.
5566
    */
5567
8.51k
    ctxt->document = oldDocInfo;
5568
8.51k
    ctxt->nodeList = oldList;
5569
8.51k
    ctxt->node = oldContextNode;
5570
8.51k
    ctxt->currentTemplateRule = oldCurTemplRule;
5571
5572
8.51k
    xpctxt->doc = oldXPDoc;
5573
8.51k
    xpctxt->contextSize = oldXPContextSize;
5574
8.51k
    xpctxt->proximityPosition = oldXPProximityPosition;
5575
8.51k
}
5576
5577
/************************************************************************
5578
 *                  *
5579
 *      Generic interface       *
5580
 *                  *
5581
 ************************************************************************/
5582
5583
#ifdef XSLT_GENERATE_HTML_DOCTYPE
5584
typedef struct xsltHTMLVersion {
5585
    const char *version;
5586
    const char *public;
5587
    const char *system;
5588
} xsltHTMLVersion;
5589
5590
static xsltHTMLVersion xsltHTMLVersions[] = {
5591
    { "5", NULL, "about:legacy-compat" },
5592
    { "4.01frame", "-//W3C//DTD HTML 4.01 Frameset//EN",
5593
      "http://www.w3.org/TR/1999/REC-html401-19991224/frameset.dtd"},
5594
    { "4.01strict", "-//W3C//DTD HTML 4.01//EN",
5595
      "http://www.w3.org/TR/1999/REC-html401-19991224/strict.dtd"},
5596
    { "4.01trans", "-//W3C//DTD HTML 4.01 Transitional//EN",
5597
      "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"},
5598
    { "4.01", "-//W3C//DTD HTML 4.01 Transitional//EN",
5599
      "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"},
5600
    { "4.0strict", "-//W3C//DTD HTML 4.01//EN",
5601
      "http://www.w3.org/TR/html4/strict.dtd"},
5602
    { "4.0trans", "-//W3C//DTD HTML 4.01 Transitional//EN",
5603
      "http://www.w3.org/TR/html4/loose.dtd"},
5604
    { "4.0frame", "-//W3C//DTD HTML 4.01 Frameset//EN",
5605
      "http://www.w3.org/TR/html4/frameset.dtd"},
5606
    { "4.0", "-//W3C//DTD HTML 4.01 Transitional//EN",
5607
      "http://www.w3.org/TR/html4/loose.dtd"},
5608
    { "3.2", "-//W3C//DTD HTML 3.2//EN", NULL }
5609
};
5610
5611
/**
5612
 * xsltGetHTMLIDs:
5613
 * @version:  the version string
5614
 * @publicID:  used to return the public ID
5615
 * @systemID:  used to return the system ID
5616
 *
5617
 * Returns -1 if not found, 0 otherwise and the system and public
5618
 *         Identifier for this given verion of HTML
5619
 */
5620
static int
5621
xsltGetHTMLIDs(const xmlChar *version, const xmlChar **publicID,
5622
8
              const xmlChar **systemID) {
5623
8
    unsigned int i;
5624
8
    if (version == NULL)
5625
0
  return(-1);
5626
78
    for (i = 0;i < (sizeof(xsltHTMLVersions)/sizeof(xsltHTMLVersions[1]));
5627
75
   i++) {
5628
75
  if (!xmlStrcasecmp(version,
5629
75
               (const xmlChar *) xsltHTMLVersions[i].version)) {
5630
5
      if (publicID != NULL)
5631
5
    *publicID = (const xmlChar *) xsltHTMLVersions[i].public;
5632
5
      if (systemID != NULL)
5633
5
    *systemID = (const xmlChar *) xsltHTMLVersions[i].system;
5634
5
      return(0);
5635
5
  }
5636
75
    }
5637
3
    return(-1);
5638
8
}
5639
#endif
5640
5641
/**
5642
 * xsltApplyStripSpaces:
5643
 * @ctxt:  a XSLT process context
5644
 * @node:  the root of the XML tree
5645
 *
5646
 * Strip the unwanted ignorable spaces from the input tree
5647
 */
5648
void
5649
1.81k
xsltApplyStripSpaces(xsltTransformContextPtr ctxt, xmlNodePtr node) {
5650
1.81k
    xmlNodePtr current;
5651
#ifdef WITH_XSLT_DEBUG_PROCESS
5652
    int nb = 0;
5653
#endif
5654
5655
5656
1.81k
    current = node;
5657
66.2k
    while (current != NULL) {
5658
  /*
5659
   * Cleanup children empty nodes if asked for
5660
   */
5661
66.1k
  if ((IS_XSLT_REAL_NODE(current)) &&
5662
66.1k
      (current->children != NULL) &&
5663
66.1k
      (xsltFindElemSpaceHandling(ctxt, current))) {
5664
5.16k
      xmlNodePtr delete = NULL, cur = current->children;
5665
5666
70.1k
      while (cur != NULL) {
5667
64.9k
    if (IS_BLANK_NODE(cur))
5668
22.1k
        delete = cur;
5669
5670
64.9k
    cur = cur->next;
5671
64.9k
    if (delete != NULL) {
5672
22.1k
        xmlUnlinkNode(delete);
5673
22.1k
        xmlFreeNode(delete);
5674
22.1k
        delete = NULL;
5675
#ifdef WITH_XSLT_DEBUG_PROCESS
5676
        nb++;
5677
#endif
5678
22.1k
    }
5679
64.9k
      }
5680
5.16k
  }
5681
5682
  /*
5683
   * Skip to next node in document order.
5684
   */
5685
66.1k
  if (node->type == XML_ENTITY_REF_NODE) {
5686
      /* process deep in entities */
5687
0
      xsltApplyStripSpaces(ctxt, node->children);
5688
0
  }
5689
66.1k
  if ((current->children != NULL) &&
5690
66.1k
            (current->type != XML_ENTITY_REF_NODE)) {
5691
9.68k
      current = current->children;
5692
56.4k
  } else if (current->next != NULL) {
5693
49.9k
      current = current->next;
5694
49.9k
  } else {
5695
9.75k
      do {
5696
9.75k
    current = current->parent;
5697
9.75k
    if (current == NULL)
5698
38
        break;
5699
9.71k
    if (current == node)
5700
1.77k
        goto done;
5701
7.93k
    if (current->next != NULL) {
5702
4.75k
        current = current->next;
5703
4.75k
        break;
5704
4.75k
    }
5705
7.93k
      } while (current != NULL);
5706
6.57k
  }
5707
66.1k
    }
5708
5709
1.81k
done:
5710
#ifdef WITH_XSLT_DEBUG_PROCESS
5711
    XSLT_TRACE(ctxt,XSLT_TRACE_STRIP_SPACES,xsltGenericDebug(xsltGenericDebugContext,
5712
       "xsltApplyStripSpaces: removed %d ignorable blank node\n", nb));
5713
#endif
5714
1.81k
    return;
5715
1.81k
}
5716
5717
static int
5718
xsltCountKeys(xsltTransformContextPtr ctxt)
5719
17.1k
{
5720
17.1k
    xsltStylesheetPtr style;
5721
17.1k
    xsltKeyDefPtr keyd;
5722
5723
17.1k
    if (ctxt == NULL)
5724
0
  return(-1);
5725
5726
    /*
5727
    * Do we have those nastly templates with a key() in the match pattern?
5728
    */
5729
17.1k
    ctxt->hasTemplKeyPatterns = 0;
5730
17.1k
    style = ctxt->style;
5731
34.8k
    while (style != NULL) {
5732
17.8k
  if (style->keyMatch != NULL) {
5733
139
      ctxt->hasTemplKeyPatterns = 1;
5734
139
      break;
5735
139
  }
5736
17.7k
  style = xsltNextImport(style);
5737
17.7k
    }
5738
    /*
5739
    * Count number of key declarations.
5740
    */
5741
17.1k
    ctxt->nbKeys = 0;
5742
17.1k
    style = ctxt->style;
5743
35.0k
    while (style != NULL) {
5744
17.8k
  keyd = style->keys;
5745
19.0k
  while (keyd) {
5746
1.16k
      ctxt->nbKeys++;
5747
1.16k
      keyd = keyd->next;
5748
1.16k
  }
5749
17.8k
  style = xsltNextImport(style);
5750
17.8k
    }
5751
17.1k
    return(ctxt->nbKeys);
5752
17.1k
}
5753
5754
/**
5755
 * xsltCleanupSourceDoc:
5756
 * @doc:  Document
5757
 *
5758
 * Resets source node flags and ids stored in 'psvi' member.
5759
 */
5760
static void
5761
314
xsltCleanupSourceDoc(xmlDocPtr doc) {
5762
314
    xmlNodePtr cur = (xmlNodePtr) doc;
5763
314
    void **psviPtr;
5764
5765
12.1k
    while (1) {
5766
12.1k
        xsltClearSourceNodeFlags(cur, XSLT_SOURCE_NODE_MASK);
5767
12.1k
        psviPtr = xsltGetPSVIPtr(cur);
5768
12.1k
        if (psviPtr)
5769
12.1k
            *psviPtr = NULL;
5770
5771
12.1k
        if (cur->type == XML_ELEMENT_NODE) {
5772
5.95k
            xmlAttrPtr prop = cur->properties;
5773
5774
8.66k
            while (prop) {
5775
2.70k
                prop->atype &= ~(XSLT_SOURCE_NODE_MASK << 27);
5776
2.70k
                prop->psvi = NULL;
5777
2.70k
                prop = prop->next;
5778
2.70k
            }
5779
5.95k
        }
5780
5781
12.1k
        if (cur->children != NULL && cur->type != XML_ENTITY_REF_NODE) {
5782
4.11k
            cur = cur->children;
5783
8.07k
        } else {
5784
8.07k
            if (cur == (xmlNodePtr) doc)
5785
0
                return;
5786
11.8k
            while (cur->next == NULL) {
5787
4.11k
                cur = cur->parent;
5788
4.11k
                if (cur == (xmlNodePtr) doc)
5789
314
                    return;
5790
4.11k
            }
5791
5792
7.76k
            cur = cur->next;
5793
7.76k
        }
5794
12.1k
    }
5795
314
}
5796
5797
/**
5798
 * xsltApplyStylesheetInternal:
5799
 * @style:  a parsed XSLT stylesheet
5800
 * @doc:  a parsed XML document
5801
 * @params:  a NULL terminated array of parameters names/values tuples
5802
 * @output:  the targetted output
5803
 * @profile:  profile FILE * output or NULL
5804
 * @user:  user provided parameter
5805
 *
5806
 * Apply the stylesheet to the document
5807
 * NOTE: This may lead to a non-wellformed output XML wise !
5808
 *
5809
 * Returns the result document or NULL in case of error
5810
 */
5811
static xmlDocPtr
5812
xsltApplyStylesheetInternal(xsltStylesheetPtr style, xmlDocPtr doc,
5813
                            const char **params, const char *output,
5814
                            FILE * profile, xsltTransformContextPtr userCtxt)
5815
17.1k
{
5816
17.1k
    xmlDocPtr res = NULL;
5817
17.1k
    xsltTransformContextPtr ctxt = NULL;
5818
17.1k
    xmlNodePtr root, node;
5819
17.1k
    const xmlChar *method;
5820
17.1k
    const xmlChar *doctypePublic;
5821
17.1k
    const xmlChar *doctypeSystem;
5822
17.1k
    const xmlChar *version;
5823
17.1k
    const xmlChar *encoding;
5824
17.1k
    xsltStackElemPtr variables;
5825
17.1k
    xsltStackElemPtr vptr;
5826
5827
17.1k
    xsltInitGlobals();
5828
5829
17.1k
    if ((style == NULL) || (doc == NULL))
5830
0
        return (NULL);
5831
5832
17.1k
    if (style->internalized == 0) {
5833
#ifdef WITH_XSLT_DEBUG
5834
  xsltGenericDebug(xsltGenericDebugContext,
5835
       "Stylesheet was not fully internalized !\n");
5836
#endif
5837
0
    }
5838
17.1k
    if (doc->intSubset != NULL) {
5839
  /*
5840
   * Avoid hitting the DTD when scanning nodes
5841
   * but keep it linked as doc->intSubset
5842
   */
5843
30
  xmlNodePtr cur = (xmlNodePtr) doc->intSubset;
5844
30
  if (cur->next != NULL)
5845
30
      cur->next->prev = cur->prev;
5846
30
  if (cur->prev != NULL)
5847
6
      cur->prev->next = cur->next;
5848
30
  if (doc->children == cur)
5849
24
      doc->children = cur->next;
5850
30
  if (doc->last == cur)
5851
0
      doc->last = cur->prev;
5852
30
  cur->prev = cur->next = NULL;
5853
30
    }
5854
5855
    /*
5856
     * Check for XPath document order availability
5857
     */
5858
17.1k
    root = xmlDocGetRootElement(doc);
5859
17.1k
    if (root != NULL) {
5860
17.1k
  if (((ptrdiff_t) root->content >= 0) &&
5861
17.1k
            (xslDebugStatus == XSLT_DEBUG_NONE))
5862
0
      xmlXPathOrderDocElems(doc);
5863
17.1k
    }
5864
5865
17.1k
    if (userCtxt != NULL)
5866
17.1k
  ctxt = userCtxt;
5867
0
    else
5868
0
  ctxt = xsltNewTransformContext(style, doc);
5869
5870
17.1k
    if (ctxt == NULL)
5871
0
        return (NULL);
5872
5873
17.1k
    ctxt->initialContextDoc = doc;
5874
17.1k
    ctxt->initialContextNode = (xmlNodePtr) doc;
5875
5876
17.1k
    if (profile != NULL) {
5877
#ifdef WITH_PROFILER
5878
        ctxt->profile = 1;
5879
#else
5880
0
        xsltTransformError(ctxt, NULL, (xmlNodePtr) doc,
5881
0
                "xsltApplyStylesheetInternal: "
5882
0
                "libxslt compiled without profiler\n");
5883
0
        goto error;
5884
0
#endif
5885
0
    }
5886
5887
17.1k
    if (output != NULL)
5888
0
        ctxt->outputFile = output;
5889
17.1k
    else
5890
17.1k
        ctxt->outputFile = NULL;
5891
5892
    /*
5893
     * internalize the modes if needed
5894
     */
5895
17.1k
    if (ctxt->dict != NULL) {
5896
17.1k
        if (ctxt->mode != NULL)
5897
0
      ctxt->mode = xmlDictLookup(ctxt->dict, ctxt->mode, -1);
5898
17.1k
        if (ctxt->modeURI != NULL)
5899
0
      ctxt->modeURI = xmlDictLookup(ctxt->dict, ctxt->modeURI, -1);
5900
17.1k
    }
5901
5902
17.1k
    XSLT_GET_IMPORT_PTR(method, style, method)
5903
17.1k
    XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
5904
17.1k
    XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
5905
17.1k
    XSLT_GET_IMPORT_PTR(version, style, version)
5906
17.1k
    XSLT_GET_IMPORT_PTR(encoding, style, encoding)
5907
5908
17.1k
    if ((method != NULL) &&
5909
17.1k
  (!xmlStrEqual(method, (const xmlChar *) "xml")))
5910
2.33k
    {
5911
2.33k
        if (xmlStrEqual(method, (const xmlChar *) "html")) {
5912
398
            ctxt->type = XSLT_OUTPUT_HTML;
5913
398
            if (((doctypePublic != NULL) || (doctypeSystem != NULL))) {
5914
0
                res = htmlNewDoc(doctypeSystem, doctypePublic);
5915
398
      } else {
5916
398
                if (version == NULL) {
5917
390
        xmlDtdPtr dtd;
5918
5919
390
        res = htmlNewDoc(NULL, NULL);
5920
        /*
5921
        * Make sure no DTD node is generated in this case
5922
        */
5923
390
        if (res != NULL) {
5924
388
      dtd = xmlGetIntSubset(res);
5925
388
      if (dtd != NULL) {
5926
388
          xmlUnlinkNode((xmlNodePtr) dtd);
5927
388
          xmlFreeDtd(dtd);
5928
388
      }
5929
388
      res->intSubset = NULL;
5930
388
      res->extSubset = NULL;
5931
388
        }
5932
390
    } else {
5933
5934
8
#ifdef XSLT_GENERATE_HTML_DOCTYPE
5935
8
        xsltGetHTMLIDs(version, &doctypePublic, &doctypeSystem);
5936
8
#endif
5937
8
        res = htmlNewDoc(doctypeSystem, doctypePublic);
5938
8
    }
5939
398
            }
5940
398
            if (res == NULL)
5941
2
                goto error;
5942
396
      res->dict = ctxt->dict;
5943
396
      xmlDictReference(res->dict);
5944
5945
#ifdef WITH_XSLT_DEBUG
5946
      xsltGenericDebug(xsltGenericDebugContext,
5947
    "reusing transformation dict for output\n");
5948
#endif
5949
1.93k
        } else if (xmlStrEqual(method, (const xmlChar *) "xhtml")) {
5950
0
      xsltTransformError(ctxt, NULL, (xmlNodePtr) doc,
5951
0
    "xsltApplyStylesheetInternal: unsupported method xhtml, using html\n");
5952
0
            ctxt->type = XSLT_OUTPUT_HTML;
5953
0
            res = htmlNewDoc(doctypeSystem, doctypePublic);
5954
0
            if (res == NULL)
5955
0
                goto error;
5956
0
      res->dict = ctxt->dict;
5957
0
      xmlDictReference(res->dict);
5958
5959
#ifdef WITH_XSLT_DEBUG
5960
      xsltGenericDebug(xsltGenericDebugContext,
5961
    "reusing transformation dict for output\n");
5962
#endif
5963
1.93k
        } else if (xmlStrEqual(method, (const xmlChar *) "text")) {
5964
1.93k
            ctxt->type = XSLT_OUTPUT_TEXT;
5965
1.93k
            res = xmlNewDoc(style->version);
5966
1.93k
            if (res == NULL)
5967
1
                goto error;
5968
1.93k
      res->dict = ctxt->dict;
5969
1.93k
      xmlDictReference(res->dict);
5970
5971
#ifdef WITH_XSLT_DEBUG
5972
      xsltGenericDebug(xsltGenericDebugContext,
5973
    "reusing transformation dict for output\n");
5974
#endif
5975
1.93k
        } else {
5976
1
      xsltTransformError(ctxt, NULL, (xmlNodePtr) doc,
5977
1
    "xsltApplyStylesheetInternal: unsupported method (%s)\n",
5978
1
    method);
5979
1
            goto error;
5980
1
        }
5981
14.7k
    } else {
5982
14.7k
        ctxt->type = XSLT_OUTPUT_XML;
5983
14.7k
        res = xmlNewDoc(style->version);
5984
14.7k
        if (res == NULL)
5985
7
            goto error;
5986
14.7k
  res->dict = ctxt->dict;
5987
14.7k
  xmlDictReference(ctxt->dict);
5988
#ifdef WITH_XSLT_DEBUG
5989
  xsltGenericDebug(xsltGenericDebugContext,
5990
       "reusing transformation dict for output\n");
5991
#endif
5992
14.7k
    }
5993
17.1k
    res->charset = XML_CHAR_ENCODING_UTF8;
5994
17.1k
    if (encoding != NULL)
5995
643
        res->encoding = xmlStrdup(encoding);
5996
17.1k
    variables = style->variables;
5997
5998
17.1k
    ctxt->node = (xmlNodePtr) doc;
5999
17.1k
    ctxt->output = res;
6000
6001
17.1k
    ctxt->xpathCtxt->contextSize = 1;
6002
17.1k
    ctxt->xpathCtxt->proximityPosition = 1;
6003
17.1k
    ctxt->xpathCtxt->node = NULL; /* TODO: Set the context node here? */
6004
6005
    /*
6006
     * Start the evaluation, evaluate the params, the stylesheets globals
6007
     * and start by processing the top node.
6008
     */
6009
17.1k
    if (xsltNeedElemSpaceHandling(ctxt))
6010
1.81k
  xsltApplyStripSpaces(ctxt, xmlDocGetRootElement(doc));
6011
    /*
6012
    * Evaluate global params and user-provided params.
6013
    */
6014
17.1k
    if (ctxt->globalVars == NULL)
6015
17.1k
  ctxt->globalVars = xmlHashCreate(20);
6016
17.1k
    if (params != NULL) {
6017
0
        xsltEvalUserParams(ctxt, params);
6018
0
    }
6019
6020
    /* need to be called before evaluating global variables */
6021
17.1k
    xsltCountKeys(ctxt);
6022
6023
17.1k
    xsltEvalGlobalVariables(ctxt);
6024
6025
    /* Clean up any unused RVTs. */
6026
17.1k
    xsltReleaseLocalRVTs(ctxt, NULL);
6027
6028
17.1k
    ctxt->insert = (xmlNodePtr) res;
6029
17.1k
    ctxt->varsBase = ctxt->varsNr - 1;
6030
6031
    /*
6032
    * Start processing the source tree -----------------------------------
6033
    */
6034
17.1k
    xsltProcessOneNode(ctxt, ctxt->node, NULL);
6035
    /*
6036
    * Remove all remaining vars from the stack.
6037
    */
6038
17.1k
    xsltLocalVariablePop(ctxt, 0, -2);
6039
17.1k
    xsltShutdownCtxtExts(ctxt);
6040
6041
17.1k
    xsltCleanupTemplates(style); /* TODO: <- style should be read only */
6042
6043
    /*
6044
     * Now cleanup our variables so stylesheet can be re-used
6045
     *
6046
     * TODO: this is not needed anymore global variables are copied
6047
     *       and not evaluated directly anymore, keep this as a check
6048
     */
6049
17.1k
    if (style->variables != variables) {
6050
0
        vptr = style->variables;
6051
0
        while (vptr->next != variables)
6052
0
            vptr = vptr->next;
6053
0
        vptr->next = NULL;
6054
0
        xsltFreeStackElemList(style->variables);
6055
0
        style->variables = variables;
6056
0
    }
6057
17.1k
    vptr = style->variables;
6058
18.5k
    while (vptr != NULL) {
6059
1.39k
        if (vptr->computed) {
6060
0
            if (vptr->value != NULL) {
6061
0
                xmlXPathFreeObject(vptr->value);
6062
0
                vptr->value = NULL;
6063
0
                vptr->computed = 0;
6064
0
            }
6065
0
        }
6066
1.39k
        vptr = vptr->next;
6067
1.39k
    }
6068
#if 0
6069
    /*
6070
     * code disabled by wmb; awaiting kb's review
6071
     * problem is that global variable(s) may contain xpath objects
6072
     * from doc associated with RVT, so can't be freed at this point.
6073
     * xsltFreeTransformContext includes a call to xsltFreeRVTs, so
6074
     * I assume this shouldn't be required at this point.
6075
     */
6076
    /*
6077
    * Free all remaining tree fragments.
6078
    */
6079
    xsltFreeRVTs(ctxt);
6080
#endif
6081
    /*
6082
     * Do some post processing work depending on the generated output
6083
     */
6084
17.1k
    root = xmlDocGetRootElement(res);
6085
17.1k
    if (root != NULL) {
6086
7.50k
        const xmlChar *doctype = NULL;
6087
6088
7.50k
        if ((root->ns != NULL) && (root->ns->prefix != NULL))
6089
587
      doctype = xmlDictQLookup(ctxt->dict, root->ns->prefix, root->name);
6090
7.50k
  if (doctype == NULL)
6091
7.02k
      doctype = root->name;
6092
6093
        /*
6094
         * Apply the default selection of the method
6095
         */
6096
7.50k
        if ((method == NULL) &&
6097
7.50k
            (root->ns == NULL) &&
6098
7.50k
            (!xmlStrcasecmp(root->name, (const xmlChar *) "html"))) {
6099
403
            xmlNodePtr tmp;
6100
6101
403
            tmp = res->children;
6102
411
            while ((tmp != NULL) && (tmp != root)) {
6103
33
                if (tmp->type == XML_ELEMENT_NODE)
6104
0
                    break;
6105
33
                if ((tmp->type == XML_TEXT_NODE) && (!xmlIsBlankNode(tmp)))
6106
25
                    break;
6107
8
    tmp = tmp->next;
6108
8
            }
6109
403
            if (tmp == root) {
6110
378
                ctxt->type = XSLT_OUTPUT_HTML;
6111
    /*
6112
    * REVISIT TODO: XML_HTML_DOCUMENT_NODE is set after the
6113
    *  transformation on the doc, but functions like
6114
    */
6115
378
                res->type = XML_HTML_DOCUMENT_NODE;
6116
378
                if (((doctypePublic != NULL) || (doctypeSystem != NULL))) {
6117
0
                    res->intSubset = xmlCreateIntSubset(res, doctype,
6118
0
                                                        doctypePublic,
6119
0
                                                        doctypeSystem);
6120
0
#ifdef XSLT_GENERATE_HTML_DOCTYPE
6121
378
    } else if (version != NULL) {
6122
0
                    xsltGetHTMLIDs(version, &doctypePublic,
6123
0
                                   &doctypeSystem);
6124
0
                    if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
6125
0
                        res->intSubset =
6126
0
                            xmlCreateIntSubset(res, doctype,
6127
0
                                               doctypePublic,
6128
0
                                               doctypeSystem);
6129
0
#endif
6130
0
                }
6131
378
            }
6132
6133
403
        }
6134
7.50k
        if (ctxt->type == XSLT_OUTPUT_XML) {
6135
6.36k
            XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
6136
6.36k
            XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
6137
6.36k
            if (((doctypePublic != NULL) || (doctypeSystem != NULL))) {
6138
0
          xmlNodePtr last;
6139
    /* Need a small "hack" here to assure DTD comes before
6140
       possible comment nodes */
6141
0
    node = res->children;
6142
0
    last = res->last;
6143
0
    res->children = NULL;
6144
0
    res->last = NULL;
6145
0
                res->intSubset = xmlCreateIntSubset(res, doctype,
6146
0
                                                    doctypePublic,
6147
0
                                                    doctypeSystem);
6148
0
    if (res->children != NULL) {
6149
0
        res->children->next = node;
6150
0
        node->prev = res->children;
6151
0
        res->last = last;
6152
0
    } else {
6153
0
        res->children = node;
6154
0
        res->last = last;
6155
0
    }
6156
0
      }
6157
6.36k
        }
6158
7.50k
    }
6159
17.1k
    xmlXPathFreeNodeSet(ctxt->nodeList);
6160
6161
#ifdef WITH_PROFILER
6162
    if (profile != NULL) {
6163
        xsltSaveProfiling(ctxt, profile);
6164
    }
6165
#endif
6166
6167
    /*
6168
     * Be pedantic.
6169
     */
6170
17.1k
    if ((ctxt != NULL) && (ctxt->state != XSLT_STATE_OK)) {
6171
9.69k
  xmlFreeDoc(res);
6172
9.69k
  res = NULL;
6173
9.69k
    }
6174
17.1k
    if ((res != NULL) && (ctxt != NULL) && (output != NULL)) {
6175
0
  int ret;
6176
6177
0
  ret = xsltCheckWrite(ctxt->sec, ctxt, (const xmlChar *) output);
6178
0
  if (ret == 0) {
6179
0
      xsltTransformError(ctxt, NULL, NULL,
6180
0
         "xsltApplyStylesheet: forbidden to save to %s\n",
6181
0
             output);
6182
0
  } else if (ret < 0) {
6183
0
      xsltTransformError(ctxt, NULL, NULL,
6184
0
         "xsltApplyStylesheet: saving to %s may not be possible\n",
6185
0
             output);
6186
0
  }
6187
0
    }
6188
6189
#ifdef XSLT_DEBUG_PROFILE_CACHE
6190
    printf("# Cache:\n");
6191
    printf("# Reused tree fragments: %d\n", ctxt->cache->dbgReusedRVTs);
6192
    printf("# Reused variables     : %d\n", ctxt->cache->dbgReusedVars);
6193
#endif
6194
6195
17.1k
    if (ctxt->sourceDocDirty)
6196
314
        xsltCleanupSourceDoc(doc);
6197
6198
17.1k
    if ((ctxt != NULL) && (userCtxt == NULL))
6199
0
  xsltFreeTransformContext(ctxt);
6200
6201
17.1k
    return (res);
6202
6203
11
error:
6204
11
    if (res != NULL)
6205
0
        xmlFreeDoc(res);
6206
6207
#ifdef XSLT_DEBUG_PROFILE_CACHE
6208
    printf("# Cache:\n");
6209
    printf("# Reused tree fragments: %d\n", ctxt->cache->dbgReusedRVTs);
6210
    printf("# Reused variables     : %d\n", ctxt->cache->dbgReusedVars);
6211
#endif
6212
6213
11
    if ((ctxt != NULL) && (userCtxt == NULL))
6214
0
        xsltFreeTransformContext(ctxt);
6215
11
    return (NULL);
6216
17.1k
}
6217
6218
/**
6219
 * xsltApplyStylesheet:
6220
 * @style:  a parsed XSLT stylesheet
6221
 * @doc:  a parsed XML document
6222
 * @params:  a NULL terminated arry of parameters names/values tuples
6223
 *
6224
 * Apply the stylesheet to the document
6225
 * NOTE: This may lead to a non-wellformed output XML wise !
6226
 *
6227
 * Returns the result document or NULL in case of error
6228
 */
6229
xmlDocPtr
6230
xsltApplyStylesheet(xsltStylesheetPtr style, xmlDocPtr doc,
6231
                    const char **params)
6232
0
{
6233
0
    return (xsltApplyStylesheetInternal(style, doc, params, NULL, NULL, NULL));
6234
0
}
6235
6236
/**
6237
 * xsltProfileStylesheet:
6238
 * @style:  a parsed XSLT stylesheet
6239
 * @doc:  a parsed XML document
6240
 * @params:  a NULL terminated arry of parameters names/values tuples
6241
 * @output:  a FILE * for the profiling output
6242
 *
6243
 * Apply the stylesheet to the document and dump the profiling to
6244
 * the given output.
6245
 *
6246
 * Returns the result document or NULL in case of error
6247
 */
6248
xmlDocPtr
6249
xsltProfileStylesheet(xsltStylesheetPtr style, xmlDocPtr doc,
6250
                      const char **params, FILE * output)
6251
0
{
6252
0
    xmlDocPtr res;
6253
6254
0
    res = xsltApplyStylesheetInternal(style, doc, params, NULL, output, NULL);
6255
0
    return (res);
6256
0
}
6257
6258
/**
6259
 * xsltApplyStylesheetUser:
6260
 * @style:  a parsed XSLT stylesheet
6261
 * @doc:  a parsed XML document
6262
 * @params:  a NULL terminated array of parameters names/values tuples
6263
 * @output:  the targetted output
6264
 * @profile:  profile FILE * output or NULL
6265
 * @userCtxt:  user provided transform context
6266
 *
6267
 * Apply the stylesheet to the document and allow the user to provide
6268
 * its own transformation context.
6269
 *
6270
 * Returns the result document or NULL in case of error
6271
 */
6272
xmlDocPtr
6273
xsltApplyStylesheetUser(xsltStylesheetPtr style, xmlDocPtr doc,
6274
                            const char **params, const char *output,
6275
                            FILE * profile, xsltTransformContextPtr userCtxt)
6276
17.1k
{
6277
17.1k
    xmlDocPtr res;
6278
6279
17.1k
    res = xsltApplyStylesheetInternal(style, doc, params, output,
6280
17.1k
                                profile, userCtxt);
6281
17.1k
    return (res);
6282
17.1k
}
6283
6284
/**
6285
 * xsltRunStylesheetUser:
6286
 * @style:  a parsed XSLT stylesheet
6287
 * @doc:  a parsed XML document
6288
 * @params:  a NULL terminated array of parameters names/values tuples
6289
 * @output:  the URL/filename ot the generated resource if available
6290
 * @SAX:  a SAX handler for progressive callback output (not implemented yet)
6291
 * @IObuf:  an output buffer for progressive output (not implemented yet)
6292
 * @profile:  profile FILE * output or NULL
6293
 * @userCtxt:  user provided transform context
6294
 *
6295
 * Apply the stylesheet to the document and generate the output according
6296
 * to @output @SAX and @IObuf. It's an error to specify both @SAX and @IObuf.
6297
 *
6298
 * NOTE: This may lead to a non-wellformed output XML wise !
6299
 * NOTE: This may also result in multiple files being generated
6300
 * NOTE: using IObuf, the result encoding used will be the one used for
6301
 *       creating the output buffer, use the following macro to read it
6302
 *       from the stylesheet
6303
 *       XSLT_GET_IMPORT_PTR(encoding, style, encoding)
6304
 * NOTE: using SAX, any encoding specified in the stylesheet will be lost
6305
 *       since the interface uses only UTF8
6306
 *
6307
 * Returns the number of by written to the main resource or -1 in case of
6308
 *         error.
6309
 */
6310
int
6311
xsltRunStylesheetUser(xsltStylesheetPtr style, xmlDocPtr doc,
6312
                  const char **params, const char *output,
6313
                  xmlSAXHandlerPtr SAX, xmlOutputBufferPtr IObuf,
6314
      FILE * profile, xsltTransformContextPtr userCtxt)
6315
0
{
6316
0
    xmlDocPtr tmp;
6317
0
    int ret;
6318
6319
0
    if ((output == NULL) && (SAX == NULL) && (IObuf == NULL))
6320
0
        return (-1);
6321
0
    if ((SAX != NULL) && (IObuf != NULL))
6322
0
        return (-1);
6323
6324
    /* unsupported yet */
6325
0
    if (SAX != NULL) {
6326
0
        XSLT_TODO   /* xsltRunStylesheet xmlSAXHandlerPtr SAX */
6327
0
  return (-1);
6328
0
    }
6329
6330
0
    tmp = xsltApplyStylesheetInternal(style, doc, params, output, profile,
6331
0
                                userCtxt);
6332
0
    if (tmp == NULL) {
6333
0
  xsltTransformError(NULL, NULL, (xmlNodePtr) doc,
6334
0
                         "xsltRunStylesheet : run failed\n");
6335
0
        return (-1);
6336
0
    }
6337
0
    if (IObuf != NULL) {
6338
        /* TODO: incomplete, IObuf output not progressive */
6339
0
        ret = xsltSaveResultTo(IObuf, tmp, style);
6340
0
    } else {
6341
0
        ret = xsltSaveResultToFilename(output, tmp, style, 0);
6342
0
    }
6343
0
    xmlFreeDoc(tmp);
6344
0
    return (ret);
6345
0
}
6346
6347
/**
6348
 * xsltRunStylesheet:
6349
 * @style:  a parsed XSLT stylesheet
6350
 * @doc:  a parsed XML document
6351
 * @params:  a NULL terminated array of parameters names/values tuples
6352
 * @output:  the URL/filename ot the generated resource if available
6353
 * @SAX:  a SAX handler for progressive callback output (not implemented yet)
6354
 * @IObuf:  an output buffer for progressive output (not implemented yet)
6355
 *
6356
 * Apply the stylesheet to the document and generate the output according
6357
 * to @output @SAX and @IObuf. It's an error to specify both @SAX and @IObuf.
6358
 *
6359
 * NOTE: This may lead to a non-wellformed output XML wise !
6360
 * NOTE: This may also result in multiple files being generated
6361
 * NOTE: using IObuf, the result encoding used will be the one used for
6362
 *       creating the output buffer, use the following macro to read it
6363
 *       from the stylesheet
6364
 *       XSLT_GET_IMPORT_PTR(encoding, style, encoding)
6365
 * NOTE: using SAX, any encoding specified in the stylesheet will be lost
6366
 *       since the interface uses only UTF8
6367
 *
6368
 * Returns the number of bytes written to the main resource or -1 in case of
6369
 *         error.
6370
 */
6371
int
6372
xsltRunStylesheet(xsltStylesheetPtr style, xmlDocPtr doc,
6373
                  const char **params, const char *output,
6374
                  xmlSAXHandlerPtr SAX, xmlOutputBufferPtr IObuf)
6375
0
{
6376
0
    return(xsltRunStylesheetUser(style, doc, params, output, SAX, IObuf,
6377
0
                     NULL, NULL));
6378
0
}
6379
6380
static void
6381
xsltMessageWrapper(xsltTransformContextPtr ctxt, xmlNodePtr node,
6382
0
                   xmlNodePtr inst, xsltElemPreCompPtr comp ATTRIBUTE_UNUSED) {
6383
0
    xsltMessage(ctxt, node, inst);
6384
0
}
6385
6386
/**
6387
 * xsltRegisterAllElement:
6388
 * @ctxt:  the XPath context
6389
 *
6390
 * Registers all default XSLT elements in this context
6391
 */
6392
void
6393
xsltRegisterAllElement(xsltTransformContextPtr ctxt)
6394
17.2k
{
6395
17.2k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "apply-templates",
6396
17.2k
                           XSLT_NAMESPACE,
6397
17.2k
         xsltApplyTemplates);
6398
17.2k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "apply-imports",
6399
17.2k
                           XSLT_NAMESPACE,
6400
17.2k
         xsltApplyImports);
6401
17.2k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "call-template",
6402
17.2k
                           XSLT_NAMESPACE,
6403
17.2k
         xsltCallTemplate);
6404
17.2k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "element",
6405
17.2k
                           XSLT_NAMESPACE,
6406
17.2k
         xsltElement);
6407
17.2k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "attribute",
6408
17.2k
                           XSLT_NAMESPACE,
6409
17.2k
         xsltAttribute);
6410
17.2k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "text",
6411
17.2k
                           XSLT_NAMESPACE,
6412
17.2k
         xsltText);
6413
17.2k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "processing-instruction",
6414
17.2k
                           XSLT_NAMESPACE,
6415
17.2k
         xsltProcessingInstruction);
6416
17.2k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "comment",
6417
17.2k
                           XSLT_NAMESPACE,
6418
17.2k
         xsltComment);
6419
17.2k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "copy",
6420
17.2k
                           XSLT_NAMESPACE,
6421
17.2k
         xsltCopy);
6422
17.2k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "value-of",
6423
17.2k
                           XSLT_NAMESPACE,
6424
17.2k
         xsltValueOf);
6425
17.2k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "number",
6426
17.2k
                           XSLT_NAMESPACE,
6427
17.2k
         xsltNumber);
6428
17.2k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "for-each",
6429
17.2k
                           XSLT_NAMESPACE,
6430
17.2k
         xsltForEach);
6431
17.2k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "if",
6432
17.2k
                           XSLT_NAMESPACE,
6433
17.2k
         xsltIf);
6434
17.2k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "choose",
6435
17.2k
                           XSLT_NAMESPACE,
6436
17.2k
         xsltChoose);
6437
17.2k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "sort",
6438
17.2k
                           XSLT_NAMESPACE,
6439
17.2k
         xsltSort);
6440
17.2k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "copy-of",
6441
17.2k
                           XSLT_NAMESPACE,
6442
17.2k
         xsltCopyOf);
6443
17.2k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "message",
6444
17.2k
                           XSLT_NAMESPACE,
6445
17.2k
         xsltMessageWrapper);
6446
6447
    /*
6448
     * Those don't have callable entry points but are registered anyway
6449
     */
6450
17.2k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "variable",
6451
17.2k
                           XSLT_NAMESPACE,
6452
17.2k
         xsltDebug);
6453
17.2k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "param",
6454
17.2k
                           XSLT_NAMESPACE,
6455
17.2k
         xsltDebug);
6456
17.2k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "with-param",
6457
17.2k
                           XSLT_NAMESPACE,
6458
17.2k
         xsltDebug);
6459
17.2k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "decimal-format",
6460
17.2k
                           XSLT_NAMESPACE,
6461
17.2k
         xsltDebug);
6462
17.2k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "when",
6463
17.2k
                           XSLT_NAMESPACE,
6464
17.2k
         xsltDebug);
6465
17.2k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "otherwise",
6466
17.2k
                           XSLT_NAMESPACE,
6467
17.2k
         xsltDebug);
6468
17.2k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "fallback",
6469
17.2k
                           XSLT_NAMESPACE,
6470
17.2k
         xsltDebug);
6471
6472
17.2k
}