Synchronize with trunk r58457.
[reactos.git] / dll / 3rdparty / libxslt / extensions.c
1 /*
2 * extensions.c: Implemetation of the extensions support
3 *
4 * Reference:
5 * http://www.w3.org/TR/1999/REC-xslt-19991116
6 *
7 * See Copyright for the status of this software.
8 *
9 * daniel@veillard.com
10 */
11
12 #define IN_LIBXSLT
13 #include "libxslt.h"
14
15 #include <string.h>
16 #include <limits.h>
17
18 #include <libxml/xmlmemory.h>
19 #include <libxml/tree.h>
20 #include <libxml/hash.h>
21 #include <libxml/xmlerror.h>
22 #include <libxml/parserInternals.h>
23 #include <libxml/xpathInternals.h>
24 #ifdef WITH_MODULES
25 #include <libxml/xmlmodule.h>
26 #endif
27 #include <libxml/list.h>
28 #include <libxml/xmlIO.h>
29 #include "xslt.h"
30 #include "xsltInternals.h"
31 #include "xsltutils.h"
32 #include "imports.h"
33 #include "extensions.h"
34
35 #ifdef _WIN32
36 #include <stdlib.h> /* for _MAX_PATH */
37 #ifndef PATH_MAX
38 #define PATH_MAX _MAX_PATH
39 #endif
40 #endif
41
42 #ifdef WITH_XSLT_DEBUG
43 #define WITH_XSLT_DEBUG_EXTENSIONS
44 #endif
45
46 /************************************************************************
47 * *
48 * Private Types and Globals *
49 * *
50 ************************************************************************/
51
52 typedef struct _xsltExtDef xsltExtDef;
53 typedef xsltExtDef *xsltExtDefPtr;
54 struct _xsltExtDef {
55 struct _xsltExtDef *next;
56 xmlChar *prefix;
57 xmlChar *URI;
58 void *data;
59 };
60
61 typedef struct _xsltExtModule xsltExtModule;
62 typedef xsltExtModule *xsltExtModulePtr;
63 struct _xsltExtModule {
64 xsltExtInitFunction initFunc;
65 xsltExtShutdownFunction shutdownFunc;
66 xsltStyleExtInitFunction styleInitFunc;
67 xsltStyleExtShutdownFunction styleShutdownFunc;
68 };
69
70 typedef struct _xsltExtData xsltExtData;
71 typedef xsltExtData *xsltExtDataPtr;
72 struct _xsltExtData {
73 xsltExtModulePtr extModule;
74 void *extData;
75 };
76
77 typedef struct _xsltExtElement xsltExtElement;
78 typedef xsltExtElement *xsltExtElementPtr;
79 struct _xsltExtElement {
80 xsltPreComputeFunction precomp;
81 xsltTransformFunction transform;
82 };
83
84 static xmlHashTablePtr xsltExtensionsHash = NULL;
85 static xmlHashTablePtr xsltFunctionsHash = NULL;
86 static xmlHashTablePtr xsltElementsHash = NULL;
87 static xmlHashTablePtr xsltTopLevelsHash = NULL;
88 static xmlHashTablePtr xsltModuleHash = NULL;
89 static xmlMutexPtr xsltExtMutex = NULL;
90
91 /************************************************************************
92 * *
93 * Type functions *
94 * *
95 ************************************************************************/
96
97 /**
98 * xsltNewExtDef:
99 * @prefix: the extension prefix
100 * @URI: the namespace URI
101 *
102 * Create a new XSLT ExtDef
103 *
104 * Returns the newly allocated xsltExtDefPtr or NULL in case of error
105 */
106 static xsltExtDefPtr
107 xsltNewExtDef(const xmlChar * prefix, const xmlChar * URI)
108 {
109 xsltExtDefPtr cur;
110
111 cur = (xsltExtDefPtr) xmlMalloc(sizeof(xsltExtDef));
112 if (cur == NULL) {
113 xsltTransformError(NULL, NULL, NULL,
114 "xsltNewExtDef : malloc failed\n");
115 return (NULL);
116 }
117 memset(cur, 0, sizeof(xsltExtDef));
118 if (prefix != NULL)
119 cur->prefix = xmlStrdup(prefix);
120 if (URI != NULL)
121 cur->URI = xmlStrdup(URI);
122 return (cur);
123 }
124
125 /**
126 * xsltFreeExtDef:
127 * @extensiond: an XSLT extension definition
128 *
129 * Free up the memory allocated by @extensiond
130 */
131 static void
132 xsltFreeExtDef(xsltExtDefPtr extensiond)
133 {
134 if (extensiond == NULL)
135 return;
136 if (extensiond->prefix != NULL)
137 xmlFree(extensiond->prefix);
138 if (extensiond->URI != NULL)
139 xmlFree(extensiond->URI);
140 xmlFree(extensiond);
141 }
142
143 /**
144 * xsltFreeExtDefList:
145 * @extensiond: an XSLT extension definition list
146 *
147 * Free up the memory allocated by all the elements of @extensiond
148 */
149 static void
150 xsltFreeExtDefList(xsltExtDefPtr extensiond)
151 {
152 xsltExtDefPtr cur;
153
154 while (extensiond != NULL) {
155 cur = extensiond;
156 extensiond = extensiond->next;
157 xsltFreeExtDef(cur);
158 }
159 }
160
161 /**
162 * xsltNewExtModule:
163 * @initFunc: the module initialization function
164 * @shutdownFunc: the module shutdown function
165 * @styleInitFunc: the stylesheet module data allocator function
166 * @styleShutdownFunc: the stylesheet module data free function
167 *
168 * Create a new XSLT extension module
169 *
170 * Returns the newly allocated xsltExtModulePtr or NULL in case of error
171 */
172 static xsltExtModulePtr
173 xsltNewExtModule(xsltExtInitFunction initFunc,
174 xsltExtShutdownFunction shutdownFunc,
175 xsltStyleExtInitFunction styleInitFunc,
176 xsltStyleExtShutdownFunction styleShutdownFunc)
177 {
178 xsltExtModulePtr cur;
179
180 cur = (xsltExtModulePtr) xmlMalloc(sizeof(xsltExtModule));
181 if (cur == NULL) {
182 xsltTransformError(NULL, NULL, NULL,
183 "xsltNewExtModule : malloc failed\n");
184 return (NULL);
185 }
186 cur->initFunc = initFunc;
187 cur->shutdownFunc = shutdownFunc;
188 cur->styleInitFunc = styleInitFunc;
189 cur->styleShutdownFunc = styleShutdownFunc;
190 return (cur);
191 }
192
193 /**
194 * xsltFreeExtModule:
195 * @ext: an XSLT extension module
196 *
197 * Free up the memory allocated by @ext
198 */
199 static void
200 xsltFreeExtModule(xsltExtModulePtr ext)
201 {
202 if (ext == NULL)
203 return;
204 xmlFree(ext);
205 }
206
207 /**
208 * xsltNewExtData:
209 * @extModule: the module
210 * @extData: the associated data
211 *
212 * Create a new XSLT extension module data wrapper
213 *
214 * Returns the newly allocated xsltExtDataPtr or NULL in case of error
215 */
216 static xsltExtDataPtr
217 xsltNewExtData(xsltExtModulePtr extModule, void *extData)
218 {
219 xsltExtDataPtr cur;
220
221 if (extModule == NULL)
222 return (NULL);
223 cur = (xsltExtDataPtr) xmlMalloc(sizeof(xsltExtData));
224 if (cur == NULL) {
225 xsltTransformError(NULL, NULL, NULL,
226 "xsltNewExtData : malloc failed\n");
227 return (NULL);
228 }
229 cur->extModule = extModule;
230 cur->extData = extData;
231 return (cur);
232 }
233
234 /**
235 * xsltFreeExtData:
236 * @ext: an XSLT extension module data wrapper
237 *
238 * Free up the memory allocated by @ext
239 */
240 static void
241 xsltFreeExtData(xsltExtDataPtr ext)
242 {
243 if (ext == NULL)
244 return;
245 xmlFree(ext);
246 }
247
248 /**
249 * xsltNewExtElement:
250 * @precomp: the pre-computation function
251 * @transform: the transformation function
252 *
253 * Create a new XSLT extension element
254 *
255 * Returns the newly allocated xsltExtElementPtr or NULL in case of
256 * error
257 */
258 static xsltExtElementPtr
259 xsltNewExtElement(xsltPreComputeFunction precomp,
260 xsltTransformFunction transform)
261 {
262 xsltExtElementPtr cur;
263
264 if (transform == NULL)
265 return (NULL);
266
267 cur = (xsltExtElementPtr) xmlMalloc(sizeof(xsltExtElement));
268 if (cur == NULL) {
269 xsltTransformError(NULL, NULL, NULL,
270 "xsltNewExtElement : malloc failed\n");
271 return (NULL);
272 }
273 cur->precomp = precomp;
274 cur->transform = transform;
275 return (cur);
276 }
277
278 /**
279 * xsltFreeExtElement:
280 * @ext: an XSLT extension element
281 *
282 * Frees up the memory allocated by @ext
283 */
284 static void
285 xsltFreeExtElement(xsltExtElementPtr ext)
286 {
287 if (ext == NULL)
288 return;
289 xmlFree(ext);
290 }
291
292
293 #ifdef WITH_MODULES
294 typedef void (*exsltRegisterFunction) (void);
295
296 #ifndef PATH_MAX
297 #define PATH_MAX 4096
298 #endif
299
300 /**
301 * xsltExtModuleRegisterDynamic:
302 * @URI: the function or element namespace URI
303 *
304 * Dynamically loads an extension plugin when available.
305 *
306 * The plugin name is derived from the URI by removing the
307 * initial protocol designation, e.g. "http://", then converting
308 * the characters ".", "-", "/", and "\" into "_", the removing
309 * any trailing "/", then concatenating LIBXML_MODULE_EXTENSION.
310 *
311 * Plugins are loaded from the directory specified by the
312 * environment variable LIBXSLT_PLUGINS_PATH, or if NULL,
313 * by LIBXSLT_DEFAULT_PLUGINS_PATH() which is determined at
314 * compile time.
315 *
316 * Returns 0 if successful, -1 in case of error.
317 */
318
319 static int
320 xsltExtModuleRegisterDynamic(const xmlChar * URI)
321 {
322
323 xmlModulePtr m;
324 exsltRegisterFunction regfunc;
325 xmlChar *ext_name;
326 char module_filename[PATH_MAX];
327 const xmlChar *ext_directory = NULL;
328 const xmlChar *protocol = NULL;
329 xmlChar *i, *regfunc_name;
330 void *vregfunc;
331 int rc;
332
333 /* check for bad inputs */
334 if (URI == NULL)
335 return (-1);
336
337 if (NULL == xsltModuleHash) {
338 xsltModuleHash = xmlHashCreate(5);
339 if (xsltModuleHash == NULL)
340 return (-1);
341 }
342
343 xmlMutexLock(xsltExtMutex);
344
345 /* have we attempted to register this module already? */
346 if (xmlHashLookup(xsltModuleHash, URI) != NULL) {
347 xmlMutexUnlock(xsltExtMutex);
348 return (-1);
349 }
350 xmlMutexUnlock(xsltExtMutex);
351
352 /* transform extension namespace into a module name */
353 protocol = xmlStrstr(URI, BAD_CAST "://");
354 if (protocol == NULL) {
355 ext_name = xmlStrdup(URI);
356 } else {
357 ext_name = xmlStrdup(protocol + 3);
358 }
359 if (ext_name == NULL) {
360 return (-1);
361 }
362
363 i = ext_name;
364 while ('\0' != *i) {
365 if (('/' == *i) || ('\\' == *i) || ('.' == *i) || ('-' == *i))
366 *i = '_';
367 i++;
368 }
369
370 if (*(i - 1) == '_')
371 *i = '\0';
372
373 /* determine module directory */
374 ext_directory = (xmlChar *) getenv("LIBXSLT_PLUGINS_PATH");
375
376 if (NULL == ext_directory) {
377 ext_directory = BAD_CAST LIBXSLT_DEFAULT_PLUGINS_PATH();
378 if (NULL == ext_directory)
379 return (-1);
380 }
381 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
382 else
383 xsltGenericDebug(xsltGenericDebugContext,
384 "LIBXSLT_PLUGINS_PATH is %s\n", ext_directory);
385 #endif
386
387 /* build the module filename, and confirm the module exists */
388 xmlStrPrintf((xmlChar *) module_filename, sizeof(module_filename),
389 BAD_CAST "%s/%s%s",
390 ext_directory, ext_name, LIBXML_MODULE_EXTENSION);
391
392 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
393 xsltGenericDebug(xsltGenericDebugContext,
394 "Attempting to load plugin: %s for URI: %s\n",
395 module_filename, URI);
396 #endif
397
398 if (1 != xmlCheckFilename(module_filename)) {
399
400 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
401 xsltGenericDebug(xsltGenericDebugContext,
402 "xmlCheckFilename failed for plugin: %s\n", module_filename);
403 #endif
404
405 xmlFree(ext_name);
406 return (-1);
407 }
408
409 /* attempt to open the module */
410 m = xmlModuleOpen(module_filename, 0);
411 if (NULL == m) {
412
413 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
414 xsltGenericDebug(xsltGenericDebugContext,
415 "xmlModuleOpen failed for plugin: %s\n", module_filename);
416 #endif
417
418 xmlFree(ext_name);
419 return (-1);
420 }
421
422 /* construct initialization func name */
423 regfunc_name = xmlStrdup(ext_name);
424 regfunc_name = xmlStrcat(regfunc_name, BAD_CAST "_init");
425
426 vregfunc = NULL;
427 rc = xmlModuleSymbol(m, (const char *) regfunc_name, &vregfunc);
428 regfunc = vregfunc;
429 if (0 == rc) {
430 /*
431 * Call the module's init function. Note that this function
432 * calls xsltRegisterExtModuleFull which will add the module
433 * to xsltExtensionsHash (together with it's entry points).
434 */
435 (*regfunc) ();
436
437 /* register this module in our hash */
438 xmlMutexLock(xsltExtMutex);
439 xmlHashAddEntry(xsltModuleHash, URI, (void *) m);
440 xmlMutexUnlock(xsltExtMutex);
441 } else {
442
443 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
444 xsltGenericDebug(xsltGenericDebugContext,
445 "xmlModuleSymbol failed for plugin: %s, regfunc: %s\n",
446 module_filename, regfunc_name);
447 #endif
448
449 /* if regfunc not found unload the module immediately */
450 xmlModuleClose(m);
451 }
452
453 xmlFree(ext_name);
454 xmlFree(regfunc_name);
455 return (NULL == regfunc) ? -1 : 0;
456 }
457 #else
458 static int
459 xsltExtModuleRegisterDynamic(const xmlChar * URI ATTRIBUTE_UNUSED)
460 {
461 return -1;
462 }
463 #endif
464
465 /************************************************************************
466 * *
467 * The stylesheet extension prefixes handling *
468 * *
469 ************************************************************************/
470
471
472 /**
473 * xsltFreeExts:
474 * @style: an XSLT stylesheet
475 *
476 * Free up the memory used by XSLT extensions in a stylesheet
477 */
478 void
479 xsltFreeExts(xsltStylesheetPtr style)
480 {
481 if (style->nsDefs != NULL)
482 xsltFreeExtDefList((xsltExtDefPtr) style->nsDefs);
483 }
484
485 /**
486 * xsltRegisterExtPrefix:
487 * @style: an XSLT stylesheet
488 * @prefix: the prefix used (optional)
489 * @URI: the URI associated to the extension
490 *
491 * Registers an extension namespace
492 * This is called from xslt.c during compile-time.
493 * The given prefix is not needed.
494 * Called by:
495 * xsltParseExtElemPrefixes() (new function)
496 * xsltRegisterExtPrefix() (old function)
497 *
498 * Returns 0 in case of success, 1 if the @URI was already
499 * registered as an extension namespace and
500 * -1 in case of failure
501 */
502 int
503 xsltRegisterExtPrefix(xsltStylesheetPtr style,
504 const xmlChar * prefix, const xmlChar * URI)
505 {
506 xsltExtDefPtr def, ret;
507
508 if ((style == NULL) || (URI == NULL))
509 return (-1);
510
511 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
512 xsltGenericDebug(xsltGenericDebugContext,
513 "Registering extension namespace '%s'.\n", URI);
514 #endif
515 def = (xsltExtDefPtr) style->nsDefs;
516 #ifdef XSLT_REFACTORED
517 /*
518 * The extension is associated with a namespace name.
519 */
520 while (def != NULL) {
521 if (xmlStrEqual(URI, def->URI))
522 return (1);
523 def = def->next;
524 }
525 #else
526 while (def != NULL) {
527 if (xmlStrEqual(prefix, def->prefix))
528 return (-1);
529 def = def->next;
530 }
531 #endif
532 ret = xsltNewExtDef(prefix, URI);
533 if (ret == NULL)
534 return (-1);
535 ret->next = (xsltExtDefPtr) style->nsDefs;
536 style->nsDefs = ret;
537
538 /*
539 * check whether there is an extension module with a stylesheet
540 * initialization function.
541 */
542 #ifdef XSLT_REFACTORED
543 /*
544 * Don't initialize modules based on specified namespaces via
545 * the attribute "[xsl:]extension-element-prefixes".
546 */
547 #else
548 if (xsltExtensionsHash != NULL) {
549 xsltExtModulePtr module;
550
551 xmlMutexLock(xsltExtMutex);
552 module = xmlHashLookup(xsltExtensionsHash, URI);
553 xmlMutexUnlock(xsltExtMutex);
554 if (NULL == module) {
555 if (!xsltExtModuleRegisterDynamic(URI)) {
556 xmlMutexLock(xsltExtMutex);
557 module = xmlHashLookup(xsltExtensionsHash, URI);
558 xmlMutexUnlock(xsltExtMutex);
559 }
560 }
561 if (module != NULL) {
562 xsltStyleGetExtData(style, URI);
563 }
564 }
565 #endif
566 return (0);
567 }
568
569 /************************************************************************
570 * *
571 * The extensions modules interfaces *
572 * *
573 ************************************************************************/
574
575 /**
576 * xsltRegisterExtFunction:
577 * @ctxt: an XSLT transformation context
578 * @name: the name of the element
579 * @URI: the URI associated to the element
580 * @function: the actual implementation which should be called
581 *
582 * Registers an extension function
583 *
584 * Returns 0 in case of success, -1 in case of failure
585 */
586 int
587 xsltRegisterExtFunction(xsltTransformContextPtr ctxt, const xmlChar * name,
588 const xmlChar * URI, xmlXPathFunction function)
589 {
590 int ret;
591
592 if ((ctxt == NULL) || (name == NULL) ||
593 (URI == NULL) || (function == NULL))
594 return (-1);
595 if (ctxt->xpathCtxt != NULL) {
596 xmlXPathRegisterFuncNS(ctxt->xpathCtxt, name, URI, function);
597 }
598 if (ctxt->extFunctions == NULL)
599 ctxt->extFunctions = xmlHashCreate(10);
600 if (ctxt->extFunctions == NULL)
601 return (-1);
602
603 ret = xmlHashAddEntry2(ctxt->extFunctions, name, URI,
604 XML_CAST_FPTR(function));
605
606 return(ret);
607 }
608
609 /**
610 * xsltRegisterExtElement:
611 * @ctxt: an XSLT transformation context
612 * @name: the name of the element
613 * @URI: the URI associated to the element
614 * @function: the actual implementation which should be called
615 *
616 * Registers an extension element
617 *
618 * Returns 0 in case of success, -1 in case of failure
619 */
620 int
621 xsltRegisterExtElement(xsltTransformContextPtr ctxt, const xmlChar * name,
622 const xmlChar * URI, xsltTransformFunction function)
623 {
624 if ((ctxt == NULL) || (name == NULL) ||
625 (URI == NULL) || (function == NULL))
626 return (-1);
627 if (ctxt->extElements == NULL)
628 ctxt->extElements = xmlHashCreate(10);
629 if (ctxt->extElements == NULL)
630 return (-1);
631 return (xmlHashAddEntry2
632 (ctxt->extElements, name, URI, XML_CAST_FPTR(function)));
633 }
634
635 /**
636 * xsltFreeCtxtExts:
637 * @ctxt: an XSLT transformation context
638 *
639 * Free the XSLT extension data
640 */
641 void
642 xsltFreeCtxtExts(xsltTransformContextPtr ctxt)
643 {
644 if (ctxt->extElements != NULL)
645 xmlHashFree(ctxt->extElements, NULL);
646 if (ctxt->extFunctions != NULL)
647 xmlHashFree(ctxt->extFunctions, NULL);
648 }
649
650 /**
651 * xsltStyleGetStylesheetExtData:
652 * @style: an XSLT stylesheet
653 * @URI: the URI associated to the exension module
654 *
655 * Fires the compile-time initialization callback
656 * of an extension module and returns a container
657 * holding the user-data (retrieved via the callback).
658 *
659 * Returns the create module-data container
660 * or NULL if such a module was not registered.
661 */
662 static xsltExtDataPtr
663 xsltStyleInitializeStylesheetModule(xsltStylesheetPtr style,
664 const xmlChar * URI)
665 {
666 xsltExtDataPtr dataContainer;
667 void *userData = NULL;
668 xsltExtModulePtr module;
669
670 if ((style == NULL) || (URI == NULL))
671 return(NULL);
672
673 if (xsltExtensionsHash == NULL) {
674 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
675 xsltGenericDebug(xsltGenericDebugContext,
676 "Not registered extension module: %s\n", URI);
677 #endif
678 return(NULL);
679 }
680
681 xmlMutexLock(xsltExtMutex);
682
683 module = xmlHashLookup(xsltExtensionsHash, URI);
684
685 xmlMutexUnlock(xsltExtMutex);
686
687 if (module == NULL) {
688 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
689 xsltGenericDebug(xsltGenericDebugContext,
690 "Not registered extension module: %s\n", URI);
691 #endif
692 return (NULL);
693 }
694 /*
695 * The specified module was registered so initialize it.
696 */
697 if (style->extInfos == NULL) {
698 style->extInfos = xmlHashCreate(10);
699 if (style->extInfos == NULL)
700 return (NULL);
701 }
702 /*
703 * Fire the initialization callback if available.
704 */
705 if (module->styleInitFunc == NULL) {
706 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
707 xsltGenericDebug(xsltGenericDebugContext,
708 "Initializing module with *no* callback: %s\n", URI);
709 #endif
710 } else {
711 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
712 xsltGenericDebug(xsltGenericDebugContext,
713 "Initializing module with callback: %s\n", URI);
714 #endif
715 /*
716 * Fire the initialization callback.
717 */
718 userData = module->styleInitFunc(style, URI);
719 }
720 /*
721 * Store the user-data in the context of the given stylesheet.
722 */
723 dataContainer = xsltNewExtData(module, userData);
724 if (dataContainer == NULL)
725 return (NULL);
726
727 if (xmlHashAddEntry(style->extInfos, URI,
728 (void *) dataContainer) < 0)
729 {
730 xsltTransformError(NULL, style, NULL,
731 "Failed to register module '%s'.\n", URI);
732 style->errors++;
733 if (module->styleShutdownFunc)
734 module->styleShutdownFunc(style, URI, userData);
735 xsltFreeExtData(dataContainer);
736 return (NULL);
737 }
738
739 return(dataContainer);
740 }
741
742 /**
743 * xsltStyleGetExtData:
744 * @style: an XSLT stylesheet
745 * @URI: the URI associated to the exension module
746 *
747 * Retrieve the data associated to the extension module
748 * in this given stylesheet.
749 * Called by:
750 * xsltRegisterExtPrefix(),
751 * ( xsltExtElementPreCompTest(), xsltExtInitTest )
752 *
753 * Returns the pointer or NULL if not present
754 */
755 void *
756 xsltStyleGetExtData(xsltStylesheetPtr style, const xmlChar * URI)
757 {
758 xsltExtDataPtr dataContainer = NULL;
759 xsltStylesheetPtr tmpStyle;
760
761 if ((style == NULL) || (URI == NULL) ||
762 (xsltExtensionsHash == NULL))
763 return (NULL);
764
765
766 #ifdef XSLT_REFACTORED
767 /*
768 * This is intended for global storage, so only the main
769 * stylesheet will hold the data.
770 */
771 tmpStyle = style;
772 while (tmpStyle->parent != NULL)
773 tmpStyle = tmpStyle->parent;
774 if (tmpStyle->extInfos != NULL) {
775 dataContainer =
776 (xsltExtDataPtr) xmlHashLookup(tmpStyle->extInfos, URI);
777 if (dataContainer != NULL) {
778 /*
779 * The module was already initialized in the context
780 * of this stylesheet; just return the user-data that
781 * comes with it.
782 */
783 return(dataContainer->extData);
784 }
785 }
786 #else
787 /*
788 * Old behaviour.
789 */
790 tmpStyle = style;
791 while (tmpStyle != NULL) {
792 if (tmpStyle->extInfos != NULL) {
793 dataContainer =
794 (xsltExtDataPtr) xmlHashLookup(tmpStyle->extInfos, URI);
795 if (dataContainer != NULL) {
796 return(dataContainer->extData);
797 }
798 }
799 tmpStyle = xsltNextImport(tmpStyle);
800 }
801 tmpStyle = style;
802 #endif
803
804 dataContainer =
805 xsltStyleInitializeStylesheetModule(tmpStyle, URI);
806 if (dataContainer != NULL)
807 return (dataContainer->extData);
808 return(NULL);
809 }
810
811 #ifdef XSLT_REFACTORED
812 /**
813 * xsltStyleStylesheetLevelGetExtData:
814 * @style: an XSLT stylesheet
815 * @URI: the URI associated to the exension module
816 *
817 * Retrieve the data associated to the extension module in this given
818 * stylesheet.
819 *
820 * Returns the pointer or NULL if not present
821 */
822 void *
823 xsltStyleStylesheetLevelGetExtData(xsltStylesheetPtr style,
824 const xmlChar * URI)
825 {
826 xsltExtDataPtr dataContainer = NULL;
827
828 if ((style == NULL) || (URI == NULL) ||
829 (xsltExtensionsHash == NULL))
830 return (NULL);
831
832 if (style->extInfos != NULL) {
833 dataContainer = (xsltExtDataPtr) xmlHashLookup(style->extInfos, URI);
834 /*
835 * The module was already initialized in the context
836 * of this stylesheet; just return the user-data that
837 * comes with it.
838 */
839 if (dataContainer)
840 return(dataContainer->extData);
841 }
842
843 dataContainer =
844 xsltStyleInitializeStylesheetModule(style, URI);
845 if (dataContainer != NULL)
846 return (dataContainer->extData);
847 return(NULL);
848 }
849 #endif
850
851 /**
852 * xsltGetExtData:
853 * @ctxt: an XSLT transformation context
854 * @URI: the URI associated to the exension module
855 *
856 * Retrieve the data associated to the extension module in this given
857 * transformation.
858 *
859 * Returns the pointer or NULL if not present
860 */
861 void *
862 xsltGetExtData(xsltTransformContextPtr ctxt, const xmlChar * URI)
863 {
864 xsltExtDataPtr data;
865
866 if ((ctxt == NULL) || (URI == NULL))
867 return (NULL);
868 if (ctxt->extInfos == NULL) {
869 ctxt->extInfos = xmlHashCreate(10);
870 if (ctxt->extInfos == NULL)
871 return (NULL);
872 data = NULL;
873 } else {
874 data = (xsltExtDataPtr) xmlHashLookup(ctxt->extInfos, URI);
875 }
876 if (data == NULL) {
877 void *extData;
878 xsltExtModulePtr module;
879
880 xmlMutexLock(xsltExtMutex);
881
882 module = xmlHashLookup(xsltExtensionsHash, URI);
883
884 xmlMutexUnlock(xsltExtMutex);
885
886 if (module == NULL) {
887 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
888 xsltGenericDebug(xsltGenericDebugContext,
889 "Not registered extension module: %s\n", URI);
890 #endif
891 return (NULL);
892 } else {
893 if (module->initFunc == NULL)
894 return (NULL);
895
896 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
897 xsltGenericDebug(xsltGenericDebugContext,
898 "Initializing module: %s\n", URI);
899 #endif
900
901 extData = module->initFunc(ctxt, URI);
902 if (extData == NULL)
903 return (NULL);
904
905 data = xsltNewExtData(module, extData);
906 if (data == NULL)
907 return (NULL);
908 if (xmlHashAddEntry(ctxt->extInfos, URI, (void *) data) < 0) {
909 xsltTransformError(ctxt, NULL, NULL,
910 "Failed to register module data: %s\n",
911 URI);
912 if (module->shutdownFunc)
913 module->shutdownFunc(ctxt, URI, extData);
914 xsltFreeExtData(data);
915 return (NULL);
916 }
917 }
918 }
919 return (data->extData);
920 }
921
922 typedef struct _xsltInitExtCtxt xsltInitExtCtxt;
923 struct _xsltInitExtCtxt {
924 xsltTransformContextPtr ctxt;
925 int ret;
926 };
927
928 /**
929 * xsltInitCtxtExt:
930 * @styleData: the registered stylesheet data for the module
931 * @ctxt: the XSLT transformation context + the return value
932 * @URI: the extension URI
933 *
934 * Initializes an extension module
935 */
936 static void
937 xsltInitCtxtExt(xsltExtDataPtr styleData, xsltInitExtCtxt * ctxt,
938 const xmlChar * URI)
939 {
940 xsltExtModulePtr module;
941 xsltExtDataPtr ctxtData;
942 void *extData;
943
944 if ((styleData == NULL) || (ctxt == NULL) || (URI == NULL) ||
945 (ctxt->ret == -1)) {
946 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
947 xsltGenericDebug(xsltGenericDebugContext,
948 "xsltInitCtxtExt: NULL param or error\n");
949 #endif
950 return;
951 }
952 module = styleData->extModule;
953 if ((module == NULL) || (module->initFunc == NULL)) {
954 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
955 xsltGenericDebug(xsltGenericDebugContext,
956 "xsltInitCtxtExt: no module or no initFunc\n");
957 #endif
958 return;
959 }
960
961 ctxtData = (xsltExtDataPtr) xmlHashLookup(ctxt->ctxt->extInfos, URI);
962 if (ctxtData != NULL) {
963 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
964 xsltGenericDebug(xsltGenericDebugContext,
965 "xsltInitCtxtExt: already initialized\n");
966 #endif
967 return;
968 }
969
970 extData = module->initFunc(ctxt->ctxt, URI);
971 if (extData == NULL) {
972 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
973 xsltGenericDebug(xsltGenericDebugContext,
974 "xsltInitCtxtExt: no extData\n");
975 #endif
976 }
977 ctxtData = xsltNewExtData(module, extData);
978 if (ctxtData == NULL) {
979 ctxt->ret = -1;
980 return;
981 }
982
983 if (ctxt->ctxt->extInfos == NULL)
984 ctxt->ctxt->extInfos = xmlHashCreate(10);
985 if (ctxt->ctxt->extInfos == NULL) {
986 ctxt->ret = -1;
987 return;
988 }
989
990 if (xmlHashAddEntry(ctxt->ctxt->extInfos, URI, ctxtData) < 0) {
991 xsltGenericError(xsltGenericErrorContext,
992 "Failed to register module data: %s\n", URI);
993 if (module->shutdownFunc)
994 module->shutdownFunc(ctxt->ctxt, URI, extData);
995 xsltFreeExtData(ctxtData);
996 ctxt->ret = -1;
997 return;
998 }
999 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
1000 xsltGenericDebug(xsltGenericDebugContext, "Registered module %s\n",
1001 URI);
1002 #endif
1003 ctxt->ret++;
1004 }
1005
1006 /**
1007 * xsltInitCtxtExts:
1008 * @ctxt: an XSLT transformation context
1009 *
1010 * Initialize the set of modules with registered stylesheet data
1011 *
1012 * Returns the number of modules initialized or -1 in case of error
1013 */
1014 int
1015 xsltInitCtxtExts(xsltTransformContextPtr ctxt)
1016 {
1017 xsltStylesheetPtr style;
1018 xsltInitExtCtxt ctx;
1019
1020 if (ctxt == NULL)
1021 return (-1);
1022
1023 style = ctxt->style;
1024 if (style == NULL)
1025 return (-1);
1026
1027 ctx.ctxt = ctxt;
1028 ctx.ret = 0;
1029
1030 while (style != NULL) {
1031 if (style->extInfos != NULL) {
1032 xmlHashScan(style->extInfos,
1033 (xmlHashScanner) xsltInitCtxtExt, &ctx);
1034 if (ctx.ret == -1)
1035 return (-1);
1036 }
1037 style = xsltNextImport(style);
1038 }
1039 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
1040 xsltGenericDebug(xsltGenericDebugContext, "Registered %d modules\n",
1041 ctx.ret);
1042 #endif
1043 return (ctx.ret);
1044 }
1045
1046 /**
1047 * xsltShutdownCtxtExt:
1048 * @data: the registered data for the module
1049 * @ctxt: the XSLT transformation context
1050 * @URI: the extension URI
1051 *
1052 * Shutdown an extension module loaded
1053 */
1054 static void
1055 xsltShutdownCtxtExt(xsltExtDataPtr data, xsltTransformContextPtr ctxt,
1056 const xmlChar * URI)
1057 {
1058 xsltExtModulePtr module;
1059
1060 if ((data == NULL) || (ctxt == NULL) || (URI == NULL))
1061 return;
1062 module = data->extModule;
1063 if ((module == NULL) || (module->shutdownFunc == NULL))
1064 return;
1065
1066 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
1067 xsltGenericDebug(xsltGenericDebugContext,
1068 "Shutting down module : %s\n", URI);
1069 #endif
1070 module->shutdownFunc(ctxt, URI, data->extData);
1071 }
1072
1073 /**
1074 * xsltShutdownCtxtExts:
1075 * @ctxt: an XSLT transformation context
1076 *
1077 * Shutdown the set of modules loaded
1078 */
1079 void
1080 xsltShutdownCtxtExts(xsltTransformContextPtr ctxt)
1081 {
1082 if (ctxt == NULL)
1083 return;
1084 if (ctxt->extInfos == NULL)
1085 return;
1086 xmlHashScan(ctxt->extInfos, (xmlHashScanner) xsltShutdownCtxtExt,
1087 ctxt);
1088 xmlHashFree(ctxt->extInfos, (xmlHashDeallocator) xsltFreeExtData);
1089 ctxt->extInfos = NULL;
1090 }
1091
1092 /**
1093 * xsltShutdownExt:
1094 * @data: the registered data for the module
1095 * @ctxt: the XSLT stylesheet
1096 * @URI: the extension URI
1097 *
1098 * Shutdown an extension module loaded
1099 */
1100 static void
1101 xsltShutdownExt(xsltExtDataPtr data, xsltStylesheetPtr style,
1102 const xmlChar * URI)
1103 {
1104 xsltExtModulePtr module;
1105
1106 if ((data == NULL) || (style == NULL) || (URI == NULL))
1107 return;
1108 module = data->extModule;
1109 if ((module == NULL) || (module->styleShutdownFunc == NULL))
1110 return;
1111
1112 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
1113 xsltGenericDebug(xsltGenericDebugContext,
1114 "Shutting down module : %s\n", URI);
1115 #endif
1116 module->styleShutdownFunc(style, URI, data->extData);
1117 /*
1118 * Don't remove the entry from the hash table here, since
1119 * this will produce segfaults - this fixes bug #340624.
1120 *
1121 * xmlHashRemoveEntry(style->extInfos, URI,
1122 * (xmlHashDeallocator) xsltFreeExtData);
1123 */
1124 }
1125
1126 /**
1127 * xsltShutdownExts:
1128 * @style: an XSLT stylesheet
1129 *
1130 * Shutdown the set of modules loaded
1131 */
1132 void
1133 xsltShutdownExts(xsltStylesheetPtr style)
1134 {
1135 if (style == NULL)
1136 return;
1137 if (style->extInfos == NULL)
1138 return;
1139 xmlHashScan(style->extInfos, (xmlHashScanner) xsltShutdownExt, style);
1140 xmlHashFree(style->extInfos, (xmlHashDeallocator) xsltFreeExtData);
1141 style->extInfos = NULL;
1142 }
1143
1144 /**
1145 * xsltCheckExtPrefix:
1146 * @style: the stylesheet
1147 * @URI: the namespace prefix (possibly NULL)
1148 *
1149 * Check if the given prefix is one of the declared extensions.
1150 * This is intended to be called only at compile-time.
1151 * Called by:
1152 * xsltGetInheritedNsList() (xslt.c)
1153 * xsltParseTemplateContent (xslt.c)
1154 *
1155 * Returns 1 if this is an extension, 0 otherwise
1156 */
1157 int
1158 xsltCheckExtPrefix(xsltStylesheetPtr style, const xmlChar * URI)
1159 {
1160 #ifdef XSLT_REFACTORED
1161 if ((style == NULL) || (style->compCtxt == NULL) ||
1162 (XSLT_CCTXT(style)->inode == NULL) ||
1163 (XSLT_CCTXT(style)->inode->extElemNs == NULL))
1164 return (0);
1165 /*
1166 * Lookup the extension namespaces registered
1167 * at the current node in the stylesheet's tree.
1168 */
1169 if (XSLT_CCTXT(style)->inode->extElemNs != NULL) {
1170 int i;
1171 xsltPointerListPtr list = XSLT_CCTXT(style)->inode->extElemNs;
1172
1173 for (i = 0; i < list->number; i++) {
1174 if (xmlStrEqual((const xmlChar *) list->items[i],
1175 URI))
1176 {
1177 return(1);
1178 }
1179 }
1180 }
1181 #else
1182 xsltExtDefPtr cur;
1183
1184 if ((style == NULL) || (style->nsDefs == NULL))
1185 return (0);
1186 if (URI == NULL)
1187 URI = BAD_CAST "#default";
1188 cur = (xsltExtDefPtr) style->nsDefs;
1189 while (cur != NULL) {
1190 /*
1191 * NOTE: This was change to work on namespace names rather
1192 * than namespace prefixes. This fixes bug #339583.
1193 * TODO: Consider renaming the field "prefix" of xsltExtDef
1194 * to "href".
1195 */
1196 if (xmlStrEqual(URI, cur->prefix))
1197 return (1);
1198 cur = cur->next;
1199 }
1200 #endif
1201 return (0);
1202 }
1203
1204 /**
1205 * xsltCheckExtURI:
1206 * @style: the stylesheet
1207 * @URI: the namespace URI (possibly NULL)
1208 *
1209 * Check if the given prefix is one of the declared extensions.
1210 * This is intended to be called only at compile-time.
1211 * Called by:
1212 * xsltPrecomputeStylesheet() (xslt.c)
1213 * xsltParseTemplateContent (xslt.c)
1214 *
1215 * Returns 1 if this is an extension, 0 otherwise
1216 */
1217 int
1218 xsltCheckExtURI(xsltStylesheetPtr style, const xmlChar * URI)
1219 {
1220 xsltExtDefPtr cur;
1221
1222 if ((style == NULL) || (style->nsDefs == NULL))
1223 return (0);
1224 if (URI == NULL)
1225 return (0);
1226 cur = (xsltExtDefPtr) style->nsDefs;
1227 while (cur != NULL) {
1228 if (xmlStrEqual(URI, cur->URI))
1229 return (1);
1230 cur = cur->next;
1231 }
1232 return (0);
1233 }
1234
1235 /**
1236 * xsltRegisterExtModuleFull:
1237 * @URI: URI associated to this module
1238 * @initFunc: the module initialization function
1239 * @shutdownFunc: the module shutdown function
1240 * @styleInitFunc: the module initialization function
1241 * @styleShutdownFunc: the module shutdown function
1242 *
1243 * Register an XSLT extension module to the library.
1244 *
1245 * Returns 0 if sucessful, -1 in case of error
1246 */
1247 int
1248 xsltRegisterExtModuleFull(const xmlChar * URI,
1249 xsltExtInitFunction initFunc,
1250 xsltExtShutdownFunction shutdownFunc,
1251 xsltStyleExtInitFunction styleInitFunc,
1252 xsltStyleExtShutdownFunction styleShutdownFunc)
1253 {
1254 int ret;
1255 xsltExtModulePtr module;
1256
1257 if ((URI == NULL) || (initFunc == NULL))
1258 return (-1);
1259 if (xsltExtensionsHash == NULL)
1260 xsltExtensionsHash = xmlHashCreate(10);
1261
1262 if (xsltExtensionsHash == NULL)
1263 return (-1);
1264
1265 xmlMutexLock(xsltExtMutex);
1266
1267 module = xmlHashLookup(xsltExtensionsHash, URI);
1268 if (module != NULL) {
1269 if ((module->initFunc == initFunc) &&
1270 (module->shutdownFunc == shutdownFunc))
1271 ret = 0;
1272 else
1273 ret = -1;
1274 goto done;
1275 }
1276 module = xsltNewExtModule(initFunc, shutdownFunc,
1277 styleInitFunc, styleShutdownFunc);
1278 if (module == NULL) {
1279 ret = -1;
1280 goto done;
1281 }
1282 ret = xmlHashAddEntry(xsltExtensionsHash, URI, (void *) module);
1283
1284 done:
1285 xmlMutexUnlock(xsltExtMutex);
1286 return (ret);
1287 }
1288
1289 /**
1290 * xsltRegisterExtModule:
1291 * @URI: URI associated to this module
1292 * @initFunc: the module initialization function
1293 * @shutdownFunc: the module shutdown function
1294 *
1295 * Register an XSLT extension module to the library.
1296 *
1297 * Returns 0 if sucessful, -1 in case of error
1298 */
1299 int
1300 xsltRegisterExtModule(const xmlChar * URI,
1301 xsltExtInitFunction initFunc,
1302 xsltExtShutdownFunction shutdownFunc)
1303 {
1304 return xsltRegisterExtModuleFull(URI, initFunc, shutdownFunc,
1305 NULL, NULL);
1306 }
1307
1308 /**
1309 * xsltUnregisterExtModule:
1310 * @URI: URI associated to this module
1311 *
1312 * Unregister an XSLT extension module from the library.
1313 *
1314 * Returns 0 if sucessful, -1 in case of error
1315 */
1316 int
1317 xsltUnregisterExtModule(const xmlChar * URI)
1318 {
1319 int ret;
1320
1321 if (URI == NULL)
1322 return (-1);
1323 if (xsltExtensionsHash == NULL)
1324 return (-1);
1325
1326 xmlMutexLock(xsltExtMutex);
1327
1328 ret = xmlHashRemoveEntry(xsltExtensionsHash, URI,
1329 (xmlHashDeallocator) xsltFreeExtModule);
1330
1331 xmlMutexUnlock(xsltExtMutex);
1332
1333 return (ret);
1334 }
1335
1336 /**
1337 * xsltUnregisterAllExtModules:
1338 *
1339 * Unregister all the XSLT extension module from the library.
1340 */
1341 static void
1342 xsltUnregisterAllExtModules(void)
1343 {
1344 if (xsltExtensionsHash == NULL)
1345 return;
1346
1347 xmlMutexLock(xsltExtMutex);
1348
1349 xmlHashFree(xsltExtensionsHash,
1350 (xmlHashDeallocator) xsltFreeExtModule);
1351 xsltExtensionsHash = NULL;
1352
1353 xmlMutexUnlock(xsltExtMutex);
1354 }
1355
1356 /**
1357 * xsltXPathGetTransformContext:
1358 * @ctxt: an XPath transformation context
1359 *
1360 * Provides the XSLT transformation context from the XPath transformation
1361 * context. This is useful when an XPath function in the extension module
1362 * is called by the XPath interpreter and that the XSLT context is needed
1363 * for example to retrieve the associated data pertaining to this XSLT
1364 * transformation.
1365 *
1366 * Returns the XSLT transformation context or NULL in case of error.
1367 */
1368 xsltTransformContextPtr
1369 xsltXPathGetTransformContext(xmlXPathParserContextPtr ctxt)
1370 {
1371 if ((ctxt == NULL) || (ctxt->context == NULL))
1372 return (NULL);
1373 return (ctxt->context->extra);
1374 }
1375
1376 /**
1377 * xsltRegisterExtModuleFunction:
1378 * @name: the function name
1379 * @URI: the function namespace URI
1380 * @function: the function callback
1381 *
1382 * Registers an extension module function.
1383 *
1384 * Returns 0 if successful, -1 in case of error.
1385 */
1386 int
1387 xsltRegisterExtModuleFunction(const xmlChar * name, const xmlChar * URI,
1388 xmlXPathFunction function)
1389 {
1390 if ((name == NULL) || (URI == NULL) || (function == NULL))
1391 return (-1);
1392
1393 if (xsltFunctionsHash == NULL)
1394 xsltFunctionsHash = xmlHashCreate(10);
1395 if (xsltFunctionsHash == NULL)
1396 return (-1);
1397
1398 xmlMutexLock(xsltExtMutex);
1399
1400 xmlHashUpdateEntry2(xsltFunctionsHash, name, URI,
1401 XML_CAST_FPTR(function), NULL);
1402
1403 xmlMutexUnlock(xsltExtMutex);
1404
1405 return (0);
1406 }
1407
1408 /**
1409 * xsltExtModuleFunctionLookup:
1410 * @name: the function name
1411 * @URI: the function namespace URI
1412 *
1413 * Looks up an extension module function
1414 *
1415 * Returns the function if found, NULL otherwise.
1416 */
1417 xmlXPathFunction
1418 xsltExtModuleFunctionLookup(const xmlChar * name, const xmlChar * URI)
1419 {
1420 xmlXPathFunction ret;
1421
1422 if ((xsltFunctionsHash == NULL) || (name == NULL) || (URI == NULL))
1423 return (NULL);
1424
1425 xmlMutexLock(xsltExtMutex);
1426
1427 XML_CAST_FPTR(ret) = xmlHashLookup2(xsltFunctionsHash, name, URI);
1428
1429 xmlMutexUnlock(xsltExtMutex);
1430
1431 /* if lookup fails, attempt a dynamic load on supported platforms */
1432 if (NULL == ret) {
1433 if (!xsltExtModuleRegisterDynamic(URI)) {
1434 xmlMutexLock(xsltExtMutex);
1435
1436 XML_CAST_FPTR(ret) =
1437 xmlHashLookup2(xsltFunctionsHash, name, URI);
1438
1439 xmlMutexUnlock(xsltExtMutex);
1440 }
1441 }
1442
1443 return ret;
1444 }
1445
1446 /**
1447 * xsltUnregisterExtModuleFunction:
1448 * @name: the function name
1449 * @URI: the function namespace URI
1450 *
1451 * Unregisters an extension module function
1452 *
1453 * Returns 0 if successful, -1 in case of error.
1454 */
1455 int
1456 xsltUnregisterExtModuleFunction(const xmlChar * name, const xmlChar * URI)
1457 {
1458 int ret;
1459
1460 if ((xsltFunctionsHash == NULL) || (name == NULL) || (URI == NULL))
1461 return (-1);
1462
1463 xmlMutexLock(xsltExtMutex);
1464
1465 ret = xmlHashRemoveEntry2(xsltFunctionsHash, name, URI, NULL);
1466
1467 xmlMutexUnlock(xsltExtMutex);
1468
1469 return(ret);
1470 }
1471
1472 /**
1473 * xsltUnregisterAllExtModuleFunction:
1474 *
1475 * Unregisters all extension module function
1476 */
1477 static void
1478 xsltUnregisterAllExtModuleFunction(void)
1479 {
1480 xmlMutexLock(xsltExtMutex);
1481
1482 xmlHashFree(xsltFunctionsHash, NULL);
1483 xsltFunctionsHash = NULL;
1484
1485 xmlMutexUnlock(xsltExtMutex);
1486 }
1487
1488
1489 /**
1490 * xsltNewElemPreComp:
1491 * @style: the XSLT stylesheet
1492 * @inst: the element node
1493 * @function: the transform function
1494 *
1495 * Creates and initializes an #xsltElemPreComp
1496 *
1497 * Returns the new and initialized #xsltElemPreComp
1498 */
1499 xsltElemPreCompPtr
1500 xsltNewElemPreComp(xsltStylesheetPtr style, xmlNodePtr inst,
1501 xsltTransformFunction function)
1502 {
1503 xsltElemPreCompPtr cur;
1504
1505 cur = (xsltElemPreCompPtr) xmlMalloc(sizeof(xsltElemPreComp));
1506 if (cur == NULL) {
1507 xsltTransformError(NULL, style, NULL,
1508 "xsltNewExtElement : malloc failed\n");
1509 return (NULL);
1510 }
1511 memset(cur, 0, sizeof(xsltElemPreComp));
1512
1513 xsltInitElemPreComp(cur, style, inst, function,
1514 (xsltElemPreCompDeallocator) xmlFree);
1515
1516 return (cur);
1517 }
1518
1519 /**
1520 * xsltInitElemPreComp:
1521 * @comp: an #xsltElemPreComp (or generally a derived structure)
1522 * @style: the XSLT stylesheet
1523 * @inst: the element node
1524 * @function: the transform function
1525 * @freeFunc: the @comp deallocator
1526 *
1527 * Initializes an existing #xsltElemPreComp structure. This is usefull
1528 * when extending an #xsltElemPreComp to store precomputed data.
1529 * This function MUST be called on any extension element precomputed
1530 * data struct.
1531 */
1532 void
1533 xsltInitElemPreComp(xsltElemPreCompPtr comp, xsltStylesheetPtr style,
1534 xmlNodePtr inst, xsltTransformFunction function,
1535 xsltElemPreCompDeallocator freeFunc)
1536 {
1537 comp->type = XSLT_FUNC_EXTENSION;
1538 comp->func = function;
1539 comp->inst = inst;
1540 comp->free = freeFunc;
1541
1542 comp->next = style->preComps;
1543 style->preComps = comp;
1544 }
1545
1546 /**
1547 * xsltPreComputeExtModuleElement:
1548 * @style: the stylesheet
1549 * @inst: the element node
1550 *
1551 * Precomputes an extension module element
1552 *
1553 * Returns the precomputed data
1554 */
1555 xsltElemPreCompPtr
1556 xsltPreComputeExtModuleElement(xsltStylesheetPtr style, xmlNodePtr inst)
1557 {
1558 xsltExtElementPtr ext;
1559 xsltElemPreCompPtr comp = NULL;
1560
1561 if ((style == NULL) || (inst == NULL) ||
1562 (inst->type != XML_ELEMENT_NODE) || (inst->ns == NULL))
1563 return (NULL);
1564
1565 xmlMutexLock(xsltExtMutex);
1566
1567 ext = (xsltExtElementPtr)
1568 xmlHashLookup2(xsltElementsHash, inst->name, inst->ns->href);
1569
1570 xmlMutexUnlock(xsltExtMutex);
1571
1572 /*
1573 * EXT TODO: Now what?
1574 */
1575 if (ext == NULL)
1576 return (NULL);
1577
1578 if (ext->precomp != NULL) {
1579 /*
1580 * REVISIT TODO: Check if the text below is correct.
1581 * This will return a xsltElemPreComp structure or NULL.
1582 * 1) If the the author of the extension needs a
1583 * custom structure to hold the specific values of
1584 * this extension, he will derive a structure based on
1585 * xsltElemPreComp; thus we obviously *cannot* refactor
1586 * the xsltElemPreComp structure, since all already derived
1587 * user-defined strucures will break.
1588 * Example: For the extension xsl:document,
1589 * in xsltDocumentComp() (preproc.c), the structure
1590 * xsltStyleItemDocument is allocated, filled with
1591 * specific values and returned.
1592 * 2) If the author needs no values to be stored in
1593 * this structure, then he'll return NULL;
1594 */
1595 comp = ext->precomp(style, inst, ext->transform);
1596 }
1597 if (comp == NULL) {
1598 /*
1599 * Default creation of a xsltElemPreComp structure, if
1600 * the author of this extension did not create a custom
1601 * structure.
1602 */
1603 comp = xsltNewElemPreComp(style, inst, ext->transform);
1604 }
1605
1606 return (comp);
1607 }
1608
1609 /**
1610 * xsltRegisterExtModuleElement:
1611 * @name: the element name
1612 * @URI: the element namespace URI
1613 * @precomp: the pre-computation callback
1614 * @transform: the transformation callback
1615 *
1616 * Registers an extension module element.
1617 *
1618 * Returns 0 if successful, -1 in case of error.
1619 */
1620 int
1621 xsltRegisterExtModuleElement(const xmlChar * name, const xmlChar * URI,
1622 xsltPreComputeFunction precomp,
1623 xsltTransformFunction transform)
1624 {
1625 int ret;
1626
1627 xsltExtElementPtr ext;
1628
1629 if ((name == NULL) || (URI == NULL) || (transform == NULL))
1630 return (-1);
1631
1632 if (xsltElementsHash == NULL)
1633 xsltElementsHash = xmlHashCreate(10);
1634 if (xsltElementsHash == NULL)
1635 return (-1);
1636
1637 xmlMutexLock(xsltExtMutex);
1638
1639 ext = xsltNewExtElement(precomp, transform);
1640 if (ext == NULL) {
1641 ret = -1;
1642 goto done;
1643 }
1644
1645 xmlHashUpdateEntry2(xsltElementsHash, name, URI, (void *) ext,
1646 (xmlHashDeallocator) xsltFreeExtElement);
1647
1648 done:
1649 xmlMutexUnlock(xsltExtMutex);
1650
1651 return (0);
1652 }
1653
1654 /**
1655 * xsltExtElementLookup:
1656 * @ctxt: an XSLT process context
1657 * @name: the element name
1658 * @URI: the element namespace URI
1659 *
1660 * Looks up an extension element. @ctxt can be NULL to search only in
1661 * module elements.
1662 *
1663 * Returns the element callback or NULL if not found
1664 */
1665 xsltTransformFunction
1666 xsltExtElementLookup(xsltTransformContextPtr ctxt,
1667 const xmlChar * name, const xmlChar * URI)
1668 {
1669 xsltTransformFunction ret;
1670
1671 if ((name == NULL) || (URI == NULL))
1672 return (NULL);
1673
1674 if ((ctxt != NULL) && (ctxt->extElements != NULL)) {
1675 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->extElements, name, URI);
1676 if (ret != NULL) {
1677 return(ret);
1678 }
1679 }
1680
1681 ret = xsltExtModuleElementLookup(name, URI);
1682
1683 return (ret);
1684 }
1685
1686 /**
1687 * xsltExtModuleElementLookup:
1688 * @name: the element name
1689 * @URI: the element namespace URI
1690 *
1691 * Looks up an extension module element
1692 *
1693 * Returns the callback function if found, NULL otherwise.
1694 */
1695 xsltTransformFunction
1696 xsltExtModuleElementLookup(const xmlChar * name, const xmlChar * URI)
1697 {
1698 xsltExtElementPtr ext;
1699
1700 if ((xsltElementsHash == NULL) || (name == NULL) || (URI == NULL))
1701 return (NULL);
1702
1703 xmlMutexLock(xsltExtMutex);
1704
1705 ext = (xsltExtElementPtr) xmlHashLookup2(xsltElementsHash, name, URI);
1706
1707 xmlMutexUnlock(xsltExtMutex);
1708
1709 /*
1710 * if function lookup fails, attempt a dynamic load on
1711 * supported platforms
1712 */
1713 if (NULL == ext) {
1714 if (!xsltExtModuleRegisterDynamic(URI)) {
1715 xmlMutexLock(xsltExtMutex);
1716
1717 ext = (xsltExtElementPtr)
1718 xmlHashLookup2(xsltElementsHash, name, URI);
1719
1720 xmlMutexUnlock(xsltExtMutex);
1721 }
1722 }
1723
1724 if (ext == NULL)
1725 return (NULL);
1726 return (ext->transform);
1727 }
1728
1729 /**
1730 * xsltExtModuleElementPreComputeLookup:
1731 * @name: the element name
1732 * @URI: the element namespace URI
1733 *
1734 * Looks up an extension module element pre-computation function
1735 *
1736 * Returns the callback function if found, NULL otherwise.
1737 */
1738 xsltPreComputeFunction
1739 xsltExtModuleElementPreComputeLookup(const xmlChar * name,
1740 const xmlChar * URI)
1741 {
1742 xsltExtElementPtr ext;
1743
1744 if ((xsltElementsHash == NULL) || (name == NULL) || (URI == NULL))
1745 return (NULL);
1746
1747 xmlMutexLock(xsltExtMutex);
1748
1749 ext = (xsltExtElementPtr) xmlHashLookup2(xsltElementsHash, name, URI);
1750
1751 xmlMutexUnlock(xsltExtMutex);
1752
1753 if (ext == NULL) {
1754 if (!xsltExtModuleRegisterDynamic(URI)) {
1755 xmlMutexLock(xsltExtMutex);
1756
1757 ext = (xsltExtElementPtr)
1758 xmlHashLookup2(xsltElementsHash, name, URI);
1759
1760 xmlMutexUnlock(xsltExtMutex);
1761 }
1762 }
1763
1764 if (ext == NULL)
1765 return (NULL);
1766 return (ext->precomp);
1767 }
1768
1769 /**
1770 * xsltUnregisterExtModuleElement:
1771 * @name: the element name
1772 * @URI: the element namespace URI
1773 *
1774 * Unregisters an extension module element
1775 *
1776 * Returns 0 if successful, -1 in case of error.
1777 */
1778 int
1779 xsltUnregisterExtModuleElement(const xmlChar * name, const xmlChar * URI)
1780 {
1781 int ret;
1782
1783 if ((xsltElementsHash == NULL) || (name == NULL) || (URI == NULL))
1784 return (-1);
1785
1786 xmlMutexLock(xsltExtMutex);
1787
1788 ret = xmlHashRemoveEntry2(xsltElementsHash, name, URI,
1789 (xmlHashDeallocator) xsltFreeExtElement);
1790
1791 xmlMutexUnlock(xsltExtMutex);
1792
1793 return(ret);
1794 }
1795
1796 /**
1797 * xsltUnregisterAllExtModuleElement:
1798 *
1799 * Unregisters all extension module element
1800 */
1801 static void
1802 xsltUnregisterAllExtModuleElement(void)
1803 {
1804 xmlMutexLock(xsltExtMutex);
1805
1806 xmlHashFree(xsltElementsHash, (xmlHashDeallocator) xsltFreeExtElement);
1807 xsltElementsHash = NULL;
1808
1809 xmlMutexUnlock(xsltExtMutex);
1810 }
1811
1812 /**
1813 * xsltRegisterExtModuleTopLevel:
1814 * @name: the top-level element name
1815 * @URI: the top-level element namespace URI
1816 * @function: the top-level element callback
1817 *
1818 * Registers an extension module top-level element.
1819 *
1820 * Returns 0 if successful, -1 in case of error.
1821 */
1822 int
1823 xsltRegisterExtModuleTopLevel(const xmlChar * name, const xmlChar * URI,
1824 xsltTopLevelFunction function)
1825 {
1826 if ((name == NULL) || (URI == NULL) || (function == NULL))
1827 return (-1);
1828
1829 if (xsltTopLevelsHash == NULL)
1830 xsltTopLevelsHash = xmlHashCreate(10);
1831 if (xsltTopLevelsHash == NULL)
1832 return (-1);
1833
1834 xmlMutexLock(xsltExtMutex);
1835
1836 xmlHashUpdateEntry2(xsltTopLevelsHash, name, URI,
1837 XML_CAST_FPTR(function), NULL);
1838
1839 xmlMutexUnlock(xsltExtMutex);
1840
1841 return (0);
1842 }
1843
1844 /**
1845 * xsltExtModuleTopLevelLookup:
1846 * @name: the top-level element name
1847 * @URI: the top-level element namespace URI
1848 *
1849 * Looks up an extension module top-level element
1850 *
1851 * Returns the callback function if found, NULL otherwise.
1852 */
1853 xsltTopLevelFunction
1854 xsltExtModuleTopLevelLookup(const xmlChar * name, const xmlChar * URI)
1855 {
1856 xsltTopLevelFunction ret;
1857
1858 if ((xsltTopLevelsHash == NULL) || (name == NULL) || (URI == NULL))
1859 return (NULL);
1860
1861 xmlMutexLock(xsltExtMutex);
1862
1863 XML_CAST_FPTR(ret) = xmlHashLookup2(xsltTopLevelsHash, name, URI);
1864
1865 xmlMutexUnlock(xsltExtMutex);
1866
1867 /* if lookup fails, attempt a dynamic load on supported platforms */
1868 if (NULL == ret) {
1869 if (!xsltExtModuleRegisterDynamic(URI)) {
1870 xmlMutexLock(xsltExtMutex);
1871
1872 XML_CAST_FPTR(ret) = xmlHashLookup2(xsltTopLevelsHash, name, URI);
1873
1874 xmlMutexUnlock(xsltExtMutex);
1875 }
1876 }
1877
1878 return (ret);
1879 }
1880
1881 /**
1882 * xsltUnregisterExtModuleTopLevel:
1883 * @name: the top-level element name
1884 * @URI: the top-level element namespace URI
1885 *
1886 * Unregisters an extension module top-level element
1887 *
1888 * Returns 0 if successful, -1 in case of error.
1889 */
1890 int
1891 xsltUnregisterExtModuleTopLevel(const xmlChar * name, const xmlChar * URI)
1892 {
1893 int ret;
1894
1895 if ((xsltTopLevelsHash == NULL) || (name == NULL) || (URI == NULL))
1896 return (-1);
1897
1898 xmlMutexLock(xsltExtMutex);
1899
1900 ret = xmlHashRemoveEntry2(xsltTopLevelsHash, name, URI, NULL);
1901
1902 xmlMutexUnlock(xsltExtMutex);
1903
1904 return(ret);
1905 }
1906
1907 /**
1908 * xsltUnregisterAllExtModuleTopLevel:
1909 *
1910 * Unregisters all extension module function
1911 */
1912 static void
1913 xsltUnregisterAllExtModuleTopLevel(void)
1914 {
1915 xmlMutexLock(xsltExtMutex);
1916
1917 xmlHashFree(xsltTopLevelsHash, NULL);
1918 xsltTopLevelsHash = NULL;
1919
1920 xmlMutexUnlock(xsltExtMutex);
1921 }
1922
1923 /**
1924 * xsltGetExtInfo:
1925 * @style: pointer to a stylesheet
1926 * @URI: the namespace URI desired
1927 *
1928 * looks up URI in extInfos of the stylesheet
1929 *
1930 * returns a pointer to the hash table if found, else NULL
1931 */
1932 xmlHashTablePtr
1933 xsltGetExtInfo(xsltStylesheetPtr style, const xmlChar * URI)
1934 {
1935 xsltExtDataPtr data;
1936
1937 /*
1938 * TODO: Why do we have a return type of xmlHashTablePtr?
1939 * Is the user-allocated data for extension modules expected
1940 * to be a xmlHashTablePtr only? Or is this intended for
1941 * the EXSLT module only?
1942 */
1943
1944 if (style != NULL && style->extInfos != NULL) {
1945 data = xmlHashLookup(style->extInfos, URI);
1946 if (data != NULL && data->extData != NULL)
1947 return data->extData;
1948 }
1949 return NULL;
1950 }
1951
1952 /************************************************************************
1953 * *
1954 * Test module http://xmlsoft.org/XSLT/ *
1955 * *
1956 ************************************************************************/
1957
1958 /************************************************************************
1959 * *
1960 * Test of the extension module API *
1961 * *
1962 ************************************************************************/
1963
1964 static xmlChar *testData = NULL;
1965 static xmlChar *testStyleData = NULL;
1966
1967 /**
1968 * xsltExtFunctionTest:
1969 * @ctxt: the XPath Parser context
1970 * @nargs: the number of arguments
1971 *
1972 * function libxslt:test() for testing the extensions support.
1973 */
1974 static void
1975 xsltExtFunctionTest(xmlXPathParserContextPtr ctxt,
1976 int nargs ATTRIBUTE_UNUSED)
1977 {
1978 xsltTransformContextPtr tctxt;
1979 void *data = NULL;
1980
1981 tctxt = xsltXPathGetTransformContext(ctxt);
1982
1983 if (testData == NULL) {
1984 xsltGenericDebug(xsltGenericDebugContext,
1985 "xsltExtFunctionTest: not initialized,"
1986 " calling xsltGetExtData\n");
1987 data = xsltGetExtData(tctxt, (const xmlChar *) XSLT_DEFAULT_URL);
1988 if (data == NULL) {
1989 xsltTransformError(tctxt, NULL, NULL,
1990 "xsltExtElementTest: not initialized\n");
1991 return;
1992 }
1993 }
1994 if (tctxt == NULL) {
1995 xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
1996 "xsltExtFunctionTest: failed to get the transformation context\n");
1997 return;
1998 }
1999 if (data == NULL)
2000 data = xsltGetExtData(tctxt, (const xmlChar *) XSLT_DEFAULT_URL);
2001 if (data == NULL) {
2002 xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
2003 "xsltExtFunctionTest: failed to get module data\n");
2004 return;
2005 }
2006 if (data != testData) {
2007 xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
2008 "xsltExtFunctionTest: got wrong module data\n");
2009 return;
2010 }
2011 #ifdef WITH_XSLT_DEBUG_FUNCTION
2012 xsltGenericDebug(xsltGenericDebugContext,
2013 "libxslt:test() called with %d args\n", nargs);
2014 #endif
2015 }
2016
2017 /**
2018 * xsltExtElementPreCompTest:
2019 * @style: the stylesheet
2020 * @inst: the instruction in the stylesheet
2021 *
2022 * Process a libxslt:test node
2023 */
2024 static xsltElemPreCompPtr
2025 xsltExtElementPreCompTest(xsltStylesheetPtr style, xmlNodePtr inst,
2026 xsltTransformFunction function)
2027 {
2028 xsltElemPreCompPtr ret;
2029
2030 if (style == NULL) {
2031 xsltTransformError(NULL, NULL, inst,
2032 "xsltExtElementTest: no transformation context\n");
2033 return (NULL);
2034 }
2035 if (testStyleData == NULL) {
2036 xsltGenericDebug(xsltGenericDebugContext,
2037 "xsltExtElementPreCompTest: not initialized,"
2038 " calling xsltStyleGetExtData\n");
2039 xsltStyleGetExtData(style, (const xmlChar *) XSLT_DEFAULT_URL);
2040 if (testStyleData == NULL) {
2041 xsltTransformError(NULL, style, inst,
2042 "xsltExtElementPreCompTest: not initialized\n");
2043 if (style != NULL)
2044 style->errors++;
2045 return (NULL);
2046 }
2047 }
2048 if (inst == NULL) {
2049 xsltTransformError(NULL, style, inst,
2050 "xsltExtElementPreCompTest: no instruction\n");
2051 if (style != NULL)
2052 style->errors++;
2053 return (NULL);
2054 }
2055 ret = xsltNewElemPreComp(style, inst, function);
2056 return (ret);
2057 }
2058
2059 /**
2060 * xsltExtElementTest:
2061 * @ctxt: an XSLT processing context
2062 * @node: The current node
2063 * @inst: the instruction in the stylesheet
2064 * @comp: precomputed informations
2065 *
2066 * Process a libxslt:test node
2067 */
2068 static void
2069 xsltExtElementTest(xsltTransformContextPtr ctxt, xmlNodePtr node,
2070 xmlNodePtr inst,
2071 xsltElemPreCompPtr comp ATTRIBUTE_UNUSED)
2072 {
2073 xmlNodePtr commentNode;
2074
2075 if (testData == NULL) {
2076 xsltGenericDebug(xsltGenericDebugContext,
2077 "xsltExtElementTest: not initialized,"
2078 " calling xsltGetExtData\n");
2079 xsltGetExtData(ctxt, (const xmlChar *) XSLT_DEFAULT_URL);
2080 if (testData == NULL) {
2081 xsltTransformError(ctxt, NULL, inst,
2082 "xsltExtElementTest: not initialized\n");
2083 return;
2084 }
2085 }
2086 if (ctxt == NULL) {
2087 xsltTransformError(ctxt, NULL, inst,
2088 "xsltExtElementTest: no transformation context\n");
2089 return;
2090 }
2091 if (node == NULL) {
2092 xsltTransformError(ctxt, NULL, inst,
2093 "xsltExtElementTest: no current node\n");
2094 return;
2095 }
2096 if (inst == NULL) {
2097 xsltTransformError(ctxt, NULL, inst,
2098 "xsltExtElementTest: no instruction\n");
2099 return;
2100 }
2101 if (ctxt->insert == NULL) {
2102 xsltTransformError(ctxt, NULL, inst,
2103 "xsltExtElementTest: no insertion point\n");
2104 return;
2105 }
2106 commentNode = xmlNewComment((const xmlChar *)
2107 "libxslt:test element test worked");
2108 xmlAddChild(ctxt->insert, commentNode);
2109 }
2110
2111 /**
2112 * xsltExtInitTest:
2113 * @ctxt: an XSLT transformation context
2114 * @URI: the namespace URI for the extension
2115 *
2116 * A function called at initialization time of an XSLT extension module
2117 *
2118 * Returns a pointer to the module specific data for this transformation
2119 */
2120 static void *
2121 xsltExtInitTest(xsltTransformContextPtr ctxt, const xmlChar * URI)
2122 {
2123 if (testStyleData == NULL) {
2124 xsltGenericDebug(xsltGenericErrorContext,
2125 "xsltExtInitTest: not initialized,"
2126 " calling xsltStyleGetExtData\n");
2127 testStyleData = xsltStyleGetExtData(ctxt->style, URI);
2128 if (testStyleData == NULL) {
2129 xsltTransformError(ctxt, NULL, NULL,
2130 "xsltExtInitTest: not initialized\n");
2131 return (NULL);
2132 }
2133 }
2134 if (testData != NULL) {
2135 xsltTransformError(ctxt, NULL, NULL,
2136 "xsltExtInitTest: already initialized\n");
2137 return (NULL);
2138 }
2139 testData = (void *) "test data";
2140 xsltGenericDebug(xsltGenericDebugContext,
2141 "Registered test module : %s\n", URI);
2142 return (testData);
2143 }
2144
2145
2146 /**
2147 * xsltExtShutdownTest:
2148 * @ctxt: an XSLT transformation context
2149 * @URI: the namespace URI for the extension
2150 * @data: the data associated to this module
2151 *
2152 * A function called at shutdown time of an XSLT extension module
2153 */
2154 static void
2155 xsltExtShutdownTest(xsltTransformContextPtr ctxt,
2156 const xmlChar * URI, void *data)
2157 {
2158 if (testData == NULL) {
2159 xsltTransformError(ctxt, NULL, NULL,
2160 "xsltExtShutdownTest: not initialized\n");
2161 return;
2162 }
2163 if (data != testData) {
2164 xsltTransformError(ctxt, NULL, NULL,
2165 "xsltExtShutdownTest: wrong data\n");
2166 }
2167 testData = NULL;
2168 xsltGenericDebug(xsltGenericDebugContext,
2169 "Unregistered test module : %s\n", URI);
2170 }
2171
2172 /**
2173 * xsltExtStyleInitTest:
2174 * @style: an XSLT stylesheet
2175 * @URI: the namespace URI for the extension
2176 *
2177 * A function called at initialization time of an XSLT extension module
2178 *
2179 * Returns a pointer to the module specific data for this transformation
2180 */
2181 static void *
2182 xsltExtStyleInitTest(xsltStylesheetPtr style ATTRIBUTE_UNUSED,
2183 const xmlChar * URI)
2184 {
2185 if (testStyleData != NULL) {
2186 xsltTransformError(NULL, NULL, NULL,
2187 "xsltExtInitTest: already initialized\n");
2188 return (NULL);
2189 }
2190 testStyleData = (void *) "test data";
2191 xsltGenericDebug(xsltGenericDebugContext,
2192 "Registered test module : %s\n", URI);
2193 return (testStyleData);
2194 }
2195
2196
2197 /**
2198 * xsltExtStyleShutdownTest:
2199 * @style: an XSLT stylesheet
2200 * @URI: the namespace URI for the extension
2201 * @data: the data associated to this module
2202 *
2203 * A function called at shutdown time of an XSLT extension module
2204 */
2205 static void
2206 xsltExtStyleShutdownTest(xsltStylesheetPtr style ATTRIBUTE_UNUSED,
2207 const xmlChar * URI, void *data)
2208 {
2209 if (testStyleData == NULL) {
2210 xsltGenericError(xsltGenericErrorContext,
2211 "xsltExtShutdownTest: not initialized\n");
2212 return;
2213 }
2214 if (data != testStyleData) {
2215 xsltTransformError(NULL, NULL, NULL,
2216 "xsltExtShutdownTest: wrong data\n");
2217 }
2218 testStyleData = NULL;
2219 xsltGenericDebug(xsltGenericDebugContext,
2220 "Unregistered test module : %s\n", URI);
2221 }
2222
2223 /**
2224 * xsltRegisterTestModule:
2225 *
2226 * Registers the test module
2227 */
2228 void
2229 xsltRegisterTestModule(void)
2230 {
2231 xsltInitGlobals();
2232 xsltRegisterExtModuleFull((const xmlChar *) XSLT_DEFAULT_URL,
2233 xsltExtInitTest, xsltExtShutdownTest,
2234 xsltExtStyleInitTest,
2235 xsltExtStyleShutdownTest);
2236 xsltRegisterExtModuleFunction((const xmlChar *) "test",
2237 (const xmlChar *) XSLT_DEFAULT_URL,
2238 xsltExtFunctionTest);
2239 xsltRegisterExtModuleElement((const xmlChar *) "test",
2240 (const xmlChar *) XSLT_DEFAULT_URL,
2241 xsltExtElementPreCompTest,
2242 xsltExtElementTest);
2243 }
2244
2245 static void
2246 xsltHashScannerModuleFree(void *payload ATTRIBUTE_UNUSED,
2247 void *data ATTRIBUTE_UNUSED,
2248 xmlChar * name ATTRIBUTE_UNUSED)
2249 {
2250 #ifdef WITH_MODULES
2251 xmlModuleClose(payload);
2252 #endif
2253 }
2254
2255 /**
2256 * xsltInitGlobals:
2257 *
2258 * Initialize the global variables for extensions
2259 */
2260 void
2261 xsltInitGlobals(void)
2262 {
2263 if (xsltExtMutex == NULL) {
2264 xsltExtMutex = xmlNewMutex();
2265 }
2266 }
2267
2268 /**
2269 * xsltCleanupGlobals:
2270 *
2271 * Unregister all global variables set up by the XSLT library
2272 */
2273 void
2274 xsltCleanupGlobals(void)
2275 {
2276 xsltUnregisterAllExtModules();
2277 xsltUnregisterAllExtModuleFunction();
2278 xsltUnregisterAllExtModuleElement();
2279 xsltUnregisterAllExtModuleTopLevel();
2280
2281 xmlMutexLock(xsltExtMutex);
2282 /* cleanup dynamic module hash */
2283 if (NULL != xsltModuleHash) {
2284 xmlHashScan(xsltModuleHash, xsltHashScannerModuleFree, 0);
2285 xmlHashFree(xsltModuleHash, NULL);
2286 xsltModuleHash = NULL;
2287 }
2288 xmlMutexUnlock(xsltExtMutex);
2289
2290 xmlFreeMutex(xsltExtMutex);
2291 xsltExtMutex = NULL;
2292 xsltFreeLocales();
2293 xsltUninit();
2294 }
2295
2296 static void
2297 xsltDebugDumpExtensionsCallback(void *function ATTRIBUTE_UNUSED,
2298 FILE * output, const xmlChar * name,
2299 const xmlChar * URI,
2300 const xmlChar * not_used ATTRIBUTE_UNUSED)
2301 {
2302 if (!name || !URI)
2303 return;
2304 fprintf(output, "{%s}%s\n", URI, name);
2305 }
2306
2307 static void
2308 xsltDebugDumpExtModulesCallback(void *function ATTRIBUTE_UNUSED,
2309 FILE * output, const xmlChar * URI,
2310 const xmlChar * not_used ATTRIBUTE_UNUSED,
2311 const xmlChar * not_used2 ATTRIBUTE_UNUSED)
2312 {
2313 if (!URI)
2314 return;
2315 fprintf(output, "%s\n", URI);
2316 }
2317
2318 /**
2319 * xsltDebugDumpExtensions:
2320 * @output: the FILE * for the output, if NULL stdout is used
2321 *
2322 * Dumps a list of the registered XSLT extension functions and elements
2323 */
2324 void
2325 xsltDebugDumpExtensions(FILE * output)
2326 {
2327 if (output == NULL)
2328 output = stdout;
2329 fprintf(output,
2330 "Registered XSLT Extensions\n--------------------------\n");
2331 if (!xsltFunctionsHash)
2332 fprintf(output, "No registered extension functions\n");
2333 else {
2334 fprintf(output, "Registered Extension Functions:\n");
2335 xmlMutexLock(xsltExtMutex);
2336 xmlHashScanFull(xsltFunctionsHash,
2337 (xmlHashScannerFull)
2338 xsltDebugDumpExtensionsCallback, output);
2339 xmlMutexUnlock(xsltExtMutex);
2340 }
2341 if (!xsltElementsHash)
2342 fprintf(output, "\nNo registered extension elements\n");
2343 else {
2344 fprintf(output, "\nRegistered Extension Elements:\n");
2345 xmlMutexLock(xsltExtMutex);
2346 xmlHashScanFull(xsltElementsHash,
2347 (xmlHashScannerFull)
2348 xsltDebugDumpExtensionsCallback, output);
2349 xmlMutexUnlock(xsltExtMutex);
2350 }
2351 if (!xsltExtensionsHash)
2352 fprintf(output, "\nNo registered extension modules\n");
2353 else {
2354 fprintf(output, "\nRegistered Extension Modules:\n");
2355 xmlMutexLock(xsltExtMutex);
2356 xmlHashScanFull(xsltExtensionsHash,
2357 (xmlHashScannerFull)
2358 xsltDebugDumpExtModulesCallback, output);
2359 xmlMutexUnlock(xsltExtMutex);
2360 }
2361
2362 }