Coverage Report

Created: 2023-12-06 19:46

/src/libxslt/libexslt/dynamic.c
Line
Count
Source (jump to first uncovered line)
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
89.8k
exsltDynEvaluateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
48
89.8k
  xmlChar *str = NULL;
49
89.8k
  xmlXPathObjectPtr ret = NULL;
50
51
89.8k
  if (ctxt == NULL)
52
0
    return;
53
89.8k
  if (nargs != 1) {
54
174
    xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
55
174
        xsltGenericError(xsltGenericErrorContext,
56
174
      "dyn:evalute() : invalid number of args %d\n", nargs);
57
174
    ctxt->error = XPATH_INVALID_ARITY;
58
174
    return;
59
174
  }
60
89.6k
  str = xmlXPathPopString(ctxt);
61
  /* return an empty node-set if an empty string is passed in */
62
89.6k
  if (!str||!xmlStrlen(str)) {
63
3.42k
    if (str) xmlFree(str);
64
3.42k
    valuePush(ctxt,xmlXPathNewNodeSet(NULL));
65
3.42k
    return;
66
3.42k
  }
67
86.2k
  ret = xmlXPathEval(str,ctxt->context);
68
86.2k
  if (ret)
69
20.2k
    valuePush(ctxt,ret);
70
65.9k
  else {
71
65.9k
    xsltGenericError(xsltGenericErrorContext,
72
65.9k
      "dyn:evaluate() : unable to evaluate expression '%s'\n",str);
73
65.9k
    valuePush(ctxt,xmlXPathNewNodeSet(NULL));
74
65.9k
  }
75
86.2k
  xmlFree(str);
76
86.2k
  return;
77
89.6k
}
78
79
/**
80
 * exsltDynMapFunction:
81
 * @ctxt:  an XPath parser context
82
 * @nargs:  the number of arguments
83
 *
84
 * Evaluates the string as an XPath expression and returns the result
85
 * value, which may be a boolean, number, string, node set, result tree
86
 * fragment or external object.
87
 */
88
89
static void
90
exsltDynMapFunction(xmlXPathParserContextPtr ctxt, int nargs)
91
7.27M
{
92
7.27M
    xmlChar *str = NULL;
93
7.27M
    xmlNodeSetPtr nodeset = NULL;
94
7.27M
    xsltTransformContextPtr tctxt;
95
7.27M
    xmlXPathCompExprPtr comp = NULL;
96
7.27M
    xmlXPathObjectPtr ret = NULL;
97
7.27M
    xmlDocPtr oldDoc, container = NULL;
98
7.27M
    xmlNodePtr oldNode;
99
7.27M
    int oldContextSize;
100
7.27M
    int oldProximityPosition;
101
7.27M
    int i, j;
102
103
104
7.27M
    if (nargs != 2) {
105
33.0k
        xmlXPathSetArityError(ctxt);
106
33.0k
        return;
107
33.0k
    }
108
7.24M
    str = xmlXPathPopString(ctxt);
109
7.24M
    if (xmlXPathCheckError(ctxt))
110
0
        goto cleanup;
111
112
7.24M
    nodeset = xmlXPathPopNodeSet(ctxt);
113
7.24M
    if (xmlXPathCheckError(ctxt))
114
4.72k
        goto cleanup;
115
116
7.23M
    ret = xmlXPathNewNodeSet(NULL);
117
7.23M
    if (ret == NULL) {
118
0
        xsltGenericError(xsltGenericErrorContext,
119
0
                         "exsltDynMapFunction: ret == NULL\n");
120
0
        goto cleanup;
121
0
    }
122
123
7.23M
    tctxt = xsltXPathGetTransformContext(ctxt);
124
7.23M
    if (tctxt == NULL) {
125
0
  xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
126
0
        "dyn:map : internal error tctxt == NULL\n");
127
0
  goto cleanup;
128
0
    }
129
130
7.23M
    if (str == NULL || !xmlStrlen(str) ||
131
7.23M
        !(comp = xmlXPathCtxtCompile(tctxt->xpathCtxt, str)))
132
5.76M
        goto cleanup;
133
134
1.46M
    oldDoc = ctxt->context->doc;
135
1.46M
    oldNode = ctxt->context->node;
136
1.46M
    oldContextSize = ctxt->context->contextSize;
137
1.46M
    oldProximityPosition = ctxt->context->proximityPosition;
138
139
        /**
140
   * since we really don't know we're going to be adding node(s)
141
   * down the road we create the RVT regardless
142
   */
143
1.46M
    container = xsltCreateRVT(tctxt);
144
1.46M
    if (container == NULL) {
145
0
  xsltTransformError(tctxt, NULL, NULL,
146
0
        "dyn:map : internal error container == NULL\n");
147
0
  goto cleanup;
148
0
    }
149
1.46M
    xsltRegisterLocalRVT(tctxt, container);
150
1.46M
    if (nodeset && nodeset->nodeNr > 0) {
151
915k
        xmlXPathNodeSetSort(nodeset);
152
915k
        ctxt->context->contextSize = nodeset->nodeNr;
153
915k
        ctxt->context->proximityPosition = 0;
154
14.6M
        for (i = 0; i < nodeset->nodeNr; i++) {
155
13.7M
            xmlXPathObjectPtr subResult = NULL;
156
13.7M
            xmlNodePtr cur = nodeset->nodeTab[i];
157
158
13.7M
            ctxt->context->proximityPosition++;
159
13.7M
            ctxt->context->node = cur;
160
161
13.7M
            if (cur->type == XML_NAMESPACE_DECL) {
162
                /*
163
                * The XPath module sets the owner element of a ns-node on
164
                * the ns->next field.
165
                */
166
116k
                cur = (xmlNodePtr) ((xmlNsPtr) cur)->next;
167
116k
                if ((cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
168
0
                    xsltGenericError(xsltGenericErrorContext,
169
0
                        "Internal error in exsltDynMapFunction: "
170
0
                        "Cannot retrieve the doc of a namespace node.\n");
171
0
                    continue;
172
0
                }
173
116k
                ctxt->context->doc = cur->doc;
174
13.6M
            } else {
175
13.6M
                ctxt->context->doc = cur->doc;
176
13.6M
            }
177
178
13.7M
            subResult = xmlXPathCompiledEval(comp, ctxt->context);
179
13.7M
            if (subResult != NULL) {
180
11.4M
                switch (subResult->type) {
181
6.39M
                    case XPATH_NODESET:
182
6.39M
                        if (subResult->nodesetval != NULL)
183
23.1M
                            for (j = 0; j < subResult->nodesetval->nodeNr;
184
16.8M
                                 j++)
185
16.8M
                                xmlXPathNodeSetAdd(ret->nodesetval,
186
16.8M
                                                   subResult->nodesetval->
187
16.8M
                                                   nodeTab[j]);
188
6.39M
                        break;
189
3.32M
                    case XPATH_BOOLEAN:
190
3.32M
                        if (container != NULL) {
191
3.32M
                            xmlNodePtr newChildNode =
192
3.32M
                                xmlNewTextChild((xmlNodePtr) container, NULL,
193
3.32M
                                                BAD_CAST "boolean",
194
3.32M
                                                BAD_CAST (subResult->
195
3.32M
                                                boolval ? "true" : ""));
196
3.32M
                            if (newChildNode != NULL) {
197
3.32M
                                newChildNode->ns =
198
3.32M
                                    xmlNewNs(newChildNode,
199
3.32M
                                             BAD_CAST
200
3.32M
                                             "http://exslt.org/common",
201
3.32M
                                             BAD_CAST "exsl");
202
3.32M
                                xmlXPathNodeSetAddUnique(ret->nodesetval,
203
3.32M
                                                         newChildNode);
204
3.32M
                            }
205
3.32M
                        }
206
3.32M
                        break;
207
1.67M
                    case XPATH_NUMBER:
208
1.67M
                        if (container != NULL) {
209
1.67M
                            xmlChar *val =
210
1.67M
                                xmlXPathCastNumberToString(subResult->
211
1.67M
                                                           floatval);
212
1.67M
                            xmlNodePtr newChildNode =
213
1.67M
                                xmlNewTextChild((xmlNodePtr) container, NULL,
214
1.67M
                                                BAD_CAST "number", val);
215
1.67M
                            if (val != NULL)
216
1.67M
                                xmlFree(val);
217
218
1.67M
                            if (newChildNode != NULL) {
219
1.67M
                                newChildNode->ns =
220
1.67M
                                    xmlNewNs(newChildNode,
221
1.67M
                                             BAD_CAST
222
1.67M
                                             "http://exslt.org/common",
223
1.67M
                                             BAD_CAST "exsl");
224
1.67M
                                xmlXPathNodeSetAddUnique(ret->nodesetval,
225
1.67M
                                                         newChildNode);
226
1.67M
                            }
227
1.67M
                        }
228
1.67M
                        break;
229
29.6k
                    case XPATH_STRING:
230
29.6k
                        if (container != NULL) {
231
29.6k
                            xmlNodePtr newChildNode =
232
29.6k
                                xmlNewTextChild((xmlNodePtr) container, NULL,
233
29.6k
                                                BAD_CAST "string",
234
29.6k
                                                subResult->stringval);
235
29.6k
                            if (newChildNode != NULL) {
236
29.6k
                                newChildNode->ns =
237
29.6k
                                    xmlNewNs(newChildNode,
238
29.6k
                                             BAD_CAST
239
29.6k
                                             "http://exslt.org/common",
240
29.6k
                                             BAD_CAST "exsl");
241
29.6k
                                xmlXPathNodeSetAddUnique(ret->nodesetval,
242
29.6k
                                                         newChildNode);
243
29.6k
                            }
244
29.6k
                        }
245
29.6k
                        break;
246
0
        default:
247
0
                        break;
248
11.4M
                }
249
11.4M
                xmlXPathFreeObject(subResult);
250
11.4M
            }
251
13.7M
        }
252
915k
    }
253
1.46M
    ctxt->context->doc = oldDoc;
254
1.46M
    ctxt->context->node = oldNode;
255
1.46M
    ctxt->context->contextSize = oldContextSize;
256
1.46M
    ctxt->context->proximityPosition = oldProximityPosition;
257
258
259
7.24M
  cleanup:
260
    /* restore the xpath context */
261
7.24M
    if (comp != NULL)
262
1.46M
        xmlXPathFreeCompExpr(comp);
263
7.24M
    if (nodeset != NULL)
264
5.65M
        xmlXPathFreeNodeSet(nodeset);
265
7.24M
    if (str != NULL)
266
7.24M
        xmlFree(str);
267
7.24M
    valuePush(ctxt, ret);
268
7.24M
    return;
269
1.46M
}
270
271
272
/**
273
 * exsltDynRegister:
274
 *
275
 * Registers the EXSLT - Dynamic module
276
 */
277
278
void
279
3.71k
exsltDynRegister (void) {
280
3.71k
    xsltRegisterExtModuleFunction ((const xmlChar *) "evaluate",
281
3.71k
           EXSLT_DYNAMIC_NAMESPACE,
282
3.71k
           exsltDynEvaluateFunction);
283
3.71k
  xsltRegisterExtModuleFunction ((const xmlChar *) "map",
284
3.71k
           EXSLT_DYNAMIC_NAMESPACE,
285
3.71k
           exsltDynMapFunction);
286
287
3.71k
}