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