1/*
2 * extensions.c: Implemetation of the extensions support
3 *
4 * Reference:
5 *   http://www.w3.org/TR/1999/REC-xslt-19991116
6 *
7 * See Copyright for the status of this software.
8 *
9 * daniel@veillard.com
10 */
11
12#define IN_LIBXSLT
13#include "libxslt.h"
14
15#include <string.h>
16#include <limits.h>
17
18#include <libxml/xmlmemory.h>
19#include <libxml/tree.h>
20#include <libxml/hash.h>
21#include <libxml/xmlerror.h>
22#include <libxml/parserInternals.h>
23#include <libxml/xpathInternals.h>
24#ifdef WITH_MODULES
25#include <libxml/xmlmodule.h>
26#endif
27#include <libxml/list.h>
28#include <libxml/xmlIO.h>
29#include "xslt.h"
30#include "xsltInternals.h"
31#include "xsltutils.h"
32#include "imports.h"
33#include "extensions.h"
34
35#ifdef _WIN32
36#include <stdlib.h>             /* for _MAX_PATH */
37#ifndef PATH_MAX
38#define PATH_MAX _MAX_PATH
39#endif
40#endif
41
42#ifdef WITH_XSLT_DEBUG
43#define WITH_XSLT_DEBUG_EXTENSIONS
44#endif
45
46/************************************************************************
47 * 									*
48 * 			Private Types and Globals			*
49 * 									*
50 ************************************************************************/
51
52typedef struct _xsltExtDef xsltExtDef;
53typedef xsltExtDef *xsltExtDefPtr;
54struct _xsltExtDef {
55    struct _xsltExtDef *next;
56    xmlChar *prefix;
57    xmlChar *URI;
58    void *data;
59};
60
61typedef struct _xsltExtModule xsltExtModule;
62typedef xsltExtModule *xsltExtModulePtr;
63struct _xsltExtModule {
64    xsltExtInitFunction initFunc;
65    xsltExtShutdownFunction shutdownFunc;
66    xsltStyleExtInitFunction styleInitFunc;
67    xsltStyleExtShutdownFunction styleShutdownFunc;
68};
69
70typedef struct _xsltExtData xsltExtData;
71typedef xsltExtData *xsltExtDataPtr;
72struct _xsltExtData {
73    xsltExtModulePtr extModule;
74    void *extData;
75};
76
77typedef struct _xsltExtElement xsltExtElement;
78typedef xsltExtElement *xsltExtElementPtr;
79struct _xsltExtElement {
80    xsltPreComputeFunction precomp;
81    xsltTransformFunction transform;
82};
83
84static xmlHashTablePtr xsltExtensionsHash = NULL;
85static xmlHashTablePtr xsltFunctionsHash = NULL;
86static xmlHashTablePtr xsltElementsHash = NULL;
87static xmlHashTablePtr xsltTopLevelsHash = NULL;
88static xmlHashTablePtr xsltModuleHash = NULL;
89static xmlMutexPtr xsltExtMutex = NULL;
90
91/************************************************************************
92 * 									*
93 * 			Type functions 					*
94 * 									*
95 ************************************************************************/
96
97/**
98 * xsltNewExtDef:
99 * @prefix:  the extension prefix
100 * @URI:  the namespace URI
101 *
102 * Create a new XSLT ExtDef
103 *
104 * Returns the newly allocated xsltExtDefPtr or NULL in case of error
105 */
106static xsltExtDefPtr
107xsltNewExtDef(const xmlChar * prefix, const xmlChar * URI)
108{
109    xsltExtDefPtr cur;
110
111    cur = (xsltExtDefPtr) xmlMalloc(sizeof(xsltExtDef));
112    if (cur == NULL) {
113        xsltTransformError(NULL, NULL, NULL,
114                           "xsltNewExtDef : malloc failed\n");
115        return (NULL);
116    }
117    memset(cur, 0, sizeof(xsltExtDef));
118    if (prefix != NULL)
119        cur->prefix = xmlStrdup(prefix);
120    if (URI != NULL)
121        cur->URI = xmlStrdup(URI);
122    return (cur);
123}
124
125/**
126 * xsltFreeExtDef:
127 * @extensiond:  an XSLT extension definition
128 *
129 * Free up the memory allocated by @extensiond
130 */
131static void
132xsltFreeExtDef(xsltExtDefPtr extensiond)
133{
134    if (extensiond == NULL)
135        return;
136    if (extensiond->prefix != NULL)
137        xmlFree(extensiond->prefix);
138    if (extensiond->URI != NULL)
139        xmlFree(extensiond->URI);
140    xmlFree(extensiond);
141}
142
143/**
144 * xsltFreeExtDefList:
145 * @extensiond:  an XSLT extension definition list
146 *
147 * Free up the memory allocated by all the elements of @extensiond
148 */
149static void
150xsltFreeExtDefList(xsltExtDefPtr extensiond)
151{
152    xsltExtDefPtr cur;
153
154    while (extensiond != NULL) {
155        cur = extensiond;
156        extensiond = extensiond->next;
157        xsltFreeExtDef(cur);
158    }
159}
160
161/**
162 * xsltNewExtModule:
163 * @initFunc:  the module initialization function
164 * @shutdownFunc:  the module shutdown function
165 * @styleInitFunc:  the stylesheet module data allocator function
166 * @styleShutdownFunc:  the stylesheet module data free function
167 *
168 * Create a new XSLT extension module
169 *
170 * Returns the newly allocated xsltExtModulePtr or NULL in case of error
171 */
172static xsltExtModulePtr
173xsltNewExtModule(xsltExtInitFunction initFunc,
174                 xsltExtShutdownFunction shutdownFunc,
175                 xsltStyleExtInitFunction styleInitFunc,
176                 xsltStyleExtShutdownFunction styleShutdownFunc)
177{
178    xsltExtModulePtr cur;
179
180    cur = (xsltExtModulePtr) xmlMalloc(sizeof(xsltExtModule));
181    if (cur == NULL) {
182        xsltTransformError(NULL, NULL, NULL,
183                           "xsltNewExtModule : malloc failed\n");
184        return (NULL);
185    }
186    cur->initFunc = initFunc;
187    cur->shutdownFunc = shutdownFunc;
188    cur->styleInitFunc = styleInitFunc;
189    cur->styleShutdownFunc = styleShutdownFunc;
190    return (cur);
191}
192
193/**
194 * xsltFreeExtModule:
195 * @ext:  an XSLT extension module
196 *
197 * Free up the memory allocated by @ext
198 */
199static void
200xsltFreeExtModule(xsltExtModulePtr ext)
201{
202    if (ext == NULL)
203        return;
204    xmlFree(ext);
205}
206
207/**
208 * xsltNewExtData:
209 * @extModule:  the module
210 * @extData:  the associated data
211 *
212 * Create a new XSLT extension module data wrapper
213 *
214 * Returns the newly allocated xsltExtDataPtr or NULL in case of error
215 */
216static xsltExtDataPtr
217xsltNewExtData(xsltExtModulePtr extModule, void *extData)
218{
219    xsltExtDataPtr cur;
220
221    if (extModule == NULL)
222        return (NULL);
223    cur = (xsltExtDataPtr) xmlMalloc(sizeof(xsltExtData));
224    if (cur == NULL) {
225        xsltTransformError(NULL, NULL, NULL,
226                           "xsltNewExtData : malloc failed\n");
227        return (NULL);
228    }
229    cur->extModule = extModule;
230    cur->extData = extData;
231    return (cur);
232}
233
234/**
235 * xsltFreeExtData:
236 * @ext:  an XSLT extension module data wrapper
237 *
238 * Free up the memory allocated by @ext
239 */
240static void
241xsltFreeExtData(xsltExtDataPtr ext)
242{
243    if (ext == NULL)
244        return;
245    xmlFree(ext);
246}
247
248/**
249 * xsltNewExtElement:
250 * @precomp:  the pre-computation function
251 * @transform:  the transformation function
252 *
253 * Create a new XSLT extension element
254 *
255 * Returns the newly allocated xsltExtElementPtr or NULL in case of
256 * error
257 */
258static xsltExtElementPtr
259xsltNewExtElement(xsltPreComputeFunction precomp,
260                  xsltTransformFunction transform)
261{
262    xsltExtElementPtr cur;
263
264    if (transform == NULL)
265        return (NULL);
266
267    cur = (xsltExtElementPtr) xmlMalloc(sizeof(xsltExtElement));
268    if (cur == NULL) {
269        xsltTransformError(NULL, NULL, NULL,
270                           "xsltNewExtElement : malloc failed\n");
271        return (NULL);
272    }
273    cur->precomp = precomp;
274    cur->transform = transform;
275    return (cur);
276}
277
278/**
279 * xsltFreeExtElement:
280 * @ext: an XSLT extension element
281 *
282 * Frees up the memory allocated by @ext
283 */
284static void
285xsltFreeExtElement(xsltExtElementPtr ext)
286{
287    if (ext == NULL)
288        return;
289    xmlFree(ext);
290}
291
292
293#ifdef WITH_MODULES
294typedef void (*exsltRegisterFunction) (void);
295
296#ifndef PATH_MAX
297#define PATH_MAX 4096
298#endif
299
300/**
301 * xsltExtModuleRegisterDynamic:
302 * @URI:  the function or element namespace URI
303 *
304 * Dynamically loads an extension plugin when available.
305 *
306 * The plugin name is derived from the URI by removing the
307 * initial protocol designation, e.g. "http://", then converting
308 * the characters ".", "-", "/", and "\" into "_", the removing
309 * any trailing "/", then concatenating LIBXML_MODULE_EXTENSION.
310 *
311 * Plugins are loaded from the directory specified by the
312 * environment variable LIBXSLT_PLUGINS_PATH, or if NULL,
313 * by LIBXSLT_DEFAULT_PLUGINS_PATH() which is determined at
314 * compile time.
315 *
316 * Returns 0 if successful, -1 in case of error.
317 */
318
319static int
320xsltExtModuleRegisterDynamic(const xmlChar * URI)
321{
322
323    xmlModulePtr m;
324    exsltRegisterFunction regfunc;
325    xmlChar *ext_name;
326    char module_filename[PATH_MAX];
327    const xmlChar *ext_directory = NULL;
328    const xmlChar *protocol = NULL;
329    xmlChar *i, *regfunc_name;
330    void *vregfunc;
331    int rc;
332
333    /* check for bad inputs */
334    if (URI == NULL)
335        return (-1);
336
337    if (NULL == xsltModuleHash) {
338        xsltModuleHash = xmlHashCreate(5);
339        if (xsltModuleHash == NULL)
340            return (-1);
341    }
342
343    xmlMutexLock(xsltExtMutex);
344
345    /* have we attempted to register this module already? */
346    if (xmlHashLookup(xsltModuleHash, URI) != NULL) {
347        xmlMutexUnlock(xsltExtMutex);
348        return (-1);
349    }
350    xmlMutexUnlock(xsltExtMutex);
351
352    /* transform extension namespace into a module name */
353    protocol = xmlStrstr(URI, BAD_CAST "://");
354    if (protocol == NULL) {
355        ext_name = xmlStrdup(URI);
356    } else {
357        ext_name = xmlStrdup(protocol + 3);
358    }
359    if (ext_name == NULL) {
360        return (-1);
361    }
362
363    i = ext_name;
364    while ('\0' != *i) {
365        if (('/' == *i) || ('\\' == *i) || ('.' == *i) || ('-' == *i))
366            *i = '_';
367        i++;
368    }
369
370    if (*(i - 1) == '_')
371        *i = '\0';
372
373    /* determine module directory */
374    ext_directory = (xmlChar *) getenv("LIBXSLT_PLUGINS_PATH");
375
376    if (NULL == ext_directory) {
377        ext_directory = BAD_CAST LIBXSLT_DEFAULT_PLUGINS_PATH();
378	if (NULL == ext_directory)
379	  return (-1);
380    }
381#ifdef WITH_XSLT_DEBUG_EXTENSIONS
382    else
383      xsltGenericDebug(xsltGenericDebugContext,
384		       "LIBXSLT_PLUGINS_PATH is %s\n", ext_directory);
385#endif
386
387    /* build the module filename, and confirm the module exists */
388    xmlStrPrintf((xmlChar *) module_filename, sizeof(module_filename),
389                 BAD_CAST "%s/%s%s",
390                 ext_directory, ext_name, LIBXML_MODULE_EXTENSION);
391
392#ifdef WITH_XSLT_DEBUG_EXTENSIONS
393    xsltGenericDebug(xsltGenericDebugContext,
394                     "Attempting to load plugin: %s for URI: %s\n",
395                     module_filename, URI);
396#endif
397
398    if (1 != xmlCheckFilename(module_filename)) {
399
400#ifdef WITH_XSLT_DEBUG_EXTENSIONS
401	xsltGenericDebug(xsltGenericDebugContext,
402                     "xmlCheckFilename failed for plugin: %s\n", module_filename);
403#endif
404
405        xmlFree(ext_name);
406        return (-1);
407    }
408
409    /* attempt to open the module */
410    m = xmlModuleOpen(module_filename, 0);
411    if (NULL == m) {
412
413#ifdef WITH_XSLT_DEBUG_EXTENSIONS
414	xsltGenericDebug(xsltGenericDebugContext,
415                     "xmlModuleOpen failed for plugin: %s\n", module_filename);
416#endif
417
418        xmlFree(ext_name);
419        return (-1);
420    }
421
422    /* construct initialization func name */
423    regfunc_name = xmlStrdup(ext_name);
424    regfunc_name = xmlStrcat(regfunc_name, BAD_CAST "_init");
425
426    vregfunc = NULL;
427    rc = xmlModuleSymbol(m, (const char *) regfunc_name, &vregfunc);
428    regfunc = vregfunc;
429    if (0 == rc) {
430        /*
431	 * Call the module's init function.  Note that this function
432	 * calls xsltRegisterExtModuleFull which will add the module
433	 * to xsltExtensionsHash (together with it's entry points).
434	 */
435        (*regfunc) ();
436
437        /* register this module in our hash */
438        xmlMutexLock(xsltExtMutex);
439        xmlHashAddEntry(xsltModuleHash, URI, (void *) m);
440        xmlMutexUnlock(xsltExtMutex);
441    } else {
442
443#ifdef WITH_XSLT_DEBUG_EXTENSIONS
444	xsltGenericDebug(xsltGenericDebugContext,
445                     "xmlModuleSymbol failed for plugin: %s, regfunc: %s\n",
446                     module_filename, regfunc_name);
447#endif
448
449        /* if regfunc not found unload the module immediately */
450        xmlModuleClose(m);
451    }
452
453    xmlFree(ext_name);
454    xmlFree(regfunc_name);
455    return (NULL == regfunc) ? -1 : 0;
456}
457#else
458static int
459xsltExtModuleRegisterDynamic(const xmlChar * URI ATTRIBUTE_UNUSED)
460{
461  return -1;
462}
463#endif
464
465/************************************************************************
466 * 									*
467 * 		The stylesheet extension prefixes handling		*
468 * 									*
469 ************************************************************************/
470
471
472/**
473 * xsltFreeExts:
474 * @style: an XSLT stylesheet
475 *
476 * Free up the memory used by XSLT extensions in a stylesheet
477 */
478void
479xsltFreeExts(xsltStylesheetPtr style)
480{
481    if (style->nsDefs != NULL)
482        xsltFreeExtDefList((xsltExtDefPtr) style->nsDefs);
483}
484
485/**
486 * xsltRegisterExtPrefix:
487 * @style: an XSLT stylesheet
488 * @prefix: the prefix used (optional)
489 * @URI: the URI associated to the extension
490 *
491 * Registers an extension namespace
492 * This is called from xslt.c during compile-time.
493 * The given prefix is not needed.
494 * Called by:
495 *   xsltParseExtElemPrefixes() (new function)
496 *   xsltRegisterExtPrefix() (old function)
497 *
498 * Returns 0 in case of success, 1 if the @URI was already
499 *         registered as an extension namespace and
500 *         -1 in case of failure
501 */
502int
503xsltRegisterExtPrefix(xsltStylesheetPtr style,
504                      const xmlChar * prefix, const xmlChar * URI)
505{
506    xsltExtDefPtr def, ret;
507
508    if ((style == NULL) || (URI == NULL))
509        return (-1);
510
511#ifdef WITH_XSLT_DEBUG_EXTENSIONS
512    xsltGenericDebug(xsltGenericDebugContext,
513	"Registering extension namespace '%s'.\n", URI);
514#endif
515    def = (xsltExtDefPtr) style->nsDefs;
516#ifdef XSLT_REFACTORED
517    /*
518    * The extension is associated with a namespace name.
519    */
520    while (def != NULL) {
521        if (xmlStrEqual(URI, def->URI))
522            return (1);
523        def = def->next;
524    }
525#else
526    while (def != NULL) {
527        if (xmlStrEqual(prefix, def->prefix))
528            return (-1);
529        def = def->next;
530    }
531#endif
532    ret = xsltNewExtDef(prefix, URI);
533    if (ret == NULL)
534        return (-1);
535    ret->next = (xsltExtDefPtr) style->nsDefs;
536    style->nsDefs = ret;
537
538    /*
539     * check whether there is an extension module with a stylesheet
540     * initialization function.
541     */
542#ifdef XSLT_REFACTORED
543    /*
544    * Don't initialize modules based on specified namespaces via
545    * the attribute "[xsl:]extension-element-prefixes".
546    */
547#else
548    if (xsltExtensionsHash != NULL) {
549        xsltExtModulePtr module;
550
551        xmlMutexLock(xsltExtMutex);
552        module = xmlHashLookup(xsltExtensionsHash, URI);
553        xmlMutexUnlock(xsltExtMutex);
554        if (NULL == module) {
555            if (!xsltExtModuleRegisterDynamic(URI)) {
556                xmlMutexLock(xsltExtMutex);
557                module = xmlHashLookup(xsltExtensionsHash, URI);
558                xmlMutexUnlock(xsltExtMutex);
559            }
560        }
561        if (module != NULL) {
562            xsltStyleGetExtData(style, URI);
563        }
564    }
565#endif
566    return (0);
567}
568
569/************************************************************************
570 * 									*
571 * 		The extensions modules interfaces			*
572 * 									*
573 ************************************************************************/
574
575/**
576 * xsltRegisterExtFunction:
577 * @ctxt: an XSLT transformation context
578 * @name: the name of the element
579 * @URI: the URI associated to the element
580 * @function: the actual implementation which should be called
581 *
582 * Registers an extension function
583 *
584 * Returns 0 in case of success, -1 in case of failure
585 */
586int
587xsltRegisterExtFunction(xsltTransformContextPtr ctxt, const xmlChar * name,
588                        const xmlChar * URI, xmlXPathFunction function)
589{
590    int ret;
591
592    if ((ctxt == NULL) || (name == NULL) ||
593        (URI == NULL) || (function == NULL))
594        return (-1);
595    if (ctxt->xpathCtxt != NULL) {
596        xmlXPathRegisterFuncNS(ctxt->xpathCtxt, name, URI, function);
597    }
598    if (ctxt->extFunctions == NULL)
599        ctxt->extFunctions = xmlHashCreate(10);
600    if (ctxt->extFunctions == NULL)
601        return (-1);
602
603    ret = xmlHashAddEntry2(ctxt->extFunctions, name, URI,
604                           XML_CAST_FPTR(function));
605
606    return(ret);
607}
608
609/**
610 * xsltRegisterExtElement:
611 * @ctxt: an XSLT transformation context
612 * @name: the name of the element
613 * @URI: the URI associated to the element
614 * @function: the actual implementation which should be called
615 *
616 * Registers an extension element
617 *
618 * Returns 0 in case of success, -1 in case of failure
619 */
620int
621xsltRegisterExtElement(xsltTransformContextPtr ctxt, const xmlChar * name,
622                       const xmlChar * URI, xsltTransformFunction function)
623{
624    if ((ctxt == NULL) || (name == NULL) ||
625        (URI == NULL) || (function == NULL))
626        return (-1);
627    if (ctxt->extElements == NULL)
628        ctxt->extElements = xmlHashCreate(10);
629    if (ctxt->extElements == NULL)
630        return (-1);
631    return (xmlHashAddEntry2
632            (ctxt->extElements, name, URI, XML_CAST_FPTR(function)));
633}
634
635/**
636 * xsltFreeCtxtExts:
637 * @ctxt: an XSLT transformation context
638 *
639 * Free the XSLT extension data
640 */
641void
642xsltFreeCtxtExts(xsltTransformContextPtr ctxt)
643{
644    if (ctxt->extElements != NULL)
645        xmlHashFree(ctxt->extElements, NULL);
646    if (ctxt->extFunctions != NULL)
647        xmlHashFree(ctxt->extFunctions, NULL);
648}
649
650/**
651 * xsltStyleGetStylesheetExtData:
652 * @style: an XSLT stylesheet
653 * @URI:  the URI associated to the exension module
654 *
655 * Fires the compile-time initialization callback
656 * of an extension module and returns a container
657 * holding the user-data (retrieved via the callback).
658 *
659 * Returns the create module-data container
660 *         or NULL if such a module was not registered.
661 */
662static xsltExtDataPtr
663xsltStyleInitializeStylesheetModule(xsltStylesheetPtr style,
664				     const xmlChar * URI)
665{
666    xsltExtDataPtr dataContainer;
667    void *userData = NULL;
668    xsltExtModulePtr module;
669
670    if ((style == NULL) || (URI == NULL))
671	return(NULL);
672
673    if (xsltExtensionsHash == NULL) {
674#ifdef WITH_XSLT_DEBUG_EXTENSIONS
675	xsltGenericDebug(xsltGenericDebugContext,
676	    "Not registered extension module: %s\n", URI);
677#endif
678	return(NULL);
679    }
680
681    xmlMutexLock(xsltExtMutex);
682
683    module = xmlHashLookup(xsltExtensionsHash, URI);
684
685    xmlMutexUnlock(xsltExtMutex);
686
687    if (module == NULL) {
688#ifdef WITH_XSLT_DEBUG_EXTENSIONS
689	xsltGenericDebug(xsltGenericDebugContext,
690	    "Not registered extension module: %s\n", URI);
691#endif
692	return (NULL);
693    }
694    /*
695    * The specified module was registered so initialize it.
696    */
697    if (style->extInfos == NULL) {
698	style->extInfos = xmlHashCreate(10);
699	if (style->extInfos == NULL)
700	    return (NULL);
701    }
702    /*
703    * Fire the initialization callback if available.
704    */
705    if (module->styleInitFunc == NULL) {
706#ifdef WITH_XSLT_DEBUG_EXTENSIONS
707	xsltGenericDebug(xsltGenericDebugContext,
708	    "Initializing module with *no* callback: %s\n", URI);
709#endif
710    } else {
711#ifdef WITH_XSLT_DEBUG_EXTENSIONS
712	xsltGenericDebug(xsltGenericDebugContext,
713	    "Initializing module with callback: %s\n", URI);
714#endif
715	/*
716	* Fire the initialization callback.
717	*/
718	userData = module->styleInitFunc(style, URI);
719    }
720    /*
721    * Store the user-data in the context of the given stylesheet.
722    */
723    dataContainer = xsltNewExtData(module, userData);
724    if (dataContainer == NULL)
725	return (NULL);
726
727    if (xmlHashAddEntry(style->extInfos, URI,
728	(void *) dataContainer) < 0)
729    {
730	xsltTransformError(NULL, style, NULL,
731	    "Failed to register module '%s'.\n", URI);
732	style->errors++;
733	if (module->styleShutdownFunc)
734	    module->styleShutdownFunc(style, URI, userData);
735	xsltFreeExtData(dataContainer);
736	return (NULL);
737    }
738
739    return(dataContainer);
740}
741
742/**
743 * xsltStyleGetExtData:
744 * @style: an XSLT stylesheet
745 * @URI:  the URI associated to the exension module
746 *
747 * Retrieve the data associated to the extension module
748 * in this given stylesheet.
749 * Called by:
750 *   xsltRegisterExtPrefix(),
751 *   ( xsltExtElementPreCompTest(), xsltExtInitTest )
752 *
753 * Returns the pointer or NULL if not present
754 */
755void *
756xsltStyleGetExtData(xsltStylesheetPtr style, const xmlChar * URI)
757{
758    xsltExtDataPtr dataContainer = NULL;
759    xsltStylesheetPtr tmpStyle;
760
761    if ((style == NULL) || (URI == NULL) ||
762	(xsltExtensionsHash == NULL))
763	return (NULL);
764
765
766#ifdef XSLT_REFACTORED
767    /*
768    * This is intended for global storage, so only the main
769    * stylesheet will hold the data.
770    */
771    tmpStyle = style;
772    while (tmpStyle->parent != NULL)
773	tmpStyle = tmpStyle->parent;
774    if (tmpStyle->extInfos != NULL) {
775	dataContainer =
776	    (xsltExtDataPtr) xmlHashLookup(tmpStyle->extInfos, URI);
777	if (dataContainer != NULL) {
778	    /*
779	    * The module was already initialized in the context
780	    * of this stylesheet; just return the user-data that
781	    * comes with it.
782	    */
783	    return(dataContainer->extData);
784	}
785    }
786#else
787    /*
788    * Old behaviour.
789    */
790    tmpStyle = style;
791    while (tmpStyle != NULL) {
792	if (tmpStyle->extInfos != NULL) {
793	    dataContainer =
794		(xsltExtDataPtr) xmlHashLookup(tmpStyle->extInfos, URI);
795	    if (dataContainer != NULL) {
796		return(dataContainer->extData);
797	    }
798	}
799	tmpStyle = xsltNextImport(tmpStyle);
800    }
801    tmpStyle = style;
802#endif
803
804    dataContainer =
805        xsltStyleInitializeStylesheetModule(tmpStyle, URI);
806    if (dataContainer != NULL)
807	return (dataContainer->extData);
808    return(NULL);
809}
810
811#ifdef XSLT_REFACTORED
812/**
813 * xsltStyleStylesheetLevelGetExtData:
814 * @style: an XSLT stylesheet
815 * @URI:  the URI associated to the exension module
816 *
817 * Retrieve the data associated to the extension module in this given
818 * stylesheet.
819 *
820 * Returns the pointer or NULL if not present
821 */
822void *
823xsltStyleStylesheetLevelGetExtData(xsltStylesheetPtr style,
824				   const xmlChar * URI)
825{
826    xsltExtDataPtr dataContainer = NULL;
827
828    if ((style == NULL) || (URI == NULL) ||
829	(xsltExtensionsHash == NULL))
830	return (NULL);
831
832    if (style->extInfos != NULL) {
833	dataContainer = (xsltExtDataPtr) xmlHashLookup(style->extInfos, URI);
834	/*
835	* The module was already initialized in the context
836	* of this stylesheet; just return the user-data that
837	* comes with it.
838	*/
839	if (dataContainer)
840	    return(dataContainer->extData);
841    }
842
843    dataContainer =
844        xsltStyleInitializeStylesheetModule(style, URI);
845    if (dataContainer != NULL)
846	return (dataContainer->extData);
847    return(NULL);
848}
849#endif
850
851/**
852 * xsltGetExtData:
853 * @ctxt: an XSLT transformation context
854 * @URI:  the URI associated to the exension module
855 *
856 * Retrieve the data associated to the extension module in this given
857 * transformation.
858 *
859 * Returns the pointer or NULL if not present
860 */
861void *
862xsltGetExtData(xsltTransformContextPtr ctxt, const xmlChar * URI)
863{
864    xsltExtDataPtr data;
865
866    if ((ctxt == NULL) || (URI == NULL))
867        return (NULL);
868    if (ctxt->extInfos == NULL) {
869        ctxt->extInfos = xmlHashCreate(10);
870        if (ctxt->extInfos == NULL)
871            return (NULL);
872        data = NULL;
873    } else {
874        data = (xsltExtDataPtr) xmlHashLookup(ctxt->extInfos, URI);
875    }
876    if (data == NULL) {
877        void *extData;
878        xsltExtModulePtr module;
879
880        xmlMutexLock(xsltExtMutex);
881
882        module = xmlHashLookup(xsltExtensionsHash, URI);
883
884        xmlMutexUnlock(xsltExtMutex);
885
886        if (module == NULL) {
887#ifdef WITH_XSLT_DEBUG_EXTENSIONS
888            xsltGenericDebug(xsltGenericDebugContext,
889                             "Not registered extension module: %s\n", URI);
890#endif
891            return (NULL);
892        } else {
893            if (module->initFunc == NULL)
894                return (NULL);
895
896#ifdef WITH_XSLT_DEBUG_EXTENSIONS
897            xsltGenericDebug(xsltGenericDebugContext,
898                             "Initializing module: %s\n", URI);
899#endif
900
901            extData = module->initFunc(ctxt, URI);
902            if (extData == NULL)
903                return (NULL);
904
905            data = xsltNewExtData(module, extData);
906            if (data == NULL)
907                return (NULL);
908            if (xmlHashAddEntry(ctxt->extInfos, URI, (void *) data) < 0) {
909                xsltTransformError(ctxt, NULL, NULL,
910                                   "Failed to register module data: %s\n",
911                                   URI);
912                if (module->shutdownFunc)
913                    module->shutdownFunc(ctxt, URI, extData);
914                xsltFreeExtData(data);
915                return (NULL);
916            }
917        }
918    }
919    return (data->extData);
920}
921
922typedef struct _xsltInitExtCtxt xsltInitExtCtxt;
923struct _xsltInitExtCtxt {
924    xsltTransformContextPtr ctxt;
925    int ret;
926};
927
928/**
929 * xsltInitCtxtExt:
930 * @styleData:  the registered stylesheet data for the module
931 * @ctxt:  the XSLT transformation context + the return value
932 * @URI:  the extension URI
933 *
934 * Initializes an extension module
935 */
936static void
937xsltInitCtxtExt(xsltExtDataPtr styleData, xsltInitExtCtxt * ctxt,
938                const xmlChar * URI)
939{
940    xsltExtModulePtr module;
941    xsltExtDataPtr ctxtData;
942    void *extData;
943
944    if ((styleData == NULL) || (ctxt == NULL) || (URI == NULL) ||
945        (ctxt->ret == -1)) {
946#ifdef WITH_XSLT_DEBUG_EXTENSIONS
947        xsltGenericDebug(xsltGenericDebugContext,
948                         "xsltInitCtxtExt: NULL param or error\n");
949#endif
950        return;
951    }
952    module = styleData->extModule;
953    if ((module == NULL) || (module->initFunc == NULL)) {
954#ifdef WITH_XSLT_DEBUG_EXTENSIONS
955        xsltGenericDebug(xsltGenericDebugContext,
956                         "xsltInitCtxtExt: no module or no initFunc\n");
957#endif
958        return;
959    }
960
961    ctxtData = (xsltExtDataPtr) xmlHashLookup(ctxt->ctxt->extInfos, URI);
962    if (ctxtData != NULL) {
963#ifdef WITH_XSLT_DEBUG_EXTENSIONS
964        xsltGenericDebug(xsltGenericDebugContext,
965                         "xsltInitCtxtExt: already initialized\n");
966#endif
967        return;
968    }
969
970    extData = module->initFunc(ctxt->ctxt, URI);
971    if (extData == NULL) {
972#ifdef WITH_XSLT_DEBUG_EXTENSIONS
973        xsltGenericDebug(xsltGenericDebugContext,
974                         "xsltInitCtxtExt: no extData\n");
975#endif
976    }
977    ctxtData = xsltNewExtData(module, extData);
978    if (ctxtData == NULL) {
979        ctxt->ret = -1;
980        return;
981    }
982
983    if (ctxt->ctxt->extInfos == NULL)
984        ctxt->ctxt->extInfos = xmlHashCreate(10);
985    if (ctxt->ctxt->extInfos == NULL) {
986        ctxt->ret = -1;
987        return;
988    }
989
990    if (xmlHashAddEntry(ctxt->ctxt->extInfos, URI, ctxtData) < 0) {
991        xsltGenericError(xsltGenericErrorContext,
992                         "Failed to register module data: %s\n", URI);
993        if (module->shutdownFunc)
994            module->shutdownFunc(ctxt->ctxt, URI, extData);
995        xsltFreeExtData(ctxtData);
996        ctxt->ret = -1;
997        return;
998    }
999#ifdef WITH_XSLT_DEBUG_EXTENSIONS
1000    xsltGenericDebug(xsltGenericDebugContext, "Registered module %s\n",
1001                     URI);
1002#endif
1003    ctxt->ret++;
1004}
1005
1006/**
1007 * xsltInitCtxtExts:
1008 * @ctxt: an XSLT transformation context
1009 *
1010 * Initialize the set of modules with registered stylesheet data
1011 *
1012 * Returns the number of modules initialized or -1 in case of error
1013 */
1014int
1015xsltInitCtxtExts(xsltTransformContextPtr ctxt)
1016{
1017    xsltStylesheetPtr style;
1018    xsltInitExtCtxt ctx;
1019
1020    if (ctxt == NULL)
1021        return (-1);
1022
1023    style = ctxt->style;
1024    if (style == NULL)
1025        return (-1);
1026
1027    ctx.ctxt = ctxt;
1028    ctx.ret = 0;
1029
1030    while (style != NULL) {
1031        if (style->extInfos != NULL) {
1032            xmlHashScan(style->extInfos,
1033                        (xmlHashScanner) xsltInitCtxtExt, &ctx);
1034            if (ctx.ret == -1)
1035                return (-1);
1036        }
1037        style = xsltNextImport(style);
1038    }
1039#ifdef WITH_XSLT_DEBUG_EXTENSIONS
1040    xsltGenericDebug(xsltGenericDebugContext, "Registered %d modules\n",
1041                     ctx.ret);
1042#endif
1043    return (ctx.ret);
1044}
1045
1046/**
1047 * xsltShutdownCtxtExt:
1048 * @data:  the registered data for the module
1049 * @ctxt:  the XSLT transformation context
1050 * @URI:  the extension URI
1051 *
1052 * Shutdown an extension module loaded
1053 */
1054static void
1055xsltShutdownCtxtExt(xsltExtDataPtr data, xsltTransformContextPtr ctxt,
1056                    const xmlChar * URI)
1057{
1058    xsltExtModulePtr module;
1059
1060    if ((data == NULL) || (ctxt == NULL) || (URI == NULL))
1061        return;
1062    module = data->extModule;
1063    if ((module == NULL) || (module->shutdownFunc == NULL))
1064        return;
1065
1066#ifdef WITH_XSLT_DEBUG_EXTENSIONS
1067    xsltGenericDebug(xsltGenericDebugContext,
1068                     "Shutting down module : %s\n", URI);
1069#endif
1070    module->shutdownFunc(ctxt, URI, data->extData);
1071}
1072
1073/**
1074 * xsltShutdownCtxtExts:
1075 * @ctxt: an XSLT transformation context
1076 *
1077 * Shutdown the set of modules loaded
1078 */
1079void
1080xsltShutdownCtxtExts(xsltTransformContextPtr ctxt)
1081{
1082    if (ctxt == NULL)
1083        return;
1084    if (ctxt->extInfos == NULL)
1085        return;
1086    xmlHashScan(ctxt->extInfos, (xmlHashScanner) xsltShutdownCtxtExt,
1087                ctxt);
1088    xmlHashFree(ctxt->extInfos, (xmlHashDeallocator) xsltFreeExtData);
1089    ctxt->extInfos = NULL;
1090}
1091
1092/**
1093 * xsltShutdownExt:
1094 * @data:  the registered data for the module
1095 * @ctxt:  the XSLT stylesheet
1096 * @URI:  the extension URI
1097 *
1098 * Shutdown an extension module loaded
1099 */
1100static void
1101xsltShutdownExt(xsltExtDataPtr data, xsltStylesheetPtr style,
1102                const xmlChar * URI)
1103{
1104    xsltExtModulePtr module;
1105
1106    if ((data == NULL) || (style == NULL) || (URI == NULL))
1107        return;
1108    module = data->extModule;
1109    if ((module == NULL) || (module->styleShutdownFunc == NULL))
1110        return;
1111
1112#ifdef WITH_XSLT_DEBUG_EXTENSIONS
1113    xsltGenericDebug(xsltGenericDebugContext,
1114                     "Shutting down module : %s\n", URI);
1115#endif
1116    module->styleShutdownFunc(style, URI, data->extData);
1117    /*
1118    * Don't remove the entry from the hash table here, since
1119    * this will produce segfaults - this fixes bug #340624.
1120    *
1121    * xmlHashRemoveEntry(style->extInfos, URI,
1122    *   (xmlHashDeallocator) xsltFreeExtData);
1123    */
1124}
1125
1126/**
1127 * xsltShutdownExts:
1128 * @style: an XSLT stylesheet
1129 *
1130 * Shutdown the set of modules loaded
1131 */
1132void
1133xsltShutdownExts(xsltStylesheetPtr style)
1134{
1135    if (style == NULL)
1136        return;
1137    if (style->extInfos == NULL)
1138        return;
1139    xmlHashScan(style->extInfos, (xmlHashScanner) xsltShutdownExt, style);
1140    xmlHashFree(style->extInfos, (xmlHashDeallocator) xsltFreeExtData);
1141    style->extInfos = NULL;
1142}
1143
1144/**
1145 * xsltCheckExtPrefix:
1146 * @style: the stylesheet
1147 * @URI: the namespace prefix (possibly NULL)
1148 *
1149 * Check if the given prefix is one of the declared extensions.
1150 * This is intended to be called only at compile-time.
1151 * Called by:
1152 *  xsltGetInheritedNsList() (xslt.c)
1153 *  xsltParseTemplateContent (xslt.c)
1154 *
1155 * Returns 1 if this is an extension, 0 otherwise
1156 */
1157int
1158xsltCheckExtPrefix(xsltStylesheetPtr style, const xmlChar * URI)
1159{
1160#ifdef XSLT_REFACTORED
1161    if ((style == NULL) || (style->compCtxt == NULL) ||
1162	(XSLT_CCTXT(style)->inode == NULL) ||
1163	(XSLT_CCTXT(style)->inode->extElemNs == NULL))
1164        return (0);
1165    /*
1166    * Lookup the extension namespaces registered
1167    * at the current node in the stylesheet's tree.
1168    */
1169    if (XSLT_CCTXT(style)->inode->extElemNs != NULL) {
1170	int i;
1171	xsltPointerListPtr list = XSLT_CCTXT(style)->inode->extElemNs;
1172
1173	for (i = 0; i < list->number; i++) {
1174	    if (xmlStrEqual((const xmlChar *) list->items[i],
1175		URI))
1176	    {
1177		return(1);
1178	    }
1179	}
1180    }
1181#else
1182    xsltExtDefPtr cur;
1183
1184    if ((style == NULL) || (style->nsDefs == NULL))
1185        return (0);
1186    if (URI == NULL)
1187        URI = BAD_CAST "#default";
1188    cur = (xsltExtDefPtr) style->nsDefs;
1189    while (cur != NULL) {
1190	/*
1191	* NOTE: This was change to work on namespace names rather
1192	* than namespace prefixes. This fixes bug #339583.
1193	* TODO: Consider renaming the field "prefix" of xsltExtDef
1194	*  to "href".
1195	*/
1196        if (xmlStrEqual(URI, cur->prefix))
1197            return (1);
1198        cur = cur->next;
1199    }
1200#endif
1201    return (0);
1202}
1203
1204/**
1205 * xsltCheckExtURI:
1206 * @style: the stylesheet
1207 * @URI: the namespace URI (possibly NULL)
1208 *
1209 * Check if the given prefix is one of the declared extensions.
1210 * This is intended to be called only at compile-time.
1211 * Called by:
1212 *  xsltPrecomputeStylesheet() (xslt.c)
1213 *  xsltParseTemplateContent (xslt.c)
1214 *
1215 * Returns 1 if this is an extension, 0 otherwise
1216 */
1217int
1218xsltCheckExtURI(xsltStylesheetPtr style, const xmlChar * URI)
1219{
1220    xsltExtDefPtr cur;
1221
1222    if ((style == NULL) || (style->nsDefs == NULL))
1223        return (0);
1224    if (URI == NULL)
1225        return (0);
1226    cur = (xsltExtDefPtr) style->nsDefs;
1227    while (cur != NULL) {
1228        if (xmlStrEqual(URI, cur->URI))
1229            return (1);
1230        cur = cur->next;
1231    }
1232    return (0);
1233}
1234
1235/**
1236 * xsltRegisterExtModuleFull:
1237 * @URI:  URI associated to this module
1238 * @initFunc:  the module initialization function
1239 * @shutdownFunc:  the module shutdown function
1240 * @styleInitFunc:  the module initialization function
1241 * @styleShutdownFunc:  the module shutdown function
1242 *
1243 * Register an XSLT extension module to the library.
1244 *
1245 * Returns 0 if sucessful, -1 in case of error
1246 */
1247int
1248xsltRegisterExtModuleFull(const xmlChar * URI,
1249                          xsltExtInitFunction initFunc,
1250                          xsltExtShutdownFunction shutdownFunc,
1251                          xsltStyleExtInitFunction styleInitFunc,
1252                          xsltStyleExtShutdownFunction styleShutdownFunc)
1253{
1254    int ret;
1255    xsltExtModulePtr module;
1256
1257    if ((URI == NULL) || (initFunc == NULL))
1258        return (-1);
1259    if (xsltExtensionsHash == NULL)
1260        xsltExtensionsHash = xmlHashCreate(10);
1261
1262    if (xsltExtensionsHash == NULL)
1263        return (-1);
1264
1265    xmlMutexLock(xsltExtMutex);
1266
1267    module = xmlHashLookup(xsltExtensionsHash, URI);
1268    if (module != NULL) {
1269        if ((module->initFunc == initFunc) &&
1270            (module->shutdownFunc == shutdownFunc))
1271            ret = 0;
1272        else
1273            ret = -1;
1274        goto done;
1275    }
1276    module = xsltNewExtModule(initFunc, shutdownFunc,
1277                              styleInitFunc, styleShutdownFunc);
1278    if (module == NULL) {
1279        ret = -1;
1280        goto done;
1281    }
1282    ret = xmlHashAddEntry(xsltExtensionsHash, URI, (void *) module);
1283
1284done:
1285    xmlMutexUnlock(xsltExtMutex);
1286    return (ret);
1287}
1288
1289/**
1290 * xsltRegisterExtModule:
1291 * @URI:  URI associated to this module
1292 * @initFunc:  the module initialization function
1293 * @shutdownFunc:  the module shutdown function
1294 *
1295 * Register an XSLT extension module to the library.
1296 *
1297 * Returns 0 if sucessful, -1 in case of error
1298 */
1299int
1300xsltRegisterExtModule(const xmlChar * URI,
1301                      xsltExtInitFunction initFunc,
1302                      xsltExtShutdownFunction shutdownFunc)
1303{
1304    return xsltRegisterExtModuleFull(URI, initFunc, shutdownFunc,
1305                                     NULL, NULL);
1306}
1307
1308/**
1309 * xsltUnregisterExtModule:
1310 * @URI:  URI associated to this module
1311 *
1312 * Unregister an XSLT extension module from the library.
1313 *
1314 * Returns 0 if sucessful, -1 in case of error
1315 */
1316int
1317xsltUnregisterExtModule(const xmlChar * URI)
1318{
1319    int ret;
1320
1321    if (URI == NULL)
1322        return (-1);
1323    if (xsltExtensionsHash == NULL)
1324        return (-1);
1325
1326    xmlMutexLock(xsltExtMutex);
1327
1328    ret = xmlHashRemoveEntry(xsltExtensionsHash, URI,
1329                             (xmlHashDeallocator) xsltFreeExtModule);
1330
1331    xmlMutexUnlock(xsltExtMutex);
1332
1333    return (ret);
1334}
1335
1336/**
1337 * xsltUnregisterAllExtModules:
1338 *
1339 * Unregister all the XSLT extension module from the library.
1340 */
1341static void
1342xsltUnregisterAllExtModules(void)
1343{
1344    if (xsltExtensionsHash == NULL)
1345        return;
1346
1347    xmlMutexLock(xsltExtMutex);
1348
1349    xmlHashFree(xsltExtensionsHash,
1350                (xmlHashDeallocator) xsltFreeExtModule);
1351    xsltExtensionsHash = NULL;
1352
1353    xmlMutexUnlock(xsltExtMutex);
1354}
1355
1356/**
1357 * xsltXPathGetTransformContext:
1358 * @ctxt:  an XPath transformation context
1359 *
1360 * Provides the XSLT transformation context from the XPath transformation
1361 * context. This is useful when an XPath function in the extension module
1362 * is called by the XPath interpreter and that the XSLT context is needed
1363 * for example to retrieve the associated data pertaining to this XSLT
1364 * transformation.
1365 *
1366 * Returns the XSLT transformation context or NULL in case of error.
1367 */
1368xsltTransformContextPtr
1369xsltXPathGetTransformContext(xmlXPathParserContextPtr ctxt)
1370{
1371    if ((ctxt == NULL) || (ctxt->context == NULL))
1372        return (NULL);
1373    return (ctxt->context->extra);
1374}
1375
1376/**
1377 * xsltRegisterExtModuleFunction:
1378 * @name:  the function name
1379 * @URI:  the function namespace URI
1380 * @function:  the function callback
1381 *
1382 * Registers an extension module function.
1383 *
1384 * Returns 0 if successful, -1 in case of error.
1385 */
1386int
1387xsltRegisterExtModuleFunction(const xmlChar * name, const xmlChar * URI,
1388                              xmlXPathFunction function)
1389{
1390    if ((name == NULL) || (URI == NULL) || (function == NULL))
1391        return (-1);
1392
1393    if (xsltFunctionsHash == NULL)
1394        xsltFunctionsHash = xmlHashCreate(10);
1395    if (xsltFunctionsHash == NULL)
1396        return (-1);
1397
1398    xmlMutexLock(xsltExtMutex);
1399
1400    xmlHashUpdateEntry2(xsltFunctionsHash, name, URI,
1401                        XML_CAST_FPTR(function), NULL);
1402
1403    xmlMutexUnlock(xsltExtMutex);
1404
1405    return (0);
1406}
1407
1408/**
1409 * xsltExtModuleFunctionLookup:
1410 * @name:  the function name
1411 * @URI:  the function namespace URI
1412 *
1413 * Looks up an extension module function
1414 *
1415 * Returns the function if found, NULL otherwise.
1416 */
1417xmlXPathFunction
1418xsltExtModuleFunctionLookup(const xmlChar * name, const xmlChar * URI)
1419{
1420    xmlXPathFunction ret;
1421
1422    if ((xsltFunctionsHash == NULL) || (name == NULL) || (URI == NULL))
1423        return (NULL);
1424
1425    xmlMutexLock(xsltExtMutex);
1426
1427    XML_CAST_FPTR(ret) = xmlHashLookup2(xsltFunctionsHash, name, URI);
1428
1429    xmlMutexUnlock(xsltExtMutex);
1430
1431    /* if lookup fails, attempt a dynamic load on supported platforms */
1432    if (NULL == ret) {
1433        if (!xsltExtModuleRegisterDynamic(URI)) {
1434            xmlMutexLock(xsltExtMutex);
1435
1436            XML_CAST_FPTR(ret) =
1437                xmlHashLookup2(xsltFunctionsHash, name, URI);
1438
1439            xmlMutexUnlock(xsltExtMutex);
1440        }
1441    }
1442
1443    return ret;
1444}
1445
1446/**
1447 * xsltUnregisterExtModuleFunction:
1448 * @name:  the function name
1449 * @URI:  the function namespace URI
1450 *
1451 * Unregisters an extension module function
1452 *
1453 * Returns 0 if successful, -1 in case of error.
1454 */
1455int
1456xsltUnregisterExtModuleFunction(const xmlChar * name, const xmlChar * URI)
1457{
1458    int ret;
1459
1460    if ((xsltFunctionsHash == NULL) || (name == NULL) || (URI == NULL))
1461        return (-1);
1462
1463    xmlMutexLock(xsltExtMutex);
1464
1465    ret = xmlHashRemoveEntry2(xsltFunctionsHash, name, URI, NULL);
1466
1467    xmlMutexUnlock(xsltExtMutex);
1468
1469    return(ret);
1470}
1471
1472/**
1473 * xsltUnregisterAllExtModuleFunction:
1474 *
1475 * Unregisters all extension module function
1476 */
1477static void
1478xsltUnregisterAllExtModuleFunction(void)
1479{
1480    xmlMutexLock(xsltExtMutex);
1481
1482    xmlHashFree(xsltFunctionsHash, NULL);
1483    xsltFunctionsHash = NULL;
1484
1485    xmlMutexUnlock(xsltExtMutex);
1486}
1487
1488
1489/**
1490 * xsltNewElemPreComp:
1491 * @style:  the XSLT stylesheet
1492 * @inst:  the element node
1493 * @function: the transform function
1494 *
1495 * Creates and initializes an #xsltElemPreComp
1496 *
1497 * Returns the new and initialized #xsltElemPreComp
1498 */
1499xsltElemPreCompPtr
1500xsltNewElemPreComp(xsltStylesheetPtr style, xmlNodePtr inst,
1501                   xsltTransformFunction function)
1502{
1503    xsltElemPreCompPtr cur;
1504
1505    cur = (xsltElemPreCompPtr) xmlMalloc(sizeof(xsltElemPreComp));
1506    if (cur == NULL) {
1507        xsltTransformError(NULL, style, NULL,
1508                           "xsltNewExtElement : malloc failed\n");
1509        return (NULL);
1510    }
1511    memset(cur, 0, sizeof(xsltElemPreComp));
1512
1513    xsltInitElemPreComp(cur, style, inst, function,
1514                        (xsltElemPreCompDeallocator) xmlFree);
1515
1516    return (cur);
1517}
1518
1519/**
1520 * xsltInitElemPreComp:
1521 * @comp:  an #xsltElemPreComp (or generally a derived structure)
1522 * @style:  the XSLT stylesheet
1523 * @inst:  the element node
1524 * @function:  the transform function
1525 * @freeFunc:  the @comp deallocator
1526 *
1527 * Initializes an existing #xsltElemPreComp structure. This is usefull
1528 * when extending an #xsltElemPreComp to store precomputed data.
1529 * This function MUST be called on any extension element precomputed
1530 * data struct.
1531 */
1532void
1533xsltInitElemPreComp(xsltElemPreCompPtr comp, xsltStylesheetPtr style,
1534                    xmlNodePtr inst, xsltTransformFunction function,
1535                    xsltElemPreCompDeallocator freeFunc)
1536{
1537    comp->type = XSLT_FUNC_EXTENSION;
1538    comp->func = function;
1539    comp->inst = inst;
1540    comp->free = freeFunc;
1541
1542    comp->next = style->preComps;
1543    style->preComps = comp;
1544}
1545
1546/**
1547 * xsltPreComputeExtModuleElement:
1548 * @style:  the stylesheet
1549 * @inst:  the element node
1550 *
1551 * Precomputes an extension module element
1552 *
1553 * Returns the precomputed data
1554 */
1555xsltElemPreCompPtr
1556xsltPreComputeExtModuleElement(xsltStylesheetPtr style, xmlNodePtr inst)
1557{
1558    xsltExtElementPtr ext;
1559    xsltElemPreCompPtr comp = NULL;
1560
1561    if ((style == NULL) || (inst == NULL) ||
1562        (inst->type != XML_ELEMENT_NODE) || (inst->ns == NULL))
1563        return (NULL);
1564
1565    xmlMutexLock(xsltExtMutex);
1566
1567    ext = (xsltExtElementPtr)
1568        xmlHashLookup2(xsltElementsHash, inst->name, inst->ns->href);
1569
1570    xmlMutexUnlock(xsltExtMutex);
1571
1572    /*
1573    * EXT TODO: Now what?
1574    */
1575    if (ext == NULL)
1576        return (NULL);
1577
1578    if (ext->precomp != NULL) {
1579	/*
1580	* REVISIT TODO: Check if the text below is correct.
1581	* This will return a xsltElemPreComp structure or NULL.
1582	* 1) If the the author of the extension needs a
1583	*  custom structure to hold the specific values of
1584	*  this extension, he will derive a structure based on
1585	*  xsltElemPreComp; thus we obviously *cannot* refactor
1586	*  the xsltElemPreComp structure, since all already derived
1587	*  user-defined strucures will break.
1588	*  Example: For the extension xsl:document,
1589	*   in xsltDocumentComp() (preproc.c), the structure
1590	*   xsltStyleItemDocument is allocated, filled with
1591	*   specific values and returned.
1592	* 2) If the author needs no values to be stored in
1593	*  this structure, then he'll return NULL;
1594	*/
1595        comp = ext->precomp(style, inst, ext->transform);
1596    }
1597    if (comp == NULL) {
1598	/*
1599	* Default creation of a xsltElemPreComp structure, if
1600	* the author of this extension did not create a custom
1601	* structure.
1602	*/
1603        comp = xsltNewElemPreComp(style, inst, ext->transform);
1604    }
1605
1606    return (comp);
1607}
1608
1609/**
1610 * xsltRegisterExtModuleElement:
1611 * @name:  the element name
1612 * @URI:  the element namespace URI
1613 * @precomp:  the pre-computation callback
1614 * @transform:  the transformation callback
1615 *
1616 * Registers an extension module element.
1617 *
1618 * Returns 0 if successful, -1 in case of error.
1619 */
1620int
1621xsltRegisterExtModuleElement(const xmlChar * name, const xmlChar * URI,
1622                             xsltPreComputeFunction precomp,
1623                             xsltTransformFunction transform)
1624{
1625    int ret;
1626
1627    xsltExtElementPtr ext;
1628
1629    if ((name == NULL) || (URI == NULL) || (transform == NULL))
1630        return (-1);
1631
1632    if (xsltElementsHash == NULL)
1633        xsltElementsHash = xmlHashCreate(10);
1634    if (xsltElementsHash == NULL)
1635        return (-1);
1636
1637    xmlMutexLock(xsltExtMutex);
1638
1639    ext = xsltNewExtElement(precomp, transform);
1640    if (ext == NULL) {
1641        ret = -1;
1642        goto done;
1643    }
1644
1645    xmlHashUpdateEntry2(xsltElementsHash, name, URI, (void *) ext,
1646                        (xmlHashDeallocator) xsltFreeExtElement);
1647
1648done:
1649    xmlMutexUnlock(xsltExtMutex);
1650
1651    return (0);
1652}
1653
1654/**
1655 * xsltExtElementLookup:
1656 * @ctxt:  an XSLT process context
1657 * @name:  the element name
1658 * @URI:  the element namespace URI
1659 *
1660 * Looks up an extension element. @ctxt can be NULL to search only in
1661 * module elements.
1662 *
1663 * Returns the element callback or NULL if not found
1664 */
1665xsltTransformFunction
1666xsltExtElementLookup(xsltTransformContextPtr ctxt,
1667                     const xmlChar * name, const xmlChar * URI)
1668{
1669    xsltTransformFunction ret;
1670
1671    if ((name == NULL) || (URI == NULL))
1672        return (NULL);
1673
1674    if ((ctxt != NULL) && (ctxt->extElements != NULL)) {
1675        XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->extElements, name, URI);
1676        if (ret != NULL) {
1677            return(ret);
1678        }
1679    }
1680
1681    ret = xsltExtModuleElementLookup(name, URI);
1682
1683    return (ret);
1684}
1685
1686/**
1687 * xsltExtModuleElementLookup:
1688 * @name:  the element name
1689 * @URI:  the element namespace URI
1690 *
1691 * Looks up an extension module element
1692 *
1693 * Returns the callback function if found, NULL otherwise.
1694 */
1695xsltTransformFunction
1696xsltExtModuleElementLookup(const xmlChar * name, const xmlChar * URI)
1697{
1698    xsltExtElementPtr ext;
1699
1700    if ((xsltElementsHash == NULL) || (name == NULL) || (URI == NULL))
1701        return (NULL);
1702
1703    xmlMutexLock(xsltExtMutex);
1704
1705    ext = (xsltExtElementPtr) xmlHashLookup2(xsltElementsHash, name, URI);
1706
1707    xmlMutexUnlock(xsltExtMutex);
1708
1709    /*
1710     * if function lookup fails, attempt a dynamic load on
1711     * supported platforms
1712     */
1713    if (NULL == ext) {
1714        if (!xsltExtModuleRegisterDynamic(URI)) {
1715            xmlMutexLock(xsltExtMutex);
1716
1717            ext = (xsltExtElementPtr)
1718	          xmlHashLookup2(xsltElementsHash, name, URI);
1719
1720            xmlMutexUnlock(xsltExtMutex);
1721        }
1722    }
1723
1724    if (ext == NULL)
1725        return (NULL);
1726    return (ext->transform);
1727}
1728
1729/**
1730 * xsltExtModuleElementPreComputeLookup:
1731 * @name:  the element name
1732 * @URI:  the element namespace URI
1733 *
1734 * Looks up an extension module element pre-computation function
1735 *
1736 * Returns the callback function if found, NULL otherwise.
1737 */
1738xsltPreComputeFunction
1739xsltExtModuleElementPreComputeLookup(const xmlChar * name,
1740                                     const xmlChar * URI)
1741{
1742    xsltExtElementPtr ext;
1743
1744    if ((xsltElementsHash == NULL) || (name == NULL) || (URI == NULL))
1745        return (NULL);
1746
1747    xmlMutexLock(xsltExtMutex);
1748
1749    ext = (xsltExtElementPtr) xmlHashLookup2(xsltElementsHash, name, URI);
1750
1751    xmlMutexUnlock(xsltExtMutex);
1752
1753    if (ext == NULL) {
1754        if (!xsltExtModuleRegisterDynamic(URI)) {
1755            xmlMutexLock(xsltExtMutex);
1756
1757            ext = (xsltExtElementPtr)
1758	          xmlHashLookup2(xsltElementsHash, name, URI);
1759
1760            xmlMutexUnlock(xsltExtMutex);
1761        }
1762    }
1763
1764    if (ext == NULL)
1765        return (NULL);
1766    return (ext->precomp);
1767}
1768
1769/**
1770 * xsltUnregisterExtModuleElement:
1771 * @name:  the element name
1772 * @URI:  the element namespace URI
1773 *
1774 * Unregisters an extension module element
1775 *
1776 * Returns 0 if successful, -1 in case of error.
1777 */
1778int
1779xsltUnregisterExtModuleElement(const xmlChar * name, const xmlChar * URI)
1780{
1781    int ret;
1782
1783    if ((xsltElementsHash == NULL) || (name == NULL) || (URI == NULL))
1784        return (-1);
1785
1786    xmlMutexLock(xsltExtMutex);
1787
1788    ret = xmlHashRemoveEntry2(xsltElementsHash, name, URI,
1789                              (xmlHashDeallocator) xsltFreeExtElement);
1790
1791    xmlMutexUnlock(xsltExtMutex);
1792
1793    return(ret);
1794}
1795
1796/**
1797 * xsltUnregisterAllExtModuleElement:
1798 *
1799 * Unregisters all extension module element
1800 */
1801static void
1802xsltUnregisterAllExtModuleElement(void)
1803{
1804    xmlMutexLock(xsltExtMutex);
1805
1806    xmlHashFree(xsltElementsHash, (xmlHashDeallocator) xsltFreeExtElement);
1807    xsltElementsHash = NULL;
1808
1809    xmlMutexUnlock(xsltExtMutex);
1810}
1811
1812/**
1813 * xsltRegisterExtModuleTopLevel:
1814 * @name:  the top-level element name
1815 * @URI:  the top-level element namespace URI
1816 * @function:  the top-level element callback
1817 *
1818 * Registers an extension module top-level element.
1819 *
1820 * Returns 0 if successful, -1 in case of error.
1821 */
1822int
1823xsltRegisterExtModuleTopLevel(const xmlChar * name, const xmlChar * URI,
1824                              xsltTopLevelFunction function)
1825{
1826    if ((name == NULL) || (URI == NULL) || (function == NULL))
1827        return (-1);
1828
1829    if (xsltTopLevelsHash == NULL)
1830        xsltTopLevelsHash = xmlHashCreate(10);
1831    if (xsltTopLevelsHash == NULL)
1832        return (-1);
1833
1834    xmlMutexLock(xsltExtMutex);
1835
1836    xmlHashUpdateEntry2(xsltTopLevelsHash, name, URI,
1837                        XML_CAST_FPTR(function), NULL);
1838
1839    xmlMutexUnlock(xsltExtMutex);
1840
1841    return (0);
1842}
1843
1844/**
1845 * xsltExtModuleTopLevelLookup:
1846 * @name:  the top-level element name
1847 * @URI:  the top-level element namespace URI
1848 *
1849 * Looks up an extension module top-level element
1850 *
1851 * Returns the callback function if found, NULL otherwise.
1852 */
1853xsltTopLevelFunction
1854xsltExtModuleTopLevelLookup(const xmlChar * name, const xmlChar * URI)
1855{
1856    xsltTopLevelFunction ret;
1857
1858    if ((xsltTopLevelsHash == NULL) || (name == NULL) || (URI == NULL))
1859        return (NULL);
1860
1861    xmlMutexLock(xsltExtMutex);
1862
1863    XML_CAST_FPTR(ret) = xmlHashLookup2(xsltTopLevelsHash, name, URI);
1864
1865    xmlMutexUnlock(xsltExtMutex);
1866
1867    /* if lookup fails, attempt a dynamic load on supported platforms */
1868    if (NULL == ret) {
1869        if (!xsltExtModuleRegisterDynamic(URI)) {
1870            xmlMutexLock(xsltExtMutex);
1871
1872            XML_CAST_FPTR(ret) = xmlHashLookup2(xsltTopLevelsHash, name, URI);
1873
1874            xmlMutexUnlock(xsltExtMutex);
1875        }
1876    }
1877
1878    return (ret);
1879}
1880
1881/**
1882 * xsltUnregisterExtModuleTopLevel:
1883 * @name:  the top-level element name
1884 * @URI:  the top-level element namespace URI
1885 *
1886 * Unregisters an extension module top-level element
1887 *
1888 * Returns 0 if successful, -1 in case of error.
1889 */
1890int
1891xsltUnregisterExtModuleTopLevel(const xmlChar * name, const xmlChar * URI)
1892{
1893    int ret;
1894
1895    if ((xsltTopLevelsHash == NULL) || (name == NULL) || (URI == NULL))
1896        return (-1);
1897
1898    xmlMutexLock(xsltExtMutex);
1899
1900    ret = xmlHashRemoveEntry2(xsltTopLevelsHash, name, URI, NULL);
1901
1902    xmlMutexUnlock(xsltExtMutex);
1903
1904    return(ret);
1905}
1906
1907/**
1908 * xsltUnregisterAllExtModuleTopLevel:
1909 *
1910 * Unregisters all extension module function
1911 */
1912static void
1913xsltUnregisterAllExtModuleTopLevel(void)
1914{
1915    xmlMutexLock(xsltExtMutex);
1916
1917    xmlHashFree(xsltTopLevelsHash, NULL);
1918    xsltTopLevelsHash = NULL;
1919
1920    xmlMutexUnlock(xsltExtMutex);
1921}
1922
1923/**
1924 * xsltGetExtInfo:
1925 * @style:  pointer to a stylesheet
1926 * @URI:    the namespace URI desired
1927 *
1928 * looks up URI in extInfos of the stylesheet
1929 *
1930 * returns a pointer to the hash table if found, else NULL
1931 */
1932xmlHashTablePtr
1933xsltGetExtInfo(xsltStylesheetPtr style, const xmlChar * URI)
1934{
1935    xsltExtDataPtr data;
1936
1937    /*
1938    * TODO: Why do we have a return type of xmlHashTablePtr?
1939    *   Is the user-allocated data for extension modules expected
1940    *   to be a xmlHashTablePtr only? Or is this intended for
1941    *   the EXSLT module only?
1942    */
1943
1944    if (style != NULL && style->extInfos != NULL) {
1945        data = xmlHashLookup(style->extInfos, URI);
1946        if (data != NULL && data->extData != NULL)
1947            return data->extData;
1948    }
1949    return NULL;
1950}
1951
1952/************************************************************************
1953 * 									*
1954 * 		Test module http://xmlsoft.org/XSLT/			*
1955 * 									*
1956 ************************************************************************/
1957
1958/************************************************************************
1959 * 									*
1960 * 		Test of the extension module API			*
1961 * 									*
1962 ************************************************************************/
1963
1964static xmlChar *testData = NULL;
1965static xmlChar *testStyleData = NULL;
1966
1967/**
1968 * xsltExtFunctionTest:
1969 * @ctxt:  the XPath Parser context
1970 * @nargs:  the number of arguments
1971 *
1972 * function libxslt:test() for testing the extensions support.
1973 */
1974static void
1975xsltExtFunctionTest(xmlXPathParserContextPtr ctxt,
1976                    int nargs ATTRIBUTE_UNUSED)
1977{
1978    xsltTransformContextPtr tctxt;
1979    void *data = NULL;
1980
1981    tctxt = xsltXPathGetTransformContext(ctxt);
1982
1983    if (testData == NULL) {
1984        xsltGenericDebug(xsltGenericDebugContext,
1985                         "xsltExtFunctionTest: not initialized,"
1986                         " calling xsltGetExtData\n");
1987        data = xsltGetExtData(tctxt, (const xmlChar *) XSLT_DEFAULT_URL);
1988        if (data == NULL) {
1989            xsltTransformError(tctxt, NULL, NULL,
1990                               "xsltExtElementTest: not initialized\n");
1991            return;
1992        }
1993    }
1994    if (tctxt == NULL) {
1995        xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
1996                           "xsltExtFunctionTest: failed to get the transformation context\n");
1997        return;
1998    }
1999    if (data == NULL)
2000        data = xsltGetExtData(tctxt, (const xmlChar *) XSLT_DEFAULT_URL);
2001    if (data == NULL) {
2002        xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
2003                           "xsltExtFunctionTest: failed to get module data\n");
2004        return;
2005    }
2006    if (data != testData) {
2007        xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
2008                           "xsltExtFunctionTest: got wrong module data\n");
2009        return;
2010    }
2011#ifdef WITH_XSLT_DEBUG_FUNCTION
2012    xsltGenericDebug(xsltGenericDebugContext,
2013                     "libxslt:test() called with %d args\n", nargs);
2014#endif
2015}
2016
2017/**
2018 * xsltExtElementPreCompTest:
2019 * @style:  the stylesheet
2020 * @inst:  the instruction in the stylesheet
2021 *
2022 * Process a libxslt:test node
2023 */
2024static xsltElemPreCompPtr
2025xsltExtElementPreCompTest(xsltStylesheetPtr style, xmlNodePtr inst,
2026                          xsltTransformFunction function)
2027{
2028    xsltElemPreCompPtr ret;
2029
2030    if (style == NULL) {
2031        xsltTransformError(NULL, NULL, inst,
2032                           "xsltExtElementTest: no transformation context\n");
2033        return (NULL);
2034    }
2035    if (testStyleData == NULL) {
2036        xsltGenericDebug(xsltGenericDebugContext,
2037                         "xsltExtElementPreCompTest: not initialized,"
2038                         " calling xsltStyleGetExtData\n");
2039        xsltStyleGetExtData(style, (const xmlChar *) XSLT_DEFAULT_URL);
2040        if (testStyleData == NULL) {
2041            xsltTransformError(NULL, style, inst,
2042                               "xsltExtElementPreCompTest: not initialized\n");
2043            if (style != NULL)
2044                style->errors++;
2045            return (NULL);
2046        }
2047    }
2048    if (inst == NULL) {
2049        xsltTransformError(NULL, style, inst,
2050                           "xsltExtElementPreCompTest: no instruction\n");
2051        if (style != NULL)
2052            style->errors++;
2053        return (NULL);
2054    }
2055    ret = xsltNewElemPreComp(style, inst, function);
2056    return (ret);
2057}
2058
2059/**
2060 * xsltExtElementTest:
2061 * @ctxt:  an XSLT processing context
2062 * @node:  The current node
2063 * @inst:  the instruction in the stylesheet
2064 * @comp:  precomputed informations
2065 *
2066 * Process a libxslt:test node
2067 */
2068static void
2069xsltExtElementTest(xsltTransformContextPtr ctxt, xmlNodePtr node,
2070                   xmlNodePtr inst,
2071                   xsltElemPreCompPtr comp ATTRIBUTE_UNUSED)
2072{
2073    xmlNodePtr commentNode;
2074
2075    if (testData == NULL) {
2076        xsltGenericDebug(xsltGenericDebugContext,
2077                         "xsltExtElementTest: not initialized,"
2078                         " calling xsltGetExtData\n");
2079        xsltGetExtData(ctxt, (const xmlChar *) XSLT_DEFAULT_URL);
2080        if (testData == NULL) {
2081            xsltTransformError(ctxt, NULL, inst,
2082                               "xsltExtElementTest: not initialized\n");
2083            return;
2084        }
2085    }
2086    if (ctxt == NULL) {
2087        xsltTransformError(ctxt, NULL, inst,
2088                           "xsltExtElementTest: no transformation context\n");
2089        return;
2090    }
2091    if (node == NULL) {
2092        xsltTransformError(ctxt, NULL, inst,
2093                           "xsltExtElementTest: no current node\n");
2094        return;
2095    }
2096    if (inst == NULL) {
2097        xsltTransformError(ctxt, NULL, inst,
2098                           "xsltExtElementTest: no instruction\n");
2099        return;
2100    }
2101    if (ctxt->insert == NULL) {
2102        xsltTransformError(ctxt, NULL, inst,
2103                           "xsltExtElementTest: no insertion point\n");
2104        return;
2105    }
2106    commentNode = xmlNewComment((const xmlChar *)
2107                                "libxslt:test element test worked");
2108    xmlAddChild(ctxt->insert, commentNode);
2109}
2110
2111/**
2112 * xsltExtInitTest:
2113 * @ctxt:  an XSLT transformation context
2114 * @URI:  the namespace URI for the extension
2115 *
2116 * A function called at initialization time of an XSLT extension module
2117 *
2118 * Returns a pointer to the module specific data for this transformation
2119 */
2120static void *
2121xsltExtInitTest(xsltTransformContextPtr ctxt, const xmlChar * URI)
2122{
2123    if (testStyleData == NULL) {
2124        xsltGenericDebug(xsltGenericErrorContext,
2125                         "xsltExtInitTest: not initialized,"
2126                         " calling xsltStyleGetExtData\n");
2127        testStyleData = xsltStyleGetExtData(ctxt->style, URI);
2128        if (testStyleData == NULL) {
2129            xsltTransformError(ctxt, NULL, NULL,
2130                               "xsltExtInitTest: not initialized\n");
2131            return (NULL);
2132        }
2133    }
2134    if (testData != NULL) {
2135        xsltTransformError(ctxt, NULL, NULL,
2136                           "xsltExtInitTest: already initialized\n");
2137        return (NULL);
2138    }
2139    testData = (void *) "test data";
2140    xsltGenericDebug(xsltGenericDebugContext,
2141                     "Registered test module : %s\n", URI);
2142    return (testData);
2143}
2144
2145
2146/**
2147 * xsltExtShutdownTest:
2148 * @ctxt:  an XSLT transformation context
2149 * @URI:  the namespace URI for the extension
2150 * @data:  the data associated to this module
2151 *
2152 * A function called at shutdown time of an XSLT extension module
2153 */
2154static void
2155xsltExtShutdownTest(xsltTransformContextPtr ctxt,
2156                    const xmlChar * URI, void *data)
2157{
2158    if (testData == NULL) {
2159        xsltTransformError(ctxt, NULL, NULL,
2160                           "xsltExtShutdownTest: not initialized\n");
2161        return;
2162    }
2163    if (data != testData) {
2164        xsltTransformError(ctxt, NULL, NULL,
2165                           "xsltExtShutdownTest: wrong data\n");
2166    }
2167    testData = NULL;
2168    xsltGenericDebug(xsltGenericDebugContext,
2169                     "Unregistered test module : %s\n", URI);
2170}
2171
2172/**
2173 * xsltExtStyleInitTest:
2174 * @style:  an XSLT stylesheet
2175 * @URI:  the namespace URI for the extension
2176 *
2177 * A function called at initialization time of an XSLT extension module
2178 *
2179 * Returns a pointer to the module specific data for this transformation
2180 */
2181static void *
2182xsltExtStyleInitTest(xsltStylesheetPtr style ATTRIBUTE_UNUSED,
2183                     const xmlChar * URI)
2184{
2185    if (testStyleData != NULL) {
2186        xsltTransformError(NULL, NULL, NULL,
2187                           "xsltExtInitTest: already initialized\n");
2188        return (NULL);
2189    }
2190    testStyleData = (void *) "test data";
2191    xsltGenericDebug(xsltGenericDebugContext,
2192                     "Registered test module : %s\n", URI);
2193    return (testStyleData);
2194}
2195
2196
2197/**
2198 * xsltExtStyleShutdownTest:
2199 * @style:  an XSLT stylesheet
2200 * @URI:  the namespace URI for the extension
2201 * @data:  the data associated to this module
2202 *
2203 * A function called at shutdown time of an XSLT extension module
2204 */
2205static void
2206xsltExtStyleShutdownTest(xsltStylesheetPtr style ATTRIBUTE_UNUSED,
2207                         const xmlChar * URI, void *data)
2208{
2209    if (testStyleData == NULL) {
2210        xsltGenericError(xsltGenericErrorContext,
2211                         "xsltExtShutdownTest: not initialized\n");
2212        return;
2213    }
2214    if (data != testStyleData) {
2215        xsltTransformError(NULL, NULL, NULL,
2216                           "xsltExtShutdownTest: wrong data\n");
2217    }
2218    testStyleData = NULL;
2219    xsltGenericDebug(xsltGenericDebugContext,
2220                     "Unregistered test module : %s\n", URI);
2221}
2222
2223/**
2224 * xsltRegisterTestModule:
2225 *
2226 * Registers the test module
2227 */
2228void
2229xsltRegisterTestModule(void)
2230{
2231    xsltInitGlobals();
2232    xsltRegisterExtModuleFull((const xmlChar *) XSLT_DEFAULT_URL,
2233                              xsltExtInitTest, xsltExtShutdownTest,
2234                              xsltExtStyleInitTest,
2235                              xsltExtStyleShutdownTest);
2236    xsltRegisterExtModuleFunction((const xmlChar *) "test",
2237                                  (const xmlChar *) XSLT_DEFAULT_URL,
2238                                  xsltExtFunctionTest);
2239    xsltRegisterExtModuleElement((const xmlChar *) "test",
2240                                 (const xmlChar *) XSLT_DEFAULT_URL,
2241                                 xsltExtElementPreCompTest,
2242                                 xsltExtElementTest);
2243}
2244
2245static void
2246xsltHashScannerModuleFree(void *payload ATTRIBUTE_UNUSED,
2247                          void *data ATTRIBUTE_UNUSED,
2248                          xmlChar * name ATTRIBUTE_UNUSED)
2249{
2250#ifdef WITH_MODULES
2251    xmlModuleClose(payload);
2252#endif
2253}
2254
2255/**
2256 * xsltInitGlobals:
2257 *
2258 * Initialize the global variables for extensions
2259 */
2260void
2261xsltInitGlobals(void)
2262{
2263    if (xsltExtMutex == NULL) {
2264        xsltExtMutex = xmlNewMutex();
2265    }
2266}
2267
2268/**
2269 * xsltCleanupGlobals:
2270 *
2271 * Unregister all global variables set up by the XSLT library
2272 */
2273void
2274xsltCleanupGlobals(void)
2275{
2276    xsltUnregisterAllExtModules();
2277    xsltUnregisterAllExtModuleFunction();
2278    xsltUnregisterAllExtModuleElement();
2279    xsltUnregisterAllExtModuleTopLevel();
2280
2281    xmlMutexLock(xsltExtMutex);
2282    /* cleanup dynamic module hash */
2283    if (NULL != xsltModuleHash) {
2284        xmlHashScan(xsltModuleHash, xsltHashScannerModuleFree, 0);
2285        xmlHashFree(xsltModuleHash, NULL);
2286        xsltModuleHash = NULL;
2287    }
2288    xmlMutexUnlock(xsltExtMutex);
2289
2290    xmlFreeMutex(xsltExtMutex);
2291    xsltExtMutex = NULL;
2292    xsltUninit();
2293}
2294
2295static void
2296xsltDebugDumpExtensionsCallback(void *function ATTRIBUTE_UNUSED,
2297                                FILE * output, const xmlChar * name,
2298                                const xmlChar * URI,
2299                                const xmlChar * not_used ATTRIBUTE_UNUSED)
2300{
2301    if (!name || !URI)
2302        return;
2303    fprintf(output, "{%s}%s\n", URI, name);
2304}
2305
2306static void
2307xsltDebugDumpExtModulesCallback(void *function ATTRIBUTE_UNUSED,
2308                                FILE * output, const xmlChar * URI,
2309                                const xmlChar * not_used ATTRIBUTE_UNUSED,
2310                                const xmlChar * not_used2 ATTRIBUTE_UNUSED)
2311{
2312    if (!URI)
2313        return;
2314    fprintf(output, "%s\n", URI);
2315}
2316
2317/**
2318 * xsltDebugDumpExtensions:
2319 * @output:  the FILE * for the output, if NULL stdout is used
2320 *
2321 * Dumps a list of the registered XSLT extension functions and elements
2322 */
2323void
2324xsltDebugDumpExtensions(FILE * output)
2325{
2326    if (output == NULL)
2327        output = stdout;
2328    fprintf(output,
2329            "Registered XSLT Extensions\n--------------------------\n");
2330    if (!xsltFunctionsHash)
2331        fprintf(output, "No registered extension functions\n");
2332    else {
2333        fprintf(output, "Registered Extension Functions:\n");
2334        xmlMutexLock(xsltExtMutex);
2335        xmlHashScanFull(xsltFunctionsHash,
2336                        (xmlHashScannerFull)
2337                        xsltDebugDumpExtensionsCallback, output);
2338        xmlMutexUnlock(xsltExtMutex);
2339    }
2340    if (!xsltElementsHash)
2341        fprintf(output, "\nNo registered extension elements\n");
2342    else {
2343        fprintf(output, "\nRegistered Extension Elements:\n");
2344        xmlMutexLock(xsltExtMutex);
2345        xmlHashScanFull(xsltElementsHash,
2346                        (xmlHashScannerFull)
2347                        xsltDebugDumpExtensionsCallback, output);
2348        xmlMutexUnlock(xsltExtMutex);
2349    }
2350    if (!xsltExtensionsHash)
2351        fprintf(output, "\nNo registered extension modules\n");
2352    else {
2353        fprintf(output, "\nRegistered Extension Modules:\n");
2354        xmlMutexLock(xsltExtMutex);
2355        xmlHashScanFull(xsltExtensionsHash,
2356                        (xmlHashScannerFull)
2357                        xsltDebugDumpExtModulesCallback, output);
2358        xmlMutexUnlock(xsltExtMutex);
2359    }
2360
2361}
2362