Coverage Report

Created: 2025-12-03 06:15

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