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 52typedef struct _xsltExtDef xsltExtDef; 53typedef xsltExtDef *xsltExtDefPtr; 54struct _xsltExtDef { 55 struct _xsltExtDef *next; 56 xmlChar *prefix; 57 xmlChar *URI; 58 void *data; 59}; 60 61typedef struct _xsltExtModule xsltExtModule; 62typedef xsltExtModule *xsltExtModulePtr; 63struct _xsltExtModule { 64 xsltExtInitFunction initFunc; 65 xsltExtShutdownFunction shutdownFunc; 66 xsltStyleExtInitFunction styleInitFunc; 67 xsltStyleExtShutdownFunction styleShutdownFunc; 68}; 69 70typedef struct _xsltExtData xsltExtData; 71typedef xsltExtData *xsltExtDataPtr; 72struct _xsltExtData { 73 xsltExtModulePtr extModule; 74 void *extData; 75}; 76 77typedef struct _xsltExtElement xsltExtElement; 78typedef xsltExtElement *xsltExtElementPtr; 79struct _xsltExtElement { 80 xsltPreComputeFunction precomp; 81 xsltTransformFunction transform; 82}; 83 84static xmlHashTablePtr xsltExtensionsHash = NULL; 85static xmlHashTablePtr xsltFunctionsHash = NULL; 86static xmlHashTablePtr xsltElementsHash = NULL; 87static xmlHashTablePtr xsltTopLevelsHash = NULL; 88static xmlHashTablePtr xsltModuleHash = NULL; 89static 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 */ 106static xsltExtDefPtr 107xsltNewExtDef(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 */ 131static void 132xsltFreeExtDef(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 */ 149static void 150xsltFreeExtDefList(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 */ 172static xsltExtModulePtr 173xsltNewExtModule(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 */ 199static void 200xsltFreeExtModule(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 */ 216static xsltExtDataPtr 217xsltNewExtData(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 */ 240static void 241xsltFreeExtData(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 */ 258static xsltExtElementPtr 259xsltNewExtElement(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 */ 284static void 285xsltFreeExtElement(xsltExtElementPtr ext) 286{ 287 if (ext == NULL) 288 return; 289 xmlFree(ext); 290} 291 292 293#ifdef WITH_MODULES 294typedef 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 319static int 320xsltExtModuleRegisterDynamic(const xmlChar * URI) 321{ 322 323 xmlModulePtr m; 324 exsltRegisterFunction regfunc; 325 xmlChar *ext_name; 326 char module_filename[PATH_MAX]; 327 const xmlChar *ext_directory = NULL; 328 const xmlChar *protocol = NULL; 329 xmlChar *i, *regfunc_name; 330 void *vregfunc; 331 int rc; 332 333 /* check for bad inputs */ 334 if (URI == NULL) 335 return (-1); 336 337 if (NULL == xsltModuleHash) { 338 xsltModuleHash = xmlHashCreate(5); 339 if (xsltModuleHash == NULL) 340 return (-1); 341 } 342 343 xmlMutexLock(xsltExtMutex); 344 345 /* have we attempted to register this module already? */ 346 if (xmlHashLookup(xsltModuleHash, URI) != NULL) { 347 xmlMutexUnlock(xsltExtMutex); 348 return (-1); 349 } 350 xmlMutexUnlock(xsltExtMutex); 351 352 /* transform extension namespace into a module name */ 353 protocol = xmlStrstr(URI, BAD_CAST "://"); 354 if (protocol == NULL) { 355 ext_name = xmlStrdup(URI); 356 } else { 357 ext_name = xmlStrdup(protocol + 3); 358 } 359 if (ext_name == NULL) { 360 return (-1); 361 } 362 363 i = ext_name; 364 while ('\0' != *i) { 365 if (('/' == *i) || ('\\' == *i) || ('.' == *i) || ('-' == *i)) 366 *i = '_'; 367 i++; 368 } 369 370 if (*(i - 1) == '_') 371 *i = '\0'; 372 373 /* determine module directory */ 374 ext_directory = (xmlChar *) getenv("LIBXSLT_PLUGINS_PATH"); 375 376 if (NULL == ext_directory) { 377 ext_directory = BAD_CAST LIBXSLT_DEFAULT_PLUGINS_PATH(); 378 if (NULL == ext_directory) 379 return (-1); 380 } 381#ifdef WITH_XSLT_DEBUG_EXTENSIONS 382 else 383 xsltGenericDebug(xsltGenericDebugContext, 384 "LIBXSLT_PLUGINS_PATH is %s\n", ext_directory); 385#endif 386 387 /* build the module filename, and confirm the module exists */ 388 xmlStrPrintf((xmlChar *) module_filename, sizeof(module_filename), 389 BAD_CAST "%s/%s%s", 390 ext_directory, ext_name, LIBXML_MODULE_EXTENSION); 391 392#ifdef WITH_XSLT_DEBUG_EXTENSIONS 393 xsltGenericDebug(xsltGenericDebugContext, 394 "Attempting to load plugin: %s for URI: %s\n", 395 module_filename, URI); 396#endif 397 398 if (1 != xmlCheckFilename(module_filename)) { 399 400#ifdef WITH_XSLT_DEBUG_EXTENSIONS 401 xsltGenericDebug(xsltGenericDebugContext, 402 "xmlCheckFilename failed for plugin: %s\n", module_filename); 403#endif 404 405 xmlFree(ext_name); 406 return (-1); 407 } 408 409 /* attempt to open the module */ 410 m = xmlModuleOpen(module_filename, 0); 411 if (NULL == m) { 412 413#ifdef WITH_XSLT_DEBUG_EXTENSIONS 414 xsltGenericDebug(xsltGenericDebugContext, 415 "xmlModuleOpen failed for plugin: %s\n", module_filename); 416#endif 417 418 xmlFree(ext_name); 419 return (-1); 420 } 421 422 /* construct initialization func name */ 423 regfunc_name = xmlStrdup(ext_name); 424 regfunc_name = xmlStrcat(regfunc_name, BAD_CAST "_init"); 425 426 vregfunc = NULL; 427 rc = xmlModuleSymbol(m, (const char *) regfunc_name, &vregfunc); 428 regfunc = vregfunc; 429 if (0 == rc) { 430 /* 431 * Call the module's init function. Note that this function 432 * calls xsltRegisterExtModuleFull which will add the module 433 * to xsltExtensionsHash (together with it's entry points). 434 */ 435 (*regfunc) (); 436 437 /* register this module in our hash */ 438 xmlMutexLock(xsltExtMutex); 439 xmlHashAddEntry(xsltModuleHash, URI, (void *) m); 440 xmlMutexUnlock(xsltExtMutex); 441 } else { 442 443#ifdef WITH_XSLT_DEBUG_EXTENSIONS 444 xsltGenericDebug(xsltGenericDebugContext, 445 "xmlModuleSymbol failed for plugin: %s, regfunc: %s\n", 446 module_filename, regfunc_name); 447#endif 448 449 /* if regfunc not found unload the module immediately */ 450 xmlModuleClose(m); 451 } 452 453 xmlFree(ext_name); 454 xmlFree(regfunc_name); 455 return (NULL == regfunc) ? -1 : 0; 456} 457#else 458static int 459xsltExtModuleRegisterDynamic(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 */ 478void 479xsltFreeExts(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 */ 502int 503xsltRegisterExtPrefix(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 */ 586int 587xsltRegisterExtFunction(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 */ 620int 621xsltRegisterExtElement(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 */ 641void 642xsltFreeCtxtExts(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 */ 662static xsltExtDataPtr 663xsltStyleInitializeStylesheetModule(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 */ 755void * 756xsltStyleGetExtData(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 */ 822void * 823xsltStyleStylesheetLevelGetExtData(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 */ 861void * 862xsltGetExtData(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 922typedef struct _xsltInitExtCtxt xsltInitExtCtxt; 923struct _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 */ 936static void 937xsltInitCtxtExt(xsltExtDataPtr styleData, xsltInitExtCtxt * ctxt, 938 const xmlChar * URI) 939{ 940 xsltExtModulePtr module; 941 xsltExtDataPtr ctxtData; 942 void *extData; 943 944 if ((styleData == NULL) || (ctxt == NULL) || (URI == NULL) || 945 (ctxt->ret == -1)) { 946#ifdef WITH_XSLT_DEBUG_EXTENSIONS 947 xsltGenericDebug(xsltGenericDebugContext, 948 "xsltInitCtxtExt: NULL param or error\n"); 949#endif 950 return; 951 } 952 module = styleData->extModule; 953 if ((module == NULL) || (module->initFunc == NULL)) { 954#ifdef WITH_XSLT_DEBUG_EXTENSIONS 955 xsltGenericDebug(xsltGenericDebugContext, 956 "xsltInitCtxtExt: no module or no initFunc\n"); 957#endif 958 return; 959 } 960 961 ctxtData = (xsltExtDataPtr) xmlHashLookup(ctxt->ctxt->extInfos, URI); 962 if (ctxtData != NULL) { 963#ifdef WITH_XSLT_DEBUG_EXTENSIONS 964 xsltGenericDebug(xsltGenericDebugContext, 965 "xsltInitCtxtExt: already initialized\n"); 966#endif 967 return; 968 } 969 970 extData = module->initFunc(ctxt->ctxt, URI); 971 if (extData == NULL) { 972#ifdef WITH_XSLT_DEBUG_EXTENSIONS 973 xsltGenericDebug(xsltGenericDebugContext, 974 "xsltInitCtxtExt: no extData\n"); 975#endif 976 } 977 ctxtData = xsltNewExtData(module, extData); 978 if (ctxtData == NULL) { 979 ctxt->ret = -1; 980 return; 981 } 982 983 if (ctxt->ctxt->extInfos == NULL) 984 ctxt->ctxt->extInfos = xmlHashCreate(10); 985 if (ctxt->ctxt->extInfos == NULL) { 986 ctxt->ret = -1; 987 return; 988 } 989 990 if (xmlHashAddEntry(ctxt->ctxt->extInfos, URI, ctxtData) < 0) { 991 xsltGenericError(xsltGenericErrorContext, 992 "Failed to register module data: %s\n", URI); 993 if (module->shutdownFunc) 994 module->shutdownFunc(ctxt->ctxt, URI, extData); 995 xsltFreeExtData(ctxtData); 996 ctxt->ret = -1; 997 return; 998 } 999#ifdef WITH_XSLT_DEBUG_EXTENSIONS 1000 xsltGenericDebug(xsltGenericDebugContext, "Registered module %s\n", 1001 URI); 1002#endif 1003 ctxt->ret++; 1004} 1005 1006/** 1007 * xsltInitCtxtExts: 1008 * @ctxt: an XSLT transformation context 1009 * 1010 * Initialize the set of modules with registered stylesheet data 1011 * 1012 * Returns the number of modules initialized or -1 in case of error 1013 */ 1014int 1015xsltInitCtxtExts(xsltTransformContextPtr ctxt) 1016{ 1017 xsltStylesheetPtr style; 1018 xsltInitExtCtxt ctx; 1019 1020 if (ctxt == NULL) 1021 return (-1); 1022 1023 style = ctxt->style; 1024 if (style == NULL) 1025 return (-1); 1026 1027 ctx.ctxt = ctxt; 1028 ctx.ret = 0; 1029 1030 while (style != NULL) { 1031 if (style->extInfos != NULL) { 1032 xmlHashScan(style->extInfos, 1033 (xmlHashScanner) xsltInitCtxtExt, &ctx); 1034 if (ctx.ret == -1) 1035 return (-1); 1036 } 1037 style = xsltNextImport(style); 1038 } 1039#ifdef WITH_XSLT_DEBUG_EXTENSIONS 1040 xsltGenericDebug(xsltGenericDebugContext, "Registered %d modules\n", 1041 ctx.ret); 1042#endif 1043 return (ctx.ret); 1044} 1045 1046/** 1047 * xsltShutdownCtxtExt: 1048 * @data: the registered data for the module 1049 * @ctxt: the XSLT transformation context 1050 * @URI: the extension URI 1051 * 1052 * Shutdown an extension module loaded 1053 */ 1054static void 1055xsltShutdownCtxtExt(xsltExtDataPtr data, xsltTransformContextPtr ctxt, 1056 const xmlChar * URI) 1057{ 1058 xsltExtModulePtr module; 1059 1060 if ((data == NULL) || (ctxt == NULL) || (URI == NULL)) 1061 return; 1062 module = data->extModule; 1063 if ((module == NULL) || (module->shutdownFunc == NULL)) 1064 return; 1065 1066#ifdef WITH_XSLT_DEBUG_EXTENSIONS 1067 xsltGenericDebug(xsltGenericDebugContext, 1068 "Shutting down module : %s\n", URI); 1069#endif 1070 module->shutdownFunc(ctxt, URI, data->extData); 1071} 1072 1073/** 1074 * xsltShutdownCtxtExts: 1075 * @ctxt: an XSLT transformation context 1076 * 1077 * Shutdown the set of modules loaded 1078 */ 1079void 1080xsltShutdownCtxtExts(xsltTransformContextPtr ctxt) 1081{ 1082 if (ctxt == NULL) 1083 return; 1084 if (ctxt->extInfos == NULL) 1085 return; 1086 xmlHashScan(ctxt->extInfos, (xmlHashScanner) xsltShutdownCtxtExt, 1087 ctxt); 1088 xmlHashFree(ctxt->extInfos, (xmlHashDeallocator) xsltFreeExtData); 1089 ctxt->extInfos = NULL; 1090} 1091 1092/** 1093 * xsltShutdownExt: 1094 * @data: the registered data for the module 1095 * @ctxt: the XSLT stylesheet 1096 * @URI: the extension URI 1097 * 1098 * Shutdown an extension module loaded 1099 */ 1100static void 1101xsltShutdownExt(xsltExtDataPtr data, xsltStylesheetPtr style, 1102 const xmlChar * URI) 1103{ 1104 xsltExtModulePtr module; 1105 1106 if ((data == NULL) || (style == NULL) || (URI == NULL)) 1107 return; 1108 module = data->extModule; 1109 if ((module == NULL) || (module->styleShutdownFunc == NULL)) 1110 return; 1111 1112#ifdef WITH_XSLT_DEBUG_EXTENSIONS 1113 xsltGenericDebug(xsltGenericDebugContext, 1114 "Shutting down module : %s\n", URI); 1115#endif 1116 module->styleShutdownFunc(style, URI, data->extData); 1117 /* 1118 * Don't remove the entry from the hash table here, since 1119 * this will produce segfaults - this fixes bug #340624. 1120 * 1121 * xmlHashRemoveEntry(style->extInfos, URI, 1122 * (xmlHashDeallocator) xsltFreeExtData); 1123 */ 1124} 1125 1126/** 1127 * xsltShutdownExts: 1128 * @style: an XSLT stylesheet 1129 * 1130 * Shutdown the set of modules loaded 1131 */ 1132void 1133xsltShutdownExts(xsltStylesheetPtr style) 1134{ 1135 if (style == NULL) 1136 return; 1137 if (style->extInfos == NULL) 1138 return; 1139 xmlHashScan(style->extInfos, (xmlHashScanner) xsltShutdownExt, style); 1140 xmlHashFree(style->extInfos, (xmlHashDeallocator) xsltFreeExtData); 1141 style->extInfos = NULL; 1142} 1143 1144/** 1145 * xsltCheckExtPrefix: 1146 * @style: the stylesheet 1147 * @URI: the namespace prefix (possibly NULL) 1148 * 1149 * Check if the given prefix is one of the declared extensions. 1150 * This is intended to be called only at compile-time. 1151 * Called by: 1152 * xsltGetInheritedNsList() (xslt.c) 1153 * xsltParseTemplateContent (xslt.c) 1154 * 1155 * Returns 1 if this is an extension, 0 otherwise 1156 */ 1157int 1158xsltCheckExtPrefix(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 */ 1217int 1218xsltCheckExtURI(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 */ 1247int 1248xsltRegisterExtModuleFull(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 1284done: 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 */ 1299int 1300xsltRegisterExtModule(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 */ 1316int 1317xsltUnregisterExtModule(const xmlChar * URI) 1318{ 1319 int ret; 1320 1321 if (URI == NULL) 1322 return (-1); 1323 if (xsltExtensionsHash == NULL) 1324 return (-1); 1325 1326 xmlMutexLock(xsltExtMutex); 1327 1328 ret = xmlHashRemoveEntry(xsltExtensionsHash, URI, 1329 (xmlHashDeallocator) xsltFreeExtModule); 1330 1331 xmlMutexUnlock(xsltExtMutex); 1332 1333 return (ret); 1334} 1335 1336/** 1337 * xsltUnregisterAllExtModules: 1338 * 1339 * Unregister all the XSLT extension module from the library. 1340 */ 1341static void 1342xsltUnregisterAllExtModules(void) 1343{ 1344 if (xsltExtensionsHash == NULL) 1345 return; 1346 1347 xmlMutexLock(xsltExtMutex); 1348 1349 xmlHashFree(xsltExtensionsHash, 1350 (xmlHashDeallocator) xsltFreeExtModule); 1351 xsltExtensionsHash = NULL; 1352 1353 xmlMutexUnlock(xsltExtMutex); 1354} 1355 1356/** 1357 * xsltXPathGetTransformContext: 1358 * @ctxt: an XPath transformation context 1359 * 1360 * Provides the XSLT transformation context from the XPath transformation 1361 * context. This is useful when an XPath function in the extension module 1362 * is called by the XPath interpreter and that the XSLT context is needed 1363 * for example to retrieve the associated data pertaining to this XSLT 1364 * transformation. 1365 * 1366 * Returns the XSLT transformation context or NULL in case of error. 1367 */ 1368xsltTransformContextPtr 1369xsltXPathGetTransformContext(xmlXPathParserContextPtr ctxt) 1370{ 1371 if ((ctxt == NULL) || (ctxt->context == NULL)) 1372 return (NULL); 1373 return (ctxt->context->extra); 1374} 1375 1376/** 1377 * xsltRegisterExtModuleFunction: 1378 * @name: the function name 1379 * @URI: the function namespace URI 1380 * @function: the function callback 1381 * 1382 * Registers an extension module function. 1383 * 1384 * Returns 0 if successful, -1 in case of error. 1385 */ 1386int 1387xsltRegisterExtModuleFunction(const xmlChar * name, const xmlChar * URI, 1388 xmlXPathFunction function) 1389{ 1390 if ((name == NULL) || (URI == NULL) || (function == NULL)) 1391 return (-1); 1392 1393 if (xsltFunctionsHash == NULL) 1394 xsltFunctionsHash = xmlHashCreate(10); 1395 if (xsltFunctionsHash == NULL) 1396 return (-1); 1397 1398 xmlMutexLock(xsltExtMutex); 1399 1400 xmlHashUpdateEntry2(xsltFunctionsHash, name, URI, 1401 XML_CAST_FPTR(function), NULL); 1402 1403 xmlMutexUnlock(xsltExtMutex); 1404 1405 return (0); 1406} 1407 1408/** 1409 * xsltExtModuleFunctionLookup: 1410 * @name: the function name 1411 * @URI: the function namespace URI 1412 * 1413 * Looks up an extension module function 1414 * 1415 * Returns the function if found, NULL otherwise. 1416 */ 1417xmlXPathFunction 1418xsltExtModuleFunctionLookup(const xmlChar * name, const xmlChar * URI) 1419{ 1420 xmlXPathFunction ret; 1421 1422 if ((xsltFunctionsHash == NULL) || (name == NULL) || (URI == NULL)) 1423 return (NULL); 1424 1425 xmlMutexLock(xsltExtMutex); 1426 1427 XML_CAST_FPTR(ret) = xmlHashLookup2(xsltFunctionsHash, name, URI); 1428 1429 xmlMutexUnlock(xsltExtMutex); 1430 1431 /* if lookup fails, attempt a dynamic load on supported platforms */ 1432 if (NULL == ret) { 1433 if (!xsltExtModuleRegisterDynamic(URI)) { 1434 xmlMutexLock(xsltExtMutex); 1435 1436 XML_CAST_FPTR(ret) = 1437 xmlHashLookup2(xsltFunctionsHash, name, URI); 1438 1439 xmlMutexUnlock(xsltExtMutex); 1440 } 1441 } 1442 1443 return ret; 1444} 1445 1446/** 1447 * xsltUnregisterExtModuleFunction: 1448 * @name: the function name 1449 * @URI: the function namespace URI 1450 * 1451 * Unregisters an extension module function 1452 * 1453 * Returns 0 if successful, -1 in case of error. 1454 */ 1455int 1456xsltUnregisterExtModuleFunction(const xmlChar * name, const xmlChar * URI) 1457{ 1458 int ret; 1459 1460 if ((xsltFunctionsHash == NULL) || (name == NULL) || (URI == NULL)) 1461 return (-1); 1462 1463 xmlMutexLock(xsltExtMutex); 1464 1465 ret = xmlHashRemoveEntry2(xsltFunctionsHash, name, URI, NULL); 1466 1467 xmlMutexUnlock(xsltExtMutex); 1468 1469 return(ret); 1470} 1471 1472/** 1473 * xsltUnregisterAllExtModuleFunction: 1474 * 1475 * Unregisters all extension module function 1476 */ 1477static void 1478xsltUnregisterAllExtModuleFunction(void) 1479{ 1480 xmlMutexLock(xsltExtMutex); 1481 1482 xmlHashFree(xsltFunctionsHash, NULL); 1483 xsltFunctionsHash = NULL; 1484 1485 xmlMutexUnlock(xsltExtMutex); 1486} 1487 1488 1489/** 1490 * xsltNewElemPreComp: 1491 * @style: the XSLT stylesheet 1492 * @inst: the element node 1493 * @function: the transform function 1494 * 1495 * Creates and initializes an #xsltElemPreComp 1496 * 1497 * Returns the new and initialized #xsltElemPreComp 1498 */ 1499xsltElemPreCompPtr 1500xsltNewElemPreComp(xsltStylesheetPtr style, xmlNodePtr inst, 1501 xsltTransformFunction function) 1502{ 1503 xsltElemPreCompPtr cur; 1504 1505 cur = (xsltElemPreCompPtr) xmlMalloc(sizeof(xsltElemPreComp)); 1506 if (cur == NULL) { 1507 xsltTransformError(NULL, style, NULL, 1508 "xsltNewExtElement : malloc failed\n"); 1509 return (NULL); 1510 } 1511 memset(cur, 0, sizeof(xsltElemPreComp)); 1512 1513 xsltInitElemPreComp(cur, style, inst, function, 1514 (xsltElemPreCompDeallocator) xmlFree); 1515 1516 return (cur); 1517} 1518 1519/** 1520 * xsltInitElemPreComp: 1521 * @comp: an #xsltElemPreComp (or generally a derived structure) 1522 * @style: the XSLT stylesheet 1523 * @inst: the element node 1524 * @function: the transform function 1525 * @freeFunc: the @comp deallocator 1526 * 1527 * Initializes an existing #xsltElemPreComp structure. This is usefull 1528 * when extending an #xsltElemPreComp to store precomputed data. 1529 * This function MUST be called on any extension element precomputed 1530 * data struct. 1531 */ 1532void 1533xsltInitElemPreComp(xsltElemPreCompPtr comp, xsltStylesheetPtr style, 1534 xmlNodePtr inst, xsltTransformFunction function, 1535 xsltElemPreCompDeallocator freeFunc) 1536{ 1537 comp->type = XSLT_FUNC_EXTENSION; 1538 comp->func = function; 1539 comp->inst = inst; 1540 comp->free = freeFunc; 1541 1542 comp->next = style->preComps; 1543 style->preComps = comp; 1544} 1545 1546/** 1547 * xsltPreComputeExtModuleElement: 1548 * @style: the stylesheet 1549 * @inst: the element node 1550 * 1551 * Precomputes an extension module element 1552 * 1553 * Returns the precomputed data 1554 */ 1555xsltElemPreCompPtr 1556xsltPreComputeExtModuleElement(xsltStylesheetPtr style, xmlNodePtr inst) 1557{ 1558 xsltExtElementPtr ext; 1559 xsltElemPreCompPtr comp = NULL; 1560 1561 if ((style == NULL) || (inst == NULL) || 1562 (inst->type != XML_ELEMENT_NODE) || (inst->ns == NULL)) 1563 return (NULL); 1564 1565 xmlMutexLock(xsltExtMutex); 1566 1567 ext = (xsltExtElementPtr) 1568 xmlHashLookup2(xsltElementsHash, inst->name, inst->ns->href); 1569 1570 xmlMutexUnlock(xsltExtMutex); 1571 1572 /* 1573 * EXT TODO: Now what? 1574 */ 1575 if (ext == NULL) 1576 return (NULL); 1577 1578 if (ext->precomp != NULL) { 1579 /* 1580 * REVISIT TODO: Check if the text below is correct. 1581 * This will return a xsltElemPreComp structure or NULL. 1582 * 1) If the the author of the extension needs a 1583 * custom structure to hold the specific values of 1584 * this extension, he will derive a structure based on 1585 * xsltElemPreComp; thus we obviously *cannot* refactor 1586 * the xsltElemPreComp structure, since all already derived 1587 * user-defined strucures will break. 1588 * Example: For the extension xsl:document, 1589 * in xsltDocumentComp() (preproc.c), the structure 1590 * xsltStyleItemDocument is allocated, filled with 1591 * specific values and returned. 1592 * 2) If the author needs no values to be stored in 1593 * this structure, then he'll return NULL; 1594 */ 1595 comp = ext->precomp(style, inst, ext->transform); 1596 } 1597 if (comp == NULL) { 1598 /* 1599 * Default creation of a xsltElemPreComp structure, if 1600 * the author of this extension did not create a custom 1601 * structure. 1602 */ 1603 comp = xsltNewElemPreComp(style, inst, ext->transform); 1604 } 1605 1606 return (comp); 1607} 1608 1609/** 1610 * xsltRegisterExtModuleElement: 1611 * @name: the element name 1612 * @URI: the element namespace URI 1613 * @precomp: the pre-computation callback 1614 * @transform: the transformation callback 1615 * 1616 * Registers an extension module element. 1617 * 1618 * Returns 0 if successful, -1 in case of error. 1619 */ 1620int 1621xsltRegisterExtModuleElement(const xmlChar * name, const xmlChar * URI, 1622 xsltPreComputeFunction precomp, 1623 xsltTransformFunction transform) 1624{ 1625 int ret; 1626 1627 xsltExtElementPtr ext; 1628 1629 if ((name == NULL) || (URI == NULL) || (transform == NULL)) 1630 return (-1); 1631 1632 if (xsltElementsHash == NULL) 1633 xsltElementsHash = xmlHashCreate(10); 1634 if (xsltElementsHash == NULL) 1635 return (-1); 1636 1637 xmlMutexLock(xsltExtMutex); 1638 1639 ext = xsltNewExtElement(precomp, transform); 1640 if (ext == NULL) { 1641 ret = -1; 1642 goto done; 1643 } 1644 1645 xmlHashUpdateEntry2(xsltElementsHash, name, URI, (void *) ext, 1646 (xmlHashDeallocator) xsltFreeExtElement); 1647 1648done: 1649 xmlMutexUnlock(xsltExtMutex); 1650 1651 return (0); 1652} 1653 1654/** 1655 * xsltExtElementLookup: 1656 * @ctxt: an XSLT process context 1657 * @name: the element name 1658 * @URI: the element namespace URI 1659 * 1660 * Looks up an extension element. @ctxt can be NULL to search only in 1661 * module elements. 1662 * 1663 * Returns the element callback or NULL if not found 1664 */ 1665xsltTransformFunction 1666xsltExtElementLookup(xsltTransformContextPtr ctxt, 1667 const xmlChar * name, const xmlChar * URI) 1668{ 1669 xsltTransformFunction ret; 1670 1671 if ((name == NULL) || (URI == NULL)) 1672 return (NULL); 1673 1674 if ((ctxt != NULL) && (ctxt->extElements != NULL)) { 1675 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->extElements, name, URI); 1676 if (ret != NULL) { 1677 return(ret); 1678 } 1679 } 1680 1681 ret = xsltExtModuleElementLookup(name, URI); 1682 1683 return (ret); 1684} 1685 1686/** 1687 * xsltExtModuleElementLookup: 1688 * @name: the element name 1689 * @URI: the element namespace URI 1690 * 1691 * Looks up an extension module element 1692 * 1693 * Returns the callback function if found, NULL otherwise. 1694 */ 1695xsltTransformFunction 1696xsltExtModuleElementLookup(const xmlChar * name, const xmlChar * URI) 1697{ 1698 xsltExtElementPtr ext; 1699 1700 if ((xsltElementsHash == NULL) || (name == NULL) || (URI == NULL)) 1701 return (NULL); 1702 1703 xmlMutexLock(xsltExtMutex); 1704 1705 ext = (xsltExtElementPtr) xmlHashLookup2(xsltElementsHash, name, URI); 1706 1707 xmlMutexUnlock(xsltExtMutex); 1708 1709 /* 1710 * if function lookup fails, attempt a dynamic load on 1711 * supported platforms 1712 */ 1713 if (NULL == ext) { 1714 if (!xsltExtModuleRegisterDynamic(URI)) { 1715 xmlMutexLock(xsltExtMutex); 1716 1717 ext = (xsltExtElementPtr) 1718 xmlHashLookup2(xsltElementsHash, name, URI); 1719 1720 xmlMutexUnlock(xsltExtMutex); 1721 } 1722 } 1723 1724 if (ext == NULL) 1725 return (NULL); 1726 return (ext->transform); 1727} 1728 1729/** 1730 * xsltExtModuleElementPreComputeLookup: 1731 * @name: the element name 1732 * @URI: the element namespace URI 1733 * 1734 * Looks up an extension module element pre-computation function 1735 * 1736 * Returns the callback function if found, NULL otherwise. 1737 */ 1738xsltPreComputeFunction 1739xsltExtModuleElementPreComputeLookup(const xmlChar * name, 1740 const xmlChar * URI) 1741{ 1742 xsltExtElementPtr ext; 1743 1744 if ((xsltElementsHash == NULL) || (name == NULL) || (URI == NULL)) 1745 return (NULL); 1746 1747 xmlMutexLock(xsltExtMutex); 1748 1749 ext = (xsltExtElementPtr) xmlHashLookup2(xsltElementsHash, name, URI); 1750 1751 xmlMutexUnlock(xsltExtMutex); 1752 1753 if (ext == NULL) { 1754 if (!xsltExtModuleRegisterDynamic(URI)) { 1755 xmlMutexLock(xsltExtMutex); 1756 1757 ext = (xsltExtElementPtr) 1758 xmlHashLookup2(xsltElementsHash, name, URI); 1759 1760 xmlMutexUnlock(xsltExtMutex); 1761 } 1762 } 1763 1764 if (ext == NULL) 1765 return (NULL); 1766 return (ext->precomp); 1767} 1768 1769/** 1770 * xsltUnregisterExtModuleElement: 1771 * @name: the element name 1772 * @URI: the element namespace URI 1773 * 1774 * Unregisters an extension module element 1775 * 1776 * Returns 0 if successful, -1 in case of error. 1777 */ 1778int 1779xsltUnregisterExtModuleElement(const xmlChar * name, const xmlChar * URI) 1780{ 1781 int ret; 1782 1783 if ((xsltElementsHash == NULL) || (name == NULL) || (URI == NULL)) 1784 return (-1); 1785 1786 xmlMutexLock(xsltExtMutex); 1787 1788 ret = xmlHashRemoveEntry2(xsltElementsHash, name, URI, 1789 (xmlHashDeallocator) xsltFreeExtElement); 1790 1791 xmlMutexUnlock(xsltExtMutex); 1792 1793 return(ret); 1794} 1795 1796/** 1797 * xsltUnregisterAllExtModuleElement: 1798 * 1799 * Unregisters all extension module element 1800 */ 1801static void 1802xsltUnregisterAllExtModuleElement(void) 1803{ 1804 xmlMutexLock(xsltExtMutex); 1805 1806 xmlHashFree(xsltElementsHash, (xmlHashDeallocator) xsltFreeExtElement); 1807 xsltElementsHash = NULL; 1808 1809 xmlMutexUnlock(xsltExtMutex); 1810} 1811 1812/** 1813 * xsltRegisterExtModuleTopLevel: 1814 * @name: the top-level element name 1815 * @URI: the top-level element namespace URI 1816 * @function: the top-level element callback 1817 * 1818 * Registers an extension module top-level element. 1819 * 1820 * Returns 0 if successful, -1 in case of error. 1821 */ 1822int 1823xsltRegisterExtModuleTopLevel(const xmlChar * name, const xmlChar * URI, 1824 xsltTopLevelFunction function) 1825{ 1826 if ((name == NULL) || (URI == NULL) || (function == NULL)) 1827 return (-1); 1828 1829 if (xsltTopLevelsHash == NULL) 1830 xsltTopLevelsHash = xmlHashCreate(10); 1831 if (xsltTopLevelsHash == NULL) 1832 return (-1); 1833 1834 xmlMutexLock(xsltExtMutex); 1835 1836 xmlHashUpdateEntry2(xsltTopLevelsHash, name, URI, 1837 XML_CAST_FPTR(function), NULL); 1838 1839 xmlMutexUnlock(xsltExtMutex); 1840 1841 return (0); 1842} 1843 1844/** 1845 * xsltExtModuleTopLevelLookup: 1846 * @name: the top-level element name 1847 * @URI: the top-level element namespace URI 1848 * 1849 * Looks up an extension module top-level element 1850 * 1851 * Returns the callback function if found, NULL otherwise. 1852 */ 1853xsltTopLevelFunction 1854xsltExtModuleTopLevelLookup(const xmlChar * name, const xmlChar * URI) 1855{ 1856 xsltTopLevelFunction ret; 1857 1858 if ((xsltTopLevelsHash == NULL) || (name == NULL) || (URI == NULL)) 1859 return (NULL); 1860 1861 xmlMutexLock(xsltExtMutex); 1862 1863 XML_CAST_FPTR(ret) = xmlHashLookup2(xsltTopLevelsHash, name, URI); 1864 1865 xmlMutexUnlock(xsltExtMutex); 1866 1867 /* if lookup fails, attempt a dynamic load on supported platforms */ 1868 if (NULL == ret) { 1869 if (!xsltExtModuleRegisterDynamic(URI)) { 1870 xmlMutexLock(xsltExtMutex); 1871 1872 XML_CAST_FPTR(ret) = xmlHashLookup2(xsltTopLevelsHash, name, URI); 1873 1874 xmlMutexUnlock(xsltExtMutex); 1875 } 1876 } 1877 1878 return (ret); 1879} 1880 1881/** 1882 * xsltUnregisterExtModuleTopLevel: 1883 * @name: the top-level element name 1884 * @URI: the top-level element namespace URI 1885 * 1886 * Unregisters an extension module top-level element 1887 * 1888 * Returns 0 if successful, -1 in case of error. 1889 */ 1890int 1891xsltUnregisterExtModuleTopLevel(const xmlChar * name, const xmlChar * URI) 1892{ 1893 int ret; 1894 1895 if ((xsltTopLevelsHash == NULL) || (name == NULL) || (URI == NULL)) 1896 return (-1); 1897 1898 xmlMutexLock(xsltExtMutex); 1899 1900 ret = xmlHashRemoveEntry2(xsltTopLevelsHash, name, URI, NULL); 1901 1902 xmlMutexUnlock(xsltExtMutex); 1903 1904 return(ret); 1905} 1906 1907/** 1908 * xsltUnregisterAllExtModuleTopLevel: 1909 * 1910 * Unregisters all extension module function 1911 */ 1912static void 1913xsltUnregisterAllExtModuleTopLevel(void) 1914{ 1915 xmlMutexLock(xsltExtMutex); 1916 1917 xmlHashFree(xsltTopLevelsHash, NULL); 1918 xsltTopLevelsHash = NULL; 1919 1920 xmlMutexUnlock(xsltExtMutex); 1921} 1922 1923/** 1924 * xsltGetExtInfo: 1925 * @style: pointer to a stylesheet 1926 * @URI: the namespace URI desired 1927 * 1928 * looks up URI in extInfos of the stylesheet 1929 * 1930 * returns a pointer to the hash table if found, else NULL 1931 */ 1932xmlHashTablePtr 1933xsltGetExtInfo(xsltStylesheetPtr style, const xmlChar * URI) 1934{ 1935 xsltExtDataPtr data; 1936 1937 /* 1938 * TODO: Why do we have a return type of xmlHashTablePtr? 1939 * Is the user-allocated data for extension modules expected 1940 * to be a xmlHashTablePtr only? Or is this intended for 1941 * the EXSLT module only? 1942 */ 1943 1944 if (style != NULL && style->extInfos != NULL) { 1945 data = xmlHashLookup(style->extInfos, URI); 1946 if (data != NULL && data->extData != NULL) 1947 return data->extData; 1948 } 1949 return NULL; 1950} 1951 1952/************************************************************************ 1953 * * 1954 * Test module http://xmlsoft.org/XSLT/ * 1955 * * 1956 ************************************************************************/ 1957 1958/************************************************************************ 1959 * * 1960 * Test of the extension module API * 1961 * * 1962 ************************************************************************/ 1963 1964static xmlChar *testData = NULL; 1965static xmlChar *testStyleData = NULL; 1966 1967/** 1968 * xsltExtFunctionTest: 1969 * @ctxt: the XPath Parser context 1970 * @nargs: the number of arguments 1971 * 1972 * function libxslt:test() for testing the extensions support. 1973 */ 1974static void 1975xsltExtFunctionTest(xmlXPathParserContextPtr ctxt, 1976 int nargs ATTRIBUTE_UNUSED) 1977{ 1978 xsltTransformContextPtr tctxt; 1979 void *data = NULL; 1980 1981 tctxt = xsltXPathGetTransformContext(ctxt); 1982 1983 if (testData == NULL) { 1984 xsltGenericDebug(xsltGenericDebugContext, 1985 "xsltExtFunctionTest: not initialized," 1986 " calling xsltGetExtData\n"); 1987 data = xsltGetExtData(tctxt, (const xmlChar *) XSLT_DEFAULT_URL); 1988 if (data == NULL) { 1989 xsltTransformError(tctxt, NULL, NULL, 1990 "xsltExtElementTest: not initialized\n"); 1991 return; 1992 } 1993 } 1994 if (tctxt == NULL) { 1995 xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, 1996 "xsltExtFunctionTest: failed to get the transformation context\n"); 1997 return; 1998 } 1999 if (data == NULL) 2000 data = xsltGetExtData(tctxt, (const xmlChar *) XSLT_DEFAULT_URL); 2001 if (data == NULL) { 2002 xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, 2003 "xsltExtFunctionTest: failed to get module data\n"); 2004 return; 2005 } 2006 if (data != testData) { 2007 xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, 2008 "xsltExtFunctionTest: got wrong module data\n"); 2009 return; 2010 } 2011#ifdef WITH_XSLT_DEBUG_FUNCTION 2012 xsltGenericDebug(xsltGenericDebugContext, 2013 "libxslt:test() called with %d args\n", nargs); 2014#endif 2015} 2016 2017/** 2018 * xsltExtElementPreCompTest: 2019 * @style: the stylesheet 2020 * @inst: the instruction in the stylesheet 2021 * 2022 * Process a libxslt:test node 2023 */ 2024static xsltElemPreCompPtr 2025xsltExtElementPreCompTest(xsltStylesheetPtr style, xmlNodePtr inst, 2026 xsltTransformFunction function) 2027{ 2028 xsltElemPreCompPtr ret; 2029 2030 if (style == NULL) { 2031 xsltTransformError(NULL, NULL, inst, 2032 "xsltExtElementTest: no transformation context\n"); 2033 return (NULL); 2034 } 2035 if (testStyleData == NULL) { 2036 xsltGenericDebug(xsltGenericDebugContext, 2037 "xsltExtElementPreCompTest: not initialized," 2038 " calling xsltStyleGetExtData\n"); 2039 xsltStyleGetExtData(style, (const xmlChar *) XSLT_DEFAULT_URL); 2040 if (testStyleData == NULL) { 2041 xsltTransformError(NULL, style, inst, 2042 "xsltExtElementPreCompTest: not initialized\n"); 2043 if (style != NULL) 2044 style->errors++; 2045 return (NULL); 2046 } 2047 } 2048 if (inst == NULL) { 2049 xsltTransformError(NULL, style, inst, 2050 "xsltExtElementPreCompTest: no instruction\n"); 2051 if (style != NULL) 2052 style->errors++; 2053 return (NULL); 2054 } 2055 ret = xsltNewElemPreComp(style, inst, function); 2056 return (ret); 2057} 2058 2059/** 2060 * xsltExtElementTest: 2061 * @ctxt: an XSLT processing context 2062 * @node: The current node 2063 * @inst: the instruction in the stylesheet 2064 * @comp: precomputed informations 2065 * 2066 * Process a libxslt:test node 2067 */ 2068static void 2069xsltExtElementTest(xsltTransformContextPtr ctxt, xmlNodePtr node, 2070 xmlNodePtr inst, 2071 xsltElemPreCompPtr comp ATTRIBUTE_UNUSED) 2072{ 2073 xmlNodePtr commentNode; 2074 2075 if (testData == NULL) { 2076 xsltGenericDebug(xsltGenericDebugContext, 2077 "xsltExtElementTest: not initialized," 2078 " calling xsltGetExtData\n"); 2079 xsltGetExtData(ctxt, (const xmlChar *) XSLT_DEFAULT_URL); 2080 if (testData == NULL) { 2081 xsltTransformError(ctxt, NULL, inst, 2082 "xsltExtElementTest: not initialized\n"); 2083 return; 2084 } 2085 } 2086 if (ctxt == NULL) { 2087 xsltTransformError(ctxt, NULL, inst, 2088 "xsltExtElementTest: no transformation context\n"); 2089 return; 2090 } 2091 if (node == NULL) { 2092 xsltTransformError(ctxt, NULL, inst, 2093 "xsltExtElementTest: no current node\n"); 2094 return; 2095 } 2096 if (inst == NULL) { 2097 xsltTransformError(ctxt, NULL, inst, 2098 "xsltExtElementTest: no instruction\n"); 2099 return; 2100 } 2101 if (ctxt->insert == NULL) { 2102 xsltTransformError(ctxt, NULL, inst, 2103 "xsltExtElementTest: no insertion point\n"); 2104 return; 2105 } 2106 commentNode = xmlNewComment((const xmlChar *) 2107 "libxslt:test element test worked"); 2108 xmlAddChild(ctxt->insert, commentNode); 2109} 2110 2111/** 2112 * xsltExtInitTest: 2113 * @ctxt: an XSLT transformation context 2114 * @URI: the namespace URI for the extension 2115 * 2116 * A function called at initialization time of an XSLT extension module 2117 * 2118 * Returns a pointer to the module specific data for this transformation 2119 */ 2120static void * 2121xsltExtInitTest(xsltTransformContextPtr ctxt, const xmlChar * URI) 2122{ 2123 if (testStyleData == NULL) { 2124 xsltGenericDebug(xsltGenericErrorContext, 2125 "xsltExtInitTest: not initialized," 2126 " calling xsltStyleGetExtData\n"); 2127 testStyleData = xsltStyleGetExtData(ctxt->style, URI); 2128 if (testStyleData == NULL) { 2129 xsltTransformError(ctxt, NULL, NULL, 2130 "xsltExtInitTest: not initialized\n"); 2131 return (NULL); 2132 } 2133 } 2134 if (testData != NULL) { 2135 xsltTransformError(ctxt, NULL, NULL, 2136 "xsltExtInitTest: already initialized\n"); 2137 return (NULL); 2138 } 2139 testData = (void *) "test data"; 2140 xsltGenericDebug(xsltGenericDebugContext, 2141 "Registered test module : %s\n", URI); 2142 return (testData); 2143} 2144 2145 2146/** 2147 * xsltExtShutdownTest: 2148 * @ctxt: an XSLT transformation context 2149 * @URI: the namespace URI for the extension 2150 * @data: the data associated to this module 2151 * 2152 * A function called at shutdown time of an XSLT extension module 2153 */ 2154static void 2155xsltExtShutdownTest(xsltTransformContextPtr ctxt, 2156 const xmlChar * URI, void *data) 2157{ 2158 if (testData == NULL) { 2159 xsltTransformError(ctxt, NULL, NULL, 2160 "xsltExtShutdownTest: not initialized\n"); 2161 return; 2162 } 2163 if (data != testData) { 2164 xsltTransformError(ctxt, NULL, NULL, 2165 "xsltExtShutdownTest: wrong data\n"); 2166 } 2167 testData = NULL; 2168 xsltGenericDebug(xsltGenericDebugContext, 2169 "Unregistered test module : %s\n", URI); 2170} 2171 2172/** 2173 * xsltExtStyleInitTest: 2174 * @style: an XSLT stylesheet 2175 * @URI: the namespace URI for the extension 2176 * 2177 * A function called at initialization time of an XSLT extension module 2178 * 2179 * Returns a pointer to the module specific data for this transformation 2180 */ 2181static void * 2182xsltExtStyleInitTest(xsltStylesheetPtr style ATTRIBUTE_UNUSED, 2183 const xmlChar * URI) 2184{ 2185 if (testStyleData != NULL) { 2186 xsltTransformError(NULL, NULL, NULL, 2187 "xsltExtInitTest: already initialized\n"); 2188 return (NULL); 2189 } 2190 testStyleData = (void *) "test data"; 2191 xsltGenericDebug(xsltGenericDebugContext, 2192 "Registered test module : %s\n", URI); 2193 return (testStyleData); 2194} 2195 2196 2197/** 2198 * xsltExtStyleShutdownTest: 2199 * @style: an XSLT stylesheet 2200 * @URI: the namespace URI for the extension 2201 * @data: the data associated to this module 2202 * 2203 * A function called at shutdown time of an XSLT extension module 2204 */ 2205static void 2206xsltExtStyleShutdownTest(xsltStylesheetPtr style ATTRIBUTE_UNUSED, 2207 const xmlChar * URI, void *data) 2208{ 2209 if (testStyleData == NULL) { 2210 xsltGenericError(xsltGenericErrorContext, 2211 "xsltExtShutdownTest: not initialized\n"); 2212 return; 2213 } 2214 if (data != testStyleData) { 2215 xsltTransformError(NULL, NULL, NULL, 2216 "xsltExtShutdownTest: wrong data\n"); 2217 } 2218 testStyleData = NULL; 2219 xsltGenericDebug(xsltGenericDebugContext, 2220 "Unregistered test module : %s\n", URI); 2221} 2222 2223/** 2224 * xsltRegisterTestModule: 2225 * 2226 * Registers the test module 2227 */ 2228void 2229xsltRegisterTestModule(void) 2230{ 2231 xsltInitGlobals(); 2232 xsltRegisterExtModuleFull((const xmlChar *) XSLT_DEFAULT_URL, 2233 xsltExtInitTest, xsltExtShutdownTest, 2234 xsltExtStyleInitTest, 2235 xsltExtStyleShutdownTest); 2236 xsltRegisterExtModuleFunction((const xmlChar *) "test", 2237 (const xmlChar *) XSLT_DEFAULT_URL, 2238 xsltExtFunctionTest); 2239 xsltRegisterExtModuleElement((const xmlChar *) "test", 2240 (const xmlChar *) XSLT_DEFAULT_URL, 2241 xsltExtElementPreCompTest, 2242 xsltExtElementTest); 2243} 2244 2245static void 2246xsltHashScannerModuleFree(void *payload ATTRIBUTE_UNUSED, 2247 void *data ATTRIBUTE_UNUSED, 2248 xmlChar * name ATTRIBUTE_UNUSED) 2249{ 2250#ifdef WITH_MODULES 2251 xmlModuleClose(payload); 2252#endif 2253} 2254 2255/** 2256 * xsltInitGlobals: 2257 * 2258 * Initialize the global variables for extensions 2259 */ 2260void 2261xsltInitGlobals(void) 2262{ 2263 if (xsltExtMutex == NULL) { 2264 xsltExtMutex = xmlNewMutex(); 2265 } 2266} 2267 2268/** 2269 * xsltCleanupGlobals: 2270 * 2271 * Unregister all global variables set up by the XSLT library 2272 */ 2273void 2274xsltCleanupGlobals(void) 2275{ 2276 xsltUnregisterAllExtModules(); 2277 xsltUnregisterAllExtModuleFunction(); 2278 xsltUnregisterAllExtModuleElement(); 2279 xsltUnregisterAllExtModuleTopLevel(); 2280 2281 xmlMutexLock(xsltExtMutex); 2282 /* cleanup dynamic module hash */ 2283 if (NULL != xsltModuleHash) { 2284 xmlHashScan(xsltModuleHash, xsltHashScannerModuleFree, 0); 2285 xmlHashFree(xsltModuleHash, NULL); 2286 xsltModuleHash = NULL; 2287 } 2288 xmlMutexUnlock(xsltExtMutex); 2289 2290 xmlFreeMutex(xsltExtMutex); 2291 xsltExtMutex = NULL; 2292 xsltUninit(); 2293} 2294 2295static void 2296xsltDebugDumpExtensionsCallback(void *function ATTRIBUTE_UNUSED, 2297 FILE * output, const xmlChar * name, 2298 const xmlChar * URI, 2299 const xmlChar * not_used ATTRIBUTE_UNUSED) 2300{ 2301 if (!name || !URI) 2302 return; 2303 fprintf(output, "{%s}%s\n", URI, name); 2304} 2305 2306static void 2307xsltDebugDumpExtModulesCallback(void *function ATTRIBUTE_UNUSED, 2308 FILE * output, const xmlChar * URI, 2309 const xmlChar * not_used ATTRIBUTE_UNUSED, 2310 const xmlChar * not_used2 ATTRIBUTE_UNUSED) 2311{ 2312 if (!URI) 2313 return; 2314 fprintf(output, "%s\n", URI); 2315} 2316 2317/** 2318 * xsltDebugDumpExtensions: 2319 * @output: the FILE * for the output, if NULL stdout is used 2320 * 2321 * Dumps a list of the registered XSLT extension functions and elements 2322 */ 2323void 2324xsltDebugDumpExtensions(FILE * output) 2325{ 2326 if (output == NULL) 2327 output = stdout; 2328 fprintf(output, 2329 "Registered XSLT Extensions\n--------------------------\n"); 2330 if (!xsltFunctionsHash) 2331 fprintf(output, "No registered extension functions\n"); 2332 else { 2333 fprintf(output, "Registered Extension Functions:\n"); 2334 xmlMutexLock(xsltExtMutex); 2335 xmlHashScanFull(xsltFunctionsHash, 2336 (xmlHashScannerFull) 2337 xsltDebugDumpExtensionsCallback, output); 2338 xmlMutexUnlock(xsltExtMutex); 2339 } 2340 if (!xsltElementsHash) 2341 fprintf(output, "\nNo registered extension elements\n"); 2342 else { 2343 fprintf(output, "\nRegistered Extension Elements:\n"); 2344 xmlMutexLock(xsltExtMutex); 2345 xmlHashScanFull(xsltElementsHash, 2346 (xmlHashScannerFull) 2347 xsltDebugDumpExtensionsCallback, output); 2348 xmlMutexUnlock(xsltExtMutex); 2349 } 2350 if (!xsltExtensionsHash) 2351 fprintf(output, "\nNo registered extension modules\n"); 2352 else { 2353 fprintf(output, "\nRegistered Extension Modules:\n"); 2354 xmlMutexLock(xsltExtMutex); 2355 xmlHashScanFull(xsltExtensionsHash, 2356 (xmlHashScannerFull) 2357 xsltDebugDumpExtModulesCallback, output); 2358 xmlMutexUnlock(xsltExtMutex); 2359 } 2360 2361} 2362