xslt: Import upstream release 1.1.38.
[wine.git] / libs / xslt / libxslt / extensions.c
blobf9ca08e7db700ce88734ef685c709e2fcc543d44
1 /*
2 * extensions.c: Implemetation of the extensions support
4 * Reference:
5 * http://www.w3.org/TR/1999/REC-xslt-19991116
7 * See Copyright for the status of this software.
9 * daniel@veillard.com
12 #define IN_LIBXSLT
13 #include "libxslt.h"
15 #include <string.h>
16 #include <limits.h>
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 "xsltlocale.h"
32 #include "xsltutils.h"
33 #include "imports.h"
34 #include "extensions.h"
36 #ifdef _WIN32
37 #include <stdlib.h> /* for _MAX_PATH */
38 #ifndef PATH_MAX
39 #define PATH_MAX _MAX_PATH
40 #endif
41 #endif
43 #ifdef WITH_XSLT_DEBUG
44 #define WITH_XSLT_DEBUG_EXTENSIONS
45 #endif
47 /************************************************************************
48 * *
49 * Private Types and Globals *
50 * *
51 ************************************************************************/
53 typedef struct _xsltExtDef xsltExtDef;
54 typedef xsltExtDef *xsltExtDefPtr;
55 struct _xsltExtDef {
56 struct _xsltExtDef *next;
57 xmlChar *prefix;
58 xmlChar *URI;
59 void *data;
62 typedef struct _xsltExtModule xsltExtModule;
63 typedef xsltExtModule *xsltExtModulePtr;
64 struct _xsltExtModule {
65 xsltExtInitFunction initFunc;
66 xsltExtShutdownFunction shutdownFunc;
67 xsltStyleExtInitFunction styleInitFunc;
68 xsltStyleExtShutdownFunction styleShutdownFunc;
71 typedef struct _xsltExtData xsltExtData;
72 typedef xsltExtData *xsltExtDataPtr;
73 struct _xsltExtData {
74 xsltExtModulePtr extModule;
75 void *extData;
78 typedef struct _xsltExtElement xsltExtElement;
79 typedef xsltExtElement *xsltExtElementPtr;
80 struct _xsltExtElement {
81 xsltPreComputeFunction precomp;
82 xsltTransformFunction transform;
85 static xmlHashTablePtr xsltExtensionsHash = NULL;
86 static xmlHashTablePtr xsltFunctionsHash = NULL;
87 static xmlHashTablePtr xsltElementsHash = NULL;
88 static xmlHashTablePtr xsltTopLevelsHash = NULL;
89 static xmlHashTablePtr xsltModuleHash = NULL;
90 static xmlMutexPtr xsltExtMutex = NULL;
92 /************************************************************************
93 * *
94 * Type functions *
95 * *
96 ************************************************************************/
98 /**
99 * xsltNewExtDef:
100 * @prefix: the extension prefix
101 * @URI: the namespace URI
103 * Create a new XSLT ExtDef
105 * Returns the newly allocated xsltExtDefPtr or NULL in case of error
107 static xsltExtDefPtr
108 xsltNewExtDef(const xmlChar * prefix, const xmlChar * URI)
110 xsltExtDefPtr cur;
112 cur = (xsltExtDefPtr) xmlMalloc(sizeof(xsltExtDef));
113 if (cur == NULL) {
114 xsltTransformError(NULL, NULL, NULL,
115 "xsltNewExtDef : malloc failed\n");
116 return (NULL);
118 memset(cur, 0, sizeof(xsltExtDef));
119 if (prefix != NULL)
120 cur->prefix = xmlStrdup(prefix);
121 if (URI != NULL)
122 cur->URI = xmlStrdup(URI);
123 return (cur);
127 * xsltFreeExtDef:
128 * @extensiond: an XSLT extension definition
130 * Free up the memory allocated by @extensiond
132 static void
133 xsltFreeExtDef(xsltExtDefPtr extensiond)
135 if (extensiond == NULL)
136 return;
137 if (extensiond->prefix != NULL)
138 xmlFree(extensiond->prefix);
139 if (extensiond->URI != NULL)
140 xmlFree(extensiond->URI);
141 xmlFree(extensiond);
145 * xsltFreeExtDefList:
146 * @extensiond: an XSLT extension definition list
148 * Free up the memory allocated by all the elements of @extensiond
150 static void
151 xsltFreeExtDefList(xsltExtDefPtr extensiond)
153 xsltExtDefPtr cur;
155 while (extensiond != NULL) {
156 cur = extensiond;
157 extensiond = extensiond->next;
158 xsltFreeExtDef(cur);
163 * xsltNewExtModule:
164 * @initFunc: the module initialization function
165 * @shutdownFunc: the module shutdown function
166 * @styleInitFunc: the stylesheet module data allocator function
167 * @styleShutdownFunc: the stylesheet module data free function
169 * Create a new XSLT extension module
171 * Returns the newly allocated xsltExtModulePtr or NULL in case of error
173 static xsltExtModulePtr
174 xsltNewExtModule(xsltExtInitFunction initFunc,
175 xsltExtShutdownFunction shutdownFunc,
176 xsltStyleExtInitFunction styleInitFunc,
177 xsltStyleExtShutdownFunction styleShutdownFunc)
179 xsltExtModulePtr cur;
181 cur = (xsltExtModulePtr) xmlMalloc(sizeof(xsltExtModule));
182 if (cur == NULL) {
183 xsltTransformError(NULL, NULL, NULL,
184 "xsltNewExtModule : malloc failed\n");
185 return (NULL);
187 cur->initFunc = initFunc;
188 cur->shutdownFunc = shutdownFunc;
189 cur->styleInitFunc = styleInitFunc;
190 cur->styleShutdownFunc = styleShutdownFunc;
191 return (cur);
195 * xsltFreeExtModule:
196 * @ext: an XSLT extension module
198 * Free up the memory allocated by @ext
200 static void
201 xsltFreeExtModule(xsltExtModulePtr ext)
203 if (ext == NULL)
204 return;
205 xmlFree(ext);
208 static void
209 xsltFreeExtModuleEntry(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
210 xsltFreeExtModule((xsltExtModulePtr) payload);
214 * xsltNewExtData:
215 * @extModule: the module
216 * @extData: the associated data
218 * Create a new XSLT extension module data wrapper
220 * Returns the newly allocated xsltExtDataPtr or NULL in case of error
222 static xsltExtDataPtr
223 xsltNewExtData(xsltExtModulePtr extModule, void *extData)
225 xsltExtDataPtr cur;
227 if (extModule == NULL)
228 return (NULL);
229 cur = (xsltExtDataPtr) xmlMalloc(sizeof(xsltExtData));
230 if (cur == NULL) {
231 xsltTransformError(NULL, NULL, NULL,
232 "xsltNewExtData : malloc failed\n");
233 return (NULL);
235 cur->extModule = extModule;
236 cur->extData = extData;
237 return (cur);
241 * xsltFreeExtData:
242 * @ext: an XSLT extension module data wrapper
244 * Free up the memory allocated by @ext
246 static void
247 xsltFreeExtData(xsltExtDataPtr ext)
249 if (ext == NULL)
250 return;
251 xmlFree(ext);
254 static void
255 xsltFreeExtDataEntry(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
256 xsltFreeExtData((xsltExtDataPtr) payload);
260 * xsltNewExtElement:
261 * @precomp: the pre-computation function
262 * @transform: the transformation function
264 * Create a new XSLT extension element
266 * Returns the newly allocated xsltExtElementPtr or NULL in case of
267 * error
269 static xsltExtElementPtr
270 xsltNewExtElement(xsltPreComputeFunction precomp,
271 xsltTransformFunction transform)
273 xsltExtElementPtr cur;
275 if (transform == NULL)
276 return (NULL);
278 cur = (xsltExtElementPtr) xmlMalloc(sizeof(xsltExtElement));
279 if (cur == NULL) {
280 xsltTransformError(NULL, NULL, NULL,
281 "xsltNewExtElement : malloc failed\n");
282 return (NULL);
284 cur->precomp = precomp;
285 cur->transform = transform;
286 return (cur);
290 * xsltFreeExtElement:
291 * @ext: an XSLT extension element
293 * Frees up the memory allocated by @ext
295 static void
296 xsltFreeExtElement(xsltExtElementPtr ext)
298 if (ext == NULL)
299 return;
300 xmlFree(ext);
303 static void
304 xsltFreeExtElementEntry(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
305 xsltFreeExtElement((xsltExtElementPtr) payload);
309 #ifdef WITH_MODULES
310 typedef void (*exsltRegisterFunction) (void);
312 #ifndef PATH_MAX
313 #define PATH_MAX 4096
314 #endif
317 * xsltExtModuleRegisterDynamic:
318 * @URI: the function or element namespace URI
320 * Dynamically loads an extension plugin when available.
322 * The plugin name is derived from the URI by removing the
323 * initial protocol designation, e.g. "http://", then converting
324 * the characters ".", "-", "/", and "\" into "_", the removing
325 * any trailing "/", then concatenating LIBXML_MODULE_EXTENSION.
327 * Plugins are loaded from the directory specified by the
328 * environment variable LIBXSLT_PLUGINS_PATH, or if NULL,
329 * by LIBXSLT_DEFAULT_PLUGINS_PATH() which is determined at
330 * compile time.
332 * Returns 0 if successful, -1 in case of error.
335 static int
336 xsltExtModuleRegisterDynamic(const xmlChar * URI)
339 xmlModulePtr m;
340 exsltRegisterFunction regfunc;
341 xmlChar *ext_name;
342 char module_filename[PATH_MAX];
343 const xmlChar *ext_directory = NULL;
344 const xmlChar *protocol = NULL;
345 xmlChar *i, *regfunc_name;
346 void *vregfunc;
347 int rc;
349 /* check for bad inputs */
350 if (URI == NULL)
351 return (-1);
353 if (NULL == xsltModuleHash) {
354 xsltModuleHash = xmlHashCreate(5);
355 if (xsltModuleHash == NULL)
356 return (-1);
359 xmlMutexLock(xsltExtMutex);
361 /* have we attempted to register this module already? */
362 if (xmlHashLookup(xsltModuleHash, URI) != NULL) {
363 xmlMutexUnlock(xsltExtMutex);
364 return (-1);
366 xmlMutexUnlock(xsltExtMutex);
368 /* transform extension namespace into a module name */
369 protocol = xmlStrstr(URI, BAD_CAST "://");
370 if (protocol == NULL) {
371 ext_name = xmlStrdup(URI);
372 } else {
373 ext_name = xmlStrdup(protocol + 3);
375 if (ext_name == NULL) {
376 return (-1);
379 i = ext_name;
380 while ('\0' != *i) {
381 if (('/' == *i) || ('\\' == *i) || ('.' == *i) || ('-' == *i))
382 *i = '_';
383 i++;
386 /* Strip underscores from end of string. */
387 while (i > ext_name && *(i - 1) == '_') {
388 i--;
389 *i = '\0';
392 /* determine module directory */
393 ext_directory = (xmlChar *) getenv("LIBXSLT_PLUGINS_PATH");
395 if (NULL == ext_directory) {
396 ext_directory = BAD_CAST LIBXSLT_DEFAULT_PLUGINS_PATH();
397 if (NULL == ext_directory)
398 return (-1);
400 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
401 else
402 xsltGenericDebug(xsltGenericDebugContext,
403 "LIBXSLT_PLUGINS_PATH is %s\n", ext_directory);
404 #endif
406 /* build the module filename, and confirm the module exists */
407 xmlStrPrintf((xmlChar *) module_filename, sizeof(module_filename),
408 "%s/%s%s", ext_directory, ext_name, LIBXML_MODULE_EXTENSION);
410 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
411 xsltGenericDebug(xsltGenericDebugContext,
412 "Attempting to load plugin: %s for URI: %s\n",
413 module_filename, URI);
414 #endif
416 if (1 != xmlCheckFilename(module_filename)) {
418 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
419 xsltGenericDebug(xsltGenericDebugContext,
420 "xmlCheckFilename failed for plugin: %s\n", module_filename);
421 #endif
423 xmlFree(ext_name);
424 return (-1);
427 /* attempt to open the module */
428 m = xmlModuleOpen(module_filename, 0);
429 if (NULL == m) {
431 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
432 xsltGenericDebug(xsltGenericDebugContext,
433 "xmlModuleOpen failed for plugin: %s\n", module_filename);
434 #endif
436 xmlFree(ext_name);
437 return (-1);
440 /* construct initialization func name */
441 regfunc_name = xmlStrdup(ext_name);
442 regfunc_name = xmlStrcat(regfunc_name, BAD_CAST "_init");
444 vregfunc = NULL;
445 rc = xmlModuleSymbol(m, (const char *) regfunc_name, &vregfunc);
446 regfunc = vregfunc;
447 if (0 == rc) {
449 * Call the module's init function. Note that this function
450 * calls xsltRegisterExtModuleFull which will add the module
451 * to xsltExtensionsHash (together with it's entry points).
453 (*regfunc) ();
455 /* register this module in our hash */
456 xmlMutexLock(xsltExtMutex);
457 xmlHashAddEntry(xsltModuleHash, URI, (void *) m);
458 xmlMutexUnlock(xsltExtMutex);
459 } else {
461 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
462 xsltGenericDebug(xsltGenericDebugContext,
463 "xmlModuleSymbol failed for plugin: %s, regfunc: %s\n",
464 module_filename, regfunc_name);
465 #endif
467 /* if regfunc not found unload the module immediately */
468 xmlModuleClose(m);
471 xmlFree(ext_name);
472 xmlFree(regfunc_name);
473 return (NULL == regfunc) ? -1 : 0;
475 #else
476 static int
477 xsltExtModuleRegisterDynamic(const xmlChar * URI ATTRIBUTE_UNUSED)
479 return -1;
481 #endif
483 /************************************************************************
485 * The stylesheet extension prefixes handling *
487 ************************************************************************/
491 * xsltFreeExts:
492 * @style: an XSLT stylesheet
494 * Free up the memory used by XSLT extensions in a stylesheet
496 void
497 xsltFreeExts(xsltStylesheetPtr style)
499 if (style->nsDefs != NULL)
500 xsltFreeExtDefList((xsltExtDefPtr) style->nsDefs);
504 * xsltRegisterExtPrefix:
505 * @style: an XSLT stylesheet
506 * @prefix: the prefix used (optional)
507 * @URI: the URI associated to the extension
509 * Registers an extension namespace
510 * This is called from xslt.c during compile-time.
511 * The given prefix is not needed.
512 * Called by:
513 * xsltParseExtElemPrefixes() (new function)
514 * xsltRegisterExtPrefix() (old function)
516 * Returns 0 in case of success, 1 if the @URI was already
517 * registered as an extension namespace and
518 * -1 in case of failure
521 xsltRegisterExtPrefix(xsltStylesheetPtr style,
522 const xmlChar * prefix, const xmlChar * URI)
524 xsltExtDefPtr def, ret;
526 if ((style == NULL) || (URI == NULL))
527 return (-1);
529 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
530 xsltGenericDebug(xsltGenericDebugContext,
531 "Registering extension namespace '%s'.\n", URI);
532 #endif
533 def = (xsltExtDefPtr) style->nsDefs;
534 #ifdef XSLT_REFACTORED
536 * The extension is associated with a namespace name.
538 while (def != NULL) {
539 if (xmlStrEqual(URI, def->URI))
540 return (1);
541 def = def->next;
543 #else
544 while (def != NULL) {
545 if (xmlStrEqual(prefix, def->prefix))
546 return (-1);
547 def = def->next;
549 #endif
550 ret = xsltNewExtDef(prefix, URI);
551 if (ret == NULL)
552 return (-1);
553 ret->next = (xsltExtDefPtr) style->nsDefs;
554 style->nsDefs = ret;
557 * check whether there is an extension module with a stylesheet
558 * initialization function.
560 #ifdef XSLT_REFACTORED
562 * Don't initialize modules based on specified namespaces via
563 * the attribute "[xsl:]extension-element-prefixes".
565 #else
566 if (xsltExtensionsHash != NULL) {
567 xsltExtModulePtr module;
569 xmlMutexLock(xsltExtMutex);
570 module = xmlHashLookup(xsltExtensionsHash, URI);
571 xmlMutexUnlock(xsltExtMutex);
572 if (NULL == module) {
573 if (!xsltExtModuleRegisterDynamic(URI)) {
574 xmlMutexLock(xsltExtMutex);
575 module = xmlHashLookup(xsltExtensionsHash, URI);
576 xmlMutexUnlock(xsltExtMutex);
579 if (module != NULL) {
580 xsltStyleGetExtData(style, URI);
583 #endif
584 return (0);
587 /************************************************************************
589 * The extensions modules interfaces *
591 ************************************************************************/
594 * xsltRegisterExtFunction:
595 * @ctxt: an XSLT transformation context
596 * @name: the name of the element
597 * @URI: the URI associated to the element
598 * @function: the actual implementation which should be called
600 * Registers an extension function
602 * Returns 0 in case of success, -1 in case of failure
605 xsltRegisterExtFunction(xsltTransformContextPtr ctxt, const xmlChar * name,
606 const xmlChar * URI, xmlXPathFunction function)
608 int ret;
610 if ((ctxt == NULL) || (name == NULL) ||
611 (URI == NULL) || (function == NULL))
612 return (-1);
613 if (ctxt->xpathCtxt != NULL) {
614 xmlXPathRegisterFuncNS(ctxt->xpathCtxt, name, URI, function);
616 if (ctxt->extFunctions == NULL)
617 ctxt->extFunctions = xmlHashCreate(10);
618 if (ctxt->extFunctions == NULL)
619 return (-1);
621 ret = xmlHashAddEntry2(ctxt->extFunctions, name, URI,
622 XML_CAST_FPTR(function));
624 return(ret);
628 * xsltRegisterExtElement:
629 * @ctxt: an XSLT transformation context
630 * @name: the name of the element
631 * @URI: the URI associated to the element
632 * @function: the actual implementation which should be called
634 * Registers an extension element
636 * Returns 0 in case of success, -1 in case of failure
639 xsltRegisterExtElement(xsltTransformContextPtr ctxt, const xmlChar * name,
640 const xmlChar * URI, xsltTransformFunction function)
642 if ((ctxt == NULL) || (name == NULL) ||
643 (URI == NULL) || (function == NULL))
644 return (-1);
645 if (ctxt->extElements == NULL)
646 ctxt->extElements = xmlHashCreate(10);
647 if (ctxt->extElements == NULL)
648 return (-1);
649 return (xmlHashAddEntry2
650 (ctxt->extElements, name, URI, XML_CAST_FPTR(function)));
654 * xsltFreeCtxtExts:
655 * @ctxt: an XSLT transformation context
657 * Free the XSLT extension data
659 void
660 xsltFreeCtxtExts(xsltTransformContextPtr ctxt)
662 if (ctxt->extElements != NULL)
663 xmlHashFree(ctxt->extElements, NULL);
664 if (ctxt->extFunctions != NULL)
665 xmlHashFree(ctxt->extFunctions, NULL);
669 * xsltStyleGetStylesheetExtData:
670 * @style: an XSLT stylesheet
671 * @URI: the URI associated to the exension module
673 * Fires the compile-time initialization callback
674 * of an extension module and returns a container
675 * holding the user-data (retrieved via the callback).
677 * Returns the create module-data container
678 * or NULL if such a module was not registered.
680 static xsltExtDataPtr
681 xsltStyleInitializeStylesheetModule(xsltStylesheetPtr style,
682 const xmlChar * URI)
684 xsltExtDataPtr dataContainer;
685 void *userData = NULL;
686 xsltExtModulePtr module;
688 if ((style == NULL) || (URI == NULL))
689 return(NULL);
691 if (xsltExtensionsHash == NULL) {
692 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
693 xsltGenericDebug(xsltGenericDebugContext,
694 "Not registered extension module: %s\n", URI);
695 #endif
696 return(NULL);
699 xmlMutexLock(xsltExtMutex);
701 module = xmlHashLookup(xsltExtensionsHash, URI);
703 xmlMutexUnlock(xsltExtMutex);
705 if (module == NULL) {
706 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
707 xsltGenericDebug(xsltGenericDebugContext,
708 "Not registered extension module: %s\n", URI);
709 #endif
710 return (NULL);
713 * The specified module was registered so initialize it.
715 if (style->extInfos == NULL) {
716 style->extInfos = xmlHashCreate(10);
717 if (style->extInfos == NULL)
718 return (NULL);
721 * Fire the initialization callback if available.
723 if (module->styleInitFunc == NULL) {
724 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
725 xsltGenericDebug(xsltGenericDebugContext,
726 "Initializing module with *no* callback: %s\n", URI);
727 #endif
728 } else {
729 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
730 xsltGenericDebug(xsltGenericDebugContext,
731 "Initializing module with callback: %s\n", URI);
732 #endif
734 * Fire the initialization callback.
736 userData = module->styleInitFunc(style, URI);
739 * Store the user-data in the context of the given stylesheet.
741 dataContainer = xsltNewExtData(module, userData);
742 if (dataContainer == NULL) {
743 if (module->styleShutdownFunc)
744 module->styleShutdownFunc(style, URI, userData);
745 return (NULL);
748 if (xmlHashAddEntry(style->extInfos, URI,
749 (void *) dataContainer) < 0)
751 xsltTransformError(NULL, style, NULL,
752 "Failed to register module '%s'.\n", URI);
753 style->errors++;
754 if (module->styleShutdownFunc)
755 module->styleShutdownFunc(style, URI, userData);
756 xsltFreeExtData(dataContainer);
757 return (NULL);
760 return(dataContainer);
764 * xsltStyleGetExtData:
765 * @style: an XSLT stylesheet
766 * @URI: the URI associated to the exension module
768 * Retrieve the data associated to the extension module
769 * in this given stylesheet.
770 * Called by:
771 * xsltRegisterExtPrefix(),
772 * ( xsltExtElementPreCompTest(), xsltExtInitTest )
774 * Returns the pointer or NULL if not present
776 void *
777 xsltStyleGetExtData(xsltStylesheetPtr style, const xmlChar * URI)
779 xsltExtDataPtr dataContainer = NULL;
780 xsltStylesheetPtr tmpStyle;
782 if ((style == NULL) || (URI == NULL) ||
783 (xsltExtensionsHash == NULL))
784 return (NULL);
787 #ifdef XSLT_REFACTORED
789 * This is intended for global storage, so only the main
790 * stylesheet will hold the data.
792 tmpStyle = style;
793 while (tmpStyle->parent != NULL)
794 tmpStyle = tmpStyle->parent;
795 if (tmpStyle->extInfos != NULL) {
796 dataContainer =
797 (xsltExtDataPtr) xmlHashLookup(tmpStyle->extInfos, URI);
798 if (dataContainer != NULL) {
800 * The module was already initialized in the context
801 * of this stylesheet; just return the user-data that
802 * comes with it.
804 return(dataContainer->extData);
807 #else
809 * Old behaviour.
811 tmpStyle = style;
812 while (tmpStyle != NULL) {
813 if (tmpStyle->extInfos != NULL) {
814 dataContainer =
815 (xsltExtDataPtr) xmlHashLookup(tmpStyle->extInfos, URI);
816 if (dataContainer != NULL) {
817 return(dataContainer->extData);
820 tmpStyle = xsltNextImport(tmpStyle);
822 tmpStyle = style;
823 #endif
825 dataContainer =
826 xsltStyleInitializeStylesheetModule(tmpStyle, URI);
827 if (dataContainer != NULL)
828 return (dataContainer->extData);
829 return(NULL);
832 #ifdef XSLT_REFACTORED
834 * xsltStyleStylesheetLevelGetExtData:
835 * @style: an XSLT stylesheet
836 * @URI: the URI associated to the exension module
838 * Retrieve the data associated to the extension module in this given
839 * stylesheet.
841 * Returns the pointer or NULL if not present
843 void *
844 xsltStyleStylesheetLevelGetExtData(xsltStylesheetPtr style,
845 const xmlChar * URI)
847 xsltExtDataPtr dataContainer = NULL;
849 if ((style == NULL) || (URI == NULL) ||
850 (xsltExtensionsHash == NULL))
851 return (NULL);
853 if (style->extInfos != NULL) {
854 dataContainer = (xsltExtDataPtr) xmlHashLookup(style->extInfos, URI);
856 * The module was already initialized in the context
857 * of this stylesheet; just return the user-data that
858 * comes with it.
860 if (dataContainer)
861 return(dataContainer->extData);
864 dataContainer =
865 xsltStyleInitializeStylesheetModule(style, URI);
866 if (dataContainer != NULL)
867 return (dataContainer->extData);
868 return(NULL);
870 #endif
873 * xsltGetExtData:
874 * @ctxt: an XSLT transformation context
875 * @URI: the URI associated to the exension module
877 * Retrieve the data associated to the extension module in this given
878 * transformation.
880 * Returns the pointer or NULL if not present
882 void *
883 xsltGetExtData(xsltTransformContextPtr ctxt, const xmlChar * URI)
885 xsltExtDataPtr data;
887 if ((ctxt == NULL) || (URI == NULL))
888 return (NULL);
889 if (ctxt->extInfos == NULL) {
890 ctxt->extInfos = xmlHashCreate(10);
891 if (ctxt->extInfos == NULL)
892 return (NULL);
893 data = NULL;
894 } else {
895 data = (xsltExtDataPtr) xmlHashLookup(ctxt->extInfos, URI);
897 if (data == NULL) {
898 void *extData;
899 xsltExtModulePtr module;
901 xmlMutexLock(xsltExtMutex);
903 module = xmlHashLookup(xsltExtensionsHash, URI);
905 xmlMutexUnlock(xsltExtMutex);
907 if (module == NULL) {
908 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
909 xsltGenericDebug(xsltGenericDebugContext,
910 "Not registered extension module: %s\n", URI);
911 #endif
912 return (NULL);
913 } else {
914 if (module->initFunc == NULL)
915 return (NULL);
917 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
918 xsltGenericDebug(xsltGenericDebugContext,
919 "Initializing module: %s\n", URI);
920 #endif
922 extData = module->initFunc(ctxt, URI);
923 if (extData == NULL)
924 return (NULL);
926 data = xsltNewExtData(module, extData);
927 if ((data == NULL) ||
928 (xmlHashAddEntry(ctxt->extInfos, URI, (void *) data) < 0)) {
929 xsltTransformError(ctxt, NULL, NULL,
930 "Failed to register module data: %s\n",
931 URI);
932 if (module->shutdownFunc)
933 module->shutdownFunc(ctxt, URI, extData);
934 xsltFreeExtData(data);
935 return (NULL);
939 return (data->extData);
942 typedef struct _xsltInitExtCtxt xsltInitExtCtxt;
943 struct _xsltInitExtCtxt {
944 xsltTransformContextPtr ctxt;
945 int ret;
949 * xsltInitCtxtExt:
950 * @styleData: the registered stylesheet data for the module
951 * @ctxt: the XSLT transformation context + the return value
952 * @URI: the extension URI
954 * Initializes an extension module
956 static void
957 xsltInitCtxtExt(void *payload, void *data, const xmlChar * URI)
959 xsltExtDataPtr styleData = (xsltExtDataPtr) payload;
960 xsltInitExtCtxt *ctxt = (xsltInitExtCtxt *) data;
961 xsltExtModulePtr module;
962 xsltExtDataPtr ctxtData;
963 void *extData;
965 if ((styleData == NULL) || (ctxt == NULL) || (URI == NULL) ||
966 (ctxt->ret == -1)) {
967 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
968 xsltGenericDebug(xsltGenericDebugContext,
969 "xsltInitCtxtExt: NULL param or error\n");
970 #endif
971 return;
973 module = styleData->extModule;
974 if ((module == NULL) || (module->initFunc == NULL)) {
975 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
976 xsltGenericDebug(xsltGenericDebugContext,
977 "xsltInitCtxtExt: no module or no initFunc\n");
978 #endif
979 return;
982 ctxtData = (xsltExtDataPtr) xmlHashLookup(ctxt->ctxt->extInfos, URI);
983 if (ctxtData != NULL) {
984 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
985 xsltGenericDebug(xsltGenericDebugContext,
986 "xsltInitCtxtExt: already initialized\n");
987 #endif
988 return;
991 extData = module->initFunc(ctxt->ctxt, URI);
992 if (extData == NULL) {
993 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
994 xsltGenericDebug(xsltGenericDebugContext,
995 "xsltInitCtxtExt: no extData\n");
996 #endif
998 ctxtData = xsltNewExtData(module, extData);
999 if (ctxtData == NULL) {
1000 if (module->shutdownFunc)
1001 module->shutdownFunc(ctxt->ctxt, URI, extData);
1002 ctxt->ret = -1;
1003 return;
1006 if (ctxt->ctxt->extInfos == NULL)
1007 ctxt->ctxt->extInfos = xmlHashCreate(10);
1008 if (ctxt->ctxt->extInfos == NULL) {
1009 if (module->shutdownFunc)
1010 module->shutdownFunc(ctxt->ctxt, URI, extData);
1011 xsltFreeExtData(ctxtData);
1012 ctxt->ret = -1;
1013 return;
1016 if (xmlHashAddEntry(ctxt->ctxt->extInfos, URI, ctxtData) < 0) {
1017 xsltGenericError(xsltGenericErrorContext,
1018 "Failed to register module data: %s\n", URI);
1019 if (module->shutdownFunc)
1020 module->shutdownFunc(ctxt->ctxt, URI, extData);
1021 xsltFreeExtData(ctxtData);
1022 ctxt->ret = -1;
1023 return;
1025 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
1026 xsltGenericDebug(xsltGenericDebugContext, "Registered module %s\n",
1027 URI);
1028 #endif
1029 ctxt->ret++;
1033 * xsltInitCtxtExts:
1034 * @ctxt: an XSLT transformation context
1036 * Initialize the set of modules with registered stylesheet data
1038 * Returns the number of modules initialized or -1 in case of error
1041 xsltInitCtxtExts(xsltTransformContextPtr ctxt)
1043 xsltStylesheetPtr style;
1044 xsltInitExtCtxt ctx;
1046 if (ctxt == NULL)
1047 return (-1);
1049 style = ctxt->style;
1050 if (style == NULL)
1051 return (-1);
1053 ctx.ctxt = ctxt;
1054 ctx.ret = 0;
1056 while (style != NULL) {
1057 if (style->extInfos != NULL) {
1058 xmlHashScan(style->extInfos, xsltInitCtxtExt, &ctx);
1059 if (ctx.ret == -1)
1060 return (-1);
1062 style = xsltNextImport(style);
1064 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
1065 xsltGenericDebug(xsltGenericDebugContext, "Registered %d modules\n",
1066 ctx.ret);
1067 #endif
1068 return (ctx.ret);
1072 * xsltShutdownCtxtExt:
1073 * @data: the registered data for the module
1074 * @ctxt: the XSLT transformation context
1075 * @URI: the extension URI
1077 * Shutdown an extension module loaded
1079 static void
1080 xsltShutdownCtxtExt(void *payload, void *vctxt, const xmlChar * URI)
1082 xsltExtDataPtr data = (xsltExtDataPtr) payload;
1083 xsltTransformContextPtr ctxt = (xsltTransformContextPtr) vctxt;
1084 xsltExtModulePtr module;
1086 if ((data == NULL) || (ctxt == NULL) || (URI == NULL))
1087 return;
1088 module = data->extModule;
1089 if ((module == NULL) || (module->shutdownFunc == NULL))
1090 return;
1092 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
1093 xsltGenericDebug(xsltGenericDebugContext,
1094 "Shutting down module : %s\n", URI);
1095 #endif
1096 module->shutdownFunc(ctxt, URI, data->extData);
1100 * xsltShutdownCtxtExts:
1101 * @ctxt: an XSLT transformation context
1103 * Shutdown the set of modules loaded
1105 void
1106 xsltShutdownCtxtExts(xsltTransformContextPtr ctxt)
1108 if (ctxt == NULL)
1109 return;
1110 if (ctxt->extInfos == NULL)
1111 return;
1112 xmlHashScan(ctxt->extInfos, xsltShutdownCtxtExt, ctxt);
1113 xmlHashFree(ctxt->extInfos, xsltFreeExtDataEntry);
1114 ctxt->extInfos = NULL;
1118 * xsltShutdownExt:
1119 * @data: the registered data for the module
1120 * @ctxt: the XSLT stylesheet
1121 * @URI: the extension URI
1123 * Shutdown an extension module loaded
1125 static void
1126 xsltShutdownExt(void *payload, void *vctxt, const xmlChar * URI)
1128 xsltExtDataPtr data = (xsltExtDataPtr) payload;
1129 xsltStylesheetPtr style = (xsltStylesheetPtr) vctxt;
1130 xsltExtModulePtr module;
1132 if ((data == NULL) || (style == NULL) || (URI == NULL))
1133 return;
1134 module = data->extModule;
1135 if ((module == NULL) || (module->styleShutdownFunc == NULL))
1136 return;
1138 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
1139 xsltGenericDebug(xsltGenericDebugContext,
1140 "Shutting down module : %s\n", URI);
1141 #endif
1142 module->styleShutdownFunc(style, URI, data->extData);
1144 * Don't remove the entry from the hash table here, since
1145 * this will produce segfaults - this fixes bug #340624.
1147 * xmlHashRemoveEntry(style->extInfos, URI, xsltFreeExtDataEntry);
1152 * xsltShutdownExts:
1153 * @style: an XSLT stylesheet
1155 * Shutdown the set of modules loaded
1157 void
1158 xsltShutdownExts(xsltStylesheetPtr style)
1160 if (style == NULL)
1161 return;
1162 if (style->extInfos == NULL)
1163 return;
1164 xmlHashScan(style->extInfos, xsltShutdownExt, style);
1165 xmlHashFree(style->extInfos, xsltFreeExtDataEntry);
1166 style->extInfos = NULL;
1170 * xsltCheckExtPrefix:
1171 * @style: the stylesheet
1172 * @URI: the namespace prefix (possibly NULL)
1174 * Check if the given prefix is one of the declared extensions.
1175 * This is intended to be called only at compile-time.
1176 * Called by:
1177 * xsltGetInheritedNsList() (xslt.c)
1178 * xsltParseTemplateContent (xslt.c)
1180 * Returns 1 if this is an extension, 0 otherwise
1183 xsltCheckExtPrefix(xsltStylesheetPtr style, const xmlChar * URI)
1185 #ifdef XSLT_REFACTORED
1186 if ((style == NULL) || (style->compCtxt == NULL) ||
1187 (XSLT_CCTXT(style)->inode == NULL) ||
1188 (XSLT_CCTXT(style)->inode->extElemNs == NULL))
1189 return (0);
1191 * Lookup the extension namespaces registered
1192 * at the current node in the stylesheet's tree.
1194 if (XSLT_CCTXT(style)->inode->extElemNs != NULL) {
1195 int i;
1196 xsltPointerListPtr list = XSLT_CCTXT(style)->inode->extElemNs;
1198 for (i = 0; i < list->number; i++) {
1199 if (xmlStrEqual((const xmlChar *) list->items[i],
1200 URI))
1202 return(1);
1206 #else
1207 xsltExtDefPtr cur;
1209 if ((style == NULL) || (style->nsDefs == NULL))
1210 return (0);
1211 if (URI == NULL)
1212 URI = BAD_CAST "#default";
1213 cur = (xsltExtDefPtr) style->nsDefs;
1214 while (cur != NULL) {
1216 * NOTE: This was change to work on namespace names rather
1217 * than namespace prefixes. This fixes bug #339583.
1218 * TODO: Consider renaming the field "prefix" of xsltExtDef
1219 * to "href".
1221 if (xmlStrEqual(URI, cur->prefix))
1222 return (1);
1223 cur = cur->next;
1225 #endif
1226 return (0);
1230 * xsltCheckExtURI:
1231 * @style: the stylesheet
1232 * @URI: the namespace URI (possibly NULL)
1234 * Check if the given prefix is one of the declared extensions.
1235 * This is intended to be called only at compile-time.
1236 * Called by:
1237 * xsltPrecomputeStylesheet() (xslt.c)
1238 * xsltParseTemplateContent (xslt.c)
1240 * Returns 1 if this is an extension, 0 otherwise
1243 xsltCheckExtURI(xsltStylesheetPtr style, const xmlChar * URI)
1245 xsltExtDefPtr cur;
1247 if ((style == NULL) || (style->nsDefs == NULL))
1248 return (0);
1249 if (URI == NULL)
1250 return (0);
1251 cur = (xsltExtDefPtr) style->nsDefs;
1252 while (cur != NULL) {
1253 if (xmlStrEqual(URI, cur->URI))
1254 return (1);
1255 cur = cur->next;
1257 return (0);
1261 * xsltRegisterExtModuleFull:
1262 * @URI: URI associated to this module
1263 * @initFunc: the module initialization function
1264 * @shutdownFunc: the module shutdown function
1265 * @styleInitFunc: the module initialization function
1266 * @styleShutdownFunc: the module shutdown function
1268 * Register an XSLT extension module to the library.
1270 * Returns 0 if sucessful, -1 in case of error
1273 xsltRegisterExtModuleFull(const xmlChar * URI,
1274 xsltExtInitFunction initFunc,
1275 xsltExtShutdownFunction shutdownFunc,
1276 xsltStyleExtInitFunction styleInitFunc,
1277 xsltStyleExtShutdownFunction styleShutdownFunc)
1279 int ret;
1280 xsltExtModulePtr module;
1282 if ((URI == NULL) || (initFunc == NULL))
1283 return (-1);
1284 if (xsltExtensionsHash == NULL)
1285 xsltExtensionsHash = xmlHashCreate(10);
1287 if (xsltExtensionsHash == NULL)
1288 return (-1);
1290 xmlMutexLock(xsltExtMutex);
1292 module = xmlHashLookup(xsltExtensionsHash, URI);
1293 if (module != NULL) {
1294 if ((module->initFunc == initFunc) &&
1295 (module->shutdownFunc == shutdownFunc))
1296 ret = 0;
1297 else
1298 ret = -1;
1299 goto done;
1301 module = xsltNewExtModule(initFunc, shutdownFunc,
1302 styleInitFunc, styleShutdownFunc);
1303 if (module == NULL) {
1304 ret = -1;
1305 goto done;
1307 ret = xmlHashAddEntry(xsltExtensionsHash, URI, (void *) module);
1309 done:
1310 xmlMutexUnlock(xsltExtMutex);
1311 return (ret);
1315 * xsltRegisterExtModule:
1316 * @URI: URI associated to this module
1317 * @initFunc: the module initialization function
1318 * @shutdownFunc: the module shutdown function
1320 * Register an XSLT extension module to the library.
1322 * Returns 0 if sucessful, -1 in case of error
1325 xsltRegisterExtModule(const xmlChar * URI,
1326 xsltExtInitFunction initFunc,
1327 xsltExtShutdownFunction shutdownFunc)
1329 return xsltRegisterExtModuleFull(URI, initFunc, shutdownFunc,
1330 NULL, NULL);
1334 * xsltUnregisterExtModule:
1335 * @URI: URI associated to this module
1337 * Unregister an XSLT extension module from the library.
1339 * Returns 0 if sucessful, -1 in case of error
1342 xsltUnregisterExtModule(const xmlChar * URI)
1344 int ret;
1346 if (URI == NULL)
1347 return (-1);
1348 if (xsltExtensionsHash == NULL)
1349 return (-1);
1351 xmlMutexLock(xsltExtMutex);
1353 ret = xmlHashRemoveEntry(xsltExtensionsHash, URI, xsltFreeExtModuleEntry);
1355 xmlMutexUnlock(xsltExtMutex);
1357 return (ret);
1361 * xsltUnregisterAllExtModules:
1363 * Unregister all the XSLT extension module from the library.
1365 static void
1366 xsltUnregisterAllExtModules(void)
1368 if (xsltExtensionsHash == NULL)
1369 return;
1371 xmlMutexLock(xsltExtMutex);
1373 xmlHashFree(xsltExtensionsHash, xsltFreeExtModuleEntry);
1374 xsltExtensionsHash = NULL;
1376 xmlMutexUnlock(xsltExtMutex);
1380 * xsltXPathGetTransformContext:
1381 * @ctxt: an XPath transformation context
1383 * Provides the XSLT transformation context from the XPath transformation
1384 * context. This is useful when an XPath function in the extension module
1385 * is called by the XPath interpreter and that the XSLT context is needed
1386 * for example to retrieve the associated data pertaining to this XSLT
1387 * transformation.
1389 * Returns the XSLT transformation context or NULL in case of error.
1391 xsltTransformContextPtr
1392 xsltXPathGetTransformContext(xmlXPathParserContextPtr ctxt)
1394 if ((ctxt == NULL) || (ctxt->context == NULL))
1395 return (NULL);
1396 return (ctxt->context->extra);
1400 * xsltRegisterExtModuleFunction:
1401 * @name: the function name
1402 * @URI: the function namespace URI
1403 * @function: the function callback
1405 * Registers an extension module function.
1407 * Returns 0 if successful, -1 in case of error.
1410 xsltRegisterExtModuleFunction(const xmlChar * name, const xmlChar * URI,
1411 xmlXPathFunction function)
1413 if ((name == NULL) || (URI == NULL) || (function == NULL))
1414 return (-1);
1416 if (xsltFunctionsHash == NULL)
1417 xsltFunctionsHash = xmlHashCreate(10);
1418 if (xsltFunctionsHash == NULL)
1419 return (-1);
1421 xmlMutexLock(xsltExtMutex);
1423 xmlHashUpdateEntry2(xsltFunctionsHash, name, URI,
1424 XML_CAST_FPTR(function), NULL);
1426 xmlMutexUnlock(xsltExtMutex);
1428 return (0);
1432 * xsltExtModuleFunctionLookup:
1433 * @name: the function name
1434 * @URI: the function namespace URI
1436 * Looks up an extension module function
1438 * Returns the function if found, NULL otherwise.
1440 xmlXPathFunction
1441 xsltExtModuleFunctionLookup(const xmlChar * name, const xmlChar * URI)
1443 xmlXPathFunction ret;
1445 if ((xsltFunctionsHash == NULL) || (name == NULL) || (URI == NULL))
1446 return (NULL);
1448 xmlMutexLock(xsltExtMutex);
1450 XML_CAST_FPTR(ret) = xmlHashLookup2(xsltFunctionsHash, name, URI);
1452 xmlMutexUnlock(xsltExtMutex);
1454 /* if lookup fails, attempt a dynamic load on supported platforms */
1455 if (NULL == ret) {
1456 if (!xsltExtModuleRegisterDynamic(URI)) {
1457 xmlMutexLock(xsltExtMutex);
1459 XML_CAST_FPTR(ret) =
1460 xmlHashLookup2(xsltFunctionsHash, name, URI);
1462 xmlMutexUnlock(xsltExtMutex);
1466 return ret;
1470 * xsltUnregisterExtModuleFunction:
1471 * @name: the function name
1472 * @URI: the function namespace URI
1474 * Unregisters an extension module function
1476 * Returns 0 if successful, -1 in case of error.
1479 xsltUnregisterExtModuleFunction(const xmlChar * name, const xmlChar * URI)
1481 int ret;
1483 if ((xsltFunctionsHash == NULL) || (name == NULL) || (URI == NULL))
1484 return (-1);
1486 xmlMutexLock(xsltExtMutex);
1488 ret = xmlHashRemoveEntry2(xsltFunctionsHash, name, URI, NULL);
1490 xmlMutexUnlock(xsltExtMutex);
1492 return(ret);
1496 * xsltUnregisterAllExtModuleFunction:
1498 * Unregisters all extension module function
1500 static void
1501 xsltUnregisterAllExtModuleFunction(void)
1503 xmlMutexLock(xsltExtMutex);
1505 xmlHashFree(xsltFunctionsHash, NULL);
1506 xsltFunctionsHash = NULL;
1508 xmlMutexUnlock(xsltExtMutex);
1512 static void
1513 xsltFreeElemPreComp(xsltElemPreCompPtr comp) {
1514 xmlFree(comp);
1518 * xsltNewElemPreComp:
1519 * @style: the XSLT stylesheet
1520 * @inst: the element node
1521 * @function: the transform function
1523 * Creates and initializes an #xsltElemPreComp
1525 * Returns the new and initialized #xsltElemPreComp
1527 xsltElemPreCompPtr
1528 xsltNewElemPreComp(xsltStylesheetPtr style, xmlNodePtr inst,
1529 xsltTransformFunction function)
1531 xsltElemPreCompPtr cur;
1533 cur = (xsltElemPreCompPtr) xmlMalloc(sizeof(xsltElemPreComp));
1534 if (cur == NULL) {
1535 xsltTransformError(NULL, style, NULL,
1536 "xsltNewExtElement : malloc failed\n");
1537 return (NULL);
1539 memset(cur, 0, sizeof(xsltElemPreComp));
1541 xsltInitElemPreComp(cur, style, inst, function, xsltFreeElemPreComp);
1543 return (cur);
1547 * xsltInitElemPreComp:
1548 * @comp: an #xsltElemPreComp (or generally a derived structure)
1549 * @style: the XSLT stylesheet
1550 * @inst: the element node
1551 * @function: the transform function
1552 * @freeFunc: the @comp deallocator
1554 * Initializes an existing #xsltElemPreComp structure. This is usefull
1555 * when extending an #xsltElemPreComp to store precomputed data.
1556 * This function MUST be called on any extension element precomputed
1557 * data struct.
1559 void
1560 xsltInitElemPreComp(xsltElemPreCompPtr comp, xsltStylesheetPtr style,
1561 xmlNodePtr inst, xsltTransformFunction function,
1562 xsltElemPreCompDeallocator freeFunc)
1564 comp->type = XSLT_FUNC_EXTENSION;
1565 comp->func = function;
1566 comp->inst = inst;
1567 comp->free = freeFunc;
1569 comp->next = style->preComps;
1570 style->preComps = comp;
1574 * xsltPreComputeExtModuleElement:
1575 * @style: the stylesheet
1576 * @inst: the element node
1578 * Precomputes an extension module element
1580 * Returns the precomputed data
1582 xsltElemPreCompPtr
1583 xsltPreComputeExtModuleElement(xsltStylesheetPtr style, xmlNodePtr inst)
1585 xsltExtElementPtr ext;
1586 xsltElemPreCompPtr comp = NULL;
1588 if ((style == NULL) || (inst == NULL) ||
1589 (inst->type != XML_ELEMENT_NODE) || (inst->ns == NULL))
1590 return (NULL);
1592 xmlMutexLock(xsltExtMutex);
1594 ext = (xsltExtElementPtr)
1595 xmlHashLookup2(xsltElementsHash, inst->name, inst->ns->href);
1597 xmlMutexUnlock(xsltExtMutex);
1600 * EXT TODO: Now what?
1602 if (ext == NULL)
1603 return (NULL);
1605 if (ext->precomp != NULL) {
1607 * REVISIT TODO: Check if the text below is correct.
1608 * This will return a xsltElemPreComp structure or NULL.
1609 * 1) If the the author of the extension needs a
1610 * custom structure to hold the specific values of
1611 * this extension, he will derive a structure based on
1612 * xsltElemPreComp; thus we obviously *cannot* refactor
1613 * the xsltElemPreComp structure, since all already derived
1614 * user-defined strucures will break.
1615 * Example: For the extension xsl:document,
1616 * in xsltDocumentComp() (preproc.c), the structure
1617 * xsltStyleItemDocument is allocated, filled with
1618 * specific values and returned.
1619 * 2) If the author needs no values to be stored in
1620 * this structure, then he'll return NULL;
1622 comp = ext->precomp(style, inst, ext->transform);
1624 if (comp == NULL) {
1626 * Default creation of a xsltElemPreComp structure, if
1627 * the author of this extension did not create a custom
1628 * structure.
1630 comp = xsltNewElemPreComp(style, inst, ext->transform);
1633 return (comp);
1637 * xsltRegisterExtModuleElement:
1638 * @name: the element name
1639 * @URI: the element namespace URI
1640 * @precomp: the pre-computation callback
1641 * @transform: the transformation callback
1643 * Registers an extension module element.
1645 * Returns 0 if successful, -1 in case of error.
1648 xsltRegisterExtModuleElement(const xmlChar * name, const xmlChar * URI,
1649 xsltPreComputeFunction precomp,
1650 xsltTransformFunction transform)
1652 int ret = 0;
1654 xsltExtElementPtr ext;
1656 if ((name == NULL) || (URI == NULL) || (transform == NULL))
1657 return (-1);
1659 if (xsltElementsHash == NULL)
1660 xsltElementsHash = xmlHashCreate(10);
1661 if (xsltElementsHash == NULL)
1662 return (-1);
1664 xmlMutexLock(xsltExtMutex);
1666 ext = xsltNewExtElement(precomp, transform);
1667 if (ext == NULL) {
1668 ret = -1;
1669 goto done;
1672 xmlHashUpdateEntry2(xsltElementsHash, name, URI, (void *) ext,
1673 xsltFreeExtElementEntry);
1675 done:
1676 xmlMutexUnlock(xsltExtMutex);
1678 return (ret);
1682 * xsltExtElementLookup:
1683 * @ctxt: an XSLT process context
1684 * @name: the element name
1685 * @URI: the element namespace URI
1687 * Looks up an extension element. @ctxt can be NULL to search only in
1688 * module elements.
1690 * Returns the element callback or NULL if not found
1692 xsltTransformFunction
1693 xsltExtElementLookup(xsltTransformContextPtr ctxt,
1694 const xmlChar * name, const xmlChar * URI)
1696 xsltTransformFunction ret;
1698 if ((name == NULL) || (URI == NULL))
1699 return (NULL);
1701 if ((ctxt != NULL) && (ctxt->extElements != NULL)) {
1702 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->extElements, name, URI);
1703 if (ret != NULL) {
1704 return(ret);
1708 ret = xsltExtModuleElementLookup(name, URI);
1710 return (ret);
1714 * xsltExtModuleElementLookup:
1715 * @name: the element name
1716 * @URI: the element namespace URI
1718 * Looks up an extension module element
1720 * Returns the callback function if found, NULL otherwise.
1722 xsltTransformFunction
1723 xsltExtModuleElementLookup(const xmlChar * name, const xmlChar * URI)
1725 xsltExtElementPtr ext;
1727 if ((xsltElementsHash == NULL) || (name == NULL) || (URI == NULL))
1728 return (NULL);
1730 xmlMutexLock(xsltExtMutex);
1732 ext = (xsltExtElementPtr) xmlHashLookup2(xsltElementsHash, name, URI);
1734 xmlMutexUnlock(xsltExtMutex);
1737 * if function lookup fails, attempt a dynamic load on
1738 * supported platforms
1740 if (NULL == ext) {
1741 if (!xsltExtModuleRegisterDynamic(URI)) {
1742 xmlMutexLock(xsltExtMutex);
1744 ext = (xsltExtElementPtr)
1745 xmlHashLookup2(xsltElementsHash, name, URI);
1747 xmlMutexUnlock(xsltExtMutex);
1751 if (ext == NULL)
1752 return (NULL);
1753 return (ext->transform);
1757 * xsltExtModuleElementPreComputeLookup:
1758 * @name: the element name
1759 * @URI: the element namespace URI
1761 * Looks up an extension module element pre-computation function
1763 * Returns the callback function if found, NULL otherwise.
1765 xsltPreComputeFunction
1766 xsltExtModuleElementPreComputeLookup(const xmlChar * name,
1767 const xmlChar * URI)
1769 xsltExtElementPtr ext;
1771 if ((xsltElementsHash == NULL) || (name == NULL) || (URI == NULL))
1772 return (NULL);
1774 xmlMutexLock(xsltExtMutex);
1776 ext = (xsltExtElementPtr) xmlHashLookup2(xsltElementsHash, name, URI);
1778 xmlMutexUnlock(xsltExtMutex);
1780 if (ext == NULL) {
1781 if (!xsltExtModuleRegisterDynamic(URI)) {
1782 xmlMutexLock(xsltExtMutex);
1784 ext = (xsltExtElementPtr)
1785 xmlHashLookup2(xsltElementsHash, name, URI);
1787 xmlMutexUnlock(xsltExtMutex);
1791 if (ext == NULL)
1792 return (NULL);
1793 return (ext->precomp);
1797 * xsltUnregisterExtModuleElement:
1798 * @name: the element name
1799 * @URI: the element namespace URI
1801 * Unregisters an extension module element
1803 * Returns 0 if successful, -1 in case of error.
1806 xsltUnregisterExtModuleElement(const xmlChar * name, const xmlChar * URI)
1808 int ret;
1810 if ((xsltElementsHash == NULL) || (name == NULL) || (URI == NULL))
1811 return (-1);
1813 xmlMutexLock(xsltExtMutex);
1815 ret = xmlHashRemoveEntry2(xsltElementsHash, name, URI,
1816 xsltFreeExtElementEntry);
1818 xmlMutexUnlock(xsltExtMutex);
1820 return(ret);
1824 * xsltUnregisterAllExtModuleElement:
1826 * Unregisters all extension module element
1828 static void
1829 xsltUnregisterAllExtModuleElement(void)
1831 xmlMutexLock(xsltExtMutex);
1833 xmlHashFree(xsltElementsHash, xsltFreeExtElementEntry);
1834 xsltElementsHash = NULL;
1836 xmlMutexUnlock(xsltExtMutex);
1840 * xsltRegisterExtModuleTopLevel:
1841 * @name: the top-level element name
1842 * @URI: the top-level element namespace URI
1843 * @function: the top-level element callback
1845 * Registers an extension module top-level element.
1847 * Returns 0 if successful, -1 in case of error.
1850 xsltRegisterExtModuleTopLevel(const xmlChar * name, const xmlChar * URI,
1851 xsltTopLevelFunction function)
1853 if ((name == NULL) || (URI == NULL) || (function == NULL))
1854 return (-1);
1856 if (xsltTopLevelsHash == NULL)
1857 xsltTopLevelsHash = xmlHashCreate(10);
1858 if (xsltTopLevelsHash == NULL)
1859 return (-1);
1861 xmlMutexLock(xsltExtMutex);
1863 xmlHashUpdateEntry2(xsltTopLevelsHash, name, URI,
1864 XML_CAST_FPTR(function), NULL);
1866 xmlMutexUnlock(xsltExtMutex);
1868 return (0);
1872 * xsltExtModuleTopLevelLookup:
1873 * @name: the top-level element name
1874 * @URI: the top-level element namespace URI
1876 * Looks up an extension module top-level element
1878 * Returns the callback function if found, NULL otherwise.
1880 xsltTopLevelFunction
1881 xsltExtModuleTopLevelLookup(const xmlChar * name, const xmlChar * URI)
1883 xsltTopLevelFunction ret;
1885 if ((xsltTopLevelsHash == NULL) || (name == NULL) || (URI == NULL))
1886 return (NULL);
1888 xmlMutexLock(xsltExtMutex);
1890 XML_CAST_FPTR(ret) = xmlHashLookup2(xsltTopLevelsHash, name, URI);
1892 xmlMutexUnlock(xsltExtMutex);
1894 /* if lookup fails, attempt a dynamic load on supported platforms */
1895 if (NULL == ret) {
1896 if (!xsltExtModuleRegisterDynamic(URI)) {
1897 xmlMutexLock(xsltExtMutex);
1899 XML_CAST_FPTR(ret) = xmlHashLookup2(xsltTopLevelsHash, name, URI);
1901 xmlMutexUnlock(xsltExtMutex);
1905 return (ret);
1909 * xsltUnregisterExtModuleTopLevel:
1910 * @name: the top-level element name
1911 * @URI: the top-level element namespace URI
1913 * Unregisters an extension module top-level element
1915 * Returns 0 if successful, -1 in case of error.
1918 xsltUnregisterExtModuleTopLevel(const xmlChar * name, const xmlChar * URI)
1920 int ret;
1922 if ((xsltTopLevelsHash == NULL) || (name == NULL) || (URI == NULL))
1923 return (-1);
1925 xmlMutexLock(xsltExtMutex);
1927 ret = xmlHashRemoveEntry2(xsltTopLevelsHash, name, URI, NULL);
1929 xmlMutexUnlock(xsltExtMutex);
1931 return(ret);
1935 * xsltUnregisterAllExtModuleTopLevel:
1937 * Unregisters all extension module function
1939 static void
1940 xsltUnregisterAllExtModuleTopLevel(void)
1942 xmlMutexLock(xsltExtMutex);
1944 xmlHashFree(xsltTopLevelsHash, NULL);
1945 xsltTopLevelsHash = NULL;
1947 xmlMutexUnlock(xsltExtMutex);
1951 * xsltGetExtInfo:
1952 * @style: pointer to a stylesheet
1953 * @URI: the namespace URI desired
1955 * looks up URI in extInfos of the stylesheet
1957 * returns a pointer to the hash table if found, else NULL
1959 xmlHashTablePtr
1960 xsltGetExtInfo(xsltStylesheetPtr style, const xmlChar * URI)
1962 xsltExtDataPtr data;
1965 * TODO: Why do we have a return type of xmlHashTablePtr?
1966 * Is the user-allocated data for extension modules expected
1967 * to be a xmlHashTablePtr only? Or is this intended for
1968 * the EXSLT module only?
1971 if (style != NULL && style->extInfos != NULL) {
1972 data = xmlHashLookup(style->extInfos, URI);
1973 if (data != NULL && data->extData != NULL)
1974 return data->extData;
1976 return NULL;
1979 /************************************************************************
1981 * Test of the extension module API *
1983 ************************************************************************/
1985 static xmlChar *testData = NULL;
1986 static xmlChar *testStyleData = NULL;
1989 * xsltExtFunctionTest:
1990 * @ctxt: the XPath Parser context
1991 * @nargs: the number of arguments
1993 * function libxslt:test() for testing the extensions support.
1995 static void
1996 xsltExtFunctionTest(xmlXPathParserContextPtr ctxt,
1997 int nargs ATTRIBUTE_UNUSED)
1999 xsltTransformContextPtr tctxt;
2000 void *data = NULL;
2002 tctxt = xsltXPathGetTransformContext(ctxt);
2004 if (testData == NULL) {
2005 xsltGenericDebug(xsltGenericDebugContext,
2006 "xsltExtFunctionTest: not initialized,"
2007 " calling xsltGetExtData\n");
2008 data = xsltGetExtData(tctxt, (const xmlChar *) XSLT_DEFAULT_URL);
2009 if (data == NULL) {
2010 xsltTransformError(tctxt, NULL, NULL,
2011 "xsltExtElementTest: not initialized\n");
2012 return;
2015 if (tctxt == NULL) {
2016 xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
2017 "xsltExtFunctionTest: failed to get the transformation context\n");
2018 return;
2020 if (data == NULL)
2021 data = xsltGetExtData(tctxt, (const xmlChar *) XSLT_DEFAULT_URL);
2022 if (data == NULL) {
2023 xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
2024 "xsltExtFunctionTest: failed to get module data\n");
2025 return;
2027 if (data != testData) {
2028 xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
2029 "xsltExtFunctionTest: got wrong module data\n");
2030 return;
2032 #ifdef WITH_XSLT_DEBUG_FUNCTION
2033 xsltGenericDebug(xsltGenericDebugContext,
2034 "libxslt:test() called with %d args\n", nargs);
2035 #endif
2039 * xsltExtElementPreCompTest:
2040 * @style: the stylesheet
2041 * @inst: the instruction in the stylesheet
2043 * Process a libxslt:test node
2045 static xsltElemPreCompPtr
2046 xsltExtElementPreCompTest(xsltStylesheetPtr style, xmlNodePtr inst,
2047 xsltTransformFunction function)
2049 xsltElemPreCompPtr ret;
2051 if (style == NULL) {
2052 xsltTransformError(NULL, NULL, inst,
2053 "xsltExtElementTest: no transformation context\n");
2054 return (NULL);
2056 if (testStyleData == NULL) {
2057 xsltGenericDebug(xsltGenericDebugContext,
2058 "xsltExtElementPreCompTest: not initialized,"
2059 " calling xsltStyleGetExtData\n");
2060 xsltStyleGetExtData(style, (const xmlChar *) XSLT_DEFAULT_URL);
2061 if (testStyleData == NULL) {
2062 xsltTransformError(NULL, style, inst,
2063 "xsltExtElementPreCompTest: not initialized\n");
2064 if (style != NULL)
2065 style->errors++;
2066 return (NULL);
2069 if (inst == NULL) {
2070 xsltTransformError(NULL, style, inst,
2071 "xsltExtElementPreCompTest: no instruction\n");
2072 if (style != NULL)
2073 style->errors++;
2074 return (NULL);
2076 ret = xsltNewElemPreComp(style, inst, function);
2077 return (ret);
2081 * xsltExtElementTest:
2082 * @ctxt: an XSLT processing context
2083 * @node: The current node
2084 * @inst: the instruction in the stylesheet
2085 * @comp: precomputed information
2087 * Process a libxslt:test node
2089 static void
2090 xsltExtElementTest(xsltTransformContextPtr ctxt, xmlNodePtr node,
2091 xmlNodePtr inst,
2092 xsltElemPreCompPtr comp ATTRIBUTE_UNUSED)
2094 xmlNodePtr commentNode;
2096 if (testData == NULL) {
2097 xsltGenericDebug(xsltGenericDebugContext,
2098 "xsltExtElementTest: not initialized,"
2099 " calling xsltGetExtData\n");
2100 xsltGetExtData(ctxt, (const xmlChar *) XSLT_DEFAULT_URL);
2101 if (testData == NULL) {
2102 xsltTransformError(ctxt, NULL, inst,
2103 "xsltExtElementTest: not initialized\n");
2104 return;
2107 if (ctxt == NULL) {
2108 xsltTransformError(ctxt, NULL, inst,
2109 "xsltExtElementTest: no transformation context\n");
2110 return;
2112 if (node == NULL) {
2113 xsltTransformError(ctxt, NULL, inst,
2114 "xsltExtElementTest: no current node\n");
2115 return;
2117 if (inst == NULL) {
2118 xsltTransformError(ctxt, NULL, inst,
2119 "xsltExtElementTest: no instruction\n");
2120 return;
2122 if (ctxt->insert == NULL) {
2123 xsltTransformError(ctxt, NULL, inst,
2124 "xsltExtElementTest: no insertion point\n");
2125 return;
2127 commentNode = xmlNewComment((const xmlChar *)
2128 "libxslt:test element test worked");
2129 xmlAddChild(ctxt->insert, commentNode);
2133 * xsltExtInitTest:
2134 * @ctxt: an XSLT transformation context
2135 * @URI: the namespace URI for the extension
2137 * A function called at initialization time of an XSLT extension module
2139 * Returns a pointer to the module specific data for this transformation
2141 static void *
2142 xsltExtInitTest(xsltTransformContextPtr ctxt, const xmlChar * URI)
2144 if (testStyleData == NULL) {
2145 xsltGenericDebug(xsltGenericErrorContext,
2146 "xsltExtInitTest: not initialized,"
2147 " calling xsltStyleGetExtData\n");
2148 testStyleData = xsltStyleGetExtData(ctxt->style, URI);
2149 if (testStyleData == NULL) {
2150 xsltTransformError(ctxt, NULL, NULL,
2151 "xsltExtInitTest: not initialized\n");
2152 return (NULL);
2155 if (testData != NULL) {
2156 xsltTransformError(ctxt, NULL, NULL,
2157 "xsltExtInitTest: already initialized\n");
2158 return (NULL);
2160 testData = (void *) "test data";
2161 xsltGenericDebug(xsltGenericDebugContext,
2162 "Registered test module : %s\n", URI);
2163 return (testData);
2168 * xsltExtShutdownTest:
2169 * @ctxt: an XSLT transformation context
2170 * @URI: the namespace URI for the extension
2171 * @data: the data associated to this module
2173 * A function called at shutdown time of an XSLT extension module
2175 static void
2176 xsltExtShutdownTest(xsltTransformContextPtr ctxt,
2177 const xmlChar * URI, void *data)
2179 if (testData == NULL) {
2180 xsltTransformError(ctxt, NULL, NULL,
2181 "xsltExtShutdownTest: not initialized\n");
2182 return;
2184 if (data != testData) {
2185 xsltTransformError(ctxt, NULL, NULL,
2186 "xsltExtShutdownTest: wrong data\n");
2188 testData = NULL;
2189 xsltGenericDebug(xsltGenericDebugContext,
2190 "Unregistered test module : %s\n", URI);
2194 * xsltExtStyleInitTest:
2195 * @style: an XSLT stylesheet
2196 * @URI: the namespace URI for the extension
2198 * A function called at initialization time of an XSLT extension module
2200 * Returns a pointer to the module specific data for this transformation
2202 static void *
2203 xsltExtStyleInitTest(xsltStylesheetPtr style ATTRIBUTE_UNUSED,
2204 const xmlChar * URI)
2206 if (testStyleData != NULL) {
2207 xsltTransformError(NULL, NULL, NULL,
2208 "xsltExtInitTest: already initialized\n");
2209 return (NULL);
2211 testStyleData = (void *) "test data";
2212 xsltGenericDebug(xsltGenericDebugContext,
2213 "Registered test module : %s\n", URI);
2214 return (testStyleData);
2219 * xsltExtStyleShutdownTest:
2220 * @style: an XSLT stylesheet
2221 * @URI: the namespace URI for the extension
2222 * @data: the data associated to this module
2224 * A function called at shutdown time of an XSLT extension module
2226 static void
2227 xsltExtStyleShutdownTest(xsltStylesheetPtr style ATTRIBUTE_UNUSED,
2228 const xmlChar * URI, void *data)
2230 if (testStyleData == NULL) {
2231 xsltGenericError(xsltGenericErrorContext,
2232 "xsltExtShutdownTest: not initialized\n");
2233 return;
2235 if (data != testStyleData) {
2236 xsltTransformError(NULL, NULL, NULL,
2237 "xsltExtShutdownTest: wrong data\n");
2239 testStyleData = NULL;
2240 xsltGenericDebug(xsltGenericDebugContext,
2241 "Unregistered test module : %s\n", URI);
2245 * xsltRegisterTestModule:
2247 * Registers the test module
2249 void
2250 xsltRegisterTestModule(void)
2252 xsltInitGlobals();
2253 xsltRegisterExtModuleFull((const xmlChar *) XSLT_DEFAULT_URL,
2254 xsltExtInitTest, xsltExtShutdownTest,
2255 xsltExtStyleInitTest,
2256 xsltExtStyleShutdownTest);
2257 xsltRegisterExtModuleFunction((const xmlChar *) "test",
2258 (const xmlChar *) XSLT_DEFAULT_URL,
2259 xsltExtFunctionTest);
2260 xsltRegisterExtModuleElement((const xmlChar *) "test",
2261 (const xmlChar *) XSLT_DEFAULT_URL,
2262 xsltExtElementPreCompTest,
2263 xsltExtElementTest);
2266 static void
2267 xsltHashScannerModuleFree(void *payload ATTRIBUTE_UNUSED,
2268 void *data ATTRIBUTE_UNUSED,
2269 const xmlChar *name ATTRIBUTE_UNUSED)
2271 #ifdef WITH_MODULES
2272 xmlModuleClose(payload);
2273 #endif
2277 * xsltInitGlobals:
2279 * Initialize the global variables for extensions
2281 void
2282 xsltInitGlobals(void)
2284 if (xsltExtMutex == NULL) {
2285 xsltExtMutex = xmlNewMutex();
2290 * xsltCleanupGlobals:
2292 * Unregister all global variables set up by the XSLT library
2294 void
2295 xsltCleanupGlobals(void)
2297 xsltUnregisterAllExtModules();
2298 xsltUnregisterAllExtModuleFunction();
2299 xsltUnregisterAllExtModuleElement();
2300 xsltUnregisterAllExtModuleTopLevel();
2302 xmlMutexLock(xsltExtMutex);
2303 /* cleanup dynamic module hash */
2304 if (NULL != xsltModuleHash) {
2305 xmlHashScan(xsltModuleHash, xsltHashScannerModuleFree, 0);
2306 xmlHashFree(xsltModuleHash, NULL);
2307 xsltModuleHash = NULL;
2309 xmlMutexUnlock(xsltExtMutex);
2311 xmlFreeMutex(xsltExtMutex);
2312 xsltExtMutex = NULL;
2313 xsltFreeLocales();
2314 xsltUninit();
2317 static void
2318 xsltDebugDumpExtensionsCallback(void *function ATTRIBUTE_UNUSED,
2319 void *data, const xmlChar * name,
2320 const xmlChar * URI,
2321 const xmlChar * not_used ATTRIBUTE_UNUSED)
2323 FILE *output = (FILE *) data;
2324 if (!name || !URI)
2325 return;
2326 fprintf(output, "{%s}%s\n", URI, name);
2329 static void
2330 xsltDebugDumpExtModulesCallback(void *function ATTRIBUTE_UNUSED,
2331 void *data, const xmlChar * URI,
2332 const xmlChar * not_used ATTRIBUTE_UNUSED,
2333 const xmlChar * not_used2 ATTRIBUTE_UNUSED)
2335 FILE *output = (FILE *) data;
2336 if (!URI)
2337 return;
2338 fprintf(output, "%s\n", URI);
2342 * xsltDebugDumpExtensions:
2343 * @output: the FILE * for the output, if NULL stdout is used
2345 * Dumps a list of the registered XSLT extension functions and elements
2347 void
2348 xsltDebugDumpExtensions(FILE * output)
2350 if (output == NULL)
2351 output = stdout;
2352 fprintf(output,
2353 "Registered XSLT Extensions\n--------------------------\n");
2354 if (!xsltFunctionsHash)
2355 fprintf(output, "No registered extension functions\n");
2356 else {
2357 fprintf(output, "Registered Extension Functions:\n");
2358 xmlMutexLock(xsltExtMutex);
2359 xmlHashScanFull(xsltFunctionsHash, xsltDebugDumpExtensionsCallback,
2360 output);
2361 xmlMutexUnlock(xsltExtMutex);
2363 if (!xsltElementsHash)
2364 fprintf(output, "\nNo registered extension elements\n");
2365 else {
2366 fprintf(output, "\nRegistered Extension Elements:\n");
2367 xmlMutexLock(xsltExtMutex);
2368 xmlHashScanFull(xsltElementsHash, xsltDebugDumpExtensionsCallback,
2369 output);
2370 xmlMutexUnlock(xsltExtMutex);
2372 if (!xsltExtensionsHash)
2373 fprintf(output, "\nNo registered extension modules\n");
2374 else {
2375 fprintf(output, "\nRegistered Extension Modules:\n");
2376 xmlMutexLock(xsltExtMutex);
2377 xmlHashScanFull(xsltExtensionsHash, xsltDebugDumpExtModulesCallback,
2378 output);
2379 xmlMutexUnlock(xsltExtMutex);