Coverage Report

Created: 2023-09-24 16:03

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