xref: /reactos/dll/3rdparty/libxslt/extensions.c (revision 8a978a17)
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 #include "precomp.h"
13 
14 #ifdef WITH_MODULES
15 #include <libxml/xmlmodule.h>
16 #endif
17 #include <libxml/list.h>
18 
19 #ifdef _WIN32
20 #ifndef PATH_MAX
21 #define PATH_MAX _MAX_PATH
22 #endif
23 #endif
24 
25 #ifdef WITH_XSLT_DEBUG
26 #define WITH_XSLT_DEBUG_EXTENSIONS
27 #endif
28 
29 /************************************************************************
30  *									*
31  *			Private Types and Globals			*
32  *									*
33  ************************************************************************/
34 
35 typedef struct _xsltExtDef xsltExtDef;
36 typedef xsltExtDef *xsltExtDefPtr;
37 struct _xsltExtDef {
38     struct _xsltExtDef *next;
39     xmlChar *prefix;
40     xmlChar *URI;
41     void *data;
42 };
43 
44 typedef struct _xsltExtModule xsltExtModule;
45 typedef xsltExtModule *xsltExtModulePtr;
46 struct _xsltExtModule {
47     xsltExtInitFunction initFunc;
48     xsltExtShutdownFunction shutdownFunc;
49     xsltStyleExtInitFunction styleInitFunc;
50     xsltStyleExtShutdownFunction styleShutdownFunc;
51 };
52 
53 typedef struct _xsltExtData xsltExtData;
54 typedef xsltExtData *xsltExtDataPtr;
55 struct _xsltExtData {
56     xsltExtModulePtr extModule;
57     void *extData;
58 };
59 
60 typedef struct _xsltExtElement xsltExtElement;
61 typedef xsltExtElement *xsltExtElementPtr;
62 struct _xsltExtElement {
63     xsltPreComputeFunction precomp;
64     xsltTransformFunction transform;
65 };
66 
67 static xmlHashTablePtr xsltExtensionsHash = NULL;
68 static xmlHashTablePtr xsltFunctionsHash = NULL;
69 static xmlHashTablePtr xsltElementsHash = NULL;
70 static xmlHashTablePtr xsltTopLevelsHash = NULL;
71 static xmlHashTablePtr xsltModuleHash = NULL;
72 static xmlMutexPtr xsltExtMutex = NULL;
73 
74 /************************************************************************
75  *									*
76  *			Type functions					*
77  *									*
78  ************************************************************************/
79 
80 /**
81  * xsltNewExtDef:
82  * @prefix:  the extension prefix
83  * @URI:  the namespace URI
84  *
85  * Create a new XSLT ExtDef
86  *
87  * Returns the newly allocated xsltExtDefPtr or NULL in case of error
88  */
89 static xsltExtDefPtr
90 xsltNewExtDef(const xmlChar * prefix, const xmlChar * URI)
91 {
92     xsltExtDefPtr cur;
93 
94     cur = (xsltExtDefPtr) xmlMalloc(sizeof(xsltExtDef));
95     if (cur == NULL) {
96         xsltTransformError(NULL, NULL, NULL,
97                            "xsltNewExtDef : malloc failed\n");
98         return (NULL);
99     }
100     memset(cur, 0, sizeof(xsltExtDef));
101     if (prefix != NULL)
102         cur->prefix = xmlStrdup(prefix);
103     if (URI != NULL)
104         cur->URI = xmlStrdup(URI);
105     return (cur);
106 }
107 
108 /**
109  * xsltFreeExtDef:
110  * @extensiond:  an XSLT extension definition
111  *
112  * Free up the memory allocated by @extensiond
113  */
114 static void
115 xsltFreeExtDef(xsltExtDefPtr extensiond)
116 {
117     if (extensiond == NULL)
118         return;
119     if (extensiond->prefix != NULL)
120         xmlFree(extensiond->prefix);
121     if (extensiond->URI != NULL)
122         xmlFree(extensiond->URI);
123     xmlFree(extensiond);
124 }
125 
126 /**
127  * xsltFreeExtDefList:
128  * @extensiond:  an XSLT extension definition list
129  *
130  * Free up the memory allocated by all the elements of @extensiond
131  */
132 static void
133 xsltFreeExtDefList(xsltExtDefPtr extensiond)
134 {
135     xsltExtDefPtr cur;
136 
137     while (extensiond != NULL) {
138         cur = extensiond;
139         extensiond = extensiond->next;
140         xsltFreeExtDef(cur);
141     }
142 }
143 
144 /**
145  * xsltNewExtModule:
146  * @initFunc:  the module initialization function
147  * @shutdownFunc:  the module shutdown function
148  * @styleInitFunc:  the stylesheet module data allocator function
149  * @styleShutdownFunc:  the stylesheet module data free function
150  *
151  * Create a new XSLT extension module
152  *
153  * Returns the newly allocated xsltExtModulePtr or NULL in case of error
154  */
155 static xsltExtModulePtr
156 xsltNewExtModule(xsltExtInitFunction initFunc,
157                  xsltExtShutdownFunction shutdownFunc,
158                  xsltStyleExtInitFunction styleInitFunc,
159                  xsltStyleExtShutdownFunction styleShutdownFunc)
160 {
161     xsltExtModulePtr cur;
162 
163     cur = (xsltExtModulePtr) xmlMalloc(sizeof(xsltExtModule));
164     if (cur == NULL) {
165         xsltTransformError(NULL, NULL, NULL,
166                            "xsltNewExtModule : malloc failed\n");
167         return (NULL);
168     }
169     cur->initFunc = initFunc;
170     cur->shutdownFunc = shutdownFunc;
171     cur->styleInitFunc = styleInitFunc;
172     cur->styleShutdownFunc = styleShutdownFunc;
173     return (cur);
174 }
175 
176 /**
177  * xsltFreeExtModule:
178  * @ext:  an XSLT extension module
179  *
180  * Free up the memory allocated by @ext
181  */
182 static void
183 xsltFreeExtModule(xsltExtModulePtr ext)
184 {
185     if (ext == NULL)
186         return;
187     xmlFree(ext);
188 }
189 
190 static void
191 xsltFreeExtModuleEntry(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
192     xsltFreeExtModule((xsltExtModulePtr) payload);
193 }
194 
195 /**
196  * xsltNewExtData:
197  * @extModule:  the module
198  * @extData:  the associated data
199  *
200  * Create a new XSLT extension module data wrapper
201  *
202  * Returns the newly allocated xsltExtDataPtr or NULL in case of error
203  */
204 static xsltExtDataPtr
205 xsltNewExtData(xsltExtModulePtr extModule, void *extData)
206 {
207     xsltExtDataPtr cur;
208 
209     if (extModule == NULL)
210         return (NULL);
211     cur = (xsltExtDataPtr) xmlMalloc(sizeof(xsltExtData));
212     if (cur == NULL) {
213         xsltTransformError(NULL, NULL, NULL,
214                            "xsltNewExtData : malloc failed\n");
215         return (NULL);
216     }
217     cur->extModule = extModule;
218     cur->extData = extData;
219     return (cur);
220 }
221 
222 /**
223  * xsltFreeExtData:
224  * @ext:  an XSLT extension module data wrapper
225  *
226  * Free up the memory allocated by @ext
227  */
228 static void
229 xsltFreeExtData(xsltExtDataPtr ext)
230 {
231     if (ext == NULL)
232         return;
233     xmlFree(ext);
234 }
235 
236 static void
237 xsltFreeExtDataEntry(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
238     xsltFreeExtData((xsltExtDataPtr) payload);
239 }
240 
241 /**
242  * xsltNewExtElement:
243  * @precomp:  the pre-computation function
244  * @transform:  the transformation function
245  *
246  * Create a new XSLT extension element
247  *
248  * Returns the newly allocated xsltExtElementPtr or NULL in case of
249  * error
250  */
251 static xsltExtElementPtr
252 xsltNewExtElement(xsltPreComputeFunction precomp,
253                   xsltTransformFunction transform)
254 {
255     xsltExtElementPtr cur;
256 
257     if (transform == NULL)
258         return (NULL);
259 
260     cur = (xsltExtElementPtr) xmlMalloc(sizeof(xsltExtElement));
261     if (cur == NULL) {
262         xsltTransformError(NULL, NULL, NULL,
263                            "xsltNewExtElement : malloc failed\n");
264         return (NULL);
265     }
266     cur->precomp = precomp;
267     cur->transform = transform;
268     return (cur);
269 }
270 
271 /**
272  * xsltFreeExtElement:
273  * @ext: an XSLT extension element
274  *
275  * Frees up the memory allocated by @ext
276  */
277 static void
278 xsltFreeExtElement(xsltExtElementPtr ext)
279 {
280     if (ext == NULL)
281         return;
282     xmlFree(ext);
283 }
284 
285 static void
286 xsltFreeExtElementEntry(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
287     xsltFreeExtElement((xsltExtElementPtr) payload);
288 }
289 
290 
291 #ifdef WITH_MODULES
292 typedef void (*exsltRegisterFunction) (void);
293 
294 #ifndef PATH_MAX
295 #define PATH_MAX 4096
296 #endif
297 
298 /**
299  * xsltExtModuleRegisterDynamic:
300  * @URI:  the function or element namespace URI
301  *
302  * Dynamically loads an extension plugin when available.
303  *
304  * The plugin name is derived from the URI by removing the
305  * initial protocol designation, e.g. "http://", then converting
306  * the characters ".", "-", "/", and "\" into "_", the removing
307  * any trailing "/", then concatenating LIBXML_MODULE_EXTENSION.
308  *
309  * Plugins are loaded from the directory specified by the
310  * environment variable LIBXSLT_PLUGINS_PATH, or if NULL,
311  * by LIBXSLT_DEFAULT_PLUGINS_PATH() which is determined at
312  * compile time.
313  *
314  * Returns 0 if successful, -1 in case of error.
315  */
316 
317 static int
318 xsltExtModuleRegisterDynamic(const xmlChar * URI)
319 {
320 
321     xmlModulePtr m;
322     exsltRegisterFunction regfunc;
323     xmlChar *ext_name;
324     char module_filename[PATH_MAX];
325     const xmlChar *ext_directory = NULL;
326     const xmlChar *protocol = NULL;
327     xmlChar *i, *regfunc_name;
328     void *vregfunc;
329     int rc;
330 
331     /* check for bad inputs */
332     if (URI == NULL)
333         return (-1);
334 
335     if (NULL == xsltModuleHash) {
336         xsltModuleHash = xmlHashCreate(5);
337         if (xsltModuleHash == NULL)
338             return (-1);
339     }
340 
341     xmlMutexLock(xsltExtMutex);
342 
343     /* have we attempted to register this module already? */
344     if (xmlHashLookup(xsltModuleHash, URI) != NULL) {
345         xmlMutexUnlock(xsltExtMutex);
346         return (-1);
347     }
348     xmlMutexUnlock(xsltExtMutex);
349 
350     /* transform extension namespace into a module name */
351     protocol = xmlStrstr(URI, BAD_CAST "://");
352     if (protocol == NULL) {
353         ext_name = xmlStrdup(URI);
354     } else {
355         ext_name = xmlStrdup(protocol + 3);
356     }
357     if (ext_name == NULL) {
358         return (-1);
359     }
360 
361     i = ext_name;
362     while ('\0' != *i) {
363         if (('/' == *i) || ('\\' == *i) || ('.' == *i) || ('-' == *i))
364             *i = '_';
365         i++;
366     }
367 
368     /* Strip underscores from end of string. */
369     while (i > ext_name && *(i - 1) == '_') {
370         i--;
371         *i = '\0';
372     }
373 
374     /* determine module directory */
375     ext_directory = (xmlChar *) getenv("LIBXSLT_PLUGINS_PATH");
376 
377     if (NULL == ext_directory) {
378         ext_directory = BAD_CAST LIBXSLT_DEFAULT_PLUGINS_PATH();
379 	if (NULL == ext_directory)
380 	  return (-1);
381     }
382 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
383     else
384       xsltGenericDebug(xsltGenericDebugContext,
385 		       "LIBXSLT_PLUGINS_PATH is %s\n", ext_directory);
386 #endif
387 
388     /* build the module filename, and confirm the module exists */
389     xmlStrPrintf((xmlChar *) module_filename, sizeof(module_filename),
390                  "%s/%s%s", 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
458 static int
459 xsltExtModuleRegisterDynamic(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  */
478 void
479 xsltFreeExts(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  */
502 int
503 xsltRegisterExtPrefix(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  */
586 int
587 xsltRegisterExtFunction(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  */
620 int
621 xsltRegisterExtElement(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  */
641 void
642 xsltFreeCtxtExts(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  */
662 static xsltExtDataPtr
663 xsltStyleInitializeStylesheetModule(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  */
755 void *
756 xsltStyleGetExtData(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  */
822 void *
823 xsltStyleStylesheetLevelGetExtData(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  */
861 void *
862 xsltGetExtData(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 
922 typedef struct _xsltInitExtCtxt xsltInitExtCtxt;
923 struct _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  */
936 static void
937 xsltInitCtxtExt(void *payload, void *data, const xmlChar * URI)
938 {
939     xsltExtDataPtr styleData = (xsltExtDataPtr) payload;
940     xsltInitExtCtxt *ctxt = (xsltInitExtCtxt *) data;
941     xsltExtModulePtr module;
942     xsltExtDataPtr ctxtData;
943     void *extData;
944 
945     if ((styleData == NULL) || (ctxt == NULL) || (URI == NULL) ||
946         (ctxt->ret == -1)) {
947 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
948         xsltGenericDebug(xsltGenericDebugContext,
949                          "xsltInitCtxtExt: NULL param or error\n");
950 #endif
951         return;
952     }
953     module = styleData->extModule;
954     if ((module == NULL) || (module->initFunc == NULL)) {
955 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
956         xsltGenericDebug(xsltGenericDebugContext,
957                          "xsltInitCtxtExt: no module or no initFunc\n");
958 #endif
959         return;
960     }
961 
962     ctxtData = (xsltExtDataPtr) xmlHashLookup(ctxt->ctxt->extInfos, URI);
963     if (ctxtData != NULL) {
964 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
965         xsltGenericDebug(xsltGenericDebugContext,
966                          "xsltInitCtxtExt: already initialized\n");
967 #endif
968         return;
969     }
970 
971     extData = module->initFunc(ctxt->ctxt, URI);
972     if (extData == NULL) {
973 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
974         xsltGenericDebug(xsltGenericDebugContext,
975                          "xsltInitCtxtExt: no extData\n");
976 #endif
977     }
978     ctxtData = xsltNewExtData(module, extData);
979     if (ctxtData == NULL) {
980         ctxt->ret = -1;
981         return;
982     }
983 
984     if (ctxt->ctxt->extInfos == NULL)
985         ctxt->ctxt->extInfos = xmlHashCreate(10);
986     if (ctxt->ctxt->extInfos == NULL) {
987         ctxt->ret = -1;
988         return;
989     }
990 
991     if (xmlHashAddEntry(ctxt->ctxt->extInfos, URI, ctxtData) < 0) {
992         xsltGenericError(xsltGenericErrorContext,
993                          "Failed to register module data: %s\n", URI);
994         if (module->shutdownFunc)
995             module->shutdownFunc(ctxt->ctxt, URI, extData);
996         xsltFreeExtData(ctxtData);
997         ctxt->ret = -1;
998         return;
999     }
1000 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
1001     xsltGenericDebug(xsltGenericDebugContext, "Registered module %s\n",
1002                      URI);
1003 #endif
1004     ctxt->ret++;
1005 }
1006 
1007 /**
1008  * xsltInitCtxtExts:
1009  * @ctxt: an XSLT transformation context
1010  *
1011  * Initialize the set of modules with registered stylesheet data
1012  *
1013  * Returns the number of modules initialized or -1 in case of error
1014  */
1015 int
1016 xsltInitCtxtExts(xsltTransformContextPtr ctxt)
1017 {
1018     xsltStylesheetPtr style;
1019     xsltInitExtCtxt ctx;
1020 
1021     if (ctxt == NULL)
1022         return (-1);
1023 
1024     style = ctxt->style;
1025     if (style == NULL)
1026         return (-1);
1027 
1028     ctx.ctxt = ctxt;
1029     ctx.ret = 0;
1030 
1031     while (style != NULL) {
1032         if (style->extInfos != NULL) {
1033             xmlHashScan(style->extInfos, 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  */
1054 static void
1055 xsltShutdownCtxtExt(void *payload, void *vctxt, const xmlChar * URI)
1056 {
1057     xsltExtDataPtr data = (xsltExtDataPtr) payload;
1058     xsltTransformContextPtr ctxt = (xsltTransformContextPtr) vctxt;
1059     xsltExtModulePtr module;
1060 
1061     if ((data == NULL) || (ctxt == NULL) || (URI == NULL))
1062         return;
1063     module = data->extModule;
1064     if ((module == NULL) || (module->shutdownFunc == NULL))
1065         return;
1066 
1067 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
1068     xsltGenericDebug(xsltGenericDebugContext,
1069                      "Shutting down module : %s\n", URI);
1070 #endif
1071     module->shutdownFunc(ctxt, URI, data->extData);
1072 }
1073 
1074 /**
1075  * xsltShutdownCtxtExts:
1076  * @ctxt: an XSLT transformation context
1077  *
1078  * Shutdown the set of modules loaded
1079  */
1080 void
1081 xsltShutdownCtxtExts(xsltTransformContextPtr ctxt)
1082 {
1083     if (ctxt == NULL)
1084         return;
1085     if (ctxt->extInfos == NULL)
1086         return;
1087     xmlHashScan(ctxt->extInfos, xsltShutdownCtxtExt, ctxt);
1088     xmlHashFree(ctxt->extInfos, xsltFreeExtDataEntry);
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  */
1100 static void
1101 xsltShutdownExt(void *payload, void *vctxt, const xmlChar * URI)
1102 {
1103     xsltExtDataPtr data = (xsltExtDataPtr) payload;
1104     xsltStylesheetPtr style = (xsltStylesheetPtr) vctxt;
1105     xsltExtModulePtr module;
1106 
1107     if ((data == NULL) || (style == NULL) || (URI == NULL))
1108         return;
1109     module = data->extModule;
1110     if ((module == NULL) || (module->styleShutdownFunc == NULL))
1111         return;
1112 
1113 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
1114     xsltGenericDebug(xsltGenericDebugContext,
1115                      "Shutting down module : %s\n", URI);
1116 #endif
1117     module->styleShutdownFunc(style, URI, data->extData);
1118     /*
1119     * Don't remove the entry from the hash table here, since
1120     * this will produce segfaults - this fixes bug #340624.
1121     *
1122     * xmlHashRemoveEntry(style->extInfos, URI, xsltFreeExtDataEntry);
1123     */
1124 }
1125 
1126 /**
1127  * xsltShutdownExts:
1128  * @style: an XSLT stylesheet
1129  *
1130  * Shutdown the set of modules loaded
1131  */
1132 void
1133 xsltShutdownExts(xsltStylesheetPtr style)
1134 {
1135     if (style == NULL)
1136         return;
1137     if (style->extInfos == NULL)
1138         return;
1139     xmlHashScan(style->extInfos, xsltShutdownExt, style);
1140     xmlHashFree(style->extInfos, xsltFreeExtDataEntry);
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  */
1157 int
1158 xsltCheckExtPrefix(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  */
1217 int
1218 xsltCheckExtURI(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  */
1247 int
1248 xsltRegisterExtModuleFull(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 
1284 done:
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  */
1299 int
1300 xsltRegisterExtModule(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  */
1316 int
1317 xsltUnregisterExtModule(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, xsltFreeExtModuleEntry);
1329 
1330     xmlMutexUnlock(xsltExtMutex);
1331 
1332     return (ret);
1333 }
1334 
1335 /**
1336  * xsltUnregisterAllExtModules:
1337  *
1338  * Unregister all the XSLT extension module from the library.
1339  */
1340 static void
1341 xsltUnregisterAllExtModules(void)
1342 {
1343     if (xsltExtensionsHash == NULL)
1344         return;
1345 
1346     xmlMutexLock(xsltExtMutex);
1347 
1348     xmlHashFree(xsltExtensionsHash, xsltFreeExtModuleEntry);
1349     xsltExtensionsHash = NULL;
1350 
1351     xmlMutexUnlock(xsltExtMutex);
1352 }
1353 
1354 /**
1355  * xsltXPathGetTransformContext:
1356  * @ctxt:  an XPath transformation context
1357  *
1358  * Provides the XSLT transformation context from the XPath transformation
1359  * context. This is useful when an XPath function in the extension module
1360  * is called by the XPath interpreter and that the XSLT context is needed
1361  * for example to retrieve the associated data pertaining to this XSLT
1362  * transformation.
1363  *
1364  * Returns the XSLT transformation context or NULL in case of error.
1365  */
1366 xsltTransformContextPtr
1367 xsltXPathGetTransformContext(xmlXPathParserContextPtr ctxt)
1368 {
1369     if ((ctxt == NULL) || (ctxt->context == NULL))
1370         return (NULL);
1371     return (ctxt->context->extra);
1372 }
1373 
1374 /**
1375  * xsltRegisterExtModuleFunction:
1376  * @name:  the function name
1377  * @URI:  the function namespace URI
1378  * @function:  the function callback
1379  *
1380  * Registers an extension module function.
1381  *
1382  * Returns 0 if successful, -1 in case of error.
1383  */
1384 int
1385 xsltRegisterExtModuleFunction(const xmlChar * name, const xmlChar * URI,
1386                               xmlXPathFunction function)
1387 {
1388     if ((name == NULL) || (URI == NULL) || (function == NULL))
1389         return (-1);
1390 
1391     if (xsltFunctionsHash == NULL)
1392         xsltFunctionsHash = xmlHashCreate(10);
1393     if (xsltFunctionsHash == NULL)
1394         return (-1);
1395 
1396     xmlMutexLock(xsltExtMutex);
1397 
1398     xmlHashUpdateEntry2(xsltFunctionsHash, name, URI,
1399                         XML_CAST_FPTR(function), NULL);
1400 
1401     xmlMutexUnlock(xsltExtMutex);
1402 
1403     return (0);
1404 }
1405 
1406 /**
1407  * xsltExtModuleFunctionLookup:
1408  * @name:  the function name
1409  * @URI:  the function namespace URI
1410  *
1411  * Looks up an extension module function
1412  *
1413  * Returns the function if found, NULL otherwise.
1414  */
1415 xmlXPathFunction
1416 xsltExtModuleFunctionLookup(const xmlChar * name, const xmlChar * URI)
1417 {
1418     xmlXPathFunction ret;
1419 
1420     if ((xsltFunctionsHash == NULL) || (name == NULL) || (URI == NULL))
1421         return (NULL);
1422 
1423     xmlMutexLock(xsltExtMutex);
1424 
1425     XML_CAST_FPTR(ret) = xmlHashLookup2(xsltFunctionsHash, name, URI);
1426 
1427     xmlMutexUnlock(xsltExtMutex);
1428 
1429     /* if lookup fails, attempt a dynamic load on supported platforms */
1430     if (NULL == ret) {
1431         if (!xsltExtModuleRegisterDynamic(URI)) {
1432             xmlMutexLock(xsltExtMutex);
1433 
1434             XML_CAST_FPTR(ret) =
1435                 xmlHashLookup2(xsltFunctionsHash, name, URI);
1436 
1437             xmlMutexUnlock(xsltExtMutex);
1438         }
1439     }
1440 
1441     return ret;
1442 }
1443 
1444 /**
1445  * xsltUnregisterExtModuleFunction:
1446  * @name:  the function name
1447  * @URI:  the function namespace URI
1448  *
1449  * Unregisters an extension module function
1450  *
1451  * Returns 0 if successful, -1 in case of error.
1452  */
1453 int
1454 xsltUnregisterExtModuleFunction(const xmlChar * name, const xmlChar * URI)
1455 {
1456     int ret;
1457 
1458     if ((xsltFunctionsHash == NULL) || (name == NULL) || (URI == NULL))
1459         return (-1);
1460 
1461     xmlMutexLock(xsltExtMutex);
1462 
1463     ret = xmlHashRemoveEntry2(xsltFunctionsHash, name, URI, NULL);
1464 
1465     xmlMutexUnlock(xsltExtMutex);
1466 
1467     return(ret);
1468 }
1469 
1470 /**
1471  * xsltUnregisterAllExtModuleFunction:
1472  *
1473  * Unregisters all extension module function
1474  */
1475 static void
1476 xsltUnregisterAllExtModuleFunction(void)
1477 {
1478     xmlMutexLock(xsltExtMutex);
1479 
1480     xmlHashFree(xsltFunctionsHash, NULL);
1481     xsltFunctionsHash = NULL;
1482 
1483     xmlMutexUnlock(xsltExtMutex);
1484 }
1485 
1486 
1487 static void
1488 xsltFreeElemPreComp(xsltElemPreCompPtr comp) {
1489     xmlFree(comp);
1490 }
1491 
1492 /**
1493  * xsltNewElemPreComp:
1494  * @style:  the XSLT stylesheet
1495  * @inst:  the element node
1496  * @function: the transform function
1497  *
1498  * Creates and initializes an #xsltElemPreComp
1499  *
1500  * Returns the new and initialized #xsltElemPreComp
1501  */
1502 xsltElemPreCompPtr
1503 xsltNewElemPreComp(xsltStylesheetPtr style, xmlNodePtr inst,
1504                    xsltTransformFunction function)
1505 {
1506     xsltElemPreCompPtr cur;
1507 
1508     cur = (xsltElemPreCompPtr) xmlMalloc(sizeof(xsltElemPreComp));
1509     if (cur == NULL) {
1510         xsltTransformError(NULL, style, NULL,
1511                            "xsltNewExtElement : malloc failed\n");
1512         return (NULL);
1513     }
1514     memset(cur, 0, sizeof(xsltElemPreComp));
1515 
1516     xsltInitElemPreComp(cur, style, inst, function, xsltFreeElemPreComp);
1517 
1518     return (cur);
1519 }
1520 
1521 /**
1522  * xsltInitElemPreComp:
1523  * @comp:  an #xsltElemPreComp (or generally a derived structure)
1524  * @style:  the XSLT stylesheet
1525  * @inst:  the element node
1526  * @function:  the transform function
1527  * @freeFunc:  the @comp deallocator
1528  *
1529  * Initializes an existing #xsltElemPreComp structure. This is usefull
1530  * when extending an #xsltElemPreComp to store precomputed data.
1531  * This function MUST be called on any extension element precomputed
1532  * data struct.
1533  */
1534 void
1535 xsltInitElemPreComp(xsltElemPreCompPtr comp, xsltStylesheetPtr style,
1536                     xmlNodePtr inst, xsltTransformFunction function,
1537                     xsltElemPreCompDeallocator freeFunc)
1538 {
1539     comp->type = XSLT_FUNC_EXTENSION;
1540     comp->func = function;
1541     comp->inst = inst;
1542     comp->free = freeFunc;
1543 
1544     comp->next = style->preComps;
1545     style->preComps = comp;
1546 }
1547 
1548 /**
1549  * xsltPreComputeExtModuleElement:
1550  * @style:  the stylesheet
1551  * @inst:  the element node
1552  *
1553  * Precomputes an extension module element
1554  *
1555  * Returns the precomputed data
1556  */
1557 xsltElemPreCompPtr
1558 xsltPreComputeExtModuleElement(xsltStylesheetPtr style, xmlNodePtr inst)
1559 {
1560     xsltExtElementPtr ext;
1561     xsltElemPreCompPtr comp = NULL;
1562 
1563     if ((style == NULL) || (inst == NULL) ||
1564         (inst->type != XML_ELEMENT_NODE) || (inst->ns == NULL))
1565         return (NULL);
1566 
1567     xmlMutexLock(xsltExtMutex);
1568 
1569     ext = (xsltExtElementPtr)
1570         xmlHashLookup2(xsltElementsHash, inst->name, inst->ns->href);
1571 
1572     xmlMutexUnlock(xsltExtMutex);
1573 
1574     /*
1575     * EXT TODO: Now what?
1576     */
1577     if (ext == NULL)
1578         return (NULL);
1579 
1580     if (ext->precomp != NULL) {
1581 	/*
1582 	* REVISIT TODO: Check if the text below is correct.
1583 	* This will return a xsltElemPreComp structure or NULL.
1584 	* 1) If the the author of the extension needs a
1585 	*  custom structure to hold the specific values of
1586 	*  this extension, he will derive a structure based on
1587 	*  xsltElemPreComp; thus we obviously *cannot* refactor
1588 	*  the xsltElemPreComp structure, since all already derived
1589 	*  user-defined strucures will break.
1590 	*  Example: For the extension xsl:document,
1591 	*   in xsltDocumentComp() (preproc.c), the structure
1592 	*   xsltStyleItemDocument is allocated, filled with
1593 	*   specific values and returned.
1594 	* 2) If the author needs no values to be stored in
1595 	*  this structure, then he'll return NULL;
1596 	*/
1597         comp = ext->precomp(style, inst, ext->transform);
1598     }
1599     if (comp == NULL) {
1600 	/*
1601 	* Default creation of a xsltElemPreComp structure, if
1602 	* the author of this extension did not create a custom
1603 	* structure.
1604 	*/
1605         comp = xsltNewElemPreComp(style, inst, ext->transform);
1606     }
1607 
1608     return (comp);
1609 }
1610 
1611 /**
1612  * xsltRegisterExtModuleElement:
1613  * @name:  the element name
1614  * @URI:  the element namespace URI
1615  * @precomp:  the pre-computation callback
1616  * @transform:  the transformation callback
1617  *
1618  * Registers an extension module element.
1619  *
1620  * Returns 0 if successful, -1 in case of error.
1621  */
1622 int
1623 xsltRegisterExtModuleElement(const xmlChar * name, const xmlChar * URI,
1624                              xsltPreComputeFunction precomp,
1625                              xsltTransformFunction transform)
1626 {
1627     int ret = 0;
1628 
1629     xsltExtElementPtr ext;
1630 
1631     if ((name == NULL) || (URI == NULL) || (transform == NULL))
1632         return (-1);
1633 
1634     if (xsltElementsHash == NULL)
1635         xsltElementsHash = xmlHashCreate(10);
1636     if (xsltElementsHash == NULL)
1637         return (-1);
1638 
1639     xmlMutexLock(xsltExtMutex);
1640 
1641     ext = xsltNewExtElement(precomp, transform);
1642     if (ext == NULL) {
1643         ret = -1;
1644         goto done;
1645     }
1646 
1647     xmlHashUpdateEntry2(xsltElementsHash, name, URI, (void *) ext,
1648                         xsltFreeExtElementEntry);
1649 
1650 done:
1651     xmlMutexUnlock(xsltExtMutex);
1652 
1653     return (ret);
1654 }
1655 
1656 /**
1657  * xsltExtElementLookup:
1658  * @ctxt:  an XSLT process context
1659  * @name:  the element name
1660  * @URI:  the element namespace URI
1661  *
1662  * Looks up an extension element. @ctxt can be NULL to search only in
1663  * module elements.
1664  *
1665  * Returns the element callback or NULL if not found
1666  */
1667 xsltTransformFunction
1668 xsltExtElementLookup(xsltTransformContextPtr ctxt,
1669                      const xmlChar * name, const xmlChar * URI)
1670 {
1671     xsltTransformFunction ret;
1672 
1673     if ((name == NULL) || (URI == NULL))
1674         return (NULL);
1675 
1676     if ((ctxt != NULL) && (ctxt->extElements != NULL)) {
1677         XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->extElements, name, URI);
1678         if (ret != NULL) {
1679             return(ret);
1680         }
1681     }
1682 
1683     ret = xsltExtModuleElementLookup(name, URI);
1684 
1685     return (ret);
1686 }
1687 
1688 /**
1689  * xsltExtModuleElementLookup:
1690  * @name:  the element name
1691  * @URI:  the element namespace URI
1692  *
1693  * Looks up an extension module element
1694  *
1695  * Returns the callback function if found, NULL otherwise.
1696  */
1697 xsltTransformFunction
1698 xsltExtModuleElementLookup(const xmlChar * name, const xmlChar * URI)
1699 {
1700     xsltExtElementPtr ext;
1701 
1702     if ((xsltElementsHash == NULL) || (name == NULL) || (URI == NULL))
1703         return (NULL);
1704 
1705     xmlMutexLock(xsltExtMutex);
1706 
1707     ext = (xsltExtElementPtr) xmlHashLookup2(xsltElementsHash, name, URI);
1708 
1709     xmlMutexUnlock(xsltExtMutex);
1710 
1711     /*
1712      * if function lookup fails, attempt a dynamic load on
1713      * supported platforms
1714      */
1715     if (NULL == ext) {
1716         if (!xsltExtModuleRegisterDynamic(URI)) {
1717             xmlMutexLock(xsltExtMutex);
1718 
1719             ext = (xsltExtElementPtr)
1720 	          xmlHashLookup2(xsltElementsHash, name, URI);
1721 
1722             xmlMutexUnlock(xsltExtMutex);
1723         }
1724     }
1725 
1726     if (ext == NULL)
1727         return (NULL);
1728     return (ext->transform);
1729 }
1730 
1731 /**
1732  * xsltExtModuleElementPreComputeLookup:
1733  * @name:  the element name
1734  * @URI:  the element namespace URI
1735  *
1736  * Looks up an extension module element pre-computation function
1737  *
1738  * Returns the callback function if found, NULL otherwise.
1739  */
1740 xsltPreComputeFunction
1741 xsltExtModuleElementPreComputeLookup(const xmlChar * name,
1742                                      const xmlChar * URI)
1743 {
1744     xsltExtElementPtr ext;
1745 
1746     if ((xsltElementsHash == NULL) || (name == NULL) || (URI == NULL))
1747         return (NULL);
1748 
1749     xmlMutexLock(xsltExtMutex);
1750 
1751     ext = (xsltExtElementPtr) xmlHashLookup2(xsltElementsHash, name, URI);
1752 
1753     xmlMutexUnlock(xsltExtMutex);
1754 
1755     if (ext == NULL) {
1756         if (!xsltExtModuleRegisterDynamic(URI)) {
1757             xmlMutexLock(xsltExtMutex);
1758 
1759             ext = (xsltExtElementPtr)
1760 	          xmlHashLookup2(xsltElementsHash, name, URI);
1761 
1762             xmlMutexUnlock(xsltExtMutex);
1763         }
1764     }
1765 
1766     if (ext == NULL)
1767         return (NULL);
1768     return (ext->precomp);
1769 }
1770 
1771 /**
1772  * xsltUnregisterExtModuleElement:
1773  * @name:  the element name
1774  * @URI:  the element namespace URI
1775  *
1776  * Unregisters an extension module element
1777  *
1778  * Returns 0 if successful, -1 in case of error.
1779  */
1780 int
1781 xsltUnregisterExtModuleElement(const xmlChar * name, const xmlChar * URI)
1782 {
1783     int ret;
1784 
1785     if ((xsltElementsHash == NULL) || (name == NULL) || (URI == NULL))
1786         return (-1);
1787 
1788     xmlMutexLock(xsltExtMutex);
1789 
1790     ret = xmlHashRemoveEntry2(xsltElementsHash, name, URI,
1791                               xsltFreeExtElementEntry);
1792 
1793     xmlMutexUnlock(xsltExtMutex);
1794 
1795     return(ret);
1796 }
1797 
1798 /**
1799  * xsltUnregisterAllExtModuleElement:
1800  *
1801  * Unregisters all extension module element
1802  */
1803 static void
1804 xsltUnregisterAllExtModuleElement(void)
1805 {
1806     xmlMutexLock(xsltExtMutex);
1807 
1808     xmlHashFree(xsltElementsHash, xsltFreeExtElementEntry);
1809     xsltElementsHash = NULL;
1810 
1811     xmlMutexUnlock(xsltExtMutex);
1812 }
1813 
1814 /**
1815  * xsltRegisterExtModuleTopLevel:
1816  * @name:  the top-level element name
1817  * @URI:  the top-level element namespace URI
1818  * @function:  the top-level element callback
1819  *
1820  * Registers an extension module top-level element.
1821  *
1822  * Returns 0 if successful, -1 in case of error.
1823  */
1824 int
1825 xsltRegisterExtModuleTopLevel(const xmlChar * name, const xmlChar * URI,
1826                               xsltTopLevelFunction function)
1827 {
1828     if ((name == NULL) || (URI == NULL) || (function == NULL))
1829         return (-1);
1830 
1831     if (xsltTopLevelsHash == NULL)
1832         xsltTopLevelsHash = xmlHashCreate(10);
1833     if (xsltTopLevelsHash == NULL)
1834         return (-1);
1835 
1836     xmlMutexLock(xsltExtMutex);
1837 
1838     xmlHashUpdateEntry2(xsltTopLevelsHash, name, URI,
1839                         XML_CAST_FPTR(function), NULL);
1840 
1841     xmlMutexUnlock(xsltExtMutex);
1842 
1843     return (0);
1844 }
1845 
1846 /**
1847  * xsltExtModuleTopLevelLookup:
1848  * @name:  the top-level element name
1849  * @URI:  the top-level element namespace URI
1850  *
1851  * Looks up an extension module top-level element
1852  *
1853  * Returns the callback function if found, NULL otherwise.
1854  */
1855 xsltTopLevelFunction
1856 xsltExtModuleTopLevelLookup(const xmlChar * name, const xmlChar * URI)
1857 {
1858     xsltTopLevelFunction ret;
1859 
1860     if ((xsltTopLevelsHash == NULL) || (name == NULL) || (URI == NULL))
1861         return (NULL);
1862 
1863     xmlMutexLock(xsltExtMutex);
1864 
1865     XML_CAST_FPTR(ret) = xmlHashLookup2(xsltTopLevelsHash, name, URI);
1866 
1867     xmlMutexUnlock(xsltExtMutex);
1868 
1869     /* if lookup fails, attempt a dynamic load on supported platforms */
1870     if (NULL == ret) {
1871         if (!xsltExtModuleRegisterDynamic(URI)) {
1872             xmlMutexLock(xsltExtMutex);
1873 
1874             XML_CAST_FPTR(ret) = xmlHashLookup2(xsltTopLevelsHash, name, URI);
1875 
1876             xmlMutexUnlock(xsltExtMutex);
1877         }
1878     }
1879 
1880     return (ret);
1881 }
1882 
1883 /**
1884  * xsltUnregisterExtModuleTopLevel:
1885  * @name:  the top-level element name
1886  * @URI:  the top-level element namespace URI
1887  *
1888  * Unregisters an extension module top-level element
1889  *
1890  * Returns 0 if successful, -1 in case of error.
1891  */
1892 int
1893 xsltUnregisterExtModuleTopLevel(const xmlChar * name, const xmlChar * URI)
1894 {
1895     int ret;
1896 
1897     if ((xsltTopLevelsHash == NULL) || (name == NULL) || (URI == NULL))
1898         return (-1);
1899 
1900     xmlMutexLock(xsltExtMutex);
1901 
1902     ret = xmlHashRemoveEntry2(xsltTopLevelsHash, name, URI, NULL);
1903 
1904     xmlMutexUnlock(xsltExtMutex);
1905 
1906     return(ret);
1907 }
1908 
1909 /**
1910  * xsltUnregisterAllExtModuleTopLevel:
1911  *
1912  * Unregisters all extension module function
1913  */
1914 static void
1915 xsltUnregisterAllExtModuleTopLevel(void)
1916 {
1917     xmlMutexLock(xsltExtMutex);
1918 
1919     xmlHashFree(xsltTopLevelsHash, NULL);
1920     xsltTopLevelsHash = NULL;
1921 
1922     xmlMutexUnlock(xsltExtMutex);
1923 }
1924 
1925 /**
1926  * xsltGetExtInfo:
1927  * @style:  pointer to a stylesheet
1928  * @URI:    the namespace URI desired
1929  *
1930  * looks up URI in extInfos of the stylesheet
1931  *
1932  * returns a pointer to the hash table if found, else NULL
1933  */
1934 xmlHashTablePtr
1935 xsltGetExtInfo(xsltStylesheetPtr style, const xmlChar * URI)
1936 {
1937     xsltExtDataPtr data;
1938 
1939     /*
1940     * TODO: Why do we have a return type of xmlHashTablePtr?
1941     *   Is the user-allocated data for extension modules expected
1942     *   to be a xmlHashTablePtr only? Or is this intended for
1943     *   the EXSLT module only?
1944     */
1945 
1946     if (style != NULL && style->extInfos != NULL) {
1947         data = xmlHashLookup(style->extInfos, URI);
1948         if (data != NULL && data->extData != NULL)
1949             return data->extData;
1950     }
1951     return NULL;
1952 }
1953 
1954 /************************************************************************
1955  *									*
1956  *		Test module http://xmlsoft.org/XSLT/			*
1957  *									*
1958  ************************************************************************/
1959 
1960 /************************************************************************
1961  *									*
1962  *		Test of the extension module API			*
1963  *									*
1964  ************************************************************************/
1965 
1966 static xmlChar *testData = NULL;
1967 static xmlChar *testStyleData = NULL;
1968 
1969 /**
1970  * xsltExtFunctionTest:
1971  * @ctxt:  the XPath Parser context
1972  * @nargs:  the number of arguments
1973  *
1974  * function libxslt:test() for testing the extensions support.
1975  */
1976 static void
1977 xsltExtFunctionTest(xmlXPathParserContextPtr ctxt,
1978                     int nargs ATTRIBUTE_UNUSED)
1979 {
1980     xsltTransformContextPtr tctxt;
1981     void *data = NULL;
1982 
1983     tctxt = xsltXPathGetTransformContext(ctxt);
1984 
1985     if (testData == NULL) {
1986         xsltGenericDebug(xsltGenericDebugContext,
1987                          "xsltExtFunctionTest: not initialized,"
1988                          " calling xsltGetExtData\n");
1989         data = xsltGetExtData(tctxt, (const xmlChar *) XSLT_DEFAULT_URL);
1990         if (data == NULL) {
1991             xsltTransformError(tctxt, NULL, NULL,
1992                                "xsltExtElementTest: not initialized\n");
1993             return;
1994         }
1995     }
1996     if (tctxt == NULL) {
1997         xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
1998                            "xsltExtFunctionTest: failed to get the transformation context\n");
1999         return;
2000     }
2001     if (data == NULL)
2002         data = xsltGetExtData(tctxt, (const xmlChar *) XSLT_DEFAULT_URL);
2003     if (data == NULL) {
2004         xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
2005                            "xsltExtFunctionTest: failed to get module data\n");
2006         return;
2007     }
2008     if (data != testData) {
2009         xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
2010                            "xsltExtFunctionTest: got wrong module data\n");
2011         return;
2012     }
2013 #ifdef WITH_XSLT_DEBUG_FUNCTION
2014     xsltGenericDebug(xsltGenericDebugContext,
2015                      "libxslt:test() called with %d args\n", nargs);
2016 #endif
2017 }
2018 
2019 /**
2020  * xsltExtElementPreCompTest:
2021  * @style:  the stylesheet
2022  * @inst:  the instruction in the stylesheet
2023  *
2024  * Process a libxslt:test node
2025  */
2026 static xsltElemPreCompPtr
2027 xsltExtElementPreCompTest(xsltStylesheetPtr style, xmlNodePtr inst,
2028                           xsltTransformFunction function)
2029 {
2030     xsltElemPreCompPtr ret;
2031 
2032     if (style == NULL) {
2033         xsltTransformError(NULL, NULL, inst,
2034                            "xsltExtElementTest: no transformation context\n");
2035         return (NULL);
2036     }
2037     if (testStyleData == NULL) {
2038         xsltGenericDebug(xsltGenericDebugContext,
2039                          "xsltExtElementPreCompTest: not initialized,"
2040                          " calling xsltStyleGetExtData\n");
2041         xsltStyleGetExtData(style, (const xmlChar *) XSLT_DEFAULT_URL);
2042         if (testStyleData == NULL) {
2043             xsltTransformError(NULL, style, inst,
2044                                "xsltExtElementPreCompTest: not initialized\n");
2045             if (style != NULL)
2046                 style->errors++;
2047             return (NULL);
2048         }
2049     }
2050     if (inst == NULL) {
2051         xsltTransformError(NULL, style, inst,
2052                            "xsltExtElementPreCompTest: no instruction\n");
2053         if (style != NULL)
2054             style->errors++;
2055         return (NULL);
2056     }
2057     ret = xsltNewElemPreComp(style, inst, function);
2058     return (ret);
2059 }
2060 
2061 /**
2062  * xsltExtElementTest:
2063  * @ctxt:  an XSLT processing context
2064  * @node:  The current node
2065  * @inst:  the instruction in the stylesheet
2066  * @comp:  precomputed information
2067  *
2068  * Process a libxslt:test node
2069  */
2070 static void
2071 xsltExtElementTest(xsltTransformContextPtr ctxt, xmlNodePtr node,
2072                    xmlNodePtr inst,
2073                    xsltElemPreCompPtr comp ATTRIBUTE_UNUSED)
2074 {
2075     xmlNodePtr commentNode;
2076 
2077     if (testData == NULL) {
2078         xsltGenericDebug(xsltGenericDebugContext,
2079                          "xsltExtElementTest: not initialized,"
2080                          " calling xsltGetExtData\n");
2081         xsltGetExtData(ctxt, (const xmlChar *) XSLT_DEFAULT_URL);
2082         if (testData == NULL) {
2083             xsltTransformError(ctxt, NULL, inst,
2084                                "xsltExtElementTest: not initialized\n");
2085             return;
2086         }
2087     }
2088     if (ctxt == NULL) {
2089         xsltTransformError(ctxt, NULL, inst,
2090                            "xsltExtElementTest: no transformation context\n");
2091         return;
2092     }
2093     if (node == NULL) {
2094         xsltTransformError(ctxt, NULL, inst,
2095                            "xsltExtElementTest: no current node\n");
2096         return;
2097     }
2098     if (inst == NULL) {
2099         xsltTransformError(ctxt, NULL, inst,
2100                            "xsltExtElementTest: no instruction\n");
2101         return;
2102     }
2103     if (ctxt->insert == NULL) {
2104         xsltTransformError(ctxt, NULL, inst,
2105                            "xsltExtElementTest: no insertion point\n");
2106         return;
2107     }
2108     commentNode = xmlNewComment((const xmlChar *)
2109                                 "libxslt:test element test worked");
2110     xmlAddChild(ctxt->insert, commentNode);
2111 }
2112 
2113 /**
2114  * xsltExtInitTest:
2115  * @ctxt:  an XSLT transformation context
2116  * @URI:  the namespace URI for the extension
2117  *
2118  * A function called at initialization time of an XSLT extension module
2119  *
2120  * Returns a pointer to the module specific data for this transformation
2121  */
2122 static void *
2123 xsltExtInitTest(xsltTransformContextPtr ctxt, const xmlChar * URI)
2124 {
2125     if (testStyleData == NULL) {
2126         xsltGenericDebug(xsltGenericErrorContext,
2127                          "xsltExtInitTest: not initialized,"
2128                          " calling xsltStyleGetExtData\n");
2129         testStyleData = xsltStyleGetExtData(ctxt->style, URI);
2130         if (testStyleData == NULL) {
2131             xsltTransformError(ctxt, NULL, NULL,
2132                                "xsltExtInitTest: not initialized\n");
2133             return (NULL);
2134         }
2135     }
2136     if (testData != NULL) {
2137         xsltTransformError(ctxt, NULL, NULL,
2138                            "xsltExtInitTest: already initialized\n");
2139         return (NULL);
2140     }
2141     testData = (void *) "test data";
2142     xsltGenericDebug(xsltGenericDebugContext,
2143                      "Registered test module : %s\n", URI);
2144     return (testData);
2145 }
2146 
2147 
2148 /**
2149  * xsltExtShutdownTest:
2150  * @ctxt:  an XSLT transformation context
2151  * @URI:  the namespace URI for the extension
2152  * @data:  the data associated to this module
2153  *
2154  * A function called at shutdown time of an XSLT extension module
2155  */
2156 static void
2157 xsltExtShutdownTest(xsltTransformContextPtr ctxt,
2158                     const xmlChar * URI, void *data)
2159 {
2160     if (testData == NULL) {
2161         xsltTransformError(ctxt, NULL, NULL,
2162                            "xsltExtShutdownTest: not initialized\n");
2163         return;
2164     }
2165     if (data != testData) {
2166         xsltTransformError(ctxt, NULL, NULL,
2167                            "xsltExtShutdownTest: wrong data\n");
2168     }
2169     testData = NULL;
2170     xsltGenericDebug(xsltGenericDebugContext,
2171                      "Unregistered test module : %s\n", URI);
2172 }
2173 
2174 /**
2175  * xsltExtStyleInitTest:
2176  * @style:  an XSLT stylesheet
2177  * @URI:  the namespace URI for the extension
2178  *
2179  * A function called at initialization time of an XSLT extension module
2180  *
2181  * Returns a pointer to the module specific data for this transformation
2182  */
2183 static void *
2184 xsltExtStyleInitTest(xsltStylesheetPtr style ATTRIBUTE_UNUSED,
2185                      const xmlChar * URI)
2186 {
2187     if (testStyleData != NULL) {
2188         xsltTransformError(NULL, NULL, NULL,
2189                            "xsltExtInitTest: already initialized\n");
2190         return (NULL);
2191     }
2192     testStyleData = (void *) "test data";
2193     xsltGenericDebug(xsltGenericDebugContext,
2194                      "Registered test module : %s\n", URI);
2195     return (testStyleData);
2196 }
2197 
2198 
2199 /**
2200  * xsltExtStyleShutdownTest:
2201  * @style:  an XSLT stylesheet
2202  * @URI:  the namespace URI for the extension
2203  * @data:  the data associated to this module
2204  *
2205  * A function called at shutdown time of an XSLT extension module
2206  */
2207 static void
2208 xsltExtStyleShutdownTest(xsltStylesheetPtr style ATTRIBUTE_UNUSED,
2209                          const xmlChar * URI, void *data)
2210 {
2211     if (testStyleData == NULL) {
2212         xsltGenericError(xsltGenericErrorContext,
2213                          "xsltExtShutdownTest: not initialized\n");
2214         return;
2215     }
2216     if (data != testStyleData) {
2217         xsltTransformError(NULL, NULL, NULL,
2218                            "xsltExtShutdownTest: wrong data\n");
2219     }
2220     testStyleData = NULL;
2221     xsltGenericDebug(xsltGenericDebugContext,
2222                      "Unregistered test module : %s\n", URI);
2223 }
2224 
2225 /**
2226  * xsltRegisterTestModule:
2227  *
2228  * Registers the test module
2229  */
2230 void
2231 xsltRegisterTestModule(void)
2232 {
2233     xsltInitGlobals();
2234     xsltRegisterExtModuleFull((const xmlChar *) XSLT_DEFAULT_URL,
2235                               xsltExtInitTest, xsltExtShutdownTest,
2236                               xsltExtStyleInitTest,
2237                               xsltExtStyleShutdownTest);
2238     xsltRegisterExtModuleFunction((const xmlChar *) "test",
2239                                   (const xmlChar *) XSLT_DEFAULT_URL,
2240                                   xsltExtFunctionTest);
2241     xsltRegisterExtModuleElement((const xmlChar *) "test",
2242                                  (const xmlChar *) XSLT_DEFAULT_URL,
2243                                  xsltExtElementPreCompTest,
2244                                  xsltExtElementTest);
2245 }
2246 
2247 static void
2248 xsltHashScannerModuleFree(void *payload ATTRIBUTE_UNUSED,
2249                           void *data ATTRIBUTE_UNUSED,
2250                           const xmlChar *name ATTRIBUTE_UNUSED)
2251 {
2252 #ifdef WITH_MODULES
2253     xmlModuleClose(payload);
2254 #endif
2255 }
2256 
2257 /**
2258  * xsltInitGlobals:
2259  *
2260  * Initialize the global variables for extensions
2261  */
2262 void
2263 xsltInitGlobals(void)
2264 {
2265     if (xsltExtMutex == NULL) {
2266         xsltExtMutex = xmlNewMutex();
2267     }
2268 }
2269 
2270 /**
2271  * xsltCleanupGlobals:
2272  *
2273  * Unregister all global variables set up by the XSLT library
2274  */
2275 void
2276 xsltCleanupGlobals(void)
2277 {
2278     xsltUnregisterAllExtModules();
2279     xsltUnregisterAllExtModuleFunction();
2280     xsltUnregisterAllExtModuleElement();
2281     xsltUnregisterAllExtModuleTopLevel();
2282 
2283     xmlMutexLock(xsltExtMutex);
2284     /* cleanup dynamic module hash */
2285     if (NULL != xsltModuleHash) {
2286         xmlHashScan(xsltModuleHash, xsltHashScannerModuleFree, 0);
2287         xmlHashFree(xsltModuleHash, NULL);
2288         xsltModuleHash = NULL;
2289     }
2290     xmlMutexUnlock(xsltExtMutex);
2291 
2292     xmlFreeMutex(xsltExtMutex);
2293     xsltExtMutex = NULL;
2294     xsltFreeLocales();
2295     xsltUninit();
2296 }
2297 
2298 static void
2299 xsltDebugDumpExtensionsCallback(void *function ATTRIBUTE_UNUSED,
2300                                 void *data, const xmlChar * name,
2301                                 const xmlChar * URI,
2302                                 const xmlChar * not_used ATTRIBUTE_UNUSED)
2303 {
2304     FILE *output = (FILE *) data;
2305     if (!name || !URI)
2306         return;
2307     fprintf(output, "{%s}%s\n", URI, name);
2308 }
2309 
2310 static void
2311 xsltDebugDumpExtModulesCallback(void *function ATTRIBUTE_UNUSED,
2312                                 void *data, const xmlChar * URI,
2313                                 const xmlChar * not_used ATTRIBUTE_UNUSED,
2314                                 const xmlChar * not_used2 ATTRIBUTE_UNUSED)
2315 {
2316     FILE *output = (FILE *) data;
2317     if (!URI)
2318         return;
2319     fprintf(output, "%s\n", URI);
2320 }
2321 
2322 /**
2323  * xsltDebugDumpExtensions:
2324  * @output:  the FILE * for the output, if NULL stdout is used
2325  *
2326  * Dumps a list of the registered XSLT extension functions and elements
2327  */
2328 void
2329 xsltDebugDumpExtensions(FILE * output)
2330 {
2331     if (output == NULL)
2332         output = stdout;
2333     fprintf(output,
2334             "Registered XSLT Extensions\n--------------------------\n");
2335     if (!xsltFunctionsHash)
2336         fprintf(output, "No registered extension functions\n");
2337     else {
2338         fprintf(output, "Registered Extension Functions:\n");
2339         xmlMutexLock(xsltExtMutex);
2340         xmlHashScanFull(xsltFunctionsHash, xsltDebugDumpExtensionsCallback,
2341                         output);
2342         xmlMutexUnlock(xsltExtMutex);
2343     }
2344     if (!xsltElementsHash)
2345         fprintf(output, "\nNo registered extension elements\n");
2346     else {
2347         fprintf(output, "\nRegistered Extension Elements:\n");
2348         xmlMutexLock(xsltExtMutex);
2349         xmlHashScanFull(xsltElementsHash, xsltDebugDumpExtensionsCallback,
2350                         output);
2351         xmlMutexUnlock(xsltExtMutex);
2352     }
2353     if (!xsltExtensionsHash)
2354         fprintf(output, "\nNo registered extension modules\n");
2355     else {
2356         fprintf(output, "\nRegistered Extension Modules:\n");
2357         xmlMutexLock(xsltExtMutex);
2358         xmlHashScanFull(xsltExtensionsHash, xsltDebugDumpExtModulesCallback,
2359                         output);
2360         xmlMutexUnlock(xsltExtMutex);
2361     }
2362 
2363 }
2364