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