• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
52 typedef struct _xsltExtDef xsltExtDef;
53 typedef xsltExtDef *xsltExtDefPtr;
54 struct _xsltExtDef {
55     struct _xsltExtDef *next;
56     xmlChar *prefix;
57     xmlChar *URI;
58     void *data;
59 };
60 
61 typedef struct _xsltExtModule xsltExtModule;
62 typedef xsltExtModule *xsltExtModulePtr;
63 struct _xsltExtModule {
64     xsltExtInitFunction initFunc;
65     xsltExtShutdownFunction shutdownFunc;
66     xsltStyleExtInitFunction styleInitFunc;
67     xsltStyleExtShutdownFunction styleShutdownFunc;
68 };
69 
70 typedef struct _xsltExtData xsltExtData;
71 typedef xsltExtData *xsltExtDataPtr;
72 struct _xsltExtData {
73     xsltExtModulePtr extModule;
74     void *extData;
75 };
76 
77 typedef struct _xsltExtElement xsltExtElement;
78 typedef xsltExtElement *xsltExtElementPtr;
79 struct _xsltExtElement {
80     xsltPreComputeFunction precomp;
81     xsltTransformFunction transform;
82 };
83 
84 static xmlHashTablePtr xsltExtensionsHash = NULL;
85 static xmlHashTablePtr xsltFunctionsHash = NULL;
86 static xmlHashTablePtr xsltElementsHash = NULL;
87 static xmlHashTablePtr xsltTopLevelsHash = NULL;
88 static xmlHashTablePtr xsltModuleHash = NULL;
89 static 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  */
106 static xsltExtDefPtr
xsltNewExtDef(const xmlChar * prefix,const xmlChar * URI)107 xsltNewExtDef(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  */
131 static void
xsltFreeExtDef(xsltExtDefPtr extensiond)132 xsltFreeExtDef(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  */
149 static void
xsltFreeExtDefList(xsltExtDefPtr extensiond)150 xsltFreeExtDefList(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  */
172 static xsltExtModulePtr
xsltNewExtModule(xsltExtInitFunction initFunc,xsltExtShutdownFunction shutdownFunc,xsltStyleExtInitFunction styleInitFunc,xsltStyleExtShutdownFunction styleShutdownFunc)173 xsltNewExtModule(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  */
199 static void
xsltFreeExtModule(xsltExtModulePtr ext)200 xsltFreeExtModule(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  */
216 static xsltExtDataPtr
xsltNewExtData(xsltExtModulePtr extModule,void * extData)217 xsltNewExtData(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  */
240 static void
xsltFreeExtData(xsltExtDataPtr ext)241 xsltFreeExtData(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  */
258 static xsltExtElementPtr
xsltNewExtElement(xsltPreComputeFunction precomp,xsltTransformFunction transform)259 xsltNewExtElement(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  */
284 static void
xsltFreeExtElement(xsltExtElementPtr ext)285 xsltFreeExtElement(xsltExtElementPtr ext)
286 {
287     if (ext == NULL)
288         return;
289     xmlFree(ext);
290 }
291 
292 
293 #ifdef WITH_MODULES
294 typedef 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 
319 static int
xsltExtModuleRegisterDynamic(const xmlChar * URI)320 xsltExtModuleRegisterDynamic(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
458 static int
xsltExtModuleRegisterDynamic(const xmlChar * URI ATTRIBUTE_UNUSED)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
xsltFreeExts(xsltStylesheetPtr style)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
xsltRegisterExtPrefix(xsltStylesheetPtr style,const xmlChar * prefix,const xmlChar * URI)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
xsltRegisterExtFunction(xsltTransformContextPtr ctxt,const xmlChar * name,const xmlChar * URI,xmlXPathFunction function)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
xsltRegisterExtElement(xsltTransformContextPtr ctxt,const xmlChar * name,const xmlChar * URI,xsltTransformFunction function)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
xsltFreeCtxtExts(xsltTransformContextPtr ctxt)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
xsltStyleInitializeStylesheetModule(xsltStylesheetPtr style,const xmlChar * URI)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 *
xsltStyleGetExtData(xsltStylesheetPtr style,const xmlChar * URI)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 *
xsltStyleStylesheetLevelGetExtData(xsltStylesheetPtr style,const xmlChar * URI)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 *
xsltGetExtData(xsltTransformContextPtr ctxt,const xmlChar * URI)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
xsltInitCtxtExt(xsltExtDataPtr styleData,xsltInitExtCtxt * ctxt,const xmlChar * URI)937 xsltInitCtxtExt(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  */
1014 int
xsltInitCtxtExts(xsltTransformContextPtr ctxt)1015 xsltInitCtxtExts(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  */
1054 static void
xsltShutdownCtxtExt(xsltExtDataPtr data,xsltTransformContextPtr ctxt,const xmlChar * URI)1055 xsltShutdownCtxtExt(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  */
1079 void
xsltShutdownCtxtExts(xsltTransformContextPtr ctxt)1080 xsltShutdownCtxtExts(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  */
1100 static void
xsltShutdownExt(xsltExtDataPtr data,xsltStylesheetPtr style,const xmlChar * URI)1101 xsltShutdownExt(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  */
1132 void
xsltShutdownExts(xsltStylesheetPtr style)1133 xsltShutdownExts(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  */
1157 int
xsltCheckExtPrefix(xsltStylesheetPtr style,const xmlChar * URI)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
xsltCheckExtURI(xsltStylesheetPtr style,const xmlChar * URI)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
xsltRegisterExtModuleFull(const xmlChar * URI,xsltExtInitFunction initFunc,xsltExtShutdownFunction shutdownFunc,xsltStyleExtInitFunction styleInitFunc,xsltStyleExtShutdownFunction styleShutdownFunc)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
xsltRegisterExtModule(const xmlChar * URI,xsltExtInitFunction initFunc,xsltExtShutdownFunction shutdownFunc)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
xsltUnregisterExtModule(const xmlChar * URI)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,
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  */
1341 static void
xsltUnregisterAllExtModules(void)1342 xsltUnregisterAllExtModules(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  */
1368 xsltTransformContextPtr
xsltXPathGetTransformContext(xmlXPathParserContextPtr ctxt)1369 xsltXPathGetTransformContext(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  */
1386 int
xsltRegisterExtModuleFunction(const xmlChar * name,const xmlChar * URI,xmlXPathFunction function)1387 xsltRegisterExtModuleFunction(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  */
1417 xmlXPathFunction
xsltExtModuleFunctionLookup(const xmlChar * name,const xmlChar * URI)1418 xsltExtModuleFunctionLookup(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  */
1455 int
xsltUnregisterExtModuleFunction(const xmlChar * name,const xmlChar * URI)1456 xsltUnregisterExtModuleFunction(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  */
1477 static void
xsltUnregisterAllExtModuleFunction(void)1478 xsltUnregisterAllExtModuleFunction(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  */
1499 xsltElemPreCompPtr
xsltNewElemPreComp(xsltStylesheetPtr style,xmlNodePtr inst,xsltTransformFunction function)1500 xsltNewElemPreComp(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  */
1532 void
xsltInitElemPreComp(xsltElemPreCompPtr comp,xsltStylesheetPtr style,xmlNodePtr inst,xsltTransformFunction function,xsltElemPreCompDeallocator freeFunc)1533 xsltInitElemPreComp(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  */
1555 xsltElemPreCompPtr
xsltPreComputeExtModuleElement(xsltStylesheetPtr style,xmlNodePtr inst)1556 xsltPreComputeExtModuleElement(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  */
1620 int
xsltRegisterExtModuleElement(const xmlChar * name,const xmlChar * URI,xsltPreComputeFunction precomp,xsltTransformFunction transform)1621 xsltRegisterExtModuleElement(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 
1648 done:
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  */
1665 xsltTransformFunction
xsltExtElementLookup(xsltTransformContextPtr ctxt,const xmlChar * name,const xmlChar * URI)1666 xsltExtElementLookup(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  */
1695 xsltTransformFunction
xsltExtModuleElementLookup(const xmlChar * name,const xmlChar * URI)1696 xsltExtModuleElementLookup(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  */
1738 xsltPreComputeFunction
xsltExtModuleElementPreComputeLookup(const xmlChar * name,const xmlChar * URI)1739 xsltExtModuleElementPreComputeLookup(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  */
1778 int
xsltUnregisterExtModuleElement(const xmlChar * name,const xmlChar * URI)1779 xsltUnregisterExtModuleElement(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  */
1801 static void
xsltUnregisterAllExtModuleElement(void)1802 xsltUnregisterAllExtModuleElement(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  */
1822 int
xsltRegisterExtModuleTopLevel(const xmlChar * name,const xmlChar * URI,xsltTopLevelFunction function)1823 xsltRegisterExtModuleTopLevel(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  */
1853 xsltTopLevelFunction
xsltExtModuleTopLevelLookup(const xmlChar * name,const xmlChar * URI)1854 xsltExtModuleTopLevelLookup(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  */
1890 int
xsltUnregisterExtModuleTopLevel(const xmlChar * name,const xmlChar * URI)1891 xsltUnregisterExtModuleTopLevel(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  */
1912 static void
xsltUnregisterAllExtModuleTopLevel(void)1913 xsltUnregisterAllExtModuleTopLevel(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  */
1932 xmlHashTablePtr
xsltGetExtInfo(xsltStylesheetPtr style,const xmlChar * URI)1933 xsltGetExtInfo(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 
1964 static xmlChar *testData = NULL;
1965 static 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  */
1974 static void
xsltExtFunctionTest(xmlXPathParserContextPtr ctxt,int nargs ATTRIBUTE_UNUSED)1975 xsltExtFunctionTest(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  */
2024 static xsltElemPreCompPtr
xsltExtElementPreCompTest(xsltStylesheetPtr style,xmlNodePtr inst,xsltTransformFunction function)2025 xsltExtElementPreCompTest(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  */
2068 static void
xsltExtElementTest(xsltTransformContextPtr ctxt,xmlNodePtr node,xmlNodePtr inst,xsltElemPreCompPtr comp ATTRIBUTE_UNUSED)2069 xsltExtElementTest(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  */
2120 static void *
xsltExtInitTest(xsltTransformContextPtr ctxt,const xmlChar * URI)2121 xsltExtInitTest(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  */
2154 static void
xsltExtShutdownTest(xsltTransformContextPtr ctxt,const xmlChar * URI,void * data)2155 xsltExtShutdownTest(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  */
2181 static void *
xsltExtStyleInitTest(xsltStylesheetPtr style ATTRIBUTE_UNUSED,const xmlChar * URI)2182 xsltExtStyleInitTest(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  */
2205 static void
xsltExtStyleShutdownTest(xsltStylesheetPtr style ATTRIBUTE_UNUSED,const xmlChar * URI,void * data)2206 xsltExtStyleShutdownTest(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  */
2228 void
xsltRegisterTestModule(void)2229 xsltRegisterTestModule(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 
2245 static void
xsltHashScannerModuleFree(void * payload ATTRIBUTE_UNUSED,void * data ATTRIBUTE_UNUSED,xmlChar * name ATTRIBUTE_UNUSED)2246 xsltHashScannerModuleFree(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  */
2260 void
xsltInitGlobals(void)2261 xsltInitGlobals(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  */
2273 void
xsltCleanupGlobals(void)2274 xsltCleanupGlobals(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 
2295 static void
xsltDebugDumpExtensionsCallback(void * function ATTRIBUTE_UNUSED,FILE * output,const xmlChar * name,const xmlChar * URI,const xmlChar * not_used ATTRIBUTE_UNUSED)2296 xsltDebugDumpExtensionsCallback(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 
2306 static void
xsltDebugDumpExtModulesCallback(void * function ATTRIBUTE_UNUSED,FILE * output,const xmlChar * URI,const xmlChar * not_used ATTRIBUTE_UNUSED,const xmlChar * not_used2 ATTRIBUTE_UNUSED)2307 xsltDebugDumpExtModulesCallback(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  */
2323 void
xsltDebugDumpExtensions(FILE * output)2324 xsltDebugDumpExtensions(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