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