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