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