Coverage Report

Created: 2024-01-17 17:02

/src/libxslt/libexslt/saxon.c
Line
Count
Source (jump to first uncovered line)
1
#define IN_LIBEXSLT
2
#include "libexslt/libexslt.h"
3
4
#include <libxml/tree.h>
5
#include <libxml/xpath.h>
6
#include <libxml/xpathInternals.h>
7
#include <libxml/parser.h>
8
#include <libxml/hash.h>
9
10
#include <libxslt/xsltutils.h>
11
#include <libxslt/xsltInternals.h>
12
#include <libxslt/extensions.h>
13
14
#include "exslt.h"
15
16
/**
17
 * exsltSaxonInit:
18
 * @ctxt: an XSLT transformation context
19
 * @URI: the namespace URI for the extension
20
 *
21
 * Initializes the SAXON module.
22
 *
23
 * Returns the data for this transformation
24
 */
25
static void *
26
exsltSaxonInit (xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED,
27
352
    const xmlChar *URI ATTRIBUTE_UNUSED) {
28
352
    return xmlHashCreate(1);
29
352
}
30
31
static void
32
exsltSaxonFreeCompExprEntry(void *payload,
33
0
                            const xmlChar *name ATTRIBUTE_UNUSED) {
34
0
    xmlXPathFreeCompExpr((xmlXPathCompExprPtr) payload);
35
0
}
36
37
/**
38
 * exsltSaxonShutdown:
39
 * @ctxt: an XSLT transformation context
40
 * @URI: the namespace URI for the extension
41
 * @data: the module data to free up
42
 *
43
 * Shutdown the SAXON extension module
44
 */
45
static void
46
exsltSaxonShutdown (xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED,
47
        const xmlChar *URI ATTRIBUTE_UNUSED,
48
0
        void *vdata) {
49
0
    xmlHashTablePtr data = (xmlHashTablePtr) vdata;
50
0
    xmlHashFree(data, exsltSaxonFreeCompExprEntry);
51
0
}
52
53
54
/**
55
 * exsltSaxonExpressionFunction:
56
 * @ctxt: an XPath parser context
57
 * @nargs: the number of arguments
58
 *
59
 * The supplied string must contain an XPath expression. The result of
60
 * the function is a stored expression, which may be supplied as an
61
 * argument to other extension functions such as saxon:eval(),
62
 * saxon:sum() and saxon:distinct(). The result of the expression will
63
 * usually depend on the current node. The expression may contain
64
 * references to variables that are in scope at the point where
65
 * saxon:expression() is called: these variables will be replaced in
66
 * the stored expression with the values they take at the time
67
 * saxon:expression() is called, not the values of the variables at
68
 * the time the stored expression is evaluated.  Similarly, if the
69
 * expression contains namespace prefixes, these are interpreted in
70
 * terms of the namespace declarations in scope at the point where the
71
 * saxon:expression() function is called, not those in scope where the
72
 * stored expression is evaluated.
73
 *
74
 * TODO: current implementation doesn't conform to SAXON behaviour
75
 * regarding context and namespaces.
76
 */
77
static void
78
5.98k
exsltSaxonExpressionFunction (xmlXPathParserContextPtr ctxt, int nargs) {
79
5.98k
    xmlChar *arg;
80
5.98k
    xmlXPathCompExprPtr ret;
81
5.98k
    xmlHashTablePtr hash;
82
5.98k
    xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt);
83
84
5.98k
    if (nargs != 1) {
85
66
  xmlXPathSetArityError(ctxt);
86
66
  return;
87
66
    }
88
89
5.92k
    arg = xmlXPathPopString(ctxt);
90
5.92k
    if (xmlXPathCheckError(ctxt) || (arg == NULL)) {
91
0
  xmlXPathSetTypeError(ctxt);
92
0
  return;
93
0
    }
94
95
5.92k
    hash = (xmlHashTablePtr) xsltGetExtData(tctxt,
96
5.92k
              ctxt->context->functionURI);
97
98
5.92k
    ret = xmlHashLookup(hash, arg);
99
100
5.92k
    if (ret == NULL) {
101
2.03k
   ret = xmlXPathCtxtCompile(tctxt->xpathCtxt, arg);
102
2.03k
   if (ret == NULL) {
103
265
        xmlFree(arg);
104
265
              xmlXPathSetError(ctxt, XPATH_EXPR_ERROR);
105
265
        return;
106
265
   }
107
1.77k
   xmlHashAddEntry(hash, arg, (void *) ret);
108
1.77k
    }
109
110
5.65k
    xmlFree(arg);
111
112
5.65k
    xmlXPathReturnExternal(ctxt, ret);
113
5.65k
}
114
115
/**
116
 * exsltSaxonEvalFunction:
117
 * @ctxt:  an XPath parser context
118
 * @nargs:  number of arguments
119
 *
120
 * Implements de SAXON eval() function:
121
 *    object saxon:eval (saxon:stored-expression)
122
 * Returns the result of evaluating the supplied stored expression.
123
 * A stored expression may be obtained as the result of calling
124
 * the saxon:expression() function.
125
 * The stored expression is evaluated in the current context, that
126
 * is, the context node is the current node, and the context position
127
 * and context size are the same as the result of calling position()
128
 * or last() respectively.
129
 */
130
static void
131
4.18k
exsltSaxonEvalFunction (xmlXPathParserContextPtr ctxt, int nargs) {
132
4.18k
     xmlXPathCompExprPtr expr;
133
4.18k
     xmlXPathObjectPtr ret;
134
135
4.18k
     if (nargs != 1) {
136
106
    xmlXPathSetArityError(ctxt);
137
106
    return;
138
106
     }
139
140
4.08k
     if (!xmlXPathStackIsExternal(ctxt)) {
141
323
    xmlXPathSetTypeError(ctxt);
142
323
    return;
143
323
     }
144
145
3.75k
     expr = (xmlXPathCompExprPtr) xmlXPathPopExternal(ctxt);
146
147
3.75k
     ret = xmlXPathCompiledEval(expr, ctxt->context);
148
3.75k
     if (ret == NULL) {
149
529
    xmlXPathSetError(ctxt, XPATH_EXPR_ERROR);
150
529
    return;
151
529
     }
152
153
3.22k
     valuePush(ctxt, ret);
154
3.22k
}
155
156
/**
157
 * exsltSaxonEvaluateFunction:
158
 * @ctxt:  an XPath parser context
159
 * @nargs: number of arguments
160
 *
161
 * Implements the SAXON evaluate() function
162
 *     object saxon:evaluate (string)
163
 * The supplied string must contain an XPath expression. The result of
164
 * the function is the result of evaluating the XPath expression. This
165
 * is useful where an expression needs to be constructed at run-time or
166
 * passed to the stylesheet as a parameter, for example where the sort
167
 * key is determined dynamically. The context for the expression (e.g.
168
 * which variables and namespaces are available) is exactly the same as
169
 * if the expression were written explicitly at this point in the
170
 * stylesheet. The function saxon:evaluate(string) is shorthand for
171
 * saxon:eval(saxon:expression(string)).
172
 */
173
static void
174
2.28k
exsltSaxonEvaluateFunction (xmlXPathParserContextPtr ctxt, int nargs) {
175
2.28k
     if (nargs != 1) {
176
14
    xmlXPathSetArityError(ctxt);
177
14
    return;
178
14
     }
179
180
2.27k
     exsltSaxonExpressionFunction(ctxt, 1);
181
2.27k
     exsltSaxonEvalFunction(ctxt, 1);
182
2.27k
}
183
184
/**
185
 * exsltSaxonSystemIdFunction:
186
 * @ctxt:  an XPath parser context
187
 * @nargs: number of arguments
188
 *
189
 * Implements the SAXON systemId() function
190
 *     string saxon:systemId ()
191
 * This function returns the system ID of the document being styled.
192
 */
193
static void
194
exsltSaxonSystemIdFunction(xmlXPathParserContextPtr ctxt, int nargs)
195
42
{
196
42
    if (ctxt == NULL)
197
0
        return;
198
42
    if (nargs != 0) {
199
14
        xmlXPathSetArityError(ctxt);
200
14
        return;
201
14
    }
202
203
28
    if ((ctxt->context) && (ctxt->context->doc) &&
204
28
        (ctxt->context->doc->URL))
205
28
  valuePush(ctxt, xmlXPathNewString(ctxt->context->doc->URL));
206
0
    else
207
0
  valuePush(ctxt, xmlXPathNewString(BAD_CAST ""));
208
28
}
209
210
/**
211
 * exsltSaxonLineNumberFunction:
212
 * @ctxt:  an XPath parser context
213
 * @nargs: number of arguments
214
 *
215
 * Implements the SAXON line-number() function
216
 *     integer saxon:line-number()
217
 *
218
 * This returns the line number of the context node in the source document
219
 * within the entity that contains it. There are no arguments. If line numbers
220
 * are not maintained for the current document, the function returns -1. (To
221
 * ensure that line numbers are maintained, use the -l option on the command
222
 * line)
223
 *
224
 * The extension has been extended to have the following form:
225
 *     integer saxon:line-number([node-set-1])
226
 * If a node-set is given, this extension will return the line number of the
227
 * node in the argument node-set that is first in document order.
228
 */
229
static void
230
9.19k
exsltSaxonLineNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
231
9.19k
    xmlNodePtr cur = NULL;
232
9.19k
    xmlXPathObjectPtr obj = NULL;
233
9.19k
    long lineNo = -1;
234
235
9.19k
    if (nargs == 0) {
236
8.59k
  cur = ctxt->context->node;
237
8.59k
    } else if (nargs == 1) {
238
551
  xmlNodeSetPtr nodelist;
239
551
  int i;
240
241
551
  if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_NODESET)) {
242
56
      xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
243
56
    "saxon:line-number() : invalid arg expecting a node-set\n");
244
56
      ctxt->error = XPATH_INVALID_TYPE;
245
56
      return;
246
56
  }
247
248
495
  obj = valuePop(ctxt);
249
495
  nodelist = obj->nodesetval;
250
495
  if ((nodelist != NULL) && (nodelist->nodeNr > 0)) {
251
155
            cur = nodelist->nodeTab[0];
252
2.89k
            for (i = 1;i < nodelist->nodeNr;i++) {
253
2.73k
                int ret = xmlXPathCmpNodes(cur, nodelist->nodeTab[i]);
254
2.73k
                if (ret == -1)
255
17
                    cur = nodelist->nodeTab[i];
256
2.73k
            }
257
155
        }
258
495
    } else {
259
54
  xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
260
54
    "saxon:line-number() : invalid number of args %d\n",
261
54
    nargs);
262
54
  ctxt->error = XPATH_INVALID_ARITY;
263
54
  return;
264
54
    }
265
266
9.08k
    if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL)) {
267
        /*
268
        * The XPath module sets the owner element of a ns-node on
269
        * the ns->next field.
270
        */
271
8
        cur = (xmlNodePtr) ((xmlNsPtr) cur)->next;
272
8
        if (cur == NULL || cur->type != XML_ELEMENT_NODE) {
273
0
            xsltGenericError(xsltGenericErrorContext,
274
0
                "Internal error in exsltSaxonLineNumberFunction: "
275
0
                "Cannot retrieve the doc of a namespace node.\n");
276
0
            cur = NULL;
277
0
        }
278
8
    }
279
280
9.08k
    if (cur != NULL)
281
8.74k
        lineNo = xmlGetLineNo(cur);
282
283
9.08k
    valuePush(ctxt, xmlXPathNewFloat(lineNo));
284
285
9.08k
    xmlXPathFreeObject(obj);
286
9.08k
}
287
288
/**
289
 * exsltSaxonRegister:
290
 *
291
 * Registers the SAXON extension module
292
 */
293
void
294
2.58k
exsltSaxonRegister (void) {
295
2.58k
     xsltRegisterExtModule (SAXON_NAMESPACE,
296
2.58k
          exsltSaxonInit,
297
2.58k
          exsltSaxonShutdown);
298
2.58k
     xsltRegisterExtModuleFunction((const xmlChar *) "expression",
299
2.58k
           SAXON_NAMESPACE,
300
2.58k
           exsltSaxonExpressionFunction);
301
2.58k
     xsltRegisterExtModuleFunction((const xmlChar *) "eval",
302
2.58k
           SAXON_NAMESPACE,
303
2.58k
           exsltSaxonEvalFunction);
304
2.58k
     xsltRegisterExtModuleFunction((const xmlChar *) "evaluate",
305
2.58k
           SAXON_NAMESPACE,
306
2.58k
           exsltSaxonEvaluateFunction);
307
2.58k
    xsltRegisterExtModuleFunction ((const xmlChar *) "line-number",
308
2.58k
           SAXON_NAMESPACE,
309
2.58k
           exsltSaxonLineNumberFunction);
310
2.58k
    xsltRegisterExtModuleFunction ((const xmlChar *) "systemId",
311
2.58k
           SAXON_NAMESPACE,
312
2.58k
           exsltSaxonSystemIdFunction);
313
2.58k
}