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