1/*
2 * extensions.c: Implemetation of the extensions support
3 *
4 * Reference:
5 *   http://www.w3.org/TR/1999/REC-xslt-19991116
6 *
7 * See Copyright for the status of this software.
8 *
9 * daniel@veillard.com
10 */
11
12#include <libxslt/libxslt.h>
13
14#ifdef WITH_MODULES
15
16#include <string.h>
17#include <limits.h>
18
19#include <libxml/xmlmemory.h>
20#include <libxml/tree.h>
21#include <libxml/hash.h>
22#include <libxml/xmlerror.h>
23#include <libxml/parserInternals.h>
24#include <libxml/xpathInternals.h>
25#include <libxml/list.h>
26#include <libxml/xmlIO.h>
27#include <libxslt/xslt.h>
28#include <libxslt/xsltInternals.h>
29#include <libxslt/xsltutils.h>
30#include <libxslt/imports.h>
31#include <libxslt/extensions.h>
32
33#define XSLT_TESTPLUGIN_URL "http://xmlsoft.org/xslt/testplugin"
34
35/* make sure init function is exported on win32 */
36#if defined(_WIN32)
37  #define PLUGINPUBFUN __declspec(dllexport)
38#else
39  #define PLUGINPUBFUN
40#endif
41
42/* include a prototype to make gcc happy */
43void
44PLUGINPUBFUN xmlsoft_org_xslt_testplugin_init(void);
45
46/************************************************************************
47 * 									*
48 * 		Test plugin module http://xmlsoft.org/xslt/testplugin			*
49 * 									*
50 ************************************************************************/
51
52/************************************************************************
53 * 									*
54 * 		Test of the extension module API			*
55 * 									*
56 ************************************************************************/
57
58static xmlChar *testData = NULL;
59static xmlChar *testStyleData = NULL;
60
61/**
62 * xsltExtFunctionTest:
63 * @ctxt:  the XPath Parser context
64 * @nargs:  the number of arguments
65 *
66 * function libxslt:test() for testing the extensions support.
67 */
68static void
69xsltExtFunctionTest(xmlXPathParserContextPtr ctxt,
70                    int nargs ATTRIBUTE_UNUSED)
71{
72    xsltTransformContextPtr tctxt;
73    void *data = NULL;
74
75    tctxt = xsltXPathGetTransformContext(ctxt);
76
77    if (testData == NULL) {
78        xsltGenericDebug(xsltGenericDebugContext,
79                         "xsltExtFunctionTest: not initialized,"
80                         " calling xsltGetExtData\n");
81        data = xsltGetExtData(tctxt, (const xmlChar *) XSLT_TESTPLUGIN_URL);
82        if (data == NULL) {
83            xsltTransformError(tctxt, NULL, NULL,
84                               "xsltExtElementTest: not initialized\n");
85            return;
86        }
87    }
88    if (tctxt == NULL) {
89        xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
90                           "xsltExtFunctionTest: failed to get the transformation context\n");
91        return;
92    }
93    if (data == NULL)
94        data = xsltGetExtData(tctxt, (const xmlChar *) XSLT_TESTPLUGIN_URL);
95    if (data == NULL) {
96        xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
97                           "xsltExtFunctionTest: failed to get module data\n");
98        return;
99    }
100    if (data != testData) {
101        xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
102                           "xsltExtFunctionTest: got wrong module data\n");
103        return;
104    }
105#ifdef WITH_XSLT_DEBUG_FUNCTION
106    xsltGenericDebug(xsltGenericDebugContext,
107                     "libxslt:test() called with %d args\n", nargs);
108#endif
109}
110
111/**
112 * xsltExtElementPreCompTest:
113 * @style:  the stylesheet
114 * @inst:  the instruction in the stylesheet
115 *
116 * Process a libxslt:test node
117 */
118static xsltElemPreCompPtr
119xsltExtElementPreCompTest(xsltStylesheetPtr style, xmlNodePtr inst,
120                          xsltTransformFunction function)
121{
122    xsltElemPreCompPtr ret;
123
124    if (style == NULL) {
125        xsltTransformError(NULL, NULL, inst,
126                           "xsltExtElementTest: no transformation context\n");
127        return (NULL);
128    }
129    if (testStyleData == NULL) {
130        xsltGenericDebug(xsltGenericDebugContext,
131                         "xsltExtElementPreCompTest: not initialized,"
132                         " calling xsltStyleGetExtData\n");
133        xsltStyleGetExtData(style, (const xmlChar *) XSLT_TESTPLUGIN_URL);
134        if (testStyleData == NULL) {
135            xsltTransformError(NULL, style, inst,
136                               "xsltExtElementPreCompTest: not initialized\n");
137            if (style != NULL)
138                style->errors++;
139            return (NULL);
140        }
141    }
142    if (inst == NULL) {
143        xsltTransformError(NULL, style, inst,
144                           "xsltExtElementPreCompTest: no instruction\n");
145        if (style != NULL)
146            style->errors++;
147        return (NULL);
148    }
149    ret = xsltNewElemPreComp(style, inst, function);
150    return (ret);
151}
152
153/**
154 * xsltExtElementTest:
155 * @ctxt:  an XSLT processing context
156 * @node:  The current node
157 * @inst:  the instruction in the stylesheet
158 * @comp:  precomputed informations
159 *
160 * Process a libxslt:test node
161 */
162static void
163xsltExtElementTest(xsltTransformContextPtr ctxt, xmlNodePtr node,
164                   xmlNodePtr inst,
165                   xsltElemPreCompPtr comp ATTRIBUTE_UNUSED)
166{
167    xmlNodePtr commentNode;
168
169    if (testData == NULL) {
170        xsltGenericDebug(xsltGenericDebugContext,
171                         "xsltExtElementTest: not initialized,"
172                         " calling xsltGetExtData\n");
173        xsltGetExtData(ctxt, (const xmlChar *) XSLT_TESTPLUGIN_URL);
174        if (testData == NULL) {
175            xsltTransformError(ctxt, NULL, inst,
176                               "xsltExtElementTest: not initialized\n");
177            return;
178        }
179    }
180    if (ctxt == NULL) {
181        xsltTransformError(ctxt, NULL, inst,
182                           "xsltExtElementTest: no transformation context\n");
183        return;
184    }
185    if (node == NULL) {
186        xsltTransformError(ctxt, NULL, inst,
187                           "xsltExtElementTest: no current node\n");
188        return;
189    }
190    if (inst == NULL) {
191        xsltTransformError(ctxt, NULL, inst,
192                           "xsltExtElementTest: no instruction\n");
193        return;
194    }
195    if (ctxt->insert == NULL) {
196        xsltTransformError(ctxt, NULL, inst,
197                           "xsltExtElementTest: no insertion point\n");
198        return;
199    }
200    commentNode = xmlNewComment((const xmlChar *)
201                                "libxslt:testplugin element test worked");
202    xmlAddChild(ctxt->insert, commentNode);
203}
204
205/**
206 * xsltExtInitTest:
207 * @ctxt:  an XSLT transformation context
208 * @URI:  the namespace URI for the extension
209 *
210 * A function called at initialization time of an XSLT extension module
211 *
212 * Returns a pointer to the module specific data for this transformation
213 */
214static void *
215xsltExtInitTest(xsltTransformContextPtr ctxt, const xmlChar * URI)
216{
217    if (testStyleData == NULL) {
218        xsltGenericDebug(xsltGenericErrorContext,
219                         "xsltExtInitTest: not initialized,"
220                         " calling xsltStyleGetExtData\n");
221        xsltStyleGetExtData(ctxt->style, URI);
222        if (testStyleData == NULL) {
223            xsltTransformError(ctxt, NULL, NULL,
224                               "xsltExtInitTest: not initialized\n");
225            return (NULL);
226        }
227    }
228    if (testData != NULL) {
229        xsltTransformError(ctxt, NULL, NULL,
230                           "xsltExtInitTest: already initialized\n");
231        return (NULL);
232    }
233    testData = (void *) "test data";
234    xsltGenericDebug(xsltGenericDebugContext,
235                     "Registered test plugin module : %s\n", URI);
236    return (testData);
237}
238
239
240/**
241 * xsltExtShutdownTest:
242 * @ctxt:  an XSLT transformation context
243 * @URI:  the namespace URI for the extension
244 * @data:  the data associated to this module
245 *
246 * A function called at shutdown time of an XSLT extension module
247 */
248static void
249xsltExtShutdownTest(xsltTransformContextPtr ctxt,
250                    const xmlChar * URI, void *data)
251{
252    if (testData == NULL) {
253        xsltTransformError(ctxt, NULL, NULL,
254                           "xsltExtShutdownTest: not initialized\n");
255        return;
256    }
257    if (data != testData) {
258        xsltTransformError(ctxt, NULL, NULL,
259                           "xsltExtShutdownTest: wrong data\n");
260    }
261    testData = NULL;
262    xsltGenericDebug(xsltGenericDebugContext,
263                     "Unregistered test plugin module : %s\n", URI);
264}
265
266/**
267 * xsltExtStyleInitTest:
268 * @style:  an XSLT stylesheet
269 * @URI:  the namespace URI for the extension
270 *
271 * A function called at initialization time of an XSLT extension module
272 *
273 * Returns a pointer to the module specific data for this transformation
274 */
275static void *
276xsltExtStyleInitTest(xsltStylesheetPtr style ATTRIBUTE_UNUSED,
277                     const xmlChar * URI)
278{
279    if (testStyleData != NULL) {
280        xsltTransformError(NULL, NULL, NULL,
281                           "xsltExtInitTest: already initialized\n");
282        return (NULL);
283    }
284    testStyleData = (void *) "test data";
285    xsltGenericDebug(xsltGenericDebugContext,
286                     "Registered test plugin module : %s\n", URI);
287    return (testStyleData);
288}
289
290
291/**
292 * xsltExtStyleShutdownTest:
293 * @style:  an XSLT stylesheet
294 * @URI:  the namespace URI for the extension
295 * @data:  the data associated to this module
296 *
297 * A function called at shutdown time of an XSLT extension module
298 */
299static void
300xsltExtStyleShutdownTest(xsltStylesheetPtr style ATTRIBUTE_UNUSED,
301                         const xmlChar * URI, void *data)
302{
303    if (testStyleData == NULL) {
304        xsltGenericError(xsltGenericErrorContext,
305                         "xsltExtShutdownTest: not initialized\n");
306        return;
307    }
308    if (data != testStyleData) {
309        xsltTransformError(NULL, NULL, NULL,
310                           "xsltExtShutdownTest: wrong data\n");
311    }
312    testStyleData = NULL;
313    xsltGenericDebug(xsltGenericDebugContext,
314                     "Unregistered test plugin module : %s\n", URI);
315}
316
317/**
318 * xmlsoft_org_xslt_testplugin_init:
319 *
320 * Registers the test plugin module
321 */
322
323void
324PLUGINPUBFUN xmlsoft_org_xslt_testplugin_init(void)
325{
326    xsltRegisterExtModuleFull((const xmlChar *) XSLT_TESTPLUGIN_URL,
327                              xsltExtInitTest, xsltExtShutdownTest,
328                              xsltExtStyleInitTest,
329                              xsltExtStyleShutdownTest);
330    xsltRegisterExtModuleFunction((const xmlChar *) "testplugin",
331                                  (const xmlChar *) XSLT_TESTPLUGIN_URL,
332                                  xsltExtFunctionTest);
333    xsltRegisterExtModuleElement((const xmlChar *) "testplugin",
334                                 (const xmlChar *) XSLT_TESTPLUGIN_URL,
335                                 xsltExtElementPreCompTest,
336                                 xsltExtElementTest);
337}
338
339#endif /*WITH_MODULES*/
340