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