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