Coverage Report

Created: 2026-05-30 06:43

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
15.9k
exsltDynEvaluateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
48
15.9k
  xmlChar *str = NULL;
49
15.9k
  xmlXPathObjectPtr ret = NULL;
50
51
15.9k
  if (ctxt == NULL)
52
0
    return;
53
15.9k
  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
15.9k
  str = xmlXPathPopString(ctxt);
61
  /* return an empty node-set if an empty string is passed in */
62
15.9k
  if (!str||!xmlStrlen(str)) {
63
754
    if (str) xmlFree(str);
64
754
    valuePush(ctxt,xmlXPathNewNodeSet(NULL));
65
754
    return;
66
754
  }
67
15.1k
#if LIBXML_VERSION >= 20911
68
        /*
69
         * Recursive evaluation can grow the call stack quickly.
70
         */
71
15.1k
        ctxt->context->depth += 5;
72
15.1k
#endif
73
15.1k
  ret = xmlXPathEval(str,ctxt->context);
74
15.1k
#if LIBXML_VERSION >= 20911
75
15.1k
        ctxt->context->depth -= 5;
76
15.1k
#endif
77
15.1k
  if (ret)
78
3.98k
    valuePush(ctxt,ret);
79
11.2k
  else {
80
11.2k
    xsltGenericError(xsltGenericErrorContext,
81
11.2k
      "dyn:evaluate() : unable to evaluate expression '%s'\n",str);
82
11.2k
    valuePush(ctxt,xmlXPathNewNodeSet(NULL));
83
11.2k
  }
84
15.1k
  xmlFree(str);
85
15.1k
  return;
86
15.9k
}
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
542k
{
101
542k
    xmlChar *str = NULL;
102
542k
    xmlNodeSetPtr nodeset = NULL;
103
542k
    xsltTransformContextPtr tctxt;
104
542k
    xmlXPathCompExprPtr comp = NULL;
105
542k
    xmlXPathObjectPtr ret = NULL;
106
542k
    xmlDocPtr oldDoc, container = NULL;
107
542k
    xmlNodePtr oldNode;
108
542k
    int oldContextSize;
109
542k
    int oldProximityPosition;
110
542k
    int i, j;
111
112
113
542k
    if (nargs != 2) {
114
2.94k
        xmlXPathSetArityError(ctxt);
115
2.94k
        return;
116
2.94k
    }
117
539k
    str = xmlXPathPopString(ctxt);
118
539k
    if (xmlXPathCheckError(ctxt))
119
174
        goto cleanup;
120
121
539k
    nodeset = xmlXPathPopNodeSet(ctxt);
122
539k
    if (xmlXPathCheckError(ctxt))
123
1.08k
        goto cleanup;
124
125
538k
    ret = xmlXPathNewNodeSet(NULL);
126
538k
    if (ret == NULL) {
127
31
        xsltGenericError(xsltGenericErrorContext,
128
31
                         "exsltDynMapFunction: ret == NULL\n");
129
31
        goto cleanup;
130
31
    }
131
132
538k
    tctxt = xsltXPathGetTransformContext(ctxt);
133
538k
    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
538k
    if (str == NULL || !xmlStrlen(str) ||
140
440k
        !(comp = xmlXPathCtxtCompile(tctxt->xpathCtxt, str)))
141
368k
        goto cleanup;
142
143
169k
    oldDoc = ctxt->context->doc;
144
169k
    oldNode = ctxt->context->node;
145
169k
    oldContextSize = ctxt->context->contextSize;
146
169k
    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
169k
    container = xsltCreateRVT(tctxt);
153
169k
    if (container == NULL) {
154
31
  xsltTransformError(tctxt, NULL, NULL,
155
31
        "dyn:map : internal error container == NULL\n");
156
31
  goto cleanup;
157
31
    }
158
169k
    xsltRegisterLocalRVT(tctxt, container);
159
169k
    if (nodeset && nodeset->nodeNr > 0) {
160
169k
        xmlXPathNodeSetSort(nodeset);
161
169k
        ctxt->context->contextSize = nodeset->nodeNr;
162
169k
        ctxt->context->proximityPosition = 0;
163
2.66M
        for (i = 0; i < nodeset->nodeNr; i++) {
164
2.49M
            xmlXPathObjectPtr subResult = NULL;
165
2.49M
            xmlNodePtr cur = nodeset->nodeTab[i];
166
167
2.49M
            ctxt->context->proximityPosition++;
168
2.49M
            ctxt->context->node = cur;
169
170
2.49M
            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
18.9k
                cur = (xmlNodePtr) ((xmlNsPtr) cur)->next;
176
18.9k
                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
18.9k
                ctxt->context->doc = cur->doc;
183
2.47M
            } else {
184
2.47M
                ctxt->context->doc = cur->doc;
185
2.47M
            }
186
187
2.49M
            subResult = xmlXPathCompiledEval(comp, ctxt->context);
188
2.49M
            if (subResult != NULL) {
189
1.68M
                switch (subResult->type) {
190
1.15M
                    case XPATH_NODESET:
191
1.15M
                        if (subResult->nodesetval != NULL)
192
15.7M
                            for (j = 0; j < subResult->nodesetval->nodeNr;
193
14.6M
                                 j++)
194
14.6M
                                xmlXPathNodeSetAdd(ret->nodesetval,
195
14.6M
                                                   subResult->nodesetval->
196
14.6M
                                                   nodeTab[j]);
197
1.15M
                        break;
198
273k
                    case XPATH_BOOLEAN:
199
273k
                        if (container != NULL) {
200
273k
                            xmlNodePtr newChildNode =
201
273k
                                xmlNewTextChild((xmlNodePtr) container, NULL,
202
273k
                                                BAD_CAST "boolean",
203
273k
                                                BAD_CAST (subResult->
204
273k
                                                boolval ? "true" : ""));
205
273k
                            if (newChildNode != NULL) {
206
272k
                                newChildNode->ns =
207
272k
                                    xmlNewNs(newChildNode,
208
272k
                                             BAD_CAST
209
272k
                                             "http://exslt.org/common",
210
272k
                                             BAD_CAST "exsl");
211
272k
                                xmlXPathNodeSetAddUnique(ret->nodesetval,
212
272k
                                                         newChildNode);
213
272k
                            }
214
273k
                        }
215
273k
                        break;
216
253k
                    case XPATH_NUMBER:
217
253k
                        if (container != NULL) {
218
253k
                            xmlChar *val =
219
253k
                                xmlXPathCastNumberToString(subResult->
220
253k
                                                           floatval);
221
253k
                            xmlNodePtr newChildNode =
222
253k
                                xmlNewTextChild((xmlNodePtr) container, NULL,
223
253k
                                                BAD_CAST "number", val);
224
253k
                            if (val != NULL)
225
253k
                                xmlFree(val);
226
227
253k
                            if (newChildNode != NULL) {
228
253k
                                newChildNode->ns =
229
253k
                                    xmlNewNs(newChildNode,
230
253k
                                             BAD_CAST
231
253k
                                             "http://exslt.org/common",
232
253k
                                             BAD_CAST "exsl");
233
253k
                                xmlXPathNodeSetAddUnique(ret->nodesetval,
234
253k
                                                         newChildNode);
235
253k
                            }
236
253k
                        }
237
253k
                        break;
238
4.57k
                    case XPATH_STRING:
239
4.57k
                        if (container != NULL) {
240
4.57k
                            xmlNodePtr newChildNode =
241
4.57k
                                xmlNewTextChild((xmlNodePtr) container, NULL,
242
4.57k
                                                BAD_CAST "string",
243
4.57k
                                                subResult->stringval);
244
4.57k
                            if (newChildNode != NULL) {
245
4.57k
                                newChildNode->ns =
246
4.57k
                                    xmlNewNs(newChildNode,
247
4.57k
                                             BAD_CAST
248
4.57k
                                             "http://exslt.org/common",
249
4.57k
                                             BAD_CAST "exsl");
250
4.57k
                                xmlXPathNodeSetAddUnique(ret->nodesetval,
251
4.57k
                                                         newChildNode);
252
4.57k
                            }
253
4.57k
                        }
254
4.57k
                        break;
255
0
        default:
256
0
                        break;
257
1.68M
                }
258
1.68M
                xmlXPathFreeObject(subResult);
259
1.68M
            }
260
2.49M
        }
261
169k
    }
262
169k
    ctxt->context->doc = oldDoc;
263
169k
    ctxt->context->node = oldNode;
264
169k
    ctxt->context->contextSize = oldContextSize;
265
169k
    ctxt->context->proximityPosition = oldProximityPosition;
266
267
268
539k
  cleanup:
269
    /* restore the xpath context */
270
539k
    if (comp != NULL)
271
169k
        xmlXPathFreeCompExpr(comp);
272
539k
    if (nodeset != NULL)
273
538k
        xmlXPathFreeNodeSet(nodeset);
274
539k
    if (str != NULL)
275
539k
        xmlFree(str);
276
539k
    valuePush(ctxt, ret);
277
539k
    return;
278
169k
}
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
}