xref: /reactos/dll/3rdparty/libxslt/extensions.c (revision f7671c1b)
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
xsltNewExtDef(const xmlChar * prefix,const xmlChar * URI)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
xsltFreeExtDef(xsltExtDefPtr extensiond)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
xsltFreeExtDefList(xsltExtDefPtr extensiond)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
xsltNewExtModule(xsltExtInitFunction initFunc,xsltExtShutdownFunction shutdownFunc,xsltStyleExtInitFunction styleInitFunc,xsltStyleExtShutdownFunction styleShutdownFunc)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
xsltFreeExtModule(xsltExtModulePtr ext)183 xsltFreeExtModule(xsltExtModulePtr ext)
184 {
185     if (ext == NULL)
186         return;
187     xmlFree(ext);
188 }
189 
190 static void
xsltFreeExtModuleEntry(void * payload,const xmlChar * name ATTRIBUTE_UNUSED)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
xsltNewExtData(xsltExtModulePtr extModule,void * extData)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
xsltFreeExtData(xsltExtDataPtr ext)229 xsltFreeExtData(xsltExtDataPtr ext)
230 {
231     if (ext == NULL)
232         return;
233     xmlFree(ext);
234 }
235 
236 static void
xsltFreeExtDataEntry(void * payload,const xmlChar * name ATTRIBUTE_UNUSED)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
xsltNewExtElement(xsltPreComputeFunction precomp,xsltTransformFunction transform)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
xsltFreeExtElement(xsltExtElementPtr ext)278 xsltFreeExtElement(xsltExtElementPtr ext)
279 {
280     if (ext == NULL)
281         return;
282     xmlFree(ext);
283 }
284 
285 static void
xsltFreeExtElementEntry(void * payload,const xmlChar * name ATTRIBUTE_UNUSED)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
xsltExtModuleRegisterDynamic(const xmlChar * URI)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
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(void * payload,void * data,const xmlChar * URI)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
xsltInitCtxtExts(xsltTransformContextPtr ctxt)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
xsltShutdownCtxtExt(void * payload,void * vctxt,const xmlChar * URI)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
xsltShutdownCtxtExts(xsltTransformContextPtr ctxt)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
xsltShutdownExt(void * payload,void * vctxt,const xmlChar * URI)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
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, 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
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, 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
xsltUnregisterAllExtModules(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
xsltXPathGetTransformContext(xmlXPathParserContextPtr ctxt)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
xsltRegisterExtModuleFunction(const xmlChar * name,const xmlChar * URI,xmlXPathFunction function)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
xsltExtModuleFunctionLookup(const xmlChar * name,const xmlChar * URI)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
xsltUnregisterExtModuleFunction(const xmlChar * name,const xmlChar * URI)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
xsltUnregisterAllExtModuleFunction(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
xsltFreeElemPreComp(xsltElemPreCompPtr comp)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
xsltNewElemPreComp(xsltStylesheetPtr style,xmlNodePtr inst,xsltTransformFunction function)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
xsltInitElemPreComp(xsltElemPreCompPtr comp,xsltStylesheetPtr style,xmlNodePtr inst,xsltTransformFunction function,xsltElemPreCompDeallocator freeFunc)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
xsltPreComputeExtModuleElement(xsltStylesheetPtr style,xmlNodePtr inst)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
xsltRegisterExtModuleElement(const xmlChar * name,const xmlChar * URI,xsltPreComputeFunction precomp,xsltTransformFunction transform)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
xsltExtElementLookup(xsltTransformContextPtr ctxt,const xmlChar * name,const xmlChar * URI)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
xsltExtModuleElementLookup(const xmlChar * name,const xmlChar * URI)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
xsltExtModuleElementPreComputeLookup(const xmlChar * name,const xmlChar * URI)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
xsltUnregisterExtModuleElement(const xmlChar * name,const xmlChar * URI)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
xsltUnregisterAllExtModuleElement(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
xsltRegisterExtModuleTopLevel(const xmlChar * name,const xmlChar * URI,xsltTopLevelFunction function)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
xsltExtModuleTopLevelLookup(const xmlChar * name,const xmlChar * URI)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
xsltUnregisterExtModuleTopLevel(const xmlChar * name,const xmlChar * URI)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
xsltUnregisterAllExtModuleTopLevel(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
xsltGetExtInfo(xsltStylesheetPtr style,const xmlChar * URI)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 of the extension module API			*
1957  *									*
1958  ************************************************************************/
1959 
1960 static xmlChar *testData = NULL;
1961 static xmlChar *testStyleData = NULL;
1962 
1963 /**
1964  * xsltExtFunctionTest:
1965  * @ctxt:  the XPath Parser context
1966  * @nargs:  the number of arguments
1967  *
1968  * function libxslt:test() for testing the extensions support.
1969  */
1970 static void
xsltExtFunctionTest(xmlXPathParserContextPtr ctxt,int nargs ATTRIBUTE_UNUSED)1971 xsltExtFunctionTest(xmlXPathParserContextPtr ctxt,
1972                     int nargs ATTRIBUTE_UNUSED)
1973 {
1974     xsltTransformContextPtr tctxt;
1975     void *data = NULL;
1976 
1977     tctxt = xsltXPathGetTransformContext(ctxt);
1978 
1979     if (testData == NULL) {
1980         xsltGenericDebug(xsltGenericDebugContext,
1981                          "xsltExtFunctionTest: not initialized,"
1982                          " calling xsltGetExtData\n");
1983         data = xsltGetExtData(tctxt, (const xmlChar *) XSLT_DEFAULT_URL);
1984         if (data == NULL) {
1985             xsltTransformError(tctxt, NULL, NULL,
1986                                "xsltExtElementTest: not initialized\n");
1987             return;
1988         }
1989     }
1990     if (tctxt == NULL) {
1991         xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
1992                            "xsltExtFunctionTest: failed to get the transformation context\n");
1993         return;
1994     }
1995     if (data == NULL)
1996         data = xsltGetExtData(tctxt, (const xmlChar *) XSLT_DEFAULT_URL);
1997     if (data == NULL) {
1998         xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
1999                            "xsltExtFunctionTest: failed to get module data\n");
2000         return;
2001     }
2002     if (data != testData) {
2003         xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
2004                            "xsltExtFunctionTest: got wrong module data\n");
2005         return;
2006     }
2007 #ifdef WITH_XSLT_DEBUG_FUNCTION
2008     xsltGenericDebug(xsltGenericDebugContext,
2009                      "libxslt:test() called with %d args\n", nargs);
2010 #endif
2011 }
2012 
2013 /**
2014  * xsltExtElementPreCompTest:
2015  * @style:  the stylesheet
2016  * @inst:  the instruction in the stylesheet
2017  *
2018  * Process a libxslt:test node
2019  */
2020 static xsltElemPreCompPtr
xsltExtElementPreCompTest(xsltStylesheetPtr style,xmlNodePtr inst,xsltTransformFunction function)2021 xsltExtElementPreCompTest(xsltStylesheetPtr style, xmlNodePtr inst,
2022                           xsltTransformFunction function)
2023 {
2024     xsltElemPreCompPtr ret;
2025 
2026     if (style == NULL) {
2027         xsltTransformError(NULL, NULL, inst,
2028                            "xsltExtElementTest: no transformation context\n");
2029         return (NULL);
2030     }
2031     if (testStyleData == NULL) {
2032         xsltGenericDebug(xsltGenericDebugContext,
2033                          "xsltExtElementPreCompTest: not initialized,"
2034                          " calling xsltStyleGetExtData\n");
2035         xsltStyleGetExtData(style, (const xmlChar *) XSLT_DEFAULT_URL);
2036         if (testStyleData == NULL) {
2037             xsltTransformError(NULL, style, inst,
2038                                "xsltExtElementPreCompTest: not initialized\n");
2039             if (style != NULL)
2040                 style->errors++;
2041             return (NULL);
2042         }
2043     }
2044     if (inst == NULL) {
2045         xsltTransformError(NULL, style, inst,
2046                            "xsltExtElementPreCompTest: no instruction\n");
2047         if (style != NULL)
2048             style->errors++;
2049         return (NULL);
2050     }
2051     ret = xsltNewElemPreComp(style, inst, function);
2052     return (ret);
2053 }
2054 
2055 /**
2056  * xsltExtElementTest:
2057  * @ctxt:  an XSLT processing context
2058  * @node:  The current node
2059  * @inst:  the instruction in the stylesheet
2060  * @comp:  precomputed information
2061  *
2062  * Process a libxslt:test node
2063  */
2064 static void
xsltExtElementTest(xsltTransformContextPtr ctxt,xmlNodePtr node,xmlNodePtr inst,xsltElemPreCompPtr comp ATTRIBUTE_UNUSED)2065 xsltExtElementTest(xsltTransformContextPtr ctxt, xmlNodePtr node,
2066                    xmlNodePtr inst,
2067                    xsltElemPreCompPtr comp ATTRIBUTE_UNUSED)
2068 {
2069     xmlNodePtr commentNode;
2070 
2071     if (testData == NULL) {
2072         xsltGenericDebug(xsltGenericDebugContext,
2073                          "xsltExtElementTest: not initialized,"
2074                          " calling xsltGetExtData\n");
2075         xsltGetExtData(ctxt, (const xmlChar *) XSLT_DEFAULT_URL);
2076         if (testData == NULL) {
2077             xsltTransformError(ctxt, NULL, inst,
2078                                "xsltExtElementTest: not initialized\n");
2079             return;
2080         }
2081     }
2082     if (ctxt == NULL) {
2083         xsltTransformError(ctxt, NULL, inst,
2084                            "xsltExtElementTest: no transformation context\n");
2085         return;
2086     }
2087     if (node == NULL) {
2088         xsltTransformError(ctxt, NULL, inst,
2089                            "xsltExtElementTest: no current node\n");
2090         return;
2091     }
2092     if (inst == NULL) {
2093         xsltTransformError(ctxt, NULL, inst,
2094                            "xsltExtElementTest: no instruction\n");
2095         return;
2096     }
2097     if (ctxt->insert == NULL) {
2098         xsltTransformError(ctxt, NULL, inst,
2099                            "xsltExtElementTest: no insertion point\n");
2100         return;
2101     }
2102     commentNode = xmlNewComment((const xmlChar *)
2103                                 "libxslt:test element test worked");
2104     xmlAddChild(ctxt->insert, commentNode);
2105 }
2106 
2107 /**
2108  * xsltExtInitTest:
2109  * @ctxt:  an XSLT transformation context
2110  * @URI:  the namespace URI for the extension
2111  *
2112  * A function called at initialization time of an XSLT extension module
2113  *
2114  * Returns a pointer to the module specific data for this transformation
2115  */
2116 static void *
xsltExtInitTest(xsltTransformContextPtr ctxt,const xmlChar * URI)2117 xsltExtInitTest(xsltTransformContextPtr ctxt, const xmlChar * URI)
2118 {
2119     if (testStyleData == NULL) {
2120         xsltGenericDebug(xsltGenericErrorContext,
2121                          "xsltExtInitTest: not initialized,"
2122                          " calling xsltStyleGetExtData\n");
2123         testStyleData = xsltStyleGetExtData(ctxt->style, URI);
2124         if (testStyleData == NULL) {
2125             xsltTransformError(ctxt, NULL, NULL,
2126                                "xsltExtInitTest: not initialized\n");
2127             return (NULL);
2128         }
2129     }
2130     if (testData != NULL) {
2131         xsltTransformError(ctxt, NULL, NULL,
2132                            "xsltExtInitTest: already initialized\n");
2133         return (NULL);
2134     }
2135     testData = (void *) "test data";
2136     xsltGenericDebug(xsltGenericDebugContext,
2137                      "Registered test module : %s\n", URI);
2138     return (testData);
2139 }
2140 
2141 
2142 /**
2143  * xsltExtShutdownTest:
2144  * @ctxt:  an XSLT transformation context
2145  * @URI:  the namespace URI for the extension
2146  * @data:  the data associated to this module
2147  *
2148  * A function called at shutdown time of an XSLT extension module
2149  */
2150 static void
xsltExtShutdownTest(xsltTransformContextPtr ctxt,const xmlChar * URI,void * data)2151 xsltExtShutdownTest(xsltTransformContextPtr ctxt,
2152                     const xmlChar * URI, void *data)
2153 {
2154     if (testData == NULL) {
2155         xsltTransformError(ctxt, NULL, NULL,
2156                            "xsltExtShutdownTest: not initialized\n");
2157         return;
2158     }
2159     if (data != testData) {
2160         xsltTransformError(ctxt, NULL, NULL,
2161                            "xsltExtShutdownTest: wrong data\n");
2162     }
2163     testData = NULL;
2164     xsltGenericDebug(xsltGenericDebugContext,
2165                      "Unregistered test module : %s\n", URI);
2166 }
2167 
2168 /**
2169  * xsltExtStyleInitTest:
2170  * @style:  an XSLT stylesheet
2171  * @URI:  the namespace URI for the extension
2172  *
2173  * A function called at initialization time of an XSLT extension module
2174  *
2175  * Returns a pointer to the module specific data for this transformation
2176  */
2177 static void *
xsltExtStyleInitTest(xsltStylesheetPtr style ATTRIBUTE_UNUSED,const xmlChar * URI)2178 xsltExtStyleInitTest(xsltStylesheetPtr style ATTRIBUTE_UNUSED,
2179                      const xmlChar * URI)
2180 {
2181     if (testStyleData != NULL) {
2182         xsltTransformError(NULL, NULL, NULL,
2183                            "xsltExtInitTest: already initialized\n");
2184         return (NULL);
2185     }
2186     testStyleData = (void *) "test data";
2187     xsltGenericDebug(xsltGenericDebugContext,
2188                      "Registered test module : %s\n", URI);
2189     return (testStyleData);
2190 }
2191 
2192 
2193 /**
2194  * xsltExtStyleShutdownTest:
2195  * @style:  an XSLT stylesheet
2196  * @URI:  the namespace URI for the extension
2197  * @data:  the data associated to this module
2198  *
2199  * A function called at shutdown time of an XSLT extension module
2200  */
2201 static void
xsltExtStyleShutdownTest(xsltStylesheetPtr style ATTRIBUTE_UNUSED,const xmlChar * URI,void * data)2202 xsltExtStyleShutdownTest(xsltStylesheetPtr style ATTRIBUTE_UNUSED,
2203                          const xmlChar * URI, void *data)
2204 {
2205     if (testStyleData == NULL) {
2206         xsltGenericError(xsltGenericErrorContext,
2207                          "xsltExtShutdownTest: not initialized\n");
2208         return;
2209     }
2210     if (data != testStyleData) {
2211         xsltTransformError(NULL, NULL, NULL,
2212                            "xsltExtShutdownTest: wrong data\n");
2213     }
2214     testStyleData = NULL;
2215     xsltGenericDebug(xsltGenericDebugContext,
2216                      "Unregistered test module : %s\n", URI);
2217 }
2218 
2219 /**
2220  * xsltRegisterTestModule:
2221  *
2222  * Registers the test module
2223  */
2224 void
xsltRegisterTestModule(void)2225 xsltRegisterTestModule(void)
2226 {
2227     xsltInitGlobals();
2228     xsltRegisterExtModuleFull((const xmlChar *) XSLT_DEFAULT_URL,
2229                               xsltExtInitTest, xsltExtShutdownTest,
2230                               xsltExtStyleInitTest,
2231                               xsltExtStyleShutdownTest);
2232     xsltRegisterExtModuleFunction((const xmlChar *) "test",
2233                                   (const xmlChar *) XSLT_DEFAULT_URL,
2234                                   xsltExtFunctionTest);
2235     xsltRegisterExtModuleElement((const xmlChar *) "test",
2236                                  (const xmlChar *) XSLT_DEFAULT_URL,
2237                                  xsltExtElementPreCompTest,
2238                                  xsltExtElementTest);
2239 }
2240 
2241 static void
xsltHashScannerModuleFree(void * payload ATTRIBUTE_UNUSED,void * data ATTRIBUTE_UNUSED,const xmlChar * name ATTRIBUTE_UNUSED)2242 xsltHashScannerModuleFree(void *payload ATTRIBUTE_UNUSED,
2243                           void *data ATTRIBUTE_UNUSED,
2244                           const xmlChar *name ATTRIBUTE_UNUSED)
2245 {
2246 #ifdef WITH_MODULES
2247     xmlModuleClose(payload);
2248 #endif
2249 }
2250 
2251 /**
2252  * xsltInitGlobals:
2253  *
2254  * Initialize the global variables for extensions
2255  */
2256 void
xsltInitGlobals(void)2257 xsltInitGlobals(void)
2258 {
2259     if (xsltExtMutex == NULL) {
2260         xsltExtMutex = xmlNewMutex();
2261     }
2262 }
2263 
2264 /**
2265  * xsltCleanupGlobals:
2266  *
2267  * Unregister all global variables set up by the XSLT library
2268  */
2269 void
xsltCleanupGlobals(void)2270 xsltCleanupGlobals(void)
2271 {
2272     xsltUnregisterAllExtModules();
2273     xsltUnregisterAllExtModuleFunction();
2274     xsltUnregisterAllExtModuleElement();
2275     xsltUnregisterAllExtModuleTopLevel();
2276 
2277     xmlMutexLock(xsltExtMutex);
2278     /* cleanup dynamic module hash */
2279     if (NULL != xsltModuleHash) {
2280         xmlHashScan(xsltModuleHash, xsltHashScannerModuleFree, 0);
2281         xmlHashFree(xsltModuleHash, NULL);
2282         xsltModuleHash = NULL;
2283     }
2284     xmlMutexUnlock(xsltExtMutex);
2285 
2286     xmlFreeMutex(xsltExtMutex);
2287     xsltExtMutex = NULL;
2288     xsltFreeLocales();
2289     xsltUninit();
2290 }
2291 
2292 static void
xsltDebugDumpExtensionsCallback(void * function ATTRIBUTE_UNUSED,void * data,const xmlChar * name,const xmlChar * URI,const xmlChar * not_used ATTRIBUTE_UNUSED)2293 xsltDebugDumpExtensionsCallback(void *function ATTRIBUTE_UNUSED,
2294                                 void *data, const xmlChar * name,
2295                                 const xmlChar * URI,
2296                                 const xmlChar * not_used ATTRIBUTE_UNUSED)
2297 {
2298     FILE *output = (FILE *) data;
2299     if (!name || !URI)
2300         return;
2301     fprintf(output, "{%s}%s\n", URI, name);
2302 }
2303 
2304 static void
xsltDebugDumpExtModulesCallback(void * function ATTRIBUTE_UNUSED,void * data,const xmlChar * URI,const xmlChar * not_used ATTRIBUTE_UNUSED,const xmlChar * not_used2 ATTRIBUTE_UNUSED)2305 xsltDebugDumpExtModulesCallback(void *function ATTRIBUTE_UNUSED,
2306                                 void *data, const xmlChar * URI,
2307                                 const xmlChar * not_used ATTRIBUTE_UNUSED,
2308                                 const xmlChar * not_used2 ATTRIBUTE_UNUSED)
2309 {
2310     FILE *output = (FILE *) data;
2311     if (!URI)
2312         return;
2313     fprintf(output, "%s\n", URI);
2314 }
2315 
2316 /**
2317  * xsltDebugDumpExtensions:
2318  * @output:  the FILE * for the output, if NULL stdout is used
2319  *
2320  * Dumps a list of the registered XSLT extension functions and elements
2321  */
2322 void
xsltDebugDumpExtensions(FILE * output)2323 xsltDebugDumpExtensions(FILE * output)
2324 {
2325     if (output == NULL)
2326         output = stdout;
2327     fprintf(output,
2328             "Registered XSLT Extensions\n--------------------------\n");
2329     if (!xsltFunctionsHash)
2330         fprintf(output, "No registered extension functions\n");
2331     else {
2332         fprintf(output, "Registered Extension Functions:\n");
2333         xmlMutexLock(xsltExtMutex);
2334         xmlHashScanFull(xsltFunctionsHash, xsltDebugDumpExtensionsCallback,
2335                         output);
2336         xmlMutexUnlock(xsltExtMutex);
2337     }
2338     if (!xsltElementsHash)
2339         fprintf(output, "\nNo registered extension elements\n");
2340     else {
2341         fprintf(output, "\nRegistered Extension Elements:\n");
2342         xmlMutexLock(xsltExtMutex);
2343         xmlHashScanFull(xsltElementsHash, xsltDebugDumpExtensionsCallback,
2344                         output);
2345         xmlMutexUnlock(xsltExtMutex);
2346     }
2347     if (!xsltExtensionsHash)
2348         fprintf(output, "\nNo registered extension modules\n");
2349     else {
2350         fprintf(output, "\nRegistered Extension Modules:\n");
2351         xmlMutexLock(xsltExtMutex);
2352         xmlHashScanFull(xsltExtensionsHash, xsltDebugDumpExtModulesCallback,
2353                         output);
2354         xmlMutexUnlock(xsltExtMutex);
2355     }
2356 
2357 }
2358