Coverage Report

Created: 2026-09-14 06:09

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
12.0k
exsltDynEvaluateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
48
12.0k
  xmlChar *str = NULL;
49
12.0k
  xmlXPathObjectPtr ret = NULL;
50
51
12.0k
  if (ctxt == NULL)
52
0
    return;
53
12.0k
  if (nargs != 1) {
54
1
    xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
55
1
        xsltGenericError(xsltGenericErrorContext,
56
1
      "dyn:evalute() : invalid number of args %d\n", nargs);
57
1
    ctxt->error = XPATH_INVALID_ARITY;
58
1
    return;
59
1
  }
60
12.0k
  str = xmlXPathPopString(ctxt);
61
  /* return an empty node-set if an empty string is passed in */
62
12.0k
  if (!str||!xmlStrlen(str)) {
63
1.06k
    if (str) xmlFree(str);
64
1.06k
    valuePush(ctxt,xmlXPathNewNodeSet(NULL));
65
1.06k
    return;
66
1.06k
  }
67
10.9k
#if LIBXML_VERSION >= 20911
68
        /*
69
         * Recursive evaluation can grow the call stack quickly.
70
         */
71
10.9k
        ctxt->context->depth += 5;
72
10.9k
#endif
73
10.9k
  ret = xmlXPathEval(str,ctxt->context);
74
10.9k
#if LIBXML_VERSION >= 20911
75
10.9k
        ctxt->context->depth -= 5;
76
10.9k
#endif
77
10.9k
  if (ret)
78
3.04k
    valuePush(ctxt,ret);
79
7.93k
  else {
80
7.93k
    xsltGenericError(xsltGenericErrorContext,
81
7.93k
      "dyn:evaluate() : unable to evaluate expression '%s'\n",str);
82
7.93k
    valuePush(ctxt,xmlXPathNewNodeSet(NULL));
83
7.93k
  }
84
10.9k
  xmlFree(str);
85
10.9k
  return;
86
12.0k
}
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
521k
{
101
521k
    xmlChar *str = NULL;
102
521k
    xmlNodeSetPtr nodeset = NULL;
103
521k
    xsltTransformContextPtr tctxt;
104
521k
    xmlXPathCompExprPtr comp = NULL;
105
521k
    xmlXPathObjectPtr ret = NULL;
106
521k
    xmlDocPtr oldDoc, container = NULL;
107
521k
    xmlNodePtr oldNode;
108
521k
    int oldContextSize;
109
521k
    int oldProximityPosition;
110
521k
    int i, j;
111
112
113
521k
    if (nargs != 2) {
114
4.37k
        xmlXPathSetArityError(ctxt);
115
4.37k
        return;
116
4.37k
    }
117
517k
    str = xmlXPathPopString(ctxt);
118
517k
    if (xmlXPathCheckError(ctxt))
119
222
        goto cleanup;
120
121
517k
    nodeset = xmlXPathPopNodeSet(ctxt);
122
517k
    if (xmlXPathCheckError(ctxt))
123
770
        goto cleanup;
124
125
516k
    ret = xmlXPathNewNodeSet(NULL);
126
516k
    if (ret == NULL) {
127
42
        xsltGenericError(xsltGenericErrorContext,
128
42
                         "exsltDynMapFunction: ret == NULL\n");
129
42
        goto cleanup;
130
42
    }
131
132
516k
    tctxt = xsltXPathGetTransformContext(ctxt);
133
516k
    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
516k
    if (str == NULL || !xmlStrlen(str) ||
140
424k
        !(comp = xmlXPathCtxtCompile(tctxt->xpathCtxt, str)))
141
348k
        goto cleanup;
142
143
168k
    oldDoc = ctxt->context->doc;
144
168k
    oldNode = ctxt->context->node;
145
168k
    oldContextSize = ctxt->context->contextSize;
146
168k
    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
168k
    container = xsltCreateRVT(tctxt);
153
168k
    if (container == NULL) {
154
24
  xsltTransformError(tctxt, NULL, NULL,
155
24
        "dyn:map : internal error container == NULL\n");
156
24
  goto cleanup;
157
24
    }
158
168k
    xsltRegisterLocalRVT(tctxt, container);
159
168k
    if (nodeset && nodeset->nodeNr > 0) {
160
167k
        xmlXPathNodeSetSort(nodeset);
161
167k
        ctxt->context->contextSize = nodeset->nodeNr;
162
167k
        ctxt->context->proximityPosition = 0;
163
2.63M
        for (i = 0; i < nodeset->nodeNr; i++) {
164
2.46M
            xmlXPathObjectPtr subResult = NULL;
165
2.46M
            xmlNodePtr cur = nodeset->nodeTab[i];
166
167
2.46M
            ctxt->context->proximityPosition++;
168
2.46M
            ctxt->context->node = cur;
169
170
2.46M
            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
19.7k
                cur = (xmlNodePtr) ((xmlNsPtr) cur)->next;
176
19.7k
                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
19.7k
                ctxt->context->doc = cur->doc;
183
2.44M
            } else {
184
2.44M
                ctxt->context->doc = cur->doc;
185
2.44M
            }
186
187
2.46M
            subResult = xmlXPathCompiledEval(comp, ctxt->context);
188
2.46M
            if (subResult != NULL) {
189
1.62M
                switch (subResult->type) {
190
1.12M
                    case XPATH_NODESET:
191
1.12M
                        if (subResult->nodesetval != NULL)
192
14.3M
                            for (j = 0; j < subResult->nodesetval->nodeNr;
193
13.2M
                                 j++)
194
13.2M
                                xmlXPathNodeSetAdd(ret->nodesetval,
195
13.2M
                                                   subResult->nodesetval->
196
13.2M
                                                   nodeTab[j]);
197
1.12M
                        break;
198
251k
                    case XPATH_BOOLEAN:
199
251k
                        if (container != NULL) {
200
251k
                            xmlNodePtr newChildNode =
201
251k
                                xmlNewTextChild((xmlNodePtr) container, NULL,
202
251k
                                                BAD_CAST "boolean",
203
251k
                                                BAD_CAST (subResult->
204
251k
                                                boolval ? "true" : ""));
205
251k
                            if (newChildNode != NULL) {
206
250k
                                newChildNode->ns =
207
250k
                                    xmlNewNs(newChildNode,
208
250k
                                             BAD_CAST
209
250k
                                             "http://exslt.org/common",
210
250k
                                             BAD_CAST "exsl");
211
250k
                                xmlXPathNodeSetAddUnique(ret->nodesetval,
212
250k
                                                         newChildNode);
213
250k
                            }
214
251k
                        }
215
251k
                        break;
216
239k
                    case XPATH_NUMBER:
217
239k
                        if (container != NULL) {
218
239k
                            xmlChar *val =
219
239k
                                xmlXPathCastNumberToString(subResult->
220
239k
                                                           floatval);
221
239k
                            xmlNodePtr newChildNode =
222
239k
                                xmlNewTextChild((xmlNodePtr) container, NULL,
223
239k
                                                BAD_CAST "number", val);
224
239k
                            if (val != NULL)
225
239k
                                xmlFree(val);
226
227
239k
                            if (newChildNode != NULL) {
228
239k
                                newChildNode->ns =
229
239k
                                    xmlNewNs(newChildNode,
230
239k
                                             BAD_CAST
231
239k
                                             "http://exslt.org/common",
232
239k
                                             BAD_CAST "exsl");
233
239k
                                xmlXPathNodeSetAddUnique(ret->nodesetval,
234
239k
                                                         newChildNode);
235
239k
                            }
236
239k
                        }
237
239k
                        break;
238
2.88k
                    case XPATH_STRING:
239
2.88k
                        if (container != NULL) {
240
2.88k
                            xmlNodePtr newChildNode =
241
2.88k
                                xmlNewTextChild((xmlNodePtr) container, NULL,
242
2.88k
                                                BAD_CAST "string",
243
2.88k
                                                subResult->stringval);
244
2.88k
                            if (newChildNode != NULL) {
245
2.88k
                                newChildNode->ns =
246
2.88k
                                    xmlNewNs(newChildNode,
247
2.88k
                                             BAD_CAST
248
2.88k
                                             "http://exslt.org/common",
249
2.88k
                                             BAD_CAST "exsl");
250
2.88k
                                xmlXPathNodeSetAddUnique(ret->nodesetval,
251
2.88k
                                                         newChildNode);
252
2.88k
                            }
253
2.88k
                        }
254
2.88k
                        break;
255
0
        default:
256
0
                        break;
257
1.62M
                }
258
1.62M
                xmlXPathFreeObject(subResult);
259
1.62M
            }
260
2.46M
        }
261
167k
    }
262
168k
    ctxt->context->doc = oldDoc;
263
168k
    ctxt->context->node = oldNode;
264
168k
    ctxt->context->contextSize = oldContextSize;
265
168k
    ctxt->context->proximityPosition = oldProximityPosition;
266
267
268
517k
  cleanup:
269
    /* restore the xpath context */
270
517k
    if (comp != NULL)
271
168k
        xmlXPathFreeCompExpr(comp);
272
517k
    if (nodeset != NULL)
273
516k
        xmlXPathFreeNodeSet(nodeset);
274
517k
    if (str != NULL)
275
517k
        xmlFree(str);
276
517k
    valuePush(ctxt, ret);
277
517k
    return;
278
168k
}
279
280
281
/**
282
 * exsltDynRegister:
283
 *
284
 * Registers the EXSLT - Dynamic module
285
 */
286
287
void
288
4
exsltDynRegister (void) {
289
4
    xsltRegisterExtModuleFunction ((const xmlChar *) "evaluate",
290
4
           EXSLT_DYNAMIC_NAMESPACE,
291
4
           exsltDynEvaluateFunction);
292
4
  xsltRegisterExtModuleFunction ((const xmlChar *) "map",
293
4
           EXSLT_DYNAMIC_NAMESPACE,
294
4
           exsltDynMapFunction);
295
296
4
}