| /* | |
| * extensions.c: Implemetation of the extensions support | |
| * | |
| * Reference: | |
| * http://www.w3.org/TR/1999/REC-xslt-19991116 | |
| * | |
| * See Copyright for the status of this software. | |
| * | |
| * [email protected] | |
| */ | |
| #define IN_LIBXSLT | |
| #include "libxslt.h" | |
| #include <string.h> | |
| #include <limits.h> | |
| #include <libxml/xmlmemory.h> | |
| #include <libxml/tree.h> | |
| #include <libxml/hash.h> | |
| #include <libxml/xmlerror.h> | |
| #include <libxml/parserInternals.h> | |
| #include <libxml/xpathInternals.h> | |
| #ifdef WITH_MODULES | |
| #include <libxml/xmlmodule.h> | |
| #endif | |
| #include <libxml/list.h> | |
| #include <libxml/xmlIO.h> | |
| #include "xslt.h" | |
| #include "xsltInternals.h" | |
| #include "xsltutils.h" | |
| #include "imports.h" | |
| #include "extensions.h" | |
| #ifdef _WIN32 | |
| #include <stdlib.h> /* for _MAX_PATH */ | |
| #ifndef PATH_MAX | |
| #define PATH_MAX _MAX_PATH | |
| #endif | |
| #endif | |
| #ifdef WITH_XSLT_DEBUG | |
| #define WITH_XSLT_DEBUG_EXTENSIONS | |
| #endif | |
| /************************************************************************ | |
| * * | |
| * Private Types and Globals * | |
| * * | |
| ************************************************************************/ | |
| typedef struct _xsltExtDef xsltExtDef; | |
| typedef xsltExtDef *xsltExtDefPtr; | |
| struct _xsltExtDef { | |
| struct _xsltExtDef *next; | |
| xmlChar *prefix; | |
| xmlChar *URI; | |
| void *data; | |
| }; | |
| typedef struct _xsltExtModule xsltExtModule; | |
| typedef xsltExtModule *xsltExtModulePtr; | |
| struct _xsltExtModule { | |
| xsltExtInitFunction initFunc; | |
| xsltExtShutdownFunction shutdownFunc; | |
| xsltStyleExtInitFunction styleInitFunc; | |
| xsltStyleExtShutdownFunction styleShutdownFunc; | |
| }; | |
| typedef struct _xsltExtData xsltExtData; | |
| typedef xsltExtData *xsltExtDataPtr; | |
| struct _xsltExtData { | |
| xsltExtModulePtr extModule; | |
| void *extData; | |
| }; | |
| typedef struct _xsltExtElement xsltExtElement; | |
| typedef xsltExtElement *xsltExtElementPtr; | |
| struct _xsltExtElement { | |
| xsltPreComputeFunction precomp; | |
| xsltTransformFunction transform; | |
| }; | |
| static xmlHashTablePtr xsltExtensionsHash = NULL; | |
| static xmlHashTablePtr xsltFunctionsHash = NULL; | |
| static xmlHashTablePtr xsltElementsHash = NULL; | |
| static xmlHashTablePtr xsltTopLevelsHash = NULL; | |
| static xmlHashTablePtr xsltModuleHash = NULL; | |
| static xmlMutexPtr xsltExtMutex = NULL; | |
| /************************************************************************ | |
| * * | |
| * Type functions * | |
| * * | |
| ************************************************************************/ | |
| /** | |
| * xsltNewExtDef: | |
| * @prefix: the extension prefix | |
| * @URI: the namespace URI | |
| * | |
| * Create a new XSLT ExtDef | |
| * | |
| * Returns the newly allocated xsltExtDefPtr or NULL in case of error | |
| */ | |
| static xsltExtDefPtr | |
| xsltNewExtDef(const xmlChar * prefix, const xmlChar * URI) | |
| { | |
| xsltExtDefPtr cur; | |
| cur = (xsltExtDefPtr) xmlMalloc(sizeof(xsltExtDef)); | |
| if (cur == NULL) { | |
| xsltTransformError(NULL, NULL, NULL, | |
| "xsltNewExtDef : malloc failed\n"); | |
| return (NULL); | |
| } | |
| memset(cur, 0, sizeof(xsltExtDef)); | |
| if (prefix != NULL) | |
| cur->prefix = xmlStrdup(prefix); | |
| if (URI != NULL) | |
| cur->URI = xmlStrdup(URI); | |
| return (cur); | |
| } | |
| /** | |
| * xsltFreeExtDef: | |
| * @extensiond: an XSLT extension definition | |
| * | |
| * Free up the memory allocated by @extensiond | |
| */ | |
| static void | |
| xsltFreeExtDef(xsltExtDefPtr extensiond) | |
| { | |
| if (extensiond == NULL) | |
| return; | |
| if (extensiond->prefix != NULL) | |
| xmlFree(extensiond->prefix); | |
| if (extensiond->URI != NULL) | |
| xmlFree(extensiond->URI); | |
| xmlFree(extensiond); | |
| } | |
| /** | |
| * xsltFreeExtDefList: | |
| * @extensiond: an XSLT extension definition list | |
| * | |
| * Free up the memory allocated by all the elements of @extensiond | |
| */ | |
| static void | |
| xsltFreeExtDefList(xsltExtDefPtr extensiond) | |
| { | |
| xsltExtDefPtr cur; | |
| while (extensiond != NULL) { | |
| cur = extensiond; | |
| extensiond = extensiond->next; | |
| xsltFreeExtDef(cur); | |
| } | |
| } | |
| /** | |
| * xsltNewExtModule: | |
| * @initFunc: the module initialization function | |
| * @shutdownFunc: the module shutdown function | |
| * @styleInitFunc: the stylesheet module data allocator function | |
| * @styleShutdownFunc: the stylesheet module data free function | |
| * | |
| * Create a new XSLT extension module | |
| * | |
| * Returns the newly allocated xsltExtModulePtr or NULL in case of error | |
| */ | |
| static xsltExtModulePtr | |
| xsltNewExtModule(xsltExtInitFunction initFunc, | |
| xsltExtShutdownFunction shutdownFunc, | |
| xsltStyleExtInitFunction styleInitFunc, | |
| xsltStyleExtShutdownFunction styleShutdownFunc) | |
| { | |
| xsltExtModulePtr cur; | |
| cur = (xsltExtModulePtr) xmlMalloc(sizeof(xsltExtModule)); | |
| if (cur == NULL) { | |
| xsltTransformError(NULL, NULL, NULL, | |
| "xsltNewExtModule : malloc failed\n"); | |
| return (NULL); | |
| } | |
| cur->initFunc = initFunc; | |
| cur->shutdownFunc = shutdownFunc; | |
| cur->styleInitFunc = styleInitFunc; | |
| cur->styleShutdownFunc = styleShutdownFunc; | |
| return (cur); | |
| } | |
| /** | |
| * xsltFreeExtModule: | |
| * @ext: an XSLT extension module | |
| * | |
| * Free up the memory allocated by @ext | |
| */ | |
| static void | |
| xsltFreeExtModule(xsltExtModulePtr ext) | |
| { | |
| if (ext == NULL) | |
| return; | |
| xmlFree(ext); | |
| } | |
| /** | |
| * xsltNewExtData: | |
| * @extModule: the module | |
| * @extData: the associated data | |
| * | |
| * Create a new XSLT extension module data wrapper | |
| * | |
| * Returns the newly allocated xsltExtDataPtr or NULL in case of error | |
| */ | |
| static xsltExtDataPtr | |
| xsltNewExtData(xsltExtModulePtr extModule, void *extData) | |
| { | |
| xsltExtDataPtr cur; | |
| if (extModule == NULL) | |
| return (NULL); | |
| cur = (xsltExtDataPtr) xmlMalloc(sizeof(xsltExtData)); | |
| if (cur == NULL) { | |
| xsltTransformError(NULL, NULL, NULL, | |
| "xsltNewExtData : malloc failed\n"); | |
| return (NULL); | |
| } | |
| cur->extModule = extModule; | |
| cur->extData = extData; | |
| return (cur); | |
| } | |
| /** | |
| * xsltFreeExtData: | |
| * @ext: an XSLT extension module data wrapper | |
| * | |
| * Free up the memory allocated by @ext | |
| */ | |
| static void | |
| xsltFreeExtData(xsltExtDataPtr ext) | |
| { | |
| if (ext == NULL) | |
| return; | |
| xmlFree(ext); | |
| } | |
| /** | |
| * xsltNewExtElement: | |
| * @precomp: the pre-computation function | |
| * @transform: the transformation function | |
| * | |
| * Create a new XSLT extension element | |
| * | |
| * Returns the newly allocated xsltExtElementPtr or NULL in case of | |
| * error | |
| */ | |
| static xsltExtElementPtr | |
| xsltNewExtElement(xsltPreComputeFunction precomp, | |
| xsltTransformFunction transform) | |
| { | |
| xsltExtElementPtr cur; | |
| if (transform == NULL) | |
| return (NULL); | |
| cur = (xsltExtElementPtr) xmlMalloc(sizeof(xsltExtElement)); | |
| if (cur == NULL) { | |
| xsltTransformError(NULL, NULL, NULL, | |
| "xsltNewExtElement : malloc failed\n"); | |
| return (NULL); | |
| } | |
| cur->precomp = precomp; | |
| cur->transform = transform; | |
| return (cur); | |
| } | |
| /** | |
| * xsltFreeExtElement: | |
| * @ext: an XSLT extension element | |
| * | |
| * Frees up the memory allocated by @ext | |
| */ | |
| static void | |
| xsltFreeExtElement(xsltExtElementPtr ext) | |
| { | |
| if (ext == NULL) | |
| return; | |
| xmlFree(ext); | |
| } | |
| #ifdef WITH_MODULES | |
| typedef void (*exsltRegisterFunction) (void); | |
| #ifndef PATH_MAX | |
| #define PATH_MAX 4096 | |
| #endif | |
| /** | |
| * xsltExtModuleRegisterDynamic: | |
| * @URI: the function or element namespace URI | |
| * | |
| * Dynamically loads an extension plugin when available. | |
| * | |
| * The plugin name is derived from the URI by removing the | |
| * initial protocol designation, e.g. "http://", then converting | |
| * the characters ".", "-", "/", and "\" into "_", the removing | |
| * any trailing "/", then concatenating LIBXML_MODULE_EXTENSION. | |
| * | |
| * Plugins are loaded from the directory specified by the | |
| * environment variable LIBXSLT_PLUGINS_PATH, or if NULL, | |
| * by LIBXSLT_DEFAULT_PLUGINS_PATH() which is determined at | |
| * compile time. | |
| * | |
| * Returns 0 if successful, -1 in case of error. | |
| */ | |
| static int | |
| xsltExtModuleRegisterDynamic(const xmlChar * URI) | |
| { | |
| xmlModulePtr m; | |
| exsltRegisterFunction regfunc; | |
| xmlChar *ext_name; | |
| char module_filename[PATH_MAX]; | |
| const xmlChar *ext_directory = NULL; | |
| const xmlChar *protocol = NULL; | |
| xmlChar *i, *regfunc_name; | |
| void *vregfunc; | |
| int rc; | |
| /* check for bad inputs */ | |
| if (URI == NULL) | |
| return (-1); | |
| if (NULL == xsltModuleHash) { | |
| xsltModuleHash = xmlHashCreate(5); | |
| if (xsltModuleHash == NULL) | |
| return (-1); | |
| } | |
| xmlMutexLock(xsltExtMutex); | |
| /* have we attempted to register this module already? */ | |
| if (xmlHashLookup(xsltModuleHash, URI) != NULL) { | |
| xmlMutexUnlock(xsltExtMutex); | |
| return (-1); | |
| } | |
| xmlMutexUnlock(xsltExtMutex); | |
| /* transform extension namespace into a module name */ | |
| protocol = xmlStrstr(URI, BAD_CAST "://"); | |
| if (protocol == NULL) { | |
| ext_name = xmlStrdup(URI); | |
| } else { | |
| ext_name = xmlStrdup(protocol + 3); | |
| } | |
| if (ext_name == NULL) { | |
| return (-1); | |
| } | |
| i = ext_name; | |
| while ('\0' != *i) { | |
| if (('/' == *i) || ('\\' == *i) || ('.' == *i) || ('-' == *i)) | |
| *i = '_'; | |
| i++; | |
| } | |
| if (*(i - 1) == '_') | |
| *i = '\0'; | |
| /* determine module directory */ | |
| ext_directory = (xmlChar *) getenv("LIBXSLT_PLUGINS_PATH"); | |
| if (NULL == ext_directory) { | |
| ext_directory = BAD_CAST LIBXSLT_DEFAULT_PLUGINS_PATH(); | |
| if (NULL == ext_directory) | |
| return (-1); | |
| } | |
| #ifdef WITH_XSLT_DEBUG_EXTENSIONS | |
| else | |
| xsltGenericDebug(xsltGenericDebugContext, | |
| "LIBXSLT_PLUGINS_PATH is %s\n", ext_directory); | |
| #endif | |
| /* build the module filename, and confirm the module exists */ | |
| xmlStrPrintf((xmlChar *) module_filename, sizeof(module_filename), | |
| BAD_CAST "%s/%s%s", | |
| ext_directory, ext_name, LIBXML_MODULE_EXTENSION); | |
| #ifdef WITH_XSLT_DEBUG_EXTENSIONS | |
| xsltGenericDebug(xsltGenericDebugContext, | |
| "Attempting to load plugin: %s for URI: %s\n", | |
| module_filename, URI); | |
| #endif | |
| if (1 != xmlCheckFilename(module_filename)) { | |
| #ifdef WITH_XSLT_DEBUG_EXTENSIONS | |
| xsltGenericDebug(xsltGenericDebugContext, | |
| "xmlCheckFilename failed for plugin: %s\n", module_filename); | |
| #endif | |
| xmlFree(ext_name); | |
| return (-1); | |
| } | |
| /* attempt to open the module */ | |
| m = xmlModuleOpen(module_filename, 0); | |
| if (NULL == m) { | |
| #ifdef WITH_XSLT_DEBUG_EXTENSIONS | |
| xsltGenericDebug(xsltGenericDebugContext, | |
| "xmlModuleOpen failed for plugin: %s\n", module_filename); | |
| #endif | |
| xmlFree(ext_name); | |
| return (-1); | |
| } | |
| /* construct initialization func name */ | |
| regfunc_name = xmlStrdup(ext_name); | |
| regfunc_name = xmlStrcat(regfunc_name, BAD_CAST "_init"); | |
| vregfunc = NULL; | |
| rc = xmlModuleSymbol(m, (const char *) regfunc_name, &vregfunc); | |
| regfunc = vregfunc; | |
| if (0 == rc) { | |
| /* | |
| * Call the module's init function. Note that this function | |
| * calls xsltRegisterExtModuleFull which will add the module | |
| * to xsltExtensionsHash (together with it's entry points). | |
| */ | |
| (*regfunc) (); | |
| /* register this module in our hash */ | |
| xmlMutexLock(xsltExtMutex); | |
| xmlHashAddEntry(xsltModuleHash, URI, (void *) m); | |
| xmlMutexUnlock(xsltExtMutex); | |
| } else { | |
| #ifdef WITH_XSLT_DEBUG_EXTENSIONS | |
| xsltGenericDebug(xsltGenericDebugContext, | |
| "xmlModuleSymbol failed for plugin: %s, regfunc: %s\n", | |
| module_filename, regfunc_name); | |
| #endif | |
| /* if regfunc not found unload the module immediately */ | |
| xmlModuleClose(m); | |
| } | |
| xmlFree(ext_name); | |
| xmlFree(regfunc_name); | |
| return (NULL == regfunc) ? -1 : 0; | |
| } | |
| #else | |
| static int | |
| xsltExtModuleRegisterDynamic(const xmlChar * URI ATTRIBUTE_UNUSED) | |
| { | |
| return -1; | |
| } | |
| #endif | |
| /************************************************************************ | |
| * * | |
| * The stylesheet extension prefixes handling * | |
| * * | |
| ************************************************************************/ | |
| /** | |
| * xsltFreeExts: | |
| * @style: an XSLT stylesheet | |
| * | |
| * Free up the memory used by XSLT extensions in a stylesheet | |
| */ | |
| void | |
| xsltFreeExts(xsltStylesheetPtr style) | |
| { | |
| if (style->nsDefs != NULL) | |
| xsltFreeExtDefList((xsltExtDefPtr) style->nsDefs); | |
| } | |
| /** | |
| * xsltRegisterExtPrefix: | |
| * @style: an XSLT stylesheet | |
| * @prefix: the prefix used (optional) | |
| * @URI: the URI associated to the extension | |
| * | |
| * Registers an extension namespace | |
| * This is called from xslt.c during compile-time. | |
| * The given prefix is not needed. | |
| * Called by: | |
| * xsltParseExtElemPrefixes() (new function) | |
| * xsltRegisterExtPrefix() (old function) | |
| * | |
| * Returns 0 in case of success, 1 if the @URI was already | |
| * registered as an extension namespace and | |
| * -1 in case of failure | |
| */ | |
| int | |
| xsltRegisterExtPrefix(xsltStylesheetPtr style, | |
| const xmlChar * prefix, const xmlChar * URI) | |
| { | |
| xsltExtDefPtr def, ret; | |
| if ((style == NULL) || (URI == NULL)) | |
| return (-1); | |
| #ifdef WITH_XSLT_DEBUG_EXTENSIONS | |
| xsltGenericDebug(xsltGenericDebugContext, | |
| "Registering extension namespace '%s'.\n", URI); | |
| #endif | |
| def = (xsltExtDefPtr) style->nsDefs; | |
| #ifdef XSLT_REFACTORED | |
| /* | |
| * The extension is associated with a namespace name. | |
| */ | |
| while (def != NULL) { | |
| if (xmlStrEqual(URI, def->URI)) | |
| return (1); | |
| def = def->next; | |
| } | |
| #else | |
| while (def != NULL) { | |
| if (xmlStrEqual(prefix, def->prefix)) | |
| return (-1); | |
| def = def->next; | |
| } | |
| #endif | |
| ret = xsltNewExtDef(prefix, URI); | |
| if (ret == NULL) | |
| return (-1); | |
| ret->next = (xsltExtDefPtr) style->nsDefs; | |
| style->nsDefs = ret; | |
| /* | |
| * check whether there is an extension module with a stylesheet | |
| * initialization function. | |
| */ | |
| #ifdef XSLT_REFACTORED | |
| /* | |
| * Don't initialize modules based on specified namespaces via | |
| * the attribute "[xsl:]extension-element-prefixes". | |
| */ | |
| #else | |
| if (xsltExtensionsHash != NULL) { | |
| xsltExtModulePtr module; | |
| xmlMutexLock(xsltExtMutex); | |
| module = xmlHashLookup(xsltExtensionsHash, URI); | |
| xmlMutexUnlock(xsltExtMutex); | |
| if (NULL == module) { | |
| if (!xsltExtModuleRegisterDynamic(URI)) { | |
| xmlMutexLock(xsltExtMutex); | |
| module = xmlHashLookup(xsltExtensionsHash, URI); | |
| xmlMutexUnlock(xsltExtMutex); | |
| } | |
| } | |
| if (module != NULL) { | |
| xsltStyleGetExtData(style, URI); | |
| } | |
| } | |
| #endif | |
| return (0); | |
| } | |
| /************************************************************************ | |
| * * | |
| * The extensions modules interfaces * | |
| * * | |
| ************************************************************************/ | |
| /** | |
| * xsltRegisterExtFunction: | |
| * @ctxt: an XSLT transformation context | |
| * @name: the name of the element | |
| * @URI: the URI associated to the element | |
| * @function: the actual implementation which should be called | |
| * | |
| * Registers an extension function | |
| * | |
| * Returns 0 in case of success, -1 in case of failure | |
| */ | |
| int | |
| xsltRegisterExtFunction(xsltTransformContextPtr ctxt, const xmlChar * name, | |
| const xmlChar * URI, xmlXPathFunction function) | |
| { | |
| int ret; | |
| if ((ctxt == NULL) || (name == NULL) || | |
| (URI == NULL) || (function == NULL)) | |
| return (-1); | |
| if (ctxt->xpathCtxt != NULL) { | |
| xmlXPathRegisterFuncNS(ctxt->xpathCtxt, name, URI, function); | |
| } | |
| if (ctxt->extFunctions == NULL) | |
| ctxt->extFunctions = xmlHashCreate(10); | |
| if (ctxt->extFunctions == NULL) | |
| return (-1); | |
| ret = xmlHashAddEntry2(ctxt->extFunctions, name, URI, | |
| XML_CAST_FPTR(function)); | |
| return(ret); | |
| } | |
| /** | |
| * xsltRegisterExtElement: | |
| * @ctxt: an XSLT transformation context | |
| * @name: the name of the element | |
| * @URI: the URI associated to the element | |
| * @function: the actual implementation which should be called | |
| * | |
| * Registers an extension element | |
| * | |
| * Returns 0 in case of success, -1 in case of failure | |
| */ | |
| int | |
| xsltRegisterExtElement(xsltTransformContextPtr ctxt, const xmlChar * name, | |
| const xmlChar * URI, xsltTransformFunction function) | |
| { | |
| if ((ctxt == NULL) || (name == NULL) || | |
| (URI == NULL) || (function == NULL)) | |
| return (-1); | |
| if (ctxt->extElements == NULL) | |
| ctxt->extElements = xmlHashCreate(10); | |
| if (ctxt->extElements == NULL) | |
| return (-1); | |
| return (xmlHashAddEntry2 | |
| (ctxt->extElements, name, URI, XML_CAST_FPTR(function))); | |
| } | |
| /** | |
| * xsltFreeCtxtExts: | |
| * @ctxt: an XSLT transformation context | |
| * | |
| * Free the XSLT extension data | |
| */ | |
| void | |
| xsltFreeCtxtExts(xsltTransformContextPtr ctxt) | |
| { | |
| if (ctxt->extElements != NULL) | |
| xmlHashFree(ctxt->extElements, NULL); | |
| if (ctxt->extFunctions != NULL) | |
| xmlHashFree(ctxt->extFunctions, NULL); | |
| } | |
| /** | |
| * xsltStyleGetStylesheetExtData: | |
| * @style: an XSLT stylesheet | |
| * @URI: the URI associated to the exension module | |
| * | |
| * Fires the compile-time initialization callback | |
| * of an extension module and returns a container | |
| * holding the user-data (retrieved via the callback). | |
| * | |
| * Returns the create module-data container | |
| * or NULL if such a module was not registered. | |
| */ | |
| static xsltExtDataPtr | |
| xsltStyleInitializeStylesheetModule(xsltStylesheetPtr style, | |
| const xmlChar * URI) | |
| { | |
| xsltExtDataPtr dataContainer; | |
| void *userData = NULL; | |
| xsltExtModulePtr module; | |
| if ((style == NULL) || (URI == NULL)) | |
| return(NULL); | |
| if (xsltExtensionsHash == NULL) { | |
| #ifdef WITH_XSLT_DEBUG_EXTENSIONS | |
| xsltGenericDebug(xsltGenericDebugContext, | |
| "Not registered extension module: %s\n", URI); | |
| #endif | |
| return(NULL); | |
| } | |
| xmlMutexLock(xsltExtMutex); | |
| module = xmlHashLookup(xsltExtensionsHash, URI); | |
| xmlMutexUnlock(xsltExtMutex); | |
| if (module == NULL) { | |
| #ifdef WITH_XSLT_DEBUG_EXTENSIONS | |
| xsltGenericDebug(xsltGenericDebugContext, | |
| "Not registered extension module: %s\n", URI); | |
| #endif | |
| return (NULL); | |
| } | |
| /* | |
| * The specified module was registered so initialize it. | |
| */ | |
| if (style->extInfos == NULL) { | |
| style->extInfos = xmlHashCreate(10); | |
| if (style->extInfos == NULL) | |
| return (NULL); | |
| } | |
| /* | |
| * Fire the initialization callback if available. | |
| */ | |
| if (module->styleInitFunc == NULL) { | |
| #ifdef WITH_XSLT_DEBUG_EXTENSIONS | |
| xsltGenericDebug(xsltGenericDebugContext, | |
| "Initializing module with *no* callback: %s\n", URI); | |
| #endif | |
| } else { | |
| #ifdef WITH_XSLT_DEBUG_EXTENSIONS | |
| xsltGenericDebug(xsltGenericDebugContext, | |
| "Initializing module with callback: %s\n", URI); | |
| #endif | |
| /* | |
| * Fire the initialization callback. | |
| */ | |
| userData = module->styleInitFunc(style, URI); | |
| } | |
| /* | |
| * Store the user-data in the context of the given stylesheet. | |
| */ | |
| dataContainer = xsltNewExtData(module, userData); | |
| if (dataContainer == NULL) | |
| return (NULL); | |
| if (xmlHashAddEntry(style->extInfos, URI, | |
| (void *) dataContainer) < 0) | |
| { | |
| xsltTransformError(NULL, style, NULL, | |
| "Failed to register module '%s'.\n", URI); | |
| style->errors++; | |
| if (module->styleShutdownFunc) | |
| module->styleShutdownFunc(style, URI, userData); | |
| xsltFreeExtData(dataContainer); | |
| return (NULL); | |
| } | |
| return(dataContainer); | |
| } | |
| /** | |
| * xsltStyleGetExtData: | |
| * @style: an XSLT stylesheet | |
| * @URI: the URI associated to the exension module | |
| * | |
| * Retrieve the data associated to the extension module | |
| * in this given stylesheet. | |
| * Called by: | |
| * xsltRegisterExtPrefix(), | |
| * ( xsltExtElementPreCompTest(), xsltExtInitTest ) | |
| * | |
| * Returns the pointer or NULL if not present | |
| */ | |
| void * | |
| xsltStyleGetExtData(xsltStylesheetPtr style, const xmlChar * URI) | |
| { | |
| xsltExtDataPtr dataContainer = NULL; | |
| xsltStylesheetPtr tmpStyle; | |
| if ((style == NULL) || (URI == NULL) || | |
| (xsltExtensionsHash == NULL)) | |
| return (NULL); | |
| #ifdef XSLT_REFACTORED | |
| /* | |
| * This is intended for global storage, so only the main | |
| * stylesheet will hold the data. | |
| */ | |
| tmpStyle = style; | |
| while (tmpStyle->parent != NULL) | |
| tmpStyle = tmpStyle->parent; | |
| if (tmpStyle->extInfos != NULL) { | |
| dataContainer = | |
| (xsltExtDataPtr) xmlHashLookup(tmpStyle->extInfos, URI); | |
| if (dataContainer != NULL) { | |
| /* | |
| * The module was already initialized in the context | |
| * of this stylesheet; just return the user-data that | |
| * comes with it. | |
| */ | |
| return(dataContainer->extData); | |
| } | |
| } | |
| #else | |
| /* | |
| * Old behaviour. | |
| */ | |
| tmpStyle = style; | |
| while (tmpStyle != NULL) { | |
| if (tmpStyle->extInfos != NULL) { | |
| dataContainer = | |
| (xsltExtDataPtr) xmlHashLookup(tmpStyle->extInfos, URI); | |
| if (dataContainer != NULL) { | |
| return(dataContainer->extData); | |
| } | |
| } | |
| tmpStyle = xsltNextImport(tmpStyle); | |
| } | |
| tmpStyle = style; | |
| #endif | |
| dataContainer = | |
| xsltStyleInitializeStylesheetModule(tmpStyle, URI); | |
| if (dataContainer != NULL) | |
| return (dataContainer->extData); | |
| return(NULL); | |
| } | |
| #ifdef XSLT_REFACTORED | |
| /** | |
| * xsltStyleStylesheetLevelGetExtData: | |
| * @style: an XSLT stylesheet | |
| * @URI: the URI associated to the exension module | |
| * | |
| * Retrieve the data associated to the extension module in this given | |
| * stylesheet. | |
| * | |
| * Returns the pointer or NULL if not present | |
| */ | |
| void * | |
| xsltStyleStylesheetLevelGetExtData(xsltStylesheetPtr style, | |
| const xmlChar * URI) | |
| { | |
| xsltExtDataPtr dataContainer = NULL; | |
| if ((style == NULL) || (URI == NULL) || | |
| (xsltExtensionsHash == NULL)) | |
| return (NULL); | |
| if (style->extInfos != NULL) { | |
| dataContainer = (xsltExtDataPtr) xmlHashLookup(style->extInfos, URI); | |
| /* | |
| * The module was already initialized in the context | |
| * of this stylesheet; just return the user-data that | |
| * comes with it. | |
| */ | |
| if (dataContainer) | |
| return(dataContainer->extData); | |
| } | |
| dataContainer = | |
| xsltStyleInitializeStylesheetModule(style, URI); | |
| if (dataContainer != NULL) | |
| return (dataContainer->extData); | |
| return(NULL); | |
| } | |
| #endif | |
| /** | |
| * xsltGetExtData: | |
| * @ctxt: an XSLT transformation context | |
| * @URI: the URI associated to the exension module | |
| * | |
| * Retrieve the data associated to the extension module in this given | |
| * transformation. | |
| * | |
| * Returns the pointer or NULL if not present | |
| */ | |
| void * | |
| xsltGetExtData(xsltTransformContextPtr ctxt, const xmlChar * URI) | |
| { | |
| xsltExtDataPtr data; | |
| if ((ctxt == NULL) || (URI == NULL)) | |
| return (NULL); | |
| if (ctxt->extInfos == NULL) { | |
| ctxt->extInfos = xmlHashCreate(10); | |
| if (ctxt->extInfos == NULL) | |
| return (NULL); | |
| data = NULL; | |
| } else { | |
| data = (xsltExtDataPtr) xmlHashLookup(ctxt->extInfos, URI); | |
| } | |
| if (data == NULL) { | |
| void *extData; | |
| xsltExtModulePtr module; | |
| xmlMutexLock(xsltExtMutex); | |
| module = xmlHashLookup(xsltExtensionsHash, URI); | |
| xmlMutexUnlock(xsltExtMutex); | |
| if (module == NULL) { | |
| #ifdef WITH_XSLT_DEBUG_EXTENSIONS | |
| xsltGenericDebug(xsltGenericDebugContext, | |
| "Not registered extension module: %s\n", URI); | |
| #endif | |
| return (NULL); | |
| } else { | |
| if (module->initFunc == NULL) | |
| return (NULL); | |
| #ifdef WITH_XSLT_DEBUG_EXTENSIONS | |
| xsltGenericDebug(xsltGenericDebugContext, | |
| "Initializing module: %s\n", URI); | |
| #endif | |
| extData = module->initFunc(ctxt, URI); | |
| if (extData == NULL) | |
| return (NULL); | |
| data = xsltNewExtData(module, extData); | |
| if (data == NULL) | |
| return (NULL); | |
| if (xmlHashAddEntry(ctxt->extInfos, URI, (void *) data) < 0) { | |
| xsltTransformError(ctxt, NULL, NULL, | |
| "Failed to register module data: %s\n", | |
| URI); | |
| if (module->shutdownFunc) | |
| module->shutdownFunc(ctxt, URI, extData); | |
| xsltFreeExtData(data); | |
| return (NULL); | |
| } | |
| } | |
| } | |
| return (data->extData); | |
| } | |
| typedef struct _xsltInitExtCtxt xsltInitExtCtxt; | |
| struct _xsltInitExtCtxt { | |
| xsltTransformContextPtr ctxt; | |
| int ret; | |
| }; | |
| /** | |
| * xsltInitCtxtExt: | |
| * @styleData: the registered stylesheet data for the module | |
| * @ctxt: the XSLT transformation context + the return value | |
| * @URI: the extension URI | |
| * | |
| * Initializes an extension module | |
| */ | |
| static void | |
| xsltInitCtxtExt(xsltExtDataPtr styleData, xsltInitExtCtxt * ctxt, | |
| const xmlChar * URI) | |
| { | |
| xsltExtModulePtr module; | |
| xsltExtDataPtr ctxtData; | |
| void *extData; | |
| if ((styleData == NULL) || (ctxt == NULL) || (URI == NULL) || | |
| (ctxt->ret == -1)) { | |
| #ifdef WITH_XSLT_DEBUG_EXTENSIONS | |
| xsltGenericDebug(xsltGenericDebugContext, | |
| "xsltInitCtxtExt: NULL param or error\n"); | |
| #endif | |
| return; | |
| } | |
| module = styleData->extModule; | |
| if ((module == NULL) || (module->initFunc == NULL)) { | |
| #ifdef WITH_XSLT_DEBUG_EXTENSIONS | |
| xsltGenericDebug(xsltGenericDebugContext, | |
| "xsltInitCtxtExt: no module or no initFunc\n"); | |
| #endif | |
| return; | |
| } | |
| ctxtData = (xsltExtDataPtr) xmlHashLookup(ctxt->ctxt->extInfos, URI); | |
| if (ctxtData != NULL) { | |
| #ifdef WITH_XSLT_DEBUG_EXTENSIONS | |
| xsltGenericDebug(xsltGenericDebugContext, | |
| "xsltInitCtxtExt: already initialized\n"); | |
| #endif | |
| return; | |
| } | |
| extData = module->initFunc(ctxt->ctxt, URI); | |
| if (extData == NULL) { | |
| #ifdef WITH_XSLT_DEBUG_EXTENSIONS | |
| xsltGenericDebug(xsltGenericDebugContext, | |
| "xsltInitCtxtExt: no extData\n"); | |
| #endif | |
| } | |
| ctxtData = xsltNewExtData(module, extData); | |
| if (ctxtData == NULL) { | |
| ctxt->ret = -1; | |
| return; | |
| } | |
| if (ctxt->ctxt->extInfos == NULL) | |
| ctxt->ctxt->extInfos = xmlHashCreate(10); | |
| if (ctxt->ctxt->extInfos == NULL) { | |
| ctxt->ret = -1; | |
| return; | |
| } | |
| if (xmlHashAddEntry(ctxt->ctxt->extInfos, URI, ctxtData) < 0) { | |
| xsltGenericError(xsltGenericErrorContext, | |
| "Failed to register module data: %s\n", URI); | |
| if (module->shutdownFunc) | |
| module->shutdownFunc(ctxt->ctxt, URI, extData); | |
| xsltFreeExtData(ctxtData); | |
| ctxt->ret = -1; | |
| return; | |
| } | |
| #ifdef WITH_XSLT_DEBUG_EXTENSIONS | |
| xsltGenericDebug(xsltGenericDebugContext, "Registered module %s\n", | |
| URI); | |
| #endif | |
| ctxt->ret++; | |
| } | |
| /** | |
| * xsltInitCtxtExts: | |
| * @ctxt: an XSLT transformation context | |
| * | |
| * Initialize the set of modules with registered stylesheet data | |
| * | |
| * Returns the number of modules initialized or -1 in case of error | |
| */ | |
| int | |
| xsltInitCtxtExts(xsltTransformContextPtr ctxt) | |
| { | |
| xsltStylesheetPtr style; | |
| xsltInitExtCtxt ctx; | |
| if (ctxt == NULL) | |
| return (-1); | |
| style = ctxt->style; | |
| if (style == NULL) | |
| return (-1); | |
| ctx.ctxt = ctxt; | |
| ctx.ret = 0; | |
| while (style != NULL) { | |
| if (style->extInfos != NULL) { | |
| xmlHashScan(style->extInfos, | |
| (xmlHashScanner) xsltInitCtxtExt, &ctx); | |
| if (ctx.ret == -1) | |
| return (-1); | |
| } | |
| style = xsltNextImport(style); | |
| } | |
| #ifdef WITH_XSLT_DEBUG_EXTENSIONS | |
| xsltGenericDebug(xsltGenericDebugContext, "Registered %d modules\n", | |
| ctx.ret); | |
| #endif | |
| return (ctx.ret); | |
| } | |
| /** | |
| * xsltShutdownCtxtExt: | |
| * @data: the registered data for the module | |
| * @ctxt: the XSLT transformation context | |
| * @URI: the extension URI | |
| * | |
| * Shutdown an extension module loaded | |
| */ | |
| static void | |
| xsltShutdownCtxtExt(xsltExtDataPtr data, xsltTransformContextPtr ctxt, | |
| const xmlChar * URI) | |
| { | |
| xsltExtModulePtr module; | |
| if ((data == NULL) || (ctxt == NULL) || (URI == NULL)) | |
| return; | |
| module = data->extModule; | |
| if ((module == NULL) || (module->shutdownFunc == NULL)) | |
| return; | |
| #ifdef WITH_XSLT_DEBUG_EXTENSIONS | |
| xsltGenericDebug(xsltGenericDebugContext, | |
| "Shutting down module : %s\n", URI); | |
| #endif | |
| module->shutdownFunc(ctxt, URI, data->extData); | |
| } | |
| /** | |
| * xsltShutdownCtxtExts: | |
| * @ctxt: an XSLT transformation context | |
| * | |
| * Shutdown the set of modules loaded | |
| */ | |
| void | |
| xsltShutdownCtxtExts(xsltTransformContextPtr ctxt) | |
| { | |
| if (ctxt == NULL) | |
| return; | |
| if (ctxt->extInfos == NULL) | |
| return; | |
| xmlHashScan(ctxt->extInfos, (xmlHashScanner) xsltShutdownCtxtExt, | |
| ctxt); | |
| xmlHashFree(ctxt->extInfos, (xmlHashDeallocator) xsltFreeExtData); | |
| ctxt->extInfos = NULL; | |
| } | |
| /** | |
| * xsltShutdownExt: | |
| * @data: the registered data for the module | |
| * @ctxt: the XSLT stylesheet | |
| * @URI: the extension URI | |
| * | |
| * Shutdown an extension module loaded | |
| */ | |
| static void | |
| xsltShutdownExt(xsltExtDataPtr data, xsltStylesheetPtr style, | |
| const xmlChar * URI) | |
| { | |
| xsltExtModulePtr module; | |
| if ((data == NULL) || (style == NULL) || (URI == NULL)) | |
| return; | |
| module = data->extModule; | |
| if ((module == NULL) || (module->styleShutdownFunc == NULL)) | |
| return; | |
| #ifdef WITH_XSLT_DEBUG_EXTENSIONS | |
| xsltGenericDebug(xsltGenericDebugContext, | |
| "Shutting down module : %s\n", URI); | |
| #endif | |
| module->styleShutdownFunc(style, URI, data->extData); | |
| /* | |
| * Don't remove the entry from the hash table here, since | |
| * this will produce segfaults - this fixes bug #340624. | |
| * | |
| * xmlHashRemoveEntry(style->extInfos, URI, | |
| * (xmlHashDeallocator) xsltFreeExtData); | |
| */ | |
| } | |
| /** | |
| * xsltShutdownExts: | |
| * @style: an XSLT stylesheet | |
| * | |
| * Shutdown the set of modules loaded | |
| */ | |
| void | |
| xsltShutdownExts(xsltStylesheetPtr style) | |
| { | |
| if (style == NULL) | |
| return; | |
| if (style->extInfos == NULL) | |
| return; | |
| xmlHashScan(style->extInfos, (xmlHashScanner) xsltShutdownExt, style); | |
| xmlHashFree(style->extInfos, (xmlHashDeallocator) xsltFreeExtData); | |
| style->extInfos = NULL; | |
| } | |
| /** | |
| * xsltCheckExtPrefix: | |
| * @style: the stylesheet | |
| * @URI: the namespace prefix (possibly NULL) | |
| * | |
| * Check if the given prefix is one of the declared extensions. | |
| * This is intended to be called only at compile-time. | |
| * Called by: | |
| * xsltGetInheritedNsList() (xslt.c) | |
| * xsltParseTemplateContent (xslt.c) | |
| * | |
| * Returns 1 if this is an extension, 0 otherwise | |
| */ | |
| int | |
| xsltCheckExtPrefix(xsltStylesheetPtr style, const xmlChar * URI) | |
| { | |
| #ifdef XSLT_REFACTORED | |
| if ((style == NULL) || (style->compCtxt == NULL) || | |
| (XSLT_CCTXT(style)->inode == NULL) || | |
| (XSLT_CCTXT(style)->inode->extElemNs == NULL)) | |
| return (0); | |
| /* | |
| * Lookup the extension namespaces registered | |
| * at the current node in the stylesheet's tree. | |
| */ | |
| if (XSLT_CCTXT(style)->inode->extElemNs != NULL) { | |
| int i; | |
| xsltPointerListPtr list = XSLT_CCTXT(style)->inode->extElemNs; | |
| for (i = 0; i < list->number; i++) { | |
| if (xmlStrEqual((const xmlChar *) list->items[i], | |
| URI)) | |
| { | |
| return(1); | |
| } | |
| } | |
| } | |
| #else | |
| xsltExtDefPtr cur; | |
| if ((style == NULL) || (style->nsDefs == NULL)) | |
| return (0); | |
| if (URI == NULL) | |
| URI = BAD_CAST "#default"; | |
| cur = (xsltExtDefPtr) style->nsDefs; | |
| while (cur != NULL) { | |
| /* | |
| * NOTE: This was change to work on namespace names rather | |
| * than namespace prefixes. This fixes bug #339583. | |
| * TODO: Consider renaming the field "prefix" of xsltExtDef | |
| * to "href". | |
| */ | |
| if (xmlStrEqual(URI, cur->prefix)) | |
| return (1); | |
| cur = cur->next; | |
| } | |
| #endif | |
| return (0); | |
| } | |
| /** | |
| * xsltCheckExtURI: | |
| * @style: the stylesheet | |
| * @URI: the namespace URI (possibly NULL) | |
| * | |
| * Check if the given prefix is one of the declared extensions. | |
| * This is intended to be called only at compile-time. | |
| * Called by: | |
| * xsltPrecomputeStylesheet() (xslt.c) | |
| * xsltParseTemplateContent (xslt.c) | |
| * | |
| * Returns 1 if this is an extension, 0 otherwise | |
| */ | |
| int | |
| xsltCheckExtURI(xsltStylesheetPtr style, const xmlChar * URI) | |
| { | |
| xsltExtDefPtr cur; | |
| if ((style == NULL) || (style->nsDefs == NULL)) | |
| return (0); | |
| if (URI == NULL) | |
| return (0); | |
| cur = (xsltExtDefPtr) style->nsDefs; | |
| while (cur != NULL) { | |
| if (xmlStrEqual(URI, cur->URI)) | |
| return (1); | |
| cur = cur->next; | |
| } | |
| return (0); | |
| } | |
| /** | |
| * xsltRegisterExtModuleFull: | |
| * @URI: URI associated to this module | |
| * @initFunc: the module initialization function | |
| * @shutdownFunc: the module shutdown function | |
| * @styleInitFunc: the module initialization function | |
| * @styleShutdownFunc: the module shutdown function | |
| * | |
| * Register an XSLT extension module to the library. | |
| * | |
| * Returns 0 if sucessful, -1 in case of error | |
| */ | |
| int | |
| xsltRegisterExtModuleFull(const xmlChar * URI, | |
| xsltExtInitFunction initFunc, | |
| xsltExtShutdownFunction shutdownFunc, | |
| xsltStyleExtInitFunction styleInitFunc, | |
| xsltStyleExtShutdownFunction styleShutdownFunc) | |
| { | |
| int ret; | |
| xsltExtModulePtr module; | |
| if ((URI == NULL) || (initFunc == NULL)) | |
| return (-1); | |
| if (xsltExtensionsHash == NULL) | |
| xsltExtensionsHash = xmlHashCreate(10); | |
| if (xsltExtensionsHash == NULL) | |
| return (-1); | |
| xmlMutexLock(xsltExtMutex); | |
| module = xmlHashLookup(xsltExtensionsHash, URI); | |
| if (module != NULL) { | |
| if ((module->initFunc == initFunc) && | |
| (module->shutdownFunc == shutdownFunc)) | |
| ret = 0; | |
| else | |
| ret = -1; | |
| goto done; | |
| } | |
| module = xsltNewExtModule(initFunc, shutdownFunc, | |
| styleInitFunc, styleShutdownFunc); | |
| if (module == NULL) { | |
| ret = -1; | |
| goto done; | |
| } | |
| ret = xmlHashAddEntry(xsltExtensionsHash, URI, (void *) module); | |
| done: | |
| xmlMutexUnlock(xsltExtMutex); | |
| return (ret); | |
| } | |
| /** | |
| * xsltRegisterExtModule: | |
| * @URI: URI associated to this module | |
| * @initFunc: the module initialization function | |
| * @shutdownFunc: the module shutdown function | |
| * | |
| * Register an XSLT extension module to the library. | |
| * | |
| * Returns 0 if sucessful, -1 in case of error | |
| */ | |
| int | |
| xsltRegisterExtModule(const xmlChar * URI, | |
| xsltExtInitFunction initFunc, | |
| xsltExtShutdownFunction shutdownFunc) | |
| { | |
| return xsltRegisterExtModuleFull(URI, initFunc, shutdownFunc, | |
| NULL, NULL); | |
| } | |
| /** | |
| * xsltUnregisterExtModule: | |
| * @URI: URI associated to this module | |
| * | |
| * Unregister an XSLT extension module from the library. | |
| * | |
| * Returns 0 if sucessful, -1 in case of error | |
| */ | |
| int | |
| xsltUnregisterExtModule(const xmlChar * URI) | |
| { | |
| int ret; | |
| if (URI == NULL) | |
| return (-1); | |
| if (xsltExtensionsHash == NULL) | |
| return (-1); | |
| xmlMutexLock(xsltExtMutex); | |
| ret = xmlHashRemoveEntry(xsltExtensionsHash, URI, | |
| (xmlHashDeallocator) xsltFreeExtModule); | |
| xmlMutexUnlock(xsltExtMutex); | |
| return (ret); | |
| } | |
| /** | |
| * xsltUnregisterAllExtModules: | |
| * | |
| * Unregister all the XSLT extension module from the library. | |
| */ | |
| static void | |
| xsltUnregisterAllExtModules(void) | |
| { | |
| if (xsltExtensionsHash == NULL) | |
| return; | |
| xmlMutexLock(xsltExtMutex); | |
| xmlHashFree(xsltExtensionsHash, | |
| (xmlHashDeallocator) xsltFreeExtModule); | |
| xsltExtensionsHash = NULL; | |
| xmlMutexUnlock(xsltExtMutex); | |
| } | |
| /** | |
| * xsltXPathGetTransformContext: | |
| * @ctxt: an XPath transformation context | |
| * | |
| * Provides the XSLT transformation context from the XPath transformation | |
| * context. This is useful when an XPath function in the extension module | |
| * is called by the XPath interpreter and that the XSLT context is needed | |
| * for example to retrieve the associated data pertaining to this XSLT | |
| * transformation. | |
| * | |
| * Returns the XSLT transformation context or NULL in case of error. | |
| */ | |
| xsltTransformContextPtr | |
| xsltXPathGetTransformContext(xmlXPathParserContextPtr ctxt) | |
| { | |
| if ((ctxt == NULL) || (ctxt->context == NULL)) | |
| return (NULL); | |
| return (ctxt->context->extra); | |
| } | |
| /** | |
| * xsltRegisterExtModuleFunction: | |
| * @name: the function name | |
| * @URI: the function namespace URI | |
| * @function: the function callback | |
| * | |
| * Registers an extension module function. | |
| * | |
| * Returns 0 if successful, -1 in case of error. | |
| */ | |
| int | |
| xsltRegisterExtModuleFunction(const xmlChar * name, const xmlChar * URI, | |
| xmlXPathFunction function) | |
| { | |
| if ((name == NULL) || (URI == NULL) || (function == NULL)) | |
| return (-1); | |
| if (xsltFunctionsHash == NULL) | |
| xsltFunctionsHash = xmlHashCreate(10); | |
| if (xsltFunctionsHash == NULL) | |
| return (-1); | |
| xmlMutexLock(xsltExtMutex); | |
| xmlHashUpdateEntry2(xsltFunctionsHash, name, URI, | |
| XML_CAST_FPTR(function), NULL); | |
| xmlMutexUnlock(xsltExtMutex); | |
| return (0); | |
| } | |
| /** | |
| * xsltExtModuleFunctionLookup: | |
| * @name: the function name | |
| * @URI: the function namespace URI | |
| * | |
| * Looks up an extension module function | |
| * | |
| * Returns the function if found, NULL otherwise. | |
| */ | |
| xmlXPathFunction | |
| xsltExtModuleFunctionLookup(const xmlChar * name, const xmlChar * URI) | |
| { | |
| xmlXPathFunction ret; | |
| if ((xsltFunctionsHash == NULL) || (name == NULL) || (URI == NULL)) | |
| return (NULL); | |
| xmlMutexLock(xsltExtMutex); | |
| XML_CAST_FPTR(ret) = xmlHashLookup2(xsltFunctionsHash, name, URI); | |
| xmlMutexUnlock(xsltExtMutex); | |
| /* if lookup fails, attempt a dynamic load on supported platforms */ | |
| if (NULL == ret) { | |
| if (!xsltExtModuleRegisterDynamic(URI)) { | |
| xmlMutexLock(xsltExtMutex); | |
| XML_CAST_FPTR(ret) = | |
| xmlHashLookup2(xsltFunctionsHash, name, URI); | |
| xmlMutexUnlock(xsltExtMutex); | |
| } | |
| } | |
| return ret; | |
| } | |
| /** | |
| * xsltUnregisterExtModuleFunction: | |
| * @name: the function name | |
| * @URI: the function namespace URI | |
| * | |
| * Unregisters an extension module function | |
| * | |
| * Returns 0 if successful, -1 in case of error. | |
| */ | |
| int | |
| xsltUnregisterExtModuleFunction(const xmlChar * name, const xmlChar * URI) | |
| { | |
| int ret; | |
| if ((xsltFunctionsHash == NULL) || (name == NULL) || (URI == NULL)) | |
| return (-1); | |
| xmlMutexLock(xsltExtMutex); | |
| ret = xmlHashRemoveEntry2(xsltFunctionsHash, name, URI, NULL); | |
| xmlMutexUnlock(xsltExtMutex); | |
| return(ret); | |
| } | |
| /** | |
| * xsltUnregisterAllExtModuleFunction: | |
| * | |
| * Unregisters all extension module function | |
| */ | |
| static void | |
| xsltUnregisterAllExtModuleFunction(void) | |
| { | |
| xmlMutexLock(xsltExtMutex); | |
| xmlHashFree(xsltFunctionsHash, NULL); | |
| xsltFunctionsHash = NULL; | |
| xmlMutexUnlock(xsltExtMutex); | |
| } | |
| /** | |
| * xsltNewElemPreComp: | |
| * @style: the XSLT stylesheet | |
| * @inst: the element node | |
| * @function: the transform function | |
| * | |
| * Creates and initializes an #xsltElemPreComp | |
| * | |
| * Returns the new and initialized #xsltElemPreComp | |
| */ | |
| xsltElemPreCompPtr | |
| xsltNewElemPreComp(xsltStylesheetPtr style, xmlNodePtr inst, | |
| xsltTransformFunction function) | |
| { | |
| xsltElemPreCompPtr cur; | |
| cur = (xsltElemPreCompPtr) xmlMalloc(sizeof(xsltElemPreComp)); | |
| if (cur == NULL) { | |
| xsltTransformError(NULL, style, NULL, | |
| "xsltNewExtElement : malloc failed\n"); | |
| return (NULL); | |
| } | |
| memset(cur, 0, sizeof(xsltElemPreComp)); | |
| xsltInitElemPreComp(cur, style, inst, function, | |
| (xsltElemPreCompDeallocator) xmlFree); | |
| return (cur); | |
| } | |
| /** | |
| * xsltInitElemPreComp: | |
| * @comp: an #xsltElemPreComp (or generally a derived structure) | |
| * @style: the XSLT stylesheet | |
| * @inst: the element node | |
| * @function: the transform function | |
| * @freeFunc: the @comp deallocator | |
| * | |
| * Initializes an existing #xsltElemPreComp structure. This is usefull | |
| * when extending an #xsltElemPreComp to store precomputed data. | |
| * This function MUST be called on any extension element precomputed | |
| * data struct. | |
| */ | |
| void | |
| xsltInitElemPreComp(xsltElemPreCompPtr comp, xsltStylesheetPtr style, | |
| xmlNodePtr inst, xsltTransformFunction function, | |
| xsltElemPreCompDeallocator freeFunc) | |
| { | |
| comp->type = XSLT_FUNC_EXTENSION; | |
| comp->func = function; | |
| comp->inst = inst; | |
| comp->free = freeFunc; | |
| comp->next = style->preComps; | |
| style->preComps = comp; | |
| } | |
| /** | |
| * xsltPreComputeExtModuleElement: | |
| * @style: the stylesheet | |
| * @inst: the element node | |
| * | |
| * Precomputes an extension module element | |
| * | |
| * Returns the precomputed data | |
| */ | |
| xsltElemPreCompPtr | |
| xsltPreComputeExtModuleElement(xsltStylesheetPtr style, xmlNodePtr inst) | |
| { | |
| xsltExtElementPtr ext; | |
| xsltElemPreCompPtr comp = NULL; | |
| if ((style == NULL) || (inst == NULL) || | |
| (inst->type != XML_ELEMENT_NODE) || (inst->ns == NULL)) | |
| return (NULL); | |
| xmlMutexLock(xsltExtMutex); | |
| ext = (xsltExtElementPtr) | |
| xmlHashLookup2(xsltElementsHash, inst->name, inst->ns->href); | |
| xmlMutexUnlock(xsltExtMutex); | |
| /* | |
| * EXT TODO: Now what? | |
| */ | |
| if (ext == NULL) | |
| return (NULL); | |
| if (ext->precomp != NULL) { | |
| /* | |
| * REVISIT TODO: Check if the text below is correct. | |
| * This will return a xsltElemPreComp structure or NULL. | |
| * 1) If the the author of the extension needs a | |
| * custom structure to hold the specific values of | |
| * this extension, he will derive a structure based on | |
| * xsltElemPreComp; thus we obviously *cannot* refactor | |
| * the xsltElemPreComp structure, since all already derived | |
| * user-defined strucures will break. | |
| * Example: For the extension xsl:document, | |
| * in xsltDocumentComp() (preproc.c), the structure | |
| * xsltStyleItemDocument is allocated, filled with | |
| * specific values and returned. | |
| * 2) If the author needs no values to be stored in | |
| * this structure, then he'll return NULL; | |
| */ | |
| comp = ext->precomp(style, inst, ext->transform); | |
| } | |
| if (comp == NULL) { | |
| /* | |
| * Default creation of a xsltElemPreComp structure, if | |
| * the author of this extension did not create a custom | |
| * structure. | |
| */ | |
| comp = xsltNewElemPreComp(style, inst, ext->transform); | |
| } | |
| return (comp); | |
| } | |
| /** | |
| * xsltRegisterExtModuleElement: | |
| * @name: the element name | |
| * @URI: the element namespace URI | |
| * @precomp: the pre-computation callback | |
| * @transform: the transformation callback | |
| * | |
| * Registers an extension module element. | |
| * | |
| * Returns 0 if successful, -1 in case of error. | |
| */ | |
| int | |
| xsltRegisterExtModuleElement(const xmlChar * name, const xmlChar * URI, | |
| xsltPreComputeFunction precomp, | |
| xsltTransformFunction transform) | |
| { | |
| int ret; | |
| xsltExtElementPtr ext; | |
| if ((name == NULL) || (URI == NULL) || (transform == NULL)) | |
| return (-1); | |
| if (xsltElementsHash == NULL) | |
| xsltElementsHash = xmlHashCreate(10); | |
| if (xsltElementsHash == NULL) | |
| return (-1); | |
| xmlMutexLock(xsltExtMutex); | |
| ext = xsltNewExtElement(precomp, transform); | |
| if (ext == NULL) { | |
| ret = -1; | |
| goto done; | |
| } | |
| xmlHashUpdateEntry2(xsltElementsHash, name, URI, (void *) ext, | |
| (xmlHashDeallocator) xsltFreeExtElement); | |
| done: | |
| xmlMutexUnlock(xsltExtMutex); | |
| return (0); | |
| } | |
| /** | |
| * xsltExtElementLookup: | |
| * @ctxt: an XSLT process context | |
| * @name: the element name | |
| * @URI: the element namespace URI | |
| * | |
| * Looks up an extension element. @ctxt can be NULL to search only in | |
| * module elements. | |
| * | |
| * Returns the element callback or NULL if not found | |
| */ | |
| xsltTransformFunction | |
| xsltExtElementLookup(xsltTransformContextPtr ctxt, | |
| const xmlChar * name, const xmlChar * URI) | |
| { | |
| xsltTransformFunction ret; | |
| if ((name == NULL) || (URI == NULL)) | |
| return (NULL); | |
| if ((ctxt != NULL) && (ctxt->extElements != NULL)) { | |
| XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->extElements, name, URI); | |
| if (ret != NULL) { | |
| return(ret); | |
| } | |
| } | |
| ret = xsltExtModuleElementLookup(name, URI); | |
| return (ret); | |
| } | |
| /** | |
| * xsltExtModuleElementLookup: | |
| * @name: the element name | |
| * @URI: the element namespace URI | |
| * | |
| * Looks up an extension module element | |
| * | |
| * Returns the callback function if found, NULL otherwise. | |
| */ | |
| xsltTransformFunction | |
| xsltExtModuleElementLookup(const xmlChar * name, const xmlChar * URI) | |
| { | |
| xsltExtElementPtr ext; | |
| if ((xsltElementsHash == NULL) || (name == NULL) || (URI == NULL)) | |
| return (NULL); | |
| xmlMutexLock(xsltExtMutex); | |
| ext = (xsltExtElementPtr) xmlHashLookup2(xsltElementsHash, name, URI); | |
| xmlMutexUnlock(xsltExtMutex); | |
| /* | |
| * if function lookup fails, attempt a dynamic load on | |
| * supported platforms | |
| */ | |
| if (NULL == ext) { | |
| if (!xsltExtModuleRegisterDynamic(URI)) { | |
| xmlMutexLock(xsltExtMutex); | |
| ext = (xsltExtElementPtr) | |
| xmlHashLookup2(xsltElementsHash, name, URI); | |
| xmlMutexUnlock(xsltExtMutex); | |
| } | |
| } | |
| if (ext == NULL) | |
| return (NULL); | |
| return (ext->transform); | |
| } | |
| /** | |
| * xsltExtModuleElementPreComputeLookup: | |
| * @name: the element name | |
| * @URI: the element namespace URI | |
| * | |
| * Looks up an extension module element pre-computation function | |
| * | |
| * Returns the callback function if found, NULL otherwise. | |
| */ | |
| xsltPreComputeFunction | |
| xsltExtModuleElementPreComputeLookup(const xmlChar * name, | |
| const xmlChar * URI) | |
| { | |
| xsltExtElementPtr ext; | |
| if ((xsltElementsHash == NULL) || (name == NULL) || (URI == NULL)) | |
| return (NULL); | |
| xmlMutexLock(xsltExtMutex); | |
| ext = (xsltExtElementPtr) xmlHashLookup2(xsltElementsHash, name, URI); | |
| xmlMutexUnlock(xsltExtMutex); | |
| if (ext == NULL) { | |
| if (!xsltExtModuleRegisterDynamic(URI)) { | |
| xmlMutexLock(xsltExtMutex); | |
| ext = (xsltExtElementPtr) | |
| xmlHashLookup2(xsltElementsHash, name, URI); | |
| xmlMutexUnlock(xsltExtMutex); | |
| } | |
| } | |
| if (ext == NULL) | |
| return (NULL); | |
| return (ext->precomp); | |
| } | |
| /** | |
| * xsltUnregisterExtModuleElement: | |
| * @name: the element name | |
| * @URI: the element namespace URI | |
| * | |
| * Unregisters an extension module element | |
| * | |
| * Returns 0 if successful, -1 in case of error. | |
| */ | |
| int | |
| xsltUnregisterExtModuleElement(const xmlChar * name, const xmlChar * URI) | |
| { | |
| int ret; | |
| if ((xsltElementsHash == NULL) || (name == NULL) || (URI == NULL)) | |
| return (-1); | |
| xmlMutexLock(xsltExtMutex); | |
| ret = xmlHashRemoveEntry2(xsltElementsHash, name, URI, | |
| (xmlHashDeallocator) xsltFreeExtElement); | |
| xmlMutexUnlock(xsltExtMutex); | |
| return(ret); | |
| } | |
| /** | |
| * xsltUnregisterAllExtModuleElement: | |
| * | |
| * Unregisters all extension module element | |
| */ | |
| static void | |
| xsltUnregisterAllExtModuleElement(void) | |
| { | |
| xmlMutexLock(xsltExtMutex); | |
| xmlHashFree(xsltElementsHash, (xmlHashDeallocator) xsltFreeExtElement); | |
| xsltElementsHash = NULL; | |
| xmlMutexUnlock(xsltExtMutex); | |
| } | |
| /** | |
| * xsltRegisterExtModuleTopLevel: | |
| * @name: the top-level element name | |
| * @URI: the top-level element namespace URI | |
| * @function: the top-level element callback | |
| * | |
| * Registers an extension module top-level element. | |
| * | |
| * Returns 0 if successful, -1 in case of error. | |
| */ | |
| int | |
| xsltRegisterExtModuleTopLevel(const xmlChar * name, const xmlChar * URI, | |
| xsltTopLevelFunction function) | |
| { | |
| if ((name == NULL) || (URI == NULL) || (function == NULL)) | |
| return (-1); | |
| if (xsltTopLevelsHash == NULL) | |
| xsltTopLevelsHash = xmlHashCreate(10); | |
| if (xsltTopLevelsHash == NULL) | |
| return (-1); | |
| xmlMutexLock(xsltExtMutex); | |
| xmlHashUpdateEntry2(xsltTopLevelsHash, name, URI, | |
| XML_CAST_FPTR(function), NULL); | |
| xmlMutexUnlock(xsltExtMutex); | |
| return (0); | |
| } | |
| /** | |
| * xsltExtModuleTopLevelLookup: | |
| * @name: the top-level element name | |
| * @URI: the top-level element namespace URI | |
| * | |
| * Looks up an extension module top-level element | |
| * | |
| * Returns the callback function if found, NULL otherwise. | |
| */ | |
| xsltTopLevelFunction | |
| xsltExtModuleTopLevelLookup(const xmlChar * name, const xmlChar * URI) | |
| { | |
| xsltTopLevelFunction ret; | |
| if ((xsltTopLevelsHash == NULL) || (name == NULL) || (URI == NULL)) | |
| return (NULL); | |
| xmlMutexLock(xsltExtMutex); | |
| XML_CAST_FPTR(ret) = xmlHashLookup2(xsltTopLevelsHash, name, URI); | |
| xmlMutexUnlock(xsltExtMutex); | |
| /* if lookup fails, attempt a dynamic load on supported platforms */ | |
| if (NULL == ret) { | |
| if (!xsltExtModuleRegisterDynamic(URI)) { | |
| xmlMutexLock(xsltExtMutex); | |
| XML_CAST_FPTR(ret) = xmlHashLookup2(xsltTopLevelsHash, name, URI); | |
| xmlMutexUnlock(xsltExtMutex); | |
| } | |
| } | |
| return (ret); | |
| } | |
| /** | |
| * xsltUnregisterExtModuleTopLevel: | |
| * @name: the top-level element name | |
| * @URI: the top-level element namespace URI | |
| * | |
| * Unregisters an extension module top-level element | |
| * | |
| * Returns 0 if successful, -1 in case of error. | |
| */ | |
| int | |
| xsltUnregisterExtModuleTopLevel(const xmlChar * name, const xmlChar * URI) | |
| { | |
| int ret; | |
| if ((xsltTopLevelsHash == NULL) || (name == NULL) || (URI == NULL)) | |
| return (-1); | |
| xmlMutexLock(xsltExtMutex); | |
| ret = xmlHashRemoveEntry2(xsltTopLevelsHash, name, URI, NULL); | |
| xmlMutexUnlock(xsltExtMutex); | |
| return(ret); | |
| } | |
| /** | |
| * xsltUnregisterAllExtModuleTopLevel: | |
| * | |
| * Unregisters all extension module function | |
| */ | |
| static void | |
| xsltUnregisterAllExtModuleTopLevel(void) | |
| { | |
| xmlMutexLock(xsltExtMutex); | |
| xmlHashFree(xsltTopLevelsHash, NULL); | |
| xsltTopLevelsHash = NULL; | |
| xmlMutexUnlock(xsltExtMutex); | |
| } | |
| /** | |
| * xsltGetExtInfo: | |
| * @style: pointer to a stylesheet | |
| * @URI: the namespace URI desired | |
| * | |
| * looks up URI in extInfos of the stylesheet | |
| * | |
| * returns a pointer to the hash table if found, else NULL | |
| */ | |
| xmlHashTablePtr | |
| xsltGetExtInfo(xsltStylesheetPtr style, const xmlChar * URI) | |
| { | |
| xsltExtDataPtr data; | |
| /* | |
| * TODO: Why do we have a return type of xmlHashTablePtr? | |
| * Is the user-allocated data for extension modules expected | |
| * to be a xmlHashTablePtr only? Or is this intended for | |
| * the EXSLT module only? | |
| */ | |
| if (style != NULL && style->extInfos != NULL) { | |
| data = xmlHashLookup(style->extInfos, URI); | |
| if (data != NULL && data->extData != NULL) | |
| return data->extData; | |
| } | |
| return NULL; | |
| } | |
| /************************************************************************ | |
| * * | |
| * Test module http://xmlsoft.org/XSLT/ * | |
| * * | |
| ************************************************************************/ | |
| /************************************************************************ | |
| * * | |
| * Test of the extension module API * | |
| * * | |
| ************************************************************************/ | |
| static xmlChar *testData = NULL; | |
| static xmlChar *testStyleData = NULL; | |
| /** | |
| * xsltExtFunctionTest: | |
| * @ctxt: the XPath Parser context | |
| * @nargs: the number of arguments | |
| * | |
| * function libxslt:test() for testing the extensions support. | |
| */ | |
| static void | |
| xsltExtFunctionTest(xmlXPathParserContextPtr ctxt, | |
| int nargs ATTRIBUTE_UNUSED) | |
| { | |
| xsltTransformContextPtr tctxt; | |
| void *data = NULL; | |
| tctxt = xsltXPathGetTransformContext(ctxt); | |
| if (testData == NULL) { | |
| xsltGenericDebug(xsltGenericDebugContext, | |
| "xsltExtFunctionTest: not initialized," | |
| " calling xsltGetExtData\n"); | |
| data = xsltGetExtData(tctxt, (const xmlChar *) XSLT_DEFAULT_URL); | |
| if (data == NULL) { | |
| xsltTransformError(tctxt, NULL, NULL, | |
| "xsltExtElementTest: not initialized\n"); | |
| return; | |
| } | |
| } | |
| if (tctxt == NULL) { | |
| xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, | |
| "xsltExtFunctionTest: failed to get the transformation context\n"); | |
| return; | |
| } | |
| if (data == NULL) | |
| data = xsltGetExtData(tctxt, (const xmlChar *) XSLT_DEFAULT_URL); | |
| if (data == NULL) { | |
| xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, | |
| "xsltExtFunctionTest: failed to get module data\n"); | |
| return; | |
| } | |
| if (data != testData) { | |
| xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, | |
| "xsltExtFunctionTest: got wrong module data\n"); | |
| return; | |
| } | |
| #ifdef WITH_XSLT_DEBUG_FUNCTION | |
| xsltGenericDebug(xsltGenericDebugContext, | |
| "libxslt:test() called with %d args\n", nargs); | |
| #endif | |
| } | |
| /** | |
| * xsltExtElementPreCompTest: | |
| * @style: the stylesheet | |
| * @inst: the instruction in the stylesheet | |
| * | |
| * Process a libxslt:test node | |
| */ | |
| static xsltElemPreCompPtr | |
| xsltExtElementPreCompTest(xsltStylesheetPtr style, xmlNodePtr inst, | |
| xsltTransformFunction function) | |
| { | |
| xsltElemPreCompPtr ret; | |
| if (style == NULL) { | |
| xsltTransformError(NULL, NULL, inst, | |
| "xsltExtElementTest: no transformation context\n"); | |
| return (NULL); | |
| } | |
| if (testStyleData == NULL) { | |
| xsltGenericDebug(xsltGenericDebugContext, | |
| "xsltExtElementPreCompTest: not initialized," | |
| " calling xsltStyleGetExtData\n"); | |
| xsltStyleGetExtData(style, (const xmlChar *) XSLT_DEFAULT_URL); | |
| if (testStyleData == NULL) { | |
| xsltTransformError(NULL, style, inst, | |
| "xsltExtElementPreCompTest: not initialized\n"); | |
| if (style != NULL) | |
| style->errors++; | |
| return (NULL); | |
| } | |
| } | |
| if (inst == NULL) { | |
| xsltTransformError(NULL, style, inst, | |
| "xsltExtElementPreCompTest: no instruction\n"); | |
| if (style != NULL) | |
| style->errors++; | |
| return (NULL); | |
| } | |
| ret = xsltNewElemPreComp(style, inst, function); | |
| return (ret); | |
| } | |
| /** | |
| * xsltExtElementTest: | |
| * @ctxt: an XSLT processing context | |
| * @node: The current node | |
| * @inst: the instruction in the stylesheet | |
| * @comp: precomputed informations | |
| * | |
| * Process a libxslt:test node | |
| */ | |
| static void | |
| xsltExtElementTest(xsltTransformContextPtr ctxt, xmlNodePtr node, | |
| xmlNodePtr inst, | |
| xsltElemPreCompPtr comp ATTRIBUTE_UNUSED) | |
| { | |
| xmlNodePtr commentNode; | |
| if (testData == NULL) { | |
| xsltGenericDebug(xsltGenericDebugContext, | |
| "xsltExtElementTest: not initialized," | |
| " calling xsltGetExtData\n"); | |
| xsltGetExtData(ctxt, (const xmlChar *) XSLT_DEFAULT_URL); | |
| if (testData == NULL) { | |
| xsltTransformError(ctxt, NULL, inst, | |
| "xsltExtElementTest: not initialized\n"); | |
| return; | |
| } | |
| } | |
| if (ctxt == NULL) { | |
| xsltTransformError(ctxt, NULL, inst, | |
| "xsltExtElementTest: no transformation context\n"); | |
| return; | |
| } | |
| if (node == NULL) { | |
| xsltTransformError(ctxt, NULL, inst, | |
| "xsltExtElementTest: no current node\n"); | |
| return; | |
| } | |
| if (inst == NULL) { | |
| xsltTransformError(ctxt, NULL, inst, | |
| "xsltExtElementTest: no instruction\n"); | |
| return; | |
| } | |
| if (ctxt->insert == NULL) { | |
| xsltTransformError(ctxt, NULL, inst, | |
| "xsltExtElementTest: no insertion point\n"); | |
| return; | |
| } | |
| commentNode = xmlNewComment((const xmlChar *) | |
| "libxslt:test element test worked"); | |
| xmlAddChild(ctxt->insert, commentNode); | |
| } | |
| /** | |
| * xsltExtInitTest: | |
| * @ctxt: an XSLT transformation context | |
| * @URI: the namespace URI for the extension | |
| * | |
| * A function called at initialization time of an XSLT extension module | |
| * | |
| * Returns a pointer to the module specific data for this transformation | |
| */ | |
| static void * | |
| xsltExtInitTest(xsltTransformContextPtr ctxt, const xmlChar * URI) | |
| { | |
| if (testStyleData == NULL) { | |
| xsltGenericDebug(xsltGenericErrorContext, | |
| "xsltExtInitTest: not initialized," | |
| " calling xsltStyleGetExtData\n"); | |
| testStyleData = xsltStyleGetExtData(ctxt->style, URI); | |
| if (testStyleData == NULL) { | |
| xsltTransformError(ctxt, NULL, NULL, | |
| "xsltExtInitTest: not initialized\n"); | |
| return (NULL); | |
| } | |
| } | |
| if (testData != NULL) { | |
| xsltTransformError(ctxt, NULL, NULL, | |
| "xsltExtInitTest: already initialized\n"); | |
| return (NULL); | |
| } | |
| testData = (void *) "test data"; | |
| xsltGenericDebug(xsltGenericDebugContext, | |
| "Registered test module : %s\n", URI); | |
| return (testData); | |
| } | |
| /** | |
| * xsltExtShutdownTest: | |
| * @ctxt: an XSLT transformation context | |
| * @URI: the namespace URI for the extension | |
| * @data: the data associated to this module | |
| * | |
| * A function called at shutdown time of an XSLT extension module | |
| */ | |
| static void | |
| xsltExtShutdownTest(xsltTransformContextPtr ctxt, | |
| const xmlChar * URI, void *data) | |
| { | |
| if (testData == NULL) { | |
| xsltTransformError(ctxt, NULL, NULL, | |
| "xsltExtShutdownTest: not initialized\n"); | |
| return; | |
| } | |
| if (data != testData) { | |
| xsltTransformError(ctxt, NULL, NULL, | |
| "xsltExtShutdownTest: wrong data\n"); | |
| } | |
| testData = NULL; | |
| xsltGenericDebug(xsltGenericDebugContext, | |
| "Unregistered test module : %s\n", URI); | |
| } | |
| /** | |
| * xsltExtStyleInitTest: | |
| * @style: an XSLT stylesheet | |
| * @URI: the namespace URI for the extension | |
| * | |
| * A function called at initialization time of an XSLT extension module | |
| * | |
| * Returns a pointer to the module specific data for this transformation | |
| */ | |
| static void * | |
| xsltExtStyleInitTest(xsltStylesheetPtr style ATTRIBUTE_UNUSED, | |
| const xmlChar * URI) | |
| { | |
| if (testStyleData != NULL) { | |
| xsltTransformError(NULL, NULL, NULL, | |
| "xsltExtInitTest: already initialized\n"); | |
| return (NULL); | |
| } | |
| testStyleData = (void *) "test data"; | |
| xsltGenericDebug(xsltGenericDebugContext, | |
| "Registered test module : %s\n", URI); | |
| return (testStyleData); | |
| } | |
| /** | |
| * xsltExtStyleShutdownTest: | |
| * @style: an XSLT stylesheet | |
| * @URI: the namespace URI for the extension | |
| * @data: the data associated to this module | |
| * | |
| * A function called at shutdown time of an XSLT extension module | |
| */ | |
| static void | |
| xsltExtStyleShutdownTest(xsltStylesheetPtr style ATTRIBUTE_UNUSED, | |
| const xmlChar * URI, void *data) | |
| { | |
| if (testStyleData == NULL) { | |
| xsltGenericError(xsltGenericErrorContext, | |
| "xsltExtShutdownTest: not initialized\n"); | |
| return; | |
| } | |
| if (data != testStyleData) { | |
| xsltTransformError(NULL, NULL, NULL, | |
| "xsltExtShutdownTest: wrong data\n"); | |
| } | |
| testStyleData = NULL; | |
| xsltGenericDebug(xsltGenericDebugContext, | |
| "Unregistered test module : %s\n", URI); | |
| } | |
| /** | |
| * xsltRegisterTestModule: | |
| * | |
| * Registers the test module | |
| */ | |
| void | |
| xsltRegisterTestModule(void) | |
| { | |
| xsltInitGlobals(); | |
| xsltRegisterExtModuleFull((const xmlChar *) XSLT_DEFAULT_URL, | |
| xsltExtInitTest, xsltExtShutdownTest, | |
| xsltExtStyleInitTest, | |
| xsltExtStyleShutdownTest); | |
| xsltRegisterExtModuleFunction((const xmlChar *) "test", | |
| (const xmlChar *) XSLT_DEFAULT_URL, | |
| xsltExtFunctionTest); | |
| xsltRegisterExtModuleElement((const xmlChar *) "test", | |
| (const xmlChar *) XSLT_DEFAULT_URL, | |
| xsltExtElementPreCompTest, | |
| xsltExtElementTest); | |
| } | |
| static void | |
| xsltHashScannerModuleFree(void *payload ATTRIBUTE_UNUSED, | |
| void *data ATTRIBUTE_UNUSED, | |
| xmlChar * name ATTRIBUTE_UNUSED) | |
| { | |
| #ifdef WITH_MODULES | |
| xmlModuleClose(payload); | |
| #endif | |
| } | |
| /** | |
| * xsltInitGlobals: | |
| * | |
| * Initialize the global variables for extensions | |
| */ | |
| void | |
| xsltInitGlobals(void) | |
| { | |
| if (xsltExtMutex == NULL) { | |
| xsltExtMutex = xmlNewMutex(); | |
| } | |
| } | |
| /** | |
| * xsltCleanupGlobals: | |
| * | |
| * Unregister all global variables set up by the XSLT library | |
| */ | |
| void | |
| xsltCleanupGlobals(void) | |
| { | |
| xsltUnregisterAllExtModules(); | |
| xsltUnregisterAllExtModuleFunction(); | |
| xsltUnregisterAllExtModuleElement(); | |
| xsltUnregisterAllExtModuleTopLevel(); | |
| xmlMutexLock(xsltExtMutex); | |
| /* cleanup dynamic module hash */ | |
| if (NULL != xsltModuleHash) { | |
| xmlHashScan(xsltModuleHash, xsltHashScannerModuleFree, 0); | |
| xmlHashFree(xsltModuleHash, NULL); | |
| xsltModuleHash = NULL; | |
| } | |
| xmlMutexUnlock(xsltExtMutex); | |
| xmlFreeMutex(xsltExtMutex); | |
| xsltExtMutex = NULL; | |
| xsltUninit(); | |
| } | |
| static void | |
| xsltDebugDumpExtensionsCallback(void *function ATTRIBUTE_UNUSED, | |
| FILE * output, const xmlChar * name, | |
| const xmlChar * URI, | |
| const xmlChar * not_used ATTRIBUTE_UNUSED) | |
| { | |
| if (!name || !URI) | |
| return; | |
| fprintf(output, "{%s}%s\n", URI, name); | |
| } | |
| static void | |
| xsltDebugDumpExtModulesCallback(void *function ATTRIBUTE_UNUSED, | |
| FILE * output, const xmlChar * URI, | |
| const xmlChar * not_used ATTRIBUTE_UNUSED, | |
| const xmlChar * not_used2 ATTRIBUTE_UNUSED) | |
| { | |
| if (!URI) | |
| return; | |
| fprintf(output, "%s\n", URI); | |
| } | |
| /** | |
| * xsltDebugDumpExtensions: | |
| * @output: the FILE * for the output, if NULL stdout is used | |
| * | |
| * Dumps a list of the registered XSLT extension functions and elements | |
| */ | |
| void | |
| xsltDebugDumpExtensions(FILE * output) | |
| { | |
| if (output == NULL) | |
| output = stdout; | |
| fprintf(output, | |
| "Registered XSLT Extensions\n--------------------------\n"); | |
| if (!xsltFunctionsHash) | |
| fprintf(output, "No registered extension functions\n"); | |
| else { | |
| fprintf(output, "Registered Extension Functions:\n"); | |
| xmlMutexLock(xsltExtMutex); | |
| xmlHashScanFull(xsltFunctionsHash, | |
| (xmlHashScannerFull) | |
| xsltDebugDumpExtensionsCallback, output); | |
| xmlMutexUnlock(xsltExtMutex); | |
| } | |
| if (!xsltElementsHash) | |
| fprintf(output, "\nNo registered extension elements\n"); | |
| else { | |
| fprintf(output, "\nRegistered Extension Elements:\n"); | |
| xmlMutexLock(xsltExtMutex); | |
| xmlHashScanFull(xsltElementsHash, | |
| (xmlHashScannerFull) | |
| xsltDebugDumpExtensionsCallback, output); | |
| xmlMutexUnlock(xsltExtMutex); | |
| } | |
| if (!xsltExtensionsHash) | |
| fprintf(output, "\nNo registered extension modules\n"); | |
| else { | |
| fprintf(output, "\nRegistered Extension Modules:\n"); | |
| xmlMutexLock(xsltExtMutex); | |
| xmlHashScanFull(xsltExtensionsHash, | |
| (xmlHashScannerFull) | |
| xsltDebugDumpExtModulesCallback, output); | |
| xmlMutexUnlock(xsltExtMutex); | |
| } | |
| } |