• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #define IN_LIBEXSLT
2 #include "libexslt/libexslt.h"
3 
4 #if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__)
5 #include <win32config.h>
6 #else
7 #include "config.h"
8 #endif
9 
10 #include <string.h>
11 
12 #include <libxml/tree.h>
13 #include <libxml/xpath.h>
14 #include <libxml/xpathInternals.h>
15 #include <libxml/hash.h>
16 #include <libxml/debugXML.h>
17 
18 #include <libxslt/xsltutils.h>
19 #include <libxslt/variables.h>
20 #include <libxslt/xsltInternals.h>
21 #include <libxslt/extensions.h>
22 #include <libxslt/transform.h>
23 #include <libxslt/imports.h>
24 
25 #include "exslt.h"
26 
27 typedef struct _exsltFuncFunctionData exsltFuncFunctionData;
28 struct _exsltFuncFunctionData {
29     int nargs;			/* number of arguments to the function */
30     xmlNodePtr content;		/* the func:fuction template content */
31 };
32 
33 typedef struct _exsltFuncData exsltFuncData;
34 struct _exsltFuncData {
35     xmlHashTablePtr funcs;	/* pointer to the stylesheet module data */
36     xmlXPathObjectPtr result;	/* returned by func:result */
37     int error;			/* did an error occur? */
38     xmlDocPtr RVT;   /* result tree fragment */
39 };
40 
41 typedef struct _exsltFuncResultPreComp exsltFuncResultPreComp;
42 struct _exsltFuncResultPreComp {
43     xsltElemPreComp comp;
44     xmlXPathCompExprPtr select;
45     xmlNsPtr *nsList;
46     int nsNr;
47 };
48 
49 /* Used for callback function in exsltInitFunc */
50 typedef struct _exsltFuncImportRegData exsltFuncImportRegData;
51 struct _exsltFuncImportRegData {
52     xsltTransformContextPtr ctxt;
53     xmlHashTablePtr hash;
54 };
55 
56 static void exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt,
57 				       int nargs);
58 static exsltFuncFunctionData *exsltFuncNewFunctionData(void);
59 
60 #define MAX_FUNC_RECURSION 1000
61 
62 /*static const xmlChar *exsltResultDataID = (const xmlChar *) "EXSLT Result";*/
63 
64 /**
65  * exsltFuncRegisterFunc:
66  * @func:  the #exsltFuncFunctionData for the function
67  * @ctxt:  an XSLT transformation context
68  * @URI:  the function namespace URI
69  * @name: the function name
70  *
71  * Registers a function declared by a func:function element
72  */
73 static void
exsltFuncRegisterFunc(exsltFuncFunctionData * data,xsltTransformContextPtr ctxt,const xmlChar * URI,const xmlChar * name,ATTRIBUTE_UNUSED const xmlChar * ignored)74 exsltFuncRegisterFunc (exsltFuncFunctionData *data,
75 		       xsltTransformContextPtr ctxt,
76 		       const xmlChar *URI, const xmlChar *name,
77 		       ATTRIBUTE_UNUSED const xmlChar *ignored) {
78     if ((data == NULL) || (ctxt == NULL) || (URI == NULL) || (name == NULL))
79 	return;
80 
81     xsltGenericDebug(xsltGenericDebugContext,
82 		     "exsltFuncRegisterFunc: register {%s}%s\n",
83 		     URI, name);
84     xsltRegisterExtFunction(ctxt, name, URI,
85 			    exsltFuncFunctionFunction);
86 }
87 
88 /*
89  * exsltFuncRegisterImportFunc
90  * @data:    the exsltFuncFunctionData for the function
91  * @ch:	     structure containing context and hash table
92  * @URI:     the function namespace URI
93  * @name:    the function name
94  *
95  * Checks if imported function is already registered in top-level
96  * stylesheet.  If not, copies function data and registers function
97  */
98 static void
exsltFuncRegisterImportFunc(exsltFuncFunctionData * data,exsltFuncImportRegData * ch,const xmlChar * URI,const xmlChar * name,ATTRIBUTE_UNUSED const xmlChar * ignored)99 exsltFuncRegisterImportFunc (exsltFuncFunctionData *data,
100 			     exsltFuncImportRegData *ch,
101 			     const xmlChar *URI, const xmlChar *name,
102 			     ATTRIBUTE_UNUSED const xmlChar *ignored) {
103     exsltFuncFunctionData *func=NULL;
104 
105     if ((data == NULL) || (ch == NULL) || (URI == NULL) || (name == NULL))
106             return;
107 
108     if (ch->ctxt == NULL || ch->hash == NULL)
109     	return;
110 
111     /* Check if already present */
112     func = (exsltFuncFunctionData*)xmlHashLookup2(ch->hash, URI, name);
113     if (func == NULL) {		/* Not yet present - copy it in */
114     	func = exsltFuncNewFunctionData();
115 	memcpy(func, data, sizeof(exsltFuncFunctionData));
116 	if (xmlHashAddEntry2(ch->hash, URI, name, func) < 0) {
117 	    xsltGenericError(xsltGenericErrorContext,
118 	    	    "Failed to register function {%s}%s\n",
119 		    URI, name);
120 	} else {		/* Do the registration */
121 	    xsltGenericDebug(xsltGenericDebugContext,
122 	            "exsltFuncRegisterImportFunc: register {%s}%s\n",
123 		    URI, name);
124 	    xsltRegisterExtFunction(ch->ctxt, name, URI,
125 		    exsltFuncFunctionFunction);
126 	}
127     }
128 }
129 
130 /**
131  * exsltFuncInit:
132  * @ctxt: an XSLT transformation context
133  * @URI: the namespace URI for the extension
134  *
135  * Initializes the EXSLT - Functions module.
136  * Called at transformation-time; merges all
137  * functions declared in the import tree taking
138  * import precedence into account, i.e. overriding
139  * functions with lower import precedence.
140  *
141  * Returns the data for this transformation
142  */
143 static exsltFuncData *
exsltFuncInit(xsltTransformContextPtr ctxt,const xmlChar * URI)144 exsltFuncInit (xsltTransformContextPtr ctxt, const xmlChar *URI) {
145     exsltFuncData *ret;
146     xsltStylesheetPtr tmp;
147     exsltFuncImportRegData ch;
148     xmlHashTablePtr hash;
149 
150     ret = (exsltFuncData *) xmlMalloc (sizeof(exsltFuncData));
151     if (ret == NULL) {
152 	xsltGenericError(xsltGenericErrorContext,
153 			 "exsltFuncInit: not enough memory\n");
154 	return(NULL);
155     }
156     memset(ret, 0, sizeof(exsltFuncData));
157 
158     ret->result = NULL;
159     ret->error = 0;
160 
161     ch.hash = (xmlHashTablePtr) xsltStyleGetExtData(ctxt->style, URI);
162     ret->funcs = ch.hash;
163     xmlHashScanFull(ch.hash, (xmlHashScannerFull) exsltFuncRegisterFunc, ctxt);
164     tmp = ctxt->style;
165     ch.ctxt = ctxt;
166     while ((tmp=xsltNextImport(tmp))!=NULL) {
167 	hash = xsltGetExtInfo(tmp, URI);
168 	if (hash != NULL) {
169 	    xmlHashScanFull(hash,
170 		    (xmlHashScannerFull) exsltFuncRegisterImportFunc, &ch);
171 	}
172     }
173 
174     return(ret);
175 }
176 
177 /**
178  * exsltFuncShutdown:
179  * @ctxt: an XSLT transformation context
180  * @URI: the namespace URI for the extension
181  * @data: the module data to free up
182  *
183  * Shutdown the EXSLT - Functions module
184  * Called at transformation-time.
185  */
186 static void
exsltFuncShutdown(xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED,const xmlChar * URI ATTRIBUTE_UNUSED,exsltFuncData * data)187 exsltFuncShutdown (xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED,
188 		   const xmlChar *URI ATTRIBUTE_UNUSED,
189 		   exsltFuncData *data) {
190     if (data->result != NULL)
191 	xmlXPathFreeObject(data->result);
192     xmlFree(data);
193 }
194 
195 /**
196  * exsltFuncStyleInit:
197  * @style: an XSLT stylesheet
198  * @URI: the namespace URI for the extension
199  *
200  * Allocates the stylesheet data for EXSLT - Function
201  * Called at compile-time.
202  *
203  * Returns the allocated data
204  */
205 static xmlHashTablePtr
exsltFuncStyleInit(xsltStylesheetPtr style ATTRIBUTE_UNUSED,const xmlChar * URI ATTRIBUTE_UNUSED)206 exsltFuncStyleInit (xsltStylesheetPtr style ATTRIBUTE_UNUSED,
207 		    const xmlChar *URI ATTRIBUTE_UNUSED) {
208     return xmlHashCreate(1);
209 }
210 
211 /**
212  * exsltFuncStyleShutdown:
213  * @style: an XSLT stylesheet
214  * @URI: the namespace URI for the extension
215  * @data: the stylesheet data to free up
216  *
217  * Shutdown the EXSLT - Function module
218  * Called at compile-time.
219  */
220 static void
exsltFuncStyleShutdown(xsltStylesheetPtr style ATTRIBUTE_UNUSED,const xmlChar * URI ATTRIBUTE_UNUSED,xmlHashTablePtr data)221 exsltFuncStyleShutdown (xsltStylesheetPtr style ATTRIBUTE_UNUSED,
222 			const xmlChar *URI ATTRIBUTE_UNUSED,
223 			xmlHashTablePtr data) {
224     xmlHashFree(data, (xmlHashDeallocator) xmlFree);
225 }
226 
227 /**
228  * exsltFuncNewFunctionData:
229  *
230  * Allocates an #exslFuncFunctionData object
231  *
232  * Returns the new structure
233  */
234 static exsltFuncFunctionData *
exsltFuncNewFunctionData(void)235 exsltFuncNewFunctionData (void) {
236     exsltFuncFunctionData *ret;
237 
238     ret = (exsltFuncFunctionData *) xmlMalloc (sizeof(exsltFuncFunctionData));
239     if (ret == NULL) {
240 	xsltGenericError(xsltGenericErrorContext,
241 			 "exsltFuncNewFunctionData: not enough memory\n");
242 	return (NULL);
243     }
244     memset(ret, 0, sizeof(exsltFuncFunctionData));
245 
246     ret->nargs = 0;
247     ret->content = NULL;
248 
249     return(ret);
250 }
251 
252 /**
253  * exsltFreeFuncResultPreComp:
254  * @comp:  the #exsltFuncResultPreComp to free up
255  *
256  * Deallocates an #exsltFuncResultPreComp
257  */
258 static void
exsltFreeFuncResultPreComp(exsltFuncResultPreComp * comp)259 exsltFreeFuncResultPreComp (exsltFuncResultPreComp *comp) {
260     if (comp == NULL)
261 	return;
262 
263     if (comp->select != NULL)
264 	xmlXPathFreeCompExpr (comp->select);
265     if (comp->nsList != NULL)
266         xmlFree(comp->nsList);
267     xmlFree(comp);
268 }
269 
270 /**
271  * exsltFuncFunctionFunction:
272  * @ctxt:  an XPath parser context
273  * @nargs:  the number of arguments
274  *
275  * Evaluates the func:function element that defines the called function.
276  */
277 static void
exsltFuncFunctionFunction(xmlXPathParserContextPtr ctxt,int nargs)278 exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt, int nargs) {
279     xmlXPathObjectPtr oldResult, ret;
280     exsltFuncData *data;
281     exsltFuncFunctionData *func;
282     xmlNodePtr paramNode, oldInsert, fake;
283     int oldBase;
284     xsltStackElemPtr params = NULL, param;
285     xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt);
286     int i, notSet;
287     struct objChain {
288 	struct objChain *next;
289 	xmlXPathObjectPtr obj;
290     };
291     struct objChain	*savedObjChain = NULL, *savedObj;
292 
293     /*
294      * retrieve func:function template
295      */
296     data = (exsltFuncData *) xsltGetExtData (tctxt,
297 					     EXSLT_FUNCTIONS_NAMESPACE);
298     oldResult = data->result;
299     data->result = NULL;
300 
301     func = (exsltFuncFunctionData*) xmlHashLookup2 (data->funcs,
302 						    ctxt->context->functionURI,
303 						    ctxt->context->function);
304 
305     /*
306      * params handling
307      */
308     if (nargs > func->nargs) {
309 	xsltGenericError(xsltGenericErrorContext,
310 			 "{%s}%s: called with too many arguments\n",
311 			 ctxt->context->functionURI, ctxt->context->function);
312 	ctxt->error = XPATH_INVALID_ARITY;
313 	return;
314     }
315     if (func->content != NULL) {
316 	paramNode = func->content->prev;
317     }
318     else
319 	paramNode = NULL;
320     if ((paramNode == NULL) && (func->nargs != 0)) {
321 	xsltGenericError(xsltGenericErrorContext,
322 			 "exsltFuncFunctionFunction: nargs != 0 and "
323 			 "param == NULL\n");
324 	return;
325     }
326     if (tctxt->funcLevel > MAX_FUNC_RECURSION) {
327 	xsltGenericError(xsltGenericErrorContext,
328 			 "{%s}%s: detected a recursion\n",
329 			 ctxt->context->functionURI, ctxt->context->function);
330 	ctxt->error = XPATH_MEMORY_ERROR;
331 	return;
332     }
333     tctxt->funcLevel++;
334 
335     /*
336      * We have a problem with the evaluation of function parameters.
337      * The original library code did not evaluate XPath expressions until
338      * the last moment.  After version 1.1.17 of the libxslt, the logic
339      * of other parts of the library was changed, and the evaluation of
340      * XPath expressions within parameters now takes place as soon as the
341      * parameter is parsed/evaluated (xsltParseStylesheetCallerParam).
342      * This means that the parameters need to be evaluated in lexical
343      * order (since a variable is "in scope" as soon as it is declared).
344      * However, on entry to this routine, the values (from the caller) are
345      * in reverse order (held on the XPath context variable stack).  To
346      * accomplish what is required, I have added code to pop the XPath
347      * objects off of the stack at the beginning and save them, then use
348      * them (in the reverse order) as the params are evaluated.  This
349      * requires an xmlMalloc/xmlFree for each param set by the caller,
350      * which is not very nice.  There is probably a much better solution
351      * (like change other code to delay the evaluation).
352      */
353     /*
354      * In order to give the function params and variables a new 'scope'
355      * we change varsBase in the context.
356      */
357     oldBase = tctxt->varsBase;
358     tctxt->varsBase = tctxt->varsNr;
359     /* If there are any parameters */
360     if (paramNode != NULL) {
361         /* Fetch the stored argument values from the caller */
362 	for (i = 0; i < nargs; i++) {
363 	    savedObj = xmlMalloc(sizeof(struct objChain));
364 	    savedObj->next = savedObjChain;
365 	    savedObj->obj = valuePop(ctxt);
366 	    savedObjChain = savedObj;
367 	}
368 
369 	/*
370 	 * Prepare to process params in reverse order.  First, go to
371 	 * the beginning of the param chain.
372 	 */
373 	for (i = 1; i <= func->nargs; i++) {
374 	    if (paramNode->prev == NULL)
375 	        break;
376 	    paramNode = paramNode->prev;
377 	}
378 	/*
379 	 * i has total # params found, nargs is number which are present
380 	 * as arguments from the caller
381 	 * Calculate the number of un-set parameters
382 	 */
383 	notSet = func->nargs - nargs;
384 	for (; i > 0; i--) {
385 	    param = xsltParseStylesheetCallerParam (tctxt, paramNode);
386 	    if (i > notSet) {	/* if parameter value set */
387 		param->computed = 1;
388 		if (param->value != NULL)
389 		    xmlXPathFreeObject(param->value);
390 		savedObj = savedObjChain;	/* get next val from chain */
391 		param->value = savedObj->obj;
392 		savedObjChain = savedObjChain->next;
393 		xmlFree(savedObj);
394 	    }
395 	    xsltLocalVariablePush(tctxt, param, -1);
396 	    param->next = params;
397 	    params = param;
398 	    paramNode = paramNode->next;
399 	}
400     }
401     /*
402      * actual processing
403      */
404     fake = xmlNewDocNode(tctxt->output, NULL,
405 			 (const xmlChar *)"fake", NULL);
406     oldInsert = tctxt->insert;
407     tctxt->insert = fake;
408     xsltApplyOneTemplate (tctxt, xmlXPathGetContextNode(ctxt),
409 			  func->content, NULL, NULL);
410     xsltLocalVariablePop(tctxt, tctxt->varsBase, -2);
411     tctxt->insert = oldInsert;
412     tctxt->varsBase = oldBase;	/* restore original scope */
413     if (params != NULL)
414 	xsltFreeStackElemList(params);
415 
416     if (data->error != 0)
417 	goto error;
418 
419     if (data->result != NULL) {
420 	ret = data->result;
421     } else
422 	ret = xmlXPathNewCString("");
423 
424     data->result = oldResult;
425 
426     /*
427      * It is an error if the instantiation of the template results in
428      * the generation of result nodes.
429      */
430     if (fake->children != NULL) {
431 #ifdef LIBXML_DEBUG_ENABLED
432 	xmlDebugDumpNode (stderr, fake, 1);
433 #endif
434 	xsltGenericError(xsltGenericErrorContext,
435 			 "{%s}%s: cannot write to result tree while "
436 			 "executing a function\n",
437 			 ctxt->context->functionURI, ctxt->context->function);
438 	xmlFreeNode(fake);
439 	goto error;
440     }
441     xmlFreeNode(fake);
442     valuePush(ctxt, ret);
443 
444 error:
445     /*
446     * IMPORTANT: This enables previously tree fragments marked as
447     * being results of a function, to be garbage-collected after
448     * the calling process exits.
449     */
450     xsltExtensionInstructionResultFinalize(tctxt);
451     tctxt->funcLevel--;
452 }
453 
454 
455 static void
exsltFuncFunctionComp(xsltStylesheetPtr style,xmlNodePtr inst)456 exsltFuncFunctionComp (xsltStylesheetPtr style, xmlNodePtr inst) {
457     xmlChar *name, *prefix;
458     xmlNsPtr ns;
459     xmlHashTablePtr data;
460     exsltFuncFunctionData *func;
461 
462     if ((style == NULL) || (inst == NULL))
463 	return;
464 
465 
466     {
467 	xmlChar *qname;
468 
469 	qname = xmlGetProp(inst, (const xmlChar *) "name");
470 	name = xmlSplitQName2 (qname, &prefix);
471 	xmlFree(qname);
472     }
473     if ((name == NULL) || (prefix == NULL)) {
474 	xsltGenericError(xsltGenericErrorContext,
475 			 "func:function: not a QName\n");
476 	if (name != NULL)
477 	    xmlFree(name);
478 	return;
479     }
480     /* namespace lookup */
481     ns = xmlSearchNs (inst->doc, inst, prefix);
482     if (ns == NULL) {
483 	xsltGenericError(xsltGenericErrorContext,
484 			 "func:function: undeclared prefix %s\n",
485 			 prefix);
486 	xmlFree(name);
487 	xmlFree(prefix);
488 	return;
489     }
490     xmlFree(prefix);
491 
492     /*
493      * Create function data
494      */
495     func = exsltFuncNewFunctionData();
496     func->content = inst->children;
497     while (IS_XSLT_ELEM(func->content) &&
498 	   IS_XSLT_NAME(func->content, "param")) {
499 	func->content = func->content->next;
500 	func->nargs++;
501     }
502 
503     xsltParseTemplateContent(style, inst);
504 
505     /*
506      * Register the function data such that it can be retrieved
507      * by exslFuncFunctionFunction
508      */
509 #ifdef XSLT_REFACTORED
510     /*
511     * Ensure that the hash table will be stored in the *current*
512     * stylesheet level in order to correctly evaluate the
513     * import precedence.
514     */
515     data = (xmlHashTablePtr)
516 	xsltStyleStylesheetLevelGetExtData(style,
517 	    EXSLT_FUNCTIONS_NAMESPACE);
518 #else
519     data = (xmlHashTablePtr)
520 	xsltStyleGetExtData (style, EXSLT_FUNCTIONS_NAMESPACE);
521 #endif
522     if (data == NULL) {
523 	xsltGenericError(xsltGenericErrorContext,
524 			 "exsltFuncFunctionComp: no stylesheet data\n");
525 	xmlFree(name);
526 	return;
527     }
528 
529     if (xmlHashAddEntry2 (data, ns->href, name, func) < 0) {
530 	xsltTransformError(NULL, style, inst,
531 	    "Failed to register function {%s}%s\n",
532 			 ns->href, name);
533 	style->errors++;
534     } else {
535 	xsltGenericDebug(xsltGenericDebugContext,
536 			 "exsltFuncFunctionComp: register {%s}%s\n",
537 			 ns->href, name);
538     }
539     xmlFree(name);
540 }
541 
542 static xsltElemPreCompPtr
exsltFuncResultComp(xsltStylesheetPtr style,xmlNodePtr inst,xsltTransformFunction function)543 exsltFuncResultComp (xsltStylesheetPtr style, xmlNodePtr inst,
544 		     xsltTransformFunction function) {
545     xmlNodePtr test;
546     xmlChar *sel;
547     exsltFuncResultPreComp *ret;
548 
549     /*
550      * "Validity" checking
551      */
552     /* it is an error to have any following sibling elements aside
553      * from the xsl:fallback element.
554      */
555     for (test = inst->next; test != NULL; test = test->next) {
556 	if (test->type != XML_ELEMENT_NODE)
557 	    continue;
558 	if (IS_XSLT_ELEM(test) && IS_XSLT_NAME(test, "fallback"))
559 	    continue;
560 	xsltGenericError(xsltGenericErrorContext,
561 			 "exsltFuncResultElem: only xsl:fallback is "
562 			 "allowed to follow func:result\n");
563 	return (NULL);
564     }
565     /* it is an error for a func:result element to not be a descendant
566      * of func:function.
567      * it is an error if a func:result occurs within a func:result
568      * element.
569      * it is an error if instanciating the content of a variable
570      * binding element (i.e. xsl:variable, xsl:param) results in the
571      * instanciation of a func:result element.
572      */
573     for (test = inst->parent; test != NULL; test = test->parent) {
574 	if (IS_XSLT_ELEM(test) &&
575 	    IS_XSLT_NAME(test, "stylesheet")) {
576 	    xsltGenericError(xsltGenericErrorContext,
577 			     "func:result element not a descendant "
578 			     "of a func:function\n");
579 	    return (NULL);
580 	}
581 	if ((test->ns != NULL) &&
582 	    (xmlStrEqual(test->ns->href, EXSLT_FUNCTIONS_NAMESPACE))) {
583 	    if (xmlStrEqual(test->name, (const xmlChar *) "function")) {
584 		break;
585 	    }
586 	    if (xmlStrEqual(test->name, (const xmlChar *) "result")) {
587 		xsltGenericError(xsltGenericErrorContext,
588 				 "func:result element not allowed within"
589 				 " another func:result element\n");
590 		return (NULL);
591 	    }
592 	}
593 	if (IS_XSLT_ELEM(test) &&
594 	    (IS_XSLT_NAME(test, "variable") ||
595 	     IS_XSLT_NAME(test, "param"))) {
596 	    xsltGenericError(xsltGenericErrorContext,
597 			     "func:result element not allowed within"
598 			     " a variable binding element\n");
599 	    return (NULL);
600 	}
601     }
602 
603     /*
604      * Precomputation
605      */
606     ret = (exsltFuncResultPreComp *)
607 	xmlMalloc (sizeof(exsltFuncResultPreComp));
608     if (ret == NULL) {
609 	xsltPrintErrorContext(NULL, NULL, NULL);
610         xsltGenericError(xsltGenericErrorContext,
611                          "exsltFuncResultComp : malloc failed\n");
612         return (NULL);
613     }
614     memset(ret, 0, sizeof(exsltFuncResultPreComp));
615 
616     xsltInitElemPreComp ((xsltElemPreCompPtr) ret, style, inst, function,
617 		 (xsltElemPreCompDeallocator) exsltFreeFuncResultPreComp);
618     ret->select = NULL;
619 
620     /*
621      * Precompute the select attribute
622      */
623     sel = xmlGetNsProp(inst, (const xmlChar *) "select", NULL);
624     if (sel != NULL) {
625 	ret->select = xmlXPathCompile (sel);
626 	xmlFree(sel);
627     }
628     /*
629      * Precompute the namespace list
630      */
631     ret->nsList = xmlGetNsList(inst->doc, inst);
632     if (ret->nsList != NULL) {
633         int i = 0;
634         while (ret->nsList[i] != NULL)
635 	    i++;
636 	ret->nsNr = i;
637     }
638     return ((xsltElemPreCompPtr) ret);
639 }
640 
641 static void
exsltFuncResultElem(xsltTransformContextPtr ctxt,xmlNodePtr node ATTRIBUTE_UNUSED,xmlNodePtr inst,exsltFuncResultPreComp * comp)642 exsltFuncResultElem (xsltTransformContextPtr ctxt,
643 	             xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr inst,
644 		     exsltFuncResultPreComp *comp) {
645     exsltFuncData *data;
646     xmlXPathObjectPtr ret;
647 
648 
649     /* It is an error if instantiating the content of the
650      * func:function element results in the instantiation of more than
651      * one func:result elements.
652      */
653     data = (exsltFuncData *) xsltGetExtData (ctxt, EXSLT_FUNCTIONS_NAMESPACE);
654     if (data == NULL) {
655 	xsltGenericError(xsltGenericErrorContext,
656 			 "exsltFuncReturnElem: data == NULL\n");
657 	return;
658     }
659     if (data->result != NULL) {
660 	xsltGenericError(xsltGenericErrorContext,
661 			 "func:result already instanciated\n");
662 	data->error = 1;
663 	return;
664     }
665     /*
666      * Processing
667      */
668     if (comp->select != NULL) {
669 	xmlNsPtr *oldXPNsList;
670 	int oldXPNsNr;
671 	xmlNodePtr oldXPContextNode;
672 	/* If the func:result element has a select attribute, then the
673 	 * value of the attribute must be an expression and the
674 	 * returned value is the object that results from evaluating
675 	 * the expression. In this case, the content must be empty.
676 	 */
677 	if (inst->children != NULL) {
678 	    xsltGenericError(xsltGenericErrorContext,
679 			     "func:result content must be empty if"
680 			     " the function has a select attribute\n");
681 	    data->error = 1;
682 	    return;
683 	}
684 	oldXPNsList = ctxt->xpathCtxt->namespaces;
685 	oldXPNsNr = ctxt->xpathCtxt->nsNr;
686 	oldXPContextNode = ctxt->xpathCtxt->node;
687 
688 	ctxt->xpathCtxt->namespaces = comp->nsList;
689 	ctxt->xpathCtxt->nsNr = comp->nsNr;
690 
691 	ret = xmlXPathCompiledEval(comp->select, ctxt->xpathCtxt);
692 
693 	ctxt->xpathCtxt->node = oldXPContextNode;
694 	ctxt->xpathCtxt->nsNr = oldXPNsNr;
695 	ctxt->xpathCtxt->namespaces = oldXPNsList;
696 
697 	if (ret == NULL) {
698 	    xsltGenericError(xsltGenericErrorContext,
699 			     "exsltFuncResultElem: ret == NULL\n");
700 	    return;
701 	}
702 	/*
703 	* Mark it as a function result in order to avoid garbage
704 	* collecting of tree fragments before the function exits.
705 	*/
706 	xsltExtensionInstructionResultRegister(ctxt, ret);
707     } else if (inst->children != NULL) {
708 	/* If the func:result element does not have a select attribute
709 	 * and has non-empty content (i.e. the func:result element has
710 	 * one or more child nodes), then the content of the
711 	 * func:result element specifies the value.
712 	 */
713 	xmlNodePtr oldInsert;
714 	xmlDocPtr container;
715 
716 	container = xsltCreateRVT(ctxt);
717 	if (container == NULL) {
718 	    xsltGenericError(xsltGenericErrorContext,
719 			     "exsltFuncResultElem: out of memory\n");
720 	    data->error = 1;
721 	    return;
722 	}
723 	xsltRegisterLocalRVT(ctxt, container);
724 
725 	oldInsert = ctxt->insert;
726 	ctxt->insert = (xmlNodePtr) container;
727 	xsltApplyOneTemplate (ctxt, ctxt->xpathCtxt->node,
728 			      inst->children, NULL, NULL);
729 	ctxt->insert = oldInsert;
730 
731 	ret = xmlXPathNewValueTree((xmlNodePtr) container);
732 	if (ret == NULL) {
733 	    xsltGenericError(xsltGenericErrorContext,
734 			     "exsltFuncResultElem: ret == NULL\n");
735 	    data->error = 1;
736 	} else {
737 	    ret->boolval = 0; /* Freeing is not handled there anymore */
738 	    /*
739 	    * Mark it as a function result in order to avoid garbage
740 	    * collecting of tree fragments before the function exits.
741 	    */
742 	    xsltExtensionInstructionResultRegister(ctxt, ret);
743 	}
744     } else {
745 	/* If the func:result element has empty content and does not
746 	 * have a select attribute, then the returned value is an
747 	 * empty string.
748 	 */
749 	ret = xmlXPathNewCString("");
750     }
751     data->result = ret;
752 }
753 
754 /**
755  * exsltFuncRegister:
756  *
757  * Registers the EXSLT - Functions module
758  */
759 void
exsltFuncRegister(void)760 exsltFuncRegister (void) {
761     xsltRegisterExtModuleFull (EXSLT_FUNCTIONS_NAMESPACE,
762 		       (xsltExtInitFunction) exsltFuncInit,
763 		       (xsltExtShutdownFunction) exsltFuncShutdown,
764 		       (xsltStyleExtInitFunction) exsltFuncStyleInit,
765 		       (xsltStyleExtShutdownFunction) exsltFuncStyleShutdown);
766 
767     xsltRegisterExtModuleTopLevel ((const xmlChar *) "function",
768 				   EXSLT_FUNCTIONS_NAMESPACE,
769 				   exsltFuncFunctionComp);
770     xsltRegisterExtModuleElement ((const xmlChar *) "result",
771 			  EXSLT_FUNCTIONS_NAMESPACE,
772 			  (xsltPreComputeFunction)exsltFuncResultComp,
773 			  (xsltTransformFunction) exsltFuncResultElem);
774 }
775