1 /*
2  * preproc.c: Preprocessing of style operations
3  *
4  * References:
5  *   http://www.w3.org/TR/1999/REC-xslt-19991116
6  *
7  *   Michael Kay "XSLT Programmer's Reference" pp 637-643
8  *   Writing Multiple Output Files
9  *
10  *   XSLT-1.1 Working Draft
11  *   http://www.w3.org/TR/xslt11#multiple-output
12  *
13  * See Copyright for the status of this software.
14  *
15  * daniel@veillard.com
16  */
17 
18 #define IN_LIBXSLT
19 #include "libxslt.h"
20 
21 #include <string.h>
22 
23 #include <libxml/xmlmemory.h>
24 #include <libxml/parser.h>
25 #include <libxml/tree.h>
26 #include <libxml/valid.h>
27 #include <libxml/hash.h>
28 #include <libxml/uri.h>
29 #include <libxml/encoding.h>
30 #include <libxml/xmlerror.h>
31 #include "xslt.h"
32 #include "xsltutils.h"
33 #include "xsltInternals.h"
34 #include "transform.h"
35 #include "templates.h"
36 #include "variables.h"
37 #include "numbersInternals.h"
38 #include "preproc.h"
39 #include "extra.h"
40 #include "imports.h"
41 #include "extensions.h"
42 #include "pattern.h"
43 
44 #ifdef WITH_XSLT_DEBUG
45 #define WITH_XSLT_DEBUG_PREPROC
46 #endif
47 
48 const xmlChar *xsltExtMarker = (const xmlChar *) "Extension Element";
49 
50 /************************************************************************
51  *									*
52  *			Grammar checks					*
53  *									*
54  ************************************************************************/
55 
56 #ifdef XSLT_REFACTORED
57     /*
58     * Grammar checks are now performed in xslt.c.
59     */
60 #else
61 /**
62  * xsltCheckTopLevelElement:
63  * @style: the XSLT stylesheet
64  * @inst: the XSLT instruction
65  * @err: raise an error or not
66  *
67  * Check that the instruction is instanciated as a top level element.
68  *
69  * Returns -1 in case of error, 0 if failed and 1 in case of success
70  */
71 static int
xsltCheckTopLevelElement(xsltStylesheetPtr style,xmlNodePtr inst,int err)72 xsltCheckTopLevelElement(xsltStylesheetPtr style, xmlNodePtr inst, int err) {
73     xmlNodePtr parent;
74     if ((style == NULL) || (inst == NULL) || (inst->ns == NULL))
75         return(-1);
76 
77     parent = inst->parent;
78     if (parent == NULL) {
79         if (err) {
80 	    xsltTransformError(NULL, style, inst,
81 		    "internal problem: element has no parent\n");
82 	    style->errors++;
83 	}
84 	return(0);
85     }
86     if ((parent->ns == NULL) || (parent->type != XML_ELEMENT_NODE) ||
87         ((parent->ns != inst->ns) &&
88 	 (!xmlStrEqual(parent->ns->href, inst->ns->href))) ||
89 	((!xmlStrEqual(parent->name, BAD_CAST "stylesheet")) &&
90 	 (!xmlStrEqual(parent->name, BAD_CAST "transform")))) {
91 	if (err) {
92 	    xsltTransformError(NULL, style, inst,
93 		    "element %s only allowed as child of stylesheet\n",
94 			       inst->name);
95 	    style->errors++;
96 	}
97 	return(0);
98     }
99     return(1);
100 }
101 
102 /**
103  * xsltCheckInstructionElement:
104  * @style: the XSLT stylesheet
105  * @inst: the XSLT instruction
106  *
107  * Check that the instruction is instanciated as an instruction element.
108  */
109 static void
xsltCheckInstructionElement(xsltStylesheetPtr style,xmlNodePtr inst)110 xsltCheckInstructionElement(xsltStylesheetPtr style, xmlNodePtr inst) {
111     xmlNodePtr parent;
112     int has_ext;
113 
114     if ((style == NULL) || (inst == NULL) || (inst->ns == NULL) ||
115         (style->literal_result))
116         return;
117 
118     has_ext = (style->extInfos != NULL);
119 
120     parent = inst->parent;
121     if (parent == NULL) {
122 	xsltTransformError(NULL, style, inst,
123 		"internal problem: element has no parent\n");
124 	style->errors++;
125 	return;
126     }
127     while ((parent != NULL) && (parent->type != XML_DOCUMENT_NODE)) {
128         if (((parent->ns == inst->ns) ||
129 	     ((parent->ns != NULL) &&
130 	      (xmlStrEqual(parent->ns->href, inst->ns->href)))) &&
131 	    ((xmlStrEqual(parent->name, BAD_CAST "template")) ||
132 	     (xmlStrEqual(parent->name, BAD_CAST "param")) ||
133 	     (xmlStrEqual(parent->name, BAD_CAST "attribute")) ||
134 	     (xmlStrEqual(parent->name, BAD_CAST "variable")))) {
135 	    return;
136 	}
137 
138 	/*
139 	 * if we are within an extension element all bets are off
140 	 * about the semantic there e.g. xsl:param within func:function
141 	 */
142 	if ((has_ext) && (parent->ns != NULL) &&
143 	    (xmlHashLookup(style->extInfos, parent->ns->href) != NULL))
144 	    return;
145 
146         parent = parent->parent;
147     }
148     xsltTransformError(NULL, style, inst,
149 	    "element %s only allowed within a template, variable or param\n",
150 		           inst->name);
151     style->errors++;
152 }
153 
154 /**
155  * xsltCheckParentElement:
156  * @style: the XSLT stylesheet
157  * @inst: the XSLT instruction
158  * @allow1: allowed parent1
159  * @allow2: allowed parent2
160  *
161  * Check that the instruction is instanciated as the childre of one of the
162  * possible parents.
163  */
164 static void
xsltCheckParentElement(xsltStylesheetPtr style,xmlNodePtr inst,const xmlChar * allow1,const xmlChar * allow2)165 xsltCheckParentElement(xsltStylesheetPtr style, xmlNodePtr inst,
166                        const xmlChar *allow1, const xmlChar *allow2) {
167     xmlNodePtr parent;
168 
169     if ((style == NULL) || (inst == NULL) || (inst->ns == NULL) ||
170         (style->literal_result))
171         return;
172 
173     parent = inst->parent;
174     if (parent == NULL) {
175 	xsltTransformError(NULL, style, inst,
176 		"internal problem: element has no parent\n");
177 	style->errors++;
178 	return;
179     }
180     if (((parent->ns == inst->ns) ||
181 	 ((parent->ns != NULL) &&
182 	  (xmlStrEqual(parent->ns->href, inst->ns->href)))) &&
183 	((xmlStrEqual(parent->name, allow1)) ||
184 	 (xmlStrEqual(parent->name, allow2)))) {
185 	return;
186     }
187 
188     if (style->extInfos != NULL) {
189 	while ((parent != NULL) && (parent->type != XML_DOCUMENT_NODE)) {
190 	    /*
191 	     * if we are within an extension element all bets are off
192 	     * about the semantic there e.g. xsl:param within func:function
193 	     */
194 	    if ((parent->ns != NULL) &&
195 		(xmlHashLookup(style->extInfos, parent->ns->href) != NULL))
196 		return;
197 
198 	    parent = parent->parent;
199 	}
200     }
201     xsltTransformError(NULL, style, inst,
202 		       "element %s is not allowed within that context\n",
203 		       inst->name);
204     style->errors++;
205 }
206 #endif
207 
208 /************************************************************************
209  *									*
210  *			handling of precomputed data			*
211  *									*
212  ************************************************************************/
213 
214 /**
215  * xsltNewStylePreComp:
216  * @style:  the XSLT stylesheet
217  * @type:  the construct type
218  *
219  * Create a new XSLT Style precomputed block
220  *
221  * Returns the newly allocated specialized structure
222  *         or NULL in case of error
223  */
224 static xsltStylePreCompPtr
xsltNewStylePreComp(xsltStylesheetPtr style,xsltStyleType type)225 xsltNewStylePreComp(xsltStylesheetPtr style, xsltStyleType type) {
226     xsltStylePreCompPtr cur;
227 #ifdef XSLT_REFACTORED
228     size_t size;
229 #endif
230 
231     if (style == NULL)
232         return(NULL);
233 
234 #ifdef XSLT_REFACTORED
235     /*
236     * URGENT TODO: Use specialized factory functions in order
237     *   to avoid this ugliness.
238     */
239     switch (type) {
240         case XSLT_FUNC_COPY:
241             size = sizeof(xsltStyleItemCopy); break;
242         case XSLT_FUNC_SORT:
243             size = sizeof(xsltStyleItemSort); break;
244         case XSLT_FUNC_TEXT:
245             size = sizeof(xsltStyleItemText); break;
246         case XSLT_FUNC_ELEMENT:
247             size = sizeof(xsltStyleItemElement); break;
248         case XSLT_FUNC_ATTRIBUTE:
249             size = sizeof(xsltStyleItemAttribute); break;
250         case XSLT_FUNC_COMMENT:
251             size = sizeof(xsltStyleItemComment); break;
252         case XSLT_FUNC_PI:
253             size = sizeof(xsltStyleItemPI); break;
254         case XSLT_FUNC_COPYOF:
255             size = sizeof(xsltStyleItemCopyOf); break;
256         case XSLT_FUNC_VALUEOF:
257             size = sizeof(xsltStyleItemValueOf); break;;
258         case XSLT_FUNC_NUMBER:
259             size = sizeof(xsltStyleItemNumber); break;
260         case XSLT_FUNC_APPLYIMPORTS:
261             size = sizeof(xsltStyleItemApplyImports); break;
262         case XSLT_FUNC_CALLTEMPLATE:
263             size = sizeof(xsltStyleItemCallTemplate); break;
264         case XSLT_FUNC_APPLYTEMPLATES:
265             size = sizeof(xsltStyleItemApplyTemplates); break;
266         case XSLT_FUNC_CHOOSE:
267             size = sizeof(xsltStyleItemChoose); break;
268         case XSLT_FUNC_IF:
269             size = sizeof(xsltStyleItemIf); break;
270         case XSLT_FUNC_FOREACH:
271             size = sizeof(xsltStyleItemForEach); break;
272         case XSLT_FUNC_DOCUMENT:
273             size = sizeof(xsltStyleItemDocument); break;
274 	case XSLT_FUNC_WITHPARAM:
275 	    size = sizeof(xsltStyleItemWithParam); break;
276 	case XSLT_FUNC_PARAM:
277 	    size = sizeof(xsltStyleItemParam); break;
278 	case XSLT_FUNC_VARIABLE:
279 	    size = sizeof(xsltStyleItemVariable); break;
280 	case XSLT_FUNC_WHEN:
281 	    size = sizeof(xsltStyleItemWhen); break;
282 	case XSLT_FUNC_OTHERWISE:
283 	    size = sizeof(xsltStyleItemOtherwise); break;
284 	default:
285 	    xsltTransformError(NULL, style, NULL,
286 		    "xsltNewStylePreComp : invalid type %d\n", type);
287 	    style->errors++;
288 	    return(NULL);
289     }
290     /*
291     * Create the structure.
292     */
293     cur = (xsltStylePreCompPtr) xmlMalloc(size);
294     if (cur == NULL) {
295 	xsltTransformError(NULL, style, NULL,
296 		"xsltNewStylePreComp : malloc failed\n");
297 	style->errors++;
298 	return(NULL);
299     }
300     memset(cur, 0, size);
301 
302 #else /* XSLT_REFACTORED */
303     /*
304     * Old behaviour.
305     */
306     cur = (xsltStylePreCompPtr) xmlMalloc(sizeof(xsltStylePreComp));
307     if (cur == NULL) {
308 	xsltTransformError(NULL, style, NULL,
309 		"xsltNewStylePreComp : malloc failed\n");
310 	style->errors++;
311 	return(NULL);
312     }
313     memset(cur, 0, sizeof(xsltStylePreComp));
314 #endif /* XSLT_REFACTORED */
315 
316     /*
317     * URGENT TODO: Better to move this to spezialized factory functions.
318     */
319     cur->type = type;
320     switch (cur->type) {
321         case XSLT_FUNC_COPY:
322             cur->func = xsltCopy;break;
323         case XSLT_FUNC_SORT:
324             cur->func = xsltSort;break;
325         case XSLT_FUNC_TEXT:
326             cur->func = xsltText;break;
327         case XSLT_FUNC_ELEMENT:
328             cur->func = xsltElement;break;
329         case XSLT_FUNC_ATTRIBUTE:
330             cur->func = xsltAttribute;break;
331         case XSLT_FUNC_COMMENT:
332             cur->func = xsltComment;break;
333         case XSLT_FUNC_PI:
334             cur->func = xsltProcessingInstruction;
335 	    break;
336         case XSLT_FUNC_COPYOF:
337             cur->func = xsltCopyOf;break;
338         case XSLT_FUNC_VALUEOF:
339             cur->func = xsltValueOf;break;
340         case XSLT_FUNC_NUMBER:
341             cur->func = xsltNumber;break;
342         case XSLT_FUNC_APPLYIMPORTS:
343             cur->func = xsltApplyImports;break;
344         case XSLT_FUNC_CALLTEMPLATE:
345             cur->func = xsltCallTemplate;break;
346         case XSLT_FUNC_APPLYTEMPLATES:
347             cur->func = xsltApplyTemplates;break;
348         case XSLT_FUNC_CHOOSE:
349             cur->func = xsltChoose;break;
350         case XSLT_FUNC_IF:
351             cur->func = xsltIf;break;
352         case XSLT_FUNC_FOREACH:
353             cur->func = xsltForEach;break;
354         case XSLT_FUNC_DOCUMENT:
355             cur->func = xsltDocumentElem;break;
356 	case XSLT_FUNC_WITHPARAM:
357 	case XSLT_FUNC_PARAM:
358 	case XSLT_FUNC_VARIABLE:
359 	case XSLT_FUNC_WHEN:
360 	    break;
361 	default:
362 	if (cur->func == NULL) {
363 	    xsltTransformError(NULL, style, NULL,
364 		    "xsltNewStylePreComp : no function for type %d\n", type);
365 	    style->errors++;
366 	}
367     }
368     cur->next = style->preComps;
369     style->preComps = (xsltElemPreCompPtr) cur;
370 
371     return(cur);
372 }
373 
374 /**
375  * xsltFreeStylePreComp:
376  * @comp:  an XSLT Style precomputed block
377  *
378  * Free up the memory allocated by @comp
379  */
380 static void
xsltFreeStylePreComp(xsltStylePreCompPtr comp)381 xsltFreeStylePreComp(xsltStylePreCompPtr comp) {
382     if (comp == NULL)
383 	return;
384 #ifdef XSLT_REFACTORED
385     /*
386     * URGENT TODO: Implement destructors.
387     */
388     switch (comp->type) {
389 	case XSLT_FUNC_LITERAL_RESULT_ELEMENT:
390 	    break;
391 	case XSLT_FUNC_COPY:
392             break;
393         case XSLT_FUNC_SORT: {
394 		xsltStyleItemSortPtr item = (xsltStyleItemSortPtr) comp;
395 		if (item->locale != (xsltLocale)0)
396 		    xsltFreeLocale(item->locale);
397 		if (item->comp != NULL)
398 		    xmlXPathFreeCompExpr(item->comp);
399 	    }
400             break;
401         case XSLT_FUNC_TEXT:
402             break;
403         case XSLT_FUNC_ELEMENT:
404             break;
405         case XSLT_FUNC_ATTRIBUTE:
406             break;
407         case XSLT_FUNC_COMMENT:
408             break;
409         case XSLT_FUNC_PI:
410 	    break;
411         case XSLT_FUNC_COPYOF: {
412 		xsltStyleItemCopyOfPtr item = (xsltStyleItemCopyOfPtr) comp;
413 		if (item->comp != NULL)
414 		    xmlXPathFreeCompExpr(item->comp);
415 	    }
416             break;
417         case XSLT_FUNC_VALUEOF: {
418 		xsltStyleItemValueOfPtr item = (xsltStyleItemValueOfPtr) comp;
419 		if (item->comp != NULL)
420 		    xmlXPathFreeCompExpr(item->comp);
421 	    }
422             break;
423         case XSLT_FUNC_NUMBER: {
424                 xsltStyleItemNumberPtr item = (xsltStyleItemNumberPtr) comp;
425                 if (item->numdata.countPat != NULL)
426                     xsltFreeCompMatchList(item->numdata.countPat);
427                 if (item->numdata.fromPat != NULL)
428                     xsltFreeCompMatchList(item->numdata.fromPat);
429             }
430             break;
431         case XSLT_FUNC_APPLYIMPORTS:
432             break;
433         case XSLT_FUNC_CALLTEMPLATE:
434             break;
435         case XSLT_FUNC_APPLYTEMPLATES: {
436 		xsltStyleItemApplyTemplatesPtr item =
437 		    (xsltStyleItemApplyTemplatesPtr) comp;
438 		if (item->comp != NULL)
439 		    xmlXPathFreeCompExpr(item->comp);
440 	    }
441             break;
442         case XSLT_FUNC_CHOOSE:
443             break;
444         case XSLT_FUNC_IF: {
445 		xsltStyleItemIfPtr item = (xsltStyleItemIfPtr) comp;
446 		if (item->comp != NULL)
447 		    xmlXPathFreeCompExpr(item->comp);
448 	    }
449             break;
450         case XSLT_FUNC_FOREACH: {
451 		xsltStyleItemForEachPtr item =
452 		    (xsltStyleItemForEachPtr) comp;
453 		if (item->comp != NULL)
454 		    xmlXPathFreeCompExpr(item->comp);
455 	    }
456             break;
457         case XSLT_FUNC_DOCUMENT:
458             break;
459 	case XSLT_FUNC_WITHPARAM: {
460 		xsltStyleItemWithParamPtr item =
461 		    (xsltStyleItemWithParamPtr) comp;
462 		if (item->comp != NULL)
463 		    xmlXPathFreeCompExpr(item->comp);
464 	    }
465 	    break;
466 	case XSLT_FUNC_PARAM: {
467 		xsltStyleItemParamPtr item =
468 		    (xsltStyleItemParamPtr) comp;
469 		if (item->comp != NULL)
470 		    xmlXPathFreeCompExpr(item->comp);
471 	    }
472 	    break;
473 	case XSLT_FUNC_VARIABLE: {
474 		xsltStyleItemVariablePtr item =
475 		    (xsltStyleItemVariablePtr) comp;
476 		if (item->comp != NULL)
477 		    xmlXPathFreeCompExpr(item->comp);
478 	    }
479 	    break;
480 	case XSLT_FUNC_WHEN: {
481 		xsltStyleItemWhenPtr item =
482 		    (xsltStyleItemWhenPtr) comp;
483 		if (item->comp != NULL)
484 		    xmlXPathFreeCompExpr(item->comp);
485 	    }
486 	    break;
487 	case XSLT_FUNC_OTHERWISE:
488 	case XSLT_FUNC_FALLBACK:
489 	case XSLT_FUNC_MESSAGE:
490 	case XSLT_FUNC_INCLUDE:
491 	case XSLT_FUNC_ATTRSET:
492 
493 	    break;
494 	default:
495 	    /* TODO: Raise error. */
496 	    break;
497     }
498 #else
499     if (comp->locale != (xsltLocale)0)
500 	xsltFreeLocale(comp->locale);
501     if (comp->comp != NULL)
502 	xmlXPathFreeCompExpr(comp->comp);
503     if (comp->numdata.countPat != NULL)
504         xsltFreeCompMatchList(comp->numdata.countPat);
505     if (comp->numdata.fromPat != NULL)
506         xsltFreeCompMatchList(comp->numdata.fromPat);
507     if (comp->nsList != NULL)
508 	xmlFree(comp->nsList);
509 #endif
510 
511     xmlFree(comp);
512 }
513 
514 
515 /************************************************************************
516  *									*
517  *		    XSLT-1.1 extensions					*
518  *									*
519  ************************************************************************/
520 
521 /**
522  * xsltDocumentComp:
523  * @style:  the XSLT stylesheet
524  * @inst:  the instruction in the stylesheet
525  * @function:  unused
526  *
527  * Pre process an XSLT-1.1 document element
528  *
529  * Returns a precompiled data structure for the element
530  */
531 xsltElemPreCompPtr
xsltDocumentComp(xsltStylesheetPtr style,xmlNodePtr inst,xsltTransformFunction function ATTRIBUTE_UNUSED)532 xsltDocumentComp(xsltStylesheetPtr style, xmlNodePtr inst,
533 		 xsltTransformFunction function ATTRIBUTE_UNUSED) {
534 #ifdef XSLT_REFACTORED
535     xsltStyleItemDocumentPtr comp;
536 #else
537     xsltStylePreCompPtr comp;
538 #endif
539     const xmlChar *filename = NULL;
540 
541     /*
542     * As of 2006-03-30, this function is currently defined in Libxslt
543     * to be used for:
544     * (in libxslt/extra.c)
545     * "output" in XSLT_SAXON_NAMESPACE
546     * "write" XSLT_XALAN_NAMESPACE
547     * "document" XSLT_XT_NAMESPACE
548     * "document" XSLT_NAMESPACE (from the abandoned old working
549     *                            draft of XSLT 1.1)
550     * (in libexslt/common.c)
551     * "document" in EXSLT_COMMON_NAMESPACE
552     */
553 #ifdef XSLT_REFACTORED
554     comp = (xsltStyleItemDocumentPtr)
555 	xsltNewStylePreComp(style, XSLT_FUNC_DOCUMENT);
556 #else
557     comp = xsltNewStylePreComp(style, XSLT_FUNC_DOCUMENT);
558 #endif
559 
560     if (comp == NULL)
561 	return (NULL);
562     comp->inst = inst;
563     comp->ver11 = 0;
564 
565     if (xmlStrEqual(inst->name, (const xmlChar *) "output")) {
566 #ifdef WITH_XSLT_DEBUG_EXTRA
567 	xsltGenericDebug(xsltGenericDebugContext,
568 	    "Found saxon:output extension\n");
569 #endif
570 	/*
571 	* The element "output" is in the namespace XSLT_SAXON_NAMESPACE
572 	*   (http://icl.com/saxon)
573 	* The @file is in no namespace; it is an AVT.
574 	*   (http://www.computerwizards.com/saxon/doc/extensions.html#saxon:output)
575 	*
576 	* TODO: Do we need not to check the namespace here?
577 	*/
578 	filename = xsltEvalStaticAttrValueTemplate(style, inst,
579 			 (const xmlChar *)"file",
580 			 NULL, &comp->has_filename);
581     } else if (xmlStrEqual(inst->name, (const xmlChar *) "write")) {
582 #ifdef WITH_XSLT_DEBUG_EXTRA
583 	xsltGenericDebug(xsltGenericDebugContext,
584 	    "Found xalan:write extension\n");
585 #endif
586 	/* the filename need to be interpreted */
587 	/*
588 	* TODO: Is "filename need to be interpreted" meant to be a todo?
589 	*   Where will be the filename of xalan:write be processed?
590 	*
591 	* TODO: Do we need not to check the namespace here?
592 	*   The extension ns is "http://xml.apache.org/xalan/redirect".
593 	*   See http://xml.apache.org/xalan-j/extensionslib.html.
594 	*/
595     } else if (xmlStrEqual(inst->name, (const xmlChar *) "document")) {
596 	if (inst->ns != NULL) {
597 	    if (xmlStrEqual(inst->ns->href, XSLT_NAMESPACE)) {
598 		/*
599 		* Mark the instruction as being of
600 		* XSLT version 1.1 (abandoned).
601 		*/
602 		comp->ver11 = 1;
603 #ifdef WITH_XSLT_DEBUG_EXTRA
604 		xsltGenericDebug(xsltGenericDebugContext,
605 		    "Found xslt11:document construct\n");
606 #endif
607 	    } else {
608 		if (xmlStrEqual(inst->ns->href,
609 		    (const xmlChar *)"http://exslt.org/common")) {
610 		    /* EXSLT. */
611 #ifdef WITH_XSLT_DEBUG_EXTRA
612 		    xsltGenericDebug(xsltGenericDebugContext,
613 			"Found exslt:document extension\n");
614 #endif
615 		} else if (xmlStrEqual(inst->ns->href, XSLT_XT_NAMESPACE)) {
616 		    /* James Clark's XT. */
617 #ifdef WITH_XSLT_DEBUG_EXTRA
618 		    xsltGenericDebug(xsltGenericDebugContext,
619 			"Found xt:document extension\n");
620 #endif
621 		}
622 	    }
623 	}
624 	/*
625 	* The element "document" is used in conjunction with the
626 	* following namespaces:
627 	*
628 	* 1) XSLT_NAMESPACE (http://www.w3.org/1999/XSL/Transform version 1.1)
629 	*    <!ELEMENT xsl:document %template;>
630 	*    <!ATTLIST xsl:document
631 	*       href %avt; #REQUIRED
632 	*    @href is an AVT
633 	*    IMPORTANT: xsl:document was in the abandoned XSLT 1.1 draft,
634 	*    it was removed and isn't available in XSLT 1.1 anymore.
635 	*    In XSLT 2.0 it was renamed to xsl:result-document.
636 	*
637 	*   All other attributes are identical to the attributes
638 	*   on xsl:output
639 	*
640 	* 2) EXSLT_COMMON_NAMESPACE (http://exslt.org/common)
641 	*    <exsl:document
642 	*       href = { uri-reference }
643 	*    TODO: is @href is an AVT?
644 	*
645 	* 3) XSLT_XT_NAMESPACE (http://www.jclark.com/xt)
646 	*     Example: <xt:document method="xml" href="myFile.xml">
647 	*    TODO: is @href is an AVT?
648 	*
649 	* In all cases @href is in no namespace.
650 	*/
651 	filename = xsltEvalStaticAttrValueTemplate(style, inst,
652 	    (const xmlChar *)"href", NULL, &comp->has_filename);
653     }
654     if (!comp->has_filename) {
655 	goto error;
656     }
657     comp->filename = filename;
658 
659 error:
660     return ((xsltElemPreCompPtr) comp);
661 }
662 
663 /************************************************************************
664  *									*
665  *		Most of the XSLT-1.0 transformations			*
666  *									*
667  ************************************************************************/
668 
669 /**
670  * xsltSortComp:
671  * @style:  the XSLT stylesheet
672  * @inst:  the xslt sort node
673  *
674  * Process the xslt sort node on the source node
675  */
676 static void
xsltSortComp(xsltStylesheetPtr style,xmlNodePtr inst)677 xsltSortComp(xsltStylesheetPtr style, xmlNodePtr inst) {
678 #ifdef XSLT_REFACTORED
679     xsltStyleItemSortPtr comp;
680 #else
681     xsltStylePreCompPtr comp;
682 #endif
683     if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
684 	return;
685 
686 #ifdef XSLT_REFACTORED
687     comp = (xsltStyleItemSortPtr) xsltNewStylePreComp(style, XSLT_FUNC_SORT);
688 #else
689     comp = xsltNewStylePreComp(style, XSLT_FUNC_SORT);
690 #endif
691 
692     if (comp == NULL)
693 	return;
694     inst->psvi = comp;
695     comp->inst = inst;
696 
697     comp->stype = xsltEvalStaticAttrValueTemplate(style, inst,
698 			 (const xmlChar *)"data-type",
699 			 NULL, &comp->has_stype);
700     if (comp->stype != NULL) {
701 	if (xmlStrEqual(comp->stype, (const xmlChar *) "text"))
702 	    comp->number = 0;
703 	else if (xmlStrEqual(comp->stype, (const xmlChar *) "number"))
704 	    comp->number = 1;
705 	else {
706 	    xsltTransformError(NULL, style, inst,
707 		 "xsltSortComp: no support for data-type = %s\n", comp->stype);
708 	    comp->number = 0; /* use default */
709 	    if (style != NULL) style->warnings++;
710 	}
711     }
712     comp->order = xsltEvalStaticAttrValueTemplate(style, inst,
713 			      (const xmlChar *)"order",
714 			      NULL, &comp->has_order);
715     if (comp->order != NULL) {
716 	if (xmlStrEqual(comp->order, (const xmlChar *) "ascending"))
717 	    comp->descending = 0;
718 	else if (xmlStrEqual(comp->order, (const xmlChar *) "descending"))
719 	    comp->descending = 1;
720 	else {
721 	    xsltTransformError(NULL, style, inst,
722 		 "xsltSortComp: invalid value %s for order\n", comp->order);
723 	    comp->descending = 0; /* use default */
724 	    if (style != NULL) style->warnings++;
725 	}
726     }
727     comp->case_order = xsltEvalStaticAttrValueTemplate(style, inst,
728 			      (const xmlChar *)"case-order",
729 			      NULL, &comp->has_use);
730     if (comp->case_order != NULL) {
731 	if (xmlStrEqual(comp->case_order, (const xmlChar *) "upper-first"))
732 	    comp->lower_first = 0;
733 	else if (xmlStrEqual(comp->case_order, (const xmlChar *) "lower-first"))
734 	    comp->lower_first = 1;
735 	else {
736 	    xsltTransformError(NULL, style, inst,
737 		 "xsltSortComp: invalid value %s for order\n", comp->order);
738 	    comp->lower_first = 0; /* use default */
739 	    if (style != NULL) style->warnings++;
740 	}
741     }
742 
743     comp->lang = xsltEvalStaticAttrValueTemplate(style, inst,
744 				 (const xmlChar *)"lang",
745 				 NULL, &comp->has_lang);
746     if (comp->lang != NULL) {
747 	comp->locale = xsltNewLocale(comp->lang);
748     }
749     else {
750         comp->locale = (xsltLocale)0;
751     }
752 
753     comp->select = xsltGetCNsProp(style, inst,(const xmlChar *)"select", XSLT_NAMESPACE);
754     if (comp->select == NULL) {
755 	/*
756 	 * The default value of the select attribute is ., which will
757 	 * cause the string-value of the current node to be used as
758 	 * the sort key.
759 	 */
760 	comp->select = xmlDictLookup(style->dict, BAD_CAST ".", 1);
761     }
762     comp->comp = xsltXPathCompile(style, comp->select);
763     if (comp->comp == NULL) {
764 	xsltTransformError(NULL, style, inst,
765 	     "xsltSortComp: could not compile select expression '%s'\n",
766 	                 comp->select);
767 	if (style != NULL) style->errors++;
768     }
769     if (inst->children != NULL) {
770 	xsltTransformError(NULL, style, inst,
771 	"xsl:sort : is not empty\n");
772 	if (style != NULL) style->errors++;
773     }
774 }
775 
776 /**
777  * xsltCopyComp:
778  * @style:  the XSLT stylesheet
779  * @inst:  the xslt copy node
780  *
781  * Process the xslt copy node on the source node
782  */
783 static void
xsltCopyComp(xsltStylesheetPtr style,xmlNodePtr inst)784 xsltCopyComp(xsltStylesheetPtr style, xmlNodePtr inst) {
785 #ifdef XSLT_REFACTORED
786     xsltStyleItemCopyPtr comp;
787 #else
788     xsltStylePreCompPtr comp;
789 #endif
790 
791     if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
792 	return;
793 #ifdef XSLT_REFACTORED
794     comp = (xsltStyleItemCopyPtr) xsltNewStylePreComp(style, XSLT_FUNC_COPY);
795 #else
796     comp = xsltNewStylePreComp(style, XSLT_FUNC_COPY);
797 #endif
798 
799     if (comp == NULL)
800 	return;
801     inst->psvi = comp;
802     comp->inst = inst;
803 
804 
805     comp->use = xsltGetCNsProp(style, inst, (const xmlChar *)"use-attribute-sets",
806 				    XSLT_NAMESPACE);
807     if (comp->use == NULL)
808 	comp->has_use = 0;
809     else
810 	comp->has_use = 1;
811 }
812 
813 #ifdef XSLT_REFACTORED
814     /* Enable if ever needed for xsl:text. */
815 #else
816 /**
817  * xsltTextComp:
818  * @style: an XSLT compiled stylesheet
819  * @inst:  the xslt text node
820  *
821  * TODO: This function is obsolete, since xsl:text won't
822  *  be compiled, but removed from the tree.
823  *
824  * Process the xslt text node on the source node
825  */
826 static void
xsltTextComp(xsltStylesheetPtr style,xmlNodePtr inst)827 xsltTextComp(xsltStylesheetPtr style, xmlNodePtr inst) {
828 #ifdef XSLT_REFACTORED
829     xsltStyleItemTextPtr comp;
830 #else
831     xsltStylePreCompPtr comp;
832 #endif
833     const xmlChar *prop;
834 
835     if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
836 	return;
837 
838 #ifdef XSLT_REFACTORED
839     comp = (xsltStyleItemTextPtr) xsltNewStylePreComp(style, XSLT_FUNC_TEXT);
840 #else
841     comp = xsltNewStylePreComp(style, XSLT_FUNC_TEXT);
842 #endif
843     if (comp == NULL)
844 	return;
845     inst->psvi = comp;
846     comp->inst = inst;
847     comp->noescape = 0;
848 
849     prop = xsltGetCNsProp(style, inst,
850 	    (const xmlChar *)"disable-output-escaping",
851 			XSLT_NAMESPACE);
852     if (prop != NULL) {
853 	if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
854 	    comp->noescape = 1;
855 	} else if (!xmlStrEqual(prop,
856 	    (const xmlChar *)"no")){
857 	    xsltTransformError(NULL, style, inst,
858 		"xsl:text: disable-output-escaping allows only yes or no\n");
859 	    if (style != NULL) style->warnings++;
860 	}
861     }
862 }
863 #endif /* else of XSLT_REFACTORED */
864 
865 /**
866  * xsltElementComp:
867  * @style: an XSLT compiled stylesheet
868  * @inst:  the xslt element node
869  *
870  * Process the xslt element node on the source node
871  */
872 static void
xsltElementComp(xsltStylesheetPtr style,xmlNodePtr inst)873 xsltElementComp(xsltStylesheetPtr style, xmlNodePtr inst) {
874 #ifdef XSLT_REFACTORED
875     xsltStyleItemElementPtr comp;
876 #else
877     xsltStylePreCompPtr comp;
878 #endif
879 
880     /*
881     * <xsl:element
882     *   name = { qname }
883     *   namespace = { uri-reference }
884     *   use-attribute-sets = qnames>
885     *   <!-- Content: template -->
886     * </xsl:element>
887     */
888     if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
889 	return;
890 
891 #ifdef XSLT_REFACTORED
892     comp = (xsltStyleItemElementPtr) xsltNewStylePreComp(style, XSLT_FUNC_ELEMENT);
893 #else
894     comp = xsltNewStylePreComp(style, XSLT_FUNC_ELEMENT);
895 #endif
896 
897     if (comp == NULL)
898 	return;
899     inst->psvi = comp;
900     comp->inst = inst;
901 
902     /*
903     * Attribute "name".
904     */
905     /*
906     * TODO: Precompile the AVT. See bug #344894.
907     */
908     comp->name = xsltEvalStaticAttrValueTemplate(style, inst,
909 	(const xmlChar *)"name", NULL, &comp->has_name);
910     if (! comp->has_name) {
911 	xsltTransformError(NULL, style, inst,
912 	    "xsl:element: The attribute 'name' is missing.\n");
913 	style->errors++;
914 	goto error;
915     }
916     /*
917     * Attribute "namespace".
918     */
919     /*
920     * TODO: Precompile the AVT. See bug #344894.
921     */
922     comp->ns = xsltEvalStaticAttrValueTemplate(style, inst,
923 	(const xmlChar *)"namespace", NULL, &comp->has_ns);
924 
925     if (comp->name != NULL) {
926 	if (xmlValidateQName(comp->name, 0)) {
927 	    xsltTransformError(NULL, style, inst,
928 		"xsl:element: The value '%s' of the attribute 'name' is "
929 		"not a valid QName.\n", comp->name);
930 	    style->errors++;
931 	} else {
932 	    const xmlChar *prefix = NULL, *name;
933 
934 	    name = xsltSplitQName(style->dict, comp->name, &prefix);
935 	    if (comp->has_ns == 0) {
936 		xmlNsPtr ns;
937 
938 		/*
939 		* SPEC XSLT 1.0:
940 		*  "If the namespace attribute is not present, then the QName is
941 		*  expanded into an expanded-name using the namespace declarations
942 		*  in effect for the xsl:element element, including any default
943 		*  namespace declaration.
944 		*/
945 		ns = xmlSearchNs(inst->doc, inst, prefix);
946 		if (ns != NULL) {
947 		    comp->ns = xmlDictLookup(style->dict, ns->href, -1);
948 		    comp->has_ns = 1;
949 #ifdef XSLT_REFACTORED
950 		    comp->nsPrefix = prefix;
951 		    comp->name = name;
952 #else
953                     (void)name; /* Suppress unused variable warning. */
954 #endif
955 		} else if (prefix != NULL) {
956 		    xsltTransformError(NULL, style, inst,
957 			"xsl:element: The prefixed QName '%s' "
958 			"has no namespace binding in scope in the "
959 			"stylesheet; this is an error, since the namespace was "
960 			"not specified by the instruction itself.\n", comp->name);
961 		    style->errors++;
962 		}
963 	    }
964 	    if ((prefix != NULL) &&
965 		(!xmlStrncasecmp(prefix, (xmlChar *)"xml", 3)))
966 	    {
967 		/*
968 		* Mark is to be skipped.
969 		*/
970 		comp->has_name = 0;
971 	    }
972 	}
973     }
974     /*
975     * Attribute "use-attribute-sets",
976     */
977     comp->use = xsltEvalStaticAttrValueTemplate(style, inst,
978 		       (const xmlChar *)"use-attribute-sets",
979 		       NULL, &comp->has_use);
980 
981 error:
982     return;
983 }
984 
985 /**
986  * xsltAttributeComp:
987  * @style: an XSLT compiled stylesheet
988  * @inst:  the xslt attribute node
989  *
990  * Process the xslt attribute node on the source node
991  */
992 static void
xsltAttributeComp(xsltStylesheetPtr style,xmlNodePtr inst)993 xsltAttributeComp(xsltStylesheetPtr style, xmlNodePtr inst) {
994 #ifdef XSLT_REFACTORED
995     xsltStyleItemAttributePtr comp;
996 #else
997     xsltStylePreCompPtr comp;
998 #endif
999 
1000     /*
1001     * <xsl:attribute
1002     *   name = { qname }
1003     *   namespace = { uri-reference }>
1004     *   <!-- Content: template -->
1005     * </xsl:attribute>
1006     */
1007     if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1008 	return;
1009 
1010 #ifdef XSLT_REFACTORED
1011     comp = (xsltStyleItemAttributePtr) xsltNewStylePreComp(style,
1012 	XSLT_FUNC_ATTRIBUTE);
1013 #else
1014     comp = xsltNewStylePreComp(style, XSLT_FUNC_ATTRIBUTE);
1015 #endif
1016 
1017     if (comp == NULL)
1018 	return;
1019     inst->psvi = comp;
1020     comp->inst = inst;
1021 
1022     /*
1023     * Attribute "name".
1024     */
1025     /*
1026     * TODO: Precompile the AVT. See bug #344894.
1027     */
1028     comp->name = xsltEvalStaticAttrValueTemplate(style, inst,
1029 				 (const xmlChar *)"name",
1030 				 NULL, &comp->has_name);
1031     if (! comp->has_name) {
1032 	xsltTransformError(NULL, style, inst,
1033 	    "XSLT-attribute: The attribute 'name' is missing.\n");
1034 	style->errors++;
1035 	return;
1036     }
1037     /*
1038     * Attribute "namespace".
1039     */
1040     /*
1041     * TODO: Precompile the AVT. See bug #344894.
1042     */
1043     comp->ns = xsltEvalStaticAttrValueTemplate(style, inst,
1044 	(const xmlChar *)"namespace",
1045 	NULL, &comp->has_ns);
1046 
1047     if (comp->name != NULL) {
1048 	if (xmlValidateQName(comp->name, 0)) {
1049 	    xsltTransformError(NULL, style, inst,
1050 		"xsl:attribute: The value '%s' of the attribute 'name' is "
1051 		"not a valid QName.\n", comp->name);
1052 	    style->errors++;
1053         } else if (xmlStrEqual(comp->name, BAD_CAST "xmlns")) {
1054 	    xsltTransformError(NULL, style, inst,
1055                 "xsl:attribute: The attribute name 'xmlns' is not allowed.\n");
1056 	    style->errors++;
1057 	} else {
1058 	    const xmlChar *prefix = NULL, *name;
1059 
1060 	    name = xsltSplitQName(style->dict, comp->name, &prefix);
1061 	    if (prefix != NULL) {
1062 		if (comp->has_ns == 0) {
1063 		    xmlNsPtr ns;
1064 
1065 		    /*
1066 		    * SPEC XSLT 1.0:
1067 		    *  "If the namespace attribute is not present, then the
1068 		    *  QName is expanded into an expanded-name using the
1069 		    *  namespace declarations in effect for the xsl:element
1070 		    *  element, including any default namespace declaration.
1071 		    */
1072 		    ns = xmlSearchNs(inst->doc, inst, prefix);
1073 		    if (ns != NULL) {
1074 			comp->ns = xmlDictLookup(style->dict, ns->href, -1);
1075 			comp->has_ns = 1;
1076 #ifdef XSLT_REFACTORED
1077 			comp->nsPrefix = prefix;
1078 			comp->name = name;
1079 #else
1080                         (void)name; /* Suppress unused variable warning. */
1081 #endif
1082 		    } else {
1083 			xsltTransformError(NULL, style, inst,
1084 			    "xsl:attribute: The prefixed QName '%s' "
1085 			    "has no namespace binding in scope in the "
1086 			    "stylesheet; this is an error, since the "
1087 			    "namespace was not specified by the instruction "
1088 			    "itself.\n", comp->name);
1089 			style->errors++;
1090 		    }
1091 		}
1092 	    }
1093 	}
1094     }
1095 }
1096 
1097 /**
1098  * xsltCommentComp:
1099  * @style: an XSLT compiled stylesheet
1100  * @inst:  the xslt comment node
1101  *
1102  * Process the xslt comment node on the source node
1103  */
1104 static void
xsltCommentComp(xsltStylesheetPtr style,xmlNodePtr inst)1105 xsltCommentComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1106 #ifdef XSLT_REFACTORED
1107     xsltStyleItemCommentPtr comp;
1108 #else
1109     xsltStylePreCompPtr comp;
1110 #endif
1111 
1112     if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1113 	return;
1114 
1115 #ifdef XSLT_REFACTORED
1116     comp = (xsltStyleItemCommentPtr) xsltNewStylePreComp(style, XSLT_FUNC_COMMENT);
1117 #else
1118     comp = xsltNewStylePreComp(style, XSLT_FUNC_COMMENT);
1119 #endif
1120 
1121     if (comp == NULL)
1122 	return;
1123     inst->psvi = comp;
1124     comp->inst = inst;
1125 }
1126 
1127 /**
1128  * xsltProcessingInstructionComp:
1129  * @style: an XSLT compiled stylesheet
1130  * @inst:  the xslt processing-instruction node
1131  *
1132  * Process the xslt processing-instruction node on the source node
1133  */
1134 static void
xsltProcessingInstructionComp(xsltStylesheetPtr style,xmlNodePtr inst)1135 xsltProcessingInstructionComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1136 #ifdef XSLT_REFACTORED
1137     xsltStyleItemPIPtr comp;
1138 #else
1139     xsltStylePreCompPtr comp;
1140 #endif
1141 
1142     if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1143 	return;
1144 
1145 #ifdef XSLT_REFACTORED
1146     comp = (xsltStyleItemPIPtr) xsltNewStylePreComp(style, XSLT_FUNC_PI);
1147 #else
1148     comp = xsltNewStylePreComp(style, XSLT_FUNC_PI);
1149 #endif
1150 
1151     if (comp == NULL)
1152 	return;
1153     inst->psvi = comp;
1154     comp->inst = inst;
1155 
1156     comp->name = xsltEvalStaticAttrValueTemplate(style, inst,
1157 				 (const xmlChar *)"name",
1158 				 XSLT_NAMESPACE, &comp->has_name);
1159 }
1160 
1161 /**
1162  * xsltCopyOfComp:
1163  * @style: an XSLT compiled stylesheet
1164  * @inst:  the xslt copy-of node
1165  *
1166  * Process the xslt copy-of node on the source node
1167  */
1168 static void
xsltCopyOfComp(xsltStylesheetPtr style,xmlNodePtr inst)1169 xsltCopyOfComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1170 #ifdef XSLT_REFACTORED
1171     xsltStyleItemCopyOfPtr comp;
1172 #else
1173     xsltStylePreCompPtr comp;
1174 #endif
1175 
1176     if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1177 	return;
1178 
1179 #ifdef XSLT_REFACTORED
1180     comp = (xsltStyleItemCopyOfPtr) xsltNewStylePreComp(style, XSLT_FUNC_COPYOF);
1181 #else
1182     comp = xsltNewStylePreComp(style, XSLT_FUNC_COPYOF);
1183 #endif
1184 
1185     if (comp == NULL)
1186 	return;
1187     inst->psvi = comp;
1188     comp->inst = inst;
1189 
1190     comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
1191 	                        XSLT_NAMESPACE);
1192     if (comp->select == NULL) {
1193 	xsltTransformError(NULL, style, inst,
1194 	     "xsl:copy-of : select is missing\n");
1195 	if (style != NULL) style->errors++;
1196 	return;
1197     }
1198     comp->comp = xsltXPathCompile(style, comp->select);
1199     if (comp->comp == NULL) {
1200 	xsltTransformError(NULL, style, inst,
1201 	     "xsl:copy-of : could not compile select expression '%s'\n",
1202 	                 comp->select);
1203 	if (style != NULL) style->errors++;
1204     }
1205 }
1206 
1207 /**
1208  * xsltValueOfComp:
1209  * @style: an XSLT compiled stylesheet
1210  * @inst:  the xslt value-of node
1211  *
1212  * Process the xslt value-of node on the source node
1213  */
1214 static void
xsltValueOfComp(xsltStylesheetPtr style,xmlNodePtr inst)1215 xsltValueOfComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1216 #ifdef XSLT_REFACTORED
1217     xsltStyleItemValueOfPtr comp;
1218 #else
1219     xsltStylePreCompPtr comp;
1220 #endif
1221     const xmlChar *prop;
1222 
1223     if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1224 	return;
1225 
1226 #ifdef XSLT_REFACTORED
1227     comp = (xsltStyleItemValueOfPtr) xsltNewStylePreComp(style, XSLT_FUNC_VALUEOF);
1228 #else
1229     comp = xsltNewStylePreComp(style, XSLT_FUNC_VALUEOF);
1230 #endif
1231 
1232     if (comp == NULL)
1233 	return;
1234     inst->psvi = comp;
1235     comp->inst = inst;
1236 
1237     prop = xsltGetCNsProp(style, inst,
1238 	    (const xmlChar *)"disable-output-escaping",
1239 			XSLT_NAMESPACE);
1240     if (prop != NULL) {
1241 	if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
1242 	    comp->noescape = 1;
1243 	} else if (!xmlStrEqual(prop,
1244 				(const xmlChar *)"no")){
1245 	    xsltTransformError(NULL, style, inst,
1246 "xsl:value-of : disable-output-escaping allows only yes or no\n");
1247 	    if (style != NULL) style->warnings++;
1248 	}
1249     }
1250     comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
1251 	                        XSLT_NAMESPACE);
1252     if (comp->select == NULL) {
1253 	xsltTransformError(NULL, style, inst,
1254 	     "xsl:value-of : select is missing\n");
1255 	if (style != NULL) style->errors++;
1256 	return;
1257     }
1258     comp->comp = xsltXPathCompile(style, comp->select);
1259     if (comp->comp == NULL) {
1260 	xsltTransformError(NULL, style, inst,
1261 	     "xsl:value-of : could not compile select expression '%s'\n",
1262 	                 comp->select);
1263 	if (style != NULL) style->errors++;
1264     }
1265 }
1266 
1267 static void
xsltGetQNameProperty(xsltStylesheetPtr style,xmlNodePtr inst,const xmlChar * propName,int mandatory,int * hasProp,const xmlChar ** nsName,const xmlChar ** localName)1268 xsltGetQNameProperty(xsltStylesheetPtr style, xmlNodePtr inst,
1269 		     const xmlChar *propName,
1270 		     int mandatory,
1271 		     int *hasProp, const xmlChar **nsName,
1272 		     const xmlChar** localName)
1273 {
1274     const xmlChar *prop;
1275 
1276     if (nsName)
1277 	*nsName = NULL;
1278     if (localName)
1279 	*localName = NULL;
1280     if (hasProp)
1281 	*hasProp = 0;
1282 
1283     prop = xsltGetCNsProp(style, inst, propName, XSLT_NAMESPACE);
1284     if (prop == NULL) {
1285 	if (mandatory) {
1286 	    xsltTransformError(NULL, style, inst,
1287 		"The attribute '%s' is missing.\n", propName);
1288 	    style->errors++;
1289 	    return;
1290 	}
1291     } else {
1292         const xmlChar *URI;
1293 
1294 	if (xmlValidateQName(prop, 0)) {
1295 	    xsltTransformError(NULL, style, inst,
1296 		"The value '%s' of the attribute "
1297 		"'%s' is not a valid QName.\n", prop, propName);
1298 	    style->errors++;
1299 	    return;
1300 	} else {
1301 	    /*
1302 	    * @prop will be in the string dict afterwards, @URI not.
1303 	    */
1304 	    URI = xsltGetQNameURI2(style, inst, &prop);
1305 	    if (prop == NULL) {
1306 		style->errors++;
1307 	    } else {
1308 		if (localName)
1309 		    *localName = prop;
1310 		if (hasProp)
1311 		    *hasProp = 1;
1312 		if (URI != NULL) {
1313 		    /*
1314 		    * Fixes bug #308441: Put the ns-name in the dict
1315 		    * in order to pointer compare names during XPath's
1316 		    * variable lookup.
1317 		    */
1318 		    if (nsName)
1319 			*nsName = xmlDictLookup(style->dict, URI, -1);
1320 		    /* comp->has_ns = 1; */
1321 		}
1322 	    }
1323 	}
1324     }
1325     return;
1326 }
1327 
1328 /**
1329  * xsltWithParamComp:
1330  * @style: an XSLT compiled stylesheet
1331  * @inst:  the xslt with-param node
1332  *
1333  * Process the xslt with-param node on the source node
1334  * Allowed parents: xsl:call-template, xsl:apply-templates.
1335  * <xsl:with-param
1336  *  name = qname
1337  *  select = expression>
1338  *  <!-- Content: template -->
1339  * </xsl:with-param>
1340  */
1341 static void
xsltWithParamComp(xsltStylesheetPtr style,xmlNodePtr inst)1342 xsltWithParamComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1343 #ifdef XSLT_REFACTORED
1344     xsltStyleItemWithParamPtr comp;
1345 #else
1346     xsltStylePreCompPtr comp;
1347 #endif
1348 
1349     if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1350 	return;
1351 
1352 #ifdef XSLT_REFACTORED
1353     comp = (xsltStyleItemWithParamPtr) xsltNewStylePreComp(style, XSLT_FUNC_WITHPARAM);
1354 #else
1355     comp = xsltNewStylePreComp(style, XSLT_FUNC_WITHPARAM);
1356 #endif
1357 
1358     if (comp == NULL)
1359 	return;
1360     inst->psvi = comp;
1361     comp->inst = inst;
1362 
1363     /*
1364     * Attribute "name".
1365     */
1366     xsltGetQNameProperty(style, inst, BAD_CAST "name",
1367 	1, &(comp->has_name), &(comp->ns), &(comp->name));
1368     if (comp->ns)
1369 	comp->has_ns = 1;
1370     /*
1371     * Attribute "select".
1372     */
1373     comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
1374 	                        XSLT_NAMESPACE);
1375     if (comp->select != NULL) {
1376 	comp->comp = xsltXPathCompile(style, comp->select);
1377 	if (comp->comp == NULL) {
1378 	    xsltTransformError(NULL, style, inst,
1379 		 "XSLT-with-param: Failed to compile select "
1380 		 "expression '%s'\n", comp->select);
1381 	    style->errors++;
1382 	}
1383 	if (inst->children != NULL) {
1384 	    xsltTransformError(NULL, style, inst,
1385 		"XSLT-with-param: The content should be empty since "
1386 		"the attribute select is present.\n");
1387 	    style->warnings++;
1388 	}
1389     }
1390 }
1391 
1392 /**
1393  * xsltNumberComp:
1394  * @style: an XSLT compiled stylesheet
1395  * @cur:   the xslt number node
1396  *
1397  * Process the xslt number node on the source node
1398  */
1399 static void
xsltNumberComp(xsltStylesheetPtr style,xmlNodePtr cur)1400 xsltNumberComp(xsltStylesheetPtr style, xmlNodePtr cur) {
1401 #ifdef XSLT_REFACTORED
1402     xsltStyleItemNumberPtr comp;
1403 #else
1404     xsltStylePreCompPtr comp;
1405 #endif
1406     const xmlChar *prop;
1407 
1408     if ((style == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE))
1409 	return;
1410 
1411 #ifdef XSLT_REFACTORED
1412     comp = (xsltStyleItemNumberPtr) xsltNewStylePreComp(style, XSLT_FUNC_NUMBER);
1413 #else
1414     comp = xsltNewStylePreComp(style, XSLT_FUNC_NUMBER);
1415 #endif
1416 
1417     if (comp == NULL)
1418 	return;
1419     cur->psvi = comp;
1420 
1421     comp->numdata.doc = cur->doc;
1422     comp->numdata.node = cur;
1423     comp->numdata.value = xsltGetCNsProp(style, cur, (const xmlChar *)"value",
1424 	                                XSLT_NAMESPACE);
1425 
1426     prop = xsltEvalStaticAttrValueTemplate(style, cur,
1427 			 (const xmlChar *)"format",
1428 			 XSLT_NAMESPACE, &comp->numdata.has_format);
1429     if (comp->numdata.has_format == 0) {
1430 	comp->numdata.format = xmlDictLookup(style->dict, BAD_CAST "" , 0);
1431     } else {
1432 	comp->numdata.format = prop;
1433     }
1434 
1435     comp->numdata.count = xsltGetCNsProp(style, cur, (const xmlChar *)"count",
1436                                          XSLT_NAMESPACE);
1437     comp->numdata.from = xsltGetCNsProp(style, cur, (const xmlChar *)"from",
1438                                         XSLT_NAMESPACE);
1439 
1440     prop = xsltGetCNsProp(style, cur, (const xmlChar *)"count", XSLT_NAMESPACE);
1441     if (prop != NULL) {
1442 	comp->numdata.countPat = xsltCompilePattern(prop, cur->doc, cur, style,
1443                                                     NULL);
1444     }
1445 
1446     prop = xsltGetCNsProp(style, cur, (const xmlChar *)"from", XSLT_NAMESPACE);
1447     if (prop != NULL) {
1448 	comp->numdata.fromPat = xsltCompilePattern(prop, cur->doc, cur, style,
1449                                                    NULL);
1450     }
1451 
1452     prop = xsltGetCNsProp(style, cur, (const xmlChar *)"level", XSLT_NAMESPACE);
1453     if (prop != NULL) {
1454 	if (xmlStrEqual(prop, BAD_CAST("single")) ||
1455 	    xmlStrEqual(prop, BAD_CAST("multiple")) ||
1456 	    xmlStrEqual(prop, BAD_CAST("any"))) {
1457 	    comp->numdata.level = prop;
1458 	} else {
1459 	    xsltTransformError(NULL, style, cur,
1460 			 "xsl:number : invalid value %s for level\n", prop);
1461 	    if (style != NULL) style->warnings++;
1462 	}
1463     }
1464 
1465     prop = xsltGetCNsProp(style, cur, (const xmlChar *)"lang", XSLT_NAMESPACE);
1466     if (prop != NULL) {
1467 	    xsltTransformError(NULL, style, cur,
1468 		 "xsl:number : lang attribute not implemented\n");
1469 	XSLT_TODO; /* xsl:number lang attribute */
1470     }
1471 
1472     prop = xsltGetCNsProp(style, cur, (const xmlChar *)"letter-value", XSLT_NAMESPACE);
1473     if (prop != NULL) {
1474 	if (xmlStrEqual(prop, BAD_CAST("alphabetic"))) {
1475 	    xsltTransformError(NULL, style, cur,
1476 		 "xsl:number : letter-value 'alphabetic' not implemented\n");
1477 	    if (style != NULL) style->warnings++;
1478 	    XSLT_TODO; /* xsl:number letter-value attribute alphabetic */
1479 	} else if (xmlStrEqual(prop, BAD_CAST("traditional"))) {
1480 	    xsltTransformError(NULL, style, cur,
1481 		 "xsl:number : letter-value 'traditional' not implemented\n");
1482 	    if (style != NULL) style->warnings++;
1483 	    XSLT_TODO; /* xsl:number letter-value attribute traditional */
1484 	} else {
1485 	    xsltTransformError(NULL, style, cur,
1486 		     "xsl:number : invalid value %s for letter-value\n", prop);
1487 	    if (style != NULL) style->warnings++;
1488 	}
1489     }
1490 
1491     prop = xsltGetCNsProp(style, cur, (const xmlChar *)"grouping-separator",
1492 	                XSLT_NAMESPACE);
1493     if (prop != NULL) {
1494         comp->numdata.groupingCharacterLen = xmlStrlen(prop);
1495 	comp->numdata.groupingCharacter =
1496 	    xsltGetUTF8Char(prop, &(comp->numdata.groupingCharacterLen));
1497     }
1498 
1499     prop = xsltGetCNsProp(style, cur, (const xmlChar *)"grouping-size", XSLT_NAMESPACE);
1500     if (prop != NULL) {
1501 	sscanf((char *)prop, "%d", &comp->numdata.digitsPerGroup);
1502     } else {
1503 	comp->numdata.groupingCharacter = 0;
1504     }
1505 
1506     /* Set default values */
1507     if (comp->numdata.value == NULL) {
1508 	if (comp->numdata.level == NULL) {
1509 	    comp->numdata.level = xmlDictLookup(style->dict,
1510 	                                        BAD_CAST"single", 6);
1511 	}
1512     }
1513 
1514 }
1515 
1516 /**
1517  * xsltApplyImportsComp:
1518  * @style: an XSLT compiled stylesheet
1519  * @inst:  the xslt apply-imports node
1520  *
1521  * Process the xslt apply-imports node on the source node
1522  */
1523 static void
xsltApplyImportsComp(xsltStylesheetPtr style,xmlNodePtr inst)1524 xsltApplyImportsComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1525 #ifdef XSLT_REFACTORED
1526     xsltStyleItemApplyImportsPtr comp;
1527 #else
1528     xsltStylePreCompPtr comp;
1529 #endif
1530 
1531     if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1532 	return;
1533 
1534 #ifdef XSLT_REFACTORED
1535     comp = (xsltStyleItemApplyImportsPtr) xsltNewStylePreComp(style, XSLT_FUNC_APPLYIMPORTS);
1536 #else
1537     comp = xsltNewStylePreComp(style, XSLT_FUNC_APPLYIMPORTS);
1538 #endif
1539 
1540     if (comp == NULL)
1541 	return;
1542     inst->psvi = comp;
1543     comp->inst = inst;
1544 }
1545 
1546 /**
1547  * xsltCallTemplateComp:
1548  * @style: an XSLT compiled stylesheet
1549  * @inst:  the xslt call-template node
1550  *
1551  * Process the xslt call-template node on the source node
1552  */
1553 static void
xsltCallTemplateComp(xsltStylesheetPtr style,xmlNodePtr inst)1554 xsltCallTemplateComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1555 #ifdef XSLT_REFACTORED
1556     xsltStyleItemCallTemplatePtr comp;
1557 #else
1558     xsltStylePreCompPtr comp;
1559 #endif
1560 
1561     if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1562 	return;
1563 
1564 #ifdef XSLT_REFACTORED
1565     comp = (xsltStyleItemCallTemplatePtr)
1566 	xsltNewStylePreComp(style, XSLT_FUNC_CALLTEMPLATE);
1567 #else
1568     comp = xsltNewStylePreComp(style, XSLT_FUNC_CALLTEMPLATE);
1569 #endif
1570 
1571     if (comp == NULL)
1572 	return;
1573     inst->psvi = comp;
1574     comp->inst = inst;
1575 
1576     /*
1577      * Attribute "name".
1578      */
1579     xsltGetQNameProperty(style, inst, BAD_CAST "name",
1580 	1, &(comp->has_name), &(comp->ns), &(comp->name));
1581     if (comp->ns)
1582 	comp->has_ns = 1;
1583 }
1584 
1585 /**
1586  * xsltApplyTemplatesComp:
1587  * @style: an XSLT compiled stylesheet
1588  * @inst:  the apply-templates node
1589  *
1590  * Process the apply-templates node on the source node
1591  */
1592 static void
xsltApplyTemplatesComp(xsltStylesheetPtr style,xmlNodePtr inst)1593 xsltApplyTemplatesComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1594 #ifdef XSLT_REFACTORED
1595     xsltStyleItemApplyTemplatesPtr comp;
1596 #else
1597     xsltStylePreCompPtr comp;
1598 #endif
1599 
1600     if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1601 	return;
1602 
1603 #ifdef XSLT_REFACTORED
1604     comp = (xsltStyleItemApplyTemplatesPtr)
1605 	xsltNewStylePreComp(style, XSLT_FUNC_APPLYTEMPLATES);
1606 #else
1607     comp = xsltNewStylePreComp(style, XSLT_FUNC_APPLYTEMPLATES);
1608 #endif
1609 
1610     if (comp == NULL)
1611 	return;
1612     inst->psvi = comp;
1613     comp->inst = inst;
1614 
1615     /*
1616      * Attribute "mode".
1617      */
1618     xsltGetQNameProperty(style, inst, BAD_CAST "mode",
1619 	0, NULL, &(comp->modeURI), &(comp->mode));
1620     /*
1621     * Attribute "select".
1622     */
1623     comp->select = xsltGetCNsProp(style, inst, BAD_CAST "select",
1624 	XSLT_NAMESPACE);
1625     if (comp->select != NULL) {
1626 	comp->comp = xsltXPathCompile(style, comp->select);
1627 	if (comp->comp == NULL) {
1628 	    xsltTransformError(NULL, style, inst,
1629 		"XSLT-apply-templates: could not compile select "
1630 		"expression '%s'\n", comp->select);
1631 	     style->errors++;
1632 	}
1633     }
1634     /* TODO: handle (or skip) the xsl:sort and xsl:with-param */
1635 }
1636 
1637 /**
1638  * xsltChooseComp:
1639  * @style: an XSLT compiled stylesheet
1640  * @inst:  the xslt choose node
1641  *
1642  * Process the xslt choose node on the source node
1643  */
1644 static void
xsltChooseComp(xsltStylesheetPtr style,xmlNodePtr inst)1645 xsltChooseComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1646 #ifdef XSLT_REFACTORED
1647     xsltStyleItemChoosePtr comp;
1648 #else
1649     xsltStylePreCompPtr comp;
1650 #endif
1651 
1652     if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1653 	return;
1654 
1655 #ifdef XSLT_REFACTORED
1656     comp = (xsltStyleItemChoosePtr)
1657 	xsltNewStylePreComp(style, XSLT_FUNC_CHOOSE);
1658 #else
1659     comp = xsltNewStylePreComp(style, XSLT_FUNC_CHOOSE);
1660 #endif
1661 
1662     if (comp == NULL)
1663 	return;
1664     inst->psvi = comp;
1665     comp->inst = inst;
1666 }
1667 
1668 /**
1669  * xsltIfComp:
1670  * @style: an XSLT compiled stylesheet
1671  * @inst:  the xslt if node
1672  *
1673  * Process the xslt if node on the source node
1674  */
1675 static void
xsltIfComp(xsltStylesheetPtr style,xmlNodePtr inst)1676 xsltIfComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1677 #ifdef XSLT_REFACTORED
1678     xsltStyleItemIfPtr comp;
1679 #else
1680     xsltStylePreCompPtr comp;
1681 #endif
1682 
1683     if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1684 	return;
1685 
1686 #ifdef XSLT_REFACTORED
1687     comp = (xsltStyleItemIfPtr)
1688 	xsltNewStylePreComp(style, XSLT_FUNC_IF);
1689 #else
1690     comp = xsltNewStylePreComp(style, XSLT_FUNC_IF);
1691 #endif
1692 
1693     if (comp == NULL)
1694 	return;
1695     inst->psvi = comp;
1696     comp->inst = inst;
1697 
1698     comp->test = xsltGetCNsProp(style, inst, (const xmlChar *)"test", XSLT_NAMESPACE);
1699     if (comp->test == NULL) {
1700 	xsltTransformError(NULL, style, inst,
1701 	     "xsl:if : test is not defined\n");
1702 	if (style != NULL) style->errors++;
1703 	return;
1704     }
1705     comp->comp = xsltXPathCompile(style, comp->test);
1706     if (comp->comp == NULL) {
1707 	xsltTransformError(NULL, style, inst,
1708 	     "xsl:if : could not compile test expression '%s'\n",
1709 	                 comp->test);
1710 	if (style != NULL) style->errors++;
1711     }
1712 }
1713 
1714 /**
1715  * xsltWhenComp:
1716  * @style: an XSLT compiled stylesheet
1717  * @inst:  the xslt if node
1718  *
1719  * Process the xslt if node on the source node
1720  */
1721 static void
xsltWhenComp(xsltStylesheetPtr style,xmlNodePtr inst)1722 xsltWhenComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1723 #ifdef XSLT_REFACTORED
1724     xsltStyleItemWhenPtr comp;
1725 #else
1726     xsltStylePreCompPtr comp;
1727 #endif
1728 
1729     if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1730 	return;
1731 
1732 #ifdef XSLT_REFACTORED
1733     comp = (xsltStyleItemWhenPtr)
1734 	xsltNewStylePreComp(style, XSLT_FUNC_WHEN);
1735 #else
1736     comp = xsltNewStylePreComp(style, XSLT_FUNC_WHEN);
1737 #endif
1738 
1739     if (comp == NULL)
1740 	return;
1741     inst->psvi = comp;
1742     comp->inst = inst;
1743 
1744     comp->test = xsltGetCNsProp(style, inst, (const xmlChar *)"test", XSLT_NAMESPACE);
1745     if (comp->test == NULL) {
1746 	xsltTransformError(NULL, style, inst,
1747 	     "xsl:when : test is not defined\n");
1748 	if (style != NULL) style->errors++;
1749 	return;
1750     }
1751     comp->comp = xsltXPathCompile(style, comp->test);
1752     if (comp->comp == NULL) {
1753 	xsltTransformError(NULL, style, inst,
1754 	     "xsl:when : could not compile test expression '%s'\n",
1755 	                 comp->test);
1756 	if (style != NULL) style->errors++;
1757     }
1758 }
1759 
1760 /**
1761  * xsltForEachComp:
1762  * @style: an XSLT compiled stylesheet
1763  * @inst:  the xslt for-each node
1764  *
1765  * Process the xslt for-each node on the source node
1766  */
1767 static void
xsltForEachComp(xsltStylesheetPtr style,xmlNodePtr inst)1768 xsltForEachComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1769 #ifdef XSLT_REFACTORED
1770     xsltStyleItemForEachPtr comp;
1771 #else
1772     xsltStylePreCompPtr comp;
1773 #endif
1774 
1775     if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1776 	return;
1777 
1778 #ifdef XSLT_REFACTORED
1779     comp = (xsltStyleItemForEachPtr)
1780 	xsltNewStylePreComp(style, XSLT_FUNC_FOREACH);
1781 #else
1782     comp = xsltNewStylePreComp(style, XSLT_FUNC_FOREACH);
1783 #endif
1784 
1785     if (comp == NULL)
1786 	return;
1787     inst->psvi = comp;
1788     comp->inst = inst;
1789 
1790     comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
1791 	                        XSLT_NAMESPACE);
1792     if (comp->select == NULL) {
1793 	xsltTransformError(NULL, style, inst,
1794 		"xsl:for-each : select is missing\n");
1795 	if (style != NULL) style->errors++;
1796     } else {
1797 	comp->comp = xsltXPathCompile(style, comp->select);
1798 	if (comp->comp == NULL) {
1799 	    xsltTransformError(NULL, style, inst,
1800      "xsl:for-each : could not compile select expression '%s'\n",
1801 			     comp->select);
1802 	    if (style != NULL) style->errors++;
1803 	}
1804     }
1805     /* TODO: handle and skip the xsl:sort */
1806 }
1807 
1808 /**
1809  * xsltVariableComp:
1810  * @style: an XSLT compiled stylesheet
1811  * @inst:  the xslt variable node
1812  *
1813  * Process the xslt variable node on the source node
1814  */
1815 static void
xsltVariableComp(xsltStylesheetPtr style,xmlNodePtr inst)1816 xsltVariableComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1817 #ifdef XSLT_REFACTORED
1818     xsltStyleItemVariablePtr comp;
1819 #else
1820     xsltStylePreCompPtr comp;
1821 #endif
1822 
1823     if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1824 	return;
1825 
1826 #ifdef XSLT_REFACTORED
1827     comp = (xsltStyleItemVariablePtr)
1828 	xsltNewStylePreComp(style, XSLT_FUNC_VARIABLE);
1829 #else
1830     comp = xsltNewStylePreComp(style, XSLT_FUNC_VARIABLE);
1831 #endif
1832 
1833     if (comp == NULL)
1834 	return;
1835 
1836     inst->psvi = comp;
1837     comp->inst = inst;
1838     /*
1839      * The full template resolution can be done statically
1840      */
1841 
1842     /*
1843     * Attribute "name".
1844     */
1845     xsltGetQNameProperty(style, inst, BAD_CAST "name",
1846 	1, &(comp->has_name), &(comp->ns), &(comp->name));
1847     if (comp->ns)
1848 	comp->has_ns = 1;
1849     /*
1850     * Attribute "select".
1851     */
1852     comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
1853 	                        XSLT_NAMESPACE);
1854     if (comp->select != NULL) {
1855 #ifndef XSLT_REFACTORED
1856         xmlNodePtr cur;
1857 #endif
1858 	comp->comp = xsltXPathCompile(style, comp->select);
1859 	if (comp->comp == NULL) {
1860 	    xsltTransformError(NULL, style, inst,
1861 		"XSLT-variable: Failed to compile the XPath expression '%s'.\n",
1862 		comp->select);
1863 	    style->errors++;
1864 	}
1865 #ifdef XSLT_REFACTORED
1866 	if (inst->children != NULL) {
1867 	    xsltTransformError(NULL, style, inst,
1868 		"XSLT-variable: There must be no child nodes, since the "
1869 		"attribute 'select' was specified.\n");
1870 	    style->errors++;
1871 	}
1872 #else
1873         for (cur = inst->children; cur != NULL; cur = cur->next) {
1874             if (cur->type != XML_COMMENT_NODE &&
1875                 (cur->type != XML_TEXT_NODE || !xsltIsBlank(cur->content)))
1876             {
1877                 xsltTransformError(NULL, style, inst,
1878                     "XSLT-variable: There must be no child nodes, since the "
1879                     "attribute 'select' was specified.\n");
1880                 style->errors++;
1881             }
1882         }
1883 #endif
1884     }
1885 }
1886 
1887 /**
1888  * xsltParamComp:
1889  * @style: an XSLT compiled stylesheet
1890  * @inst:  the xslt param node
1891  *
1892  * Process the xslt param node on the source node
1893  */
1894 static void
xsltParamComp(xsltStylesheetPtr style,xmlNodePtr inst)1895 xsltParamComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1896 #ifdef XSLT_REFACTORED
1897     xsltStyleItemParamPtr comp;
1898 #else
1899     xsltStylePreCompPtr comp;
1900 #endif
1901 
1902     if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1903 	return;
1904 
1905 #ifdef XSLT_REFACTORED
1906     comp = (xsltStyleItemParamPtr)
1907 	xsltNewStylePreComp(style, XSLT_FUNC_PARAM);
1908 #else
1909     comp = xsltNewStylePreComp(style, XSLT_FUNC_PARAM);
1910 #endif
1911 
1912     if (comp == NULL)
1913 	return;
1914     inst->psvi = comp;
1915     comp->inst = inst;
1916 
1917     /*
1918      * Attribute "name".
1919      */
1920     xsltGetQNameProperty(style, inst, BAD_CAST "name",
1921 	1, &(comp->has_name), &(comp->ns), &(comp->name));
1922     if (comp->ns)
1923 	comp->has_ns = 1;
1924     /*
1925     * Attribute "select".
1926     */
1927     comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
1928 	                        XSLT_NAMESPACE);
1929     if (comp->select != NULL) {
1930 	comp->comp = xsltXPathCompile(style, comp->select);
1931 	if (comp->comp == NULL) {
1932 	    xsltTransformError(NULL, style, inst,
1933 		"XSLT-param: could not compile select expression '%s'.\n",
1934 		comp->select);
1935 	    style->errors++;
1936 	}
1937 	if (inst->children != NULL) {
1938 	    xsltTransformError(NULL, style, inst,
1939 		"XSLT-param: The content should be empty since the "
1940 		"attribute 'select' is present.\n");
1941 	    style->warnings++;
1942 	}
1943     }
1944 }
1945 
1946 /************************************************************************
1947  *									*
1948  *		    Generic interface					*
1949  *									*
1950  ************************************************************************/
1951 
1952 /**
1953  * xsltFreeStylePreComps:
1954  * @style:  an XSLT transformation context
1955  *
1956  * Free up the memory allocated by all precomputed blocks
1957  */
1958 void
xsltFreeStylePreComps(xsltStylesheetPtr style)1959 xsltFreeStylePreComps(xsltStylesheetPtr style) {
1960     xsltElemPreCompPtr cur, next;
1961 
1962     if (style == NULL)
1963 	return;
1964 
1965     cur = style->preComps;
1966     while (cur != NULL) {
1967 	next = cur->next;
1968 	if (cur->type == XSLT_FUNC_EXTENSION)
1969 	    cur->free(cur);
1970 	else
1971 	    xsltFreeStylePreComp((xsltStylePreCompPtr) cur);
1972 	cur = next;
1973     }
1974 }
1975 
1976 #ifdef XSLT_REFACTORED
1977 
1978 /**
1979  * xsltStylePreCompute:
1980  * @style:  the XSLT stylesheet
1981  * @node:  the element in the XSLT namespace
1982  *
1983  * Precompute an XSLT element.
1984  * This expects the type of the element to be already
1985  * set in style->compCtxt->inode->type;
1986  */
1987 void
xsltStylePreCompute(xsltStylesheetPtr style,xmlNodePtr node)1988 xsltStylePreCompute(xsltStylesheetPtr style, xmlNodePtr node) {
1989     /*
1990     * The xsltXSLTElemMarker marker was set beforehand by
1991     *  the parsing mechanism for all elements in the XSLT namespace.
1992     */
1993     if (style == NULL) {
1994 	if ((node != NULL) && (node->type == XML_ELEMENT_NODE))
1995 	    node->psvi = NULL;
1996 	return;
1997     }
1998     if (node == NULL)
1999 	return;
2000     if (! IS_XSLT_ELEM_FAST(node))
2001 	return;
2002 
2003     node->psvi = NULL;
2004     if (XSLT_CCTXT(style)->inode->type != 0) {
2005 	switch (XSLT_CCTXT(style)->inode->type) {
2006 	    case XSLT_FUNC_APPLYTEMPLATES:
2007 		xsltApplyTemplatesComp(style, node);
2008 		break;
2009 	    case XSLT_FUNC_WITHPARAM:
2010 		xsltWithParamComp(style, node);
2011 		break;
2012 	    case XSLT_FUNC_VALUEOF:
2013 		xsltValueOfComp(style, node);
2014 		break;
2015 	    case XSLT_FUNC_COPY:
2016 		xsltCopyComp(style, node);
2017 		break;
2018 	    case XSLT_FUNC_COPYOF:
2019 		xsltCopyOfComp(style, node);
2020 		break;
2021 	    case XSLT_FUNC_IF:
2022 		xsltIfComp(style, node);
2023 		break;
2024 	    case XSLT_FUNC_CHOOSE:
2025 		xsltChooseComp(style, node);
2026 		break;
2027 	    case XSLT_FUNC_WHEN:
2028 		xsltWhenComp(style, node);
2029 		break;
2030 	    case XSLT_FUNC_OTHERWISE:
2031 		/* NOP yet */
2032 		return;
2033 	    case XSLT_FUNC_FOREACH:
2034 		xsltForEachComp(style, node);
2035 		break;
2036 	    case XSLT_FUNC_APPLYIMPORTS:
2037 		xsltApplyImportsComp(style, node);
2038 		break;
2039 	    case XSLT_FUNC_ATTRIBUTE:
2040 		xsltAttributeComp(style, node);
2041 		break;
2042 	    case XSLT_FUNC_ELEMENT:
2043 		xsltElementComp(style, node);
2044 		break;
2045 	    case XSLT_FUNC_SORT:
2046 		xsltSortComp(style, node);
2047 		break;
2048 	    case XSLT_FUNC_COMMENT:
2049 		xsltCommentComp(style, node);
2050 		break;
2051 	    case XSLT_FUNC_NUMBER:
2052 		xsltNumberComp(style, node);
2053 		break;
2054 	    case XSLT_FUNC_PI:
2055 		xsltProcessingInstructionComp(style, node);
2056 		break;
2057 	    case XSLT_FUNC_CALLTEMPLATE:
2058 		xsltCallTemplateComp(style, node);
2059 		break;
2060 	    case XSLT_FUNC_PARAM:
2061 		xsltParamComp(style, node);
2062 		break;
2063 	    case XSLT_FUNC_VARIABLE:
2064 		xsltVariableComp(style, node);
2065 		break;
2066 	    case XSLT_FUNC_FALLBACK:
2067 		/* NOP yet */
2068 		return;
2069 	    case XSLT_FUNC_DOCUMENT:
2070 		/* The extra one */
2071 		node->psvi = (void *) xsltDocumentComp(style, node,
2072 		    xsltDocumentElem);
2073 		break;
2074 	    case XSLT_FUNC_MESSAGE:
2075 		/* NOP yet */
2076 		return;
2077 	    default:
2078 		/*
2079 		* NOTE that xsl:text, xsl:template, xsl:stylesheet,
2080 		*  xsl:transform, xsl:import, xsl:include are not expected
2081 		*  to be handed over to this function.
2082 		*/
2083 		xsltTransformError(NULL, style, node,
2084 		    "Internal error: (xsltStylePreCompute) cannot handle "
2085 		    "the XSLT element '%s'.\n", node->name);
2086 		style->errors++;
2087 		return;
2088 	}
2089     } else {
2090 	/*
2091 	* Fallback to string comparison.
2092 	*/
2093 	if (IS_XSLT_NAME(node, "apply-templates")) {
2094 	    xsltApplyTemplatesComp(style, node);
2095 	} else if (IS_XSLT_NAME(node, "with-param")) {
2096 	    xsltWithParamComp(style, node);
2097 	} else if (IS_XSLT_NAME(node, "value-of")) {
2098 	    xsltValueOfComp(style, node);
2099 	} else if (IS_XSLT_NAME(node, "copy")) {
2100 	    xsltCopyComp(style, node);
2101 	} else if (IS_XSLT_NAME(node, "copy-of")) {
2102 	    xsltCopyOfComp(style, node);
2103 	} else if (IS_XSLT_NAME(node, "if")) {
2104 	    xsltIfComp(style, node);
2105 	} else if (IS_XSLT_NAME(node, "choose")) {
2106 	    xsltChooseComp(style, node);
2107 	} else if (IS_XSLT_NAME(node, "when")) {
2108 	    xsltWhenComp(style, node);
2109 	} else if (IS_XSLT_NAME(node, "otherwise")) {
2110 	    /* NOP yet */
2111 	    return;
2112 	} else if (IS_XSLT_NAME(node, "for-each")) {
2113 	    xsltForEachComp(style, node);
2114 	} else if (IS_XSLT_NAME(node, "apply-imports")) {
2115 	    xsltApplyImportsComp(style, node);
2116 	} else if (IS_XSLT_NAME(node, "attribute")) {
2117 	    xsltAttributeComp(style, node);
2118 	} else if (IS_XSLT_NAME(node, "element")) {
2119 	    xsltElementComp(style, node);
2120 	} else if (IS_XSLT_NAME(node, "sort")) {
2121 	    xsltSortComp(style, node);
2122 	} else if (IS_XSLT_NAME(node, "comment")) {
2123 	    xsltCommentComp(style, node);
2124 	} else if (IS_XSLT_NAME(node, "number")) {
2125 	    xsltNumberComp(style, node);
2126 	} else if (IS_XSLT_NAME(node, "processing-instruction")) {
2127 	    xsltProcessingInstructionComp(style, node);
2128 	} else if (IS_XSLT_NAME(node, "call-template")) {
2129 	    xsltCallTemplateComp(style, node);
2130 	} else if (IS_XSLT_NAME(node, "param")) {
2131 	    xsltParamComp(style, node);
2132 	} else if (IS_XSLT_NAME(node, "variable")) {
2133 	    xsltVariableComp(style, node);
2134 	} else if (IS_XSLT_NAME(node, "fallback")) {
2135 	    /* NOP yet */
2136 	    return;
2137 	} else if (IS_XSLT_NAME(node, "document")) {
2138 	    /* The extra one */
2139 	    node->psvi = (void *) xsltDocumentComp(style, node,
2140 		xsltDocumentElem);
2141 	} else if (IS_XSLT_NAME(node, "output")) {
2142 	    /* Top-level */
2143 	    return;
2144 	} else if (IS_XSLT_NAME(node, "preserve-space")) {
2145 	    /* Top-level */
2146 	    return;
2147 	} else if (IS_XSLT_NAME(node, "strip-space")) {
2148 	    /* Top-level */
2149 	    return;
2150 	} else if (IS_XSLT_NAME(node, "key")) {
2151 	    /* Top-level */
2152 	    return;
2153 	} else if (IS_XSLT_NAME(node, "message")) {
2154 	    return;
2155 	} else if (IS_XSLT_NAME(node, "attribute-set")) {
2156 	    /* Top-level */
2157 	    return;
2158 	} else if (IS_XSLT_NAME(node, "namespace-alias")) {
2159 	    /* Top-level */
2160 	    return;
2161 	} else if (IS_XSLT_NAME(node, "decimal-format")) {
2162 	    /* Top-level */
2163 	    return;
2164 	} else if (IS_XSLT_NAME(node, "include")) {
2165 	    /* Top-level */
2166 	} else {
2167 	    /*
2168 	    * NOTE that xsl:text, xsl:template, xsl:stylesheet,
2169 	    *  xsl:transform, xsl:import, xsl:include are not expected
2170 	    *  to be handed over to this function.
2171 	    */
2172 	    xsltTransformError(NULL, style, node,
2173 		"Internal error: (xsltStylePreCompute) cannot handle "
2174 		"the XSLT element '%s'.\n", node->name);
2175 		style->errors++;
2176 	    return;
2177 	}
2178     }
2179     /*
2180     * Assign the current list of in-scope namespaces to the
2181     * item. This is needed for XPath expressions.
2182     */
2183     if (node->psvi != NULL) {
2184 	((xsltStylePreCompPtr) node->psvi)->inScopeNs =
2185 	    XSLT_CCTXT(style)->inode->inScopeNs;
2186     }
2187 }
2188 
2189 #else
2190 
2191 /**
2192  * xsltStylePreCompute:
2193  * @style:  the XSLT stylesheet
2194  * @inst:  the instruction in the stylesheet
2195  *
2196  * Precompute an XSLT stylesheet element
2197  */
2198 void
xsltStylePreCompute(xsltStylesheetPtr style,xmlNodePtr inst)2199 xsltStylePreCompute(xsltStylesheetPtr style, xmlNodePtr inst) {
2200     /*
2201     * URGENT TODO: Normally inst->psvi Should never be reserved here,
2202     *   BUT: since if we include the same stylesheet from
2203     *   multiple imports, then the stylesheet will be parsed
2204     *   again. We simply must not try to compute the stylesheet again.
2205     * TODO: Get to the point where we don't need to query the
2206     *   namespace- and local-name of the node, but can evaluate this
2207     *   using cctxt->style->inode->category;
2208     */
2209     if ((inst == NULL) || (inst->type != XML_ELEMENT_NODE) ||
2210         (inst->psvi != NULL))
2211 	return;
2212 
2213     if (IS_XSLT_ELEM(inst)) {
2214 	xsltStylePreCompPtr cur;
2215 
2216 	if (IS_XSLT_NAME(inst, "apply-templates")) {
2217 	    xsltCheckInstructionElement(style, inst);
2218 	    xsltApplyTemplatesComp(style, inst);
2219 	} else if (IS_XSLT_NAME(inst, "with-param")) {
2220 	    xsltCheckParentElement(style, inst, BAD_CAST "apply-templates",
2221 	                           BAD_CAST "call-template");
2222 	    xsltWithParamComp(style, inst);
2223 	} else if (IS_XSLT_NAME(inst, "value-of")) {
2224 	    xsltCheckInstructionElement(style, inst);
2225 	    xsltValueOfComp(style, inst);
2226 	} else if (IS_XSLT_NAME(inst, "copy")) {
2227 	    xsltCheckInstructionElement(style, inst);
2228 	    xsltCopyComp(style, inst);
2229 	} else if (IS_XSLT_NAME(inst, "copy-of")) {
2230 	    xsltCheckInstructionElement(style, inst);
2231 	    xsltCopyOfComp(style, inst);
2232 	} else if (IS_XSLT_NAME(inst, "if")) {
2233 	    xsltCheckInstructionElement(style, inst);
2234 	    xsltIfComp(style, inst);
2235 	} else if (IS_XSLT_NAME(inst, "when")) {
2236 	    xsltCheckParentElement(style, inst, BAD_CAST "choose", NULL);
2237 	    xsltWhenComp(style, inst);
2238 	} else if (IS_XSLT_NAME(inst, "choose")) {
2239 	    xsltCheckInstructionElement(style, inst);
2240 	    xsltChooseComp(style, inst);
2241 	} else if (IS_XSLT_NAME(inst, "for-each")) {
2242 	    xsltCheckInstructionElement(style, inst);
2243 	    xsltForEachComp(style, inst);
2244 	} else if (IS_XSLT_NAME(inst, "apply-imports")) {
2245 	    xsltCheckInstructionElement(style, inst);
2246 	    xsltApplyImportsComp(style, inst);
2247 	} else if (IS_XSLT_NAME(inst, "attribute")) {
2248 	    xmlNodePtr parent = inst->parent;
2249 
2250 	    if ((parent == NULL) ||
2251 	        (parent->type != XML_ELEMENT_NODE) || (parent->ns == NULL) ||
2252 		((parent->ns != inst->ns) &&
2253 		 (!xmlStrEqual(parent->ns->href, inst->ns->href))) ||
2254 		(!xmlStrEqual(parent->name, BAD_CAST "attribute-set"))) {
2255 		xsltCheckInstructionElement(style, inst);
2256 	    }
2257 	    xsltAttributeComp(style, inst);
2258 	} else if (IS_XSLT_NAME(inst, "element")) {
2259 	    xsltCheckInstructionElement(style, inst);
2260 	    xsltElementComp(style, inst);
2261 	} else if (IS_XSLT_NAME(inst, "text")) {
2262 	    xsltCheckInstructionElement(style, inst);
2263 	    xsltTextComp(style, inst);
2264 	} else if (IS_XSLT_NAME(inst, "sort")) {
2265 	    xsltCheckParentElement(style, inst, BAD_CAST "apply-templates",
2266 	                           BAD_CAST "for-each");
2267 	    xsltSortComp(style, inst);
2268 	} else if (IS_XSLT_NAME(inst, "comment")) {
2269 	    xsltCheckInstructionElement(style, inst);
2270 	    xsltCommentComp(style, inst);
2271 	} else if (IS_XSLT_NAME(inst, "number")) {
2272 	    xsltCheckInstructionElement(style, inst);
2273 	    xsltNumberComp(style, inst);
2274 	} else if (IS_XSLT_NAME(inst, "processing-instruction")) {
2275 	    xsltCheckInstructionElement(style, inst);
2276 	    xsltProcessingInstructionComp(style, inst);
2277 	} else if (IS_XSLT_NAME(inst, "call-template")) {
2278 	    xsltCheckInstructionElement(style, inst);
2279 	    xsltCallTemplateComp(style, inst);
2280 	} else if (IS_XSLT_NAME(inst, "param")) {
2281 	    if (xsltCheckTopLevelElement(style, inst, 0) == 0)
2282 	        xsltCheckInstructionElement(style, inst);
2283 	    xsltParamComp(style, inst);
2284 	} else if (IS_XSLT_NAME(inst, "variable")) {
2285 	    if (xsltCheckTopLevelElement(style, inst, 0) == 0)
2286 	        xsltCheckInstructionElement(style, inst);
2287 	    xsltVariableComp(style, inst);
2288 	} else if (IS_XSLT_NAME(inst, "otherwise")) {
2289 	    xsltCheckParentElement(style, inst, BAD_CAST "choose", NULL);
2290 	    xsltCheckInstructionElement(style, inst);
2291 	    return;
2292 	} else if (IS_XSLT_NAME(inst, "template")) {
2293 	    xsltCheckTopLevelElement(style, inst, 1);
2294 	    return;
2295 	} else if (IS_XSLT_NAME(inst, "output")) {
2296 	    xsltCheckTopLevelElement(style, inst, 1);
2297 	    return;
2298 	} else if (IS_XSLT_NAME(inst, "preserve-space")) {
2299 	    xsltCheckTopLevelElement(style, inst, 1);
2300 	    return;
2301 	} else if (IS_XSLT_NAME(inst, "strip-space")) {
2302 	    xsltCheckTopLevelElement(style, inst, 1);
2303 	    return;
2304 	} else if ((IS_XSLT_NAME(inst, "stylesheet")) ||
2305 	           (IS_XSLT_NAME(inst, "transform"))) {
2306 	    xmlNodePtr parent = inst->parent;
2307 
2308 	    if ((parent == NULL) || (parent->type != XML_DOCUMENT_NODE)) {
2309 		xsltTransformError(NULL, style, inst,
2310 		    "element %s only allowed only as root element\n",
2311 				   inst->name);
2312 		style->errors++;
2313 	    }
2314 	    return;
2315 	} else if (IS_XSLT_NAME(inst, "key")) {
2316 	    xsltCheckTopLevelElement(style, inst, 1);
2317 	    return;
2318 	} else if (IS_XSLT_NAME(inst, "message")) {
2319 	    xsltCheckInstructionElement(style, inst);
2320 	    return;
2321 	} else if (IS_XSLT_NAME(inst, "attribute-set")) {
2322 	    xsltCheckTopLevelElement(style, inst, 1);
2323 	    return;
2324 	} else if (IS_XSLT_NAME(inst, "namespace-alias")) {
2325 	    xsltCheckTopLevelElement(style, inst, 1);
2326 	    return;
2327 	} else if (IS_XSLT_NAME(inst, "include")) {
2328 	    xsltCheckTopLevelElement(style, inst, 1);
2329 	    return;
2330 	} else if (IS_XSLT_NAME(inst, "import")) {
2331 	    xsltCheckTopLevelElement(style, inst, 1);
2332 	    return;
2333 	} else if (IS_XSLT_NAME(inst, "decimal-format")) {
2334 	    xsltCheckTopLevelElement(style, inst, 1);
2335 	    return;
2336 	} else if (IS_XSLT_NAME(inst, "fallback")) {
2337 	    xsltCheckInstructionElement(style, inst);
2338 	    return;
2339 	} else if (IS_XSLT_NAME(inst, "document")) {
2340 	    xsltCheckInstructionElement(style, inst);
2341 	    inst->psvi = (void *) xsltDocumentComp(style, inst,
2342 				xsltDocumentElem);
2343 	} else if ((style == NULL) || (style->forwards_compatible == 0)) {
2344 	    xsltTransformError(NULL, style, inst,
2345 		 "xsltStylePreCompute: unknown xsl:%s\n", inst->name);
2346 	    if (style != NULL) style->warnings++;
2347 	}
2348 
2349 	cur = (xsltStylePreCompPtr) inst->psvi;
2350 	/*
2351 	* A ns-list is build for every XSLT item in the
2352 	* node-tree. This is needed for XPath expressions.
2353 	*/
2354 	if (cur != NULL) {
2355 	    int i = 0;
2356 
2357 	    cur->nsList = xmlGetNsList(inst->doc, inst);
2358             if (cur->nsList != NULL) {
2359 		while (cur->nsList[i] != NULL)
2360 		    i++;
2361 	    }
2362 	    cur->nsNr = i;
2363 	}
2364     } else {
2365 	inst->psvi =
2366 	    (void *) xsltPreComputeExtModuleElement(style, inst);
2367 
2368 	/*
2369 	 * Unknown element, maybe registered at the context
2370 	 * level. Mark it for later recognition.
2371 	 */
2372 	if (inst->psvi == NULL)
2373 	    inst->psvi = (void *) xsltExtMarker;
2374     }
2375 }
2376 #endif /* XSLT_REFACTORED */
2377