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