Coverage Report

Created: 2026-03-21 06:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libxslt/libexslt/dynamic.c
Line
Count
Source
1
/*
2
 * dynamic.c: Implementation of the EXSLT -- Dynamic module
3
 *
4
 * References:
5
 *   http://www.exslt.org/dyn/dyn.html
6
 *
7
 * See Copyright for the status of this software.
8
 *
9
 * Authors:
10
 *   Mark Vakoc <mark_vakoc@jdedwards.com>
11
 *   Thomas Broyer <tbroyer@ltgt.net>
12
 *
13
 * TODO:
14
 * elements:
15
 * functions:
16
 *    min
17
 *    max
18
 *    sum
19
 *    map
20
 *    closure
21
 */
22
23
#define IN_LIBEXSLT
24
#include "libexslt/libexslt.h"
25
26
#include <libxml/tree.h>
27
#include <libxml/xpath.h>
28
#include <libxml/xpathInternals.h>
29
30
#include <libxslt/xsltutils.h>
31
#include <libxslt/xsltInternals.h>
32
#include <libxslt/extensions.h>
33
34
#include "exslt.h"
35
36
/**
37
 * exsltDynEvaluateFunction:
38
 * @ctxt:  an XPath parser context
39
 * @nargs:  the number of arguments
40
 *
41
 * Evaluates the string as an XPath expression and returns the result
42
 * value, which may be a boolean, number, string, node set, result tree
43
 * fragment or external object.
44
 */
45
46
static void
47
0
exsltDynEvaluateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
48
0
  xmlChar *str = NULL;
49
0
  xmlXPathObjectPtr ret = NULL;
50
51
0
  if (ctxt == NULL)
52
0
    return;
53
0
  if (nargs != 1) {
54
0
    xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
55
0
        xsltGenericError(xsltGenericErrorContext,
56
0
      "dyn:evalute() : invalid number of args %d\n", nargs);
57
0
    ctxt->error = XPATH_INVALID_ARITY;
58
0
    return;
59
0
  }
60
0
  str = xmlXPathPopString(ctxt);
61
  /* return an empty node-set if an empty string is passed in */
62
0
  if (!str||!xmlStrlen(str)) {
63
0
    if (str) xmlFree(str);
64
0
    valuePush(ctxt,xmlXPathNewNodeSet(NULL));
65
0
    return;
66
0
  }
67
0
#if LIBXML_VERSION >= 20911
68
        /*
69
         * Recursive evaluation can grow the call stack quickly.
70
         */
71
0
        ctxt->context->depth += 5;
72
0
#endif
73
0
  ret = xmlXPathEval(str,ctxt->context);
74
0
#if LIBXML_VERSION >= 20911
75
0
        ctxt->context->depth -= 5;
76
0
#endif
77
0
  if (ret)
78
0
    valuePush(ctxt,ret);
79
0
  else {
80
0
    xsltGenericError(xsltGenericErrorContext,
81
0
      "dyn:evaluate() : unable to evaluate expression '%s'\n",str);
82
0
    valuePush(ctxt,xmlXPathNewNodeSet(NULL));
83
0
  }
84
0
  xmlFree(str);
85
0
  return;
86
0
}
87
88
/**
89
 * exsltDynMapFunction:
90
 * @ctxt:  an XPath parser context
91
 * @nargs:  the number of arguments
92
 *
93
 * Evaluates the string as an XPath expression and returns the result
94
 * value, which may be a boolean, number, string, node set, result tree
95
 * fragment or external object.
96
 */
97
98
static void
99
exsltDynMapFunction(xmlXPathParserContextPtr ctxt, int nargs)
100
10.5k
{
101
10.5k
    xmlChar *str = NULL;
102
10.5k
    xmlNodeSetPtr nodeset = NULL;
103
10.5k
    xsltTransformContextPtr tctxt;
104
10.5k
    xmlXPathCompExprPtr comp = NULL;
105
10.5k
    xmlXPathObjectPtr ret = NULL;
106
10.5k
    xmlDocPtr oldDoc, container = NULL;
107
10.5k
    xmlNodePtr oldNode;
108
10.5k
    int oldContextSize;
109
10.5k
    int oldProximityPosition;
110
10.5k
    int i, j;
111
112
113
10.5k
    if (nargs != 2) {
114
0
        xmlXPathSetArityError(ctxt);
115
0
        return;
116
0
    }
117
10.5k
    str = xmlXPathPopString(ctxt);
118
10.5k
    if (xmlXPathCheckError(ctxt))
119
0
        goto cleanup;
120
121
10.5k
    nodeset = xmlXPathPopNodeSet(ctxt);
122
10.5k
    if (xmlXPathCheckError(ctxt))
123
0
        goto cleanup;
124
125
10.5k
    ret = xmlXPathNewNodeSet(NULL);
126
10.5k
    if (ret == NULL) {
127
0
        xsltGenericError(xsltGenericErrorContext,
128
0
                         "exsltDynMapFunction: ret == NULL\n");
129
0
        goto cleanup;
130
0
    }
131
132
10.5k
    tctxt = xsltXPathGetTransformContext(ctxt);
133
10.5k
    if (tctxt == NULL) {
134
0
  xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
135
0
        "dyn:map : internal error tctxt == NULL\n");
136
0
  goto cleanup;
137
0
    }
138
139
10.5k
    if (str == NULL || !xmlStrlen(str) ||
140
8.95k
        !(comp = xmlXPathCtxtCompile(tctxt->xpathCtxt, str)))
141
8.77k
        goto cleanup;
142
143
1.82k
    oldDoc = ctxt->context->doc;
144
1.82k
    oldNode = ctxt->context->node;
145
1.82k
    oldContextSize = ctxt->context->contextSize;
146
1.82k
    oldProximityPosition = ctxt->context->proximityPosition;
147
148
        /**
149
   * since we really don't know we're going to be adding node(s)
150
   * down the road we create the RVT regardless
151
   */
152
1.82k
    container = xsltCreateRVT(tctxt);
153
1.82k
    if (container == NULL) {
154
0
  xsltTransformError(tctxt, NULL, NULL,
155
0
        "dyn:map : internal error container == NULL\n");
156
0
  goto cleanup;
157
0
    }
158
1.82k
    xsltRegisterLocalRVT(tctxt, container);
159
1.82k
    if (nodeset && nodeset->nodeNr > 0) {
160
1.82k
        xmlXPathNodeSetSort(nodeset);
161
1.82k
        ctxt->context->contextSize = nodeset->nodeNr;
162
1.82k
        ctxt->context->proximityPosition = 0;
163
44.2k
        for (i = 0; i < nodeset->nodeNr; i++) {
164
42.4k
            xmlXPathObjectPtr subResult = NULL;
165
42.4k
            xmlNodePtr cur = nodeset->nodeTab[i];
166
167
42.4k
            ctxt->context->proximityPosition++;
168
42.4k
            ctxt->context->node = cur;
169
170
42.4k
            if (cur->type == XML_NAMESPACE_DECL) {
171
                /*
172
                * The XPath module sets the owner element of a ns-node on
173
                * the ns->next field.
174
                */
175
0
                cur = (xmlNodePtr) ((xmlNsPtr) cur)->next;
176
0
                if ((cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
177
0
                    xsltGenericError(xsltGenericErrorContext,
178
0
                        "Internal error in exsltDynMapFunction: "
179
0
                        "Cannot retrieve the doc of a namespace node.\n");
180
0
                    continue;
181
0
                }
182
0
                ctxt->context->doc = cur->doc;
183
42.4k
            } else {
184
42.4k
                ctxt->context->doc = cur->doc;
185
42.4k
            }
186
187
42.4k
            subResult = xmlXPathCompiledEval(comp, ctxt->context);
188
42.4k
            if (subResult != NULL) {
189
35.6k
                switch (subResult->type) {
190
28.8k
                    case XPATH_NODESET:
191
28.8k
                        if (subResult->nodesetval != NULL)
192
28.8k
                            for (j = 0; j < subResult->nodesetval->nodeNr;
193
28.8k
                                 j++)
194
0
                                xmlXPathNodeSetAdd(ret->nodesetval,
195
0
                                                   subResult->nodesetval->
196
0
                                                   nodeTab[j]);
197
28.8k
                        break;
198
2.78k
                    case XPATH_BOOLEAN:
199
2.78k
                        if (container != NULL) {
200
2.78k
                            xmlNodePtr newChildNode =
201
2.78k
                                xmlNewTextChild((xmlNodePtr) container, NULL,
202
2.78k
                                                BAD_CAST "boolean",
203
2.78k
                                                BAD_CAST (subResult->
204
2.78k
                                                boolval ? "true" : ""));
205
2.78k
                            if (newChildNode != NULL) {
206
2.78k
                                newChildNode->ns =
207
2.78k
                                    xmlNewNs(newChildNode,
208
2.78k
                                             BAD_CAST
209
2.78k
                                             "http://exslt.org/common",
210
2.78k
                                             BAD_CAST "exsl");
211
2.78k
                                xmlXPathNodeSetAddUnique(ret->nodesetval,
212
2.78k
                                                         newChildNode);
213
2.78k
                            }
214
2.78k
                        }
215
2.78k
                        break;
216
3.49k
                    case XPATH_NUMBER:
217
3.49k
                        if (container != NULL) {
218
3.49k
                            xmlChar *val =
219
3.49k
                                xmlXPathCastNumberToString(subResult->
220
3.49k
                                                           floatval);
221
3.49k
                            xmlNodePtr newChildNode =
222
3.49k
                                xmlNewTextChild((xmlNodePtr) container, NULL,
223
3.49k
                                                BAD_CAST "number", val);
224
3.49k
                            if (val != NULL)
225
3.49k
                                xmlFree(val);
226
227
3.49k
                            if (newChildNode != NULL) {
228
3.49k
                                newChildNode->ns =
229
3.49k
                                    xmlNewNs(newChildNode,
230
3.49k
                                             BAD_CAST
231
3.49k
                                             "http://exslt.org/common",
232
3.49k
                                             BAD_CAST "exsl");
233
3.49k
                                xmlXPathNodeSetAddUnique(ret->nodesetval,
234
3.49k
                                                         newChildNode);
235
3.49k
                            }
236
3.49k
                        }
237
3.49k
                        break;
238
537
                    case XPATH_STRING:
239
537
                        if (container != NULL) {
240
537
                            xmlNodePtr newChildNode =
241
537
                                xmlNewTextChild((xmlNodePtr) container, NULL,
242
537
                                                BAD_CAST "string",
243
537
                                                subResult->stringval);
244
537
                            if (newChildNode != NULL) {
245
537
                                newChildNode->ns =
246
537
                                    xmlNewNs(newChildNode,
247
537
                                             BAD_CAST
248
537
                                             "http://exslt.org/common",
249
537
                                             BAD_CAST "exsl");
250
537
                                xmlXPathNodeSetAddUnique(ret->nodesetval,
251
537
                                                         newChildNode);
252
537
                            }
253
537
                        }
254
537
                        break;
255
0
        default:
256
0
                        break;
257
35.6k
                }
258
35.6k
                xmlXPathFreeObject(subResult);
259
35.6k
            }
260
42.4k
        }
261
1.82k
    }
262
1.82k
    ctxt->context->doc = oldDoc;
263
1.82k
    ctxt->context->node = oldNode;
264
1.82k
    ctxt->context->contextSize = oldContextSize;
265
1.82k
    ctxt->context->proximityPosition = oldProximityPosition;
266
267
268
10.5k
  cleanup:
269
    /* restore the xpath context */
270
10.5k
    if (comp != NULL)
271
1.82k
        xmlXPathFreeCompExpr(comp);
272
10.5k
    if (nodeset != NULL)
273
10.5k
        xmlXPathFreeNodeSet(nodeset);
274
10.5k
    if (str != NULL)
275
10.5k
        xmlFree(str);
276
10.5k
    valuePush(ctxt, ret);
277
10.5k
    return;
278
1.82k
}
279
280
281
/**
282
 * exsltDynRegister:
283
 *
284
 * Registers the EXSLT - Dynamic module
285
 */
286
287
void
288
2
exsltDynRegister (void) {
289
2
    xsltRegisterExtModuleFunction ((const xmlChar *) "evaluate",
290
2
           EXSLT_DYNAMIC_NAMESPACE,
291
2
           exsltDynEvaluateFunction);
292
2
  xsltRegisterExtModuleFunction ((const xmlChar *) "map",
293
2
           EXSLT_DYNAMIC_NAMESPACE,
294
2
           exsltDynMapFunction);
295
296
2
}