• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * xslt.c: Implemetation of an XSL Transformation 1.0 engine
3  *
4  * Reference:
5  *   XSLT specification
6  *   http://www.w3.org/TR/1999/REC-xslt-19991116
7  *
8  *   Associating Style Sheets with XML documents
9  *   http://www.w3.org/1999/06/REC-xml-stylesheet-19990629
10  *
11  * See Copyright for the status of this software.
12  *
13  * daniel@veillard.com
14  */
15 
16 #define IN_LIBXSLT
17 #include "libxslt.h"
18 
19 #include <string.h>
20 
21 #include <libxml/xmlmemory.h>
22 #include <libxml/parser.h>
23 #include <libxml/tree.h>
24 #include <libxml/valid.h>
25 #include <libxml/hash.h>
26 #include <libxml/uri.h>
27 #include <libxml/xmlerror.h>
28 #include <libxml/parserInternals.h>
29 #include <libxml/xpathInternals.h>
30 #include <libxml/xpath.h>
31 #include "xslt.h"
32 #include "xsltInternals.h"
33 #include "pattern.h"
34 #include "variables.h"
35 #include "namespaces.h"
36 #include "attributes.h"
37 #include "xsltutils.h"
38 #include "imports.h"
39 #include "keys.h"
40 #include "documents.h"
41 #include "extensions.h"
42 #include "preproc.h"
43 #include "extra.h"
44 #include "security.h"
45 
46 #ifdef WITH_XSLT_DEBUG
47 #define WITH_XSLT_DEBUG_PARSING
48 /* #define WITH_XSLT_DEBUG_BLANKS */
49 #endif
50 
51 const char *xsltEngineVersion = LIBXSLT_VERSION_STRING LIBXSLT_VERSION_EXTRA;
52 const int xsltLibxsltVersion = LIBXSLT_VERSION;
53 const int xsltLibxmlVersion = LIBXML_VERSION;
54 
55 #ifdef XSLT_REFACTORED
56 
57 const xmlChar *xsltConstNamespaceNameXSLT = (const xmlChar *) XSLT_NAMESPACE;
58 
59 #define XSLT_ELEMENT_CATEGORY_XSLT 0
60 #define XSLT_ELEMENT_CATEGORY_EXTENSION 1
61 #define XSLT_ELEMENT_CATEGORY_LRE 2
62 
63 /*
64 * xsltLiteralResultMarker:
65 * Marker for Literal result elements, in order to avoid multiple attempts
66 * to recognize such elements in the stylesheet's tree.
67 * This marker is set on node->psvi during the initial traversal
68 * of a stylesheet's node tree.
69 *
70 const xmlChar *xsltLiteralResultMarker =
71     (const xmlChar *) "Literal Result Element";
72 */
73 
74 /*
75 * xsltXSLTTextMarker:
76 * Marker for xsl:text elements. Used to recognize xsl:text elements
77 * for post-processing of the stylesheet's tree, where those
78 * elements are removed from the tree.
79 */
80 const xmlChar *xsltXSLTTextMarker = (const xmlChar *) "XSLT Text Element";
81 
82 /*
83 * xsltXSLTAttrMarker:
84 * Marker for XSLT attribute on Literal Result Elements.
85 */
86 const xmlChar *xsltXSLTAttrMarker = (const xmlChar *) "LRE XSLT Attr";
87 
88 #endif
89 
90 #ifdef XSLT_LOCALE_WINAPI
91 extern xmlRMutexPtr xsltLocaleMutex;
92 #endif
93 /*
94  * Harmless but avoiding a problem when compiling against a
95  * libxml <= 2.3.11 without LIBXML_DEBUG_ENABLED
96  */
97 #ifndef LIBXML_DEBUG_ENABLED
98 double xmlXPathStringEvalNumber(const xmlChar *str);
99 #endif
100 /*
101  * Useful macros
102  */
103 
104 #ifdef  IS_BLANK
105 #undef	IS_BLANK
106 #endif
107 #define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) ||	\
108                      ((c) == 0x0D))
109 
110 #ifdef	IS_BLANK_NODE
111 #undef	IS_BLANK_NODE
112 #endif
113 #define IS_BLANK_NODE(n)						\
114     (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
115 
116 /**
117  * xsltParseContentError:
118  *
119  * @style: the stylesheet
120  * @node: the node where the error occured
121  *
122  * Compile-time error function.
123  */
124 static void
xsltParseContentError(xsltStylesheetPtr style,xmlNodePtr node)125 xsltParseContentError(xsltStylesheetPtr style,
126 		       xmlNodePtr node)
127 {
128     if ((style == NULL) || (node == NULL))
129 	return;
130 
131     if (IS_XSLT_ELEM(node))
132 	xsltTransformError(NULL, style, node,
133 	    "The XSLT-element '%s' is not allowed at this position.\n",
134 	    node->name);
135     else
136 	xsltTransformError(NULL, style, node,
137 	    "The element '%s' is not allowed at this position.\n",
138 	    node->name);
139     style->errors++;
140 }
141 
142 #ifdef XSLT_REFACTORED
143 #else
144 /**
145  * exclPrefixPush:
146  * @style: the transformation stylesheet
147  * @value:  the excluded namespace name to push on the stack
148  *
149  * Push an excluded namespace name on the stack
150  *
151  * Returns the new index in the stack or -1 if already present or
152  * in case of error
153  */
154 static int
exclPrefixPush(xsltStylesheetPtr style,xmlChar * value)155 exclPrefixPush(xsltStylesheetPtr style, xmlChar * value)
156 {
157     int i;
158 
159     if (style->exclPrefixMax == 0) {
160         style->exclPrefixMax = 4;
161         style->exclPrefixTab =
162             (xmlChar * *)xmlMalloc(style->exclPrefixMax *
163                                    sizeof(style->exclPrefixTab[0]));
164         if (style->exclPrefixTab == NULL) {
165             xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
166             return (-1);
167         }
168     }
169     /* do not push duplicates */
170     for (i = 0;i < style->exclPrefixNr;i++) {
171         if (xmlStrEqual(style->exclPrefixTab[i], value))
172 	    return(-1);
173     }
174     if (style->exclPrefixNr >= style->exclPrefixMax) {
175         style->exclPrefixMax *= 2;
176         style->exclPrefixTab =
177             (xmlChar * *)xmlRealloc(style->exclPrefixTab,
178                                     style->exclPrefixMax *
179                                     sizeof(style->exclPrefixTab[0]));
180         if (style->exclPrefixTab == NULL) {
181             xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
182             return (-1);
183         }
184     }
185     style->exclPrefixTab[style->exclPrefixNr] = value;
186     style->exclPrefix = value;
187     return (style->exclPrefixNr++);
188 }
189 /**
190  * exclPrefixPop:
191  * @style: the transformation stylesheet
192  *
193  * Pop an excluded prefix value from the stack
194  *
195  * Returns the stored excluded prefix value
196  */
197 static xmlChar *
exclPrefixPop(xsltStylesheetPtr style)198 exclPrefixPop(xsltStylesheetPtr style)
199 {
200     xmlChar *ret;
201 
202     if (style->exclPrefixNr <= 0)
203         return (0);
204     style->exclPrefixNr--;
205     if (style->exclPrefixNr > 0)
206         style->exclPrefix = style->exclPrefixTab[style->exclPrefixNr - 1];
207     else
208         style->exclPrefix = NULL;
209     ret = style->exclPrefixTab[style->exclPrefixNr];
210     style->exclPrefixTab[style->exclPrefixNr] = 0;
211     return (ret);
212 }
213 #endif
214 
215 /************************************************************************
216  *									*
217  *			Helper functions				*
218  *									*
219  ************************************************************************/
220 
221 static int initialized = 0;
222 /**
223  * xsltInit:
224  *
225  * Initializes the processor (e.g. registers built-in extensions,
226  * etc.)
227  */
228 void
xsltInit(void)229 xsltInit (void) {
230     if (initialized == 0) {
231 	initialized = 1;
232 #ifdef XSLT_LOCALE_WINAPI
233 	xsltLocaleMutex = xmlNewRMutex();
234 #endif
235         xsltRegisterAllExtras();
236     }
237 }
238 
239 /**
240  * xsltUninit:
241  *
242  * Uninitializes the processor.
243  */
244 void
xsltUninit(void)245 xsltUninit (void) {
246     initialized = 0;
247 }
248 
249 /**
250  * xsltIsBlank:
251  * @str:  a string
252  *
253  * Check if a string is ignorable
254  *
255  * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
256  */
257 int
xsltIsBlank(xmlChar * str)258 xsltIsBlank(xmlChar *str) {
259     if (str == NULL)
260 	return(1);
261     while (*str != 0) {
262 	if (!(IS_BLANK(*str))) return(0);
263 	str++;
264     }
265     return(1);
266 }
267 
268 /************************************************************************
269  *									*
270  *		Routines to handle XSLT data structures			*
271  *									*
272  ************************************************************************/
273 static xsltDecimalFormatPtr
xsltNewDecimalFormat(xmlChar * name)274 xsltNewDecimalFormat(xmlChar *name)
275 {
276     xsltDecimalFormatPtr self;
277     /* UTF-8 for 0x2030 */
278     static const xmlChar permille[4] = {0xe2, 0x80, 0xb0, 0};
279 
280     self = xmlMalloc(sizeof(xsltDecimalFormat));
281     if (self != NULL) {
282 	self->next = NULL;
283 	self->name = name;
284 
285 	/* Default values */
286 	self->digit = xmlStrdup(BAD_CAST("#"));
287 	self->patternSeparator = xmlStrdup(BAD_CAST(";"));
288 	self->decimalPoint = xmlStrdup(BAD_CAST("."));
289 	self->grouping = xmlStrdup(BAD_CAST(","));
290 	self->percent = xmlStrdup(BAD_CAST("%"));
291 	self->permille = xmlStrdup(BAD_CAST(permille));
292 	self->zeroDigit = xmlStrdup(BAD_CAST("0"));
293 	self->minusSign = xmlStrdup(BAD_CAST("-"));
294 	self->infinity = xmlStrdup(BAD_CAST("Infinity"));
295 	self->noNumber = xmlStrdup(BAD_CAST("NaN"));
296     }
297     return self;
298 }
299 
300 static void
xsltFreeDecimalFormat(xsltDecimalFormatPtr self)301 xsltFreeDecimalFormat(xsltDecimalFormatPtr self)
302 {
303     if (self != NULL) {
304 	if (self->digit)
305 	    xmlFree(self->digit);
306 	if (self->patternSeparator)
307 	    xmlFree(self->patternSeparator);
308 	if (self->decimalPoint)
309 	    xmlFree(self->decimalPoint);
310 	if (self->grouping)
311 	    xmlFree(self->grouping);
312 	if (self->percent)
313 	    xmlFree(self->percent);
314 	if (self->permille)
315 	    xmlFree(self->permille);
316 	if (self->zeroDigit)
317 	    xmlFree(self->zeroDigit);
318 	if (self->minusSign)
319 	    xmlFree(self->minusSign);
320 	if (self->infinity)
321 	    xmlFree(self->infinity);
322 	if (self->noNumber)
323 	    xmlFree(self->noNumber);
324 	if (self->name)
325 	    xmlFree(self->name);
326 	xmlFree(self);
327     }
328 }
329 
330 static void
xsltFreeDecimalFormatList(xsltStylesheetPtr self)331 xsltFreeDecimalFormatList(xsltStylesheetPtr self)
332 {
333     xsltDecimalFormatPtr iter;
334     xsltDecimalFormatPtr tmp;
335 
336     if (self == NULL)
337 	return;
338 
339     iter = self->decimalFormat;
340     while (iter != NULL) {
341 	tmp = iter->next;
342 	xsltFreeDecimalFormat(iter);
343 	iter = tmp;
344     }
345 }
346 
347 /**
348  * xsltDecimalFormatGetByName:
349  * @style: the XSLT stylesheet
350  * @name: the decimal-format name to find
351  *
352  * Find decimal-format by name
353  *
354  * Returns the xsltDecimalFormatPtr
355  */
356 xsltDecimalFormatPtr
xsltDecimalFormatGetByName(xsltStylesheetPtr style,xmlChar * name)357 xsltDecimalFormatGetByName(xsltStylesheetPtr style, xmlChar *name)
358 {
359     xsltDecimalFormatPtr result = NULL;
360 
361     if (name == NULL)
362 	return style->decimalFormat;
363 
364     while (style != NULL) {
365 	for (result = style->decimalFormat->next;
366 	     result != NULL;
367 	     result = result->next) {
368 	    if (xmlStrEqual(name, result->name))
369 		return result;
370 	}
371 	style = xsltNextImport(style);
372     }
373     return result;
374 }
375 
376 
377 /**
378  * xsltNewTemplate:
379  *
380  * Create a new XSLT Template
381  *
382  * Returns the newly allocated xsltTemplatePtr or NULL in case of error
383  */
384 static xsltTemplatePtr
xsltNewTemplate(void)385 xsltNewTemplate(void) {
386     xsltTemplatePtr cur;
387 
388     cur = (xsltTemplatePtr) xmlMalloc(sizeof(xsltTemplate));
389     if (cur == NULL) {
390 	xsltTransformError(NULL, NULL, NULL,
391 		"xsltNewTemplate : malloc failed\n");
392 	return(NULL);
393     }
394     memset(cur, 0, sizeof(xsltTemplate));
395     cur->priority = XSLT_PAT_NO_PRIORITY;
396     return(cur);
397 }
398 
399 /**
400  * xsltFreeTemplate:
401  * @template:  an XSLT template
402  *
403  * Free up the memory allocated by @template
404  */
405 static void
xsltFreeTemplate(xsltTemplatePtr template)406 xsltFreeTemplate(xsltTemplatePtr template) {
407     if (template == NULL)
408 	return;
409     if (template->match) xmlFree(template->match);
410 /*
411 *   NOTE: @name and @nameURI are put into the string dict now.
412 *   if (template->name) xmlFree(template->name);
413 *   if (template->nameURI) xmlFree(template->nameURI);
414 */
415 /*
416     if (template->mode) xmlFree(template->mode);
417     if (template->modeURI) xmlFree(template->modeURI);
418  */
419     if (template->inheritedNs) xmlFree(template->inheritedNs);
420     memset(template, -1, sizeof(xsltTemplate));
421     xmlFree(template);
422 }
423 
424 /**
425  * xsltFreeTemplateList:
426  * @template:  an XSLT template list
427  *
428  * Free up the memory allocated by all the elements of @template
429  */
430 static void
xsltFreeTemplateList(xsltTemplatePtr template)431 xsltFreeTemplateList(xsltTemplatePtr template) {
432     xsltTemplatePtr cur;
433 
434     while (template != NULL) {
435 	cur = template;
436 	template = template->next;
437 	xsltFreeTemplate(cur);
438     }
439 }
440 
441 #ifdef XSLT_REFACTORED
442 
443 static void
xsltFreeNsAliasList(xsltNsAliasPtr item)444 xsltFreeNsAliasList(xsltNsAliasPtr item)
445 {
446     xsltNsAliasPtr tmp;
447 
448     while (item) {
449 	tmp = item;
450 	item = item->next;
451 	xmlFree(tmp);
452     }
453     return;
454 }
455 
456 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
457 static void
xsltFreeNamespaceMap(xsltNsMapPtr item)458 xsltFreeNamespaceMap(xsltNsMapPtr item)
459 {
460     xsltNsMapPtr tmp;
461 
462     while (item) {
463 	tmp = item;
464 	item = item->next;
465 	xmlFree(tmp);
466     }
467     return;
468 }
469 
470 static xsltNsMapPtr
xsltNewNamespaceMapItem(xsltCompilerCtxtPtr cctxt,xmlDocPtr doc,xmlNsPtr ns,xmlNodePtr elem)471 xsltNewNamespaceMapItem(xsltCompilerCtxtPtr cctxt,
472 			xmlDocPtr doc,
473 			xmlNsPtr ns,
474 			xmlNodePtr elem)
475 {
476     xsltNsMapPtr ret;
477 
478     if ((cctxt == NULL) || (doc == NULL) || (ns == NULL))
479 	return(NULL);
480 
481     ret = (xsltNsMapPtr) xmlMalloc(sizeof(xsltNsMap));
482     if (ret == NULL) {
483 	xsltTransformError(NULL, cctxt->style, elem,
484 	    "Internal error: (xsltNewNamespaceMapItem) "
485 	    "memory allocation failed.\n");
486 	return(NULL);
487     }
488     memset(ret, 0, sizeof(xsltNsMap));
489     ret->doc = doc;
490     ret->ns = ns;
491     ret->origNsName = ns->href;
492     /*
493     * Store the item at current stylesheet-level.
494     */
495     if (cctxt->psData->nsMap != NULL)
496 	ret->next = cctxt->psData->nsMap;
497     cctxt->psData->nsMap = ret;
498 
499     return(ret);
500 }
501 #endif /* XSLT_REFACTORED_XSLT_NSCOMP */
502 
503 /**
504  * xsltCompilerVarInfoFree:
505  * @cctxt: the compilation context
506  *
507  * Frees the list of information for vars/params.
508  */
509 static void
xsltCompilerVarInfoFree(xsltCompilerCtxtPtr cctxt)510 xsltCompilerVarInfoFree(xsltCompilerCtxtPtr cctxt)
511 {
512     xsltVarInfoPtr ivar = cctxt->ivars, ivartmp;
513 
514     while (ivar) {
515 	ivartmp = ivar;
516 	ivar = ivar->next;
517 	xmlFree(ivartmp);
518     }
519 }
520 
521 /**
522  * xsltCompilerCtxtFree:
523  *
524  * Free an XSLT compiler context.
525  */
526 static void
xsltCompilationCtxtFree(xsltCompilerCtxtPtr cctxt)527 xsltCompilationCtxtFree(xsltCompilerCtxtPtr cctxt)
528 {
529     if (cctxt == NULL)
530 	return;
531 #ifdef WITH_XSLT_DEBUG_PARSING
532     xsltGenericDebug(xsltGenericDebugContext,
533 	"Freeing compilation context\n");
534     xsltGenericDebug(xsltGenericDebugContext,
535 	"### Max inodes: %d\n", cctxt->maxNodeInfos);
536     xsltGenericDebug(xsltGenericDebugContext,
537 	"### Max LREs  : %d\n", cctxt->maxLREs);
538 #endif
539     /*
540     * Free node-infos.
541     */
542     if (cctxt->inodeList != NULL) {
543 	xsltCompilerNodeInfoPtr tmp, cur = cctxt->inodeList;
544 	while (cur != NULL) {
545 	    tmp = cur;
546 	    cur = cur->next;
547 	    xmlFree(tmp);
548 	}
549     }
550     if (cctxt->tmpList != NULL)
551 	xsltPointerListFree(cctxt->tmpList);
552 #ifdef XSLT_REFACTORED_XPATHCOMP
553     if (cctxt->xpathCtxt != NULL)
554 	xmlXPathFreeContext(cctxt->xpathCtxt);
555 #endif
556     if (cctxt->nsAliases != NULL)
557 	xsltFreeNsAliasList(cctxt->nsAliases);
558 
559     if (cctxt->ivars)
560 	xsltCompilerVarInfoFree(cctxt);
561 
562     xmlFree(cctxt);
563 }
564 
565 /**
566  * xsltCompilerCreate:
567  *
568  * Creates an XSLT compiler context.
569  *
570  * Returns the pointer to the created xsltCompilerCtxt or
571  *         NULL in case of an internal error.
572  */
573 static xsltCompilerCtxtPtr
xsltCompilationCtxtCreate(xsltStylesheetPtr style)574 xsltCompilationCtxtCreate(xsltStylesheetPtr style) {
575     xsltCompilerCtxtPtr ret;
576 
577     ret = (xsltCompilerCtxtPtr) xmlMalloc(sizeof(xsltCompilerCtxt));
578     if (ret == NULL) {
579 	xsltTransformError(NULL, style, NULL,
580 	    "xsltCompilerCreate: allocation of compiler "
581 	    "context failed.\n");
582 	return(NULL);
583     }
584     memset(ret, 0, sizeof(xsltCompilerCtxt));
585 
586     ret->errSeverity = XSLT_ERROR_SEVERITY_ERROR;
587     ret->tmpList = xsltPointerListCreate(20);
588     if (ret->tmpList == NULL) {
589 	goto internal_err;
590     }
591 #ifdef XSLT_REFACTORED_XPATHCOMP
592     /*
593     * Create the XPath compilation context in order
594     * to speed up precompilation of XPath expressions.
595     */
596     ret->xpathCtxt = xmlXPathNewContext(NULL);
597     if (ret->xpathCtxt == NULL)
598 	goto internal_err;
599 #endif
600 
601     return(ret);
602 
603 internal_err:
604     xsltCompilationCtxtFree(ret);
605     return(NULL);
606 }
607 
608 static void
xsltLREEffectiveNsNodesFree(xsltEffectiveNsPtr first)609 xsltLREEffectiveNsNodesFree(xsltEffectiveNsPtr first)
610 {
611     xsltEffectiveNsPtr tmp;
612 
613     while (first != NULL) {
614 	tmp = first;
615 	first = first->nextInStore;
616 	xmlFree(tmp);
617     }
618 }
619 
620 static void
xsltFreePrincipalStylesheetData(xsltPrincipalStylesheetDataPtr data)621 xsltFreePrincipalStylesheetData(xsltPrincipalStylesheetDataPtr data)
622 {
623     if (data == NULL)
624 	return;
625 
626     if (data->inScopeNamespaces != NULL) {
627 	int i;
628 	xsltNsListContainerPtr nsi;
629 	xsltPointerListPtr list =
630 	    (xsltPointerListPtr) data->inScopeNamespaces;
631 
632 	for (i = 0; i < list->number; i++) {
633 	    /*
634 	    * REVISIT TODO: Free info of in-scope namespaces.
635 	    */
636 	    nsi = (xsltNsListContainerPtr) list->items[i];
637 	    if (nsi->list != NULL)
638 		xmlFree(nsi->list);
639 	    xmlFree(nsi);
640 	}
641 	xsltPointerListFree(list);
642 	data->inScopeNamespaces = NULL;
643     }
644 
645     if (data->exclResultNamespaces != NULL) {
646 	int i;
647 	xsltPointerListPtr list = (xsltPointerListPtr)
648 	    data->exclResultNamespaces;
649 
650 	for (i = 0; i < list->number; i++)
651 	    xsltPointerListFree((xsltPointerListPtr) list->items[i]);
652 
653 	xsltPointerListFree(list);
654 	data->exclResultNamespaces = NULL;
655     }
656 
657     if (data->extElemNamespaces != NULL) {
658 	xsltPointerListPtr list = (xsltPointerListPtr)
659 	    data->extElemNamespaces;
660 	int i;
661 
662 	for (i = 0; i < list->number; i++)
663 	    xsltPointerListFree((xsltPointerListPtr) list->items[i]);
664 
665 	xsltPointerListFree(list);
666 	data->extElemNamespaces = NULL;
667     }
668     if (data->effectiveNs) {
669 	xsltLREEffectiveNsNodesFree(data->effectiveNs);
670 	data->effectiveNs = NULL;
671     }
672 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
673     xsltFreeNamespaceMap(data->nsMap);
674 #endif
675     xmlFree(data);
676 }
677 
678 static xsltPrincipalStylesheetDataPtr
xsltNewPrincipalStylesheetData(void)679 xsltNewPrincipalStylesheetData(void)
680 {
681     xsltPrincipalStylesheetDataPtr ret;
682 
683     ret = (xsltPrincipalStylesheetDataPtr)
684 	xmlMalloc(sizeof(xsltPrincipalStylesheetData));
685     if (ret == NULL) {
686 	xsltTransformError(NULL, NULL, NULL,
687 	    "xsltNewPrincipalStylesheetData: memory allocation failed.\n");
688 	return(NULL);
689     }
690     memset(ret, 0, sizeof(xsltPrincipalStylesheetData));
691 
692     /*
693     * Global list of in-scope namespaces.
694     */
695     ret->inScopeNamespaces = xsltPointerListCreate(-1);
696     if (ret->inScopeNamespaces == NULL)
697 	goto internal_err;
698     /*
699     * Global list of excluded result ns-decls.
700     */
701     ret->exclResultNamespaces = xsltPointerListCreate(-1);
702     if (ret->exclResultNamespaces == NULL)
703 	goto internal_err;
704     /*
705     * Global list of extension instruction namespace names.
706     */
707     ret->extElemNamespaces = xsltPointerListCreate(-1);
708     if (ret->extElemNamespaces == NULL)
709 	goto internal_err;
710 
711     return(ret);
712 
713 internal_err:
714 
715     return(NULL);
716 }
717 
718 #endif
719 
720 /**
721  * xsltNewStylesheet:
722  *
723  * Create a new XSLT Stylesheet
724  *
725  * Returns the newly allocated xsltStylesheetPtr or NULL in case of error
726  */
727 xsltStylesheetPtr
xsltNewStylesheet(void)728 xsltNewStylesheet(void) {
729     xsltStylesheetPtr ret = NULL;
730 
731     ret = (xsltStylesheetPtr) xmlMalloc(sizeof(xsltStylesheet));
732     if (ret == NULL) {
733 	xsltTransformError(NULL, NULL, NULL,
734 		"xsltNewStylesheet : malloc failed\n");
735 	goto internal_err;
736     }
737     memset(ret, 0, sizeof(xsltStylesheet));
738 
739     ret->omitXmlDeclaration = -1;
740     ret->standalone = -1;
741     ret->decimalFormat = xsltNewDecimalFormat(NULL);
742     ret->indent = -1;
743     ret->errors = 0;
744     ret->warnings = 0;
745     ret->exclPrefixNr = 0;
746     ret->exclPrefixMax = 0;
747     ret->exclPrefixTab = NULL;
748     ret->extInfos = NULL;
749     ret->extrasNr = 0;
750     ret->internalized = 1;
751     ret->literal_result = 0;
752     ret->dict = xmlDictCreate();
753 #ifdef WITH_XSLT_DEBUG
754     xsltGenericDebug(xsltGenericDebugContext,
755 	"creating dictionary for stylesheet\n");
756 #endif
757 
758     xsltInit();
759 
760     return(ret);
761 
762 internal_err:
763     if (ret != NULL)
764 	xsltFreeStylesheet(ret);
765     return(NULL);
766 }
767 
768 /**
769  * xsltAllocateExtra:
770  * @style:  an XSLT stylesheet
771  *
772  * Allocate an extra runtime information slot statically while compiling
773  * the stylesheet and return its number
774  *
775  * Returns the number of the slot
776  */
777 int
xsltAllocateExtra(xsltStylesheetPtr style)778 xsltAllocateExtra(xsltStylesheetPtr style)
779 {
780     return(style->extrasNr++);
781 }
782 
783 /**
784  * xsltAllocateExtraCtxt:
785  * @ctxt:  an XSLT transformation context
786  *
787  * Allocate an extra runtime information slot at run-time
788  * and return its number
789  * This make sure there is a slot ready in the transformation context
790  *
791  * Returns the number of the slot
792  */
793 int
xsltAllocateExtraCtxt(xsltTransformContextPtr ctxt)794 xsltAllocateExtraCtxt(xsltTransformContextPtr ctxt)
795 {
796     if (ctxt->extrasNr >= ctxt->extrasMax) {
797 	int i;
798 	if (ctxt->extrasNr == 0) {
799 	    ctxt->extrasMax = 20;
800 	    ctxt->extras = (xsltRuntimeExtraPtr)
801 		xmlMalloc(ctxt->extrasMax * sizeof(xsltRuntimeExtra));
802 	    if (ctxt->extras == NULL) {
803 		xmlGenericError(xmlGenericErrorContext,
804 			"xsltAllocateExtraCtxt: out of memory\n");
805 		ctxt->state = XSLT_STATE_ERROR;
806 		return(0);
807 	    }
808 	    for (i = 0;i < ctxt->extrasMax;i++) {
809 		ctxt->extras[i].info = NULL;
810 		ctxt->extras[i].deallocate = NULL;
811 		ctxt->extras[i].val.ptr = NULL;
812 	    }
813 
814 	} else {
815 	    xsltRuntimeExtraPtr tmp;
816 
817 	    ctxt->extrasMax += 100;
818 	    tmp = (xsltRuntimeExtraPtr) xmlRealloc(ctxt->extras,
819 		            ctxt->extrasMax * sizeof(xsltRuntimeExtra));
820 	    if (tmp == NULL) {
821 		xmlGenericError(xmlGenericErrorContext,
822 			"xsltAllocateExtraCtxt: out of memory\n");
823 		ctxt->state = XSLT_STATE_ERROR;
824 		return(0);
825 	    }
826 	    ctxt->extras = tmp;
827 	    for (i = ctxt->extrasNr;i < ctxt->extrasMax;i++) {
828 		ctxt->extras[i].info = NULL;
829 		ctxt->extras[i].deallocate = NULL;
830 		ctxt->extras[i].val.ptr = NULL;
831 	    }
832 	}
833     }
834     return(ctxt->extrasNr++);
835 }
836 
837 /**
838  * xsltFreeStylesheetList:
839  * @style:  an XSLT stylesheet list
840  *
841  * Free up the memory allocated by the list @style
842  */
843 static void
xsltFreeStylesheetList(xsltStylesheetPtr style)844 xsltFreeStylesheetList(xsltStylesheetPtr style) {
845     xsltStylesheetPtr next;
846 
847     while (style != NULL) {
848 	next = style->next;
849 	xsltFreeStylesheet(style);
850 	style = next;
851     }
852 }
853 
854 /**
855  * xsltCleanupStylesheetTree:
856  *
857  * @doc: the document-node
858  * @node: the element where the stylesheet is rooted at
859  *
860  * Actually @node need not be the document-element, but
861  * currently Libxslt does not support embedded stylesheets.
862  *
863  * Returns 0 if OK, -1 on API or internal errors.
864  */
865 static int
xsltCleanupStylesheetTree(xmlDocPtr doc ATTRIBUTE_UNUSED,xmlNodePtr rootElem ATTRIBUTE_UNUSED)866 xsltCleanupStylesheetTree(xmlDocPtr doc ATTRIBUTE_UNUSED,
867 			  xmlNodePtr rootElem ATTRIBUTE_UNUSED)
868 {
869 #if 0 /* TODO: Currently disabled, since probably not needed. */
870     xmlNodePtr cur;
871 
872     if ((doc == NULL) || (rootElem == NULL) ||
873 	(rootElem->type != XML_ELEMENT_NODE) ||
874 	(doc != rootElem->doc))
875 	return(-1);
876 
877     /*
878     * Cleanup was suggested by Aleksey Sanin:
879     * Clear the PSVI field to avoid problems if the
880     * node-tree of the stylesheet is intended to be used for
881     * further processing by the user (e.g. for compiling it
882     * once again - although not recommended).
883     */
884 
885     cur = rootElem;
886     while (cur != NULL) {
887 	if (cur->type == XML_ELEMENT_NODE) {
888 	    /*
889 	    * Clear the PSVI field.
890 	    */
891 	    cur->psvi = NULL;
892 	    if (cur->children) {
893 		cur = cur->children;
894 		continue;
895 	    }
896 	}
897 
898 leave_node:
899 	if (cur == rootElem)
900 	    break;
901 	if (cur->next != NULL)
902 	    cur = cur->next;
903 	else {
904 	    cur = cur->parent;
905 	    if (cur == NULL)
906 		break;
907 	    goto leave_node;
908 	}
909     }
910 #endif /* #if 0 */
911     return(0);
912 }
913 
914 /**
915  * xsltFreeStylesheet:
916  * @style:  an XSLT stylesheet
917  *
918  * Free up the memory allocated by @style
919  */
920 void
xsltFreeStylesheet(xsltStylesheetPtr style)921 xsltFreeStylesheet(xsltStylesheetPtr style)
922 {
923     if (style == NULL)
924         return;
925 
926 #ifdef XSLT_REFACTORED
927     /*
928     * Start with a cleanup of the main stylesheet's doc.
929     */
930     if ((style->principal == style) && (style->doc))
931 	xsltCleanupStylesheetTree(style->doc,
932 	    xmlDocGetRootElement(style->doc));
933 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
934     /*
935     * Restore changed ns-decls before freeing the document.
936     */
937     if ((style->doc != NULL) &&
938 	XSLT_HAS_INTERNAL_NSMAP(style))
939     {
940 	xsltRestoreDocumentNamespaces(XSLT_GET_INTERNAL_NSMAP(style),
941 	    style->doc);
942     }
943 #endif /* XSLT_REFACTORED_XSLT_NSCOMP */
944 #else
945     /*
946     * Start with a cleanup of the main stylesheet's doc.
947     */
948     if ((style->parent == NULL) && (style->doc))
949 	xsltCleanupStylesheetTree(style->doc,
950 	    xmlDocGetRootElement(style->doc));
951 #endif /* XSLT_REFACTORED */
952 
953     xsltFreeKeys(style);
954     xsltFreeExts(style);
955     xsltFreeTemplateHashes(style);
956     xsltFreeDecimalFormatList(style);
957     xsltFreeTemplateList(style->templates);
958     xsltFreeAttributeSetsHashes(style);
959     xsltFreeNamespaceAliasHashes(style);
960     xsltFreeStylePreComps(style);
961     /*
962     * Free documents of all included stylsheet modules of this
963     * stylesheet level.
964     */
965     xsltFreeStyleDocuments(style);
966     /*
967     * TODO: Best time to shutdown extension stuff?
968     */
969     xsltShutdownExts(style);
970 
971     if (style->variables != NULL)
972         xsltFreeStackElemList(style->variables);
973     if (style->cdataSection != NULL)
974         xmlHashFree(style->cdataSection, NULL);
975     if (style->stripSpaces != NULL)
976         xmlHashFree(style->stripSpaces, NULL);
977     if (style->nsHash != NULL)
978         xmlHashFree(style->nsHash, NULL);
979     if (style->exclPrefixTab != NULL)
980         xmlFree(style->exclPrefixTab);
981     if (style->method != NULL)
982         xmlFree(style->method);
983     if (style->methodURI != NULL)
984         xmlFree(style->methodURI);
985     if (style->version != NULL)
986         xmlFree(style->version);
987     if (style->encoding != NULL)
988         xmlFree(style->encoding);
989     if (style->doctypePublic != NULL)
990         xmlFree(style->doctypePublic);
991     if (style->doctypeSystem != NULL)
992         xmlFree(style->doctypeSystem);
993     if (style->mediaType != NULL)
994         xmlFree(style->mediaType);
995     if (style->attVTs)
996         xsltFreeAVTList(style->attVTs);
997     if (style->imports != NULL)
998         xsltFreeStylesheetList(style->imports);
999 
1000 #ifdef XSLT_REFACTORED
1001     /*
1002     * If this is the principal stylesheet, then
1003     * free its internal data.
1004     */
1005     if (style->principal == style) {
1006 	if (style->principalData) {
1007 	    xsltFreePrincipalStylesheetData(style->principalData);
1008 	    style->principalData = NULL;
1009 	}
1010     }
1011 #endif
1012     /*
1013     * Better to free the main document of this stylesheet level
1014     * at the end - so here.
1015     */
1016     if (style->doc != NULL) {
1017         xmlFreeDoc(style->doc);
1018     }
1019 
1020 #ifdef WITH_XSLT_DEBUG
1021     xsltGenericDebug(xsltGenericDebugContext,
1022                      "freeing dictionary from stylesheet\n");
1023 #endif
1024     xmlDictFree(style->dict);
1025 
1026     memset(style, -1, sizeof(xsltStylesheet));
1027     xmlFree(style);
1028 }
1029 
1030 /************************************************************************
1031  *									*
1032  *		Parsing of an XSLT Stylesheet				*
1033  *									*
1034  ************************************************************************/
1035 
1036 #ifdef XSLT_REFACTORED
1037     /*
1038     * This is now performed in an optimized way in xsltParseXSLTTemplate.
1039     */
1040 #else
1041 /**
1042  * xsltGetInheritedNsList:
1043  * @style:  the stylesheet
1044  * @template: the template
1045  * @node:  the current node
1046  *
1047  * Search all the namespace applying to a given element except the ones
1048  * from excluded output prefixes currently in scope. Initialize the
1049  * template inheritedNs list with it.
1050  *
1051  * Returns the number of entries found
1052  */
1053 static int
xsltGetInheritedNsList(xsltStylesheetPtr style,xsltTemplatePtr template,xmlNodePtr node)1054 xsltGetInheritedNsList(xsltStylesheetPtr style,
1055 	               xsltTemplatePtr template,
1056 	               xmlNodePtr node)
1057 {
1058     xmlNsPtr cur;
1059     xmlNsPtr *ret = NULL;
1060     int nbns = 0;
1061     int maxns = 10;
1062     int i;
1063 
1064     if ((style == NULL) || (template == NULL) || (node == NULL) ||
1065 	(template->inheritedNsNr != 0) || (template->inheritedNs != NULL))
1066 	return(0);
1067     while (node != NULL) {
1068         if (node->type == XML_ELEMENT_NODE) {
1069             cur = node->nsDef;
1070             while (cur != NULL) {
1071 		if (xmlStrEqual(cur->href, XSLT_NAMESPACE))
1072 		    goto skip_ns;
1073 
1074 		if ((cur->prefix != NULL) &&
1075 		    (xsltCheckExtPrefix(style, cur->prefix)))
1076 		    goto skip_ns;
1077 		/*
1078 		* Check if this namespace was excluded.
1079 		* Note that at this point only the exclusions defined
1080 		* on the topmost stylesheet element are in the exclusion-list.
1081 		*/
1082 		for (i = 0;i < style->exclPrefixNr;i++) {
1083 		    if (xmlStrEqual(cur->href, style->exclPrefixTab[i]))
1084 			goto skip_ns;
1085 		}
1086                 if (ret == NULL) {
1087                     ret =
1088                         (xmlNsPtr *) xmlMalloc((maxns + 1) *
1089                                                sizeof(xmlNsPtr));
1090                     if (ret == NULL) {
1091                         xmlGenericError(xmlGenericErrorContext,
1092                                         "xsltGetInheritedNsList : out of memory!\n");
1093                         return(0);
1094                     }
1095                     ret[nbns] = NULL;
1096                 }
1097 		/*
1098 		* Skip shadowed namespace bindings.
1099 		*/
1100                 for (i = 0; i < nbns; i++) {
1101                     if ((cur->prefix == ret[i]->prefix) ||
1102                         (xmlStrEqual(cur->prefix, ret[i]->prefix)))
1103                         break;
1104                 }
1105                 if (i >= nbns) {
1106                     if (nbns >= maxns) {
1107                         maxns *= 2;
1108                         ret = (xmlNsPtr *) xmlRealloc(ret,
1109                                                       (maxns +
1110                                                        1) *
1111                                                       sizeof(xmlNsPtr));
1112                         if (ret == NULL) {
1113                             xmlGenericError(xmlGenericErrorContext,
1114                                             "xsltGetInheritedNsList : realloc failed!\n");
1115                             return(0);
1116                         }
1117                     }
1118                     ret[nbns++] = cur;
1119                     ret[nbns] = NULL;
1120                 }
1121 skip_ns:
1122                 cur = cur->next;
1123             }
1124         }
1125         node = node->parent;
1126     }
1127     if (nbns != 0) {
1128 #ifdef WITH_XSLT_DEBUG_PARSING
1129         xsltGenericDebug(xsltGenericDebugContext,
1130                          "template has %d inherited namespaces\n", nbns);
1131 #endif
1132 	template->inheritedNsNr = nbns;
1133 	template->inheritedNs = ret;
1134     }
1135     return (nbns);
1136 }
1137 #endif /* else of XSLT_REFACTORED */
1138 
1139 /**
1140  * xsltParseStylesheetOutput:
1141  * @style:  the XSLT stylesheet
1142  * @cur:  the "output" element
1143  *
1144  * parse an XSLT stylesheet output element and record
1145  * information related to the stylesheet output
1146  */
1147 
1148 void
xsltParseStylesheetOutput(xsltStylesheetPtr style,xmlNodePtr cur)1149 xsltParseStylesheetOutput(xsltStylesheetPtr style, xmlNodePtr cur)
1150 {
1151     xmlChar *elements,
1152      *prop;
1153     xmlChar *element,
1154      *end;
1155 
1156     if ((cur == NULL) || (style == NULL))
1157         return;
1158 
1159     prop = xmlGetNsProp(cur, (const xmlChar *) "version", NULL);
1160     if (prop != NULL) {
1161         if (style->version != NULL)
1162             xmlFree(style->version);
1163         style->version = prop;
1164     }
1165 
1166     prop = xmlGetNsProp(cur, (const xmlChar *) "encoding", NULL);
1167     if (prop != NULL) {
1168         if (style->encoding != NULL)
1169             xmlFree(style->encoding);
1170         style->encoding = prop;
1171     }
1172 
1173     /* relaxed to support xt:document
1174     * TODO KB: What does "relaxed to support xt:document" mean?
1175     */
1176     prop = xmlGetNsProp(cur, (const xmlChar *) "method", NULL);
1177     if (prop != NULL) {
1178         const xmlChar *URI;
1179 
1180         if (style->method != NULL)
1181             xmlFree(style->method);
1182         style->method = NULL;
1183         if (style->methodURI != NULL)
1184             xmlFree(style->methodURI);
1185         style->methodURI = NULL;
1186 
1187 	/*
1188 	* TODO: Don't use xsltGetQNameURI().
1189 	*/
1190 	URI = xsltGetQNameURI(cur, &prop);
1191 	if (prop == NULL) {
1192 	    if (style != NULL) style->errors++;
1193 	} else if (URI == NULL) {
1194             if ((xmlStrEqual(prop, (const xmlChar *) "xml")) ||
1195                 (xmlStrEqual(prop, (const xmlChar *) "html")) ||
1196                 (xmlStrEqual(prop, (const xmlChar *) "text"))) {
1197                 style->method = prop;
1198             } else {
1199 		xsltTransformError(NULL, style, cur,
1200                                  "invalid value for method: %s\n", prop);
1201                 if (style != NULL) style->warnings++;
1202             }
1203 	} else {
1204 	    style->method = prop;
1205 	    style->methodURI = xmlStrdup(URI);
1206 	}
1207     }
1208 
1209     prop = xmlGetNsProp(cur, (const xmlChar *) "doctype-system", NULL);
1210     if (prop != NULL) {
1211         if (style->doctypeSystem != NULL)
1212             xmlFree(style->doctypeSystem);
1213         style->doctypeSystem = prop;
1214     }
1215 
1216     prop = xmlGetNsProp(cur, (const xmlChar *) "doctype-public", NULL);
1217     if (prop != NULL) {
1218         if (style->doctypePublic != NULL)
1219             xmlFree(style->doctypePublic);
1220         style->doctypePublic = prop;
1221     }
1222 
1223     prop = xmlGetNsProp(cur, (const xmlChar *) "standalone", NULL);
1224     if (prop != NULL) {
1225         if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
1226             style->standalone = 1;
1227         } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
1228             style->standalone = 0;
1229         } else {
1230 	    xsltTransformError(NULL, style, cur,
1231                              "invalid value for standalone: %s\n", prop);
1232             style->errors++;
1233         }
1234         xmlFree(prop);
1235     }
1236 
1237     prop = xmlGetNsProp(cur, (const xmlChar *) "indent", NULL);
1238     if (prop != NULL) {
1239         if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
1240             style->indent = 1;
1241         } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
1242             style->indent = 0;
1243         } else {
1244 	    xsltTransformError(NULL, style, cur,
1245                              "invalid value for indent: %s\n", prop);
1246             style->errors++;
1247         }
1248         xmlFree(prop);
1249     }
1250 
1251     prop = xmlGetNsProp(cur, (const xmlChar *) "omit-xml-declaration", NULL);
1252     if (prop != NULL) {
1253         if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
1254             style->omitXmlDeclaration = 1;
1255         } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
1256             style->omitXmlDeclaration = 0;
1257         } else {
1258 	    xsltTransformError(NULL, style, cur,
1259                              "invalid value for omit-xml-declaration: %s\n",
1260                              prop);
1261             style->errors++;
1262         }
1263         xmlFree(prop);
1264     }
1265 
1266     elements = xmlGetNsProp(cur, (const xmlChar *) "cdata-section-elements",
1267 	NULL);
1268     if (elements != NULL) {
1269         if (style->cdataSection == NULL)
1270             style->cdataSection = xmlHashCreate(10);
1271         if (style->cdataSection == NULL)
1272             return;
1273 
1274         element = elements;
1275         while (*element != 0) {
1276             while (IS_BLANK(*element))
1277                 element++;
1278             if (*element == 0)
1279                 break;
1280             end = element;
1281             while ((*end != 0) && (!IS_BLANK(*end)))
1282                 end++;
1283             element = xmlStrndup(element, end - element);
1284             if (element) {
1285 #ifdef WITH_XSLT_DEBUG_PARSING
1286                 xsltGenericDebug(xsltGenericDebugContext,
1287                                  "add cdata section output element %s\n",
1288                                  element);
1289 #endif
1290 		if (xmlValidateQName(BAD_CAST element, 0) != 0) {
1291 		    xsltTransformError(NULL, style, cur,
1292 			"Attribute 'cdata-section-elements': The value "
1293 			"'%s' is not a valid QName.\n", element);
1294 		    xmlFree(element);
1295 		    style->errors++;
1296 		} else {
1297 		    const xmlChar *URI;
1298 
1299 		    /*
1300 		    * TODO: Don't use xsltGetQNameURI().
1301 		    */
1302 		    URI = xsltGetQNameURI(cur, &element);
1303 		    if (element == NULL) {
1304 			/*
1305 			* TODO: We'll report additionally an error
1306 			*  via the stylesheet's error handling.
1307 			*/
1308 			xsltTransformError(NULL, style, cur,
1309 			    "Attribute 'cdata-section-elements': The value "
1310 			    "'%s' is not a valid QName.\n", element);
1311 			style->errors++;
1312 		    } else {
1313 			xmlNsPtr ns;
1314 
1315 			/*
1316 			* XSLT-1.0 "Each QName is expanded into an
1317 			*  expanded-name using the namespace declarations in
1318 			*  effect on the xsl:output element in which the QName
1319 			*  occurs; if there is a default namespace, it is used
1320 			*  for QNames that do not have a prefix"
1321 			* NOTE: Fix of bug #339570.
1322 			*/
1323 			if (URI == NULL) {
1324 			    ns = xmlSearchNs(style->doc, cur, NULL);
1325 			    if (ns != NULL)
1326 				URI = ns->href;
1327 			}
1328 			xmlHashAddEntry2(style->cdataSection, element, URI,
1329 			    (void *) "cdata");
1330 			xmlFree(element);
1331 		    }
1332 		}
1333             }
1334             element = end;
1335         }
1336         xmlFree(elements);
1337     }
1338 
1339     prop = xmlGetNsProp(cur, (const xmlChar *) "media-type", NULL);
1340     if (prop != NULL) {
1341 	if (style->mediaType)
1342 	    xmlFree(style->mediaType);
1343 	style->mediaType = prop;
1344     }
1345     if (cur->children != NULL) {
1346 	xsltParseContentError(style, cur->children);
1347     }
1348 }
1349 
1350 /**
1351  * xsltParseStylesheetDecimalFormat:
1352  * @style:  the XSLT stylesheet
1353  * @cur:  the "decimal-format" element
1354  *
1355  * <!-- Category: top-level-element -->
1356  * <xsl:decimal-format
1357  *   name = qname, decimal-separator = char, grouping-separator = char,
1358  *   infinity = string, minus-sign = char, NaN = string, percent = char
1359  *   per-mille = char, zero-digit = char, digit = char,
1360  * pattern-separator = char />
1361  *
1362  * parse an XSLT stylesheet decimal-format element and
1363  * and record the formatting characteristics
1364  */
1365 static void
xsltParseStylesheetDecimalFormat(xsltStylesheetPtr style,xmlNodePtr cur)1366 xsltParseStylesheetDecimalFormat(xsltStylesheetPtr style, xmlNodePtr cur)
1367 {
1368     xmlChar *prop;
1369     xsltDecimalFormatPtr format;
1370     xsltDecimalFormatPtr iter;
1371 
1372     if ((cur == NULL) || (style == NULL))
1373 	return;
1374 
1375     format = style->decimalFormat;
1376 
1377     prop = xmlGetNsProp(cur, BAD_CAST("name"), NULL);
1378     if (prop != NULL) {
1379 	format = xsltDecimalFormatGetByName(style, prop);
1380 	if (format != NULL) {
1381 	    xsltTransformError(NULL, style, cur,
1382 	 "xsltParseStylestyleDecimalFormat: %s already exists\n", prop);
1383 	    if (style != NULL) style->warnings++;
1384 	    return;
1385 	}
1386 	format = xsltNewDecimalFormat(prop);
1387 	if (format == NULL) {
1388 	    xsltTransformError(NULL, style, cur,
1389      "xsltParseStylestyleDecimalFormat: failed creating new decimal-format\n");
1390 	    if (style != NULL) style->errors++;
1391 	    return;
1392 	}
1393 	/* Append new decimal-format structure */
1394 	for (iter = style->decimalFormat; iter->next; iter = iter->next)
1395 	    ;
1396 	if (iter)
1397 	    iter->next = format;
1398     }
1399 
1400     prop = xmlGetNsProp(cur, (const xmlChar *)"decimal-separator", NULL);
1401     if (prop != NULL) {
1402 	if (format->decimalPoint != NULL) xmlFree(format->decimalPoint);
1403 	format->decimalPoint  = prop;
1404     }
1405 
1406     prop = xmlGetNsProp(cur, (const xmlChar *)"grouping-separator", NULL);
1407     if (prop != NULL) {
1408 	if (format->grouping != NULL) xmlFree(format->grouping);
1409 	format->grouping  = prop;
1410     }
1411 
1412     prop = xmlGetNsProp(cur, (const xmlChar *)"infinity", NULL);
1413     if (prop != NULL) {
1414 	if (format->infinity != NULL) xmlFree(format->infinity);
1415 	format->infinity  = prop;
1416     }
1417 
1418     prop = xmlGetNsProp(cur, (const xmlChar *)"minus-sign", NULL);
1419     if (prop != NULL) {
1420 	if (format->minusSign != NULL) xmlFree(format->minusSign);
1421 	format->minusSign  = prop;
1422     }
1423 
1424     prop = xmlGetNsProp(cur, (const xmlChar *)"NaN", NULL);
1425     if (prop != NULL) {
1426 	if (format->noNumber != NULL) xmlFree(format->noNumber);
1427 	format->noNumber  = prop;
1428     }
1429 
1430     prop = xmlGetNsProp(cur, (const xmlChar *)"percent", NULL);
1431     if (prop != NULL) {
1432 	if (format->percent != NULL) xmlFree(format->percent);
1433 	format->percent  = prop;
1434     }
1435 
1436     prop = xmlGetNsProp(cur, (const xmlChar *)"per-mille", NULL);
1437     if (prop != NULL) {
1438 	if (format->permille != NULL) xmlFree(format->permille);
1439 	format->permille  = prop;
1440     }
1441 
1442     prop = xmlGetNsProp(cur, (const xmlChar *)"zero-digit", NULL);
1443     if (prop != NULL) {
1444 	if (format->zeroDigit != NULL) xmlFree(format->zeroDigit);
1445 	format->zeroDigit  = prop;
1446     }
1447 
1448     prop = xmlGetNsProp(cur, (const xmlChar *)"digit", NULL);
1449     if (prop != NULL) {
1450 	if (format->digit != NULL) xmlFree(format->digit);
1451 	format->digit  = prop;
1452     }
1453 
1454     prop = xmlGetNsProp(cur, (const xmlChar *)"pattern-separator", NULL);
1455     if (prop != NULL) {
1456 	if (format->patternSeparator != NULL) xmlFree(format->patternSeparator);
1457 	format->patternSeparator  = prop;
1458     }
1459     if (cur->children != NULL) {
1460 	xsltParseContentError(style, cur->children);
1461     }
1462 }
1463 
1464 /**
1465  * xsltParseStylesheetPreserveSpace:
1466  * @style:  the XSLT stylesheet
1467  * @cur:  the "preserve-space" element
1468  *
1469  * parse an XSLT stylesheet preserve-space element and record
1470  * elements needing preserving
1471  */
1472 
1473 static void
xsltParseStylesheetPreserveSpace(xsltStylesheetPtr style,xmlNodePtr cur)1474 xsltParseStylesheetPreserveSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
1475     xmlChar *elements;
1476     xmlChar *element, *end;
1477 
1478     if ((cur == NULL) || (style == NULL))
1479 	return;
1480 
1481     elements = xmlGetNsProp(cur, (const xmlChar *)"elements", NULL);
1482     if (elements == NULL) {
1483 	xsltTransformError(NULL, style, cur,
1484 	    "xsltParseStylesheetPreserveSpace: missing elements attribute\n");
1485 	if (style != NULL) style->warnings++;
1486 	return;
1487     }
1488 
1489     if (style->stripSpaces == NULL)
1490 	style->stripSpaces = xmlHashCreate(10);
1491     if (style->stripSpaces == NULL)
1492 	return;
1493 
1494     element = elements;
1495     while (*element != 0) {
1496 	while (IS_BLANK(*element)) element++;
1497 	if (*element == 0)
1498 	    break;
1499         end = element;
1500 	while ((*end != 0) && (!IS_BLANK(*end))) end++;
1501 	element = xmlStrndup(element, end - element);
1502 	if (element) {
1503 #ifdef WITH_XSLT_DEBUG_PARSING
1504 	    xsltGenericDebug(xsltGenericDebugContext,
1505 		"add preserved space element %s\n", element);
1506 #endif
1507 	    if (xmlStrEqual(element, (const xmlChar *)"*")) {
1508 		style->stripAll = -1;
1509 	    } else {
1510 		const xmlChar *URI;
1511 
1512 		/*
1513 		* TODO: Don't use xsltGetQNameURI().
1514 		*/
1515                 URI = xsltGetQNameURI(cur, &element);
1516 
1517 		xmlHashAddEntry2(style->stripSpaces, element, URI,
1518 				(xmlChar *) "preserve");
1519 	    }
1520 	    xmlFree(element);
1521 	}
1522 	element = end;
1523     }
1524     xmlFree(elements);
1525     if (cur->children != NULL) {
1526 	xsltParseContentError(style, cur->children);
1527     }
1528 }
1529 
1530 #ifdef XSLT_REFACTORED
1531 #else
1532 /**
1533  * xsltParseStylesheetExtPrefix:
1534  * @style:  the XSLT stylesheet
1535  * @template:  the "extension-element-prefixes" prefix
1536  *
1537  * parse an XSLT stylesheet's "extension-element-prefix" attribute value
1538  * and register the namespaces of extension instruction.
1539  * SPEC "A namespace is designated as an extension namespace by using
1540  *   an extension-element-prefixes attribute on:
1541  *   1) an xsl:stylesheet element
1542  *   2) an xsl:extension-element-prefixes attribute on a
1543  *      literal result element
1544  *   3) an extension instruction."
1545  */
1546 static void
xsltParseStylesheetExtPrefix(xsltStylesheetPtr style,xmlNodePtr cur,int isXsltElem)1547 xsltParseStylesheetExtPrefix(xsltStylesheetPtr style, xmlNodePtr cur,
1548 			     int isXsltElem) {
1549     xmlChar *prefixes;
1550     xmlChar *prefix, *end;
1551 
1552     if ((cur == NULL) || (style == NULL))
1553 	return;
1554 
1555     if (isXsltElem) {
1556 	/* For xsl:stylesheet/xsl:transform. */
1557 	prefixes = xmlGetNsProp(cur,
1558 	    (const xmlChar *)"extension-element-prefixes", NULL);
1559     } else {
1560 	/* For literal result elements and extension instructions. */
1561 	prefixes = xmlGetNsProp(cur,
1562 	    (const xmlChar *)"extension-element-prefixes", XSLT_NAMESPACE);
1563     }
1564     if (prefixes == NULL) {
1565 	return;
1566     }
1567 
1568     prefix = prefixes;
1569     while (*prefix != 0) {
1570 	while (IS_BLANK(*prefix)) prefix++;
1571 	if (*prefix == 0)
1572 	    break;
1573         end = prefix;
1574 	while ((*end != 0) && (!IS_BLANK(*end))) end++;
1575 	prefix = xmlStrndup(prefix, end - prefix);
1576 	if (prefix) {
1577 	    xmlNsPtr ns;
1578 
1579 	    if (xmlStrEqual(prefix, (const xmlChar *)"#default"))
1580 		ns = xmlSearchNs(style->doc, cur, NULL);
1581 	    else
1582 		ns = xmlSearchNs(style->doc, cur, prefix);
1583 	    if (ns == NULL) {
1584 		xsltTransformError(NULL, style, cur,
1585 	    "xsl:extension-element-prefix : undefined namespace %s\n",
1586 	                         prefix);
1587 		if (style != NULL) style->warnings++;
1588 	    } else {
1589 #ifdef WITH_XSLT_DEBUG_PARSING
1590 		xsltGenericDebug(xsltGenericDebugContext,
1591 		    "add extension prefix %s\n", prefix);
1592 #endif
1593 		xsltRegisterExtPrefix(style, prefix, ns->href);
1594 	    }
1595 	    xmlFree(prefix);
1596 	}
1597 	prefix = end;
1598     }
1599     xmlFree(prefixes);
1600 }
1601 #endif /* else of XSLT_REFACTORED */
1602 
1603 /**
1604  * xsltParseStylesheetStripSpace:
1605  * @style:  the XSLT stylesheet
1606  * @cur:  the "strip-space" element
1607  *
1608  * parse an XSLT stylesheet's strip-space element and record
1609  * the elements needing stripping
1610  */
1611 
1612 static void
xsltParseStylesheetStripSpace(xsltStylesheetPtr style,xmlNodePtr cur)1613 xsltParseStylesheetStripSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
1614     xmlChar *elements;
1615     xmlChar *element, *end;
1616 
1617     if ((cur == NULL) || (style == NULL))
1618 	return;
1619 
1620     elements = xmlGetNsProp(cur, (const xmlChar *)"elements", NULL);
1621     if (elements == NULL) {
1622 	xsltTransformError(NULL, style, cur,
1623 	    "xsltParseStylesheetStripSpace: missing elements attribute\n");
1624 	if (style != NULL) style->warnings++;
1625 	return;
1626     }
1627 
1628     if (style->stripSpaces == NULL)
1629 	style->stripSpaces = xmlHashCreate(10);
1630     if (style->stripSpaces == NULL)
1631 	return;
1632 
1633     element = elements;
1634     while (*element != 0) {
1635 	while (IS_BLANK(*element)) element++;
1636 	if (*element == 0)
1637 	    break;
1638         end = element;
1639 	while ((*end != 0) && (!IS_BLANK(*end))) end++;
1640 	element = xmlStrndup(element, end - element);
1641 	if (element) {
1642 #ifdef WITH_XSLT_DEBUG_PARSING
1643 	    xsltGenericDebug(xsltGenericDebugContext,
1644 		"add stripped space element %s\n", element);
1645 #endif
1646 	    if (xmlStrEqual(element, (const xmlChar *)"*")) {
1647 		style->stripAll = 1;
1648 	    } else {
1649 		const xmlChar *URI;
1650 
1651 		/*
1652 		* TODO: Don't use xsltGetQNameURI().
1653 		*/
1654                 URI = xsltGetQNameURI(cur, &element);
1655 
1656 		xmlHashAddEntry2(style->stripSpaces, element, URI,
1657 			        (xmlChar *) "strip");
1658 	    }
1659 	    xmlFree(element);
1660 	}
1661 	element = end;
1662     }
1663     xmlFree(elements);
1664     if (cur->children != NULL) {
1665 	xsltParseContentError(style, cur->children);
1666     }
1667 }
1668 
1669 #ifdef XSLT_REFACTORED
1670 #else
1671 /**
1672  * xsltParseStylesheetExcludePrefix:
1673  * @style:  the XSLT stylesheet
1674  * @cur:  the current point in the stylesheet
1675  *
1676  * parse an XSLT stylesheet exclude prefix and record
1677  * namespaces needing stripping
1678  *
1679  * Returns the number of Excluded prefixes added at that level
1680  */
1681 
1682 static int
xsltParseStylesheetExcludePrefix(xsltStylesheetPtr style,xmlNodePtr cur,int isXsltElem)1683 xsltParseStylesheetExcludePrefix(xsltStylesheetPtr style, xmlNodePtr cur,
1684 				 int isXsltElem)
1685 {
1686     int nb = 0;
1687     xmlChar *prefixes;
1688     xmlChar *prefix, *end;
1689 
1690     if ((cur == NULL) || (style == NULL))
1691 	return(0);
1692 
1693     if (isXsltElem)
1694 	prefixes = xmlGetNsProp(cur,
1695 	    (const xmlChar *)"exclude-result-prefixes", NULL);
1696     else
1697 	prefixes = xmlGetNsProp(cur,
1698 	    (const xmlChar *)"exclude-result-prefixes", XSLT_NAMESPACE);
1699 
1700     if (prefixes == NULL) {
1701 	return(0);
1702     }
1703 
1704     prefix = prefixes;
1705     while (*prefix != 0) {
1706 	while (IS_BLANK(*prefix)) prefix++;
1707 	if (*prefix == 0)
1708 	    break;
1709         end = prefix;
1710 	while ((*end != 0) && (!IS_BLANK(*end))) end++;
1711 	prefix = xmlStrndup(prefix, end - prefix);
1712 	if (prefix) {
1713 	    xmlNsPtr ns;
1714 
1715 	    if (xmlStrEqual(prefix, (const xmlChar *)"#default"))
1716 		ns = xmlSearchNs(style->doc, cur, NULL);
1717 	    else
1718 		ns = xmlSearchNs(style->doc, cur, prefix);
1719 	    if (ns == NULL) {
1720 		xsltTransformError(NULL, style, cur,
1721 	    "xsl:exclude-result-prefixes : undefined namespace %s\n",
1722 	                         prefix);
1723 		if (style != NULL) style->warnings++;
1724 	    } else {
1725 		if (exclPrefixPush(style, (xmlChar *) ns->href) >= 0) {
1726 #ifdef WITH_XSLT_DEBUG_PARSING
1727 		    xsltGenericDebug(xsltGenericDebugContext,
1728 			"exclude result prefix %s\n", prefix);
1729 #endif
1730 		    nb++;
1731 		}
1732 	    }
1733 	    xmlFree(prefix);
1734 	}
1735 	prefix = end;
1736     }
1737     xmlFree(prefixes);
1738     return(nb);
1739 }
1740 #endif /* else of XSLT_REFACTORED */
1741 
1742 #ifdef XSLT_REFACTORED
1743 
1744 /*
1745 * xsltTreeEnsureXMLDecl:
1746 * @doc: the doc
1747 *
1748 * BIG NOTE:
1749 *  This was copy&pasted from Libxml2's xmlTreeEnsureXMLDecl() in "tree.c".
1750 * Ensures that there is an XML namespace declaration on the doc.
1751 *
1752 * Returns the XML ns-struct or NULL on API and internal errors.
1753 */
1754 static xmlNsPtr
xsltTreeEnsureXMLDecl(xmlDocPtr doc)1755 xsltTreeEnsureXMLDecl(xmlDocPtr doc)
1756 {
1757     if (doc == NULL)
1758 	return (NULL);
1759     if (doc->oldNs != NULL)
1760 	return (doc->oldNs);
1761     {
1762 	xmlNsPtr ns;
1763 	ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1764 	if (ns == NULL) {
1765 	    xmlGenericError(xmlGenericErrorContext,
1766 		"xsltTreeEnsureXMLDecl: Failed to allocate "
1767 		"the XML namespace.\n");
1768 	    return (NULL);
1769 	}
1770 	memset(ns, 0, sizeof(xmlNs));
1771 	ns->type = XML_LOCAL_NAMESPACE;
1772 	/*
1773 	* URGENT TODO: revisit this.
1774 	*/
1775 #ifdef LIBXML_NAMESPACE_DICT
1776 	if (doc->dict)
1777 	    ns->href = xmlDictLookup(doc->dict, XML_XML_NAMESPACE, -1);
1778 	else
1779 	    ns->href = xmlStrdup(XML_XML_NAMESPACE);
1780 #else
1781 	ns->href = xmlStrdup(XML_XML_NAMESPACE);
1782 #endif
1783 	ns->prefix = xmlStrdup((const xmlChar *)"xml");
1784 	doc->oldNs = ns;
1785 	return (ns);
1786     }
1787 }
1788 
1789 /*
1790 * xsltTreeAcquireStoredNs:
1791 * @doc: the doc
1792 * @nsName: the namespace name
1793 * @prefix: the prefix
1794 *
1795 * BIG NOTE:
1796 *  This was copy&pasted from Libxml2's xmlDOMWrapStoreNs() in "tree.c".
1797 * Creates or reuses an xmlNs struct on doc->oldNs with
1798 * the given prefix and namespace name.
1799 *
1800 * Returns the aquired ns struct or NULL in case of an API
1801 *         or internal error.
1802 */
1803 static xmlNsPtr
xsltTreeAcquireStoredNs(xmlDocPtr doc,const xmlChar * nsName,const xmlChar * prefix)1804 xsltTreeAcquireStoredNs(xmlDocPtr doc,
1805 			const xmlChar *nsName,
1806 			const xmlChar *prefix)
1807 {
1808     xmlNsPtr ns;
1809 
1810     if (doc == NULL)
1811 	return (NULL);
1812     if (doc->oldNs != NULL)
1813 	ns = doc->oldNs;
1814     else
1815 	ns = xsltTreeEnsureXMLDecl(doc);
1816     if (ns == NULL)
1817 	return (NULL);
1818     if (ns->next != NULL) {
1819 	/* Reuse. */
1820 	ns = ns->next;
1821 	while (ns != NULL) {
1822 	    if ((ns->prefix == NULL) != (prefix == NULL)) {
1823 		/* NOP */
1824 	    } else if (prefix == NULL) {
1825 		if (xmlStrEqual(ns->href, nsName))
1826 		    return (ns);
1827 	    } else {
1828 		if ((ns->prefix[0] == prefix[0]) &&
1829 		     xmlStrEqual(ns->prefix, prefix) &&
1830 		     xmlStrEqual(ns->href, nsName))
1831 		    return (ns);
1832 
1833 	    }
1834 	    if (ns->next == NULL)
1835 		break;
1836 	    ns = ns->next;
1837 	}
1838     }
1839     /* Create. */
1840     ns->next = xmlNewNs(NULL, nsName, prefix);
1841     return (ns->next);
1842 }
1843 
1844 /**
1845  * xsltLREBuildEffectiveNs:
1846  *
1847  * Apply ns-aliasing on the namespace of the given @elem and
1848  * its attributes.
1849  */
1850 static int
xsltLREBuildEffectiveNs(xsltCompilerCtxtPtr cctxt,xmlNodePtr elem)1851 xsltLREBuildEffectiveNs(xsltCompilerCtxtPtr cctxt,
1852 			xmlNodePtr elem)
1853 {
1854     xmlNsPtr ns;
1855     xsltNsAliasPtr alias;
1856 
1857     if ((cctxt == NULL) || (elem == NULL))
1858 	return(-1);
1859     if ((cctxt->nsAliases == NULL) || (! cctxt->hasNsAliases))
1860 	return(0);
1861 
1862     alias = cctxt->nsAliases;
1863     while (alias != NULL) {
1864 	if ( /* If both namespaces are NULL... */
1865 	    ( (elem->ns == NULL) &&
1866 	    ((alias->literalNs == NULL) ||
1867 	    (alias->literalNs->href == NULL)) ) ||
1868 	    /* ... or both namespace are equal */
1869 	    ( (elem->ns != NULL) &&
1870 	    (alias->literalNs != NULL) &&
1871 	    xmlStrEqual(elem->ns->href, alias->literalNs->href) ) )
1872 	{
1873 	    if ((alias->targetNs != NULL) &&
1874 		(alias->targetNs->href != NULL))
1875 	    {
1876 		/*
1877 		* Convert namespace.
1878 		*/
1879 		if (elem->doc == alias->docOfTargetNs) {
1880 		    /*
1881 		    * This is the nice case: same docs.
1882 		    * This will eventually assign a ns-decl which
1883 		    * is shadowed, but this has no negative effect on
1884 		    * the generation of the result tree.
1885 		    */
1886 		    elem->ns = alias->targetNs;
1887 		} else {
1888 		    /*
1889 		    * This target xmlNs originates from a different
1890 		    * stylesheet tree. Try to locate it in the
1891 		    * in-scope namespaces.
1892 		    * OPTIMIZE TODO: Use the compiler-node-info inScopeNs.
1893 		    */
1894 		    ns = xmlSearchNs(elem->doc, elem,
1895 			alias->targetNs->prefix);
1896 		    /*
1897 		    * If no matching ns-decl found, then assign a
1898 		    * ns-decl stored in xmlDoc.
1899 		    */
1900 		    if ((ns == NULL) ||
1901 			(! xmlStrEqual(ns->href, alias->targetNs->href)))
1902 		    {
1903 			/*
1904 			* BIG NOTE: The use of xsltTreeAcquireStoredNs()
1905 			*  is not very efficient, but currently I don't
1906 			*  see an other way of *safely* changing a node's
1907 			*  namespace, since the xmlNs struct in
1908 			*  alias->targetNs might come from an other
1909 			*  stylesheet tree. So we need to anchor it in the
1910 			*  current document, without adding it to the tree,
1911 			*  which would otherwise change the in-scope-ns
1912 			*  semantic of the tree.
1913 			*/
1914 			ns = xsltTreeAcquireStoredNs(elem->doc,
1915 			    alias->targetNs->href,
1916 			    alias->targetNs->prefix);
1917 
1918 			if (ns == NULL) {
1919 			    xsltTransformError(NULL, cctxt->style, elem,
1920 				"Internal error in "
1921 				"xsltLREBuildEffectiveNs(): "
1922 				"failed to acquire a stored "
1923 				"ns-declaration.\n");
1924 			    cctxt->style->errors++;
1925 			    return(-1);
1926 
1927 			}
1928 		    }
1929 		    elem->ns = ns;
1930 		}
1931 	    } else {
1932 		/*
1933 		* Move into or leave in the NULL namespace.
1934 		*/
1935 		elem->ns = NULL;
1936 	    }
1937 	    break;
1938 	}
1939 	alias = alias->next;
1940     }
1941     /*
1942     * Same with attributes of literal result elements.
1943     */
1944     if (elem->properties != NULL) {
1945 	xmlAttrPtr attr = elem->properties;
1946 
1947 	while (attr != NULL) {
1948 	    if (attr->ns == NULL) {
1949 		attr = attr->next;
1950 		continue;
1951 	    }
1952 	    alias = cctxt->nsAliases;
1953 	    while (alias != NULL) {
1954 		if ( /* If both namespaces are NULL... */
1955 		    ( (elem->ns == NULL) &&
1956 		    ((alias->literalNs == NULL) ||
1957 		    (alias->literalNs->href == NULL)) ) ||
1958 		    /* ... or both namespace are equal */
1959 		    ( (elem->ns != NULL) &&
1960 		    (alias->literalNs != NULL) &&
1961 		    xmlStrEqual(elem->ns->href, alias->literalNs->href) ) )
1962 		{
1963 		    if ((alias->targetNs != NULL) &&
1964 			(alias->targetNs->href != NULL))
1965 		    {
1966 			if (elem->doc == alias->docOfTargetNs) {
1967 			    elem->ns = alias->targetNs;
1968 			} else {
1969 			    ns = xmlSearchNs(elem->doc, elem,
1970 				alias->targetNs->prefix);
1971 			    if ((ns == NULL) ||
1972 				(! xmlStrEqual(ns->href, alias->targetNs->href)))
1973 			    {
1974 				ns = xsltTreeAcquireStoredNs(elem->doc,
1975 				    alias->targetNs->href,
1976 				    alias->targetNs->prefix);
1977 
1978 				if (ns == NULL) {
1979 				    xsltTransformError(NULL, cctxt->style, elem,
1980 					"Internal error in "
1981 					"xsltLREBuildEffectiveNs(): "
1982 					"failed to acquire a stored "
1983 					"ns-declaration.\n");
1984 				    cctxt->style->errors++;
1985 				    return(-1);
1986 
1987 				}
1988 			    }
1989 			    elem->ns = ns;
1990 			}
1991 		    } else {
1992 		    /*
1993 		    * Move into or leave in the NULL namespace.
1994 			*/
1995 			elem->ns = NULL;
1996 		    }
1997 		    break;
1998 		}
1999 		alias = alias->next;
2000 	    }
2001 
2002 	    attr = attr->next;
2003 	}
2004     }
2005     return(0);
2006 }
2007 
2008 /**
2009  * xsltLREBuildEffectiveNsNodes:
2010  *
2011  * Computes the effective namespaces nodes for a literal result
2012  * element.
2013  * @effectiveNs is the set of effective ns-nodes
2014  *  on the literal result element, which will be added to the result
2015  *  element if not already existing in the result tree.
2016  *  This means that excluded namespaces (via exclude-result-prefixes,
2017  *  extension-element-prefixes and the XSLT namespace) not added
2018  *  to the set.
2019  *  Namespace-aliasing was applied on the @effectiveNs.
2020  */
2021 static int
xsltLREBuildEffectiveNsNodes(xsltCompilerCtxtPtr cctxt,xsltStyleItemLRElementInfoPtr item,xmlNodePtr elem,int isLRE)2022 xsltLREBuildEffectiveNsNodes(xsltCompilerCtxtPtr cctxt,
2023 			     xsltStyleItemLRElementInfoPtr item,
2024 			     xmlNodePtr elem,
2025 			     int isLRE)
2026 {
2027     xmlNsPtr ns, tmpns;
2028     xsltEffectiveNsPtr effNs, lastEffNs = NULL;
2029     int i, j, holdByElem;
2030     xsltPointerListPtr extElemNs = cctxt->inode->extElemNs;
2031     xsltPointerListPtr exclResultNs = cctxt->inode->exclResultNs;
2032 
2033     if ((cctxt == NULL) || (cctxt->inode == NULL) || (elem == NULL) ||
2034 	(item == NULL) || (item->effectiveNs != NULL))
2035 	return(-1);
2036 
2037     if (item->inScopeNs == NULL)
2038 	return(0);
2039 
2040     extElemNs = cctxt->inode->extElemNs;
2041     exclResultNs = cctxt->inode->exclResultNs;
2042 
2043     for (i = 0; i < item->inScopeNs->totalNumber; i++) {
2044 	ns = item->inScopeNs->list[i];
2045 	/*
2046 	* Skip namespaces designated as excluded namespaces
2047 	* -------------------------------------------------
2048 	*
2049 	* XSLT-20 TODO: In XSLT 2.0 we need to keep namespaces
2050 	*  which are target namespaces of namespace-aliases
2051 	*  regardless if designated as excluded.
2052 	*
2053 	* Exclude the XSLT namespace.
2054 	*/
2055 	if (xmlStrEqual(ns->href, XSLT_NAMESPACE))
2056 	    goto skip_ns;
2057 
2058 	/*
2059 	* Apply namespace aliasing
2060 	* ------------------------
2061 	*
2062 	* SPEC XSLT 2.0
2063 	*  "- A namespace node whose string value is a literal namespace
2064 	*     URI is not copied to the result tree.
2065 	*   - A namespace node whose string value is a target namespace URI
2066 	*     is copied to the result tree, whether or not the URI
2067 	*     identifies an excluded namespace."
2068 	*
2069 	* NOTE: The ns-aliasing machanism is non-cascading.
2070 	*  (checked with Saxon, Xalan and MSXML .NET).
2071 	* URGENT TODO: is style->nsAliases the effective list of
2072 	*  ns-aliases, or do we need to lookup the whole
2073 	*  import-tree?
2074 	* TODO: Get rid of import-tree lookup.
2075 	*/
2076 	if (cctxt->hasNsAliases) {
2077 	    xsltNsAliasPtr alias;
2078 	    /*
2079 	    * First check for being a target namespace.
2080 	    */
2081 	    alias = cctxt->nsAliases;
2082 	    do {
2083 		/*
2084 		* TODO: Is xmlns="" handled already?
2085 		*/
2086 		if ((alias->targetNs != NULL) &&
2087 		    (xmlStrEqual(alias->targetNs->href, ns->href)))
2088 		{
2089 		    /*
2090 		    * Recognized as a target namespace; use it regardless
2091 		    * if excluded otherwise.
2092 		    */
2093 		    goto add_effective_ns;
2094 		}
2095 		alias = alias->next;
2096 	    } while (alias != NULL);
2097 
2098 	    alias = cctxt->nsAliases;
2099 	    do {
2100 		/*
2101 		* TODO: Is xmlns="" handled already?
2102 		*/
2103 		if ((alias->literalNs != NULL) &&
2104 		    (xmlStrEqual(alias->literalNs->href, ns->href)))
2105 		{
2106 		    /*
2107 		    * Recognized as an namespace alias; do not use it.
2108 		    */
2109 		    goto skip_ns;
2110 		}
2111 		alias = alias->next;
2112 	    } while (alias != NULL);
2113 	}
2114 
2115 	/*
2116 	* Exclude excluded result namespaces.
2117 	*/
2118 	if (exclResultNs) {
2119 	    for (j = 0; j < exclResultNs->number; j++)
2120 		if (xmlStrEqual(ns->href, BAD_CAST exclResultNs->items[j]))
2121 		    goto skip_ns;
2122 	}
2123 	/*
2124 	* Exclude extension-element namespaces.
2125 	*/
2126 	if (extElemNs) {
2127 	    for (j = 0; j < extElemNs->number; j++)
2128 		if (xmlStrEqual(ns->href, BAD_CAST extElemNs->items[j]))
2129 		    goto skip_ns;
2130 	}
2131 
2132 add_effective_ns:
2133 	/*
2134 	* OPTIMIZE TODO: This information may not be needed.
2135 	*/
2136 	if (isLRE && (elem->nsDef != NULL)) {
2137 	    holdByElem = 0;
2138 	    tmpns = elem->nsDef;
2139 	    do {
2140 		if (tmpns == ns) {
2141 		    holdByElem = 1;
2142 		    break;
2143 		}
2144 		tmpns = tmpns->next;
2145 	    } while (tmpns != NULL);
2146 	} else
2147 	    holdByElem = 0;
2148 
2149 
2150 	/*
2151 	* Add the effective namespace declaration.
2152 	*/
2153 	effNs = (xsltEffectiveNsPtr) xmlMalloc(sizeof(xsltEffectiveNs));
2154 	if (effNs == NULL) {
2155 	    xsltTransformError(NULL, cctxt->style, elem,
2156 		"Internal error in xsltLREBuildEffectiveNs(): "
2157 		"failed to allocate memory.\n");
2158 	    cctxt->style->errors++;
2159 	    return(-1);
2160 	}
2161 	if (cctxt->psData->effectiveNs == NULL) {
2162 	    cctxt->psData->effectiveNs = effNs;
2163 	    effNs->nextInStore = NULL;
2164 	} else {
2165 	    effNs->nextInStore = cctxt->psData->effectiveNs;
2166 	    cctxt->psData->effectiveNs = effNs;
2167 	}
2168 
2169 	effNs->next = NULL;
2170 	effNs->prefix = ns->prefix;
2171 	effNs->nsName = ns->href;
2172 	effNs->holdByElem = holdByElem;
2173 
2174 	if (lastEffNs == NULL)
2175 	    item->effectiveNs = effNs;
2176 	else
2177 	    lastEffNs->next = effNs;
2178 	lastEffNs = effNs;
2179 
2180 skip_ns:
2181 	{}
2182     }
2183     return(0);
2184 }
2185 
2186 
2187 /**
2188  * xsltLREInfoCreate:
2189  *
2190  * @isLRE: indicates if the given @elem is a literal result element
2191  *
2192  * Creates a new info for a literal result element.
2193  */
2194 static int
xsltLREInfoCreate(xsltCompilerCtxtPtr cctxt,xmlNodePtr elem,int isLRE)2195 xsltLREInfoCreate(xsltCompilerCtxtPtr cctxt,
2196 		  xmlNodePtr elem,
2197 		  int isLRE)
2198 {
2199     xsltStyleItemLRElementInfoPtr item;
2200 
2201     if ((cctxt == NULL) || (cctxt->inode == NULL))
2202 	return(-1);
2203 
2204     item = (xsltStyleItemLRElementInfoPtr)
2205 	xmlMalloc(sizeof(xsltStyleItemLRElementInfo));
2206     if (item == NULL) {
2207 	xsltTransformError(NULL, cctxt->style, NULL,
2208 	    "Internal error in xsltLREInfoCreate(): "
2209 	    "memory allocation failed.\n");
2210 	cctxt->style->errors++;
2211 	return(-1);
2212     }
2213     memset(item, 0, sizeof(xsltStyleItemLRElementInfo));
2214     item->type = XSLT_FUNC_LITERAL_RESULT_ELEMENT;
2215     /*
2216     * Store it in the stylesheet.
2217     */
2218     item->next = cctxt->style->preComps;
2219     cctxt->style->preComps = (xsltElemPreCompPtr) item;
2220     /*
2221     * @inScopeNs are used for execution of XPath expressions
2222     *  in AVTs.
2223     */
2224     item->inScopeNs = cctxt->inode->inScopeNs;
2225 
2226     if (elem)
2227 	xsltLREBuildEffectiveNsNodes(cctxt, item, elem, isLRE);
2228 
2229     cctxt->inode->litResElemInfo = item;
2230     cctxt->inode->nsChanged = 0;
2231     cctxt->maxLREs++;
2232     return(0);
2233 }
2234 
2235 /**
2236  * xsltCompilerVarInfoPush:
2237  * @cctxt: the compilation context
2238  *
2239  * Pushes a new var/param info onto the stack.
2240  *
2241  * Returns the acquired variable info.
2242  */
2243 static xsltVarInfoPtr
xsltCompilerVarInfoPush(xsltCompilerCtxtPtr cctxt,xmlNodePtr inst,const xmlChar * name,const xmlChar * nsName)2244 xsltCompilerVarInfoPush(xsltCompilerCtxtPtr cctxt,
2245 				  xmlNodePtr inst,
2246 				  const xmlChar *name,
2247 				  const xmlChar *nsName)
2248 {
2249     xsltVarInfoPtr ivar;
2250 
2251     if ((cctxt->ivar != NULL) && (cctxt->ivar->next != NULL)) {
2252 	ivar = cctxt->ivar->next;
2253     } else if ((cctxt->ivar == NULL) && (cctxt->ivars != NULL)) {
2254 	ivar = cctxt->ivars;
2255     } else {
2256 	ivar = (xsltVarInfoPtr) xmlMalloc(sizeof(xsltVarInfo));
2257 	if (ivar == NULL) {
2258 	    xsltTransformError(NULL, cctxt->style, inst,
2259 		"xsltParseInScopeVarPush: xmlMalloc() failed!\n");
2260 	    cctxt->style->errors++;
2261 	    return(NULL);
2262 	}
2263 	/* memset(retVar, 0, sizeof(xsltInScopeVar)); */
2264 	if (cctxt->ivars == NULL) {
2265 	    cctxt->ivars = ivar;
2266 	    ivar->prev = NULL;
2267 	} else {
2268 	    cctxt->ivar->next = ivar;
2269 	    ivar->prev = cctxt->ivar;
2270 	}
2271 	cctxt->ivar = ivar;
2272 	ivar->next = NULL;
2273     }
2274     ivar->depth = cctxt->depth;
2275     ivar->name = name;
2276     ivar->nsName = nsName;
2277     return(ivar);
2278 }
2279 
2280 /**
2281  * xsltCompilerVarInfoPop:
2282  * @cctxt: the compilation context
2283  *
2284  * Pops all var/param infos from the stack, which
2285  * have the current depth.
2286  */
2287 static void
xsltCompilerVarInfoPop(xsltCompilerCtxtPtr cctxt)2288 xsltCompilerVarInfoPop(xsltCompilerCtxtPtr cctxt)
2289 {
2290 
2291     while ((cctxt->ivar != NULL) &&
2292 	(cctxt->ivar->depth > cctxt->depth))
2293     {
2294 	cctxt->ivar = cctxt->ivar->prev;
2295     }
2296 }
2297 
2298 /*
2299 * xsltCompilerNodePush:
2300 *
2301 * @cctxt: the compilation context
2302 * @node: the node to be pushed (this can also be the doc-node)
2303 *
2304 *
2305 *
2306 * Returns the current node info structure or
2307 *         NULL in case of an internal error.
2308 */
2309 static xsltCompilerNodeInfoPtr
xsltCompilerNodePush(xsltCompilerCtxtPtr cctxt,xmlNodePtr node)2310 xsltCompilerNodePush(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
2311 {
2312     xsltCompilerNodeInfoPtr inode, iprev;
2313 
2314     if ((cctxt->inode != NULL) && (cctxt->inode->next != NULL)) {
2315 	inode = cctxt->inode->next;
2316     } else if ((cctxt->inode == NULL) && (cctxt->inodeList != NULL)) {
2317 	inode = cctxt->inodeList;
2318     } else {
2319 	/*
2320 	* Create a new node-info.
2321 	*/
2322 	inode = (xsltCompilerNodeInfoPtr)
2323 	    xmlMalloc(sizeof(xsltCompilerNodeInfo));
2324 	if (inode == NULL) {
2325 	    xsltTransformError(NULL, cctxt->style, NULL,
2326 		"xsltCompilerNodePush: malloc failed.\n");
2327 	    return(NULL);
2328 	}
2329 	memset(inode, 0, sizeof(xsltCompilerNodeInfo));
2330 	if (cctxt->inodeList == NULL)
2331 	    cctxt->inodeList = inode;
2332 	else {
2333 	    cctxt->inodeLast->next = inode;
2334 	    inode->prev = cctxt->inodeLast;
2335 	}
2336 	cctxt->inodeLast = inode;
2337 	cctxt->maxNodeInfos++;
2338 	if (cctxt->inode == NULL) {
2339 	    cctxt->inode = inode;
2340 	    /*
2341 	    * Create an initial literal result element info for
2342 	    * the root of the stylesheet.
2343 	    */
2344 	    xsltLREInfoCreate(cctxt, NULL, 0);
2345 	}
2346     }
2347     cctxt->depth++;
2348     cctxt->inode = inode;
2349     /*
2350     * REVISIT TODO: Keep the reset always complete.
2351     * NOTE: Be carefull with the @node, since it might be
2352     *  a doc-node.
2353     */
2354     inode->node = node;
2355     inode->depth = cctxt->depth;
2356     inode->templ = NULL;
2357     inode->category = XSLT_ELEMENT_CATEGORY_XSLT;
2358     inode->type = 0;
2359     inode->item = NULL;
2360     inode->curChildType = 0;
2361     inode->extContentHandled = 0;
2362     inode->isRoot = 0;
2363 
2364     if (inode->prev != NULL) {
2365 	iprev = inode->prev;
2366 	/*
2367 	* Inherit the following information:
2368 	* ---------------------------------
2369 	*
2370 	* In-scope namespaces
2371 	*/
2372 	inode->inScopeNs = iprev->inScopeNs;
2373 	/*
2374 	* Info for literal result elements
2375 	*/
2376 	inode->litResElemInfo = iprev->litResElemInfo;
2377 	inode->nsChanged = iprev->nsChanged;
2378 	/*
2379 	* Excluded result namespaces
2380 	*/
2381 	inode->exclResultNs = iprev->exclResultNs;
2382 	/*
2383 	* Extension instruction namespaces
2384 	*/
2385 	inode->extElemNs = iprev->extElemNs;
2386 	/*
2387 	* Whitespace preservation
2388 	*/
2389 	inode->preserveWhitespace = iprev->preserveWhitespace;
2390 	/*
2391 	* Forwards-compatible mode
2392 	*/
2393 	inode->forwardsCompat = iprev->forwardsCompat;
2394     } else {
2395 	inode->inScopeNs = NULL;
2396 	inode->exclResultNs = NULL;
2397 	inode->extElemNs = NULL;
2398 	inode->preserveWhitespace = 0;
2399 	inode->forwardsCompat = 0;
2400     }
2401 
2402     return(inode);
2403 }
2404 
2405 /*
2406 * xsltCompilerNodePop:
2407 *
2408 * @cctxt: the compilation context
2409 * @node: the node to be pushed (this can also be the doc-node)
2410 *
2411 * Pops the current node info.
2412 */
2413 static void
xsltCompilerNodePop(xsltCompilerCtxtPtr cctxt,xmlNodePtr node)2414 xsltCompilerNodePop(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
2415 {
2416     if (cctxt->inode == NULL) {
2417 	xmlGenericError(xmlGenericErrorContext,
2418 	    "xsltCompilerNodePop: Top-node mismatch.\n");
2419 	return;
2420     }
2421     /*
2422     * NOTE: Be carefull with the @node, since it might be
2423     *  a doc-node.
2424     */
2425     if (cctxt->inode->node != node) {
2426 	xmlGenericError(xmlGenericErrorContext,
2427 	"xsltCompilerNodePop: Node mismatch.\n");
2428 	goto mismatch;
2429     }
2430     if (cctxt->inode->depth != cctxt->depth) {
2431 	xmlGenericError(xmlGenericErrorContext,
2432 	"xsltCompilerNodePop: Depth mismatch.\n");
2433 	goto mismatch;
2434     }
2435     /*
2436     * Pop information of variables.
2437     */
2438     if ((cctxt->ivar) && (cctxt->ivar->depth > cctxt->depth))
2439 	xsltCompilerVarInfoPop(cctxt);
2440 
2441     cctxt->depth--;
2442     cctxt->inode = cctxt->inode->prev;
2443     if (cctxt->inode != NULL)
2444 	cctxt->inode->curChildType = 0;
2445     return;
2446 
2447 mismatch:
2448     {
2449 	const xmlChar *nsName = NULL, *name = NULL;
2450 	const xmlChar *infnsName = NULL, *infname = NULL;
2451 
2452 	if (node) {
2453 	    if (node->type == XML_ELEMENT_NODE) {
2454 		name = node->name;
2455 		if (node->ns != NULL)
2456 		    nsName = node->ns->href;
2457 		else
2458 		    nsName = BAD_CAST "";
2459 	    } else {
2460 		name = BAD_CAST "#document";
2461 		nsName = BAD_CAST "";
2462 	    }
2463 	} else
2464 	    name = BAD_CAST "Not given";
2465 
2466 	if (cctxt->inode->node) {
2467 	    if (node->type == XML_ELEMENT_NODE) {
2468 		infname = cctxt->inode->node->name;
2469 		if (cctxt->inode->node->ns != NULL)
2470 		    infnsName = cctxt->inode->node->ns->href;
2471 		else
2472 		    infnsName = BAD_CAST "";
2473 	    } else {
2474 		infname = BAD_CAST "#document";
2475 		infnsName = BAD_CAST "";
2476 	    }
2477 	} else
2478 	    infname = BAD_CAST "Not given";
2479 
2480 
2481 	xmlGenericError(xmlGenericErrorContext,
2482 	    "xsltCompilerNodePop: Given   : '%s' URI '%s'\n",
2483 	    name, nsName);
2484 	xmlGenericError(xmlGenericErrorContext,
2485 	    "xsltCompilerNodePop: Expected: '%s' URI '%s'\n",
2486 	    infname, infnsName);
2487     }
2488 }
2489 
2490 /*
2491 * xsltCompilerBuildInScopeNsList:
2492 *
2493 * Create and store the list of in-scope namespaces for the given
2494 * node in the stylesheet. If there are no changes in the in-scope
2495 * namespaces then the last ns-info of the ancestor axis will be returned.
2496 * Compilation-time only.
2497 *
2498 * Returns the ns-info or NULL if there are no namespaces in scope.
2499 */
2500 static xsltNsListContainerPtr
xsltCompilerBuildInScopeNsList(xsltCompilerCtxtPtr cctxt,xmlNodePtr node)2501 xsltCompilerBuildInScopeNsList(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
2502 {
2503     xsltNsListContainerPtr nsi = NULL;
2504     xmlNsPtr *list = NULL, ns;
2505     int i, maxns = 5;
2506     /*
2507     * Create a new ns-list for this position in the node-tree.
2508     * xmlGetNsList() will return NULL, if there are no ns-decls in the
2509     * tree. Note that the ns-decl for the XML namespace is not added
2510     * to the resulting list; the XPath module handles the XML namespace
2511     * internally.
2512     */
2513     while (node != NULL) {
2514         if (node->type == XML_ELEMENT_NODE) {
2515             ns = node->nsDef;
2516             while (ns != NULL) {
2517                 if (nsi == NULL) {
2518 		    nsi = (xsltNsListContainerPtr)
2519 			xmlMalloc(sizeof(xsltNsListContainer));
2520 		    if (nsi == NULL) {
2521 			xsltTransformError(NULL, cctxt->style, NULL,
2522 			    "xsltCompilerBuildInScopeNsList: "
2523 			    "malloc failed!\n");
2524 			goto internal_err;
2525 		    }
2526 		    memset(nsi, 0, sizeof(xsltNsListContainer));
2527                     nsi->list =
2528                         (xmlNsPtr *) xmlMalloc(maxns * sizeof(xmlNsPtr));
2529                     if (nsi->list == NULL) {
2530 			xsltTransformError(NULL, cctxt->style, NULL,
2531 			    "xsltCompilerBuildInScopeNsList: "
2532 			    "malloc failed!\n");
2533 			goto internal_err;
2534                     }
2535                     nsi->list[0] = NULL;
2536                 }
2537 		/*
2538 		* Skip shadowed namespace bindings.
2539 		*/
2540                 for (i = 0; i < nsi->totalNumber; i++) {
2541                     if ((ns->prefix == nsi->list[i]->prefix) ||
2542                         (xmlStrEqual(ns->prefix, nsi->list[i]->prefix)))
2543 		    break;
2544                 }
2545                 if (i >= nsi->totalNumber) {
2546                     if (nsi->totalNumber +1 >= maxns) {
2547                         maxns *= 2;
2548 			nsi->list =
2549 			    (xmlNsPtr *) xmlRealloc(nsi->list,
2550 				maxns * sizeof(xmlNsPtr));
2551                         if (nsi->list == NULL) {
2552                             xsltTransformError(NULL, cctxt->style, NULL,
2553 				"xsltCompilerBuildInScopeNsList: "
2554 				"realloc failed!\n");
2555 				goto internal_err;
2556                         }
2557                     }
2558                     nsi->list[nsi->totalNumber++] = ns;
2559                     nsi->list[nsi->totalNumber] = NULL;
2560                 }
2561 
2562                 ns = ns->next;
2563             }
2564         }
2565         node = node->parent;
2566     }
2567     if (nsi == NULL)
2568 	return(NULL);
2569     /*
2570     * Move the default namespace to last position.
2571     */
2572     nsi->xpathNumber = nsi->totalNumber;
2573     for (i = 0; i < nsi->totalNumber; i++) {
2574 	if (nsi->list[i]->prefix == NULL) {
2575 	    ns = nsi->list[i];
2576 	    nsi->list[i] = nsi->list[nsi->totalNumber-1];
2577 	    nsi->list[nsi->totalNumber-1] = ns;
2578 	    nsi->xpathNumber--;
2579 	    break;
2580 	}
2581     }
2582     /*
2583     * Store the ns-list in the stylesheet.
2584     */
2585     if (xsltPointerListAddSize(
2586 	(xsltPointerListPtr)cctxt->psData->inScopeNamespaces,
2587 	(void *) nsi, 5) == -1)
2588     {
2589 	xmlFree(nsi);
2590 	nsi = NULL;
2591 	xsltTransformError(NULL, cctxt->style, NULL,
2592 	    "xsltCompilerBuildInScopeNsList: failed to add ns-info.\n");
2593 	goto internal_err;
2594     }
2595     /*
2596     * Notify of change in status wrt namespaces.
2597     */
2598     if (cctxt->inode != NULL)
2599 	cctxt->inode->nsChanged = 1;
2600 
2601     return(nsi);
2602 
2603 internal_err:
2604     if (list != NULL)
2605 	xmlFree(list);
2606     cctxt->style->errors++;
2607     return(NULL);
2608 }
2609 
2610 static int
xsltParseNsPrefixList(xsltCompilerCtxtPtr cctxt,xsltPointerListPtr list,xmlNodePtr node,const xmlChar * value)2611 xsltParseNsPrefixList(xsltCompilerCtxtPtr cctxt,
2612 		      xsltPointerListPtr list,
2613 		      xmlNodePtr node,
2614 		      const xmlChar *value)
2615 {
2616     xmlChar *cur, *end;
2617     xmlNsPtr ns;
2618 
2619     if ((cctxt == NULL) || (value == NULL) || (list == NULL))
2620 	return(-1);
2621 
2622     list->number = 0;
2623 
2624     cur = (xmlChar *) value;
2625     while (*cur != 0) {
2626 	while (IS_BLANK(*cur)) cur++;
2627 	if (*cur == 0)
2628 	    break;
2629 	end = cur;
2630 	while ((*end != 0) && (!IS_BLANK(*end))) end++;
2631 	cur = xmlStrndup(cur, end - cur);
2632 	if (cur == NULL) {
2633 	    cur = end;
2634 	    continue;
2635 	}
2636 	/*
2637 	* TODO: Export and use xmlSearchNsByPrefixStrict()
2638 	*   in Libxml2, tree.c, since xmlSearchNs() is in most
2639 	*   cases not efficient and in some cases not correct.
2640 	*
2641 	* XSLT-2 TODO: XSLT 2.0 allows an additional "#all" value.
2642 	*/
2643 	if ((cur[0] == '#') &&
2644 	    xmlStrEqual(cur, (const xmlChar *)"#default"))
2645 	    ns = xmlSearchNs(cctxt->style->doc, node, NULL);
2646 	else
2647 	    ns = xmlSearchNs(cctxt->style->doc, node, cur);
2648 
2649 	if (ns == NULL) {
2650 	    /*
2651 	    * TODO: Better to report the attr-node, otherwise
2652 	    *  the user won't know which attribute was invalid.
2653 	    */
2654 	    xsltTransformError(NULL, cctxt->style, node,
2655 		"No namespace binding in scope for prefix '%s'.\n", cur);
2656 	    /*
2657 	    * XSLT-1.0: "It is an error if there is no namespace
2658 	    *  bound to the prefix on the element bearing the
2659 	    *  exclude-result-prefixes or xsl:exclude-result-prefixes
2660 	    *  attribute."
2661 	    */
2662 	    cctxt->style->errors++;
2663 	} else {
2664 #ifdef WITH_XSLT_DEBUG_PARSING
2665 	    xsltGenericDebug(xsltGenericDebugContext,
2666 		"resolved prefix '%s'\n", cur);
2667 #endif
2668 	    /*
2669 	    * Note that we put the namespace name into the dict.
2670 	    */
2671 	    if (xsltPointerListAddSize(list,
2672 		(void *) xmlDictLookup(cctxt->style->dict,
2673 		ns->href, -1), 5) == -1)
2674 	    {
2675 		xmlFree(cur);
2676 		goto internal_err;
2677 	    }
2678 	}
2679 	xmlFree(cur);
2680 
2681 	cur = end;
2682     }
2683     return(0);
2684 
2685 internal_err:
2686     cctxt->style->errors++;
2687     return(-1);
2688 }
2689 
2690 /**
2691  * xsltCompilerUtilsCreateMergedList:
2692  * @dest: the destination list (optional)
2693  * @first: the first list
2694  * @second: the second list (optional)
2695  *
2696  * Appends the content of @second to @first into @destination.
2697  * If @destination is NULL a new list will be created.
2698  *
2699  * Returns the merged list of items or NULL if there's nothing to merge.
2700  */
2701 static xsltPointerListPtr
xsltCompilerUtilsCreateMergedList(xsltPointerListPtr first,xsltPointerListPtr second)2702 xsltCompilerUtilsCreateMergedList(xsltPointerListPtr first,
2703 			    xsltPointerListPtr second)
2704 {
2705     xsltPointerListPtr ret;
2706     size_t num;
2707 
2708     if (first)
2709 	num = first->number;
2710     else
2711 	num = 0;
2712     if (second)
2713 	num += second->number;
2714     if (num == 0)
2715 	return(NULL);
2716     ret = xsltPointerListCreate(num);
2717     if (ret == NULL)
2718 	return(NULL);
2719     /*
2720     * Copy contents.
2721     */
2722     if ((first != NULL) &&  (first->number != 0)) {
2723 	memcpy(ret->items, first->items,
2724 	    first->number * sizeof(void *));
2725 	if ((second != NULL) && (second->number != 0))
2726 	    memcpy(ret->items + first->number, second->items,
2727 		second->number * sizeof(void *));
2728     } else if ((second != NULL) && (second->number != 0))
2729 	memcpy(ret->items, (void *) second->items,
2730 	    second->number * sizeof(void *));
2731     ret->number = num;
2732     return(ret);
2733 }
2734 
2735 /*
2736 * xsltParseExclResultPrefixes:
2737 *
2738 * Create and store the list of in-scope namespaces for the given
2739 * node in the stylesheet. If there are no changes in the in-scope
2740 * namespaces then the last ns-info of the ancestor axis will be returned.
2741 * Compilation-time only.
2742 *
2743 * Returns the ns-info or NULL if there are no namespaces in scope.
2744 */
2745 static xsltPointerListPtr
xsltParseExclResultPrefixes(xsltCompilerCtxtPtr cctxt,xmlNodePtr node,xsltPointerListPtr def,int instrCategory)2746 xsltParseExclResultPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
2747 			    xsltPointerListPtr def,
2748 			    int instrCategory)
2749 {
2750     xsltPointerListPtr list = NULL;
2751     xmlChar *value;
2752     xmlAttrPtr attr;
2753 
2754     if ((cctxt == NULL) || (node == NULL))
2755 	return(NULL);
2756 
2757     if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
2758 	attr = xmlHasNsProp(node, BAD_CAST "exclude-result-prefixes", NULL);
2759     else
2760 	attr = xmlHasNsProp(node, BAD_CAST "exclude-result-prefixes",
2761 	    XSLT_NAMESPACE);
2762     if (attr == NULL)
2763 	return(def);
2764 
2765     if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
2766 	/*
2767 	* Mark the XSLT attr.
2768 	*/
2769 	attr->psvi = (void *) xsltXSLTAttrMarker;
2770     }
2771 
2772     if ((attr->children != NULL) &&
2773 	(attr->children->content != NULL))
2774 	value = attr->children->content;
2775     else {
2776 	xsltTransformError(NULL, cctxt->style, node,
2777 	    "Attribute 'exclude-result-prefixes': Invalid value.\n");
2778 	cctxt->style->errors++;
2779 	return(def);
2780     }
2781 
2782     if (xsltParseNsPrefixList(cctxt, cctxt->tmpList, node,
2783 	BAD_CAST value) != 0)
2784 	goto exit;
2785     if (cctxt->tmpList->number == 0)
2786 	goto exit;
2787     /*
2788     * Merge the list with the inherited list.
2789     */
2790     list = xsltCompilerUtilsCreateMergedList(def, cctxt->tmpList);
2791     if (list == NULL)
2792 	goto exit;
2793     /*
2794     * Store the list in the stylesheet/compiler context.
2795     */
2796     if (xsltPointerListAddSize(
2797 	cctxt->psData->exclResultNamespaces, list, 5) == -1)
2798     {
2799 	xsltPointerListFree(list);
2800 	list = NULL;
2801 	goto exit;
2802     }
2803     /*
2804     * Notify of change in status wrt namespaces.
2805     */
2806     if (cctxt->inode != NULL)
2807 	cctxt->inode->nsChanged = 1;
2808 
2809 exit:
2810     if (list != NULL)
2811 	return(list);
2812     else
2813 	return(def);
2814 }
2815 
2816 /*
2817 * xsltParseExtElemPrefixes:
2818 *
2819 * Create and store the list of in-scope namespaces for the given
2820 * node in the stylesheet. If there are no changes in the in-scope
2821 * namespaces then the last ns-info of the ancestor axis will be returned.
2822 * Compilation-time only.
2823 *
2824 * Returns the ns-info or NULL if there are no namespaces in scope.
2825 */
2826 static xsltPointerListPtr
xsltParseExtElemPrefixes(xsltCompilerCtxtPtr cctxt,xmlNodePtr node,xsltPointerListPtr def,int instrCategory)2827 xsltParseExtElemPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
2828 			 xsltPointerListPtr def,
2829 			 int instrCategory)
2830 {
2831     xsltPointerListPtr list = NULL;
2832     xmlAttrPtr attr;
2833     xmlChar *value;
2834     int i;
2835 
2836     if ((cctxt == NULL) || (node == NULL))
2837 	return(NULL);
2838 
2839     if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
2840 	attr = xmlHasNsProp(node, BAD_CAST "extension-element-prefixes", NULL);
2841     else
2842 	attr = xmlHasNsProp(node, BAD_CAST "extension-element-prefixes",
2843 	    XSLT_NAMESPACE);
2844     if (attr == NULL)
2845 	return(def);
2846 
2847     if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
2848 	/*
2849 	* Mark the XSLT attr.
2850 	*/
2851 	attr->psvi = (void *) xsltXSLTAttrMarker;
2852     }
2853 
2854     if ((attr->children != NULL) &&
2855 	(attr->children->content != NULL))
2856 	value = attr->children->content;
2857     else {
2858 	xsltTransformError(NULL, cctxt->style, node,
2859 	    "Attribute 'extension-element-prefixes': Invalid value.\n");
2860 	cctxt->style->errors++;
2861 	return(def);
2862     }
2863 
2864 
2865     if (xsltParseNsPrefixList(cctxt, cctxt->tmpList, node,
2866 	BAD_CAST value) != 0)
2867 	goto exit;
2868 
2869     if (cctxt->tmpList->number == 0)
2870 	goto exit;
2871     /*
2872     * REVISIT: Register the extension namespaces.
2873     */
2874     for (i = 0; i < cctxt->tmpList->number; i++)
2875 	xsltRegisterExtPrefix(cctxt->style, NULL,
2876 	BAD_CAST cctxt->tmpList->items[i]);
2877     /*
2878     * Merge the list with the inherited list.
2879     */
2880     list = xsltCompilerUtilsCreateMergedList(def, cctxt->tmpList);
2881     if (list == NULL)
2882 	goto exit;
2883     /*
2884     * Store the list in the stylesheet.
2885     */
2886     if (xsltPointerListAddSize(
2887 	cctxt->psData->extElemNamespaces, list, 5) == -1)
2888     {
2889 	xsltPointerListFree(list);
2890 	list = NULL;
2891 	goto exit;
2892     }
2893     /*
2894     * Notify of change in status wrt namespaces.
2895     */
2896     if (cctxt->inode != NULL)
2897 	cctxt->inode->nsChanged = 1;
2898 
2899 exit:
2900     if (list != NULL)
2901 	return(list);
2902     else
2903 	return(def);
2904 }
2905 
2906 /*
2907 * xsltParseAttrXSLTVersion:
2908 *
2909 * @cctxt: the compilation context
2910 * @node: the element-node
2911 * @isXsltElem: whether this is an XSLT element
2912 *
2913 * Parses the attribute xsl:version.
2914 *
2915 * Returns 1 if there was such an attribute, 0 if not and
2916 *         -1 if an internal or API error occured.
2917 */
2918 static int
xsltParseAttrXSLTVersion(xsltCompilerCtxtPtr cctxt,xmlNodePtr node,int instrCategory)2919 xsltParseAttrXSLTVersion(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
2920 			 int instrCategory)
2921 {
2922     xmlChar *value;
2923     xmlAttrPtr attr;
2924 
2925     if ((cctxt == NULL) || (node == NULL))
2926 	return(-1);
2927 
2928     if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
2929 	attr = xmlHasNsProp(node, BAD_CAST "version", NULL);
2930     else
2931 	attr = xmlHasNsProp(node, BAD_CAST "version", XSLT_NAMESPACE);
2932 
2933     if (attr == NULL)
2934 	return(0);
2935 
2936     attr->psvi = (void *) xsltXSLTAttrMarker;
2937 
2938     if ((attr->children != NULL) &&
2939 	(attr->children->content != NULL))
2940 	value = attr->children->content;
2941     else {
2942 	xsltTransformError(NULL, cctxt->style, node,
2943 	    "Attribute 'version': Invalid value.\n");
2944 	cctxt->style->errors++;
2945 	return(1);
2946     }
2947 
2948     if (! xmlStrEqual(value, (const xmlChar *)"1.0")) {
2949 	cctxt->inode->forwardsCompat = 1;
2950 	/*
2951 	* TODO: To what extent do we support the
2952 	*  forwards-compatible mode?
2953 	*/
2954 	/*
2955 	* Report this only once per compilation episode.
2956 	*/
2957 	if (! cctxt->hasForwardsCompat) {
2958 	    cctxt->hasForwardsCompat = 1;
2959 	    cctxt->errSeverity = XSLT_ERROR_SEVERITY_WARNING;
2960 	    xsltTransformError(NULL, cctxt->style, node,
2961 		"Warning: the attribute xsl:version specifies a value "
2962 		"different from '1.0'. Switching to forwards-compatible "
2963 		"mode. Only features of XSLT 1.0 are supported by this "
2964 		"processor.\n");
2965 	    cctxt->style->warnings++;
2966 	    cctxt->errSeverity = XSLT_ERROR_SEVERITY_ERROR;
2967 	}
2968     } else {
2969 	cctxt->inode->forwardsCompat = 0;
2970     }
2971 
2972     if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
2973 	/*
2974 	* Set a marker on XSLT attributes.
2975 	*/
2976 	attr->psvi = (void *) xsltXSLTAttrMarker;
2977     }
2978     return(1);
2979 }
2980 
2981 static int
xsltParsePreprocessStylesheetTree(xsltCompilerCtxtPtr cctxt,xmlNodePtr node)2982 xsltParsePreprocessStylesheetTree(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
2983 {
2984     xmlNodePtr deleteNode, cur, txt, textNode = NULL;
2985     xmlDocPtr doc;
2986     xsltStylesheetPtr style;
2987     int internalize = 0, findSpaceAttr;
2988     int xsltStylesheetElemDepth;
2989     xmlAttrPtr attr;
2990     xmlChar *value;
2991     const xmlChar *name, *nsNameXSLT = NULL;
2992     int strictWhitespace, inXSLText = 0;
2993 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
2994     xsltNsMapPtr nsMapItem;
2995 #endif
2996 
2997     if ((cctxt == NULL) || (cctxt->style == NULL) ||
2998 	(node == NULL) || (node->type != XML_ELEMENT_NODE))
2999         return(-1);
3000 
3001     doc = node->doc;
3002     if (doc == NULL)
3003 	goto internal_err;
3004 
3005     style = cctxt->style;
3006     if ((style->dict != NULL) && (doc->dict == style->dict))
3007 	internalize = 1;
3008     else
3009         style->internalized = 0;
3010 
3011     /*
3012     * Init value of xml:space. Since this might be an embedded
3013     * stylesheet, this is needed to be performed on the element
3014     * where the stylesheet is rooted at, taking xml:space of
3015     * ancestors into account.
3016     */
3017     if (! cctxt->simplified)
3018 	xsltStylesheetElemDepth = cctxt->depth +1;
3019     else
3020 	xsltStylesheetElemDepth = 0;
3021 
3022     if (xmlNodeGetSpacePreserve(node) != 1)
3023 	cctxt->inode->preserveWhitespace = 0;
3024     else
3025 	cctxt->inode->preserveWhitespace = 1;
3026 
3027     /*
3028     * Eval if we should keep the old incorrect behaviour.
3029     */
3030     strictWhitespace = (cctxt->strict != 0) ? 1 : 0;
3031 
3032     nsNameXSLT = xsltConstNamespaceNameXSLT;
3033 
3034     deleteNode = NULL;
3035     cur = node;
3036     while (cur != NULL) {
3037 	if (deleteNode != NULL)	{
3038 
3039 #ifdef WITH_XSLT_DEBUG_BLANKS
3040 	    xsltGenericDebug(xsltGenericDebugContext,
3041 	     "xsltParsePreprocessStylesheetTree: removing node\n");
3042 #endif
3043 	    xmlUnlinkNode(deleteNode);
3044 	    xmlFreeNode(deleteNode);
3045 	    deleteNode = NULL;
3046 	}
3047 	if (cur->type == XML_ELEMENT_NODE) {
3048 
3049 	    /*
3050 	    * Clear the PSVI field.
3051 	    */
3052 	    cur->psvi = NULL;
3053 
3054 	    xsltCompilerNodePush(cctxt, cur);
3055 
3056 	    inXSLText = 0;
3057 	    textNode = NULL;
3058 	    findSpaceAttr = 1;
3059 	    cctxt->inode->stripWhitespace = 0;
3060 	    /*
3061 	    * TODO: I'd love to use a string pointer comparison here :-/
3062 	    */
3063 	    if (IS_XSLT_ELEM(cur)) {
3064 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
3065 		if (cur->ns->href != nsNameXSLT) {
3066 		    nsMapItem = xsltNewNamespaceMapItem(cctxt,
3067 			doc, cur->ns, cur);
3068 		    if (nsMapItem == NULL)
3069 			goto internal_err;
3070 		    cur->ns->href = nsNameXSLT;
3071 		}
3072 #endif
3073 
3074 		if (cur->name == NULL)
3075 		    goto process_attributes;
3076 		/*
3077 		* Mark the XSLT element for later recognition.
3078 		* TODO: Using the marker is still too dangerous, since if
3079 		*   the parsing mechanism leaves out an XSLT element, then
3080 		*   this might hit the transformation-mechanism, which
3081 		*   will break if it doesn't expect such a marker.
3082 		*/
3083 		/* cur->psvi = (void *) xsltXSLTElemMarker; */
3084 
3085 		/*
3086 		* XSLT 2.0: "Any whitespace text node whose parent is
3087 		* one of the following elements is removed from the "
3088 		* tree, regardless of any xml:space attributes:..."
3089 		* xsl:apply-imports,
3090 		* xsl:apply-templates,
3091 		* xsl:attribute-set,
3092 		* xsl:call-template,
3093 		* xsl:choose,
3094 		* xsl:stylesheet, xsl:transform.
3095 		* XSLT 2.0: xsl:analyze-string,
3096 		*           xsl:character-map,
3097 		*           xsl:next-match
3098 		*
3099 		* TODO: I'd love to use a string pointer comparison here :-/
3100 		*/
3101 		name = cur->name;
3102 		switch (*name) {
3103 		    case 't':
3104 			if ((name[0] == 't') && (name[1] == 'e') &&
3105 			    (name[2] == 'x') && (name[3] == 't') &&
3106 			    (name[4] == 0))
3107 			{
3108 			    /*
3109 			    * Process the xsl:text element.
3110 			    * ----------------------------
3111 			    * Mark it for later recognition.
3112 			    */
3113 			    cur->psvi = (void *) xsltXSLTTextMarker;
3114 			    /*
3115 			    * For stylesheets, the set of
3116 			    * whitespace-preserving element names
3117 			    * consists of just xsl:text.
3118 			    */
3119 			    findSpaceAttr = 0;
3120 			    cctxt->inode->preserveWhitespace = 1;
3121 			    inXSLText = 1;
3122 			}
3123 			break;
3124 		    case 'c':
3125 			if (xmlStrEqual(name, BAD_CAST "choose") ||
3126 			    xmlStrEqual(name, BAD_CAST "call-template"))
3127 			    cctxt->inode->stripWhitespace = 1;
3128 			break;
3129 		    case 'a':
3130 			if (xmlStrEqual(name, BAD_CAST "apply-templates") ||
3131 			    xmlStrEqual(name, BAD_CAST "apply-imports") ||
3132 			    xmlStrEqual(name, BAD_CAST "attribute-set"))
3133 
3134 			    cctxt->inode->stripWhitespace = 1;
3135 			break;
3136 		    default:
3137 			if (xsltStylesheetElemDepth == cctxt->depth) {
3138 			    /*
3139 			    * This is a xsl:stylesheet/xsl:transform.
3140 			    */
3141 			    cctxt->inode->stripWhitespace = 1;
3142 			    break;
3143 			}
3144 
3145 			if ((cur->prev != NULL) &&
3146 			    (cur->prev->type == XML_TEXT_NODE))
3147 			{
3148 			    /*
3149 			    * XSLT 2.0 : "Any whitespace text node whose
3150 			    *  following-sibling node is an xsl:param or
3151 			    *  xsl:sort element is removed from the tree,
3152 			    *  regardless of any xml:space attributes."
3153 			    */
3154 			    if (((*name == 'p') || (*name == 's')) &&
3155 				(xmlStrEqual(name, BAD_CAST "param") ||
3156 				 xmlStrEqual(name, BAD_CAST "sort")))
3157 			    {
3158 				do {
3159 				    if (IS_BLANK_NODE(cur->prev)) {
3160 					txt = cur->prev;
3161 					xmlUnlinkNode(txt);
3162 					xmlFreeNode(txt);
3163 				    } else {
3164 					/*
3165 					* This will result in a content
3166 					* error, when hitting the parsing
3167 					* functions.
3168 					*/
3169 					break;
3170 				    }
3171 				} while (cur->prev);
3172 			    }
3173 			}
3174 			break;
3175 		}
3176 	    }
3177 
3178 process_attributes:
3179 	    /*
3180 	    * Process attributes.
3181 	    * ------------------
3182 	    */
3183 	    if (cur->properties != NULL) {
3184 		if (cur->children == NULL)
3185 		    findSpaceAttr = 0;
3186 		attr = cur->properties;
3187 		do {
3188 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
3189 		    if ((attr->ns) && (attr->ns->href != nsNameXSLT) &&
3190 			xmlStrEqual(attr->ns->href, nsNameXSLT))
3191 		    {
3192 			nsMapItem = xsltNewNamespaceMapItem(cctxt,
3193 			    doc, attr->ns, cur);
3194 			if (nsMapItem == NULL)
3195 			    goto internal_err;
3196 			attr->ns->href = nsNameXSLT;
3197 		    }
3198 #endif
3199 		    if (internalize) {
3200 			/*
3201 			* Internalize the attribute's value; the goal is to
3202 			* speed up operations and minimize used space by
3203 			* compiled stylesheets.
3204 			*/
3205 			txt = attr->children;
3206 			/*
3207 			* NOTE that this assumes only one
3208 			*  text-node in the attribute's content.
3209 			*/
3210 			if ((txt != NULL) && (txt->content != NULL) &&
3211 			    (!xmlDictOwns(style->dict, txt->content)))
3212 			{
3213 			    value = (xmlChar *) xmlDictLookup(style->dict,
3214 				txt->content, -1);
3215 			    xmlNodeSetContent(txt, NULL);
3216 			    txt->content = value;
3217 			}
3218 		    }
3219 		    /*
3220 		    * Process xml:space attributes.
3221 		    * ----------------------------
3222 		    */
3223 		    if ((findSpaceAttr != 0) &&
3224 			(attr->ns != NULL) &&
3225 			(attr->name != NULL) &&
3226 			(attr->name[0] == 's') &&
3227 			(attr->ns->prefix != NULL) &&
3228 			(attr->ns->prefix[0] == 'x') &&
3229 			(attr->ns->prefix[1] == 'm') &&
3230 			(attr->ns->prefix[2] == 'l') &&
3231 			(attr->ns->prefix[3] == 0))
3232 		    {
3233 			value = xmlGetNsProp(cur, BAD_CAST "space",
3234 			    XML_XML_NAMESPACE);
3235 			if (value != NULL) {
3236 			    if (xmlStrEqual(value, BAD_CAST "preserve")) {
3237 				cctxt->inode->preserveWhitespace = 1;
3238 			    } else if (xmlStrEqual(value, BAD_CAST "default")) {
3239 				cctxt->inode->preserveWhitespace = 0;
3240 			    } else {
3241 				/* Invalid value for xml:space. */
3242 				xsltTransformError(NULL, style, cur,
3243 				    "Attribute xml:space: Invalid value.\n");
3244 				cctxt->style->warnings++;
3245 			    }
3246 			    findSpaceAttr = 0;
3247 			    xmlFree(value);
3248 			}
3249 
3250 		    }
3251 		    attr = attr->next;
3252 		} while (attr != NULL);
3253 	    }
3254 	    /*
3255 	    * We'll descend into the children of element nodes only.
3256 	    */
3257 	    if (cur->children != NULL) {
3258 		cur = cur->children;
3259 		continue;
3260 	    }
3261 	} else if ((cur->type == XML_TEXT_NODE) ||
3262 		(cur->type == XML_CDATA_SECTION_NODE))
3263 	{
3264 	    /*
3265 	    * Merge adjacent text/CDATA-section-nodes
3266 	    * ---------------------------------------
3267 	    * In order to avoid breaking of existing stylesheets,
3268 	    * if the old behaviour is wanted (strictWhitespace == 0),
3269 	    * then we *won't* merge adjacent text-nodes
3270 	    * (except in xsl:text); this will ensure that whitespace-only
3271 	    * text nodes are (incorrectly) not stripped in some cases.
3272 	    *
3273 	    * Example:               : <foo>  <!-- bar -->zoo</foo>
3274 	    * Corrent (strict) result: <foo>  zoo</foo>
3275 	    * Incorrect (old) result : <foo>zoo</foo>
3276 	    *
3277 	    * NOTE that we *will* merge adjacent text-nodes if
3278 	    * they are in xsl:text.
3279 	    * Example, the following:
3280 	    * <xsl:text>  <!-- bar -->zoo<xsl:text>
3281 	    * will result in both cases in:
3282 	    * <xsl:text>  zoo<xsl:text>
3283 	    */
3284 	    cur->type = XML_TEXT_NODE;
3285 	    if ((strictWhitespace != 0) || (inXSLText != 0)) {
3286 		/*
3287 		* New behaviour; merge nodes.
3288 		*/
3289 		if (textNode == NULL)
3290 		    textNode = cur;
3291 		else {
3292 		    if (cur->content != NULL)
3293 			xmlNodeAddContent(textNode, cur->content);
3294 		    deleteNode = cur;
3295 		}
3296 		if ((cur->next == NULL) ||
3297 		    (cur->next->type == XML_ELEMENT_NODE))
3298 		    goto end_of_text;
3299 		else
3300 		    goto next_sibling;
3301 	    } else {
3302 		/*
3303 		* Old behaviour.
3304 		*/
3305 		if (textNode == NULL)
3306 		    textNode = cur;
3307 		goto end_of_text;
3308 	    }
3309 	} else if ((cur->type == XML_COMMENT_NODE) ||
3310 	    (cur->type == XML_PI_NODE))
3311 	{
3312 	    /*
3313 	    * Remove processing instructions and comments.
3314 	    */
3315 	    deleteNode = cur;
3316 	    if ((cur->next == NULL) ||
3317 		(cur->next->type == XML_ELEMENT_NODE))
3318 		goto end_of_text;
3319 	    else
3320 		goto next_sibling;
3321 	} else {
3322 	    textNode = NULL;
3323 	    /*
3324 	    * Invalid node-type for this data-model.
3325 	    */
3326 	    xsltTransformError(NULL, style, cur,
3327 		"Invalid type of node for the XSLT data model.\n");
3328 	    cctxt->style->errors++;
3329 	    goto next_sibling;
3330 	}
3331 
3332 end_of_text:
3333 	if (textNode) {
3334 	    value = textNode->content;
3335 	    /*
3336 	    * At this point all adjacent text/CDATA-section nodes
3337 	    * have been merged.
3338 	    *
3339 	    * Strip whitespace-only text-nodes.
3340 	    * (cctxt->inode->stripWhitespace)
3341 	    */
3342 	    if ((value == NULL) || (*value == 0) ||
3343 		(((cctxt->inode->stripWhitespace) ||
3344 		  (! cctxt->inode->preserveWhitespace)) &&
3345 		 IS_BLANK(*value) &&
3346 		 xsltIsBlank(value)))
3347 	    {
3348 		if (textNode != cur) {
3349 		    xmlUnlinkNode(textNode);
3350 		    xmlFreeNode(textNode);
3351 		} else
3352 		    deleteNode = textNode;
3353 		textNode = NULL;
3354 		goto next_sibling;
3355 	    }
3356 	    /*
3357 	    * Convert CDATA-section nodes to text-nodes.
3358 	    * TODO: Can this produce problems?
3359 	    */
3360 	    if (textNode->type != XML_TEXT_NODE) {
3361 		textNode->type = XML_TEXT_NODE;
3362 		textNode->name = xmlStringText;
3363 	    }
3364 	    if (internalize &&
3365 		(textNode->content != NULL) &&
3366 		(!xmlDictOwns(style->dict, textNode->content)))
3367 	    {
3368 		/*
3369 		* Internalize the string.
3370 		*/
3371 		value = (xmlChar *) xmlDictLookup(style->dict,
3372 		    textNode->content, -1);
3373 		xmlNodeSetContent(textNode, NULL);
3374 		textNode->content = value;
3375 	    }
3376 	    textNode = NULL;
3377 	    /*
3378 	    * Note that "disable-output-escaping" of the xsl:text
3379 	    * element will be applied at a later level, when
3380 	    * XSLT elements are processed.
3381 	    */
3382 	}
3383 
3384 next_sibling:
3385 	if (cur->type == XML_ELEMENT_NODE) {
3386 	    xsltCompilerNodePop(cctxt, cur);
3387 	}
3388 	if (cur == node)
3389 	    break;
3390 	if (cur->next != NULL) {
3391 	    cur = cur->next;
3392 	} else {
3393 	    cur = cur->parent;
3394 	    inXSLText = 0;
3395 	    goto next_sibling;
3396 	};
3397     }
3398     if (deleteNode != NULL) {
3399 #ifdef WITH_XSLT_DEBUG_PARSING
3400 	xsltGenericDebug(xsltGenericDebugContext,
3401 	 "xsltParsePreprocessStylesheetTree: removing node\n");
3402 #endif
3403 	xmlUnlinkNode(deleteNode);
3404 	xmlFreeNode(deleteNode);
3405     }
3406     return(0);
3407 
3408 internal_err:
3409     return(-1);
3410 }
3411 
3412 #endif /* XSLT_REFACTORED */
3413 
3414 #ifdef XSLT_REFACTORED
3415 #else
3416 static void
xsltPrecomputeStylesheet(xsltStylesheetPtr style,xmlNodePtr cur)3417 xsltPrecomputeStylesheet(xsltStylesheetPtr style, xmlNodePtr cur)
3418 {
3419     xmlNodePtr deleteNode, styleelem;
3420     int internalize = 0;
3421 
3422     if ((style == NULL) || (cur == NULL))
3423         return;
3424 
3425     if ((cur->doc != NULL) && (style->dict != NULL) &&
3426         (cur->doc->dict == style->dict))
3427 	internalize = 1;
3428     else
3429         style->internalized = 0;
3430 
3431     if ((cur != NULL) && (IS_XSLT_ELEM(cur)) &&
3432         (IS_XSLT_NAME(cur, "stylesheet"))) {
3433 	styleelem = cur;
3434     } else {
3435         styleelem = NULL;
3436     }
3437 
3438     /*
3439      * This content comes from the stylesheet
3440      * For stylesheets, the set of whitespace-preserving
3441      * element names consists of just xsl:text.
3442      */
3443     deleteNode = NULL;
3444     while (cur != NULL) {
3445 	if (deleteNode != NULL) {
3446 #ifdef WITH_XSLT_DEBUG_BLANKS
3447 	    xsltGenericDebug(xsltGenericDebugContext,
3448 	     "xsltPrecomputeStylesheet: removing ignorable blank node\n");
3449 #endif
3450 	    xmlUnlinkNode(deleteNode);
3451 	    xmlFreeNode(deleteNode);
3452 	    deleteNode = NULL;
3453 	}
3454 	if (cur->type == XML_ELEMENT_NODE) {
3455 	    int exclPrefixes;
3456 	    /*
3457 	     * Internalize attributes values.
3458 	     */
3459 	    if ((internalize) && (cur->properties != NULL)) {
3460 	        xmlAttrPtr attr = cur->properties;
3461 		xmlNodePtr txt;
3462 
3463 		while (attr != NULL) {
3464 		    txt = attr->children;
3465 		    if ((txt != NULL) && (txt->type == XML_TEXT_NODE) &&
3466 		        (txt->content != NULL) &&
3467 			(!xmlDictOwns(style->dict, txt->content)))
3468 		    {
3469 			xmlChar *tmp;
3470 
3471 			/*
3472 			 * internalize the text string, goal is to speed
3473 			 * up operations and minimize used space by compiled
3474 			 * stylesheets.
3475 			 */
3476 			tmp = (xmlChar *) xmlDictLookup(style->dict,
3477 			                                txt->content, -1);
3478 			if (tmp != txt->content) {
3479 			    xmlNodeSetContent(txt, NULL);
3480 			    txt->content = tmp;
3481 			}
3482 		    }
3483 		    attr = attr->next;
3484 		}
3485 	    }
3486 	    if (IS_XSLT_ELEM(cur)) {
3487 		exclPrefixes = 0;
3488 		xsltStylePreCompute(style, cur);
3489 		if (IS_XSLT_NAME(cur, "text")) {
3490 		    for (;exclPrefixes > 0;exclPrefixes--)
3491 			exclPrefixPop(style);
3492 		    goto skip_children;
3493 		}
3494 	    } else {
3495 		exclPrefixes = xsltParseStylesheetExcludePrefix(style, cur, 0);
3496 	    }
3497 
3498 	    if ((cur->nsDef != NULL) && (style->exclPrefixNr > 0)) {
3499 		xmlNsPtr ns = cur->nsDef, prev = NULL, next;
3500 		xmlNodePtr root = NULL;
3501 		int i, moved;
3502 
3503 		root = xmlDocGetRootElement(cur->doc);
3504 		if ((root != NULL) && (root != cur)) {
3505 		    while (ns != NULL) {
3506 			moved = 0;
3507 			next = ns->next;
3508 			for (i = 0;i < style->exclPrefixNr;i++) {
3509 			    if ((ns->prefix != NULL) &&
3510 			        (xmlStrEqual(ns->href,
3511 					     style->exclPrefixTab[i]))) {
3512 				/*
3513 				 * Move the namespace definition on the root
3514 				 * element to avoid duplicating it without
3515 				 * loosing it.
3516 				 */
3517 				if (prev == NULL) {
3518 				    cur->nsDef = ns->next;
3519 				} else {
3520 				    prev->next = ns->next;
3521 				}
3522 				ns->next = root->nsDef;
3523 				root->nsDef = ns;
3524 				moved = 1;
3525 				break;
3526 			    }
3527 			}
3528 			if (moved == 0)
3529 			    prev = ns;
3530 			ns = next;
3531 		    }
3532 		}
3533 	    }
3534 	    /*
3535 	     * If we have prefixes locally, recurse and pop them up when
3536 	     * going back
3537 	     */
3538 	    if (exclPrefixes > 0) {
3539 		xsltPrecomputeStylesheet(style, cur->children);
3540 		for (;exclPrefixes > 0;exclPrefixes--)
3541 		    exclPrefixPop(style);
3542 		goto skip_children;
3543 	    }
3544 	} else if (cur->type == XML_TEXT_NODE) {
3545 	    if (IS_BLANK_NODE(cur)) {
3546 		if (xmlNodeGetSpacePreserve(cur) != 1) {
3547 		    deleteNode = cur;
3548 		}
3549 	    } else if ((cur->content != NULL) && (internalize) &&
3550 	               (!xmlDictOwns(style->dict, cur->content))) {
3551 		xmlChar *tmp;
3552 
3553 		/*
3554 		 * internalize the text string, goal is to speed
3555 		 * up operations and minimize used space by compiled
3556 		 * stylesheets.
3557 		 */
3558 		tmp = (xmlChar *) xmlDictLookup(style->dict, cur->content, -1);
3559 		xmlNodeSetContent(cur, NULL);
3560 		cur->content = tmp;
3561 	    }
3562 	} else if ((cur->type != XML_ELEMENT_NODE) &&
3563 		   (cur->type != XML_CDATA_SECTION_NODE)) {
3564 	    deleteNode = cur;
3565 	    goto skip_children;
3566 	}
3567 
3568 	/*
3569 	 * Skip to next node. In case of a namespaced element children of
3570 	 * the stylesheet and not in the XSLT namespace and not an extension
3571 	 * element, ignore its content.
3572 	 */
3573 	if ((cur->type == XML_ELEMENT_NODE) && (cur->ns != NULL) &&
3574 	    (styleelem != NULL) && (cur->parent == styleelem) &&
3575 	    (!xmlStrEqual(cur->ns->href, XSLT_NAMESPACE)) &&
3576 	    (!xsltCheckExtURI(style, cur->ns->href))) {
3577 	    goto skip_children;
3578 	} else if (cur->children != NULL) {
3579 	    if ((cur->children->type != XML_ENTITY_DECL) &&
3580 		(cur->children->type != XML_ENTITY_REF_NODE) &&
3581 		(cur->children->type != XML_ENTITY_NODE)) {
3582 		cur = cur->children;
3583 		continue;
3584 	    }
3585 	}
3586 
3587 skip_children:
3588 	if (cur->next != NULL) {
3589 	    cur = cur->next;
3590 	    continue;
3591 	}
3592 	do {
3593 
3594 	    cur = cur->parent;
3595 	    if (cur == NULL)
3596 		break;
3597 	    if (cur == (xmlNodePtr) style->doc) {
3598 		cur = NULL;
3599 		break;
3600 	    }
3601 	    if (cur->next != NULL) {
3602 		cur = cur->next;
3603 		break;
3604 	    }
3605 	} while (cur != NULL);
3606     }
3607     if (deleteNode != NULL) {
3608 #ifdef WITH_XSLT_DEBUG_PARSING
3609 	xsltGenericDebug(xsltGenericDebugContext,
3610 	 "xsltPrecomputeStylesheet: removing ignorable blank node\n");
3611 #endif
3612 	xmlUnlinkNode(deleteNode);
3613 	xmlFreeNode(deleteNode);
3614     }
3615 }
3616 #endif /* end of else XSLT_REFACTORED */
3617 
3618 /**
3619  * xsltGatherNamespaces:
3620  * @style:  the XSLT stylesheet
3621  *
3622  * Browse the stylesheet and build the namspace hash table which
3623  * will be used for XPath interpretation. If needed do a bit of normalization
3624  */
3625 
3626 static void
xsltGatherNamespaces(xsltStylesheetPtr style)3627 xsltGatherNamespaces(xsltStylesheetPtr style) {
3628     xmlNodePtr cur;
3629     const xmlChar *URI;
3630 
3631     if (style == NULL)
3632         return;
3633     /*
3634      * TODO: basically if the stylesheet uses the same prefix for different
3635      *       patterns, well they may be in problem, hopefully they will get
3636      *       a warning first.
3637      */
3638     /*
3639     * TODO: Eliminate the use of the hash for XPath expressions.
3640     *   An expression should be evaluated in the context of the in-scope
3641     *   namespaces; eliminate the restriction of an XML document to contain
3642     *   no duplicate prefixes for different namespace names.
3643     *
3644     */
3645     cur = xmlDocGetRootElement(style->doc);
3646     while (cur != NULL) {
3647 	if (cur->type == XML_ELEMENT_NODE) {
3648 	    xmlNsPtr ns = cur->nsDef;
3649 	    while (ns != NULL) {
3650 		if (ns->prefix != NULL) {
3651 		    if (style->nsHash == NULL) {
3652 			style->nsHash = xmlHashCreate(10);
3653 			if (style->nsHash == NULL) {
3654 			    xsltTransformError(NULL, style, cur,
3655 		 "xsltGatherNamespaces: failed to create hash table\n");
3656 			    style->errors++;
3657 			    return;
3658 			}
3659 		    }
3660 		    URI = xmlHashLookup(style->nsHash, ns->prefix);
3661 		    if ((URI != NULL) && (!xmlStrEqual(URI, ns->href))) {
3662 			xsltTransformError(NULL, style, cur,
3663 	     "Namespaces prefix %s used for multiple namespaces\n",ns->prefix);
3664 			style->warnings++;
3665 		    } else if (URI == NULL) {
3666 			xmlHashUpdateEntry(style->nsHash, ns->prefix,
3667 			    (void *) ns->href, (xmlHashDeallocator)xmlFree);
3668 
3669 #ifdef WITH_XSLT_DEBUG_PARSING
3670 			xsltGenericDebug(xsltGenericDebugContext,
3671 		 "Added namespace: %s mapped to %s\n", ns->prefix, ns->href);
3672 #endif
3673 		    }
3674 		}
3675 		ns = ns->next;
3676 	    }
3677 	}
3678 
3679 	/*
3680 	 * Skip to next node
3681 	 */
3682 	if (cur->children != NULL) {
3683 	    if (cur->children->type != XML_ENTITY_DECL) {
3684 		cur = cur->children;
3685 		continue;
3686 	    }
3687 	}
3688 	if (cur->next != NULL) {
3689 	    cur = cur->next;
3690 	    continue;
3691 	}
3692 
3693 	do {
3694 	    cur = cur->parent;
3695 	    if (cur == NULL)
3696 		break;
3697 	    if (cur == (xmlNodePtr) style->doc) {
3698 		cur = NULL;
3699 		break;
3700 	    }
3701 	    if (cur->next != NULL) {
3702 		cur = cur->next;
3703 		break;
3704 	    }
3705 	} while (cur != NULL);
3706     }
3707 }
3708 
3709 #ifdef XSLT_REFACTORED
3710 
3711 static xsltStyleType
xsltGetXSLTElementTypeByNode(xsltCompilerCtxtPtr cctxt,xmlNodePtr node)3712 xsltGetXSLTElementTypeByNode(xsltCompilerCtxtPtr cctxt,
3713 			     xmlNodePtr node)
3714 {
3715     if ((node == NULL) || (node->type != XML_ELEMENT_NODE) ||
3716 	(node->name == NULL))
3717 	return(0);
3718 
3719     if (node->name[0] == 'a') {
3720 	if (IS_XSLT_NAME(node, "apply-templates"))
3721 	    return(XSLT_FUNC_APPLYTEMPLATES);
3722 	else if (IS_XSLT_NAME(node, "attribute"))
3723 	    return(XSLT_FUNC_ATTRIBUTE);
3724 	else if (IS_XSLT_NAME(node, "apply-imports"))
3725 	    return(XSLT_FUNC_APPLYIMPORTS);
3726 	else if (IS_XSLT_NAME(node, "attribute-set"))
3727 	    return(0);
3728 
3729     } else if (node->name[0] == 'c') {
3730 	if (IS_XSLT_NAME(node, "choose"))
3731 	    return(XSLT_FUNC_CHOOSE);
3732 	else if (IS_XSLT_NAME(node, "copy"))
3733 	    return(XSLT_FUNC_COPY);
3734 	else if (IS_XSLT_NAME(node, "copy-of"))
3735 	    return(XSLT_FUNC_COPYOF);
3736 	else if (IS_XSLT_NAME(node, "call-template"))
3737 	    return(XSLT_FUNC_CALLTEMPLATE);
3738 	else if (IS_XSLT_NAME(node, "comment"))
3739 	    return(XSLT_FUNC_COMMENT);
3740 
3741     } else if (node->name[0] == 'd') {
3742 	if (IS_XSLT_NAME(node, "document"))
3743 	    return(XSLT_FUNC_DOCUMENT);
3744 	else if (IS_XSLT_NAME(node, "decimal-format"))
3745 	    return(0);
3746 
3747     } else if (node->name[0] == 'e') {
3748 	if (IS_XSLT_NAME(node, "element"))
3749 	    return(XSLT_FUNC_ELEMENT);
3750 
3751     } else if (node->name[0] == 'f') {
3752 	if (IS_XSLT_NAME(node, "for-each"))
3753 	    return(XSLT_FUNC_FOREACH);
3754 	else if (IS_XSLT_NAME(node, "fallback"))
3755 	    return(XSLT_FUNC_FALLBACK);
3756 
3757     } else if (*(node->name) == 'i') {
3758 	if (IS_XSLT_NAME(node, "if"))
3759 	    return(XSLT_FUNC_IF);
3760 	else if (IS_XSLT_NAME(node, "include"))
3761 	    return(0);
3762 	else if (IS_XSLT_NAME(node, "import"))
3763 	    return(0);
3764 
3765     } else if (*(node->name) == 'k') {
3766 	if (IS_XSLT_NAME(node, "key"))
3767 	    return(0);
3768 
3769     } else if (*(node->name) == 'm') {
3770 	if (IS_XSLT_NAME(node, "message"))
3771 	    return(XSLT_FUNC_MESSAGE);
3772 
3773     } else if (*(node->name) == 'n') {
3774 	if (IS_XSLT_NAME(node, "number"))
3775 	    return(XSLT_FUNC_NUMBER);
3776 	else if (IS_XSLT_NAME(node, "namespace-alias"))
3777 	    return(0);
3778 
3779     } else if (*(node->name) == 'o') {
3780 	if (IS_XSLT_NAME(node, "otherwise"))
3781 	    return(XSLT_FUNC_OTHERWISE);
3782 	else if (IS_XSLT_NAME(node, "output"))
3783 	    return(0);
3784 
3785     } else if (*(node->name) == 'p') {
3786 	if (IS_XSLT_NAME(node, "param"))
3787 	    return(XSLT_FUNC_PARAM);
3788 	else if (IS_XSLT_NAME(node, "processing-instruction"))
3789 	    return(XSLT_FUNC_PI);
3790 	else if (IS_XSLT_NAME(node, "preserve-space"))
3791 	    return(0);
3792 
3793     } else if (*(node->name) == 's') {
3794 	if (IS_XSLT_NAME(node, "sort"))
3795 	    return(XSLT_FUNC_SORT);
3796 	else if (IS_XSLT_NAME(node, "strip-space"))
3797 	    return(0);
3798 	else if (IS_XSLT_NAME(node, "stylesheet"))
3799 	    return(0);
3800 
3801     } else if (node->name[0] == 't') {
3802 	if (IS_XSLT_NAME(node, "text"))
3803 	    return(XSLT_FUNC_TEXT);
3804 	else if (IS_XSLT_NAME(node, "template"))
3805 	    return(0);
3806 	else if (IS_XSLT_NAME(node, "transform"))
3807 	    return(0);
3808 
3809     } else if (*(node->name) == 'v') {
3810 	if (IS_XSLT_NAME(node, "value-of"))
3811 	    return(XSLT_FUNC_VALUEOF);
3812 	else if (IS_XSLT_NAME(node, "variable"))
3813 	    return(XSLT_FUNC_VARIABLE);
3814 
3815     } else if (*(node->name) == 'w') {
3816 	if (IS_XSLT_NAME(node, "when"))
3817 	    return(XSLT_FUNC_WHEN);
3818 	if (IS_XSLT_NAME(node, "with-param"))
3819 	    return(XSLT_FUNC_WITHPARAM);
3820     }
3821     return(0);
3822 }
3823 
3824 /**
3825  * xsltParseAnyXSLTElem:
3826  *
3827  * @cctxt: the compilation context
3828  * @elem: the element node of the XSLT instruction
3829  *
3830  * Parses, validates the content models and compiles XSLT instructions.
3831  *
3832  * Returns 0 if everything's fine;
3833  *         -1 on API or internal errors.
3834  */
3835 int
xsltParseAnyXSLTElem(xsltCompilerCtxtPtr cctxt,xmlNodePtr elem)3836 xsltParseAnyXSLTElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr elem)
3837 {
3838     if ((cctxt == NULL) || (elem == NULL) ||
3839 	(elem->type != XML_ELEMENT_NODE))
3840 	return(-1);
3841 
3842     elem->psvi = NULL;
3843 
3844     if (! (IS_XSLT_ELEM_FAST(elem)))
3845 	return(-1);
3846     /*
3847     * Detection of handled content of extension instructions.
3848     */
3849     if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
3850 	cctxt->inode->extContentHandled = 1;
3851     }
3852 
3853     xsltCompilerNodePush(cctxt, elem);
3854     /*
3855     * URGENT TODO: Find a way to speed up this annoying redundant
3856     *  textual node-name and namespace comparison.
3857     */
3858     if (cctxt->inode->prev->curChildType != 0)
3859 	cctxt->inode->type = cctxt->inode->prev->curChildType;
3860     else
3861 	cctxt->inode->type = xsltGetXSLTElementTypeByNode(cctxt, elem);
3862     /*
3863     * Update the in-scope namespaces if needed.
3864     */
3865     if (elem->nsDef != NULL)
3866 	cctxt->inode->inScopeNs =
3867 	    xsltCompilerBuildInScopeNsList(cctxt, elem);
3868     /*
3869     * xsltStylePreCompute():
3870     *  This will compile the information found on the current
3871     *  element's attributes. NOTE that this won't process the
3872     *  children of the instruction.
3873     */
3874     xsltStylePreCompute(cctxt->style, elem);
3875     /*
3876     * TODO: How to react on errors in xsltStylePreCompute() ?
3877     */
3878 
3879     /*
3880     * Validate the content model of the XSLT-element.
3881     */
3882     switch (cctxt->inode->type) {
3883 	case XSLT_FUNC_APPLYIMPORTS:
3884 	    /* EMPTY */
3885 	    goto empty_content;
3886 	case XSLT_FUNC_APPLYTEMPLATES:
3887 	    /* <!-- Content: (xsl:sort | xsl:with-param)* --> */
3888 	    goto apply_templates;
3889 	case XSLT_FUNC_ATTRIBUTE:
3890 	    /* <!-- Content: template --> */
3891 	    goto sequence_constructor;
3892 	case XSLT_FUNC_CALLTEMPLATE:
3893 	    /* <!-- Content: xsl:with-param* --> */
3894 	    goto call_template;
3895 	case XSLT_FUNC_CHOOSE:
3896 	    /* <!-- Content: (xsl:when+, xsl:otherwise?) --> */
3897 	    goto choose;
3898 	case XSLT_FUNC_COMMENT:
3899 	    /* <!-- Content: template --> */
3900 	    goto sequence_constructor;
3901 	case XSLT_FUNC_COPY:
3902 	    /* <!-- Content: template --> */
3903 	    goto sequence_constructor;
3904 	case XSLT_FUNC_COPYOF:
3905 	    /* EMPTY */
3906 	    goto empty_content;
3907 	case XSLT_FUNC_DOCUMENT: /* Extra one */
3908 	    /* ?? template ?? */
3909 	    goto sequence_constructor;
3910 	case XSLT_FUNC_ELEMENT:
3911 	    /* <!-- Content: template --> */
3912 	    goto sequence_constructor;
3913 	case XSLT_FUNC_FALLBACK:
3914 	    /* <!-- Content: template --> */
3915 	    goto sequence_constructor;
3916 	case XSLT_FUNC_FOREACH:
3917 	    /* <!-- Content: (xsl:sort*, template) --> */
3918 	    goto for_each;
3919 	case XSLT_FUNC_IF:
3920 	    /* <!-- Content: template --> */
3921 	    goto sequence_constructor;
3922 	case XSLT_FUNC_OTHERWISE:
3923 	    /* <!-- Content: template --> */
3924 	    goto sequence_constructor;
3925 	case XSLT_FUNC_MESSAGE:
3926 	    /* <!-- Content: template --> */
3927 	    goto sequence_constructor;
3928 	case XSLT_FUNC_NUMBER:
3929 	    /* EMPTY */
3930 	    goto empty_content;
3931 	case XSLT_FUNC_PARAM:
3932 	    /*
3933 	    * Check for redefinition.
3934 	    */
3935 	    if ((elem->psvi != NULL) && (cctxt->ivar != NULL)) {
3936 		xsltVarInfoPtr ivar = cctxt->ivar;
3937 
3938 		do {
3939 		    if ((ivar->name ==
3940 			 ((xsltStyleItemParamPtr) elem->psvi)->name) &&
3941 			(ivar->nsName ==
3942 			 ((xsltStyleItemParamPtr) elem->psvi)->ns))
3943 		    {
3944 			elem->psvi = NULL;
3945 			xsltTransformError(NULL, cctxt->style, elem,
3946 			    "Redefinition of variable or parameter '%s'.\n",
3947 			    ivar->name);
3948 			cctxt->style->errors++;
3949 			goto error;
3950 		    }
3951 		    ivar = ivar->prev;
3952 		} while (ivar != NULL);
3953 	    }
3954 	    /*  <!-- Content: template --> */
3955 	    goto sequence_constructor;
3956 	case XSLT_FUNC_PI:
3957 	    /*  <!-- Content: template --> */
3958 	    goto sequence_constructor;
3959 	case XSLT_FUNC_SORT:
3960 	    /* EMPTY */
3961 	    goto empty_content;
3962 	case XSLT_FUNC_TEXT:
3963 	    /* <!-- Content: #PCDATA --> */
3964 	    goto text;
3965 	case XSLT_FUNC_VALUEOF:
3966 	    /* EMPTY */
3967 	    goto empty_content;
3968 	case XSLT_FUNC_VARIABLE:
3969 	    /*
3970 	    * Check for redefinition.
3971 	    */
3972 	    if ((elem->psvi != NULL) && (cctxt->ivar != NULL)) {
3973 		xsltVarInfoPtr ivar = cctxt->ivar;
3974 
3975 		do {
3976 		    if ((ivar->name ==
3977 			 ((xsltStyleItemVariablePtr) elem->psvi)->name) &&
3978 			(ivar->nsName ==
3979 			 ((xsltStyleItemVariablePtr) elem->psvi)->ns))
3980 		    {
3981 			elem->psvi = NULL;
3982 			xsltTransformError(NULL, cctxt->style, elem,
3983 			    "Redefinition of variable or parameter '%s'.\n",
3984 			    ivar->name);
3985 			cctxt->style->errors++;
3986 			goto error;
3987 		    }
3988 		    ivar = ivar->prev;
3989 		} while (ivar != NULL);
3990 	    }
3991 	    /* <!-- Content: template --> */
3992 	    goto sequence_constructor;
3993 	case XSLT_FUNC_WHEN:
3994 	    /* <!-- Content: template --> */
3995 	    goto sequence_constructor;
3996 	case XSLT_FUNC_WITHPARAM:
3997 	    /* <!-- Content: template --> */
3998 	    goto sequence_constructor;
3999 	default:
4000 #ifdef WITH_XSLT_DEBUG_PARSING
4001 	    xsltGenericDebug(xsltGenericDebugContext,
4002 		"xsltParseXSLTNode: Unhandled XSLT element '%s'.\n",
4003 		elem->name);
4004 #endif
4005 	    xsltTransformError(NULL, cctxt->style, elem,
4006 		"xsltParseXSLTNode: Internal error; "
4007 		"unhandled XSLT element '%s'.\n", elem->name);
4008 	    cctxt->style->errors++;
4009 	    goto internal_err;
4010     }
4011 
4012 apply_templates:
4013     /* <!-- Content: (xsl:sort | xsl:with-param)* --> */
4014     if (elem->children != NULL) {
4015 	xmlNodePtr child = elem->children;
4016 	do {
4017 	    if (child->type == XML_ELEMENT_NODE) {
4018 		if (IS_XSLT_ELEM_FAST(child)) {
4019 		    if (xmlStrEqual(child->name, BAD_CAST "with-param")) {
4020 			cctxt->inode->curChildType = XSLT_FUNC_WITHPARAM;
4021 			xsltParseAnyXSLTElem(cctxt, child);
4022 		    } else if (xmlStrEqual(child->name, BAD_CAST "sort")) {
4023 			cctxt->inode->curChildType = XSLT_FUNC_SORT;
4024 			xsltParseAnyXSLTElem(cctxt, child);
4025 		    } else
4026 			xsltParseContentError(cctxt->style, child);
4027 		} else
4028 		    xsltParseContentError(cctxt->style, child);
4029 	    }
4030 	    child = child->next;
4031 	} while (child != NULL);
4032     }
4033     goto exit;
4034 
4035 call_template:
4036     /* <!-- Content: xsl:with-param* --> */
4037     if (elem->children != NULL) {
4038 	xmlNodePtr child = elem->children;
4039 	do {
4040 	    if (child->type == XML_ELEMENT_NODE) {
4041 		if (IS_XSLT_ELEM_FAST(child)) {
4042 		    xsltStyleType type;
4043 
4044 		    type = xsltGetXSLTElementTypeByNode(cctxt, child);
4045 		    if (type == XSLT_FUNC_WITHPARAM) {
4046 			cctxt->inode->curChildType = XSLT_FUNC_WITHPARAM;
4047 			xsltParseAnyXSLTElem(cctxt, child);
4048 		    } else {
4049 			xsltParseContentError(cctxt->style, child);
4050 		    }
4051 		} else
4052 		    xsltParseContentError(cctxt->style, child);
4053 	    }
4054 	    child = child->next;
4055 	} while (child != NULL);
4056     }
4057     goto exit;
4058 
4059 text:
4060     if (elem->children != NULL) {
4061 	xmlNodePtr child = elem->children;
4062 	do {
4063 	    if ((child->type != XML_TEXT_NODE) &&
4064 		(child->type != XML_CDATA_SECTION_NODE))
4065 	    {
4066 		xsltTransformError(NULL, cctxt->style, elem,
4067 		    "The XSLT 'text' element must have only character "
4068 		    "data as content.\n");
4069 	    }
4070 	    child = child->next;
4071 	} while (child != NULL);
4072     }
4073     goto exit;
4074 
4075 empty_content:
4076     if (elem->children != NULL) {
4077 	xmlNodePtr child = elem->children;
4078 	/*
4079 	* Relaxed behaviour: we will allow whitespace-only text-nodes.
4080 	*/
4081 	do {
4082 	    if (((child->type != XML_TEXT_NODE) &&
4083 		 (child->type != XML_CDATA_SECTION_NODE)) ||
4084 		(! IS_BLANK_NODE(child)))
4085 	    {
4086 		xsltTransformError(NULL, cctxt->style, elem,
4087 		    "This XSLT element must have no content.\n");
4088 		cctxt->style->errors++;
4089 		break;
4090 	    }
4091 	    child = child->next;
4092 	} while (child != NULL);
4093     }
4094     goto exit;
4095 
4096 choose:
4097     /* <!-- Content: (xsl:when+, xsl:otherwise?) --> */
4098     /*
4099     * TODO: text-nodes in between are *not* allowed in XSLT 1.0.
4100     *   The old behaviour did not check this.
4101     * NOTE: In XSLT 2.0 they are stripped beforehand
4102     *  if whitespace-only (regardless of xml:space).
4103     */
4104     if (elem->children != NULL) {
4105 	xmlNodePtr child = elem->children;
4106 	int nbWhen = 0, nbOtherwise = 0, err = 0;
4107 	do {
4108 	    if (child->type == XML_ELEMENT_NODE) {
4109 		if (IS_XSLT_ELEM_FAST(child)) {
4110 		    xsltStyleType type;
4111 
4112 		    type = xsltGetXSLTElementTypeByNode(cctxt, child);
4113 		    if (type == XSLT_FUNC_WHEN) {
4114 			nbWhen++;
4115 			if (nbOtherwise) {
4116 			    xsltParseContentError(cctxt->style, child);
4117 			    err = 1;
4118 			    break;
4119 			}
4120 			cctxt->inode->curChildType = XSLT_FUNC_WHEN;
4121 			xsltParseAnyXSLTElem(cctxt, child);
4122 		    } else if (type == XSLT_FUNC_OTHERWISE) {
4123 			if (! nbWhen) {
4124 			    xsltParseContentError(cctxt->style, child);
4125 			    err = 1;
4126 			    break;
4127 			}
4128 			if (nbOtherwise) {
4129 			    xsltTransformError(NULL, cctxt->style, elem,
4130 				"The XSLT 'choose' element must not contain "
4131 				"more than one XSLT 'otherwise' element.\n");
4132 			    cctxt->style->errors++;
4133 			    err = 1;
4134 			    break;
4135 			}
4136 			nbOtherwise++;
4137 			cctxt->inode->curChildType = XSLT_FUNC_OTHERWISE;
4138 			xsltParseAnyXSLTElem(cctxt, child);
4139 		    } else
4140 			xsltParseContentError(cctxt->style, child);
4141 		} else
4142 		    xsltParseContentError(cctxt->style, child);
4143 	    }
4144 	    /*
4145 		else
4146 		    xsltParseContentError(cctxt, child);
4147 	    */
4148 	    child = child->next;
4149 	} while (child != NULL);
4150 	if ((! err) && (! nbWhen)) {
4151 	    xsltTransformError(NULL, cctxt->style, elem,
4152 		"The XSLT element 'choose' must contain at least one "
4153 		"XSLT element 'when'.\n");
4154 		cctxt->style->errors++;
4155 	}
4156     }
4157     goto exit;
4158 
4159 for_each:
4160     /* <!-- Content: (xsl:sort*, template) --> */
4161     /*
4162     * NOTE: Text-nodes before xsl:sort are *not* allowed in XSLT 1.0.
4163     *   The old behaviour did not allow this, but it catched this
4164     *   only at transformation-time.
4165     *   In XSLT 2.0 they are stripped beforehand if whitespace-only
4166     *   (regardless of xml:space).
4167     */
4168     if (elem->children != NULL) {
4169 	xmlNodePtr child = elem->children;
4170 	/*
4171 	* Parse xsl:sort first.
4172 	*/
4173 	do {
4174 	    if ((child->type == XML_ELEMENT_NODE) &&
4175 		IS_XSLT_ELEM_FAST(child))
4176 	    {
4177 		if (xsltGetXSLTElementTypeByNode(cctxt, child) ==
4178 		    XSLT_FUNC_SORT)
4179 		{
4180 		    cctxt->inode->curChildType = XSLT_FUNC_SORT;
4181 		    xsltParseAnyXSLTElem(cctxt, child);
4182 		} else
4183 		    break;
4184 	    } else
4185 		break;
4186 	    child = child->next;
4187 	} while (child != NULL);
4188 	/*
4189 	* Parse the sequece constructor.
4190 	*/
4191 	if (child != NULL)
4192 	    xsltParseSequenceConstructor(cctxt, child);
4193     }
4194     goto exit;
4195 
4196 sequence_constructor:
4197     /*
4198     * Parse the sequence constructor.
4199     */
4200     if (elem->children != NULL)
4201 	xsltParseSequenceConstructor(cctxt, elem->children);
4202 
4203     /*
4204     * Register information for vars/params. Only needed if there
4205     * are any following siblings.
4206     */
4207     if ((elem->next != NULL) &&
4208 	((cctxt->inode->type == XSLT_FUNC_VARIABLE) ||
4209 	 (cctxt->inode->type == XSLT_FUNC_PARAM)))
4210     {
4211 	if ((elem->psvi != NULL) &&
4212 	    (((xsltStyleBasicItemVariablePtr) elem->psvi)->name))
4213 	{
4214 	    xsltCompilerVarInfoPush(cctxt, elem,
4215 		((xsltStyleBasicItemVariablePtr) elem->psvi)->name,
4216 		((xsltStyleBasicItemVariablePtr) elem->psvi)->ns);
4217 	}
4218     }
4219 
4220 error:
4221 exit:
4222     xsltCompilerNodePop(cctxt, elem);
4223     return(0);
4224 
4225 internal_err:
4226     xsltCompilerNodePop(cctxt, elem);
4227     return(-1);
4228 }
4229 
4230 /**
4231  * xsltForwardsCompatUnkownItemCreate:
4232  *
4233  * @cctxt: the compilation context
4234  *
4235  * Creates a compiled representation of the unknown
4236  * XSLT instruction.
4237  *
4238  * Returns the compiled representation.
4239  */
4240 static xsltStyleItemUknownPtr
xsltForwardsCompatUnkownItemCreate(xsltCompilerCtxtPtr cctxt)4241 xsltForwardsCompatUnkownItemCreate(xsltCompilerCtxtPtr cctxt)
4242 {
4243     xsltStyleItemUknownPtr item;
4244 
4245     item = (xsltStyleItemUknownPtr) xmlMalloc(sizeof(xsltStyleItemUknown));
4246     if (item == NULL) {
4247 	xsltTransformError(NULL, cctxt->style, NULL,
4248 	    "Internal error in xsltForwardsCompatUnkownItemCreate(): "
4249 	    "Failed to allocate memory.\n");
4250 	cctxt->style->errors++;
4251 	return(NULL);
4252     }
4253     memset(item, 0, sizeof(xsltStyleItemUknown));
4254     item->type = XSLT_FUNC_UNKOWN_FORWARDS_COMPAT;
4255     /*
4256     * Store it in the stylesheet.
4257     */
4258     item->next = cctxt->style->preComps;
4259     cctxt->style->preComps = (xsltElemPreCompPtr) item;
4260     return(item);
4261 }
4262 
4263 /**
4264  * xsltParseUnknownXSLTElem:
4265  *
4266  * @cctxt: the compilation context
4267  * @node: the element of the unknown XSLT instruction
4268  *
4269  * Parses an unknown XSLT element.
4270  * If forwards compatible mode is enabled this will allow
4271  * such an unknown XSLT and; otherwise it is rejected.
4272  *
4273  * Returns 1 in the unknown XSLT instruction is rejected,
4274  *         0 if everything's fine and
4275  *         -1 on API or internal errors.
4276  */
4277 static int
xsltParseUnknownXSLTElem(xsltCompilerCtxtPtr cctxt,xmlNodePtr node)4278 xsltParseUnknownXSLTElem(xsltCompilerCtxtPtr cctxt,
4279 			    xmlNodePtr node)
4280 {
4281     if ((cctxt == NULL) || (node == NULL))
4282 	return(-1);
4283 
4284     /*
4285     * Detection of handled content of extension instructions.
4286     */
4287     if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
4288 	cctxt->inode->extContentHandled = 1;
4289     }
4290     if (cctxt->inode->forwardsCompat == 0) {
4291 	/*
4292 	* We are not in forwards-compatible mode, so raise an error.
4293 	*/
4294 	xsltTransformError(NULL, cctxt->style, node,
4295 	    "Unknown XSLT element '%s'.\n", node->name);
4296 	cctxt->style->errors++;
4297 	return(1);
4298     }
4299     /*
4300     * Forwards-compatible mode.
4301     * ------------------------
4302     *
4303     * Parse/compile xsl:fallback elements.
4304     *
4305     * QUESTION: Do we have to raise an error if there's no xsl:fallback?
4306     * ANSWER: No, since in the stylesheet the fallback behaviour might
4307     *  also be provided by using the XSLT function "element-available".
4308     */
4309     if (cctxt->unknownItem == NULL) {
4310 	/*
4311 	* Create a singleton for all unknown XSLT instructions.
4312 	*/
4313 	cctxt->unknownItem = xsltForwardsCompatUnkownItemCreate(cctxt);
4314 	if (cctxt->unknownItem == NULL) {
4315 	    node->psvi = NULL;
4316 	    return(-1);
4317 	}
4318     }
4319     node->psvi = cctxt->unknownItem;
4320     if (node->children == NULL)
4321 	return(0);
4322     else {
4323 	xmlNodePtr child = node->children;
4324 
4325 	xsltCompilerNodePush(cctxt, node);
4326 	/*
4327 	* Update the in-scope namespaces if needed.
4328 	*/
4329 	if (node->nsDef != NULL)
4330 	    cctxt->inode->inScopeNs =
4331 		xsltCompilerBuildInScopeNsList(cctxt, node);
4332 	/*
4333 	* Parse all xsl:fallback children.
4334 	*/
4335 	do {
4336 	    if ((child->type == XML_ELEMENT_NODE) &&
4337 		IS_XSLT_ELEM_FAST(child) &&
4338 		IS_XSLT_NAME(child, "fallback"))
4339 	    {
4340 		cctxt->inode->curChildType = XSLT_FUNC_FALLBACK;
4341 		xsltParseAnyXSLTElem(cctxt, child);
4342 	    }
4343 	    child = child->next;
4344 	} while (child != NULL);
4345 
4346 	xsltCompilerNodePop(cctxt, node);
4347     }
4348     return(0);
4349 }
4350 
4351 /**
4352  * xsltParseSequenceConstructor:
4353  *
4354  * @cctxt: the compilation context
4355  * @cur: the start-node of the content to be parsed
4356  *
4357  * Parses a "template" content (or "sequence constructor" in XSLT 2.0 terms).
4358  * This will additionally remove xsl:text elements from the tree.
4359  */
4360 void
xsltParseSequenceConstructor(xsltCompilerCtxtPtr cctxt,xmlNodePtr cur)4361 xsltParseSequenceConstructor(xsltCompilerCtxtPtr cctxt, xmlNodePtr cur)
4362 {
4363     xsltStyleType type;
4364     xmlNodePtr deleteNode = NULL;
4365 
4366     if (cctxt == NULL) {
4367 	xmlGenericError(xmlGenericErrorContext,
4368 	    "xsltParseSequenceConstructor: Bad arguments\n");
4369 	cctxt->style->errors++;
4370 	return;
4371     }
4372     /*
4373     * Detection of handled content of extension instructions.
4374     */
4375     if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
4376 	cctxt->inode->extContentHandled = 1;
4377     }
4378     if (cur == NULL)
4379 	return;
4380     /*
4381     * This is the content reffered to as a "template".
4382     * E.g. an xsl:element has such content model:
4383     * <xsl:element
4384     *   name = { qname }
4385     *   namespace = { uri-reference }
4386     *   use-attribute-sets = qnames>
4387     * <!-- Content: template -->
4388     *
4389     * NOTE that in XSLT-2 the term "template" was abandoned due to
4390     *  confusion with xsl:template and the term "sequence constructor"
4391     *  was introduced instead.
4392     *
4393     * The following XSLT-instructions are allowed to appear:
4394     *  xsl:apply-templates, xsl:call-template, xsl:apply-imports,
4395     *  xsl:for-each, xsl:value-of, xsl:copy-of, xsl:number,
4396     *  xsl:choose, xsl:if, xsl:text, xsl:copy, xsl:variable,
4397     *  xsl:message, xsl:fallback,
4398     *  xsl:processing-instruction, xsl:comment, xsl:element
4399     *  xsl:attribute.
4400     * Additional allowed content:
4401     * 1) extension instructions
4402     * 2) literal result elements
4403     * 3) PCDATA
4404     *
4405     * NOTE that this content model does *not* allow xsl:param.
4406     */
4407     while (cur != NULL) {
4408 	if (deleteNode != NULL)	{
4409 #ifdef WITH_XSLT_DEBUG_BLANKS
4410 	    xsltGenericDebug(xsltGenericDebugContext,
4411 	     "xsltParseSequenceConstructor: removing xsl:text element\n");
4412 #endif
4413 	    xmlUnlinkNode(deleteNode);
4414 	    xmlFreeNode(deleteNode);
4415 	    deleteNode = NULL;
4416 	}
4417 	if (cur->type == XML_ELEMENT_NODE) {
4418 
4419 	    if (cur->psvi == xsltXSLTTextMarker) {
4420 		/*
4421 		* xsl:text elements
4422 		* --------------------------------------------------------
4423 		*/
4424 		xmlNodePtr tmp;
4425 
4426 		cur->psvi = NULL;
4427 		/*
4428 		* Mark the xsl:text element for later deletion.
4429 		*/
4430 		deleteNode = cur;
4431 		/*
4432 		* Validate content.
4433 		*/
4434 		tmp = cur->children;
4435 		if (tmp) {
4436 		    /*
4437 		    * We don't expect more than one text-node in the
4438 		    * content, since we already merged adjacent
4439 		    * text/CDATA-nodes and eliminated PI/comment-nodes.
4440 		    */
4441 		    if ((tmp->type == XML_TEXT_NODE) ||
4442 			(tmp->next == NULL))
4443 		    {
4444 			/*
4445 			* Leave the contained text-node in the tree.
4446 			*/
4447 			xmlUnlinkNode(tmp);
4448 			xmlAddPrevSibling(cur, tmp);
4449 		    } else {
4450 			tmp = NULL;
4451 			xsltTransformError(NULL, cctxt->style, cur,
4452 			    "Element 'xsl:text': Invalid type "
4453 			    "of node found in content.\n");
4454 			cctxt->style->errors++;
4455 		    }
4456 		}
4457 		if (cur->properties) {
4458 		    xmlAttrPtr attr;
4459 		    /*
4460 		    * TODO: We need to report errors for
4461 		    *  invalid attrs.
4462 		    */
4463 		    attr = cur->properties;
4464 		    do {
4465 			if ((attr->ns == NULL) &&
4466 			    (attr->name != NULL) &&
4467 			    (attr->name[0] == 'd') &&
4468 			    xmlStrEqual(attr->name,
4469 			    BAD_CAST "disable-output-escaping"))
4470 			{
4471 			    /*
4472 			    * Attr "disable-output-escaping".
4473 			    * XSLT-2: This attribute is deprecated.
4474 			    */
4475 			    if ((attr->children != NULL) &&
4476 				xmlStrEqual(attr->children->content,
4477 				BAD_CAST "yes"))
4478 			    {
4479 				/*
4480 				* Disable output escaping for this
4481 				* text node.
4482 				*/
4483 				if (tmp)
4484 				    tmp->name = xmlStringTextNoenc;
4485 			    } else if ((attr->children == NULL) ||
4486 				(attr->children->content == NULL) ||
4487 				(!xmlStrEqual(attr->children->content,
4488 				BAD_CAST "no")))
4489 			    {
4490 				xsltTransformError(NULL, cctxt->style,
4491 				    cur,
4492 				    "Attribute 'disable-output-escaping': "
4493 				    "Invalid value. Expected is "
4494 				    "'yes' or 'no'.\n");
4495 				cctxt->style->errors++;
4496 			    }
4497 			    break;
4498 			}
4499 			attr = attr->next;
4500 		    } while (attr != NULL);
4501 		}
4502 	    } else if (IS_XSLT_ELEM_FAST(cur)) {
4503 		/*
4504 		* TODO: Using the XSLT-marker is still not stable yet.
4505 		*/
4506 		/* if (cur->psvi == xsltXSLTElemMarker) { */
4507 		/*
4508 		* XSLT instructions
4509 		* --------------------------------------------------------
4510 		*/
4511 		cur->psvi = NULL;
4512 		type = xsltGetXSLTElementTypeByNode(cctxt, cur);
4513 		switch (type) {
4514 		    case XSLT_FUNC_APPLYIMPORTS:
4515 		    case XSLT_FUNC_APPLYTEMPLATES:
4516 		    case XSLT_FUNC_ATTRIBUTE:
4517 		    case XSLT_FUNC_CALLTEMPLATE:
4518 		    case XSLT_FUNC_CHOOSE:
4519 		    case XSLT_FUNC_COMMENT:
4520 		    case XSLT_FUNC_COPY:
4521 		    case XSLT_FUNC_COPYOF:
4522 		    case XSLT_FUNC_DOCUMENT: /* Extra one */
4523 		    case XSLT_FUNC_ELEMENT:
4524 		    case XSLT_FUNC_FALLBACK:
4525 		    case XSLT_FUNC_FOREACH:
4526 		    case XSLT_FUNC_IF:
4527 		    case XSLT_FUNC_MESSAGE:
4528 		    case XSLT_FUNC_NUMBER:
4529 		    case XSLT_FUNC_PI:
4530 		    case XSLT_FUNC_TEXT:
4531 		    case XSLT_FUNC_VALUEOF:
4532 		    case XSLT_FUNC_VARIABLE:
4533 			/*
4534 			* Parse the XSLT element.
4535 			*/
4536 			cctxt->inode->curChildType = type;
4537 			xsltParseAnyXSLTElem(cctxt, cur);
4538 			break;
4539 		    default:
4540 			xsltParseUnknownXSLTElem(cctxt, cur);
4541 			cur = cur->next;
4542 			continue;
4543 		}
4544 	    } else {
4545 		/*
4546 		* Non-XSLT elements
4547 		* -----------------
4548 		*/
4549 		xsltCompilerNodePush(cctxt, cur);
4550 		/*
4551 		* Update the in-scope namespaces if needed.
4552 		*/
4553 		if (cur->nsDef != NULL)
4554 		    cctxt->inode->inScopeNs =
4555 			xsltCompilerBuildInScopeNsList(cctxt, cur);
4556 		/*
4557 		* The current element is either a literal result element
4558 		* or an extension instruction.
4559 		*
4560 		* Process attr "xsl:extension-element-prefixes".
4561 		* FUTURE TODO: IIRC in XSLT 2.0 this attribute must be
4562 		* processed by the implementor of the extension function;
4563 		* i.e., it won't be handled by the XSLT processor.
4564 		*/
4565 		/* SPEC 1.0:
4566 		*   "exclude-result-prefixes" is only allowed on literal
4567 		*   result elements and "xsl:exclude-result-prefixes"
4568 		*   on xsl:stylesheet/xsl:transform.
4569 		* SPEC 2.0:
4570 		*   "There are a number of standard attributes
4571 		*   that may appear on any XSLT element: specifically
4572 		*   version, exclude-result-prefixes,
4573 		*   extension-element-prefixes, xpath-default-namespace,
4574 		*   default-collation, and use-when."
4575 		*
4576 		* SPEC 2.0:
4577 		*   For literal result elements:
4578 		*   "xsl:version, xsl:exclude-result-prefixes,
4579 		*    xsl:extension-element-prefixes,
4580 		*    xsl:xpath-default-namespace,
4581 		*    xsl:default-collation, or xsl:use-when."
4582 		*/
4583 		if (cur->properties)
4584 		    cctxt->inode->extElemNs =
4585 			xsltParseExtElemPrefixes(cctxt,
4586 			    cur, cctxt->inode->extElemNs,
4587 			    XSLT_ELEMENT_CATEGORY_LRE);
4588 		/*
4589 		* Eval if we have an extension instruction here.
4590 		*/
4591 		if ((cur->ns != NULL) &&
4592 		    (cctxt->inode->extElemNs != NULL) &&
4593 		    (xsltCheckExtPrefix(cctxt->style, cur->ns->href) == 1))
4594 		{
4595 		    /*
4596 		    * Extension instructions
4597 		    * ----------------------------------------------------
4598 		    * Mark the node information.
4599 		    */
4600 		    cctxt->inode->category = XSLT_ELEMENT_CATEGORY_EXTENSION;
4601 		    cctxt->inode->extContentHandled = 0;
4602 		    if (cur->psvi != NULL) {
4603 			cur->psvi = NULL;
4604 			/*
4605 			* TODO: Temporary sanity check.
4606 			*/
4607 			xsltTransformError(NULL, cctxt->style, cur,
4608 			    "Internal error in xsltParseSequenceConstructor(): "
4609 			    "Occupied PSVI field.\n");
4610 			cctxt->style->errors++;
4611 			cur = cur->next;
4612 			continue;
4613 		    }
4614 		    cur->psvi = (void *)
4615 			xsltPreComputeExtModuleElement(cctxt->style, cur);
4616 
4617 		    if (cur->psvi == NULL) {
4618 			/*
4619 			* OLD COMMENT: "Unknown element, maybe registered
4620 			*  at the context level. Mark it for later
4621 			*  recognition."
4622 			* QUESTION: What does the xsltExtMarker mean?
4623 			*  ANSWER: It is used in
4624 			*   xsltApplySequenceConstructor() at
4625 			*   transformation-time to look out for extension
4626 			*   registered in the transformation context.
4627 			*/
4628 			cur->psvi = (void *) xsltExtMarker;
4629 		    }
4630 		    /*
4631 		    * BIG NOTE: Now the ugly part. In previous versions
4632 		    *  of Libxslt (until 1.1.16), all the content of an
4633 		    *  extension instruction was processed and compiled without
4634 		    *  the need of the extension-author to explicitely call
4635 		    *  such a processing;.We now need to mimic this old
4636 		    *  behaviour in order to avoid breaking old code
4637 		    *  on the extension-author's side.
4638 		    * The mechanism:
4639 		    *  1) If the author does *not* set the
4640 		    *    compile-time-flag @extContentHandled, then we'll
4641 		    *    parse the content assuming that it's a "template"
4642 		    *    (or "sequence constructor in XSLT 2.0 terms).
4643 		    *    NOTE: If the extension is registered at
4644 		    *    transformation-time only, then there's no way of
4645 		    *    knowing that content shall be valid, and we'll
4646 		    *    process the content the same way.
4647 		    *  2) If the author *does* set the flag, then we'll assume
4648 		    *   that the author has handled the parsing him/herself
4649 		    *   (e.g. called xsltParseSequenceConstructor(), etc.
4650 		    *   explicitely in his/her code).
4651 		    */
4652 		    if ((cur->children != NULL) &&
4653 			(cctxt->inode->extContentHandled == 0))
4654 		    {
4655 			/*
4656 			* Default parsing of the content using the
4657 			* sequence-constructor model.
4658 			*/
4659 			xsltParseSequenceConstructor(cctxt, cur->children);
4660 		    }
4661 		} else {
4662 		    /*
4663 		    * Literal result element
4664 		    * ----------------------------------------------------
4665 		    * Allowed XSLT attributes:
4666 		    *  xsl:extension-element-prefixes CDATA #IMPLIED
4667 		    *  xsl:exclude-result-prefixes CDATA #IMPLIED
4668 		    *  TODO: xsl:use-attribute-sets %qnames; #IMPLIED
4669 		    *  xsl:version NMTOKEN #IMPLIED
4670 		    */
4671 		    cur->psvi = NULL;
4672 		    cctxt->inode->category = XSLT_ELEMENT_CATEGORY_LRE;
4673 		    if (cur->properties != NULL) {
4674 			xmlAttrPtr attr = cur->properties;
4675 			/*
4676 			* Attribute "xsl:exclude-result-prefixes".
4677 			*/
4678 			cctxt->inode->exclResultNs =
4679 			    xsltParseExclResultPrefixes(cctxt, cur,
4680 				cctxt->inode->exclResultNs,
4681 				XSLT_ELEMENT_CATEGORY_LRE);
4682 			/*
4683 			* Attribute "xsl:version".
4684 			*/
4685 			xsltParseAttrXSLTVersion(cctxt, cur,
4686 			    XSLT_ELEMENT_CATEGORY_LRE);
4687 			/*
4688 			* Report invalid XSLT attributes.
4689 			* For XSLT 1.0 only xsl:use-attribute-sets is allowed
4690 			* next to xsl:version, xsl:exclude-result-prefixes and
4691 			* xsl:extension-element-prefixes.
4692 			*
4693 			* Mark all XSLT attributes, in order to skip such
4694 			* attributes when instantiating the LRE.
4695 			*/
4696 			do {
4697 			    if ((attr->psvi != xsltXSLTAttrMarker) &&
4698 				IS_XSLT_ATTR_FAST(attr))
4699 			    {
4700 				if (! xmlStrEqual(attr->name,
4701 				    BAD_CAST "use-attribute-sets"))
4702 				{
4703 				    xsltTransformError(NULL, cctxt->style,
4704 					cur,
4705 					"Unknown XSLT attribute '%s'.\n",
4706 					attr->name);
4707 				    cctxt->style->errors++;
4708 				} else {
4709 				    /*
4710 				    * XSLT attr marker.
4711 				    */
4712 				    attr->psvi = (void *) xsltXSLTAttrMarker;
4713 				}
4714 			    }
4715 			    attr = attr->next;
4716 			} while (attr != NULL);
4717 		    }
4718 		    /*
4719 		    * Create/reuse info for the literal result element.
4720 		    */
4721 		    if (cctxt->inode->nsChanged)
4722 			xsltLREInfoCreate(cctxt, cur, 1);
4723 		    cur->psvi = cctxt->inode->litResElemInfo;
4724 		    /*
4725 		    * Apply ns-aliasing on the element and on its attributes.
4726 		    */
4727 		    if (cctxt->hasNsAliases)
4728 			xsltLREBuildEffectiveNs(cctxt, cur);
4729 		    /*
4730 		    * Compile attribute value templates (AVT).
4731 		    */
4732 		    if (cur->properties) {
4733 			xmlAttrPtr attr = cur->properties;
4734 
4735 			while (attr != NULL) {
4736 			    xsltCompileAttr(cctxt->style, attr);
4737 			    attr = attr->next;
4738 			}
4739 		    }
4740 		    /*
4741 		    * Parse the content, which is defined to be a "template"
4742 		    * (or "sequence constructor" in XSLT 2.0 terms).
4743 		    */
4744 		    if (cur->children != NULL) {
4745 			xsltParseSequenceConstructor(cctxt, cur->children);
4746 		    }
4747 		}
4748 		/*
4749 		* Leave the non-XSLT element.
4750 		*/
4751 		xsltCompilerNodePop(cctxt, cur);
4752 	    }
4753 	}
4754 	cur = cur->next;
4755     }
4756     if (deleteNode != NULL) {
4757 #ifdef WITH_XSLT_DEBUG_BLANKS
4758 	xsltGenericDebug(xsltGenericDebugContext,
4759 	    "xsltParseSequenceConstructor: removing xsl:text element\n");
4760 #endif
4761 	xmlUnlinkNode(deleteNode);
4762 	xmlFreeNode(deleteNode);
4763 	deleteNode = NULL;
4764     }
4765 }
4766 
4767 /**
4768  * xsltParseTemplateContent:
4769  * @style:  the XSLT stylesheet
4770  * @templ:  the node containing the content to be parsed
4771  *
4772  * Parses and compiles the content-model of an xsl:template element.
4773  * Note that this is *not* the "template" content model (or "sequence
4774  *  constructor" in XSLT 2.0); it it allows addional xsl:param
4775  *  elements as immediate children of @templ.
4776  *
4777  * Called by:
4778  *   exsltFuncFunctionComp() (EXSLT, functions.c)
4779  *   So this is intended to be called from extension functions.
4780  */
4781 void
xsltParseTemplateContent(xsltStylesheetPtr style,xmlNodePtr templ)4782 xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) {
4783     if ((style == NULL) || (templ == NULL))
4784 	return;
4785 
4786     /*
4787     * Detection of handled content of extension instructions.
4788     */
4789     if (XSLT_CCTXT(style)->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
4790 	XSLT_CCTXT(style)->inode->extContentHandled = 1;
4791     }
4792 
4793     if (templ->children != NULL) {
4794 	xmlNodePtr child = templ->children;
4795 	/*
4796 	* Process xsl:param elements, which can only occur as the
4797 	* immediate children of xsl:template (well, and of any
4798 	* user-defined extension instruction if needed).
4799 	*/
4800 	do {
4801 	    if ((child->type == XML_ELEMENT_NODE) &&
4802 		IS_XSLT_ELEM_FAST(child) &&
4803 		IS_XSLT_NAME(child, "param"))
4804 	    {
4805 		XSLT_CCTXT(style)->inode->curChildType = XSLT_FUNC_PARAM;
4806 		xsltParseAnyXSLTElem(XSLT_CCTXT(style), child);
4807 	    } else
4808 		break;
4809 	    child = child->next;
4810 	} while (child != NULL);
4811 	/*
4812 	* Parse the content and register the pattern.
4813 	*/
4814 	xsltParseSequenceConstructor(XSLT_CCTXT(style), child);
4815     }
4816 }
4817 
4818 #else /* XSLT_REFACTORED */
4819 
4820 /**
4821  * xsltParseTemplateContent:
4822  * @style:  the XSLT stylesheet
4823  * @templ:  the container node (can be a document for literal results)
4824  *
4825  * parse a template content-model
4826  * Clean-up the template content from unwanted ignorable blank nodes
4827  * and process xslt:text
4828  */
4829 void
xsltParseTemplateContent(xsltStylesheetPtr style,xmlNodePtr templ)4830 xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) {
4831     xmlNodePtr cur, delete;
4832     /*
4833      * This content comes from the stylesheet
4834      * For stylesheets, the set of whitespace-preserving
4835      * element names consists of just xsl:text.
4836      */
4837     cur = templ->children;
4838     delete = NULL;
4839     while (cur != NULL) {
4840 	if (delete != NULL) {
4841 #ifdef WITH_XSLT_DEBUG_BLANKS
4842 	    xsltGenericDebug(xsltGenericDebugContext,
4843 	     "xsltParseTemplateContent: removing text\n");
4844 #endif
4845 	    xmlUnlinkNode(delete);
4846 	    xmlFreeNode(delete);
4847 	    delete = NULL;
4848 	}
4849 	if (IS_XSLT_ELEM(cur)) {
4850 	    if (IS_XSLT_NAME(cur, "text")) {
4851 		/*
4852 		* TODO: Processing of xsl:text should be moved to
4853 		*   xsltPrecomputeStylesheet(), since otherwise this
4854 		*   will be performed for every multiply included
4855 		*   stylesheet; i.e. this here is not skipped with
4856 		*   the use of the style->nopreproc flag.
4857 		*/
4858 		if (cur->children != NULL) {
4859 		    xmlChar *prop;
4860 		    xmlNodePtr text = cur->children, next;
4861 		    int noesc = 0;
4862 
4863 		    prop = xmlGetNsProp(cur,
4864 			(const xmlChar *)"disable-output-escaping",
4865 			NULL);
4866 		    if (prop != NULL) {
4867 #ifdef WITH_XSLT_DEBUG_PARSING
4868 			xsltGenericDebug(xsltGenericDebugContext,
4869 			     "Disable escaping: %s\n", text->content);
4870 #endif
4871 			if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
4872 			    noesc = 1;
4873 			} else if (!xmlStrEqual(prop,
4874 						(const xmlChar *)"no")){
4875 			    xsltTransformError(NULL, style, cur,
4876 	     "xsl:text: disable-output-escaping allows only yes or no\n");
4877 			    style->warnings++;
4878 
4879 			}
4880 			xmlFree(prop);
4881 		    }
4882 
4883 		    while (text != NULL) {
4884 			if (text->type == XML_COMMENT_NODE) {
4885 			    text = text->next;
4886 			    continue;
4887 			}
4888 			if ((text->type != XML_TEXT_NODE) &&
4889 			     (text->type != XML_CDATA_SECTION_NODE)) {
4890 			    xsltTransformError(NULL, style, cur,
4891 		 "xsltParseTemplateContent: xslt:text content problem\n");
4892 			    style->errors++;
4893 			    break;
4894 			}
4895 			if ((noesc) && (text->type != XML_CDATA_SECTION_NODE))
4896 			    text->name = xmlStringTextNoenc;
4897 			text = text->next;
4898 		    }
4899 
4900 		    /*
4901 		     * replace xsl:text by the list of childs
4902 		     */
4903 		    if (text == NULL) {
4904 			text = cur->children;
4905 			while (text != NULL) {
4906 			    if ((style->internalized) &&
4907 			        (text->content != NULL) &&
4908 			        (!xmlDictOwns(style->dict, text->content))) {
4909 
4910 				/*
4911 				 * internalize the text string
4912 				 */
4913 				if (text->doc->dict != NULL) {
4914 				    const xmlChar *tmp;
4915 
4916 				    tmp = xmlDictLookup(text->doc->dict,
4917 				                        text->content, -1);
4918 				    if (tmp != text->content) {
4919 				        xmlNodeSetContent(text, NULL);
4920 					text->content = (xmlChar *) tmp;
4921 				    }
4922 				}
4923 			    }
4924 
4925 			    next = text->next;
4926 			    xmlUnlinkNode(text);
4927 			    xmlAddPrevSibling(cur, text);
4928 			    text = next;
4929 			}
4930 		    }
4931 		}
4932 		delete = cur;
4933 		goto skip_children;
4934 	    }
4935 	}
4936 	else if ((cur->ns != NULL) && (style->nsDefs != NULL) &&
4937 	    (xsltCheckExtPrefix(style, cur->ns->prefix)))
4938 	{
4939 	    /*
4940 	     * okay this is an extension element compile it too
4941 	     */
4942 	    xsltStylePreCompute(style, cur);
4943 	}
4944 	else if (cur->type == XML_ELEMENT_NODE)
4945 	{
4946 	    /*
4947 	     * This is an element which will be output as part of the
4948 	     * template exectution, precompile AVT if found.
4949 	     */
4950 	    if ((cur->ns == NULL) && (style->defaultAlias != NULL)) {
4951 		cur->ns = xmlSearchNsByHref(cur->doc, cur,
4952 			style->defaultAlias);
4953 	    }
4954 	    if (cur->properties != NULL) {
4955 	        xmlAttrPtr attr = cur->properties;
4956 
4957 		while (attr != NULL) {
4958 		    xsltCompileAttr(style, attr);
4959 		    attr = attr->next;
4960 		}
4961 	    }
4962 	}
4963 	/*
4964 	 * Skip to next node
4965 	 */
4966 	if (cur->children != NULL) {
4967 	    if (cur->children->type != XML_ENTITY_DECL) {
4968 		cur = cur->children;
4969 		continue;
4970 	    }
4971 	}
4972 skip_children:
4973 	if (cur->next != NULL) {
4974 	    cur = cur->next;
4975 	    continue;
4976 	}
4977 
4978 	do {
4979 	    cur = cur->parent;
4980 	    if (cur == NULL)
4981 		break;
4982 	    if (cur == templ) {
4983 		cur = NULL;
4984 		break;
4985 	    }
4986 	    if (cur->next != NULL) {
4987 		cur = cur->next;
4988 		break;
4989 	    }
4990 	} while (cur != NULL);
4991     }
4992     if (delete != NULL) {
4993 #ifdef WITH_XSLT_DEBUG_PARSING
4994 	xsltGenericDebug(xsltGenericDebugContext,
4995 	 "xsltParseTemplateContent: removing text\n");
4996 #endif
4997 	xmlUnlinkNode(delete);
4998 	xmlFreeNode(delete);
4999 	delete = NULL;
5000     }
5001 
5002     /*
5003      * Skip the first params
5004      */
5005     cur = templ->children;
5006     while (cur != NULL) {
5007 	if ((IS_XSLT_ELEM(cur)) && (!(IS_XSLT_NAME(cur, "param"))))
5008 	    break;
5009 	cur = cur->next;
5010     }
5011 
5012     /*
5013      * Browse the remainder of the template
5014      */
5015     while (cur != NULL) {
5016 	if ((IS_XSLT_ELEM(cur)) && (IS_XSLT_NAME(cur, "param"))) {
5017 	    xmlNodePtr param = cur;
5018 
5019 	    xsltTransformError(NULL, style, cur,
5020 		"xsltParseTemplateContent: ignoring misplaced param element\n");
5021 	    if (style != NULL) style->warnings++;
5022             cur = cur->next;
5023 	    xmlUnlinkNode(param);
5024 	    xmlFreeNode(param);
5025 	} else
5026 	    break;
5027     }
5028 }
5029 
5030 #endif /* else XSLT_REFACTORED */
5031 
5032 /**
5033  * xsltParseStylesheetKey:
5034  * @style:  the XSLT stylesheet
5035  * @key:  the "key" element
5036  *
5037  * <!-- Category: top-level-element -->
5038  * <xsl:key name = qname, match = pattern, use = expression />
5039  *
5040  * parse an XSLT stylesheet key definition and register it
5041  */
5042 
5043 static void
xsltParseStylesheetKey(xsltStylesheetPtr style,xmlNodePtr key)5044 xsltParseStylesheetKey(xsltStylesheetPtr style, xmlNodePtr key) {
5045     xmlChar *prop = NULL;
5046     xmlChar *use = NULL;
5047     xmlChar *match = NULL;
5048     xmlChar *name = NULL;
5049     xmlChar *nameURI = NULL;
5050 
5051     if ((style == NULL) || (key == NULL))
5052 	return;
5053 
5054     /*
5055      * Get arguments
5056      */
5057     prop = xmlGetNsProp(key, (const xmlChar *)"name", NULL);
5058     if (prop != NULL) {
5059         const xmlChar *URI;
5060 
5061 	/*
5062 	* TODO: Don't use xsltGetQNameURI().
5063 	*/
5064 	URI = xsltGetQNameURI(key, &prop);
5065 	if (prop == NULL) {
5066 	    if (style != NULL) style->errors++;
5067 	    goto error;
5068 	} else {
5069 	    name = prop;
5070 	    if (URI != NULL)
5071 		nameURI = xmlStrdup(URI);
5072 	}
5073 #ifdef WITH_XSLT_DEBUG_PARSING
5074 	xsltGenericDebug(xsltGenericDebugContext,
5075 	     "xsltParseStylesheetKey: name %s\n", name);
5076 #endif
5077     } else {
5078 	xsltTransformError(NULL, style, key,
5079 	    "xsl:key : error missing name\n");
5080 	if (style != NULL) style->errors++;
5081 	goto error;
5082     }
5083 
5084     match = xmlGetNsProp(key, (const xmlChar *)"match", NULL);
5085     if (match == NULL) {
5086 	xsltTransformError(NULL, style, key,
5087 	    "xsl:key : error missing match\n");
5088 	if (style != NULL) style->errors++;
5089 	goto error;
5090     }
5091 
5092     use = xmlGetNsProp(key, (const xmlChar *)"use", NULL);
5093     if (use == NULL) {
5094 	xsltTransformError(NULL, style, key,
5095 	    "xsl:key : error missing use\n");
5096 	if (style != NULL) style->errors++;
5097 	goto error;
5098     }
5099 
5100     /*
5101      * register the keys
5102      */
5103     xsltAddKey(style, name, nameURI, match, use, key);
5104 
5105 
5106 error:
5107     if (use != NULL)
5108 	xmlFree(use);
5109     if (match != NULL)
5110 	xmlFree(match);
5111     if (name != NULL)
5112 	xmlFree(name);
5113     if (nameURI != NULL)
5114 	xmlFree(nameURI);
5115 
5116     if (key->children != NULL) {
5117 	xsltParseContentError(style, key->children);
5118     }
5119 }
5120 
5121 #ifdef XSLT_REFACTORED
5122 /**
5123  * xsltParseXSLTTemplate:
5124  * @style:  the XSLT stylesheet
5125  * @template:  the "template" element
5126  *
5127  * parse an XSLT stylesheet template building the associated structures
5128  * TODO: Is @style ever expected to be NULL?
5129  *
5130  * Called from:
5131  *   xsltParseXSLTStylesheet()
5132  *   xsltParseStylesheetTop()
5133  */
5134 
5135 static void
xsltParseXSLTTemplate(xsltCompilerCtxtPtr cctxt,xmlNodePtr templNode)5136 xsltParseXSLTTemplate(xsltCompilerCtxtPtr cctxt, xmlNodePtr templNode) {
5137     xsltTemplatePtr templ;
5138     xmlChar *prop;
5139     double  priority;
5140 
5141     if ((cctxt == NULL) || (templNode == NULL))
5142 	return;
5143 
5144     /*
5145      * Create and link the structure
5146      */
5147     templ = xsltNewTemplate();
5148     if (templ == NULL)
5149 	return;
5150 
5151     xsltCompilerNodePush(cctxt, templNode);
5152     if (templNode->nsDef != NULL)
5153 	cctxt->inode->inScopeNs =
5154 	    xsltCompilerBuildInScopeNsList(cctxt, templNode);
5155 
5156     templ->next = cctxt->style->templates;
5157     cctxt->style->templates = templ;
5158     templ->style = cctxt->style;
5159 
5160     /*
5161     * Attribute "mode".
5162     */
5163     prop = xmlGetNsProp(templNode, (const xmlChar *)"mode", NULL);
5164     if (prop != NULL) {
5165         const xmlChar *modeURI;
5166 
5167 	/*
5168 	* TODO: We need a standardized function for extraction
5169 	*  of namespace names and local names from QNames.
5170 	*  Don't use xsltGetQNameURI() as it cannot channel
5171 	*  reports through the context.
5172 	*/
5173 	modeURI = xsltGetQNameURI(templNode, &prop);
5174 	if (prop == NULL) {
5175 	    cctxt->style->errors++;
5176 	    goto error;
5177 	}
5178 	templ->mode = xmlDictLookup(cctxt->style->dict, prop, -1);
5179 	xmlFree(prop);
5180 	prop = NULL;
5181 	if (xmlValidateNCName(templ->mode, 0)) {
5182 	    xsltTransformError(NULL, cctxt->style, templNode,
5183 		"xsl:template: Attribute 'mode': The local part '%s' "
5184 		"of the value is not a valid NCName.\n", templ->name);
5185 	    cctxt->style->errors++;
5186 	    goto error;
5187 	}
5188 	if (modeURI != NULL)
5189 	    templ->modeURI = xmlDictLookup(cctxt->style->dict, modeURI, -1);
5190 #ifdef WITH_XSLT_DEBUG_PARSING
5191 	xsltGenericDebug(xsltGenericDebugContext,
5192 	     "xsltParseXSLTTemplate: mode %s\n", templ->mode);
5193 #endif
5194     }
5195     /*
5196     * Attribute "match".
5197     */
5198     prop = xmlGetNsProp(templNode, (const xmlChar *)"match", NULL);
5199     if (prop != NULL) {
5200 	templ->match  = prop;
5201 	prop = NULL;
5202     }
5203     /*
5204     * Attribute "priority".
5205     */
5206     prop = xmlGetNsProp(templNode, (const xmlChar *)"priority", NULL);
5207     if (prop != NULL) {
5208 	priority = xmlXPathStringEvalNumber(prop);
5209 	templ->priority = (float) priority;
5210 	xmlFree(prop);
5211 	prop = NULL;
5212     }
5213     /*
5214     * Attribute "name".
5215     */
5216     prop = xmlGetNsProp(templNode, (const xmlChar *)"name", NULL);
5217     if (prop != NULL) {
5218         const xmlChar *nameURI;
5219 	xsltTemplatePtr curTempl;
5220 
5221 	/*
5222 	* TODO: Don't use xsltGetQNameURI().
5223 	*/
5224 	nameURI = xsltGetQNameURI(templNode, &prop);
5225 	if (prop == NULL) {
5226 	    cctxt->style->errors++;
5227 	    goto error;
5228 	}
5229 	templ->name = xmlDictLookup(cctxt->style->dict, prop, -1);
5230 	xmlFree(prop);
5231 	prop = NULL;
5232 	if (xmlValidateNCName(templ->name, 0)) {
5233 	    xsltTransformError(NULL, cctxt->style, templNode,
5234 		"xsl:template: Attribute 'name': The local part '%s' of "
5235 		"the value is not a valid NCName.\n", templ->name);
5236 	    cctxt->style->errors++;
5237 	    goto error;
5238 	}
5239 	if (nameURI != NULL)
5240 	    templ->nameURI = xmlDictLookup(cctxt->style->dict, nameURI, -1);
5241 	curTempl = templ->next;
5242 	while (curTempl != NULL) {
5243 	    if ((nameURI != NULL && xmlStrEqual(curTempl->name, templ->name) &&
5244 		xmlStrEqual(curTempl->nameURI, nameURI) ) ||
5245 		(nameURI == NULL && curTempl->nameURI == NULL &&
5246 		xmlStrEqual(curTempl->name, templ->name)))
5247 	    {
5248 		xsltTransformError(NULL, cctxt->style, templNode,
5249 		    "xsl:template: error duplicate name '%s'\n", templ->name);
5250 		cctxt->style->errors++;
5251 		goto error;
5252 	    }
5253 	    curTempl = curTempl->next;
5254 	}
5255     }
5256     if (templNode->children != NULL) {
5257 	xsltParseTemplateContent(cctxt->style, templNode);
5258 	/*
5259 	* MAYBE TODO: Custom behaviour: In order to stay compatible with
5260 	* Xalan and MSXML(.NET), we could allow whitespace
5261 	* to appear before an xml:param element; this whitespace
5262 	* will additionally become part of the "template".
5263 	* NOTE that this is totally deviates from the spec, but
5264 	* is the de facto behaviour of Xalan and MSXML(.NET).
5265 	* Personally I wouldn't allow this, since if we have:
5266 	* <xsl:template ...xml:space="preserve">
5267 	*   <xsl:param name="foo"/>
5268 	*   <xsl:param name="bar"/>
5269 	*   <xsl:param name="zoo"/>
5270 	* ... the whitespace between every xsl:param would be
5271 	* added to the result tree.
5272 	*/
5273     }
5274 
5275     templ->elem = templNode;
5276     templ->content = templNode->children;
5277     xsltAddTemplate(cctxt->style, templ, templ->mode, templ->modeURI);
5278 
5279 error:
5280     xsltCompilerNodePop(cctxt, templNode);
5281     return;
5282 }
5283 
5284 #else /* XSLT_REFACTORED */
5285 
5286 /**
5287  * xsltParseStylesheetTemplate:
5288  * @style:  the XSLT stylesheet
5289  * @template:  the "template" element
5290  *
5291  * parse an XSLT stylesheet template building the associated structures
5292  */
5293 
5294 static void
xsltParseStylesheetTemplate(xsltStylesheetPtr style,xmlNodePtr template)5295 xsltParseStylesheetTemplate(xsltStylesheetPtr style, xmlNodePtr template) {
5296     xsltTemplatePtr ret;
5297     xmlChar *prop;
5298     xmlChar *mode = NULL;
5299     xmlChar *modeURI = NULL;
5300     double  priority;
5301 
5302     if (template == NULL)
5303 	return;
5304 
5305     /*
5306      * Create and link the structure
5307      */
5308     ret = xsltNewTemplate();
5309     if (ret == NULL)
5310 	return;
5311     ret->next = style->templates;
5312     style->templates = ret;
5313     ret->style = style;
5314 
5315     /*
5316      * Get inherited namespaces
5317      */
5318     /*
5319     * TODO: Apply the optimized in-scope-namespace mechanism
5320     *   as for the other XSLT instructions.
5321     */
5322     xsltGetInheritedNsList(style, ret, template);
5323 
5324     /*
5325      * Get arguments
5326      */
5327     prop = xmlGetNsProp(template, (const xmlChar *)"mode", NULL);
5328     if (prop != NULL) {
5329         const xmlChar *URI;
5330 
5331 	/*
5332 	* TODO: Don't use xsltGetQNameURI().
5333 	*/
5334 	URI = xsltGetQNameURI(template, &prop);
5335 	if (prop == NULL) {
5336 	    if (style != NULL) style->errors++;
5337 	    goto error;
5338 	} else {
5339 	    mode = prop;
5340 	    if (URI != NULL)
5341 		modeURI = xmlStrdup(URI);
5342 	}
5343 	ret->mode = xmlDictLookup(style->dict, mode, -1);
5344 	ret->modeURI = xmlDictLookup(style->dict, modeURI, -1);
5345 #ifdef WITH_XSLT_DEBUG_PARSING
5346 	xsltGenericDebug(xsltGenericDebugContext,
5347 	     "xsltParseStylesheetTemplate: mode %s\n", mode);
5348 #endif
5349         if (mode != NULL) xmlFree(mode);
5350 	if (modeURI != NULL) xmlFree(modeURI);
5351     }
5352     prop = xmlGetNsProp(template, (const xmlChar *)"match", NULL);
5353     if (prop != NULL) {
5354 	if (ret->match != NULL) xmlFree(ret->match);
5355 	ret->match  = prop;
5356     }
5357 
5358     prop = xmlGetNsProp(template, (const xmlChar *)"priority", NULL);
5359     if (prop != NULL) {
5360 	priority = xmlXPathStringEvalNumber(prop);
5361 	ret->priority = (float) priority;
5362 	xmlFree(prop);
5363     }
5364 
5365     prop = xmlGetNsProp(template, (const xmlChar *)"name", NULL);
5366     if (prop != NULL) {
5367         const xmlChar *URI;
5368 	xsltTemplatePtr cur;
5369 
5370 	/*
5371 	* TODO: Don't use xsltGetQNameURI().
5372 	*/
5373 	URI = xsltGetQNameURI(template, &prop);
5374 	if (prop == NULL) {
5375 	    if (style != NULL) style->errors++;
5376 	    goto error;
5377 	} else {
5378 	    if (xmlValidateNCName(prop,0)) {
5379 	        xsltTransformError(NULL, style, template,
5380 	            "xsl:template : error invalid name '%s'\n", prop);
5381 		if (style != NULL) style->errors++;
5382 		goto error;
5383 	    }
5384 	    ret->name = xmlDictLookup(style->dict, BAD_CAST prop, -1);
5385 	    xmlFree(prop);
5386 	    prop = NULL;
5387 	    if (URI != NULL)
5388 		ret->nameURI = xmlDictLookup(style->dict, BAD_CAST URI, -1);
5389 	    else
5390 		ret->nameURI = NULL;
5391 	    cur = ret->next;
5392 	    while (cur != NULL) {
5393 	        if ((URI != NULL && xmlStrEqual(cur->name, ret->name) &&
5394 				xmlStrEqual(cur->nameURI, URI) ) ||
5395 		    (URI == NULL && cur->nameURI == NULL &&
5396 				xmlStrEqual(cur->name, ret->name))) {
5397 		    xsltTransformError(NULL, style, template,
5398 		        "xsl:template: error duplicate name '%s'\n", ret->name);
5399 		    style->errors++;
5400 		    goto error;
5401 		}
5402 		cur = cur->next;
5403 	    }
5404 	}
5405     }
5406 
5407     /*
5408      * parse the content and register the pattern
5409      */
5410     xsltParseTemplateContent(style, template);
5411     ret->elem = template;
5412     ret->content = template->children;
5413     xsltAddTemplate(style, ret, ret->mode, ret->modeURI);
5414 
5415 error:
5416     return;
5417 }
5418 
5419 #endif /* else XSLT_REFACTORED */
5420 
5421 #ifdef XSLT_REFACTORED
5422 
5423 /**
5424  * xsltIncludeComp:
5425  * @cctxt: the compilation contenxt
5426  * @node:  the xsl:include node
5427  *
5428  * Process the xslt include node on the source node
5429  */
5430 static xsltStyleItemIncludePtr
xsltCompileXSLTIncludeElem(xsltCompilerCtxtPtr cctxt,xmlNodePtr node)5431 xsltCompileXSLTIncludeElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) {
5432     xsltStyleItemIncludePtr item;
5433 
5434     if ((cctxt == NULL) || (node == NULL))
5435 	return(NULL);
5436 
5437     node->psvi = NULL;
5438     item = (xsltStyleItemIncludePtr) xmlMalloc(sizeof(xsltStyleItemInclude));
5439     if (item == NULL) {
5440 	xsltTransformError(NULL, cctxt->style, node,
5441 		"xsltIncludeComp : malloc failed\n");
5442 	cctxt->style->errors++;
5443 	return(NULL);
5444     }
5445     memset(item, 0, sizeof(xsltStyleItemInclude));
5446 
5447     node->psvi = item;
5448     item->inst = node;
5449     item->type = XSLT_FUNC_INCLUDE;
5450 
5451     item->next = cctxt->style->preComps;
5452     cctxt->style->preComps = (xsltElemPreCompPtr) item;
5453 
5454     return(item);
5455 }
5456 
5457 /**
5458  * xsltParseFindTopLevelElem:
5459  */
5460 static int
xsltParseFindTopLevelElem(xsltCompilerCtxtPtr cctxt,xmlNodePtr cur,const xmlChar * name,const xmlChar * namespaceURI,int breakOnOtherElem,xmlNodePtr * resultNode)5461 xsltParseFindTopLevelElem(xsltCompilerCtxtPtr cctxt,
5462 			      xmlNodePtr cur,
5463 			      const xmlChar *name,
5464 			      const xmlChar *namespaceURI,
5465 			      int breakOnOtherElem,
5466 			      xmlNodePtr *resultNode)
5467 {
5468     if (name == NULL)
5469 	return(-1);
5470 
5471     *resultNode = NULL;
5472     while (cur != NULL) {
5473 	if (cur->type == XML_ELEMENT_NODE) {
5474 	    if ((cur->ns != NULL) && (cur->name != NULL)) {
5475 		if ((*(cur->name) == *name) &&
5476 		    xmlStrEqual(cur->name, name) &&
5477 		    xmlStrEqual(cur->ns->href, namespaceURI))
5478 		{
5479 		    *resultNode = cur;
5480 		    return(1);
5481 		}
5482 	    }
5483 	    if (breakOnOtherElem)
5484 		break;
5485 	}
5486 	cur = cur->next;
5487     }
5488     *resultNode = cur;
5489     return(0);
5490 }
5491 
5492 static int
xsltParseTopLevelXSLTElem(xsltCompilerCtxtPtr cctxt,xmlNodePtr node,xsltStyleType type)5493 xsltParseTopLevelXSLTElem(xsltCompilerCtxtPtr cctxt,
5494 			  xmlNodePtr node,
5495 			  xsltStyleType type)
5496 {
5497     int ret = 0;
5498 
5499     /*
5500     * TODO: The reason why this function exists:
5501     *  due to historical reasons some of the
5502     *  top-level declarations are processed by functions
5503     *  in other files. Since we need still to set
5504     *  up the node-info and generate information like
5505     *  in-scope namespaces, this is a wrapper around
5506     *  those old parsing functions.
5507     */
5508     xsltCompilerNodePush(cctxt, node);
5509     if (node->nsDef != NULL)
5510 	cctxt->inode->inScopeNs =
5511 	    xsltCompilerBuildInScopeNsList(cctxt, node);
5512     cctxt->inode->type = type;
5513 
5514     switch (type) {
5515 	case XSLT_FUNC_INCLUDE:
5516 	    {
5517 		int oldIsInclude;
5518 
5519 		if (xsltCompileXSLTIncludeElem(cctxt, node) == NULL)
5520 		    goto exit;
5521 		/*
5522 		* Mark this stylesheet tree as being currently included.
5523 		*/
5524 		oldIsInclude = cctxt->isInclude;
5525 		cctxt->isInclude = 1;
5526 
5527 		if (xsltParseStylesheetInclude(cctxt->style, node) != 0) {
5528 		    cctxt->style->errors++;
5529 		}
5530 		cctxt->isInclude = oldIsInclude;
5531 	    }
5532 	    break;
5533 	case XSLT_FUNC_PARAM:
5534 	    xsltStylePreCompute(cctxt->style, node);
5535 	    xsltParseGlobalParam(cctxt->style, node);
5536 	    break;
5537 	case XSLT_FUNC_VARIABLE:
5538 	    xsltStylePreCompute(cctxt->style, node);
5539 	    xsltParseGlobalVariable(cctxt->style, node);
5540 	    break;
5541 	case XSLT_FUNC_ATTRSET:
5542 	    xsltParseStylesheetAttributeSet(cctxt->style, node);
5543 	    break;
5544 	default:
5545 	    xsltTransformError(NULL, cctxt->style, node,
5546 		"Internal error: (xsltParseTopLevelXSLTElem) "
5547 		"Cannot handle this top-level declaration.\n");
5548 	    cctxt->style->errors++;
5549 	    ret = -1;
5550     }
5551 
5552 exit:
5553     xsltCompilerNodePop(cctxt, node);
5554 
5555     return(ret);
5556 }
5557 
5558 #if 0
5559 static int
5560 xsltParseRemoveWhitespace(xmlNodePtr node)
5561 {
5562     if ((node == NULL) || (node->children == NULL))
5563 	return(0);
5564     else {
5565 	xmlNodePtr delNode = NULL, child = node->children;
5566 
5567 	do {
5568 	    if (delNode) {
5569 		xmlUnlinkNode(delNode);
5570 		xmlFreeNode(delNode);
5571 		delNode = NULL;
5572 	    }
5573 	    if (((child->type == XML_TEXT_NODE) ||
5574 		 (child->type == XML_CDATA_SECTION_NODE)) &&
5575 		(IS_BLANK_NODE(child)))
5576 		delNode = child;
5577 	    child = child->next;
5578 	} while (child != NULL);
5579 	if (delNode) {
5580 	    xmlUnlinkNode(delNode);
5581 	    xmlFreeNode(delNode);
5582 	    delNode = NULL;
5583 	}
5584     }
5585     return(0);
5586 }
5587 #endif
5588 
5589 static int
xsltParseXSLTStylesheetElemCore(xsltCompilerCtxtPtr cctxt,xmlNodePtr node)5590 xsltParseXSLTStylesheetElemCore(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
5591 {
5592 #ifdef WITH_XSLT_DEBUG_PARSING
5593     int templates = 0;
5594 #endif
5595     xmlNodePtr cur, start = NULL;
5596     xsltStylesheetPtr style;
5597 
5598     if ((cctxt == NULL) || (node == NULL) ||
5599 	(node->type != XML_ELEMENT_NODE))
5600 	return(-1);
5601 
5602     style = cctxt->style;
5603     /*
5604     * At this stage all import declarations of all stylesheet modules
5605     * with the same stylesheet level have been processed.
5606     * Now we can safely parse the rest of the declarations.
5607     */
5608     if (IS_XSLT_ELEM_FAST(node) && IS_XSLT_NAME(node, "include"))
5609     {
5610 	xsltDocumentPtr include;
5611 	/*
5612 	* URGENT TODO: Make this work with simplified stylesheets!
5613 	*   I.e., when we won't find an xsl:stylesheet element.
5614 	*/
5615 	/*
5616 	* This is as include declaration.
5617 	*/
5618 	include = ((xsltStyleItemIncludePtr) node->psvi)->include;
5619 	if (include == NULL) {
5620 	    /* TODO: raise error? */
5621 	    return(-1);
5622 	}
5623 	/*
5624 	* TODO: Actually an xsl:include should locate an embedded
5625 	*  stylesheet as well; so the document-element won't always
5626 	*  be the element where the actual stylesheet is rooted at.
5627 	*  But such embedded stylesheets are not supported by Libxslt yet.
5628 	*/
5629 	node = xmlDocGetRootElement(include->doc);
5630 	if (node == NULL) {
5631 	    return(-1);
5632 	}
5633     }
5634 
5635     if (node->children == NULL)
5636 	return(0);
5637     /*
5638     * Push the xsl:stylesheet/xsl:transform element.
5639     */
5640     xsltCompilerNodePush(cctxt, node);
5641     cctxt->inode->isRoot = 1;
5642     cctxt->inode->nsChanged = 0;
5643     /*
5644     * Start with the naked dummy info for literal result elements.
5645     */
5646     cctxt->inode->litResElemInfo = cctxt->inodeList->litResElemInfo;
5647 
5648     /*
5649     * In every case, we need to have
5650     * the in-scope namespaces of the element, where the
5651     * stylesheet is rooted at, regardless if it's an XSLT
5652     * instruction or a literal result instruction (or if
5653     * this is an embedded stylesheet).
5654     */
5655     cctxt->inode->inScopeNs =
5656 	xsltCompilerBuildInScopeNsList(cctxt, node);
5657 
5658     /*
5659     * Process attributes of xsl:stylesheet/xsl:transform.
5660     * --------------------------------------------------
5661     * Allowed are:
5662     *  id = id
5663     *  extension-element-prefixes = tokens
5664     *  exclude-result-prefixes = tokens
5665     *  version = number (mandatory)
5666     */
5667     if (xsltParseAttrXSLTVersion(cctxt, node,
5668 	XSLT_ELEMENT_CATEGORY_XSLT) == 0)
5669     {
5670 	/*
5671 	* Attribute "version".
5672 	* XSLT 1.0: "An xsl:stylesheet element *must* have a version
5673 	*  attribute, indicating the version of XSLT that the
5674 	*  stylesheet requires".
5675 	* The root element of a simplified stylesheet must also have
5676 	* this attribute.
5677 	*/
5678 #ifdef XSLT_REFACTORED_MANDATORY_VERSION
5679 	if (isXsltElem)
5680 	    xsltTransformError(NULL, cctxt->style, node,
5681 		"The attribute 'version' is missing.\n");
5682 	cctxt->style->errors++;
5683 #else
5684 	/* OLD behaviour. */
5685 	xsltTransformError(NULL, cctxt->style, node,
5686 	    "xsl:version is missing: document may not be a stylesheet\n");
5687 	cctxt->style->warnings++;
5688 #endif
5689     }
5690     /*
5691     * The namespaces declared by the attributes
5692     *  "extension-element-prefixes" and
5693     *  "exclude-result-prefixes" are local to *this*
5694     *  stylesheet tree; i.e., they are *not* visible to
5695     *  other stylesheet-modules, whether imported or included.
5696     *
5697     * Attribute "extension-element-prefixes".
5698     */
5699     cctxt->inode->extElemNs =
5700 	xsltParseExtElemPrefixes(cctxt, node, NULL,
5701 	    XSLT_ELEMENT_CATEGORY_XSLT);
5702     /*
5703     * Attribute "exclude-result-prefixes".
5704     */
5705     cctxt->inode->exclResultNs =
5706 	xsltParseExclResultPrefixes(cctxt, node, NULL,
5707 	    XSLT_ELEMENT_CATEGORY_XSLT);
5708     /*
5709     * Create/reuse info for the literal result element.
5710     */
5711     if (cctxt->inode->nsChanged)
5712 	xsltLREInfoCreate(cctxt, node, 0);
5713     /*
5714     * Processed top-level elements:
5715     * ----------------------------
5716     *  xsl:variable, xsl:param (QName, in-scope ns,
5717     *    expression (vars allowed))
5718     *  xsl:attribute-set (QName, in-scope ns)
5719     *  xsl:strip-space, xsl:preserve-space (XPath NameTests,
5720     *    in-scope ns)
5721     *    I *think* global scope, merge with includes
5722     *  xsl:output (QName, in-scope ns)
5723     *  xsl:key (QName, in-scope ns, pattern,
5724     *    expression (vars *not* allowed))
5725     *  xsl:decimal-format (QName, needs in-scope ns)
5726     *  xsl:namespace-alias (in-scope ns)
5727     *    global scope, merge with includes
5728     *  xsl:template (last, QName, pattern)
5729     *
5730     * (whitespace-only text-nodes have *not* been removed
5731     *  yet; this will be done in xsltParseSequenceConstructor)
5732     *
5733     * Report misplaced child-nodes first.
5734     */
5735     cur = node->children;
5736     while (cur != NULL) {
5737 	if (cur->type == XML_TEXT_NODE) {
5738 	    xsltTransformError(NULL, style, cur,
5739 		"Misplaced text node (content: '%s').\n",
5740 		(cur->content != NULL) ? cur->content : BAD_CAST "");
5741 	    style->errors++;
5742 	} else if (cur->type != XML_ELEMENT_NODE) {
5743 	    xsltTransformError(NULL, style, cur, "Misplaced node.\n");
5744 	    style->errors++;
5745 	}
5746 	cur = cur->next;
5747     }
5748     /*
5749     * Skip xsl:import elements; they have been processed
5750     * already.
5751     */
5752     cur = node->children;
5753     while ((cur != NULL) && xsltParseFindTopLevelElem(cctxt, cur,
5754 	    BAD_CAST "import", XSLT_NAMESPACE, 1, &cur) == 1)
5755 	cur = cur->next;
5756     if (cur == NULL)
5757 	goto exit;
5758 
5759     start = cur;
5760     /*
5761     * Process all top-level xsl:param elements.
5762     */
5763     while ((cur != NULL) &&
5764 	xsltParseFindTopLevelElem(cctxt, cur,
5765 	BAD_CAST "param", XSLT_NAMESPACE, 0, &cur) == 1)
5766     {
5767 	xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_PARAM);
5768 	cur = cur->next;
5769     }
5770     /*
5771     * Process all top-level xsl:variable elements.
5772     */
5773     cur = start;
5774     while ((cur != NULL) &&
5775 	xsltParseFindTopLevelElem(cctxt, cur,
5776 	BAD_CAST "variable", XSLT_NAMESPACE, 0, &cur) == 1)
5777     {
5778 	xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_VARIABLE);
5779 	cur = cur->next;
5780     }
5781     /*
5782     * Process all the rest of top-level elements.
5783     */
5784     cur = start;
5785     while (cur != NULL) {
5786 	/*
5787 	* Process element nodes.
5788 	*/
5789 	if (cur->type == XML_ELEMENT_NODE) {
5790 	    if (cur->ns == NULL) {
5791 		xsltTransformError(NULL, style, cur,
5792 		    "Unexpected top-level element in no namespace.\n");
5793 		style->errors++;
5794 		cur = cur->next;
5795 		continue;
5796 	    }
5797 	    /*
5798 	    * Process all XSLT elements.
5799 	    */
5800 	    if (IS_XSLT_ELEM_FAST(cur)) {
5801 		/*
5802 		* xsl:import is only allowed at the beginning.
5803 		*/
5804 		if (IS_XSLT_NAME(cur, "import")) {
5805 		    xsltTransformError(NULL, style, cur,
5806 			"Misplaced xsl:import element.\n");
5807 		    style->errors++;
5808 		    cur = cur->next;
5809 		    continue;
5810 		}
5811 		/*
5812 		* TODO: Change the return type of the parsing functions
5813 		*  to int.
5814 		*/
5815 		if (IS_XSLT_NAME(cur, "template")) {
5816 #ifdef WITH_XSLT_DEBUG_PARSING
5817 		    templates++;
5818 #endif
5819 		    /*
5820 		    * TODO: Is the position of xsl:template in the
5821 		    *  tree significant? If not it would be easier to
5822 		    *  parse them at a later stage.
5823 		    */
5824 		    xsltParseXSLTTemplate(cctxt, cur);
5825 		} else if (IS_XSLT_NAME(cur, "variable")) {
5826 		    /* NOP; done already */
5827 		} else if (IS_XSLT_NAME(cur, "param")) {
5828 		    /* NOP; done already */
5829 		} else if (IS_XSLT_NAME(cur, "include")) {
5830 		    if (cur->psvi != NULL)
5831 			xsltParseXSLTStylesheetElemCore(cctxt, cur);
5832 		    else {
5833 			xsltTransformError(NULL, style, cur,
5834 			    "Internal error: "
5835 			    "(xsltParseXSLTStylesheetElemCore) "
5836 			    "The xsl:include element was not compiled.\n");
5837 			style->errors++;
5838 		    }
5839 		} else if (IS_XSLT_NAME(cur, "strip-space")) {
5840 		    /* No node info needed. */
5841 		    xsltParseStylesheetStripSpace(style, cur);
5842 		} else if (IS_XSLT_NAME(cur, "preserve-space")) {
5843 		    /* No node info needed. */
5844 		    xsltParseStylesheetPreserveSpace(style, cur);
5845 		} else if (IS_XSLT_NAME(cur, "output")) {
5846 		    /* No node-info needed. */
5847 		    xsltParseStylesheetOutput(style, cur);
5848 		} else if (IS_XSLT_NAME(cur, "key")) {
5849 		    /* TODO: node-info needed for expressions ? */
5850 		    xsltParseStylesheetKey(style, cur);
5851 		} else if (IS_XSLT_NAME(cur, "decimal-format")) {
5852 		    /* No node-info needed. */
5853 		    xsltParseStylesheetDecimalFormat(style, cur);
5854 		} else if (IS_XSLT_NAME(cur, "attribute-set")) {
5855 		    xsltParseTopLevelXSLTElem(cctxt, cur,
5856 			XSLT_FUNC_ATTRSET);
5857 		} else if (IS_XSLT_NAME(cur, "namespace-alias")) {
5858 		    /* NOP; done already */
5859 		} else {
5860 		    if (cctxt->inode->forwardsCompat) {
5861 			/*
5862 			* Forwards-compatible mode:
5863 			*
5864 			* XSLT-1: "if it is a top-level element and
5865 			*  XSLT 1.0 does not allow such elements as top-level
5866 			*  elements, then the element must be ignored along
5867 			*  with its content;"
5868 			*/
5869 			/*
5870 			* TODO: I don't think we should generate a warning.
5871 			*/
5872 			xsltTransformError(NULL, style, cur,
5873 			    "Forwards-compatible mode: Ignoring unknown XSLT "
5874 			    "element '%s'.\n", cur->name);
5875 			style->warnings++;
5876 		    } else {
5877 			xsltTransformError(NULL, style, cur,
5878 			    "Unknown XSLT element '%s'.\n", cur->name);
5879 			style->errors++;
5880 		    }
5881 		}
5882 	    } else {
5883 		xsltTopLevelFunction function;
5884 
5885 		/*
5886 		* Process non-XSLT elements, which are in a
5887 		*  non-NULL namespace.
5888 		*/
5889 		/*
5890 		* QUESTION: What does xsltExtModuleTopLevelLookup()
5891 		*  do exactly?
5892 		*/
5893 		function = xsltExtModuleTopLevelLookup(cur->name,
5894 		    cur->ns->href);
5895 		if (function != NULL)
5896 		    function(style, cur);
5897 #ifdef WITH_XSLT_DEBUG_PARSING
5898 		xsltGenericDebug(xsltGenericDebugContext,
5899 		    "xsltParseXSLTStylesheetElemCore : User-defined "
5900 		    "data element '%s'.\n", cur->name);
5901 #endif
5902 	    }
5903 	}
5904 	cur = cur->next;
5905     }
5906 
5907 exit:
5908 
5909 #ifdef WITH_XSLT_DEBUG_PARSING
5910     xsltGenericDebug(xsltGenericDebugContext,
5911 	"### END of parsing top-level elements of doc '%s'.\n",
5912 	node->doc->URL);
5913     xsltGenericDebug(xsltGenericDebugContext,
5914 	"### Templates: %d\n", templates);
5915 #ifdef XSLT_REFACTORED
5916     xsltGenericDebug(xsltGenericDebugContext,
5917 	"### Max inodes: %d\n", cctxt->maxNodeInfos);
5918     xsltGenericDebug(xsltGenericDebugContext,
5919 	"### Max LREs  : %d\n", cctxt->maxLREs);
5920 #endif /* XSLT_REFACTORED */
5921 #endif /* WITH_XSLT_DEBUG_PARSING */
5922 
5923     xsltCompilerNodePop(cctxt, node);
5924     return(0);
5925 }
5926 
5927 /**
5928  * xsltParseXSLTStylesheet:
5929  * @cctxt: the compiler context
5930  * @node: the xsl:stylesheet/xsl:transform element-node
5931  *
5932  * Parses the xsl:stylesheet and xsl:transform element.
5933  *
5934  * <xsl:stylesheet
5935  *  id = id
5936  *  extension-element-prefixes = tokens
5937  *  exclude-result-prefixes = tokens
5938  *  version = number>
5939  *  <!-- Content: (xsl:import*, top-level-elements) -->
5940  * </xsl:stylesheet>
5941  *
5942  * BIG TODO: The xsl:include stuff.
5943  *
5944  * Called by xsltParseStylesheetTree()
5945  *
5946  * Returns 0 on success, a positive result on errors and
5947  *         -1 on API or internal errors.
5948  */
5949 static int
xsltParseXSLTStylesheetElem(xsltCompilerCtxtPtr cctxt,xmlNodePtr node)5950 xsltParseXSLTStylesheetElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
5951 {
5952     xmlNodePtr cur, start;
5953 
5954     if ((cctxt == NULL) || (node == NULL))
5955 	return(-1);
5956 
5957     if (node->children == NULL)
5958 	goto exit;
5959 
5960     /*
5961     * Process top-level elements:
5962     *  xsl:import (must be first)
5963     *  xsl:include (this is just a pre-processing)
5964     */
5965     cur = node->children;
5966     /*
5967     * Process xsl:import elements.
5968     * XSLT 1.0: "The xsl:import element children must precede all
5969     *  other element children of an xsl:stylesheet element,
5970     *  including any xsl:include element children."
5971     */
5972     while ((cur != NULL) &&
5973 	xsltParseFindTopLevelElem(cctxt, cur,
5974 	    BAD_CAST "import", XSLT_NAMESPACE, 1, &cur) == 1)
5975     {
5976 	if (xsltParseStylesheetImport(cctxt->style, cur) != 0) {
5977 	    cctxt->style->errors++;
5978 	}
5979 	cur = cur->next;
5980     }
5981     if (cur == NULL)
5982 	goto exit;
5983     start = cur;
5984     /*
5985     * Pre-process all xsl:include elements.
5986     */
5987     cur = start;
5988     while ((cur != NULL) &&
5989 	xsltParseFindTopLevelElem(cctxt, cur,
5990 	    BAD_CAST "include", XSLT_NAMESPACE, 0, &cur) == 1)
5991     {
5992 	xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_INCLUDE);
5993 	cur = cur->next;
5994     }
5995     /*
5996     * Pre-process all xsl:namespace-alias elements.
5997     * URGENT TODO: This won't work correctly: the order of included
5998     *  aliases and aliases defined here is significant.
5999     */
6000     cur = start;
6001     while ((cur != NULL) &&
6002 	xsltParseFindTopLevelElem(cctxt, cur,
6003 	    BAD_CAST "namespace-alias", XSLT_NAMESPACE, 0, &cur) == 1)
6004     {
6005 	xsltNamespaceAlias(cctxt->style, cur);
6006 	cur = cur->next;
6007     }
6008 
6009     if (cctxt->isInclude) {
6010 	/*
6011 	* If this stylesheet is intended for inclusion, then
6012 	* we will process only imports and includes.
6013 	*/
6014 	goto exit;
6015     }
6016     /*
6017     * Now parse the rest of the top-level elements.
6018     */
6019     xsltParseXSLTStylesheetElemCore(cctxt, node);
6020 exit:
6021 
6022     return(0);
6023 }
6024 
6025 #else /* XSLT_REFACTORED */
6026 
6027 /**
6028  * xsltParseStylesheetTop:
6029  * @style:  the XSLT stylesheet
6030  * @top:  the top level "stylesheet" or "transform" element
6031  *
6032  * scan the top level elements of an XSL stylesheet
6033  */
6034 static void
xsltParseStylesheetTop(xsltStylesheetPtr style,xmlNodePtr top)6035 xsltParseStylesheetTop(xsltStylesheetPtr style, xmlNodePtr top) {
6036     xmlNodePtr cur;
6037     xmlChar *prop;
6038 #ifdef WITH_XSLT_DEBUG_PARSING
6039     int templates = 0;
6040 #endif
6041 
6042     if (top == NULL)
6043 	return;
6044 
6045     prop = xmlGetNsProp(top, (const xmlChar *)"version", NULL);
6046     if (prop == NULL) {
6047 	xsltTransformError(NULL, style, top,
6048 	    "xsl:version is missing: document may not be a stylesheet\n");
6049 	if (style != NULL) style->warnings++;
6050     } else {
6051 	if ((!xmlStrEqual(prop, (const xmlChar *)"1.0")) &&
6052             (!xmlStrEqual(prop, (const xmlChar *)"1.1"))) {
6053 	    xsltTransformError(NULL, style, top,
6054 		"xsl:version: only 1.0 features are supported\n");
6055 	     /* TODO set up compatibility when not XSLT 1.0 */
6056 	    if (style != NULL) style->warnings++;
6057 	}
6058 	xmlFree(prop);
6059     }
6060 
6061     /*
6062      * process xsl:import elements
6063      */
6064     cur = top->children;
6065     while (cur != NULL) {
6066 	    if (IS_BLANK_NODE(cur)) {
6067 		    cur = cur->next;
6068 		    continue;
6069 	    }
6070 	    if (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "import")) {
6071 		    if (xsltParseStylesheetImport(style, cur) != 0)
6072 			    if (style != NULL) style->errors++;
6073 	    } else
6074 		    break;
6075 	    cur = cur->next;
6076     }
6077 
6078     /*
6079      * process other top-level elements
6080      */
6081     while (cur != NULL) {
6082 	if (IS_BLANK_NODE(cur)) {
6083 	    cur = cur->next;
6084 	    continue;
6085 	}
6086 	if (cur->type == XML_TEXT_NODE) {
6087 	    if (cur->content != NULL) {
6088 		xsltTransformError(NULL, style, cur,
6089 		    "misplaced text node: '%s'\n", cur->content);
6090 	    }
6091 	    if (style != NULL) style->errors++;
6092             cur = cur->next;
6093 	    continue;
6094 	}
6095 	if ((cur->type == XML_ELEMENT_NODE) && (cur->ns == NULL)) {
6096 	    xsltGenericError(xsltGenericErrorContext,
6097 		     "Found a top-level element %s with null namespace URI\n",
6098 		     cur->name);
6099 	    if (style != NULL) style->errors++;
6100 	    cur = cur->next;
6101 	    continue;
6102 	}
6103 	if ((cur->type == XML_ELEMENT_NODE) && (!(IS_XSLT_ELEM(cur)))) {
6104 	    xsltTopLevelFunction function;
6105 
6106 	    function = xsltExtModuleTopLevelLookup(cur->name,
6107 						   cur->ns->href);
6108 	    if (function != NULL)
6109 		function(style, cur);
6110 
6111 #ifdef WITH_XSLT_DEBUG_PARSING
6112 	    xsltGenericDebug(xsltGenericDebugContext,
6113 		    "xsltParseStylesheetTop : found foreign element %s\n",
6114 		    cur->name);
6115 #endif
6116             cur = cur->next;
6117 	    continue;
6118 	}
6119 	if (IS_XSLT_NAME(cur, "import")) {
6120 	    xsltTransformError(NULL, style, cur,
6121 			"xsltParseStylesheetTop: ignoring misplaced import element\n");
6122 	    if (style != NULL) style->errors++;
6123     } else if (IS_XSLT_NAME(cur, "include")) {
6124 	    if (xsltParseStylesheetInclude(style, cur) != 0)
6125 		if (style != NULL) style->errors++;
6126     } else if (IS_XSLT_NAME(cur, "strip-space")) {
6127 	    xsltParseStylesheetStripSpace(style, cur);
6128     } else if (IS_XSLT_NAME(cur, "preserve-space")) {
6129 	    xsltParseStylesheetPreserveSpace(style, cur);
6130     } else if (IS_XSLT_NAME(cur, "output")) {
6131 	    xsltParseStylesheetOutput(style, cur);
6132     } else if (IS_XSLT_NAME(cur, "key")) {
6133 	    xsltParseStylesheetKey(style, cur);
6134     } else if (IS_XSLT_NAME(cur, "decimal-format")) {
6135 	    xsltParseStylesheetDecimalFormat(style, cur);
6136     } else if (IS_XSLT_NAME(cur, "attribute-set")) {
6137 	    xsltParseStylesheetAttributeSet(style, cur);
6138     } else if (IS_XSLT_NAME(cur, "variable")) {
6139 	    xsltParseGlobalVariable(style, cur);
6140     } else if (IS_XSLT_NAME(cur, "param")) {
6141 	    xsltParseGlobalParam(style, cur);
6142     } else if (IS_XSLT_NAME(cur, "template")) {
6143 #ifdef WITH_XSLT_DEBUG_PARSING
6144 	    templates++;
6145 #endif
6146 	    xsltParseStylesheetTemplate(style, cur);
6147     } else if (IS_XSLT_NAME(cur, "namespace-alias")) {
6148 	    xsltNamespaceAlias(style, cur);
6149 	} else {
6150 	    /*
6151 	    * BUG TODO: The version of the *doc* is irrelevant for
6152 	    *  the forwards-compatible mode.
6153 	    */
6154             if ((style != NULL) && (style->doc->version != NULL) &&
6155 	        (!strncmp((const char *) style->doc->version, "1.0", 3))) {
6156 	        xsltTransformError(NULL, style, cur,
6157 			"xsltParseStylesheetTop: unknown %s element\n",
6158 			cur->name);
6159 	        if (style != NULL) style->errors++;
6160 	    }
6161 	    else {
6162                 /* do Forwards-Compatible Processing */
6163 	        xsltTransformError(NULL, style, cur,
6164 			"xsltParseStylesheetTop: ignoring unknown %s element\n",
6165 			cur->name);
6166 	        if (style != NULL) style->warnings++;
6167             }
6168 	}
6169 	cur = cur->next;
6170     }
6171 #ifdef WITH_XSLT_DEBUG_PARSING
6172     xsltGenericDebug(xsltGenericDebugContext,
6173 		    "parsed %d templates\n", templates);
6174 #endif
6175 }
6176 
6177 #endif /* else of XSLT_REFACTORED */
6178 
6179 #ifdef XSLT_REFACTORED
6180 /**
6181  * xsltParseSimplifiedStylesheetTree:
6182  *
6183  * @style: the stylesheet (TODO: Change this to the compiler context)
6184  * @doc: the document containing the stylesheet.
6185  * @node: the node where the stylesheet is rooted at
6186  *
6187  * Returns 0 in case of success, a positive result if an error occurred
6188  *         and -1 on API and internal errors.
6189  */
6190 static int
xsltParseSimplifiedStylesheetTree(xsltCompilerCtxtPtr cctxt,xmlDocPtr doc,xmlNodePtr node)6191 xsltParseSimplifiedStylesheetTree(xsltCompilerCtxtPtr cctxt,
6192 				  xmlDocPtr doc,
6193 				  xmlNodePtr node)
6194 {
6195     xsltTemplatePtr templ;
6196 
6197     if ((cctxt == NULL) || (node == NULL))
6198 	return(-1);
6199 
6200     if (xsltParseAttrXSLTVersion(cctxt, node, 0) == XSLT_ELEMENT_CATEGORY_LRE)
6201     {
6202 	/*
6203 	* TODO: Adjust report, since this might be an
6204 	* embedded stylesheet.
6205 	*/
6206 	xsltTransformError(NULL, cctxt->style, node,
6207 	    "The attribute 'xsl:version' is missing; cannot identify "
6208 	    "this document as an XSLT stylesheet document.\n");
6209 	cctxt->style->errors++;
6210 	return(1);
6211     }
6212 
6213 #ifdef WITH_XSLT_DEBUG_PARSING
6214     xsltGenericDebug(xsltGenericDebugContext,
6215 	"xsltParseSimplifiedStylesheetTree: document is stylesheet\n");
6216 #endif
6217 
6218     /*
6219     * Create and link the template
6220     */
6221     templ = xsltNewTemplate();
6222     if (templ == NULL) {
6223 	return(-1);
6224     }
6225     templ->next = cctxt->style->templates;
6226     cctxt->style->templates = templ;
6227     templ->match = xmlStrdup(BAD_CAST "/");
6228 
6229     /*
6230     * Note that we push the document-node in this special case.
6231     */
6232     xsltCompilerNodePush(cctxt, (xmlNodePtr) doc);
6233     /*
6234     * In every case, we need to have
6235     * the in-scope namespaces of the element, where the
6236     * stylesheet is rooted at, regardless if it's an XSLT
6237     * instruction or a literal result instruction (or if
6238     * this is an embedded stylesheet).
6239     */
6240     cctxt->inode->inScopeNs =
6241 	xsltCompilerBuildInScopeNsList(cctxt, node);
6242     /*
6243     * Parse the content and register the match-pattern.
6244     */
6245     xsltParseSequenceConstructor(cctxt, node);
6246     xsltCompilerNodePop(cctxt, (xmlNodePtr) doc);
6247 
6248     templ->elem = (xmlNodePtr) doc;
6249     templ->content = node;
6250     xsltAddTemplate(cctxt->style, templ, NULL, NULL);
6251     cctxt->style->literal_result = 1;
6252     return(0);
6253 }
6254 
6255 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
6256 /**
6257  * xsltRestoreDocumentNamespaces:
6258  * @ns: map of namespaces
6259  * @doc: the document
6260  *
6261  * Restore the namespaces for the document
6262  *
6263  * Returns 0 in case of success, -1 in case of failure
6264  */
6265 int
xsltRestoreDocumentNamespaces(xsltNsMapPtr ns,xmlDocPtr doc)6266 xsltRestoreDocumentNamespaces(xsltNsMapPtr ns, xmlDocPtr doc)
6267 {
6268     if (doc == NULL)
6269 	return(-1);
6270     /*
6271     * Revert the changes we have applied to the namespace-URIs of
6272     * ns-decls.
6273     */
6274     while (ns != NULL) {
6275 	if ((ns->doc == doc) && (ns->ns != NULL)) {
6276 	    ns->ns->href = ns->origNsName;
6277 	    ns->origNsName = NULL;
6278 	    ns->ns = NULL;
6279 	}
6280 	ns = ns->next;
6281     }
6282     return(0);
6283 }
6284 #endif /* XSLT_REFACTORED_XSLT_NSCOMP */
6285 
6286 /**
6287  * xsltParseStylesheetProcess:
6288  * @style:  the XSLT stylesheet (the current stylesheet-level)
6289  * @doc:  and xmlDoc parsed XML
6290  *
6291  * Parses an XSLT stylesheet, adding the associated structures.
6292  * Called by:
6293  *  xsltParseStylesheetImportedDoc() (xslt.c)
6294  *  xsltParseStylesheetInclude() (imports.c)
6295  *
6296  * Returns the value of the @style parameter if everything
6297  * went right, NULL if something went amiss.
6298  */
6299 xsltStylesheetPtr
xsltParseStylesheetProcess(xsltStylesheetPtr style,xmlDocPtr doc)6300 xsltParseStylesheetProcess(xsltStylesheetPtr style, xmlDocPtr doc)
6301 {
6302     xsltCompilerCtxtPtr cctxt;
6303     xmlNodePtr cur;
6304     int oldIsSimplifiedStylesheet;
6305 
6306     xsltInitGlobals();
6307 
6308     if ((style == NULL) || (doc == NULL))
6309 	return(NULL);
6310 
6311     cctxt = XSLT_CCTXT(style);
6312 
6313     cur = xmlDocGetRootElement(doc);
6314     if (cur == NULL) {
6315 	xsltTransformError(NULL, style, (xmlNodePtr) doc,
6316 		"xsltParseStylesheetProcess : empty stylesheet\n");
6317 	return(NULL);
6318     }
6319     oldIsSimplifiedStylesheet = cctxt->simplified;
6320 
6321     if ((IS_XSLT_ELEM(cur)) &&
6322 	((IS_XSLT_NAME(cur, "stylesheet")) ||
6323 	 (IS_XSLT_NAME(cur, "transform")))) {
6324 #ifdef WITH_XSLT_DEBUG_PARSING
6325 	xsltGenericDebug(xsltGenericDebugContext,
6326 		"xsltParseStylesheetProcess : found stylesheet\n");
6327 #endif
6328 	cctxt->simplified = 0;
6329 	style->literal_result = 0;
6330     } else {
6331 	cctxt->simplified = 1;
6332 	style->literal_result = 1;
6333     }
6334     /*
6335     * Pre-process the stylesheet if not already done before.
6336     *  This will remove PIs and comments, merge adjacent
6337     *  text nodes, internalize strings, etc.
6338     */
6339     if (! style->nopreproc)
6340 	xsltParsePreprocessStylesheetTree(cctxt, cur);
6341     /*
6342     * Parse and compile the stylesheet.
6343     */
6344     if (style->literal_result == 0) {
6345 	if (xsltParseXSLTStylesheetElem(cctxt, cur) != 0)
6346 	    return(NULL);
6347     } else {
6348 	if (xsltParseSimplifiedStylesheetTree(cctxt, doc, cur) != 0)
6349 	    return(NULL);
6350     }
6351 
6352     cctxt->simplified = oldIsSimplifiedStylesheet;
6353 
6354     return(style);
6355 }
6356 
6357 #else /* XSLT_REFACTORED */
6358 
6359 /**
6360  * xsltParseStylesheetProcess:
6361  * @ret:  the XSLT stylesheet (the current stylesheet-level)
6362  * @doc:  and xmlDoc parsed XML
6363  *
6364  * Parses an XSLT stylesheet, adding the associated structures.
6365  * Called by:
6366  *  xsltParseStylesheetImportedDoc() (xslt.c)
6367  *  xsltParseStylesheetInclude() (imports.c)
6368  *
6369  * Returns the value of the @style parameter if everything
6370  * went right, NULL if something went amiss.
6371  */
6372 xsltStylesheetPtr
xsltParseStylesheetProcess(xsltStylesheetPtr ret,xmlDocPtr doc)6373 xsltParseStylesheetProcess(xsltStylesheetPtr ret, xmlDocPtr doc) {
6374     xmlNodePtr cur;
6375 
6376     xsltInitGlobals();
6377 
6378     if (doc == NULL)
6379 	return(NULL);
6380     if (ret == NULL)
6381 	return(ret);
6382 
6383     /*
6384      * First steps, remove blank nodes,
6385      * locate the xsl:stylesheet element and the
6386      * namespace declaration.
6387      */
6388     cur = xmlDocGetRootElement(doc);
6389     if (cur == NULL) {
6390 	xsltTransformError(NULL, ret, (xmlNodePtr) doc,
6391 		"xsltParseStylesheetProcess : empty stylesheet\n");
6392 	return(NULL);
6393     }
6394 
6395     if ((IS_XSLT_ELEM(cur)) &&
6396 	((IS_XSLT_NAME(cur, "stylesheet")) ||
6397 	 (IS_XSLT_NAME(cur, "transform")))) {
6398 #ifdef WITH_XSLT_DEBUG_PARSING
6399 	xsltGenericDebug(xsltGenericDebugContext,
6400 		"xsltParseStylesheetProcess : found stylesheet\n");
6401 #endif
6402 	ret->literal_result = 0;
6403 	xsltParseStylesheetExcludePrefix(ret, cur, 1);
6404 	xsltParseStylesheetExtPrefix(ret, cur, 1);
6405     } else {
6406 	xsltParseStylesheetExcludePrefix(ret, cur, 0);
6407 	xsltParseStylesheetExtPrefix(ret, cur, 0);
6408 	ret->literal_result = 1;
6409     }
6410     if (!ret->nopreproc) {
6411 	xsltPrecomputeStylesheet(ret, cur);
6412     }
6413     if (ret->literal_result == 0) {
6414 	xsltParseStylesheetTop(ret, cur);
6415     } else {
6416 	xmlChar *prop;
6417 	xsltTemplatePtr template;
6418 
6419 	/*
6420 	 * the document itself might be the template, check xsl:version
6421 	 */
6422 	prop = xmlGetNsProp(cur, (const xmlChar *)"version", XSLT_NAMESPACE);
6423 	if (prop == NULL) {
6424 	    xsltTransformError(NULL, ret, cur,
6425 		"xsltParseStylesheetProcess : document is not a stylesheet\n");
6426 	    return(NULL);
6427 	}
6428 
6429 #ifdef WITH_XSLT_DEBUG_PARSING
6430         xsltGenericDebug(xsltGenericDebugContext,
6431 		"xsltParseStylesheetProcess : document is stylesheet\n");
6432 #endif
6433 
6434 	if (!xmlStrEqual(prop, (const xmlChar *)"1.0")) {
6435 	    xsltTransformError(NULL, ret, cur,
6436 		"xsl:version: only 1.0 features are supported\n");
6437 	     /* TODO set up compatibility when not XSLT 1.0 */
6438 	    ret->warnings++;
6439 	}
6440 	xmlFree(prop);
6441 
6442 	/*
6443 	 * Create and link the template
6444 	 */
6445 	template = xsltNewTemplate();
6446 	if (template == NULL) {
6447 	    return(NULL);
6448 	}
6449 	template->next = ret->templates;
6450 	ret->templates = template;
6451 	template->match = xmlStrdup((const xmlChar *)"/");
6452 
6453 	/*
6454 	 * parse the content and register the pattern
6455 	 */
6456 	xsltParseTemplateContent(ret, (xmlNodePtr) doc);
6457 	template->elem = (xmlNodePtr) doc;
6458 	template->content = doc->children;
6459 	xsltAddTemplate(ret, template, NULL, NULL);
6460 	ret->literal_result = 1;
6461     }
6462 
6463     return(ret);
6464 }
6465 
6466 #endif /* else of XSLT_REFACTORED */
6467 
6468 /**
6469  * xsltParseStylesheetImportedDoc:
6470  * @doc:  an xmlDoc parsed XML
6471  * @parentStyle: pointer to the parent stylesheet (if it exists)
6472  *
6473  * parse an XSLT stylesheet building the associated structures
6474  * except the processing not needed for imported documents.
6475  *
6476  * Returns a new XSLT stylesheet structure.
6477  */
6478 
6479 xsltStylesheetPtr
xsltParseStylesheetImportedDoc(xmlDocPtr doc,xsltStylesheetPtr parentStyle)6480 xsltParseStylesheetImportedDoc(xmlDocPtr doc,
6481 			       xsltStylesheetPtr parentStyle) {
6482     xsltStylesheetPtr retStyle;
6483 
6484     if (doc == NULL)
6485 	return(NULL);
6486 
6487     retStyle = xsltNewStylesheet();
6488     if (retStyle == NULL)
6489 	return(NULL);
6490     /*
6491     * Set the importing stylesheet module; also used to detect recursion.
6492     */
6493     retStyle->parent = parentStyle;
6494     /*
6495     * Adjust the string dict.
6496     */
6497     if (doc->dict != NULL) {
6498         xmlDictFree(retStyle->dict);
6499 	retStyle->dict = doc->dict;
6500 #ifdef WITH_XSLT_DEBUG
6501         xsltGenericDebug(xsltGenericDebugContext,
6502 	    "reusing dictionary from %s for stylesheet\n",
6503 	    doc->URL);
6504 #endif
6505 	xmlDictReference(retStyle->dict);
6506     }
6507 
6508     /*
6509     * TODO: Eliminate xsltGatherNamespaces(); we must not restrict
6510     *  the stylesheet to containt distinct namespace prefixes.
6511     */
6512     xsltGatherNamespaces(retStyle);
6513 
6514 #ifdef XSLT_REFACTORED
6515     {
6516 	xsltCompilerCtxtPtr cctxt;
6517 	xsltStylesheetPtr oldCurSheet;
6518 
6519 	if (parentStyle == NULL) {
6520 	    xsltPrincipalStylesheetDataPtr principalData;
6521 	    /*
6522 	    * Principal stylesheet
6523 	    * --------------------
6524 	    */
6525 	    retStyle->principal = retStyle;
6526 	    /*
6527 	    * Create extra data for the principal stylesheet.
6528 	    */
6529 	    principalData = xsltNewPrincipalStylesheetData();
6530 	    if (principalData == NULL) {
6531 		xsltFreeStylesheet(retStyle);
6532 		return(NULL);
6533 	    }
6534 	    retStyle->principalData = principalData;
6535 	    /*
6536 	    * Create the compilation context
6537 	    * ------------------------------
6538 	    * (only once; for the principal stylesheet).
6539 	    * This is currently the only function where the
6540 	    * compilation context is created.
6541 	    */
6542 	    cctxt = xsltCompilationCtxtCreate(retStyle);
6543 	    if (cctxt == NULL) {
6544 		xsltFreeStylesheet(retStyle);
6545 		return(NULL);
6546 	    }
6547 	    retStyle->compCtxt = (void *) cctxt;
6548 	    cctxt->style = retStyle;
6549 	    cctxt->dict = retStyle->dict;
6550 	    cctxt->psData = principalData;
6551 	    /*
6552 	    * Push initial dummy node info.
6553 	    */
6554 	    cctxt->depth = -1;
6555 	    xsltCompilerNodePush(cctxt, (xmlNodePtr) doc);
6556 	} else {
6557 	    /*
6558 	    * Imported stylesheet.
6559 	    */
6560 	    retStyle->principal = parentStyle->principal;
6561 	    cctxt = parentStyle->compCtxt;
6562 	    retStyle->compCtxt = cctxt;
6563 	}
6564 	/*
6565 	* Save the old and set the current stylesheet structure in the
6566 	* compilation context.
6567 	*/
6568 	oldCurSheet = cctxt->style;
6569 	cctxt->style = retStyle;
6570 
6571 	retStyle->doc = doc;
6572 	xsltParseStylesheetProcess(retStyle, doc);
6573 
6574 	cctxt->style = oldCurSheet;
6575 	if (parentStyle == NULL) {
6576 	    /*
6577 	    * Pop the initial dummy node info.
6578 	    */
6579 	    xsltCompilerNodePop(cctxt, (xmlNodePtr) doc);
6580 	} else {
6581 	    /*
6582 	    * Clear the compilation context of imported
6583 	    * stylesheets.
6584 	    * TODO: really?
6585 	    */
6586 	    /* retStyle->compCtxt = NULL; */
6587 	}
6588 	/*
6589 	* Free the stylesheet if there were errors.
6590 	*/
6591 	if (retStyle != NULL) {
6592 	    if (retStyle->errors != 0) {
6593 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
6594 		/*
6595 		* Restore all changes made to namespace URIs of ns-decls.
6596 		*/
6597 		if (cctxt->psData->nsMap)
6598 		    xsltRestoreDocumentNamespaces(cctxt->psData->nsMap, doc);
6599 #endif
6600 		/*
6601 		* Detach the doc from the stylesheet; otherwise the doc
6602 		* will be freed in xsltFreeStylesheet().
6603 		*/
6604 		retStyle->doc = NULL;
6605 		/*
6606 		* Cleanup the doc if its the main stylesheet.
6607 		*/
6608 		if (parentStyle == NULL) {
6609 		    xsltCleanupStylesheetTree(doc, xmlDocGetRootElement(doc));
6610 		    if (retStyle->compCtxt != NULL) {
6611 			xsltCompilationCtxtFree(retStyle->compCtxt);
6612 			retStyle->compCtxt = NULL;
6613 		    }
6614 		}
6615 
6616 		xsltFreeStylesheet(retStyle);
6617 		retStyle = NULL;
6618 	    }
6619 	}
6620     }
6621 
6622 #else /* XSLT_REFACTORED */
6623     /*
6624     * Old behaviour.
6625     */
6626     retStyle->doc = doc;
6627     if (xsltParseStylesheetProcess(retStyle, doc) == NULL) {
6628 		retStyle->doc = NULL;
6629 		xsltFreeStylesheet(retStyle);
6630 		retStyle = NULL;
6631     }
6632     if (retStyle != NULL) {
6633 	if (retStyle->errors != 0) {
6634 	    retStyle->doc = NULL;
6635 	    if (parentStyle == NULL)
6636 		xsltCleanupStylesheetTree(doc,
6637 		    xmlDocGetRootElement(doc));
6638 	    xsltFreeStylesheet(retStyle);
6639 	    retStyle = NULL;
6640 	}
6641     }
6642 #endif /* else of XSLT_REFACTORED */
6643 
6644     return(retStyle);
6645 }
6646 
6647 /**
6648  * xsltParseStylesheetDoc:
6649  * @doc:  and xmlDoc parsed XML
6650  *
6651  * parse an XSLT stylesheet, building the associated structures.  doc
6652  * is kept as a reference within the returned stylesheet, so changes
6653  * to doc after the parsing will be reflected when the stylesheet
6654  * is applied, and the doc is automatically freed when the
6655  * stylesheet is closed.
6656  *
6657  * Returns a new XSLT stylesheet structure.
6658  */
6659 
6660 xsltStylesheetPtr
xsltParseStylesheetDoc(xmlDocPtr doc)6661 xsltParseStylesheetDoc(xmlDocPtr doc) {
6662     xsltStylesheetPtr ret;
6663 
6664     xsltInitGlobals();
6665 
6666     ret = xsltParseStylesheetImportedDoc(doc, NULL);
6667     if (ret == NULL)
6668 	return(NULL);
6669 
6670     xsltResolveStylesheetAttributeSet(ret);
6671 #ifdef XSLT_REFACTORED
6672     /*
6673     * Free the compilation context.
6674     * TODO: Check if it's better to move this cleanup to
6675     *   xsltParseStylesheetImportedDoc().
6676     */
6677     if (ret->compCtxt != NULL) {
6678 	xsltCompilationCtxtFree(XSLT_CCTXT(ret));
6679 	ret->compCtxt = NULL;
6680     }
6681 #endif
6682     return(ret);
6683 }
6684 
6685 /**
6686  * xsltParseStylesheetFile:
6687  * @filename:  the filename/URL to the stylesheet
6688  *
6689  * Load and parse an XSLT stylesheet
6690  *
6691  * Returns a new XSLT stylesheet structure.
6692  */
6693 
6694 xsltStylesheetPtr
xsltParseStylesheetFile(const xmlChar * filename)6695 xsltParseStylesheetFile(const xmlChar* filename) {
6696     xsltSecurityPrefsPtr sec;
6697     xsltStylesheetPtr ret;
6698     xmlDocPtr doc;
6699 
6700     xsltInitGlobals();
6701 
6702     if (filename == NULL)
6703 	return(NULL);
6704 
6705 #ifdef WITH_XSLT_DEBUG_PARSING
6706     xsltGenericDebug(xsltGenericDebugContext,
6707 	    "xsltParseStylesheetFile : parse %s\n", filename);
6708 #endif
6709 
6710     /*
6711      * Security framework check
6712      */
6713     sec = xsltGetDefaultSecurityPrefs();
6714     if (sec != NULL) {
6715 	int res;
6716 
6717 	res = xsltCheckRead(sec, NULL, filename);
6718 	if (res == 0) {
6719 	    xsltTransformError(NULL, NULL, NULL,
6720 		 "xsltParseStylesheetFile: read rights for %s denied\n",
6721 			     filename);
6722 	    return(NULL);
6723 	}
6724     }
6725 
6726     doc = xsltDocDefaultLoader(filename, NULL, XSLT_PARSE_OPTIONS,
6727                                NULL, XSLT_LOAD_START);
6728     if (doc == NULL) {
6729 	xsltTransformError(NULL, NULL, NULL,
6730 		"xsltParseStylesheetFile : cannot parse %s\n", filename);
6731 	return(NULL);
6732     }
6733     ret = xsltParseStylesheetDoc(doc);
6734     if (ret == NULL) {
6735 	xmlFreeDoc(doc);
6736 	return(NULL);
6737     }
6738 
6739     return(ret);
6740 }
6741 
6742 /************************************************************************
6743  *									*
6744  *			Handling of Stylesheet PI			*
6745  *									*
6746  ************************************************************************/
6747 
6748 #define CUR (*cur)
6749 #define SKIP(val) cur += (val)
6750 #define NXT(val) cur[(val)]
6751 #define SKIP_BLANKS						\
6752     while (IS_BLANK(CUR)) NEXT
6753 #define NEXT ((*cur) ?  cur++ : cur)
6754 
6755 /**
6756  * xsltParseStylesheetPI:
6757  * @value: the value of the PI
6758  *
6759  * This function checks that the type is text/xml and extracts
6760  * the URI-Reference for the stylesheet
6761  *
6762  * Returns the URI-Reference for the stylesheet or NULL (it need to
6763  *         be freed by the caller)
6764  */
6765 static xmlChar *
xsltParseStylesheetPI(const xmlChar * value)6766 xsltParseStylesheetPI(const xmlChar *value) {
6767     const xmlChar *cur;
6768     const xmlChar *start;
6769     xmlChar *val;
6770     xmlChar tmp;
6771     xmlChar *href = NULL;
6772     int isXml = 0;
6773 
6774     if (value == NULL)
6775 	return(NULL);
6776 
6777     cur = value;
6778     while (CUR != 0) {
6779 	SKIP_BLANKS;
6780 	if ((CUR == 't') && (NXT(1) == 'y') && (NXT(2) == 'p') &&
6781 	    (NXT(3) == 'e')) {
6782 	    SKIP(4);
6783 	    SKIP_BLANKS;
6784 	    if (CUR != '=')
6785 		continue;
6786 	    NEXT;
6787 	    if ((CUR != '\'') && (CUR != '"'))
6788 		continue;
6789 	    tmp = CUR;
6790 	    NEXT;
6791 	    start = cur;
6792 	    while ((CUR != 0) && (CUR != tmp))
6793 		NEXT;
6794 	    if (CUR != tmp)
6795 		continue;
6796 	    val = xmlStrndup(start, cur - start);
6797 	    NEXT;
6798 	    if (val == NULL)
6799 		return(NULL);
6800 	    if ((xmlStrcasecmp(val, BAD_CAST "text/xml")) &&
6801 		(xmlStrcasecmp(val, BAD_CAST "text/xsl"))) {
6802                 xmlFree(val);
6803 		break;
6804 	    }
6805 	    isXml = 1;
6806 	    xmlFree(val);
6807 	} else if ((CUR == 'h') && (NXT(1) == 'r') && (NXT(2) == 'e') &&
6808 	    (NXT(3) == 'f')) {
6809 	    SKIP(4);
6810 	    SKIP_BLANKS;
6811 	    if (CUR != '=')
6812 		continue;
6813 	    NEXT;
6814 	    if ((CUR != '\'') && (CUR != '"'))
6815 		continue;
6816 	    tmp = CUR;
6817 	    NEXT;
6818 	    start = cur;
6819 	    while ((CUR != 0) && (CUR != tmp))
6820 		NEXT;
6821 	    if (CUR != tmp)
6822 		continue;
6823 	    if (href == NULL)
6824 		href = xmlStrndup(start, cur - start);
6825 	    NEXT;
6826 	} else {
6827 	    while ((CUR != 0) && (!IS_BLANK(CUR)))
6828 		NEXT;
6829 	}
6830 
6831     }
6832 
6833     if (!isXml) {
6834 	if (href != NULL)
6835 	    xmlFree(href);
6836 	href = NULL;
6837     }
6838     return(href);
6839 }
6840 
6841 /**
6842  * xsltLoadStylesheetPI:
6843  * @doc:  a document to process
6844  *
6845  * This function tries to locate the stylesheet PI in the given document
6846  * If found, and if contained within the document, it will extract
6847  * that subtree to build the stylesheet to process @doc (doc itself will
6848  * be modified). If found but referencing an external document it will
6849  * attempt to load it and generate a stylesheet from it. In both cases,
6850  * the resulting stylesheet and the document need to be freed once the
6851  * transformation is done.
6852  *
6853  * Returns a new XSLT stylesheet structure or NULL if not found.
6854  */
6855 xsltStylesheetPtr
xsltLoadStylesheetPI(xmlDocPtr doc)6856 xsltLoadStylesheetPI(xmlDocPtr doc) {
6857     xmlNodePtr child;
6858     xsltStylesheetPtr ret = NULL;
6859     xmlChar *href = NULL;
6860     xmlURIPtr URI;
6861 
6862     xsltInitGlobals();
6863 
6864     if (doc == NULL)
6865 	return(NULL);
6866 
6867     /*
6868      * Find the text/xml stylesheet PI id any before the root
6869      */
6870     child = doc->children;
6871     while ((child != NULL) && (child->type != XML_ELEMENT_NODE)) {
6872 	if ((child->type == XML_PI_NODE) &&
6873 	    (xmlStrEqual(child->name, BAD_CAST "xml-stylesheet"))) {
6874 	    href = xsltParseStylesheetPI(child->content);
6875 	    if (href != NULL)
6876 		break;
6877 	}
6878 	child = child->next;
6879     }
6880 
6881     /*
6882      * If found check the href to select processing
6883      */
6884     if (href != NULL) {
6885 #ifdef WITH_XSLT_DEBUG_PARSING
6886 	xsltGenericDebug(xsltGenericDebugContext,
6887 		"xsltLoadStylesheetPI : found PI href=%s\n", href);
6888 #endif
6889 	URI = xmlParseURI((const char *) href);
6890 	if (URI == NULL) {
6891 	    xsltTransformError(NULL, NULL, child,
6892 		    "xml-stylesheet : href %s is not valid\n", href);
6893 	    xmlFree(href);
6894 	    return(NULL);
6895 	}
6896 	if ((URI->fragment != NULL) && (URI->scheme == NULL) &&
6897             (URI->opaque == NULL) && (URI->authority == NULL) &&
6898             (URI->server == NULL) && (URI->user == NULL) &&
6899             (URI->path == NULL) && (URI->query == NULL)) {
6900 	    xmlAttrPtr ID;
6901 
6902 #ifdef WITH_XSLT_DEBUG_PARSING
6903 	    xsltGenericDebug(xsltGenericDebugContext,
6904 		    "xsltLoadStylesheetPI : Reference to ID %s\n", href);
6905 #endif
6906 	    if (URI->fragment[0] == '#')
6907 		ID = xmlGetID(doc, (const xmlChar *) &(URI->fragment[1]));
6908 	    else
6909 		ID = xmlGetID(doc, (const xmlChar *) URI->fragment);
6910 	    if (ID == NULL) {
6911 		xsltTransformError(NULL, NULL, child,
6912 		    "xml-stylesheet : no ID %s found\n", URI->fragment);
6913 	    } else {
6914 		xmlDocPtr fake;
6915 		xmlNodePtr subtree, newtree;
6916 		xmlNsPtr ns;
6917 
6918 #ifdef WITH_XSLT_DEBUG
6919 		xsltGenericDebug(xsltGenericDebugContext,
6920 		    "creating new document from %s for embedded stylesheet\n",
6921 		    doc->URL);
6922 #endif
6923 		/*
6924 		 * move the subtree in a new document passed to
6925 		 * the stylesheet analyzer
6926 		 */
6927 		subtree = ID->parent;
6928 		fake = xmlNewDoc(NULL);
6929 		if (fake != NULL) {
6930 		    /*
6931 		    * Should the dictionary still be shared even though
6932 		    * the nodes are being copied rather than moved?
6933 		    */
6934 		    fake->dict = doc->dict;
6935 		    xmlDictReference(doc->dict);
6936 #ifdef WITH_XSLT_DEBUG
6937 		    xsltGenericDebug(xsltGenericDebugContext,
6938 			"reusing dictionary from %s for embedded stylesheet\n",
6939 			doc->URL);
6940 #endif
6941 
6942 		    newtree = xmlDocCopyNode(subtree, fake, 1);
6943 
6944 		    fake->URL = xmlNodeGetBase(doc, subtree->parent);
6945 #ifdef WITH_XSLT_DEBUG
6946 		    xsltGenericDebug(xsltGenericDebugContext,
6947 			"set base URI for embedded stylesheet as %s\n",
6948 			fake->URL);
6949 #endif
6950 
6951 		    /*
6952 		    * Add all namespaces in scope of embedded stylesheet to
6953 		    * root element of newly created stylesheet document
6954 		    */
6955 		    while ((subtree = subtree->parent) != (xmlNodePtr)doc) {
6956 			for (ns = subtree->ns; ns; ns = ns->next) {
6957 			    xmlNewNs(newtree,  ns->href, ns->prefix);
6958 			}
6959 		    }
6960 
6961 		    xmlAddChild((xmlNodePtr)fake, newtree);
6962 		    ret = xsltParseStylesheetDoc(fake);
6963 		    if (ret == NULL)
6964 			xmlFreeDoc(fake);
6965 		}
6966 	    }
6967 	} else {
6968 	    xmlChar *URL, *base;
6969 
6970 	    /*
6971 	     * Reference to an external stylesheet
6972 	     */
6973 
6974 	    base = xmlNodeGetBase(doc, (xmlNodePtr) doc);
6975 	    URL = xmlBuildURI(href, base);
6976 	    if (URL != NULL) {
6977 #ifdef WITH_XSLT_DEBUG_PARSING
6978 		xsltGenericDebug(xsltGenericDebugContext,
6979 			"xsltLoadStylesheetPI : fetching %s\n", URL);
6980 #endif
6981 		ret = xsltParseStylesheetFile(URL);
6982 		xmlFree(URL);
6983 	    } else {
6984 #ifdef WITH_XSLT_DEBUG_PARSING
6985 		xsltGenericDebug(xsltGenericDebugContext,
6986 			"xsltLoadStylesheetPI : fetching %s\n", href);
6987 #endif
6988 		ret = xsltParseStylesheetFile(href);
6989 	    }
6990 	    if (base != NULL)
6991 		xmlFree(base);
6992 	}
6993 	xmlFreeURI(URI);
6994 	xmlFree(href);
6995     }
6996     return(ret);
6997 }
6998