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