Coverage Report

Created: 2025-07-07 10:01

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