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