blob: 1aa2f1ab5047c3665e5f3951a85a99b84b95fff5 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer
Elliott Hughes7fbecab2019-01-10 16:42:03 -08005 *
Owen Taylor3473f882001-02-23 17:55:21 +00006 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 * http://www.w3.org/TR/xpath
10 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011 * See Copyright for the status of this software
Owen Taylor3473f882001-02-23 17:55:21 +000012 *
Daniel Veillardc5d64342001-06-24 12:13:24 +000013 * Author: daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000014 *
Owen Taylor3473f882001-02-23 17:55:21 +000015 */
16
Stéphane Michaut454e3972017-08-28 14:30:43 +020017/* To avoid EBCDIC trouble when parsing on zOS */
18#if defined(__MVS__)
19#pragma convert("ISO8859-1")
20#endif
21
Daniel Veillard34ce8be2002-03-18 19:37:11 +000022#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000023#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000024
Nick Wellnhofera58331a2017-05-29 21:02:21 +020025#include <limits.h>
Owen Taylor3473f882001-02-23 17:55:21 +000026#include <string.h>
Nick Wellnhoferd422b952017-10-09 13:37:42 +020027#include <stddef.h>
Owen Taylor3473f882001-02-23 17:55:21 +000028
29#ifdef HAVE_SYS_TYPES_H
30#include <sys/types.h>
31#endif
32#ifdef HAVE_MATH_H
33#include <math.h>
34#endif
35#ifdef HAVE_FLOAT_H
36#include <float.h>
37#endif
Owen Taylor3473f882001-02-23 17:55:21 +000038#ifdef HAVE_CTYPE_H
39#include <ctype.h>
40#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000041#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000042#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000043#endif
Owen Taylor3473f882001-02-23 17:55:21 +000044
45#include <libxml/xmlmemory.h>
46#include <libxml/tree.h>
47#include <libxml/valid.h>
48#include <libxml/xpath.h>
49#include <libxml/xpathInternals.h>
50#include <libxml/parserInternals.h>
51#include <libxml/hash.h>
52#ifdef LIBXML_XPTR_ENABLED
53#include <libxml/xpointer.h>
54#endif
55#ifdef LIBXML_DEBUG_ENABLED
56#include <libxml/debugXML.h>
57#endif
58#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000059#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000060#include <libxml/globals.h>
Daniel Veillard56de87e2005-02-16 00:22:29 +000061#ifdef LIBXML_PATTERN_ENABLED
62#include <libxml/pattern.h>
63#endif
64
Daniel Veillardade10f22012-07-12 09:43:27 +080065#include "buf.h"
66
Daniel Veillard56de87e2005-02-16 00:22:29 +000067#ifdef LIBXML_PATTERN_ENABLED
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000068#define XPATH_STREAMING
Daniel Veillard56de87e2005-02-16 00:22:29 +000069#endif
Owen Taylor3473f882001-02-23 17:55:21 +000070
Daniel Veillard45490ae2008-07-29 09:13:19 +000071#define TODO \
Daniel Veillardd96f6d32003-10-07 21:25:12 +000072 xmlGenericError(xmlGenericErrorContext, \
73 "Unimplemented block at %s:%d\n", \
74 __FILE__, __LINE__);
75
Vojtech Fried3e031b72012-08-24 16:52:44 +080076/**
77 * WITH_TIM_SORT:
78 *
79 * Use the Timsort algorithm provided in timsort.h to sort
80 * nodeset as this is a great improvement over the old Shell sort
81 * used in xmlXPathNodeSetSort()
82 */
83#define WITH_TIM_SORT
84
William M. Brackd1757ab2004-10-02 22:07:48 +000085/*
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000086* XP_OPTIMIZED_NON_ELEM_COMPARISON:
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +000087* If defined, this will use xmlXPathCmpNodesExt() instead of
88* xmlXPathCmpNodes(). The new function is optimized comparison of
89* non-element nodes; actually it will speed up comparison only if
90* xmlXPathOrderDocElems() was called in order to index the elements of
91* a tree in document order; Libxslt does such an indexing, thus it will
92* benefit from this optimization.
93*/
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000094#define XP_OPTIMIZED_NON_ELEM_COMPARISON
95
96/*
97* XP_OPTIMIZED_FILTER_FIRST:
98* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
99* in a way, that it stop evaluation at the first node.
Daniel Veillard45490ae2008-07-29 09:13:19 +0000100*/
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000101#define XP_OPTIMIZED_FILTER_FIRST
102
Kasimier T. Buchcik97258712006-01-05 12:30:43 +0000103/*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000104* XP_DEBUG_OBJ_USAGE:
105* Internal flag to enable tracking of how much XPath objects have been
106* created.
107*/
108/* #define XP_DEBUG_OBJ_USAGE */
109
110/*
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800111 * XPATH_MAX_STEPS:
112 * when compiling an XPath expression we arbitrary limit the maximum
113 * number of step operation in the compiled expression. 1000000 is
114 * an insanely large value which should never be reached under normal
115 * circumstances
116 */
117#define XPATH_MAX_STEPS 1000000
118
119/*
120 * XPATH_MAX_STACK_DEPTH:
121 * when evaluating an XPath expression we arbitrary limit the maximum
122 * number of object allowed to be pushed on the stack. 1000000 is
123 * an insanely large value which should never be reached under normal
124 * circumstances
125 */
126#define XPATH_MAX_STACK_DEPTH 1000000
127
128/*
129 * XPATH_MAX_NODESET_LENGTH:
130 * when evaluating an XPath expression nodesets are created and we
131 * arbitrary limit the maximum length of those node set. 10000000 is
132 * an insanely large value which should never be reached under normal
133 * circumstances, one would first need to construct an in memory tree
134 * with more than 10 millions nodes.
135 */
136#define XPATH_MAX_NODESET_LENGTH 10000000
137
138/*
Haibo Huangf0a546b2020-09-01 20:28:19 -0700139 * XPATH_MAX_RECRUSION_DEPTH:
140 * Maximum amount of nested functions calls when parsing or evaluating
141 * expressions
142 */
143#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
144#define XPATH_MAX_RECURSION_DEPTH 500
145#else
146#define XPATH_MAX_RECURSION_DEPTH 5000
147#endif
148
149/*
William M. Brackd1757ab2004-10-02 22:07:48 +0000150 * TODO:
151 * There are a few spots where some tests are done which depend upon ascii
152 * data. These should be enhanced for full UTF8 support (see particularly
153 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
154 */
Kasimier T. Buchcik97258712006-01-05 12:30:43 +0000155
Denis Pauke28c8a12013-08-03 14:22:54 +0300156#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
157/**
158 * xmlXPathCmpNodesExt:
159 * @node1: the first node
160 * @node2: the second node
161 *
162 * Compare two nodes w.r.t document order.
163 * This one is optimized for handling of non-element nodes.
164 *
165 * Returns -2 in case of error 1 if first point < second point, 0 if
166 * it's the same node, -1 otherwise
167 */
168static int
169xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
170 int depth1, depth2;
171 int misc = 0, precedence1 = 0, precedence2 = 0;
172 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
173 xmlNodePtr cur, root;
Nick Wellnhoferd422b952017-10-09 13:37:42 +0200174 ptrdiff_t l1, l2;
Denis Pauke28c8a12013-08-03 14:22:54 +0300175
176 if ((node1 == NULL) || (node2 == NULL))
177 return(-2);
178
179 if (node1 == node2)
180 return(0);
181
182 /*
183 * a couple of optimizations which will avoid computations in most cases
184 */
185 switch (node1->type) {
186 case XML_ELEMENT_NODE:
187 if (node2->type == XML_ELEMENT_NODE) {
Nick Wellnhoferd422b952017-10-09 13:37:42 +0200188 if ((0 > (ptrdiff_t) node1->content) &&
189 (0 > (ptrdiff_t) node2->content) &&
Denis Pauke28c8a12013-08-03 14:22:54 +0300190 (node1->doc == node2->doc))
191 {
Nick Wellnhoferd422b952017-10-09 13:37:42 +0200192 l1 = -((ptrdiff_t) node1->content);
193 l2 = -((ptrdiff_t) node2->content);
Denis Pauke28c8a12013-08-03 14:22:54 +0300194 if (l1 < l2)
195 return(1);
196 if (l1 > l2)
197 return(-1);
198 } else
199 goto turtle_comparison;
200 }
201 break;
202 case XML_ATTRIBUTE_NODE:
203 precedence1 = 1; /* element is owner */
204 miscNode1 = node1;
205 node1 = node1->parent;
206 misc = 1;
207 break;
208 case XML_TEXT_NODE:
209 case XML_CDATA_SECTION_NODE:
210 case XML_COMMENT_NODE:
211 case XML_PI_NODE: {
212 miscNode1 = node1;
213 /*
214 * Find nearest element node.
215 */
216 if (node1->prev != NULL) {
217 do {
218 node1 = node1->prev;
219 if (node1->type == XML_ELEMENT_NODE) {
220 precedence1 = 3; /* element in prev-sibl axis */
221 break;
222 }
223 if (node1->prev == NULL) {
224 precedence1 = 2; /* element is parent */
225 /*
226 * URGENT TODO: Are there any cases, where the
227 * parent of such a node is not an element node?
228 */
229 node1 = node1->parent;
230 break;
231 }
232 } while (1);
233 } else {
234 precedence1 = 2; /* element is parent */
235 node1 = node1->parent;
236 }
237 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
Nick Wellnhoferd422b952017-10-09 13:37:42 +0200238 (0 <= (ptrdiff_t) node1->content)) {
Denis Pauke28c8a12013-08-03 14:22:54 +0300239 /*
240 * Fallback for whatever case.
241 */
242 node1 = miscNode1;
243 precedence1 = 0;
244 } else
245 misc = 1;
246 }
247 break;
248 case XML_NAMESPACE_DECL:
249 /*
250 * TODO: why do we return 1 for namespace nodes?
251 */
252 return(1);
253 default:
254 break;
255 }
256 switch (node2->type) {
257 case XML_ELEMENT_NODE:
258 break;
259 case XML_ATTRIBUTE_NODE:
260 precedence2 = 1; /* element is owner */
261 miscNode2 = node2;
262 node2 = node2->parent;
263 misc = 1;
264 break;
265 case XML_TEXT_NODE:
266 case XML_CDATA_SECTION_NODE:
267 case XML_COMMENT_NODE:
268 case XML_PI_NODE: {
269 miscNode2 = node2;
270 if (node2->prev != NULL) {
271 do {
272 node2 = node2->prev;
273 if (node2->type == XML_ELEMENT_NODE) {
274 precedence2 = 3; /* element in prev-sibl axis */
275 break;
276 }
277 if (node2->prev == NULL) {
278 precedence2 = 2; /* element is parent */
279 node2 = node2->parent;
280 break;
281 }
282 } while (1);
283 } else {
284 precedence2 = 2; /* element is parent */
285 node2 = node2->parent;
286 }
287 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
Nick Wellnhoferd422b952017-10-09 13:37:42 +0200288 (0 <= (ptrdiff_t) node2->content))
Denis Pauke28c8a12013-08-03 14:22:54 +0300289 {
290 node2 = miscNode2;
291 precedence2 = 0;
292 } else
293 misc = 1;
294 }
295 break;
296 case XML_NAMESPACE_DECL:
297 return(1);
298 default:
299 break;
300 }
301 if (misc) {
302 if (node1 == node2) {
303 if (precedence1 == precedence2) {
304 /*
305 * The ugly case; but normally there aren't many
306 * adjacent non-element nodes around.
307 */
308 cur = miscNode2->prev;
309 while (cur != NULL) {
310 if (cur == miscNode1)
311 return(1);
312 if (cur->type == XML_ELEMENT_NODE)
313 return(-1);
314 cur = cur->prev;
315 }
316 return (-1);
317 } else {
318 /*
319 * Evaluate based on higher precedence wrt to the element.
320 * TODO: This assumes attributes are sorted before content.
321 * Is this 100% correct?
322 */
323 if (precedence1 < precedence2)
324 return(1);
325 else
326 return(-1);
327 }
328 }
329 /*
330 * Special case: One of the helper-elements is contained by the other.
331 * <foo>
332 * <node2>
333 * <node1>Text-1(precedence1 == 2)</node1>
334 * </node2>
335 * Text-6(precedence2 == 3)
336 * </foo>
337 */
338 if ((precedence2 == 3) && (precedence1 > 1)) {
339 cur = node1->parent;
340 while (cur) {
341 if (cur == node2)
342 return(1);
343 cur = cur->parent;
344 }
345 }
346 if ((precedence1 == 3) && (precedence2 > 1)) {
347 cur = node2->parent;
348 while (cur) {
349 if (cur == node1)
350 return(-1);
351 cur = cur->parent;
352 }
353 }
354 }
355
356 /*
Haibo Huangcfd91dc2020-07-30 23:01:33 -0700357 * Speedup using document order if available.
Denis Pauke28c8a12013-08-03 14:22:54 +0300358 */
359 if ((node1->type == XML_ELEMENT_NODE) &&
360 (node2->type == XML_ELEMENT_NODE) &&
Nick Wellnhoferd422b952017-10-09 13:37:42 +0200361 (0 > (ptrdiff_t) node1->content) &&
362 (0 > (ptrdiff_t) node2->content) &&
Denis Pauke28c8a12013-08-03 14:22:54 +0300363 (node1->doc == node2->doc)) {
364
Nick Wellnhoferd422b952017-10-09 13:37:42 +0200365 l1 = -((ptrdiff_t) node1->content);
366 l2 = -((ptrdiff_t) node2->content);
Denis Pauke28c8a12013-08-03 14:22:54 +0300367 if (l1 < l2)
368 return(1);
369 if (l1 > l2)
370 return(-1);
371 }
372
373turtle_comparison:
374
375 if (node1 == node2->prev)
376 return(1);
377 if (node1 == node2->next)
378 return(-1);
379 /*
380 * compute depth to root
381 */
Nick Wellnhofer3eaedba2015-07-11 14:27:34 +0200382 for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
383 if (cur->parent == node1)
Denis Pauke28c8a12013-08-03 14:22:54 +0300384 return(1);
385 depth2++;
386 }
387 root = cur;
Nick Wellnhofer3eaedba2015-07-11 14:27:34 +0200388 for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
389 if (cur->parent == node2)
Denis Pauke28c8a12013-08-03 14:22:54 +0300390 return(-1);
391 depth1++;
392 }
393 /*
394 * Distinct document (or distinct entities :-( ) case.
395 */
396 if (root != cur) {
397 return(-2);
398 }
399 /*
400 * get the nearest common ancestor.
401 */
402 while (depth1 > depth2) {
403 depth1--;
404 node1 = node1->parent;
405 }
406 while (depth2 > depth1) {
407 depth2--;
408 node2 = node2->parent;
409 }
410 while (node1->parent != node2->parent) {
411 node1 = node1->parent;
412 node2 = node2->parent;
413 /* should not happen but just in case ... */
414 if ((node1 == NULL) || (node2 == NULL))
415 return(-2);
416 }
417 /*
418 * Find who's first.
419 */
420 if (node1 == node2->prev)
421 return(1);
422 if (node1 == node2->next)
423 return(-1);
424 /*
Haibo Huangcfd91dc2020-07-30 23:01:33 -0700425 * Speedup using document order if available.
Denis Pauke28c8a12013-08-03 14:22:54 +0300426 */
427 if ((node1->type == XML_ELEMENT_NODE) &&
428 (node2->type == XML_ELEMENT_NODE) &&
Nick Wellnhoferd422b952017-10-09 13:37:42 +0200429 (0 > (ptrdiff_t) node1->content) &&
430 (0 > (ptrdiff_t) node2->content) &&
Denis Pauke28c8a12013-08-03 14:22:54 +0300431 (node1->doc == node2->doc)) {
432
Nick Wellnhoferd422b952017-10-09 13:37:42 +0200433 l1 = -((ptrdiff_t) node1->content);
434 l2 = -((ptrdiff_t) node2->content);
Denis Pauke28c8a12013-08-03 14:22:54 +0300435 if (l1 < l2)
436 return(1);
437 if (l1 > l2)
438 return(-1);
439 }
440
441 for (cur = node1->next;cur != NULL;cur = cur->next)
442 if (cur == node2)
443 return(1);
444 return(-1); /* assume there is no sibling list corruption */
445}
446#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
447
Vojtech Fried3e031b72012-08-24 16:52:44 +0800448/*
Haibo Huangcfd91dc2020-07-30 23:01:33 -0700449 * Wrapper for the Timsort algorithm from timsort.h
Vojtech Fried3e031b72012-08-24 16:52:44 +0800450 */
451#ifdef WITH_TIM_SORT
452#define SORT_NAME libxml_domnode
453#define SORT_TYPE xmlNodePtr
454/**
455 * wrap_cmp:
456 * @x: a node
457 * @y: another node
458 *
459 * Comparison function for the Timsort implementation
460 *
Daniel Veillard510e7582012-09-04 11:50:36 +0800461 * Returns -2 in case of error -1 if first point < second point, 0 if
462 * it's the same node, +1 otherwise
Vojtech Fried3e031b72012-08-24 16:52:44 +0800463 */
464static
465int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
466#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Vojtech Fried3e031b72012-08-24 16:52:44 +0800467 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
468 {
469 int res = xmlXPathCmpNodesExt(x, y);
470 return res == -2 ? res : -res;
471 }
472#else
473 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
474 {
475 int res = xmlXPathCmpNodes(x, y);
476 return res == -2 ? res : -res;
477 }
478#endif
479#define SORT_CMP(x, y) (wrap_cmp(x, y))
480#include "timsort.h"
481#endif /* WITH_TIM_SORT */
482
William M. Brack21e4ef22005-01-02 09:53:13 +0000483#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000484
485/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000486 * *
487 * Floating point stuff *
488 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000489 ************************************************************************/
490
Elliott Hughes7fbecab2019-01-10 16:42:03 -0800491double xmlXPathNAN;
492double xmlXPathPINF;
493double xmlXPathNINF;
Owen Taylor3473f882001-02-23 17:55:21 +0000494
Owen Taylor3473f882001-02-23 17:55:21 +0000495/**
496 * xmlXPathInit:
497 *
498 * Initialize the XPath environment
499 */
Elliott Hughes5cefca72021-05-06 13:23:15 -0700500ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
Owen Taylor3473f882001-02-23 17:55:21 +0000501void
502xmlXPathInit(void) {
Elliott Hughes5cefca72021-05-06 13:23:15 -0700503 /* MSVC doesn't allow division by zero in constant expressions. */
504 double zero = 0.0;
505 xmlXPathNAN = 0.0 / zero;
506 xmlXPathPINF = 1.0 / zero;
507 xmlXPathNINF = -xmlXPathPINF;
Owen Taylor3473f882001-02-23 17:55:21 +0000508}
509
Daniel Veillardcda96922001-08-21 10:56:31 +0000510/**
511 * xmlXPathIsNaN:
512 * @val: a double value
513 *
Daniel Veillardcda96922001-08-21 10:56:31 +0000514 * Returns 1 if the value is a NaN, 0 otherwise
515 */
516int
517xmlXPathIsNaN(double val) {
Nick Wellnhofer8813f392017-09-21 00:11:26 +0200518#ifdef isnan
519 return isnan(val);
520#else
521 return !(val == val);
522#endif
Daniel Veillardcda96922001-08-21 10:56:31 +0000523}
524
525/**
526 * xmlXPathIsInf:
527 * @val: a double value
528 *
Nick Wellnhofer8813f392017-09-21 00:11:26 +0200529 * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
Daniel Veillardcda96922001-08-21 10:56:31 +0000530 */
531int
532xmlXPathIsInf(double val) {
Nick Wellnhofer8813f392017-09-21 00:11:26 +0200533#ifdef isinf
Nick Wellnhoferddbb0752017-11-27 14:30:19 +0100534 return isinf(val) ? (val > 0 ? 1 : -1) : 0;
Nick Wellnhofer8813f392017-09-21 00:11:26 +0200535#else
Elliott Hughes5cefca72021-05-06 13:23:15 -0700536 if (val >= xmlXPathPINF)
Nick Wellnhofer8813f392017-09-21 00:11:26 +0200537 return 1;
Elliott Hughes5cefca72021-05-06 13:23:15 -0700538 if (val <= -xmlXPathPINF)
Nick Wellnhofer8813f392017-09-21 00:11:26 +0200539 return -1;
540 return 0;
541#endif
Daniel Veillardcda96922001-08-21 10:56:31 +0000542}
543
Daniel Veillard4432df22003-09-28 18:58:27 +0000544#endif /* SCHEMAS or XPATH */
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000545
Nick Wellnhofer8813f392017-09-21 00:11:26 +0200546#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000547
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000548/*
549 * TODO: when compatibility allows remove all "fake node libxslt" strings
550 * the test should just be name[0] = ' '
551 */
Daniel Veillard074f37e2008-09-01 13:38:22 +0000552#ifdef DEBUG_XPATH_EXPRESSION
553#define DEBUG_STEP
554#define DEBUG_EXPR
555#define DEBUG_EVAL_COUNTS
556#endif
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000557
558static xmlNs xmlXPathXMLNamespaceStruct = {
559 NULL,
560 XML_NAMESPACE_DECL,
561 XML_XML_NAMESPACE,
562 BAD_CAST "xml",
William M. Brackee0b9822007-03-07 08:15:01 +0000563 NULL,
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000564 NULL
565};
566static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
567#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard45490ae2008-07-29 09:13:19 +0000568/*
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000569 * Optimizer is disabled only when threaded apps are detected while
570 * the library ain't compiled for thread safety.
571 */
572static int xmlXPathDisableOptimizer = 0;
573#endif
574
Owen Taylor3473f882001-02-23 17:55:21 +0000575/************************************************************************
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000576 * *
577 * Error handling routines *
578 * *
579 ************************************************************************/
580
Daniel Veillard24505b02005-07-28 23:49:35 +0000581/**
582 * XP_ERRORNULL:
583 * @X: the error code
584 *
585 * Macro to raise an XPath error and return NULL.
586 */
587#define XP_ERRORNULL(X) \
588 { xmlXPathErr(ctxt, X); return(NULL); }
589
William M. Brack08171912003-12-29 02:52:11 +0000590/*
591 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
592 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000593static const char *xmlXPathErrorMessages[] = {
594 "Ok\n",
595 "Number encoding\n",
596 "Unfinished literal\n",
597 "Start of literal\n",
598 "Expected $ for variable reference\n",
599 "Undefined variable\n",
600 "Invalid predicate\n",
601 "Invalid expression\n",
602 "Missing closing curly brace\n",
603 "Unregistered function\n",
604 "Invalid operand\n",
605 "Invalid type\n",
606 "Invalid number of arguments\n",
607 "Invalid context size\n",
608 "Invalid context position\n",
609 "Memory allocation error\n",
610 "Syntax error\n",
611 "Resource error\n",
612 "Sub resource error\n",
613 "Undefined namespace prefix\n",
614 "Encoding error\n",
Daniel Veillard57b25162004-11-06 14:50:18 +0000615 "Char out of XML range\n",
William M. Brackcd65bc92005-01-06 09:39:18 +0000616 "Invalid or incomplete context\n",
Jan Pokorný75801652013-12-19 15:09:14 +0100617 "Stack usage error\n",
Daniel Veillard47881282012-09-07 14:24:50 +0800618 "Forbidden variable\n",
Haibo Huangcfd91dc2020-07-30 23:01:33 -0700619 "Operation limit exceeded\n",
620 "Recursion limit exceeded\n",
William M. Brackcd65bc92005-01-06 09:39:18 +0000621 "?? Unknown error ??\n" /* Must be last in the list! */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000622};
William M. Brackcd65bc92005-01-06 09:39:18 +0000623#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
624 sizeof(xmlXPathErrorMessages[0])) - 1)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000625/**
626 * xmlXPathErrMemory:
627 * @ctxt: an XPath context
Haibo Huangcfd91dc2020-07-30 23:01:33 -0700628 * @extra: extra information
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000629 *
630 * Handle a redefinition of attribute error
631 */
632static void
633xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
634{
635 if (ctxt != NULL) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -0700636 xmlResetError(&ctxt->lastError);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000637 if (extra) {
638 xmlChar buf[200];
639
640 xmlStrPrintf(buf, 200,
David Kilzer4472c3a2016-05-13 15:13:17 +0800641 "Memory allocation failed : %s\n",
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000642 extra);
643 ctxt->lastError.message = (char *) xmlStrdup(buf);
644 } else {
645 ctxt->lastError.message = (char *)
646 xmlStrdup(BAD_CAST "Memory allocation failed\n");
647 }
648 ctxt->lastError.domain = XML_FROM_XPATH;
649 ctxt->lastError.code = XML_ERR_NO_MEMORY;
650 if (ctxt->error != NULL)
651 ctxt->error(ctxt->userData, &ctxt->lastError);
652 } else {
653 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000654 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000655 NULL, NULL, XML_FROM_XPATH,
656 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
657 extra, NULL, NULL, 0, 0,
658 "Memory allocation failed : %s\n", extra);
659 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000660 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000661 NULL, NULL, XML_FROM_XPATH,
662 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
663 NULL, NULL, NULL, 0, 0,
664 "Memory allocation failed\n");
665 }
666}
667
668/**
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000669 * xmlXPathPErrMemory:
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000670 * @ctxt: an XPath parser context
Haibo Huangcfd91dc2020-07-30 23:01:33 -0700671 * @extra: extra information
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000672 *
673 * Handle a redefinition of attribute error
674 */
675static void
676xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
677{
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000678 if (ctxt == NULL)
679 xmlXPathErrMemory(NULL, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000680 else {
681 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000682 xmlXPathErrMemory(ctxt->context, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000683 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000684}
685
686/**
687 * xmlXPathErr:
688 * @ctxt: a XPath parser context
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000689 * @error: the error code
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000690 *
William M. Brackcd65bc92005-01-06 09:39:18 +0000691 * Handle an XPath error
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000692 */
693void
694xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
695{
William M. Brackcd65bc92005-01-06 09:39:18 +0000696 if ((error < 0) || (error > MAXERRNO))
697 error = MAXERRNO;
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000698 if (ctxt == NULL) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000699 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000700 NULL, NULL, XML_FROM_XPATH,
701 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
702 XML_ERR_ERROR, NULL, 0,
703 NULL, NULL, NULL, 0, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200704 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000705 return;
706 }
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000707 ctxt->error = error;
708 if (ctxt->context == NULL) {
709 __xmlRaiseError(NULL, NULL, NULL,
710 NULL, NULL, XML_FROM_XPATH,
711 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
712 XML_ERR_ERROR, NULL, 0,
713 (const char *) ctxt->base, NULL, NULL,
714 ctxt->cur - ctxt->base, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200715 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000716 return;
717 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +0000718
719 /* cleanup current last error */
Daniel Veillard45490ae2008-07-29 09:13:19 +0000720 xmlResetError(&ctxt->context->lastError);
Aleksey Sanin1b2be102006-05-31 20:53:43 +0000721
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000722 ctxt->context->lastError.domain = XML_FROM_XPATH;
723 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
724 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000725 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000726 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
727 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
728 ctxt->context->lastError.node = ctxt->context->debugNode;
729 if (ctxt->context->error != NULL) {
730 ctxt->context->error(ctxt->context->userData,
731 &ctxt->context->lastError);
732 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000733 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000734 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
735 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
736 XML_ERR_ERROR, NULL, 0,
737 (const char *) ctxt->base, NULL, NULL,
738 ctxt->cur - ctxt->base, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200739 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000740 }
741
742}
743
744/**
745 * xmlXPatherror:
746 * @ctxt: the XPath Parser context
747 * @file: the file name
748 * @line: the line number
749 * @no: the error number
750 *
751 * Formats an error message.
752 */
753void
754xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
755 int line ATTRIBUTE_UNUSED, int no) {
756 xmlXPathErr(ctxt, no);
757}
758
Haibo Huangcfd91dc2020-07-30 23:01:33 -0700759/**
760 * xmlXPathCheckOpLimit:
761 * @ctxt: the XPath Parser context
762 * @opCount: the number of operations to be added
763 *
764 * Adds opCount to the running total of operations and returns -1 if the
765 * operation limit is exceeded. Returns 0 otherwise.
766 */
767static int
768xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
769 xmlXPathContextPtr xpctxt = ctxt->context;
770
771 if ((opCount > xpctxt->opLimit) ||
772 (xpctxt->opCount > xpctxt->opLimit - opCount)) {
773 xpctxt->opCount = xpctxt->opLimit;
774 xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
775 return(-1);
776 }
777
778 xpctxt->opCount += opCount;
779 return(0);
780}
781
782#define OP_LIMIT_EXCEEDED(ctxt, n) \
783 ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
784
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000785/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000786 * *
787 * Utilities *
788 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000789 ************************************************************************/
790
791/**
792 * xsltPointerList:
793 *
794 * Pointer-list for various purposes.
795 */
796typedef struct _xmlPointerList xmlPointerList;
797typedef xmlPointerList *xmlPointerListPtr;
798struct _xmlPointerList {
799 void **items;
800 int number;
801 int size;
802};
803/*
804* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
805* and here, we should make the functions public.
806*/
807static int
Daniel Veillard45490ae2008-07-29 09:13:19 +0000808xmlPointerListAddSize(xmlPointerListPtr list,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000809 void *item,
810 int initialSize)
811{
812 if (list->items == NULL) {
813 if (initialSize <= 0)
814 initialSize = 1;
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800815 list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000816 if (list->items == NULL) {
817 xmlXPathErrMemory(NULL,
818 "xmlPointerListCreate: allocating item\n");
819 return(-1);
820 }
821 list->number = 0;
822 list->size = initialSize;
823 } else if (list->size <= list->number) {
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800824 if (list->size > 50000000) {
825 xmlXPathErrMemory(NULL,
826 "xmlPointerListAddSize: re-allocating item\n");
827 return(-1);
828 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000829 list->size *= 2;
830 list->items = (void **) xmlRealloc(list->items,
831 list->size * sizeof(void *));
832 if (list->items == NULL) {
833 xmlXPathErrMemory(NULL,
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800834 "xmlPointerListAddSize: re-allocating item\n");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000835 list->size = 0;
836 return(-1);
837 }
838 }
839 list->items[list->number++] = item;
840 return(0);
841}
842
843/**
844 * xsltPointerListCreate:
845 *
846 * Creates an xsltPointerList structure.
847 *
848 * Returns a xsltPointerList structure or NULL in case of an error.
849 */
850static xmlPointerListPtr
851xmlPointerListCreate(int initialSize)
852{
853 xmlPointerListPtr ret;
854
855 ret = xmlMalloc(sizeof(xmlPointerList));
856 if (ret == NULL) {
857 xmlXPathErrMemory(NULL,
858 "xmlPointerListCreate: allocating item\n");
859 return (NULL);
860 }
861 memset(ret, 0, sizeof(xmlPointerList));
862 if (initialSize > 0) {
863 xmlPointerListAddSize(ret, NULL, initialSize);
864 ret->number = 0;
865 }
866 return (ret);
867}
868
869/**
870 * xsltPointerListFree:
871 *
872 * Frees the xsltPointerList structure. This does not free
873 * the content of the list.
874 */
875static void
876xmlPointerListFree(xmlPointerListPtr list)
877{
878 if (list == NULL)
879 return;
880 if (list->items != NULL)
881 xmlFree(list->items);
882 xmlFree(list);
883}
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000884
885/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000886 * *
887 * Parser Types *
888 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000889 ************************************************************************/
890
891/*
892 * Types are private:
893 */
894
895typedef enum {
896 XPATH_OP_END=0,
897 XPATH_OP_AND,
898 XPATH_OP_OR,
899 XPATH_OP_EQUAL,
900 XPATH_OP_CMP,
901 XPATH_OP_PLUS,
902 XPATH_OP_MULT,
903 XPATH_OP_UNION,
904 XPATH_OP_ROOT,
905 XPATH_OP_NODE,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000906 XPATH_OP_COLLECT,
Elliott Hughes7fbecab2019-01-10 16:42:03 -0800907 XPATH_OP_VALUE, /* 11 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000908 XPATH_OP_VARIABLE,
909 XPATH_OP_FUNCTION,
910 XPATH_OP_ARG,
911 XPATH_OP_PREDICATE,
Elliott Hughes7fbecab2019-01-10 16:42:03 -0800912 XPATH_OP_FILTER, /* 16 */
913 XPATH_OP_SORT /* 17 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000914#ifdef LIBXML_XPTR_ENABLED
915 ,XPATH_OP_RANGETO
916#endif
917} xmlXPathOp;
918
919typedef enum {
920 AXIS_ANCESTOR = 1,
921 AXIS_ANCESTOR_OR_SELF,
922 AXIS_ATTRIBUTE,
923 AXIS_CHILD,
924 AXIS_DESCENDANT,
925 AXIS_DESCENDANT_OR_SELF,
926 AXIS_FOLLOWING,
927 AXIS_FOLLOWING_SIBLING,
928 AXIS_NAMESPACE,
929 AXIS_PARENT,
930 AXIS_PRECEDING,
931 AXIS_PRECEDING_SIBLING,
Daniel Veillard45490ae2008-07-29 09:13:19 +0000932 AXIS_SELF
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000933} xmlXPathAxisVal;
934
935typedef enum {
936 NODE_TEST_NONE = 0,
937 NODE_TEST_TYPE = 1,
938 NODE_TEST_PI = 2,
939 NODE_TEST_ALL = 3,
940 NODE_TEST_NS = 4,
941 NODE_TEST_NAME = 5
942} xmlXPathTestVal;
943
944typedef enum {
945 NODE_TYPE_NODE = 0,
946 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
947 NODE_TYPE_TEXT = XML_TEXT_NODE,
Daniel Veillard45490ae2008-07-29 09:13:19 +0000948 NODE_TYPE_PI = XML_PI_NODE
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000949} xmlXPathTypeVal;
950
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000951typedef struct _xmlXPathStepOp xmlXPathStepOp;
952typedef xmlXPathStepOp *xmlXPathStepOpPtr;
953struct _xmlXPathStepOp {
William M. Brack08171912003-12-29 02:52:11 +0000954 xmlXPathOp op; /* The identifier of the operation */
955 int ch1; /* First child */
956 int ch2; /* Second child */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000957 int value;
958 int value2;
959 int value3;
960 void *value4;
961 void *value5;
Nick Wellnhofer229d1f92016-08-22 13:21:57 +0200962 xmlXPathFunction cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000963 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000964};
965
966struct _xmlXPathCompExpr {
William M. Brack08171912003-12-29 02:52:11 +0000967 int nbStep; /* Number of steps in this expression */
968 int maxStep; /* Maximum number of steps allocated */
969 xmlXPathStepOp *steps; /* ops for computation of this expression */
970 int last; /* index of last step in expression */
971 xmlChar *expr; /* the expression being computed */
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200972 xmlDictPtr dict; /* the dictionary to use if any */
Daniel Veillardf06307e2001-07-03 10:35:50 +0000973#ifdef DEBUG_EVAL_COUNTS
974 int nb;
975 xmlChar *string;
976#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000977#ifdef XPATH_STREAMING
978 xmlPatternPtr stream;
979#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000980};
981
982/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000983 * *
984 * Forward declarations *
985 * *
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +0000986 ************************************************************************/
987static void
988xmlXPathFreeValueTree(xmlNodeSetPtr obj);
989static void
990xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
991static int
992xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
993 xmlXPathStepOpPtr op, xmlNodePtr *first);
994static int
995xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +0000996 xmlXPathStepOpPtr op,
997 int isPredicate);
Nick Wellnhofere03f0a12017-11-09 16:42:47 +0100998static void
999xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00001000
1001/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +00001002 * *
1003 * Parser Type functions *
1004 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001005 ************************************************************************/
1006
1007/**
1008 * xmlXPathNewCompExpr:
1009 *
1010 * Create a new Xpath component
1011 *
1012 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
1013 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001014static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001015xmlXPathNewCompExpr(void) {
1016 xmlXPathCompExprPtr cur;
1017
1018 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1019 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001020 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001021 return(NULL);
1022 }
1023 memset(cur, 0, sizeof(xmlXPathCompExpr));
1024 cur->maxStep = 10;
1025 cur->nbStep = 0;
1026 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1027 sizeof(xmlXPathStepOp));
1028 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001029 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001030 xmlFree(cur);
1031 return(NULL);
1032 }
1033 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1034 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +00001035#ifdef DEBUG_EVAL_COUNTS
1036 cur->nb = 0;
1037#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001038 return(cur);
1039}
1040
1041/**
1042 * xmlXPathFreeCompExpr:
1043 * @comp: an XPATH comp
1044 *
1045 * Free up the memory allocated by @comp
1046 */
1047void
Daniel Veillardf06307e2001-07-03 10:35:50 +00001048xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1049{
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001050 xmlXPathStepOpPtr op;
1051 int i;
1052
1053 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00001054 return;
Daniel Veillard4773df22004-01-23 13:15:13 +00001055 if (comp->dict == NULL) {
1056 for (i = 0; i < comp->nbStep; i++) {
1057 op = &comp->steps[i];
1058 if (op->value4 != NULL) {
1059 if (op->op == XPATH_OP_VALUE)
1060 xmlXPathFreeObject(op->value4);
1061 else
1062 xmlFree(op->value4);
1063 }
1064 if (op->value5 != NULL)
1065 xmlFree(op->value5);
1066 }
1067 } else {
1068 for (i = 0; i < comp->nbStep; i++) {
1069 op = &comp->steps[i];
1070 if (op->value4 != NULL) {
1071 if (op->op == XPATH_OP_VALUE)
1072 xmlXPathFreeObject(op->value4);
1073 }
1074 }
1075 xmlDictFree(comp->dict);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001076 }
1077 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00001078 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001079 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00001080#ifdef DEBUG_EVAL_COUNTS
1081 if (comp->string != NULL) {
1082 xmlFree(comp->string);
1083 }
1084#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +00001085#ifdef XPATH_STREAMING
1086 if (comp->stream != NULL) {
1087 xmlFreePatternList(comp->stream);
1088 }
1089#endif
Daniel Veillard118aed72002-09-24 14:13:13 +00001090 if (comp->expr != NULL) {
1091 xmlFree(comp->expr);
1092 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00001093
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001094 xmlFree(comp);
1095}
1096
1097/**
1098 * xmlXPathCompExprAdd:
1099 * @comp: the compiled expression
1100 * @ch1: first child index
1101 * @ch2: second child index
1102 * @op: an op
1103 * @value: the first int value
1104 * @value2: the second int value
1105 * @value3: the third int value
1106 * @value4: the first string value
1107 * @value5: the second string value
1108 *
William M. Brack08171912003-12-29 02:52:11 +00001109 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001110 *
1111 * Returns -1 in case of failure, the index otherwise
1112 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001113static int
Haibo Huangcfd91dc2020-07-30 23:01:33 -07001114xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001115 xmlXPathOp op, int value,
1116 int value2, int value3, void *value4, void *value5) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07001117 xmlXPathCompExprPtr comp = ctxt->comp;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001118 if (comp->nbStep >= comp->maxStep) {
1119 xmlXPathStepOp *real;
1120
Daniel Veillardcd852ad2012-07-30 10:12:18 +08001121 if (comp->maxStep >= XPATH_MAX_STEPS) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07001122 xmlXPathPErrMemory(ctxt, "adding step\n");
Daniel Veillardcd852ad2012-07-30 10:12:18 +08001123 return(-1);
1124 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001125 comp->maxStep *= 2;
1126 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1127 comp->maxStep * sizeof(xmlXPathStepOp));
1128 if (real == NULL) {
1129 comp->maxStep /= 2;
Haibo Huangcfd91dc2020-07-30 23:01:33 -07001130 xmlXPathPErrMemory(ctxt, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001131 return(-1);
1132 }
1133 comp->steps = real;
1134 }
1135 comp->last = comp->nbStep;
1136 comp->steps[comp->nbStep].ch1 = ch1;
1137 comp->steps[comp->nbStep].ch2 = ch2;
1138 comp->steps[comp->nbStep].op = op;
1139 comp->steps[comp->nbStep].value = value;
1140 comp->steps[comp->nbStep].value2 = value2;
1141 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +00001142 if ((comp->dict != NULL) &&
1143 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1144 (op == XPATH_OP_COLLECT))) {
1145 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +00001146 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +00001147 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +00001148 xmlFree(value4);
1149 } else
1150 comp->steps[comp->nbStep].value4 = NULL;
1151 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +00001152 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +00001153 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +00001154 xmlFree(value5);
1155 } else
1156 comp->steps[comp->nbStep].value5 = NULL;
1157 } else {
1158 comp->steps[comp->nbStep].value4 = value4;
1159 comp->steps[comp->nbStep].value5 = value5;
1160 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +00001161 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001162 return(comp->nbStep++);
1163}
1164
Daniel Veillardf06307e2001-07-03 10:35:50 +00001165/**
1166 * xmlXPathCompSwap:
1167 * @comp: the compiled expression
1168 * @op: operation index
1169 *
1170 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +00001171 */
1172static void
1173xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1174 int tmp;
1175
Daniel Veillardbc6f7592002-04-16 07:49:59 +00001176#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +00001177 /*
1178 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +00001179 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +00001180 * application
1181 */
1182 if (xmlXPathDisableOptimizer)
1183 return;
1184#endif
1185
Daniel Veillardf06307e2001-07-03 10:35:50 +00001186 tmp = op->ch1;
1187 op->ch1 = op->ch2;
1188 op->ch2 = tmp;
1189}
1190
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001191#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
Haibo Huangcfd91dc2020-07-30 23:01:33 -07001192 xmlXPathCompExprAdd(ctxt, (op1), (op2), \
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001193 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001194#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
Haibo Huangcfd91dc2020-07-30 23:01:33 -07001195 xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1, \
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001196 (op), (val), (val2), (val3), (val4), (val5))
1197
Daniel Veillard45490ae2008-07-29 09:13:19 +00001198#define PUSH_LEAVE_EXPR(op, val, val2) \
Haibo Huangcfd91dc2020-07-30 23:01:33 -07001199xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001200
Daniel Veillard45490ae2008-07-29 09:13:19 +00001201#define PUSH_UNARY_EXPR(op, ch, val, val2) \
Haibo Huangcfd91dc2020-07-30 23:01:33 -07001202xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001203
Daniel Veillard45490ae2008-07-29 09:13:19 +00001204#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
Haibo Huangcfd91dc2020-07-30 23:01:33 -07001205xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op), \
William M. Brack08171912003-12-29 02:52:11 +00001206 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001207
1208/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +00001209 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +00001210 * XPath object cache structures *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001211 * *
1212 ************************************************************************/
1213
1214/* #define XP_DEFAULT_CACHE_ON */
1215
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001216#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001217
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001218typedef struct _xmlXPathContextCache xmlXPathContextCache;
1219typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1220struct _xmlXPathContextCache {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00001221 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
1222 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
1223 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
1224 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
1225 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001226 int maxNodeset;
1227 int maxString;
1228 int maxBoolean;
1229 int maxNumber;
1230 int maxMisc;
1231#ifdef XP_DEBUG_OBJ_USAGE
1232 int dbgCachedAll;
1233 int dbgCachedNodeset;
1234 int dbgCachedString;
1235 int dbgCachedBool;
1236 int dbgCachedNumber;
1237 int dbgCachedPoint;
1238 int dbgCachedRange;
1239 int dbgCachedLocset;
1240 int dbgCachedUsers;
1241 int dbgCachedXSLTTree;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001242 int dbgCachedUndefined;
1243
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001244
1245 int dbgReusedAll;
1246 int dbgReusedNodeset;
1247 int dbgReusedString;
1248 int dbgReusedBool;
1249 int dbgReusedNumber;
1250 int dbgReusedPoint;
1251 int dbgReusedRange;
1252 int dbgReusedLocset;
1253 int dbgReusedUsers;
1254 int dbgReusedXSLTTree;
1255 int dbgReusedUndefined;
1256
1257#endif
1258};
1259
1260/************************************************************************
1261 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +00001262 * Debugging related functions *
Owen Taylor3473f882001-02-23 17:55:21 +00001263 * *
1264 ************************************************************************/
1265
Daniel Veillard45490ae2008-07-29 09:13:19 +00001266#define STRANGE \
Owen Taylor3473f882001-02-23 17:55:21 +00001267 xmlGenericError(xmlGenericErrorContext, \
1268 "Internal error at %s:%d\n", \
1269 __FILE__, __LINE__);
1270
1271#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001272static void
1273xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001274 int i;
1275 char shift[100];
1276
1277 for (i = 0;((i < depth) && (i < 25));i++)
1278 shift[2 * i] = shift[2 * i + 1] = ' ';
1279 shift[2 * i] = shift[2 * i + 1] = 0;
1280 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001281 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001282 fprintf(output, "Node is NULL !\n");
1283 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001284
Owen Taylor3473f882001-02-23 17:55:21 +00001285 }
1286
1287 if ((cur->type == XML_DOCUMENT_NODE) ||
1288 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001289 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001290 fprintf(output, " /\n");
1291 } else if (cur->type == XML_ATTRIBUTE_NODE)
1292 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1293 else
1294 xmlDebugDumpOneNode(output, cur, depth);
1295}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001296static void
1297xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001298 xmlNodePtr tmp;
1299 int i;
1300 char shift[100];
1301
1302 for (i = 0;((i < depth) && (i < 25));i++)
1303 shift[2 * i] = shift[2 * i + 1] = ' ';
1304 shift[2 * i] = shift[2 * i + 1] = 0;
1305 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001306 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001307 fprintf(output, "Node is NULL !\n");
1308 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001309
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001310 }
1311
1312 while (cur != NULL) {
1313 tmp = cur;
1314 cur = cur->next;
1315 xmlDebugDumpOneNode(output, tmp, depth);
1316 }
1317}
Owen Taylor3473f882001-02-23 17:55:21 +00001318
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001319static void
1320xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001321 int i;
1322 char shift[100];
1323
1324 for (i = 0;((i < depth) && (i < 25));i++)
1325 shift[2 * i] = shift[2 * i + 1] = ' ';
1326 shift[2 * i] = shift[2 * i + 1] = 0;
1327
1328 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001329 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001330 fprintf(output, "NodeSet is NULL !\n");
1331 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001332
Owen Taylor3473f882001-02-23 17:55:21 +00001333 }
1334
Daniel Veillard911f49a2001-04-07 15:39:35 +00001335 if (cur != NULL) {
1336 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1337 for (i = 0;i < cur->nodeNr;i++) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001338 fprintf(output, "%s", shift);
Daniel Veillard911f49a2001-04-07 15:39:35 +00001339 fprintf(output, "%d", i + 1);
1340 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1341 }
Owen Taylor3473f882001-02-23 17:55:21 +00001342 }
1343}
1344
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001345static void
1346xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001347 int i;
1348 char shift[100];
1349
1350 for (i = 0;((i < depth) && (i < 25));i++)
1351 shift[2 * i] = shift[2 * i + 1] = ' ';
1352 shift[2 * i] = shift[2 * i + 1] = 0;
1353
1354 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001355 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001356 fprintf(output, "Value Tree is NULL !\n");
1357 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001358
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001359 }
1360
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001361 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001362 fprintf(output, "%d", i + 1);
1363 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1364}
Owen Taylor3473f882001-02-23 17:55:21 +00001365#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001366static void
1367xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001368 int i;
1369 char shift[100];
1370
1371 for (i = 0;((i < depth) && (i < 25));i++)
1372 shift[2 * i] = shift[2 * i + 1] = ' ';
1373 shift[2 * i] = shift[2 * i + 1] = 0;
1374
1375 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001376 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001377 fprintf(output, "LocationSet is NULL !\n");
1378 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001379
Owen Taylor3473f882001-02-23 17:55:21 +00001380 }
1381
1382 for (i = 0;i < cur->locNr;i++) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001383 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001384 fprintf(output, "%d : ", i + 1);
1385 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1386 }
1387}
Daniel Veillard017b1082001-06-21 11:20:21 +00001388#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001389
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00001390/**
1391 * xmlXPathDebugDumpObject:
1392 * @output: the FILE * to dump the output
1393 * @cur: the object to inspect
1394 * @depth: indentation level
1395 *
1396 * Dump the content of the object for debugging purposes
1397 */
1398void
1399xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001400 int i;
1401 char shift[100];
1402
Daniel Veillarda82b1822004-11-08 16:24:57 +00001403 if (output == NULL) return;
1404
Owen Taylor3473f882001-02-23 17:55:21 +00001405 for (i = 0;((i < depth) && (i < 25));i++)
1406 shift[2 * i] = shift[2 * i + 1] = ' ';
1407 shift[2 * i] = shift[2 * i + 1] = 0;
1408
Kasimier T. Buchcik97258712006-01-05 12:30:43 +00001409
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001410 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001411
1412 if (cur == NULL) {
1413 fprintf(output, "Object is empty (NULL)\n");
1414 return;
1415 }
1416 switch(cur->type) {
1417 case XPATH_UNDEFINED:
1418 fprintf(output, "Object is uninitialized\n");
1419 break;
1420 case XPATH_NODESET:
1421 fprintf(output, "Object is a Node Set :\n");
1422 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1423 break;
1424 case XPATH_XSLT_TREE:
1425 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001426 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +00001427 break;
1428 case XPATH_BOOLEAN:
1429 fprintf(output, "Object is a Boolean : ");
1430 if (cur->boolval) fprintf(output, "true\n");
1431 else fprintf(output, "false\n");
1432 break;
1433 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +00001434 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001435 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001436 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001437 break;
1438 case -1:
1439 fprintf(output, "Object is a number : -Infinity\n");
1440 break;
1441 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001442 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001443 fprintf(output, "Object is a number : NaN\n");
Nick Wellnhofer8813f392017-09-21 00:11:26 +02001444 } else if (cur->floatval == 0) {
1445 /* Omit sign for negative zero. */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001446 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001447 } else {
1448 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1449 }
1450 }
Owen Taylor3473f882001-02-23 17:55:21 +00001451 break;
1452 case XPATH_STRING:
1453 fprintf(output, "Object is a string : ");
1454 xmlDebugDumpString(output, cur->stringval);
1455 fprintf(output, "\n");
1456 break;
1457 case XPATH_POINT:
1458 fprintf(output, "Object is a point : index %d in node", cur->index);
1459 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1460 fprintf(output, "\n");
1461 break;
1462 case XPATH_RANGE:
1463 if ((cur->user2 == NULL) ||
1464 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1465 fprintf(output, "Object is a collapsed range :\n");
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001466 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001467 if (cur->index >= 0)
1468 fprintf(output, "index %d in ", cur->index);
1469 fprintf(output, "node\n");
1470 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1471 depth + 1);
1472 } else {
1473 fprintf(output, "Object is a range :\n");
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001474 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001475 fprintf(output, "From ");
1476 if (cur->index >= 0)
1477 fprintf(output, "index %d in ", cur->index);
1478 fprintf(output, "node\n");
1479 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1480 depth + 1);
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001481 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001482 fprintf(output, "To ");
1483 if (cur->index2 >= 0)
1484 fprintf(output, "index %d in ", cur->index2);
1485 fprintf(output, "node\n");
1486 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1487 depth + 1);
1488 fprintf(output, "\n");
1489 }
1490 break;
1491 case XPATH_LOCATIONSET:
1492#if defined(LIBXML_XPTR_ENABLED)
1493 fprintf(output, "Object is a Location Set:\n");
1494 xmlXPathDebugDumpLocationSet(output,
1495 (xmlLocationSetPtr) cur->user, depth);
1496#endif
1497 break;
1498 case XPATH_USERS:
1499 fprintf(output, "Object is user defined\n");
1500 break;
1501 }
1502}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001503
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001504static void
1505xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001506 xmlXPathStepOpPtr op, int depth) {
1507 int i;
1508 char shift[100];
1509
1510 for (i = 0;((i < depth) && (i < 25));i++)
1511 shift[2 * i] = shift[2 * i + 1] = ' ';
1512 shift[2 * i] = shift[2 * i + 1] = 0;
1513
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001514 fprintf(output, "%s", shift);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001515 if (op == NULL) {
1516 fprintf(output, "Step is NULL\n");
1517 return;
1518 }
1519 switch (op->op) {
1520 case XPATH_OP_END:
1521 fprintf(output, "END"); break;
1522 case XPATH_OP_AND:
1523 fprintf(output, "AND"); break;
1524 case XPATH_OP_OR:
1525 fprintf(output, "OR"); break;
1526 case XPATH_OP_EQUAL:
1527 if (op->value)
1528 fprintf(output, "EQUAL =");
1529 else
1530 fprintf(output, "EQUAL !=");
1531 break;
1532 case XPATH_OP_CMP:
1533 if (op->value)
1534 fprintf(output, "CMP <");
1535 else
1536 fprintf(output, "CMP >");
1537 if (!op->value2)
1538 fprintf(output, "=");
1539 break;
1540 case XPATH_OP_PLUS:
1541 if (op->value == 0)
1542 fprintf(output, "PLUS -");
1543 else if (op->value == 1)
1544 fprintf(output, "PLUS +");
1545 else if (op->value == 2)
1546 fprintf(output, "PLUS unary -");
1547 else if (op->value == 3)
1548 fprintf(output, "PLUS unary - -");
1549 break;
1550 case XPATH_OP_MULT:
1551 if (op->value == 0)
1552 fprintf(output, "MULT *");
1553 else if (op->value == 1)
1554 fprintf(output, "MULT div");
1555 else
1556 fprintf(output, "MULT mod");
1557 break;
1558 case XPATH_OP_UNION:
1559 fprintf(output, "UNION"); break;
1560 case XPATH_OP_ROOT:
1561 fprintf(output, "ROOT"); break;
1562 case XPATH_OP_NODE:
1563 fprintf(output, "NODE"); break;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001564 case XPATH_OP_SORT:
1565 fprintf(output, "SORT"); break;
1566 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +00001567 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1568 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1569 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001570 const xmlChar *prefix = op->value4;
1571 const xmlChar *name = op->value5;
1572
1573 fprintf(output, "COLLECT ");
1574 switch (axis) {
1575 case AXIS_ANCESTOR:
1576 fprintf(output, " 'ancestors' "); break;
1577 case AXIS_ANCESTOR_OR_SELF:
1578 fprintf(output, " 'ancestors-or-self' "); break;
1579 case AXIS_ATTRIBUTE:
1580 fprintf(output, " 'attributes' "); break;
1581 case AXIS_CHILD:
1582 fprintf(output, " 'child' "); break;
1583 case AXIS_DESCENDANT:
1584 fprintf(output, " 'descendant' "); break;
1585 case AXIS_DESCENDANT_OR_SELF:
1586 fprintf(output, " 'descendant-or-self' "); break;
1587 case AXIS_FOLLOWING:
1588 fprintf(output, " 'following' "); break;
1589 case AXIS_FOLLOWING_SIBLING:
1590 fprintf(output, " 'following-siblings' "); break;
1591 case AXIS_NAMESPACE:
1592 fprintf(output, " 'namespace' "); break;
1593 case AXIS_PARENT:
1594 fprintf(output, " 'parent' "); break;
1595 case AXIS_PRECEDING:
1596 fprintf(output, " 'preceding' "); break;
1597 case AXIS_PRECEDING_SIBLING:
1598 fprintf(output, " 'preceding-sibling' "); break;
1599 case AXIS_SELF:
1600 fprintf(output, " 'self' "); break;
1601 }
1602 switch (test) {
1603 case NODE_TEST_NONE:
1604 fprintf(output, "'none' "); break;
1605 case NODE_TEST_TYPE:
1606 fprintf(output, "'type' "); break;
1607 case NODE_TEST_PI:
1608 fprintf(output, "'PI' "); break;
1609 case NODE_TEST_ALL:
1610 fprintf(output, "'all' "); break;
1611 case NODE_TEST_NS:
1612 fprintf(output, "'namespace' "); break;
1613 case NODE_TEST_NAME:
1614 fprintf(output, "'name' "); break;
1615 }
1616 switch (type) {
1617 case NODE_TYPE_NODE:
1618 fprintf(output, "'node' "); break;
1619 case NODE_TYPE_COMMENT:
1620 fprintf(output, "'comment' "); break;
1621 case NODE_TYPE_TEXT:
1622 fprintf(output, "'text' "); break;
1623 case NODE_TYPE_PI:
1624 fprintf(output, "'PI' "); break;
1625 }
1626 if (prefix != NULL)
1627 fprintf(output, "%s:", prefix);
1628 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001629 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001630 break;
1631
1632 }
1633 case XPATH_OP_VALUE: {
1634 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1635
1636 fprintf(output, "ELEM ");
1637 xmlXPathDebugDumpObject(output, object, 0);
1638 goto finish;
1639 }
1640 case XPATH_OP_VARIABLE: {
1641 const xmlChar *prefix = op->value5;
1642 const xmlChar *name = op->value4;
1643
1644 if (prefix != NULL)
1645 fprintf(output, "VARIABLE %s:%s", prefix, name);
1646 else
1647 fprintf(output, "VARIABLE %s", name);
1648 break;
1649 }
1650 case XPATH_OP_FUNCTION: {
1651 int nbargs = op->value;
1652 const xmlChar *prefix = op->value5;
1653 const xmlChar *name = op->value4;
1654
1655 if (prefix != NULL)
1656 fprintf(output, "FUNCTION %s:%s(%d args)",
1657 prefix, name, nbargs);
1658 else
1659 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1660 break;
1661 }
1662 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1663 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001664 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001665#ifdef LIBXML_XPTR_ENABLED
1666 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1667#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001668 default:
1669 fprintf(output, "UNKNOWN %d\n", op->op); return;
1670 }
1671 fprintf(output, "\n");
1672finish:
1673 if (op->ch1 >= 0)
1674 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1675 if (op->ch2 >= 0)
1676 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1677}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001678
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001679/**
1680 * xmlXPathDebugDumpCompExpr:
1681 * @output: the FILE * for the output
1682 * @comp: the precompiled XPath expression
1683 * @depth: the indentation level.
1684 *
1685 * Dumps the tree of the compiled XPath expression.
1686 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001687void
1688xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1689 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001690 int i;
1691 char shift[100];
1692
Daniel Veillarda82b1822004-11-08 16:24:57 +00001693 if ((output == NULL) || (comp == NULL)) return;
1694
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001695 for (i = 0;((i < depth) && (i < 25));i++)
1696 shift[2 * i] = shift[2 * i + 1] = ' ';
1697 shift[2 * i] = shift[2 * i + 1] = 0;
1698
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001699 fprintf(output, "%s", shift);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001700
Nick Wellnhoferca8635b2017-09-07 15:46:12 +02001701#ifdef XPATH_STREAMING
1702 if (comp->stream) {
1703 fprintf(output, "Streaming Expression\n");
1704 } else
1705#endif
1706 {
1707 fprintf(output, "Compiled Expression : %d elements\n",
1708 comp->nbStep);
1709 i = comp->last;
1710 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1711 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001712}
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001713
1714#ifdef XP_DEBUG_OBJ_USAGE
1715
1716/*
1717* XPath object usage related debugging variables.
1718*/
1719static int xmlXPathDebugObjCounterUndefined = 0;
1720static int xmlXPathDebugObjCounterNodeset = 0;
1721static int xmlXPathDebugObjCounterBool = 0;
1722static int xmlXPathDebugObjCounterNumber = 0;
1723static int xmlXPathDebugObjCounterString = 0;
1724static int xmlXPathDebugObjCounterPoint = 0;
1725static int xmlXPathDebugObjCounterRange = 0;
1726static int xmlXPathDebugObjCounterLocset = 0;
1727static int xmlXPathDebugObjCounterUsers = 0;
1728static int xmlXPathDebugObjCounterXSLTTree = 0;
1729static int xmlXPathDebugObjCounterAll = 0;
1730
1731static int xmlXPathDebugObjTotalUndefined = 0;
1732static int xmlXPathDebugObjTotalNodeset = 0;
1733static int xmlXPathDebugObjTotalBool = 0;
1734static int xmlXPathDebugObjTotalNumber = 0;
1735static int xmlXPathDebugObjTotalString = 0;
1736static int xmlXPathDebugObjTotalPoint = 0;
1737static int xmlXPathDebugObjTotalRange = 0;
1738static int xmlXPathDebugObjTotalLocset = 0;
1739static int xmlXPathDebugObjTotalUsers = 0;
1740static int xmlXPathDebugObjTotalXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001741static int xmlXPathDebugObjTotalAll = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001742
1743static int xmlXPathDebugObjMaxUndefined = 0;
1744static int xmlXPathDebugObjMaxNodeset = 0;
1745static int xmlXPathDebugObjMaxBool = 0;
1746static int xmlXPathDebugObjMaxNumber = 0;
1747static int xmlXPathDebugObjMaxString = 0;
1748static int xmlXPathDebugObjMaxPoint = 0;
1749static int xmlXPathDebugObjMaxRange = 0;
1750static int xmlXPathDebugObjMaxLocset = 0;
1751static int xmlXPathDebugObjMaxUsers = 0;
1752static int xmlXPathDebugObjMaxXSLTTree = 0;
1753static int xmlXPathDebugObjMaxAll = 0;
1754
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001755static void
1756xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1757{
1758 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001759 if (ctxt->cache != NULL) {
1760 xmlXPathContextCachePtr cache =
1761 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001762
1763 cache->dbgCachedAll = 0;
1764 cache->dbgCachedNodeset = 0;
1765 cache->dbgCachedString = 0;
1766 cache->dbgCachedBool = 0;
1767 cache->dbgCachedNumber = 0;
1768 cache->dbgCachedPoint = 0;
1769 cache->dbgCachedRange = 0;
1770 cache->dbgCachedLocset = 0;
1771 cache->dbgCachedUsers = 0;
1772 cache->dbgCachedXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001773 cache->dbgCachedUndefined = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001774
1775 cache->dbgReusedAll = 0;
1776 cache->dbgReusedNodeset = 0;
1777 cache->dbgReusedString = 0;
1778 cache->dbgReusedBool = 0;
1779 cache->dbgReusedNumber = 0;
1780 cache->dbgReusedPoint = 0;
1781 cache->dbgReusedRange = 0;
1782 cache->dbgReusedLocset = 0;
1783 cache->dbgReusedUsers = 0;
1784 cache->dbgReusedXSLTTree = 0;
1785 cache->dbgReusedUndefined = 0;
1786 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00001787 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001788
1789 xmlXPathDebugObjCounterUndefined = 0;
1790 xmlXPathDebugObjCounterNodeset = 0;
1791 xmlXPathDebugObjCounterBool = 0;
1792 xmlXPathDebugObjCounterNumber = 0;
1793 xmlXPathDebugObjCounterString = 0;
1794 xmlXPathDebugObjCounterPoint = 0;
1795 xmlXPathDebugObjCounterRange = 0;
1796 xmlXPathDebugObjCounterLocset = 0;
1797 xmlXPathDebugObjCounterUsers = 0;
1798 xmlXPathDebugObjCounterXSLTTree = 0;
1799 xmlXPathDebugObjCounterAll = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001800
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001801 xmlXPathDebugObjTotalUndefined = 0;
1802 xmlXPathDebugObjTotalNodeset = 0;
1803 xmlXPathDebugObjTotalBool = 0;
1804 xmlXPathDebugObjTotalNumber = 0;
1805 xmlXPathDebugObjTotalString = 0;
1806 xmlXPathDebugObjTotalPoint = 0;
1807 xmlXPathDebugObjTotalRange = 0;
1808 xmlXPathDebugObjTotalLocset = 0;
1809 xmlXPathDebugObjTotalUsers = 0;
1810 xmlXPathDebugObjTotalXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001811 xmlXPathDebugObjTotalAll = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001812
1813 xmlXPathDebugObjMaxUndefined = 0;
1814 xmlXPathDebugObjMaxNodeset = 0;
1815 xmlXPathDebugObjMaxBool = 0;
1816 xmlXPathDebugObjMaxNumber = 0;
1817 xmlXPathDebugObjMaxString = 0;
1818 xmlXPathDebugObjMaxPoint = 0;
1819 xmlXPathDebugObjMaxRange = 0;
1820 xmlXPathDebugObjMaxLocset = 0;
1821 xmlXPathDebugObjMaxUsers = 0;
1822 xmlXPathDebugObjMaxXSLTTree = 0;
1823 xmlXPathDebugObjMaxAll = 0;
1824
1825}
1826
1827static void
1828xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1829 xmlXPathObjectType objType)
1830{
1831 int isCached = 0;
1832
1833 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001834 if (ctxt->cache != NULL) {
1835 xmlXPathContextCachePtr cache =
1836 (xmlXPathContextCachePtr) ctxt->cache;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001837
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001838 isCached = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001839
1840 cache->dbgReusedAll++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001841 switch (objType) {
1842 case XPATH_UNDEFINED:
1843 cache->dbgReusedUndefined++;
1844 break;
1845 case XPATH_NODESET:
1846 cache->dbgReusedNodeset++;
1847 break;
1848 case XPATH_BOOLEAN:
1849 cache->dbgReusedBool++;
1850 break;
1851 case XPATH_NUMBER:
1852 cache->dbgReusedNumber++;
1853 break;
1854 case XPATH_STRING:
1855 cache->dbgReusedString++;
1856 break;
1857 case XPATH_POINT:
1858 cache->dbgReusedPoint++;
1859 break;
1860 case XPATH_RANGE:
1861 cache->dbgReusedRange++;
1862 break;
1863 case XPATH_LOCATIONSET:
1864 cache->dbgReusedLocset++;
1865 break;
1866 case XPATH_USERS:
1867 cache->dbgReusedUsers++;
1868 break;
1869 case XPATH_XSLT_TREE:
1870 cache->dbgReusedXSLTTree++;
1871 break;
1872 default:
1873 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001874 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001875 }
1876 }
1877
1878 switch (objType) {
1879 case XPATH_UNDEFINED:
1880 if (! isCached)
1881 xmlXPathDebugObjTotalUndefined++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001882 xmlXPathDebugObjCounterUndefined++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001883 if (xmlXPathDebugObjCounterUndefined >
1884 xmlXPathDebugObjMaxUndefined)
1885 xmlXPathDebugObjMaxUndefined =
1886 xmlXPathDebugObjCounterUndefined;
1887 break;
1888 case XPATH_NODESET:
1889 if (! isCached)
1890 xmlXPathDebugObjTotalNodeset++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001891 xmlXPathDebugObjCounterNodeset++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001892 if (xmlXPathDebugObjCounterNodeset >
1893 xmlXPathDebugObjMaxNodeset)
1894 xmlXPathDebugObjMaxNodeset =
1895 xmlXPathDebugObjCounterNodeset;
1896 break;
1897 case XPATH_BOOLEAN:
1898 if (! isCached)
1899 xmlXPathDebugObjTotalBool++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001900 xmlXPathDebugObjCounterBool++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001901 if (xmlXPathDebugObjCounterBool >
1902 xmlXPathDebugObjMaxBool)
1903 xmlXPathDebugObjMaxBool =
1904 xmlXPathDebugObjCounterBool;
1905 break;
1906 case XPATH_NUMBER:
1907 if (! isCached)
1908 xmlXPathDebugObjTotalNumber++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001909 xmlXPathDebugObjCounterNumber++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001910 if (xmlXPathDebugObjCounterNumber >
1911 xmlXPathDebugObjMaxNumber)
1912 xmlXPathDebugObjMaxNumber =
1913 xmlXPathDebugObjCounterNumber;
1914 break;
1915 case XPATH_STRING:
1916 if (! isCached)
1917 xmlXPathDebugObjTotalString++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001918 xmlXPathDebugObjCounterString++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001919 if (xmlXPathDebugObjCounterString >
1920 xmlXPathDebugObjMaxString)
1921 xmlXPathDebugObjMaxString =
1922 xmlXPathDebugObjCounterString;
1923 break;
1924 case XPATH_POINT:
1925 if (! isCached)
1926 xmlXPathDebugObjTotalPoint++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001927 xmlXPathDebugObjCounterPoint++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001928 if (xmlXPathDebugObjCounterPoint >
1929 xmlXPathDebugObjMaxPoint)
1930 xmlXPathDebugObjMaxPoint =
1931 xmlXPathDebugObjCounterPoint;
1932 break;
1933 case XPATH_RANGE:
1934 if (! isCached)
1935 xmlXPathDebugObjTotalRange++;
1936 xmlXPathDebugObjCounterRange++;
1937 if (xmlXPathDebugObjCounterRange >
1938 xmlXPathDebugObjMaxRange)
1939 xmlXPathDebugObjMaxRange =
1940 xmlXPathDebugObjCounterRange;
1941 break;
1942 case XPATH_LOCATIONSET:
1943 if (! isCached)
1944 xmlXPathDebugObjTotalLocset++;
1945 xmlXPathDebugObjCounterLocset++;
1946 if (xmlXPathDebugObjCounterLocset >
1947 xmlXPathDebugObjMaxLocset)
1948 xmlXPathDebugObjMaxLocset =
1949 xmlXPathDebugObjCounterLocset;
1950 break;
1951 case XPATH_USERS:
1952 if (! isCached)
1953 xmlXPathDebugObjTotalUsers++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001954 xmlXPathDebugObjCounterUsers++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001955 if (xmlXPathDebugObjCounterUsers >
1956 xmlXPathDebugObjMaxUsers)
1957 xmlXPathDebugObjMaxUsers =
1958 xmlXPathDebugObjCounterUsers;
1959 break;
1960 case XPATH_XSLT_TREE:
1961 if (! isCached)
1962 xmlXPathDebugObjTotalXSLTTree++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001963 xmlXPathDebugObjCounterXSLTTree++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001964 if (xmlXPathDebugObjCounterXSLTTree >
1965 xmlXPathDebugObjMaxXSLTTree)
1966 xmlXPathDebugObjMaxXSLTTree =
1967 xmlXPathDebugObjCounterXSLTTree;
1968 break;
1969 default:
1970 break;
1971 }
1972 if (! isCached)
1973 xmlXPathDebugObjTotalAll++;
1974 xmlXPathDebugObjCounterAll++;
1975 if (xmlXPathDebugObjCounterAll >
1976 xmlXPathDebugObjMaxAll)
1977 xmlXPathDebugObjMaxAll =
1978 xmlXPathDebugObjCounterAll;
1979}
1980
1981static void
1982xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1983 xmlXPathObjectType objType)
1984{
1985 int isCached = 0;
1986
1987 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001988 if (ctxt->cache != NULL) {
1989 xmlXPathContextCachePtr cache =
1990 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001991
Daniel Veillard45490ae2008-07-29 09:13:19 +00001992 isCached = 1;
1993
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001994 cache->dbgCachedAll++;
1995 switch (objType) {
1996 case XPATH_UNDEFINED:
1997 cache->dbgCachedUndefined++;
1998 break;
1999 case XPATH_NODESET:
2000 cache->dbgCachedNodeset++;
2001 break;
2002 case XPATH_BOOLEAN:
2003 cache->dbgCachedBool++;
2004 break;
2005 case XPATH_NUMBER:
2006 cache->dbgCachedNumber++;
2007 break;
2008 case XPATH_STRING:
2009 cache->dbgCachedString++;
2010 break;
2011 case XPATH_POINT:
2012 cache->dbgCachedPoint++;
2013 break;
2014 case XPATH_RANGE:
2015 cache->dbgCachedRange++;
2016 break;
2017 case XPATH_LOCATIONSET:
2018 cache->dbgCachedLocset++;
2019 break;
2020 case XPATH_USERS:
2021 cache->dbgCachedUsers++;
2022 break;
2023 case XPATH_XSLT_TREE:
2024 cache->dbgCachedXSLTTree++;
2025 break;
2026 default:
2027 break;
2028 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00002029
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002030 }
2031 }
2032 switch (objType) {
2033 case XPATH_UNDEFINED:
2034 xmlXPathDebugObjCounterUndefined--;
2035 break;
2036 case XPATH_NODESET:
2037 xmlXPathDebugObjCounterNodeset--;
2038 break;
2039 case XPATH_BOOLEAN:
2040 xmlXPathDebugObjCounterBool--;
2041 break;
2042 case XPATH_NUMBER:
2043 xmlXPathDebugObjCounterNumber--;
2044 break;
2045 case XPATH_STRING:
2046 xmlXPathDebugObjCounterString--;
2047 break;
2048 case XPATH_POINT:
2049 xmlXPathDebugObjCounterPoint--;
2050 break;
2051 case XPATH_RANGE:
2052 xmlXPathDebugObjCounterRange--;
2053 break;
2054 case XPATH_LOCATIONSET:
2055 xmlXPathDebugObjCounterLocset--;
2056 break;
2057 case XPATH_USERS:
2058 xmlXPathDebugObjCounterUsers--;
2059 break;
2060 case XPATH_XSLT_TREE:
2061 xmlXPathDebugObjCounterXSLTTree--;
2062 break;
2063 default:
2064 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002065 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002066 xmlXPathDebugObjCounterAll--;
2067}
2068
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002069static void
2070xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2071{
2072 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2073 reqXSLTTree, reqUndefined;
2074 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2075 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2076 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2077 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2078 int leftObjs = xmlXPathDebugObjCounterAll;
2079
2080 reqAll = xmlXPathDebugObjTotalAll;
2081 reqNodeset = xmlXPathDebugObjTotalNodeset;
2082 reqString = xmlXPathDebugObjTotalString;
2083 reqBool = xmlXPathDebugObjTotalBool;
2084 reqNumber = xmlXPathDebugObjTotalNumber;
2085 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2086 reqUndefined = xmlXPathDebugObjTotalUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002087
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002088 printf("# XPath object usage:\n");
2089
2090 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002091 if (ctxt->cache != NULL) {
2092 xmlXPathContextCachePtr cache =
2093 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002094
2095 reAll = cache->dbgReusedAll;
2096 reqAll += reAll;
2097 reNodeset = cache->dbgReusedNodeset;
2098 reqNodeset += reNodeset;
2099 reString = cache->dbgReusedString;
2100 reqString += reString;
2101 reBool = cache->dbgReusedBool;
2102 reqBool += reBool;
2103 reNumber = cache->dbgReusedNumber;
2104 reqNumber += reNumber;
2105 reXSLTTree = cache->dbgReusedXSLTTree;
2106 reqXSLTTree += reXSLTTree;
2107 reUndefined = cache->dbgReusedUndefined;
2108 reqUndefined += reUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002109
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002110 caAll = cache->dbgCachedAll;
2111 caBool = cache->dbgCachedBool;
2112 caNodeset = cache->dbgCachedNodeset;
2113 caString = cache->dbgCachedString;
2114 caNumber = cache->dbgCachedNumber;
2115 caXSLTTree = cache->dbgCachedXSLTTree;
2116 caUndefined = cache->dbgCachedUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002117
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002118 if (cache->nodesetObjs)
2119 leftObjs -= cache->nodesetObjs->number;
2120 if (cache->stringObjs)
2121 leftObjs -= cache->stringObjs->number;
2122 if (cache->booleanObjs)
2123 leftObjs -= cache->booleanObjs->number;
2124 if (cache->numberObjs)
2125 leftObjs -= cache->numberObjs->number;
2126 if (cache->miscObjs)
2127 leftObjs -= cache->miscObjs->number;
2128 }
2129 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00002130
2131 printf("# all\n");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002132 printf("# total : %d\n", reqAll);
2133 printf("# left : %d\n", leftObjs);
2134 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
2135 printf("# reused : %d\n", reAll);
2136 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
2137
2138 printf("# node-sets\n");
2139 printf("# total : %d\n", reqNodeset);
2140 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
2141 printf("# reused : %d\n", reNodeset);
2142 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
2143
2144 printf("# strings\n");
2145 printf("# total : %d\n", reqString);
2146 printf("# created: %d\n", xmlXPathDebugObjTotalString);
2147 printf("# reused : %d\n", reString);
2148 printf("# max : %d\n", xmlXPathDebugObjMaxString);
2149
2150 printf("# booleans\n");
2151 printf("# total : %d\n", reqBool);
2152 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
2153 printf("# reused : %d\n", reBool);
2154 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
2155
2156 printf("# numbers\n");
2157 printf("# total : %d\n", reqNumber);
2158 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
2159 printf("# reused : %d\n", reNumber);
2160 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
2161
2162 printf("# XSLT result tree fragments\n");
2163 printf("# total : %d\n", reqXSLTTree);
2164 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2165 printf("# reused : %d\n", reXSLTTree);
2166 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
2167
2168 printf("# undefined\n");
2169 printf("# total : %d\n", reqUndefined);
2170 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
2171 printf("# reused : %d\n", reUndefined);
2172 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
2173
2174}
2175
2176#endif /* XP_DEBUG_OBJ_USAGE */
2177
Daniel Veillard017b1082001-06-21 11:20:21 +00002178#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002179
2180/************************************************************************
2181 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002182 * XPath object caching *
2183 * *
2184 ************************************************************************/
2185
2186/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002187 * xmlXPathNewCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002188 *
2189 * Create a new object cache
2190 *
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002191 * Returns the xmlXPathCache just allocated.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002192 */
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002193static xmlXPathContextCachePtr
2194xmlXPathNewCache(void)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002195{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002196 xmlXPathContextCachePtr ret;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002197
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002198 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002199 if (ret == NULL) {
2200 xmlXPathErrMemory(NULL, "creating object cache\n");
2201 return(NULL);
2202 }
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002203 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002204 ret->maxNodeset = 100;
2205 ret->maxString = 100;
2206 ret->maxBoolean = 100;
2207 ret->maxNumber = 100;
2208 ret->maxMisc = 100;
2209 return(ret);
2210}
2211
2212static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002213xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002214{
2215 int i;
2216 xmlXPathObjectPtr obj;
2217
2218 if (list == NULL)
2219 return;
2220
2221 for (i = 0; i < list->number; i++) {
2222 obj = list->items[i];
2223 /*
2224 * Note that it is already assured that we don't need to
2225 * look out for namespace nodes in the node-set.
2226 */
2227 if (obj->nodesetval != NULL) {
2228 if (obj->nodesetval->nodeTab != NULL)
2229 xmlFree(obj->nodesetval->nodeTab);
2230 xmlFree(obj->nodesetval);
2231 }
2232 xmlFree(obj);
2233#ifdef XP_DEBUG_OBJ_USAGE
2234 xmlXPathDebugObjCounterAll--;
2235#endif
2236 }
2237 xmlPointerListFree(list);
2238}
2239
2240static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002241xmlXPathFreeCache(xmlXPathContextCachePtr cache)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002242{
2243 if (cache == NULL)
2244 return;
2245 if (cache->nodesetObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002246 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002247 if (cache->stringObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002248 xmlXPathCacheFreeObjectList(cache->stringObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002249 if (cache->booleanObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002250 xmlXPathCacheFreeObjectList(cache->booleanObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002251 if (cache->numberObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002252 xmlXPathCacheFreeObjectList(cache->numberObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002253 if (cache->miscObjs)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002254 xmlXPathCacheFreeObjectList(cache->miscObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002255 xmlFree(cache);
2256}
2257
2258/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002259 * xmlXPathContextSetCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002260 *
2261 * @ctxt: the XPath context
2262 * @active: enables/disables (creates/frees) the cache
Haibo Huangcfd91dc2020-07-30 23:01:33 -07002263 * @value: a value with semantics dependent on @options
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002264 * @options: options (currently only the value 0 is used)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002265 *
2266 * Creates/frees an object cache on the XPath context.
2267 * If activates XPath objects (xmlXPathObject) will be cached internally
Aleksey Sanin1b2be102006-05-31 20:53:43 +00002268 * to be reused.
2269 * @options:
2270 * 0: This will set the XPath object caching:
2271 * @value:
2272 * This will set the maximum number of XPath objects
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002273 * to be cached per slot
2274 * There are 5 slots for: node-set, string, number, boolean, and
Aleksey Sanin1b2be102006-05-31 20:53:43 +00002275 * misc objects. Use <0 for the default number (100).
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002276 * Other values for @options have currently no effect.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002277 *
2278 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2279 */
2280int
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002281xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2282 int active,
2283 int value,
2284 int options)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002285{
2286 if (ctxt == NULL)
2287 return(-1);
2288 if (active) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002289 xmlXPathContextCachePtr cache;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002290
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002291 if (ctxt->cache == NULL) {
2292 ctxt->cache = xmlXPathNewCache();
2293 if (ctxt->cache == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002294 return(-1);
2295 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +00002296 cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002297 if (options == 0) {
2298 if (value < 0)
2299 value = 100;
2300 cache->maxNodeset = value;
2301 cache->maxString = value;
2302 cache->maxNumber = value;
2303 cache->maxBoolean = value;
Aleksey Sanin1b2be102006-05-31 20:53:43 +00002304 cache->maxMisc = value;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002305 }
2306 } else if (ctxt->cache != NULL) {
2307 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2308 ctxt->cache = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002309 }
2310 return(0);
2311}
2312
2313/**
2314 * xmlXPathCacheWrapNodeSet:
2315 * @ctxt: the XPath context
2316 * @val: the NodePtr value
2317 *
2318 * This is the cached version of xmlXPathWrapNodeSet().
2319 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2320 *
2321 * Returns the created or reused object.
2322 */
2323static xmlXPathObjectPtr
2324xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002325{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002326 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2327 xmlXPathContextCachePtr cache =
2328 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002329
2330 if ((cache->miscObjs != NULL) &&
2331 (cache->miscObjs->number != 0))
2332 {
2333 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002334
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002335 ret = (xmlXPathObjectPtr)
2336 cache->miscObjs->items[--cache->miscObjs->number];
2337 ret->type = XPATH_NODESET;
2338 ret->nodesetval = val;
2339#ifdef XP_DEBUG_OBJ_USAGE
2340 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2341#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00002342 return(ret);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002343 }
2344 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00002345
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002346 return(xmlXPathWrapNodeSet(val));
Daniel Veillard45490ae2008-07-29 09:13:19 +00002347
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002348}
2349
2350/**
2351 * xmlXPathCacheWrapString:
2352 * @ctxt: the XPath context
2353 * @val: the xmlChar * value
2354 *
2355 * This is the cached version of xmlXPathWrapString().
2356 * Wraps the @val string into an XPath object.
2357 *
2358 * Returns the created or reused object.
2359 */
2360static xmlXPathObjectPtr
2361xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002362{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002363 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2364 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002365
2366 if ((cache->stringObjs != NULL) &&
2367 (cache->stringObjs->number != 0))
2368 {
Daniel Veillard45490ae2008-07-29 09:13:19 +00002369
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002370 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002371
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002372 ret = (xmlXPathObjectPtr)
2373 cache->stringObjs->items[--cache->stringObjs->number];
2374 ret->type = XPATH_STRING;
2375 ret->stringval = val;
2376#ifdef XP_DEBUG_OBJ_USAGE
2377 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2378#endif
2379 return(ret);
2380 } else if ((cache->miscObjs != NULL) &&
2381 (cache->miscObjs->number != 0))
2382 {
2383 xmlXPathObjectPtr ret;
2384 /*
2385 * Fallback to misc-cache.
2386 */
2387 ret = (xmlXPathObjectPtr)
2388 cache->miscObjs->items[--cache->miscObjs->number];
2389
2390 ret->type = XPATH_STRING;
2391 ret->stringval = val;
2392#ifdef XP_DEBUG_OBJ_USAGE
2393 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2394#endif
2395 return(ret);
2396 }
2397 }
2398 return(xmlXPathWrapString(val));
2399}
2400
2401/**
2402 * xmlXPathCacheNewNodeSet:
2403 * @ctxt: the XPath context
2404 * @val: the NodePtr value
2405 *
2406 * This is the cached version of xmlXPathNewNodeSet().
2407 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2408 * it with the single Node @val
2409 *
2410 * Returns the created or reused object.
2411 */
2412static xmlXPathObjectPtr
2413xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2414{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002415 if ((ctxt != NULL) && (ctxt->cache)) {
2416 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002417
2418 if ((cache->nodesetObjs != NULL) &&
2419 (cache->nodesetObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002420 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002421 xmlXPathObjectPtr ret;
2422 /*
Haibo Huangcfd91dc2020-07-30 23:01:33 -07002423 * Use the nodeset-cache.
Daniel Veillard45490ae2008-07-29 09:13:19 +00002424 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002425 ret = (xmlXPathObjectPtr)
2426 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2427 ret->type = XPATH_NODESET;
2428 ret->boolval = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002429 if (val) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002430 if ((ret->nodesetval->nodeMax == 0) ||
2431 (val->type == XML_NAMESPACE_DECL))
2432 {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07002433 /* TODO: Check memory error. */
Daniel Veillard45490ae2008-07-29 09:13:19 +00002434 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002435 } else {
2436 ret->nodesetval->nodeTab[0] = val;
2437 ret->nodesetval->nodeNr = 1;
2438 }
2439 }
2440#ifdef XP_DEBUG_OBJ_USAGE
2441 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2442#endif
2443 return(ret);
2444 } else if ((cache->miscObjs != NULL) &&
2445 (cache->miscObjs->number != 0))
2446 {
2447 xmlXPathObjectPtr ret;
2448 /*
2449 * Fallback to misc-cache.
2450 */
2451
2452 ret = (xmlXPathObjectPtr)
2453 cache->miscObjs->items[--cache->miscObjs->number];
2454
2455 ret->type = XPATH_NODESET;
2456 ret->boolval = 0;
2457 ret->nodesetval = xmlXPathNodeSetCreate(val);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08002458 if (ret->nodesetval == NULL) {
2459 ctxt->lastError.domain = XML_FROM_XPATH;
2460 ctxt->lastError.code = XML_ERR_NO_MEMORY;
2461 return(NULL);
2462 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002463#ifdef XP_DEBUG_OBJ_USAGE
2464 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2465#endif
2466 return(ret);
2467 }
2468 }
2469 return(xmlXPathNewNodeSet(val));
2470}
2471
2472/**
2473 * xmlXPathCacheNewCString:
2474 * @ctxt: the XPath context
2475 * @val: the char * value
2476 *
2477 * This is the cached version of xmlXPathNewCString().
2478 * Acquire an xmlXPathObjectPtr of type string and of value @val
2479 *
2480 * Returns the created or reused object.
2481 */
2482static xmlXPathObjectPtr
2483xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002484{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002485 if ((ctxt != NULL) && (ctxt->cache)) {
2486 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002487
2488 if ((cache->stringObjs != NULL) &&
2489 (cache->stringObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002490 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002491 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002492
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002493 ret = (xmlXPathObjectPtr)
2494 cache->stringObjs->items[--cache->stringObjs->number];
2495
2496 ret->type = XPATH_STRING;
2497 ret->stringval = xmlStrdup(BAD_CAST val);
2498#ifdef XP_DEBUG_OBJ_USAGE
2499 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2500#endif
2501 return(ret);
2502 } else if ((cache->miscObjs != NULL) &&
2503 (cache->miscObjs->number != 0))
2504 {
2505 xmlXPathObjectPtr ret;
2506
2507 ret = (xmlXPathObjectPtr)
2508 cache->miscObjs->items[--cache->miscObjs->number];
2509
2510 ret->type = XPATH_STRING;
2511 ret->stringval = xmlStrdup(BAD_CAST val);
2512#ifdef XP_DEBUG_OBJ_USAGE
2513 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2514#endif
2515 return(ret);
2516 }
2517 }
2518 return(xmlXPathNewCString(val));
2519}
2520
2521/**
2522 * xmlXPathCacheNewString:
2523 * @ctxt: the XPath context
2524 * @val: the xmlChar * value
2525 *
2526 * This is the cached version of xmlXPathNewString().
2527 * Acquire an xmlXPathObjectPtr of type string and of value @val
2528 *
2529 * Returns the created or reused object.
2530 */
2531static xmlXPathObjectPtr
2532xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002533{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002534 if ((ctxt != NULL) && (ctxt->cache)) {
2535 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002536
2537 if ((cache->stringObjs != NULL) &&
2538 (cache->stringObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002539 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002540 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002541
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002542 ret = (xmlXPathObjectPtr)
2543 cache->stringObjs->items[--cache->stringObjs->number];
2544 ret->type = XPATH_STRING;
2545 if (val != NULL)
2546 ret->stringval = xmlStrdup(val);
2547 else
2548 ret->stringval = xmlStrdup((const xmlChar *)"");
2549#ifdef XP_DEBUG_OBJ_USAGE
2550 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2551#endif
2552 return(ret);
2553 } else if ((cache->miscObjs != NULL) &&
2554 (cache->miscObjs->number != 0))
2555 {
2556 xmlXPathObjectPtr ret;
2557
2558 ret = (xmlXPathObjectPtr)
2559 cache->miscObjs->items[--cache->miscObjs->number];
2560
2561 ret->type = XPATH_STRING;
2562 if (val != NULL)
2563 ret->stringval = xmlStrdup(val);
2564 else
2565 ret->stringval = xmlStrdup((const xmlChar *)"");
2566#ifdef XP_DEBUG_OBJ_USAGE
2567 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2568#endif
2569 return(ret);
2570 }
2571 }
2572 return(xmlXPathNewString(val));
2573}
2574
2575/**
2576 * xmlXPathCacheNewBoolean:
2577 * @ctxt: the XPath context
2578 * @val: the boolean value
2579 *
2580 * This is the cached version of xmlXPathNewBoolean().
2581 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2582 *
2583 * Returns the created or reused object.
2584 */
2585static xmlXPathObjectPtr
2586xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002587{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002588 if ((ctxt != NULL) && (ctxt->cache)) {
2589 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002590
2591 if ((cache->booleanObjs != NULL) &&
2592 (cache->booleanObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002593 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002594 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002595
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002596 ret = (xmlXPathObjectPtr)
2597 cache->booleanObjs->items[--cache->booleanObjs->number];
2598 ret->type = XPATH_BOOLEAN;
2599 ret->boolval = (val != 0);
2600#ifdef XP_DEBUG_OBJ_USAGE
2601 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2602#endif
2603 return(ret);
2604 } else if ((cache->miscObjs != NULL) &&
2605 (cache->miscObjs->number != 0))
2606 {
2607 xmlXPathObjectPtr ret;
2608
2609 ret = (xmlXPathObjectPtr)
2610 cache->miscObjs->items[--cache->miscObjs->number];
2611
2612 ret->type = XPATH_BOOLEAN;
2613 ret->boolval = (val != 0);
2614#ifdef XP_DEBUG_OBJ_USAGE
2615 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2616#endif
2617 return(ret);
2618 }
2619 }
2620 return(xmlXPathNewBoolean(val));
2621}
2622
2623/**
2624 * xmlXPathCacheNewFloat:
2625 * @ctxt: the XPath context
2626 * @val: the double value
2627 *
2628 * This is the cached version of xmlXPathNewFloat().
2629 * Acquires an xmlXPathObjectPtr of type double and of value @val
2630 *
2631 * Returns the created or reused object.
2632 */
2633static xmlXPathObjectPtr
2634xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2635{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002636 if ((ctxt != NULL) && (ctxt->cache)) {
2637 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002638
2639 if ((cache->numberObjs != NULL) &&
2640 (cache->numberObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002641 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002642 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002643
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002644 ret = (xmlXPathObjectPtr)
2645 cache->numberObjs->items[--cache->numberObjs->number];
2646 ret->type = XPATH_NUMBER;
2647 ret->floatval = val;
2648#ifdef XP_DEBUG_OBJ_USAGE
2649 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2650#endif
2651 return(ret);
2652 } else if ((cache->miscObjs != NULL) &&
2653 (cache->miscObjs->number != 0))
2654 {
2655 xmlXPathObjectPtr ret;
2656
2657 ret = (xmlXPathObjectPtr)
2658 cache->miscObjs->items[--cache->miscObjs->number];
2659
2660 ret->type = XPATH_NUMBER;
2661 ret->floatval = val;
2662#ifdef XP_DEBUG_OBJ_USAGE
2663 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2664#endif
2665 return(ret);
2666 }
2667 }
2668 return(xmlXPathNewFloat(val));
2669}
2670
2671/**
2672 * xmlXPathCacheConvertString:
2673 * @ctxt: the XPath context
2674 * @val: an XPath object
2675 *
2676 * This is the cached version of xmlXPathConvertString().
2677 * Converts an existing object to its string() equivalent
2678 *
2679 * Returns a created or reused object, the old one is freed (cached)
2680 * (or the operation is done directly on @val)
2681 */
2682
2683static xmlXPathObjectPtr
2684xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00002685 xmlChar *res = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002686
2687 if (val == NULL)
2688 return(xmlXPathCacheNewCString(ctxt, ""));
2689
2690 switch (val->type) {
2691 case XPATH_UNDEFINED:
2692#ifdef DEBUG_EXPR
2693 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2694#endif
2695 break;
2696 case XPATH_NODESET:
2697 case XPATH_XSLT_TREE:
2698 res = xmlXPathCastNodeSetToString(val->nodesetval);
2699 break;
2700 case XPATH_STRING:
2701 return(val);
2702 case XPATH_BOOLEAN:
2703 res = xmlXPathCastBooleanToString(val->boolval);
2704 break;
2705 case XPATH_NUMBER:
2706 res = xmlXPathCastNumberToString(val->floatval);
2707 break;
2708 case XPATH_USERS:
2709 case XPATH_POINT:
2710 case XPATH_RANGE:
2711 case XPATH_LOCATIONSET:
2712 TODO;
2713 break;
2714 }
2715 xmlXPathReleaseObject(ctxt, val);
2716 if (res == NULL)
2717 return(xmlXPathCacheNewCString(ctxt, ""));
2718 return(xmlXPathCacheWrapString(ctxt, res));
2719}
2720
2721/**
2722 * xmlXPathCacheObjectCopy:
2723 * @ctxt: the XPath context
2724 * @val: the original object
2725 *
2726 * This is the cached version of xmlXPathObjectCopy().
2727 * Acquire a copy of a given object
2728 *
2729 * Returns a created or reused created object.
2730 */
2731static xmlXPathObjectPtr
2732xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2733{
2734 if (val == NULL)
2735 return(NULL);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002736
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002737 if (XP_HAS_CACHE(ctxt)) {
2738 switch (val->type) {
2739 case XPATH_NODESET:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002740 return(xmlXPathCacheWrapNodeSet(ctxt,
2741 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002742 case XPATH_STRING:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002743 return(xmlXPathCacheNewString(ctxt, val->stringval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002744 case XPATH_BOOLEAN:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002745 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002746 case XPATH_NUMBER:
2747 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2748 default:
2749 break;
2750 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002751 }
2752 return(xmlXPathObjectCopy(val));
2753}
2754
2755/**
2756 * xmlXPathCacheConvertBoolean:
2757 * @ctxt: the XPath context
2758 * @val: an XPath object
2759 *
2760 * This is the cached version of xmlXPathConvertBoolean().
2761 * Converts an existing object to its boolean() equivalent
2762 *
2763 * Returns a created or reused object, the old one is freed (or the operation
2764 * is done directly on @val)
2765 */
2766static xmlXPathObjectPtr
2767xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2768 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002769
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002770 if (val == NULL)
2771 return(xmlXPathCacheNewBoolean(ctxt, 0));
2772 if (val->type == XPATH_BOOLEAN)
2773 return(val);
2774 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2775 xmlXPathReleaseObject(ctxt, val);
2776 return(ret);
2777}
2778
2779/**
2780 * xmlXPathCacheConvertNumber:
2781 * @ctxt: the XPath context
2782 * @val: an XPath object
2783 *
2784 * This is the cached version of xmlXPathConvertNumber().
2785 * Converts an existing object to its number() equivalent
2786 *
2787 * Returns a created or reused object, the old one is freed (or the operation
2788 * is done directly on @val)
2789 */
2790static xmlXPathObjectPtr
2791xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2792 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002793
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002794 if (val == NULL)
2795 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2796 if (val->type == XPATH_NUMBER)
2797 return(val);
2798 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2799 xmlXPathReleaseObject(ctxt, val);
2800 return(ret);
2801}
2802
2803/************************************************************************
2804 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +00002805 * Parser stacks related functions and macros *
Owen Taylor3473f882001-02-23 17:55:21 +00002806 * *
2807 ************************************************************************/
2808
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002809/**
Daniel Veillardf5048b32011-08-18 17:10:13 +08002810 * xmlXPathSetFrame:
2811 * @ctxt: an XPath parser context
2812 *
2813 * Set the callee evaluation frame
2814 *
2815 * Returns the previous frame value to be restored once done
2816 */
2817static int
2818xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2819 int ret;
2820
2821 if (ctxt == NULL)
2822 return(0);
2823 ret = ctxt->valueFrame;
2824 ctxt->valueFrame = ctxt->valueNr;
2825 return(ret);
2826}
2827
2828/**
2829 * xmlXPathPopFrame:
2830 * @ctxt: an XPath parser context
2831 * @frame: the previous frame value
2832 *
2833 * Remove the callee evaluation frame
2834 */
2835static void
2836xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2837 if (ctxt == NULL)
2838 return;
2839 if (ctxt->valueNr < ctxt->valueFrame) {
2840 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2841 }
2842 ctxt->valueFrame = frame;
2843}
2844
2845/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002846 * valuePop:
2847 * @ctxt: an XPath evaluation context
2848 *
2849 * Pops the top XPath object from the value stack
2850 *
2851 * Returns the XPath object just removed
2852 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002853xmlXPathObjectPtr
Daniel Veillard1c732d22002-11-30 11:22:59 +00002854valuePop(xmlXPathParserContextPtr ctxt)
2855{
2856 xmlXPathObjectPtr ret;
2857
Daniel Veillarda82b1822004-11-08 16:24:57 +00002858 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
Daniel Veillard24505b02005-07-28 23:49:35 +00002859 return (NULL);
Daniel Veillardf5048b32011-08-18 17:10:13 +08002860
2861 if (ctxt->valueNr <= ctxt->valueFrame) {
2862 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2863 return (NULL);
2864 }
2865
Daniel Veillard1c732d22002-11-30 11:22:59 +00002866 ctxt->valueNr--;
2867 if (ctxt->valueNr > 0)
2868 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2869 else
2870 ctxt->value = NULL;
2871 ret = ctxt->valueTab[ctxt->valueNr];
Daniel Veillard24505b02005-07-28 23:49:35 +00002872 ctxt->valueTab[ctxt->valueNr] = NULL;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002873 return (ret);
2874}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002875/**
2876 * valuePush:
2877 * @ctxt: an XPath evaluation context
2878 * @value: the XPath object
2879 *
Haibo Huangcfd91dc2020-07-30 23:01:33 -07002880 * Pushes a new XPath object on top of the value stack. If value is NULL,
2881 * a memory error is recorded in the parser context.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002882 *
Haibo Huangcfd91dc2020-07-30 23:01:33 -07002883 * Returns the number of items on the value stack, or -1 in case of error.
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002884 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002885int
Daniel Veillard1c732d22002-11-30 11:22:59 +00002886valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2887{
Haibo Huangcfd91dc2020-07-30 23:01:33 -07002888 if (ctxt == NULL) return(-1);
2889 if (value == NULL) {
2890 /*
2891 * A NULL value typically indicates that a memory allocation failed,
2892 * so we set ctxt->error here to propagate the error.
2893 */
2894 ctxt->error = XPATH_MEMORY_ERROR;
2895 return(-1);
2896 }
Daniel Veillard1c732d22002-11-30 11:22:59 +00002897 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002898 xmlXPathObjectPtr *tmp;
2899
Daniel Veillardcd852ad2012-07-30 10:12:18 +08002900 if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07002901 xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n");
2902 return (-1);
Daniel Veillardcd852ad2012-07-30 10:12:18 +08002903 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002904 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2905 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00002906 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002907 if (tmp == NULL) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07002908 xmlXPathPErrMemory(ctxt, "pushing value\n");
2909 return (-1);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002910 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002911 ctxt->valueMax *= 2;
2912 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002913 }
2914 ctxt->valueTab[ctxt->valueNr] = value;
2915 ctxt->value = value;
2916 return (ctxt->valueNr++);
2917}
Owen Taylor3473f882001-02-23 17:55:21 +00002918
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002919/**
2920 * xmlXPathPopBoolean:
2921 * @ctxt: an XPath parser context
2922 *
2923 * Pops a boolean from the stack, handling conversion if needed.
2924 * Check error with #xmlXPathCheckError.
2925 *
2926 * Returns the boolean
2927 */
2928int
2929xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2930 xmlXPathObjectPtr obj;
2931 int ret;
2932
2933 obj = valuePop(ctxt);
2934 if (obj == NULL) {
2935 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2936 return(0);
2937 }
William M. Brack08171912003-12-29 02:52:11 +00002938 if (obj->type != XPATH_BOOLEAN)
2939 ret = xmlXPathCastToBoolean(obj);
2940 else
2941 ret = obj->boolval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002942 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002943 return(ret);
2944}
2945
2946/**
2947 * xmlXPathPopNumber:
2948 * @ctxt: an XPath parser context
2949 *
2950 * Pops a number from the stack, handling conversion if needed.
2951 * Check error with #xmlXPathCheckError.
2952 *
2953 * Returns the number
2954 */
2955double
2956xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2957 xmlXPathObjectPtr obj;
2958 double ret;
2959
2960 obj = valuePop(ctxt);
2961 if (obj == NULL) {
2962 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2963 return(0);
2964 }
William M. Brack08171912003-12-29 02:52:11 +00002965 if (obj->type != XPATH_NUMBER)
2966 ret = xmlXPathCastToNumber(obj);
2967 else
2968 ret = obj->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002969 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002970 return(ret);
2971}
2972
2973/**
2974 * xmlXPathPopString:
2975 * @ctxt: an XPath parser context
2976 *
2977 * Pops a string from the stack, handling conversion if needed.
2978 * Check error with #xmlXPathCheckError.
2979 *
2980 * Returns the string
2981 */
2982xmlChar *
2983xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2984 xmlXPathObjectPtr obj;
2985 xmlChar * ret;
2986
2987 obj = valuePop(ctxt);
2988 if (obj == NULL) {
2989 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2990 return(NULL);
2991 }
William M. Brack08171912003-12-29 02:52:11 +00002992 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002993 /* TODO: needs refactoring somewhere else */
2994 if (obj->stringval == ret)
2995 obj->stringval = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002996 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002997 return(ret);
2998}
2999
3000/**
3001 * xmlXPathPopNodeSet:
3002 * @ctxt: an XPath parser context
3003 *
3004 * Pops a node-set from the stack, handling conversion if needed.
3005 * Check error with #xmlXPathCheckError.
3006 *
3007 * Returns the node-set
3008 */
3009xmlNodeSetPtr
3010xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
3011 xmlXPathObjectPtr obj;
3012 xmlNodeSetPtr ret;
3013
Daniel Veillardf2a36f92004-11-08 17:55:01 +00003014 if (ctxt == NULL) return(NULL);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003015 if (ctxt->value == NULL) {
3016 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3017 return(NULL);
3018 }
3019 if (!xmlXPathStackIsNodeSet(ctxt)) {
3020 xmlXPathSetTypeError(ctxt);
3021 return(NULL);
3022 }
3023 obj = valuePop(ctxt);
3024 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00003025#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00003026 /* to fix memory leak of not clearing obj->user */
3027 if (obj->boolval && obj->user != NULL)
3028 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00003029#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003030 obj->nodesetval = NULL;
3031 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003032 return(ret);
3033}
3034
3035/**
3036 * xmlXPathPopExternal:
3037 * @ctxt: an XPath parser context
3038 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003039 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003040 * Check error with #xmlXPathCheckError.
3041 *
3042 * Returns the object
3043 */
3044void *
3045xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3046 xmlXPathObjectPtr obj;
3047 void * ret;
3048
Daniel Veillarda82b1822004-11-08 16:24:57 +00003049 if ((ctxt == NULL) || (ctxt->value == NULL)) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003050 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3051 return(NULL);
3052 }
3053 if (ctxt->value->type != XPATH_USERS) {
3054 xmlXPathSetTypeError(ctxt);
3055 return(NULL);
3056 }
3057 obj = valuePop(ctxt);
3058 ret = obj->user;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003059 obj->user = NULL;
3060 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003061 return(ret);
3062}
3063
Owen Taylor3473f882001-02-23 17:55:21 +00003064/*
3065 * Macros for accessing the content. Those should be used only by the parser,
3066 * and not exported.
3067 *
3068 * Dirty macros, i.e. one need to make assumption on the context to use them
3069 *
3070 * CUR_PTR return the current pointer to the xmlChar to be parsed.
3071 * CUR returns the current xmlChar value, i.e. a 8 bit value
3072 * in ISO-Latin or UTF-8.
3073 * This should be used internally by the parser
3074 * only to compare to ASCII values otherwise it would break when
3075 * running with UTF-8 encoding.
3076 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
3077 * to compare on ASCII based substring.
3078 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3079 * strings within the parser.
3080 * CURRENT Returns the current char value, with the full decoding of
3081 * UTF-8 if we are using this mode. It returns an int.
3082 * NEXT Skip to the next character, this does the proper decoding
3083 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
3084 * It returns the pointer to the current xmlChar.
3085 */
3086
3087#define CUR (*ctxt->cur)
3088#define SKIP(val) ctxt->cur += (val)
3089#define NXT(val) ctxt->cur[(val)]
3090#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00003091#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3092
3093#define COPY_BUF(l,b,i,v) \
3094 if (l == 1) b[i++] = (xmlChar) v; \
3095 else i += xmlCopyChar(l,&b[i],v)
3096
3097#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00003098
Daniel Veillard45490ae2008-07-29 09:13:19 +00003099#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00003100 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00003101
3102#define CURRENT (*ctxt->cur)
3103#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
3104
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003105
3106#ifndef DBL_DIG
3107#define DBL_DIG 16
3108#endif
3109#ifndef DBL_EPSILON
3110#define DBL_EPSILON 1E-9
3111#endif
3112
3113#define UPPER_DOUBLE 1E9
3114#define LOWER_DOUBLE 1E-5
William M. Brackca797882007-05-11 14:45:53 +00003115#define LOWER_DOUBLE_EXP 5
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003116
3117#define INTEGER_DIGITS DBL_DIG
William M. Brackca797882007-05-11 14:45:53 +00003118#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003119#define EXPONENT_DIGITS (3 + 2)
3120
3121/**
3122 * xmlXPathFormatNumber:
3123 * @number: number to format
3124 * @buffer: output buffer
3125 * @buffersize: size of output buffer
3126 *
3127 * Convert the number into a string representation.
3128 */
3129static void
3130xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3131{
Daniel Veillardcda96922001-08-21 10:56:31 +00003132 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003133 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003134 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00003135 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003136 break;
3137 case -1:
3138 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00003139 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003140 break;
3141 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003142 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003143 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00003144 snprintf(buffer, buffersize, "NaN");
Nick Wellnhofer8813f392017-09-21 00:11:26 +02003145 } else if (number == 0) {
3146 /* Omit sign for negative zero. */
Aleksey Sanin49cc9752002-06-14 17:07:10 +00003147 snprintf(buffer, buffersize, "0");
Nick Wellnhofer7482f412017-06-01 22:00:19 +02003148 } else if ((number > INT_MIN) && (number < INT_MAX) &&
3149 (number == (int) number)) {
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003150 char work[30];
3151 char *ptr, *cur;
Daniel Veillardb3d14912005-09-04 20:47:39 +00003152 int value = (int) number;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003153
3154 ptr = &buffer[0];
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003155 if (value == 0) {
3156 *ptr++ = '0';
3157 } else {
Daniel Veillardb3d14912005-09-04 20:47:39 +00003158 snprintf(work, 29, "%d", value);
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003159 cur = &work[0];
Daniel Veillardb3d14912005-09-04 20:47:39 +00003160 while ((*cur) && (ptr - buffer < buffersize)) {
3161 *ptr++ = *cur++;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003162 }
3163 }
3164 if (ptr - buffer < buffersize) {
3165 *ptr = 0;
3166 } else if (buffersize > 0) {
3167 ptr--;
3168 *ptr = 0;
3169 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003170 } else {
William M. Brackca797882007-05-11 14:45:53 +00003171 /*
3172 For the dimension of work,
3173 DBL_DIG is number of significant digits
3174 EXPONENT is only needed for "scientific notation"
3175 3 is sign, decimal point, and terminating zero
3176 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3177 Note that this dimension is slightly (a few characters)
3178 larger than actually necessary.
3179 */
3180 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
Bjorn Reese70a9da52001-04-21 16:57:29 +00003181 int integer_place, fraction_place;
3182 char *ptr;
3183 char *after_fraction;
3184 double absolute_value;
3185 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003186
Bjorn Reese70a9da52001-04-21 16:57:29 +00003187 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003188
Bjorn Reese70a9da52001-04-21 16:57:29 +00003189 /*
3190 * First choose format - scientific or regular floating point.
3191 * In either case, result is in work, and after_fraction points
3192 * just past the fractional part.
3193 */
3194 if ( ((absolute_value > UPPER_DOUBLE) ||
3195 (absolute_value < LOWER_DOUBLE)) &&
3196 (absolute_value != 0.0) ) {
3197 /* Use scientific notation */
3198 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3199 fraction_place = DBL_DIG - 1;
Daniel Veillard11ce4002006-03-10 00:36:23 +00003200 size = snprintf(work, sizeof(work),"%*.*e",
Bjorn Reese70a9da52001-04-21 16:57:29 +00003201 integer_place, fraction_place, number);
Daniel Veillard11ce4002006-03-10 00:36:23 +00003202 while ((size > 0) && (work[size] != 'e')) size--;
Daniel Veillard11ce4002006-03-10 00:36:23 +00003203
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003204 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00003205 else {
3206 /* Use regular notation */
William M. Brackca797882007-05-11 14:45:53 +00003207 if (absolute_value > 0.0) {
3208 integer_place = (int)log10(absolute_value);
3209 if (integer_place > 0)
3210 fraction_place = DBL_DIG - integer_place - 1;
3211 else
3212 fraction_place = DBL_DIG - integer_place;
3213 } else {
3214 fraction_place = 1;
3215 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00003216 size = snprintf(work, sizeof(work), "%0.*f",
3217 fraction_place, number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003218 }
3219
Daniel Veillardb9e4d5b2013-07-22 13:21:31 +08003220 /* Remove leading spaces sometimes inserted by snprintf */
3221 while (work[0] == ' ') {
3222 for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3223 size--;
3224 }
3225
Bjorn Reese70a9da52001-04-21 16:57:29 +00003226 /* Remove fractional trailing zeroes */
William M. Brackca797882007-05-11 14:45:53 +00003227 after_fraction = work + size;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003228 ptr = after_fraction;
3229 while (*(--ptr) == '0')
3230 ;
3231 if (*ptr != '.')
3232 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00003233 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003234
3235 /* Finally copy result back to caller */
3236 size = strlen(work) + 1;
3237 if (size > buffersize) {
3238 work[buffersize - 1] = 0;
3239 size = buffersize;
3240 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00003241 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003242 }
3243 break;
3244 }
3245}
3246
Owen Taylor3473f882001-02-23 17:55:21 +00003247
3248/************************************************************************
3249 * *
3250 * Routines to handle NodeSets *
3251 * *
3252 ************************************************************************/
3253
3254/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003255 * xmlXPathOrderDocElems:
3256 * @doc: an input document
3257 *
3258 * Call this routine to speed up XPath computation on static documents.
3259 * This stamps all the element nodes with the document order
3260 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00003261 * field, the value stored is actually - the node number (starting at -1)
3262 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003263 *
William M. Brack08171912003-12-29 02:52:11 +00003264 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003265 * of error.
3266 */
3267long
3268xmlXPathOrderDocElems(xmlDocPtr doc) {
Nick Wellnhoferd422b952017-10-09 13:37:42 +02003269 ptrdiff_t count = 0;
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003270 xmlNodePtr cur;
3271
3272 if (doc == NULL)
3273 return(-1);
3274 cur = doc->children;
3275 while (cur != NULL) {
3276 if (cur->type == XML_ELEMENT_NODE) {
3277 cur->content = (void *) (-(++count));
3278 if (cur->children != NULL) {
3279 cur = cur->children;
3280 continue;
3281 }
3282 }
3283 if (cur->next != NULL) {
3284 cur = cur->next;
3285 continue;
3286 }
3287 do {
3288 cur = cur->parent;
3289 if (cur == NULL)
3290 break;
3291 if (cur == (xmlNodePtr) doc) {
3292 cur = NULL;
3293 break;
3294 }
3295 if (cur->next != NULL) {
3296 cur = cur->next;
3297 break;
3298 }
3299 } while (cur != NULL);
3300 }
Nick Wellnhoferd422b952017-10-09 13:37:42 +02003301 return((long) count);
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003302}
3303
3304/**
Owen Taylor3473f882001-02-23 17:55:21 +00003305 * xmlXPathCmpNodes:
3306 * @node1: the first node
3307 * @node2: the second node
3308 *
3309 * Compare two nodes w.r.t document order
3310 *
3311 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00003312 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00003313 */
3314int
3315xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3316 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00003317 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00003318 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003319 xmlNodePtr cur, root;
3320
3321 if ((node1 == NULL) || (node2 == NULL))
3322 return(-2);
3323 /*
3324 * a couple of optimizations which will avoid computations in most cases
3325 */
William M. Brackee0b9822007-03-07 08:15:01 +00003326 if (node1 == node2) /* trivial case */
3327 return(0);
Daniel Veillardedfd5882003-03-07 14:20:40 +00003328 if (node1->type == XML_ATTRIBUTE_NODE) {
3329 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00003330 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00003331 node1 = node1->parent;
3332 }
3333 if (node2->type == XML_ATTRIBUTE_NODE) {
3334 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00003335 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00003336 node2 = node2->parent;
3337 }
3338 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00003339 if (attr1 == attr2) {
3340 /* not required, but we keep attributes in order */
3341 if (attr1 != 0) {
3342 cur = attrNode2->prev;
3343 while (cur != NULL) {
3344 if (cur == attrNode1)
3345 return (1);
3346 cur = cur->prev;
3347 }
3348 return (-1);
3349 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00003350 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00003351 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00003352 if (attr2 == 1)
3353 return(1);
3354 return(-1);
3355 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003356 if ((node1->type == XML_NAMESPACE_DECL) ||
3357 (node2->type == XML_NAMESPACE_DECL))
3358 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00003359 if (node1 == node2->prev)
3360 return(1);
3361 if (node1 == node2->next)
3362 return(-1);
3363
3364 /*
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003365 * Speedup using document order if available.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00003366 */
3367 if ((node1->type == XML_ELEMENT_NODE) &&
3368 (node2->type == XML_ELEMENT_NODE) &&
Nick Wellnhoferd422b952017-10-09 13:37:42 +02003369 (0 > (ptrdiff_t) node1->content) &&
3370 (0 > (ptrdiff_t) node2->content) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003371 (node1->doc == node2->doc)) {
Nick Wellnhoferd422b952017-10-09 13:37:42 +02003372 ptrdiff_t l1, l2;
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003373
Nick Wellnhoferd422b952017-10-09 13:37:42 +02003374 l1 = -((ptrdiff_t) node1->content);
3375 l2 = -((ptrdiff_t) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00003376 if (l1 < l2)
3377 return(1);
3378 if (l1 > l2)
3379 return(-1);
3380 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003381
Daniel Veillard7216cfd2002-11-08 15:10:00 +00003382 /*
Owen Taylor3473f882001-02-23 17:55:21 +00003383 * compute depth to root
3384 */
3385 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
Nick Wellnhofera0051992016-06-28 14:19:58 +02003386 if (cur->parent == node1)
Owen Taylor3473f882001-02-23 17:55:21 +00003387 return(1);
3388 depth2++;
3389 }
3390 root = cur;
3391 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
Nick Wellnhofera0051992016-06-28 14:19:58 +02003392 if (cur->parent == node2)
Owen Taylor3473f882001-02-23 17:55:21 +00003393 return(-1);
3394 depth1++;
3395 }
3396 /*
3397 * Distinct document (or distinct entities :-( ) case.
3398 */
3399 if (root != cur) {
3400 return(-2);
3401 }
3402 /*
3403 * get the nearest common ancestor.
3404 */
3405 while (depth1 > depth2) {
3406 depth1--;
3407 node1 = node1->parent;
3408 }
3409 while (depth2 > depth1) {
3410 depth2--;
3411 node2 = node2->parent;
3412 }
3413 while (node1->parent != node2->parent) {
3414 node1 = node1->parent;
3415 node2 = node2->parent;
3416 /* should not happen but just in case ... */
3417 if ((node1 == NULL) || (node2 == NULL))
3418 return(-2);
3419 }
3420 /*
3421 * Find who's first.
3422 */
Daniel Veillardf49be472004-02-17 11:48:18 +00003423 if (node1 == node2->prev)
3424 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00003425 if (node1 == node2->next)
3426 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00003427 /*
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003428 * Speedup using document order if available.
Daniel Veillardf49be472004-02-17 11:48:18 +00003429 */
3430 if ((node1->type == XML_ELEMENT_NODE) &&
3431 (node2->type == XML_ELEMENT_NODE) &&
Nick Wellnhoferd422b952017-10-09 13:37:42 +02003432 (0 > (ptrdiff_t) node1->content) &&
3433 (0 > (ptrdiff_t) node2->content) &&
Daniel Veillardf49be472004-02-17 11:48:18 +00003434 (node1->doc == node2->doc)) {
Nick Wellnhoferd422b952017-10-09 13:37:42 +02003435 ptrdiff_t l1, l2;
Daniel Veillardf49be472004-02-17 11:48:18 +00003436
Nick Wellnhoferd422b952017-10-09 13:37:42 +02003437 l1 = -((ptrdiff_t) node1->content);
3438 l2 = -((ptrdiff_t) node2->content);
Daniel Veillardf49be472004-02-17 11:48:18 +00003439 if (l1 < l2)
3440 return(1);
3441 if (l1 > l2)
3442 return(-1);
3443 }
3444
Owen Taylor3473f882001-02-23 17:55:21 +00003445 for (cur = node1->next;cur != NULL;cur = cur->next)
3446 if (cur == node2)
3447 return(1);
3448 return(-1); /* assume there is no sibling list corruption */
3449}
3450
3451/**
3452 * xmlXPathNodeSetSort:
3453 * @set: the node set
3454 *
3455 * Sort the node set in document order
3456 */
3457void
3458xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Vojtech Fried3e031b72012-08-24 16:52:44 +08003459#ifndef WITH_TIM_SORT
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003460 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003461 xmlNodePtr tmp;
Vojtech Fried3e031b72012-08-24 16:52:44 +08003462#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003463
3464 if (set == NULL)
3465 return;
3466
Vojtech Fried3e031b72012-08-24 16:52:44 +08003467#ifndef WITH_TIM_SORT
3468 /*
3469 * Use the old Shell's sort implementation to sort the node-set
3470 * Timsort ought to be quite faster
3471 */
Owen Taylor3473f882001-02-23 17:55:21 +00003472 len = set->nodeNr;
3473 for (incr = len / 2; incr > 0; incr /= 2) {
3474 for (i = incr; i < len; i++) {
3475 j = i - incr;
3476 while (j >= 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003477#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003478 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3479 set->nodeTab[j + incr]) == -1)
3480#else
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003481 if (xmlXPathCmpNodes(set->nodeTab[j],
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003482 set->nodeTab[j + incr]) == -1)
3483#endif
3484 {
Owen Taylor3473f882001-02-23 17:55:21 +00003485 tmp = set->nodeTab[j];
3486 set->nodeTab[j] = set->nodeTab[j + incr];
3487 set->nodeTab[j + incr] = tmp;
3488 j -= incr;
3489 } else
3490 break;
3491 }
3492 }
3493 }
Vojtech Fried3e031b72012-08-24 16:52:44 +08003494#else /* WITH_TIM_SORT */
3495 libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3496#endif /* WITH_TIM_SORT */
Owen Taylor3473f882001-02-23 17:55:21 +00003497}
3498
3499#define XML_NODESET_DEFAULT 10
3500/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003501 * xmlXPathNodeSetDupNs:
3502 * @node: the parent node of the namespace XPath node
3503 * @ns: the libxml namespace declaration node.
3504 *
3505 * Namespace node in libxml don't match the XPath semantic. In a node set
3506 * the namespace nodes are duplicated and the next pointer is set to the
3507 * parent node in the XPath semantic.
3508 *
3509 * Returns the newly created object.
3510 */
3511static xmlNodePtr
3512xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3513 xmlNsPtr cur;
3514
3515 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3516 return(NULL);
3517 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3518 return((xmlNodePtr) ns);
3519
3520 /*
3521 * Allocate a new Namespace and fill the fields.
3522 */
3523 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3524 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003525 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003526 return(NULL);
3527 }
3528 memset(cur, 0, sizeof(xmlNs));
3529 cur->type = XML_NAMESPACE_DECL;
3530 if (ns->href != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003531 cur->href = xmlStrdup(ns->href);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003532 if (ns->prefix != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003533 cur->prefix = xmlStrdup(ns->prefix);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003534 cur->next = (xmlNsPtr) node;
3535 return((xmlNodePtr) cur);
3536}
3537
3538/**
3539 * xmlXPathNodeSetFreeNs:
3540 * @ns: the XPath namespace node found in a nodeset.
3541 *
William M. Brack08171912003-12-29 02:52:11 +00003542 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003543 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00003544 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003545 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00003546void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003547xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3548 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3549 return;
3550
3551 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3552 if (ns->href != NULL)
3553 xmlFree((xmlChar *)ns->href);
3554 if (ns->prefix != NULL)
3555 xmlFree((xmlChar *)ns->prefix);
3556 xmlFree(ns);
3557 }
3558}
3559
3560/**
Owen Taylor3473f882001-02-23 17:55:21 +00003561 * xmlXPathNodeSetCreate:
3562 * @val: an initial xmlNodePtr, or NULL
3563 *
3564 * Create a new xmlNodeSetPtr of type double and of value @val
3565 *
3566 * Returns the newly created object.
3567 */
3568xmlNodeSetPtr
3569xmlXPathNodeSetCreate(xmlNodePtr val) {
3570 xmlNodeSetPtr ret;
3571
3572 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3573 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003574 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003575 return(NULL);
3576 }
3577 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3578 if (val != NULL) {
3579 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3580 sizeof(xmlNodePtr));
3581 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003582 xmlXPathErrMemory(NULL, "creating nodeset\n");
3583 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003584 return(NULL);
3585 }
3586 memset(ret->nodeTab, 0 ,
3587 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3588 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003589 if (val->type == XML_NAMESPACE_DECL) {
3590 xmlNsPtr ns = (xmlNsPtr) val;
3591
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003592 /* TODO: Check memory error. */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003593 ret->nodeTab[ret->nodeNr++] =
3594 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3595 } else
3596 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003597 }
3598 return(ret);
3599}
3600
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003601/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003602 * xmlXPathNodeSetContains:
3603 * @cur: the node-set
3604 * @val: the node
3605 *
3606 * checks whether @cur contains @val
3607 *
3608 * Returns true (1) if @cur contains @val, false (0) otherwise
3609 */
3610int
3611xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3612 int i;
3613
Daniel Veillarda82b1822004-11-08 16:24:57 +00003614 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003615 if (val->type == XML_NAMESPACE_DECL) {
3616 for (i = 0; i < cur->nodeNr; i++) {
3617 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3618 xmlNsPtr ns1, ns2;
3619
3620 ns1 = (xmlNsPtr) val;
3621 ns2 = (xmlNsPtr) cur->nodeTab[i];
3622 if (ns1 == ns2)
3623 return(1);
3624 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3625 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3626 return(1);
3627 }
3628 }
3629 } else {
3630 for (i = 0; i < cur->nodeNr; i++) {
3631 if (cur->nodeTab[i] == val)
3632 return(1);
3633 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003634 }
3635 return(0);
3636}
3637
3638/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003639 * xmlXPathNodeSetAddNs:
3640 * @cur: the initial node set
3641 * @node: the hosting node
3642 * @ns: a the namespace node
3643 *
3644 * add a new namespace node to an existing NodeSet
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003645 *
3646 * Returns 0 in case of success and -1 in case of error
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003647 */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003648int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003649xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3650 int i;
3651
Daniel Veillard45490ae2008-07-29 09:13:19 +00003652
Daniel Veillarda82b1822004-11-08 16:24:57 +00003653 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3654 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003655 (node->type != XML_ELEMENT_NODE))
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003656 return(-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003657
William M. Brack08171912003-12-29 02:52:11 +00003658 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003659 /*
William M. Brack08171912003-12-29 02:52:11 +00003660 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003661 */
3662 for (i = 0;i < cur->nodeNr;i++) {
3663 if ((cur->nodeTab[i] != NULL) &&
3664 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00003665 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003666 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003667 return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003668 }
3669
3670 /*
3671 * grow the nodeTab if needed
3672 */
3673 if (cur->nodeMax == 0) {
3674 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3675 sizeof(xmlNodePtr));
3676 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003677 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003678 return(-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003679 }
3680 memset(cur->nodeTab, 0 ,
3681 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3682 cur->nodeMax = XML_NODESET_DEFAULT;
3683 } else if (cur->nodeNr == cur->nodeMax) {
3684 xmlNodePtr *temp;
3685
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003686 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3687 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003688 return(-1);
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003689 }
Chris Evansd7958b22011-03-23 08:13:06 +08003690 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003691 sizeof(xmlNodePtr));
3692 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003693 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003694 return(-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003695 }
Chris Evansd7958b22011-03-23 08:13:06 +08003696 cur->nodeMax *= 2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003697 cur->nodeTab = temp;
3698 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003699 /* TODO: Check memory error. */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003700 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003701 return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003702}
3703
3704/**
Owen Taylor3473f882001-02-23 17:55:21 +00003705 * xmlXPathNodeSetAdd:
3706 * @cur: the initial node set
3707 * @val: a new xmlNodePtr
3708 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003709 * add a new xmlNodePtr to an existing NodeSet
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003710 *
3711 * Returns 0 in case of success, and -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00003712 */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003713int
Owen Taylor3473f882001-02-23 17:55:21 +00003714xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3715 int i;
3716
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003717 if ((cur == NULL) || (val == NULL)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003718
William M. Brack08171912003-12-29 02:52:11 +00003719 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003720 /*
Shlomi Fishd5bd2a92016-04-03 05:14:44 +03003721 * prevent duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00003722 */
3723 for (i = 0;i < cur->nodeNr;i++)
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003724 if (cur->nodeTab[i] == val) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003725
3726 /*
3727 * grow the nodeTab if needed
3728 */
3729 if (cur->nodeMax == 0) {
3730 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3731 sizeof(xmlNodePtr));
3732 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003733 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003734 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003735 }
3736 memset(cur->nodeTab, 0 ,
3737 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3738 cur->nodeMax = XML_NODESET_DEFAULT;
3739 } else if (cur->nodeNr == cur->nodeMax) {
3740 xmlNodePtr *temp;
3741
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003742 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3743 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003744 return(-1);
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003745 }
Daniel Veillard0cbeb502010-11-15 12:06:29 +01003746 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003747 sizeof(xmlNodePtr));
3748 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003749 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003750 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003751 }
Daniel Veillard0cbeb502010-11-15 12:06:29 +01003752 cur->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003753 cur->nodeTab = temp;
3754 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003755 if (val->type == XML_NAMESPACE_DECL) {
3756 xmlNsPtr ns = (xmlNsPtr) val;
3757
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003758 /* TODO: Check memory error. */
Daniel Veillard45490ae2008-07-29 09:13:19 +00003759 cur->nodeTab[cur->nodeNr++] =
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003760 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3761 } else
3762 cur->nodeTab[cur->nodeNr++] = val;
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003763 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003764}
3765
3766/**
3767 * xmlXPathNodeSetAddUnique:
3768 * @cur: the initial node set
3769 * @val: a new xmlNodePtr
3770 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003771 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00003772 * when we are sure the node is not already in the set.
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003773 *
3774 * Returns 0 in case of success and -1 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +00003775 */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003776int
Owen Taylor3473f882001-02-23 17:55:21 +00003777xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003778 if ((cur == NULL) || (val == NULL)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003779
William M. Brack08171912003-12-29 02:52:11 +00003780 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003781 /*
3782 * grow the nodeTab if needed
3783 */
3784 if (cur->nodeMax == 0) {
3785 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3786 sizeof(xmlNodePtr));
3787 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003788 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003789 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003790 }
3791 memset(cur->nodeTab, 0 ,
3792 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3793 cur->nodeMax = XML_NODESET_DEFAULT;
3794 } else if (cur->nodeNr == cur->nodeMax) {
3795 xmlNodePtr *temp;
3796
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003797 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3798 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003799 return(-1);
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003800 }
Chris Evansd7958b22011-03-23 08:13:06 +08003801 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003802 sizeof(xmlNodePtr));
3803 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003804 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003805 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003806 }
3807 cur->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08003808 cur->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003809 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003810 if (val->type == XML_NAMESPACE_DECL) {
3811 xmlNsPtr ns = (xmlNsPtr) val;
3812
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003813 /* TODO: Check memory error. */
Daniel Veillard45490ae2008-07-29 09:13:19 +00003814 cur->nodeTab[cur->nodeNr++] =
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003815 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3816 } else
3817 cur->nodeTab[cur->nodeNr++] = val;
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003818 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003819}
3820
3821/**
3822 * xmlXPathNodeSetMerge:
3823 * @val1: the first NodeSet or NULL
3824 * @val2: the second NodeSet
3825 *
3826 * Merges two nodesets, all nodes from @val2 are added to @val1
3827 * if @val1 is NULL, a new set is created and copied from @val2
3828 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003829 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003830 */
3831xmlNodeSetPtr
3832xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003833 int i, j, initNr, skip;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003834 xmlNodePtr n1, n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003835
3836 if (val2 == NULL) return(val1);
3837 if (val1 == NULL) {
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003838 val1 = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00003839 if (val1 == NULL)
3840 return (NULL);
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003841#if 0
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003842 /*
3843 * TODO: The optimization won't work in every case, since
3844 * those nasty namespace nodes need to be added with
3845 * xmlXPathNodeSetDupNs() to the set; thus a pure
3846 * memcpy is not possible.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00003847 * If there was a flag on the nodesetval, indicating that
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003848 * some temporary nodes are in, that would be helpful.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003849 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00003850 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003851 * Optimization: Create an equally sized node-set
3852 * and memcpy the content.
3853 */
3854 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3855 if (val1 == NULL)
3856 return(NULL);
3857 if (val2->nodeNr != 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003858 if (val2->nodeNr == 1)
3859 *(val1->nodeTab) = *(val2->nodeTab);
3860 else {
3861 memcpy(val1->nodeTab, val2->nodeTab,
3862 val2->nodeNr * sizeof(xmlNodePtr));
3863 }
3864 val1->nodeNr = val2->nodeNr;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003865 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003866 return(val1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003867#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003868 }
3869
William M. Brack08171912003-12-29 02:52:11 +00003870 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003871 initNr = val1->nodeNr;
3872
3873 for (i = 0;i < val2->nodeNr;i++) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00003874 n2 = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00003875 /*
William M. Brack08171912003-12-29 02:52:11 +00003876 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00003877 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003878 skip = 0;
3879 for (j = 0; j < initNr; j++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003880 n1 = val1->nodeTab[j];
3881 if (n1 == n2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003882 skip = 1;
3883 break;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003884 } else if ((n1->type == XML_NAMESPACE_DECL) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +00003885 (n2->type == XML_NAMESPACE_DECL)) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003886 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3887 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3888 ((xmlNsPtr) n2)->prefix)))
3889 {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003890 skip = 1;
3891 break;
3892 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003893 }
3894 }
3895 if (skip)
3896 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00003897
3898 /*
3899 * grow the nodeTab if needed
3900 */
3901 if (val1->nodeMax == 0) {
3902 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3903 sizeof(xmlNodePtr));
3904 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003905 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003906 return(NULL);
3907 }
3908 memset(val1->nodeTab, 0 ,
3909 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3910 val1->nodeMax = XML_NODESET_DEFAULT;
3911 } else if (val1->nodeNr == val1->nodeMax) {
3912 xmlNodePtr *temp;
3913
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003914 if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3915 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3916 return(NULL);
3917 }
Chris Evansd7958b22011-03-23 08:13:06 +08003918 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003919 sizeof(xmlNodePtr));
3920 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003921 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003922 return(NULL);
3923 }
3924 val1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08003925 val1->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003926 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003927 if (n2->type == XML_NAMESPACE_DECL) {
3928 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003929
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003930 /* TODO: Check memory error. */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003931 val1->nodeTab[val1->nodeNr++] =
3932 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3933 } else
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003934 val1->nodeTab[val1->nodeNr++] = n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003935 }
3936
3937 return(val1);
3938}
3939
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003940
3941/**
3942 * xmlXPathNodeSetMergeAndClear:
3943 * @set1: the first NodeSet or NULL
3944 * @set2: the second NodeSet
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003945 *
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003946 * Merges two nodesets, all nodes from @set2 are added to @set1.
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003947 * Checks for duplicate nodes. Clears set2.
3948 *
3949 * Returns @set1 once extended or NULL in case of error.
3950 */
3951static xmlNodeSetPtr
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003952xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003953{
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003954 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003955 int i, j, initNbSet1;
3956 xmlNodePtr n1, n2;
3957
Daniel Veillard45490ae2008-07-29 09:13:19 +00003958 initNbSet1 = set1->nodeNr;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003959 for (i = 0;i < set2->nodeNr;i++) {
3960 n2 = set2->nodeTab[i];
3961 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003962 * Skip duplicates.
3963 */
3964 for (j = 0; j < initNbSet1; j++) {
3965 n1 = set1->nodeTab[j];
Daniel Veillard45490ae2008-07-29 09:13:19 +00003966 if (n1 == n2) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003967 goto skip_node;
3968 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3969 (n2->type == XML_NAMESPACE_DECL))
Daniel Veillard45490ae2008-07-29 09:13:19 +00003970 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003971 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3972 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3973 ((xmlNsPtr) n2)->prefix)))
3974 {
3975 /*
3976 * Free the namespace node.
3977 */
3978 set2->nodeTab[i] = NULL;
3979 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3980 goto skip_node;
3981 }
3982 }
3983 }
3984 /*
3985 * grow the nodeTab if needed
3986 */
3987 if (set1->nodeMax == 0) {
3988 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3989 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3990 if (set1->nodeTab == NULL) {
3991 xmlXPathErrMemory(NULL, "merging nodeset\n");
3992 return(NULL);
3993 }
3994 memset(set1->nodeTab, 0,
3995 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3996 set1->nodeMax = XML_NODESET_DEFAULT;
3997 } else if (set1->nodeNr >= set1->nodeMax) {
3998 xmlNodePtr *temp;
Daniel Veillard45490ae2008-07-29 09:13:19 +00003999
Daniel Veillardcd852ad2012-07-30 10:12:18 +08004000 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4001 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4002 return(NULL);
4003 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004004 temp = (xmlNodePtr *) xmlRealloc(
Chris Evansd7958b22011-03-23 08:13:06 +08004005 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004006 if (temp == NULL) {
4007 xmlXPathErrMemory(NULL, "merging nodeset\n");
4008 return(NULL);
4009 }
4010 set1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08004011 set1->nodeMax *= 2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004012 }
Nick Wellnhofer9d08b342017-05-21 16:46:12 +02004013 set1->nodeTab[set1->nodeNr++] = n2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004014skip_node:
4015 {}
4016 }
4017 }
4018 set2->nodeNr = 0;
4019 return(set1);
4020}
4021
4022/**
4023 * xmlXPathNodeSetMergeAndClearNoDupls:
4024 * @set1: the first NodeSet or NULL
4025 * @set2: the second NodeSet
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004026 *
Haibo Huangcfd91dc2020-07-30 23:01:33 -07004027 * Merges two nodesets, all nodes from @set2 are added to @set1.
4028 * Doesn't check for duplicate nodes. Clears set2.
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004029 *
4030 * Returns @set1 once extended or NULL in case of error.
4031 */
4032static xmlNodeSetPtr
Haibo Huangcfd91dc2020-07-30 23:01:33 -07004033xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004034{
Haibo Huangcfd91dc2020-07-30 23:01:33 -07004035 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004036 int i;
4037 xmlNodePtr n2;
4038
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004039 for (i = 0;i < set2->nodeNr;i++) {
4040 n2 = set2->nodeTab[i];
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004041 if (set1->nodeMax == 0) {
4042 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4043 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4044 if (set1->nodeTab == NULL) {
4045 xmlXPathErrMemory(NULL, "merging nodeset\n");
4046 return(NULL);
4047 }
4048 memset(set1->nodeTab, 0,
4049 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4050 set1->nodeMax = XML_NODESET_DEFAULT;
4051 } else if (set1->nodeNr >= set1->nodeMax) {
4052 xmlNodePtr *temp;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004053
Daniel Veillardcd852ad2012-07-30 10:12:18 +08004054 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4055 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4056 return(NULL);
4057 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004058 temp = (xmlNodePtr *) xmlRealloc(
Chris Evansd7958b22011-03-23 08:13:06 +08004059 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004060 if (temp == NULL) {
4061 xmlXPathErrMemory(NULL, "merging nodeset\n");
4062 return(NULL);
4063 }
4064 set1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08004065 set1->nodeMax *= 2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004066 }
4067 set1->nodeTab[set1->nodeNr++] = n2;
4068 }
4069 }
4070 set2->nodeNr = 0;
4071 return(set1);
4072}
Daniel Veillard75be0132002-03-13 10:03:35 +00004073
4074/**
Owen Taylor3473f882001-02-23 17:55:21 +00004075 * xmlXPathNodeSetDel:
4076 * @cur: the initial node set
4077 * @val: an xmlNodePtr
4078 *
4079 * Removes an xmlNodePtr from an existing NodeSet
4080 */
4081void
4082xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4083 int i;
4084
4085 if (cur == NULL) return;
4086 if (val == NULL) return;
4087
4088 /*
William M. Brack08171912003-12-29 02:52:11 +00004089 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00004090 */
4091 for (i = 0;i < cur->nodeNr;i++)
4092 if (cur->nodeTab[i] == val) break;
4093
William M. Brack08171912003-12-29 02:52:11 +00004094 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00004095#ifdef DEBUG
Daniel Veillard45490ae2008-07-29 09:13:19 +00004096 xmlGenericError(xmlGenericErrorContext,
Owen Taylor3473f882001-02-23 17:55:21 +00004097 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4098 val->name);
4099#endif
4100 return;
4101 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004102 if ((cur->nodeTab[i] != NULL) &&
4103 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4104 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004105 cur->nodeNr--;
4106 for (;i < cur->nodeNr;i++)
4107 cur->nodeTab[i] = cur->nodeTab[i + 1];
4108 cur->nodeTab[cur->nodeNr] = NULL;
4109}
4110
4111/**
4112 * xmlXPathNodeSetRemove:
4113 * @cur: the initial node set
4114 * @val: the index to remove
4115 *
4116 * Removes an entry from an existing NodeSet list.
4117 */
4118void
4119xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4120 if (cur == NULL) return;
4121 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004122 if ((cur->nodeTab[val] != NULL) &&
4123 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4124 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00004125 cur->nodeNr--;
4126 for (;val < cur->nodeNr;val++)
4127 cur->nodeTab[val] = cur->nodeTab[val + 1];
4128 cur->nodeTab[cur->nodeNr] = NULL;
4129}
4130
4131/**
4132 * xmlXPathFreeNodeSet:
4133 * @obj: the xmlNodeSetPtr to free
4134 *
4135 * Free the NodeSet compound (not the actual nodes !).
4136 */
4137void
4138xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4139 if (obj == NULL) return;
4140 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004141 int i;
4142
William M. Brack08171912003-12-29 02:52:11 +00004143 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004144 for (i = 0;i < obj->nodeNr;i++)
4145 if ((obj->nodeTab[i] != NULL) &&
4146 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4147 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004148 xmlFree(obj->nodeTab);
4149 }
Owen Taylor3473f882001-02-23 17:55:21 +00004150 xmlFree(obj);
4151}
4152
4153/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004154 * xmlXPathNodeSetClearFromPos:
4155 * @set: the node set to be cleared
4156 * @pos: the start position to clear from
Daniel Veillard45490ae2008-07-29 09:13:19 +00004157 *
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004158 * Clears the list from temporary XPath objects (e.g. namespace nodes
4159 * are feed) starting with the entry at @pos, but does *not* free the list
4160 * itself. Sets the length of the list to @pos.
4161 */
4162static void
4163xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4164{
Nick Wellnhofer95a92492017-05-21 15:18:58 +02004165 if ((set == NULL) || (pos >= set->nodeNr))
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004166 return;
4167 else if ((hasNsNodes)) {
4168 int i;
4169 xmlNodePtr node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004170
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004171 for (i = pos; i < set->nodeNr; i++) {
4172 node = set->nodeTab[i];
4173 if ((node != NULL) &&
4174 (node->type == XML_NAMESPACE_DECL))
4175 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
Daniel Veillard45490ae2008-07-29 09:13:19 +00004176 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004177 }
4178 set->nodeNr = pos;
4179}
4180
4181/**
Nick Wellnhofer95a92492017-05-21 15:18:58 +02004182 * xmlXPathNodeSetClear:
4183 * @set: the node set to clear
4184 *
4185 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4186 * are feed), but does *not* free the list itself. Sets the length of the
4187 * list to 0.
4188 */
4189static void
4190xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4191{
4192 xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4193}
4194
4195/**
4196 * xmlXPathNodeSetKeepLast:
4197 * @set: the node set to be cleared
4198 *
4199 * Move the last node to the first position and clear temporary XPath objects
4200 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4201 * to 1.
4202 */
4203static void
4204xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4205{
4206 int i;
4207 xmlNodePtr node;
4208
4209 if ((set == NULL) || (set->nodeNr <= 1))
4210 return;
4211 for (i = 0; i < set->nodeNr - 1; i++) {
4212 node = set->nodeTab[i];
4213 if ((node != NULL) &&
4214 (node->type == XML_NAMESPACE_DECL))
4215 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4216 }
4217 set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4218 set->nodeNr = 1;
4219}
4220
4221/**
Owen Taylor3473f882001-02-23 17:55:21 +00004222 * xmlXPathFreeValueTree:
4223 * @obj: the xmlNodeSetPtr to free
4224 *
4225 * Free the NodeSet compound and the actual tree, this is different
4226 * from xmlXPathFreeNodeSet()
4227 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004228static void
Owen Taylor3473f882001-02-23 17:55:21 +00004229xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4230 int i;
4231
4232 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00004233
4234 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004235 for (i = 0;i < obj->nodeNr;i++) {
4236 if (obj->nodeTab[i] != NULL) {
4237 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4238 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4239 } else {
4240 xmlFreeNodeList(obj->nodeTab[i]);
4241 }
4242 }
4243 }
Owen Taylor3473f882001-02-23 17:55:21 +00004244 xmlFree(obj->nodeTab);
4245 }
Owen Taylor3473f882001-02-23 17:55:21 +00004246 xmlFree(obj);
4247}
4248
4249#if defined(DEBUG) || defined(DEBUG_STEP)
4250/**
4251 * xmlGenericErrorContextNodeSet:
4252 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00004253 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00004254 *
4255 * Quick display of a NodeSet
4256 */
4257void
4258xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4259 int i;
4260
4261 if (output == NULL) output = xmlGenericErrorContext;
4262 if (obj == NULL) {
4263 fprintf(output, "NodeSet == NULL !\n");
4264 return;
4265 }
4266 if (obj->nodeNr == 0) {
4267 fprintf(output, "NodeSet is empty\n");
4268 return;
4269 }
4270 if (obj->nodeTab == NULL) {
4271 fprintf(output, " nodeTab == NULL !\n");
4272 return;
4273 }
4274 for (i = 0; i < obj->nodeNr; i++) {
4275 if (obj->nodeTab[i] == NULL) {
4276 fprintf(output, " NULL !\n");
4277 return;
4278 }
4279 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4280 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4281 fprintf(output, " /");
4282 else if (obj->nodeTab[i]->name == NULL)
4283 fprintf(output, " noname!");
4284 else fprintf(output, " %s", obj->nodeTab[i]->name);
4285 }
4286 fprintf(output, "\n");
4287}
4288#endif
4289
4290/**
4291 * xmlXPathNewNodeSet:
4292 * @val: the NodePtr value
4293 *
4294 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4295 * it with the single Node @val
4296 *
4297 * Returns the newly created object.
4298 */
4299xmlXPathObjectPtr
4300xmlXPathNewNodeSet(xmlNodePtr val) {
4301 xmlXPathObjectPtr ret;
4302
4303 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4304 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004305 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004306 return(NULL);
4307 }
4308 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4309 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00004310 ret->boolval = 0;
Haibo Huangcfd91dc2020-07-30 23:01:33 -07004311 /* TODO: Check memory error. */
Owen Taylor3473f882001-02-23 17:55:21 +00004312 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00004313 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004314#ifdef XP_DEBUG_OBJ_USAGE
4315 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4316#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004317 return(ret);
4318}
4319
4320/**
4321 * xmlXPathNewValueTree:
4322 * @val: the NodePtr value
4323 *
4324 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4325 * it with the tree root @val
4326 *
4327 * Returns the newly created object.
4328 */
4329xmlXPathObjectPtr
4330xmlXPathNewValueTree(xmlNodePtr val) {
4331 xmlXPathObjectPtr ret;
4332
4333 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4334 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004335 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004336 return(NULL);
4337 }
4338 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4339 ret->type = XPATH_XSLT_TREE;
Elliott Hughes7fbecab2019-01-10 16:42:03 -08004340 ret->boolval = 1;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00004341 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00004342 ret->nodesetval = xmlXPathNodeSetCreate(val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004343#ifdef XP_DEBUG_OBJ_USAGE
4344 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4345#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004346 return(ret);
4347}
4348
4349/**
4350 * xmlXPathNewNodeSetList:
4351 * @val: an existing NodeSet
4352 *
4353 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4354 * it with the Nodeset @val
4355 *
4356 * Returns the newly created object.
4357 */
4358xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004359xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4360{
Owen Taylor3473f882001-02-23 17:55:21 +00004361 xmlXPathObjectPtr ret;
4362 int i;
4363
4364 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004365 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00004366 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004367 ret = xmlXPathNewNodeSet(NULL);
4368 else {
4369 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004370 if (ret) {
4371 for (i = 1; i < val->nodeNr; ++i) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07004372 /* TODO: Propagate memory error. */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004373 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4374 < 0) break;
4375 }
4376 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004377 }
Owen Taylor3473f882001-02-23 17:55:21 +00004378
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004379 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004380}
4381
4382/**
4383 * xmlXPathWrapNodeSet:
4384 * @val: the NodePtr value
4385 *
4386 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4387 *
4388 * Returns the newly created object.
4389 */
4390xmlXPathObjectPtr
4391xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4392 xmlXPathObjectPtr ret;
4393
4394 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4395 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004396 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004397 return(NULL);
4398 }
4399 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4400 ret->type = XPATH_NODESET;
4401 ret->nodesetval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004402#ifdef XP_DEBUG_OBJ_USAGE
4403 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4404#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004405 return(ret);
4406}
4407
4408/**
4409 * xmlXPathFreeNodeSetList:
4410 * @obj: an existing NodeSetList object
4411 *
4412 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4413 * the list contrary to xmlXPathFreeObject().
4414 */
4415void
4416xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4417 if (obj == NULL) return;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004418#ifdef XP_DEBUG_OBJ_USAGE
4419 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4420#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004421 xmlFree(obj);
4422}
4423
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004424/**
4425 * xmlXPathDifference:
4426 * @nodes1: a node-set
4427 * @nodes2: a node-set
4428 *
4429 * Implements the EXSLT - Sets difference() function:
4430 * node-set set:difference (node-set, node-set)
4431 *
4432 * Returns the difference between the two node sets, or nodes1 if
4433 * nodes2 is empty
4434 */
4435xmlNodeSetPtr
4436xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4437 xmlNodeSetPtr ret;
4438 int i, l1;
4439 xmlNodePtr cur;
4440
4441 if (xmlXPathNodeSetIsEmpty(nodes2))
4442 return(nodes1);
4443
Haibo Huangcfd91dc2020-07-30 23:01:33 -07004444 /* TODO: Check memory error. */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004445 ret = xmlXPathNodeSetCreate(NULL);
4446 if (xmlXPathNodeSetIsEmpty(nodes1))
4447 return(ret);
4448
4449 l1 = xmlXPathNodeSetGetLength(nodes1);
4450
4451 for (i = 0; i < l1; i++) {
4452 cur = xmlXPathNodeSetItem(nodes1, i);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004453 if (!xmlXPathNodeSetContains(nodes2, cur)) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07004454 /* TODO: Propagate memory error. */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004455 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4456 break;
4457 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004458 }
4459 return(ret);
4460}
4461
4462/**
4463 * xmlXPathIntersection:
4464 * @nodes1: a node-set
4465 * @nodes2: a node-set
4466 *
4467 * Implements the EXSLT - Sets intersection() function:
4468 * node-set set:intersection (node-set, node-set)
4469 *
4470 * Returns a node set comprising the nodes that are within both the
4471 * node sets passed as arguments
4472 */
4473xmlNodeSetPtr
4474xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4475 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4476 int i, l1;
4477 xmlNodePtr cur;
4478
Daniel Veillardf88d8492008-04-01 08:00:31 +00004479 if (ret == NULL)
4480 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004481 if (xmlXPathNodeSetIsEmpty(nodes1))
4482 return(ret);
4483 if (xmlXPathNodeSetIsEmpty(nodes2))
4484 return(ret);
4485
4486 l1 = xmlXPathNodeSetGetLength(nodes1);
4487
4488 for (i = 0; i < l1; i++) {
4489 cur = xmlXPathNodeSetItem(nodes1, i);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004490 if (xmlXPathNodeSetContains(nodes2, cur)) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07004491 /* TODO: Propagate memory error. */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004492 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4493 break;
4494 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004495 }
4496 return(ret);
4497}
4498
4499/**
4500 * xmlXPathDistinctSorted:
4501 * @nodes: a node-set, sorted by document order
4502 *
4503 * Implements the EXSLT - Sets distinct() function:
4504 * node-set set:distinct (node-set)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004505 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004506 * Returns a subset of the nodes contained in @nodes, or @nodes if
4507 * it is empty
4508 */
4509xmlNodeSetPtr
4510xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4511 xmlNodeSetPtr ret;
4512 xmlHashTablePtr hash;
4513 int i, l;
4514 xmlChar * strval;
4515 xmlNodePtr cur;
4516
4517 if (xmlXPathNodeSetIsEmpty(nodes))
4518 return(nodes);
4519
4520 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004521 if (ret == NULL)
4522 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004523 l = xmlXPathNodeSetGetLength(nodes);
4524 hash = xmlHashCreate (l);
4525 for (i = 0; i < l; i++) {
4526 cur = xmlXPathNodeSetItem(nodes, i);
4527 strval = xmlXPathCastNodeToString(cur);
4528 if (xmlHashLookup(hash, strval) == NULL) {
4529 xmlHashAddEntry(hash, strval, strval);
Haibo Huangcfd91dc2020-07-30 23:01:33 -07004530 /* TODO: Propagate memory error. */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004531 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4532 break;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004533 } else {
4534 xmlFree(strval);
4535 }
4536 }
Nick Wellnhofere03f0a12017-11-09 16:42:47 +01004537 xmlHashFree(hash, xmlHashDefaultDeallocator);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004538 return(ret);
4539}
4540
4541/**
4542 * xmlXPathDistinct:
4543 * @nodes: a node-set
4544 *
4545 * Implements the EXSLT - Sets distinct() function:
4546 * node-set set:distinct (node-set)
4547 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4548 * is called with the sorted node-set
4549 *
4550 * Returns a subset of the nodes contained in @nodes, or @nodes if
4551 * it is empty
4552 */
4553xmlNodeSetPtr
4554xmlXPathDistinct (xmlNodeSetPtr nodes) {
4555 if (xmlXPathNodeSetIsEmpty(nodes))
4556 return(nodes);
4557
4558 xmlXPathNodeSetSort(nodes);
4559 return(xmlXPathDistinctSorted(nodes));
4560}
4561
4562/**
4563 * xmlXPathHasSameNodes:
4564 * @nodes1: a node-set
4565 * @nodes2: a node-set
4566 *
4567 * Implements the EXSLT - Sets has-same-nodes function:
4568 * boolean set:has-same-node(node-set, node-set)
4569 *
4570 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4571 * otherwise
4572 */
4573int
4574xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4575 int i, l;
4576 xmlNodePtr cur;
4577
4578 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4579 xmlXPathNodeSetIsEmpty(nodes2))
4580 return(0);
4581
4582 l = xmlXPathNodeSetGetLength(nodes1);
4583 for (i = 0; i < l; i++) {
4584 cur = xmlXPathNodeSetItem(nodes1, i);
4585 if (xmlXPathNodeSetContains(nodes2, cur))
4586 return(1);
4587 }
4588 return(0);
4589}
4590
4591/**
4592 * xmlXPathNodeLeadingSorted:
4593 * @nodes: a node-set, sorted by document order
4594 * @node: a node
4595 *
4596 * Implements the EXSLT - Sets leading() function:
4597 * node-set set:leading (node-set, node-set)
4598 *
4599 * Returns the nodes in @nodes that precede @node in document order,
4600 * @nodes if @node is NULL or an empty node-set if @nodes
4601 * doesn't contain @node
4602 */
4603xmlNodeSetPtr
4604xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4605 int i, l;
4606 xmlNodePtr cur;
4607 xmlNodeSetPtr ret;
4608
4609 if (node == NULL)
4610 return(nodes);
4611
4612 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004613 if (ret == NULL)
4614 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004615 if (xmlXPathNodeSetIsEmpty(nodes) ||
4616 (!xmlXPathNodeSetContains(nodes, node)))
4617 return(ret);
4618
4619 l = xmlXPathNodeSetGetLength(nodes);
4620 for (i = 0; i < l; i++) {
4621 cur = xmlXPathNodeSetItem(nodes, i);
4622 if (cur == node)
4623 break;
Haibo Huangcfd91dc2020-07-30 23:01:33 -07004624 /* TODO: Propagate memory error. */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004625 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4626 break;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004627 }
4628 return(ret);
4629}
4630
4631/**
4632 * xmlXPathNodeLeading:
4633 * @nodes: a node-set
4634 * @node: a node
4635 *
4636 * Implements the EXSLT - Sets leading() function:
4637 * node-set set:leading (node-set, node-set)
4638 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4639 * is called.
4640 *
4641 * Returns the nodes in @nodes that precede @node in document order,
4642 * @nodes if @node is NULL or an empty node-set if @nodes
4643 * doesn't contain @node
4644 */
4645xmlNodeSetPtr
4646xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4647 xmlXPathNodeSetSort(nodes);
4648 return(xmlXPathNodeLeadingSorted(nodes, node));
4649}
4650
4651/**
4652 * xmlXPathLeadingSorted:
4653 * @nodes1: a node-set, sorted by document order
4654 * @nodes2: a node-set, sorted by document order
4655 *
4656 * Implements the EXSLT - Sets leading() function:
4657 * node-set set:leading (node-set, node-set)
4658 *
4659 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4660 * in document order, @nodes1 if @nodes2 is NULL or empty or
4661 * an empty node-set if @nodes1 doesn't contain @nodes2
4662 */
4663xmlNodeSetPtr
4664xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4665 if (xmlXPathNodeSetIsEmpty(nodes2))
4666 return(nodes1);
4667 return(xmlXPathNodeLeadingSorted(nodes1,
4668 xmlXPathNodeSetItem(nodes2, 1)));
4669}
4670
4671/**
4672 * xmlXPathLeading:
4673 * @nodes1: a node-set
4674 * @nodes2: a node-set
4675 *
4676 * Implements the EXSLT - Sets leading() function:
4677 * node-set set:leading (node-set, node-set)
4678 * @nodes1 and @nodes2 are sorted by document order, then
4679 * #exslSetsLeadingSorted is called.
4680 *
4681 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4682 * in document order, @nodes1 if @nodes2 is NULL or empty or
4683 * an empty node-set if @nodes1 doesn't contain @nodes2
4684 */
4685xmlNodeSetPtr
4686xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4687 if (xmlXPathNodeSetIsEmpty(nodes2))
4688 return(nodes1);
4689 if (xmlXPathNodeSetIsEmpty(nodes1))
4690 return(xmlXPathNodeSetCreate(NULL));
4691 xmlXPathNodeSetSort(nodes1);
4692 xmlXPathNodeSetSort(nodes2);
4693 return(xmlXPathNodeLeadingSorted(nodes1,
4694 xmlXPathNodeSetItem(nodes2, 1)));
4695}
4696
4697/**
4698 * xmlXPathNodeTrailingSorted:
4699 * @nodes: a node-set, sorted by document order
4700 * @node: a node
4701 *
4702 * Implements the EXSLT - Sets trailing() function:
4703 * node-set set:trailing (node-set, node-set)
4704 *
4705 * Returns the nodes in @nodes that follow @node in document order,
4706 * @nodes if @node is NULL or an empty node-set if @nodes
4707 * doesn't contain @node
4708 */
4709xmlNodeSetPtr
4710xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4711 int i, l;
4712 xmlNodePtr cur;
4713 xmlNodeSetPtr ret;
4714
4715 if (node == NULL)
4716 return(nodes);
4717
4718 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004719 if (ret == NULL)
4720 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004721 if (xmlXPathNodeSetIsEmpty(nodes) ||
4722 (!xmlXPathNodeSetContains(nodes, node)))
4723 return(ret);
4724
4725 l = xmlXPathNodeSetGetLength(nodes);
William M. Brack97ac8192007-06-06 17:19:24 +00004726 for (i = l - 1; i >= 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004727 cur = xmlXPathNodeSetItem(nodes, i);
4728 if (cur == node)
4729 break;
Haibo Huangcfd91dc2020-07-30 23:01:33 -07004730 /* TODO: Propagate memory error. */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004731 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4732 break;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004733 }
William M. Brack97ac8192007-06-06 17:19:24 +00004734 xmlXPathNodeSetSort(ret); /* bug 413451 */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004735 return(ret);
4736}
4737
4738/**
4739 * xmlXPathNodeTrailing:
4740 * @nodes: a node-set
4741 * @node: a node
4742 *
4743 * Implements the EXSLT - Sets trailing() function:
4744 * node-set set:trailing (node-set, node-set)
4745 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4746 * is called.
4747 *
4748 * Returns the nodes in @nodes that follow @node in document order,
4749 * @nodes if @node is NULL or an empty node-set if @nodes
4750 * doesn't contain @node
4751 */
4752xmlNodeSetPtr
4753xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4754 xmlXPathNodeSetSort(nodes);
4755 return(xmlXPathNodeTrailingSorted(nodes, node));
4756}
4757
4758/**
4759 * xmlXPathTrailingSorted:
4760 * @nodes1: a node-set, sorted by document order
4761 * @nodes2: a node-set, sorted by document order
4762 *
4763 * Implements the EXSLT - Sets trailing() function:
4764 * node-set set:trailing (node-set, node-set)
4765 *
4766 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4767 * in document order, @nodes1 if @nodes2 is NULL or empty or
4768 * an empty node-set if @nodes1 doesn't contain @nodes2
4769 */
4770xmlNodeSetPtr
4771xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4772 if (xmlXPathNodeSetIsEmpty(nodes2))
4773 return(nodes1);
4774 return(xmlXPathNodeTrailingSorted(nodes1,
4775 xmlXPathNodeSetItem(nodes2, 0)));
4776}
4777
4778/**
4779 * xmlXPathTrailing:
4780 * @nodes1: a node-set
4781 * @nodes2: a node-set
4782 *
4783 * Implements the EXSLT - Sets trailing() function:
4784 * node-set set:trailing (node-set, node-set)
4785 * @nodes1 and @nodes2 are sorted by document order, then
4786 * #xmlXPathTrailingSorted is called.
4787 *
4788 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4789 * in document order, @nodes1 if @nodes2 is NULL or empty or
4790 * an empty node-set if @nodes1 doesn't contain @nodes2
4791 */
4792xmlNodeSetPtr
4793xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4794 if (xmlXPathNodeSetIsEmpty(nodes2))
4795 return(nodes1);
4796 if (xmlXPathNodeSetIsEmpty(nodes1))
4797 return(xmlXPathNodeSetCreate(NULL));
4798 xmlXPathNodeSetSort(nodes1);
4799 xmlXPathNodeSetSort(nodes2);
4800 return(xmlXPathNodeTrailingSorted(nodes1,
4801 xmlXPathNodeSetItem(nodes2, 0)));
4802}
4803
Owen Taylor3473f882001-02-23 17:55:21 +00004804/************************************************************************
4805 * *
4806 * Routines to handle extra functions *
4807 * *
4808 ************************************************************************/
4809
4810/**
4811 * xmlXPathRegisterFunc:
4812 * @ctxt: the XPath context
4813 * @name: the function name
4814 * @f: the function implementation or NULL
4815 *
4816 * Register a new function. If @f is NULL it unregisters the function
4817 *
4818 * Returns 0 in case of success, -1 in case of error
4819 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00004820int
Owen Taylor3473f882001-02-23 17:55:21 +00004821xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4822 xmlXPathFunction f) {
4823 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4824}
4825
4826/**
4827 * xmlXPathRegisterFuncNS:
4828 * @ctxt: the XPath context
4829 * @name: the function name
4830 * @ns_uri: the function namespace URI
4831 * @f: the function implementation or NULL
4832 *
4833 * Register a new function. If @f is NULL it unregisters the function
4834 *
4835 * Returns 0 in case of success, -1 in case of error
4836 */
4837int
4838xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4839 const xmlChar *ns_uri, xmlXPathFunction f) {
4840 if (ctxt == NULL)
4841 return(-1);
4842 if (name == NULL)
4843 return(-1);
4844
4845 if (ctxt->funcHash == NULL)
4846 ctxt->funcHash = xmlHashCreate(0);
4847 if (ctxt->funcHash == NULL)
4848 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004849 if (f == NULL)
4850 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
Nick Wellnhofer13acadb2017-11-12 17:28:12 +01004851XML_IGNORE_PEDANTIC_WARNINGS
4852 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4853XML_POP_WARNINGS
Owen Taylor3473f882001-02-23 17:55:21 +00004854}
4855
4856/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00004857 * xmlXPathRegisterFuncLookup:
4858 * @ctxt: the XPath context
4859 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004860 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00004861 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004862 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00004863 */
4864void
4865xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4866 xmlXPathFuncLookupFunc f,
4867 void *funcCtxt) {
4868 if (ctxt == NULL)
4869 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004870 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004871 ctxt->funcLookupData = funcCtxt;
4872}
4873
4874/**
Owen Taylor3473f882001-02-23 17:55:21 +00004875 * xmlXPathFunctionLookup:
4876 * @ctxt: the XPath context
4877 * @name: the function name
4878 *
4879 * Search in the Function array of the context for the given
4880 * function.
4881 *
4882 * Returns the xmlXPathFunction or NULL if not found
4883 */
4884xmlXPathFunction
4885xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00004886 if (ctxt == NULL)
4887 return (NULL);
4888
4889 if (ctxt->funcLookupFunc != NULL) {
4890 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004891 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004892
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004893 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004894 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004895 if (ret != NULL)
4896 return(ret);
4897 }
Owen Taylor3473f882001-02-23 17:55:21 +00004898 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4899}
4900
4901/**
4902 * xmlXPathFunctionLookupNS:
4903 * @ctxt: the XPath context
4904 * @name: the function name
4905 * @ns_uri: the function namespace URI
4906 *
4907 * Search in the Function array of the context for the given
4908 * function.
4909 *
4910 * Returns the xmlXPathFunction or NULL if not found
4911 */
4912xmlXPathFunction
4913xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4914 const xmlChar *ns_uri) {
William M. Brackad0e67c2004-12-01 14:35:10 +00004915 xmlXPathFunction ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004916
Owen Taylor3473f882001-02-23 17:55:21 +00004917 if (ctxt == NULL)
4918 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004919 if (name == NULL)
4920 return(NULL);
4921
Thomas Broyerba4ad322001-07-26 16:55:21 +00004922 if (ctxt->funcLookupFunc != NULL) {
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004923 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004924
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004925 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004926 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004927 if (ret != NULL)
4928 return(ret);
4929 }
4930
4931 if (ctxt->funcHash == NULL)
4932 return(NULL);
4933
Nick Wellnhofer13acadb2017-11-12 17:28:12 +01004934XML_IGNORE_PEDANTIC_WARNINGS
4935 ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4936XML_POP_WARNINGS
William M. Brackad0e67c2004-12-01 14:35:10 +00004937 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004938}
4939
4940/**
4941 * xmlXPathRegisteredFuncsCleanup:
4942 * @ctxt: the XPath context
4943 *
4944 * Cleanup the XPath context data associated to registered functions
4945 */
4946void
4947xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4948 if (ctxt == NULL)
4949 return;
4950
4951 xmlHashFree(ctxt->funcHash, NULL);
4952 ctxt->funcHash = NULL;
4953}
4954
4955/************************************************************************
4956 * *
William M. Brack08171912003-12-29 02:52:11 +00004957 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00004958 * *
4959 ************************************************************************/
4960
4961/**
4962 * xmlXPathRegisterVariable:
4963 * @ctxt: the XPath context
4964 * @name: the variable name
4965 * @value: the variable value or NULL
4966 *
4967 * Register a new variable value. If @value is NULL it unregisters
4968 * the variable
4969 *
4970 * Returns 0 in case of success, -1 in case of error
4971 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00004972int
Owen Taylor3473f882001-02-23 17:55:21 +00004973xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4974 xmlXPathObjectPtr value) {
4975 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4976}
4977
4978/**
4979 * xmlXPathRegisterVariableNS:
4980 * @ctxt: the XPath context
4981 * @name: the variable name
4982 * @ns_uri: the variable namespace URI
4983 * @value: the variable value or NULL
4984 *
4985 * Register a new variable value. If @value is NULL it unregisters
4986 * the variable
4987 *
4988 * Returns 0 in case of success, -1 in case of error
4989 */
4990int
4991xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4992 const xmlChar *ns_uri,
4993 xmlXPathObjectPtr value) {
4994 if (ctxt == NULL)
4995 return(-1);
4996 if (name == NULL)
4997 return(-1);
4998
4999 if (ctxt->varHash == NULL)
5000 ctxt->varHash = xmlHashCreate(0);
5001 if (ctxt->varHash == NULL)
5002 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00005003 if (value == NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00005004 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
Nick Wellnhofere03f0a12017-11-09 16:42:47 +01005005 xmlXPathFreeObjectEntry));
Owen Taylor3473f882001-02-23 17:55:21 +00005006 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
Nick Wellnhofere03f0a12017-11-09 16:42:47 +01005007 (void *) value, xmlXPathFreeObjectEntry));
Owen Taylor3473f882001-02-23 17:55:21 +00005008}
5009
5010/**
5011 * xmlXPathRegisterVariableLookup:
5012 * @ctxt: the XPath context
5013 * @f: the lookup function
5014 * @data: the lookup data
5015 *
5016 * register an external mechanism to do variable lookup
5017 */
5018void
5019xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5020 xmlXPathVariableLookupFunc f, void *data) {
5021 if (ctxt == NULL)
5022 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00005023 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00005024 ctxt->varLookupData = data;
5025}
5026
5027/**
5028 * xmlXPathVariableLookup:
5029 * @ctxt: the XPath context
5030 * @name: the variable name
5031 *
5032 * Search in the Variable array of the context for the given
5033 * variable value.
5034 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00005035 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00005036 */
5037xmlXPathObjectPtr
5038xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5039 if (ctxt == NULL)
5040 return(NULL);
5041
5042 if (ctxt->varLookupFunc != NULL) {
5043 xmlXPathObjectPtr ret;
5044
5045 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5046 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00005047 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005048 }
5049 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5050}
5051
5052/**
5053 * xmlXPathVariableLookupNS:
5054 * @ctxt: the XPath context
5055 * @name: the variable name
5056 * @ns_uri: the variable namespace URI
5057 *
5058 * Search in the Variable array of the context for the given
Daniel Veillard45490ae2008-07-29 09:13:19 +00005059 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00005060 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00005061 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00005062 */
5063xmlXPathObjectPtr
5064xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5065 const xmlChar *ns_uri) {
5066 if (ctxt == NULL)
5067 return(NULL);
5068
5069 if (ctxt->varLookupFunc != NULL) {
5070 xmlXPathObjectPtr ret;
5071
5072 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5073 (ctxt->varLookupData, name, ns_uri);
5074 if (ret != NULL) return(ret);
5075 }
5076
5077 if (ctxt->varHash == NULL)
5078 return(NULL);
5079 if (name == NULL)
5080 return(NULL);
5081
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005082 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
Daniel Veillard8c357d52001-07-03 23:43:33 +00005083 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00005084}
5085
5086/**
5087 * xmlXPathRegisteredVariablesCleanup:
5088 * @ctxt: the XPath context
5089 *
5090 * Cleanup the XPath context data associated to registered variables
5091 */
5092void
5093xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5094 if (ctxt == NULL)
5095 return;
5096
Nick Wellnhofere03f0a12017-11-09 16:42:47 +01005097 xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
Owen Taylor3473f882001-02-23 17:55:21 +00005098 ctxt->varHash = NULL;
5099}
5100
5101/**
5102 * xmlXPathRegisterNs:
5103 * @ctxt: the XPath context
Daniel Veillarddb3ce962009-03-25 09:43:49 +00005104 * @prefix: the namespace prefix cannot be NULL or empty string
Owen Taylor3473f882001-02-23 17:55:21 +00005105 * @ns_uri: the namespace name
5106 *
5107 * Register a new namespace. If @ns_uri is NULL it unregisters
5108 * the namespace
5109 *
5110 * Returns 0 in case of success, -1 in case of error
5111 */
5112int
5113xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5114 const xmlChar *ns_uri) {
5115 if (ctxt == NULL)
5116 return(-1);
5117 if (prefix == NULL)
5118 return(-1);
Daniel Veillarddb3ce962009-03-25 09:43:49 +00005119 if (prefix[0] == 0)
5120 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00005121
5122 if (ctxt->nsHash == NULL)
5123 ctxt->nsHash = xmlHashCreate(10);
5124 if (ctxt->nsHash == NULL)
5125 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00005126 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00005127 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Nick Wellnhofere03f0a12017-11-09 16:42:47 +01005128 xmlHashDefaultDeallocator));
Daniel Veillard42766c02002-08-22 20:52:17 +00005129 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Nick Wellnhofere03f0a12017-11-09 16:42:47 +01005130 xmlHashDefaultDeallocator));
Owen Taylor3473f882001-02-23 17:55:21 +00005131}
5132
5133/**
5134 * xmlXPathNsLookup:
5135 * @ctxt: the XPath context
5136 * @prefix: the namespace prefix value
5137 *
5138 * Search in the namespace declaration array of the context for the given
5139 * namespace name associated to the given prefix
5140 *
5141 * Returns the value or NULL if not found
5142 */
5143const xmlChar *
5144xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5145 if (ctxt == NULL)
5146 return(NULL);
5147 if (prefix == NULL)
5148 return(NULL);
5149
5150#ifdef XML_XML_NAMESPACE
5151 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5152 return(XML_XML_NAMESPACE);
5153#endif
5154
Daniel Veillardc8f620b2001-04-30 20:31:33 +00005155 if (ctxt->namespaces != NULL) {
5156 int i;
5157
5158 for (i = 0;i < ctxt->nsNr;i++) {
5159 if ((ctxt->namespaces[i] != NULL) &&
5160 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5161 return(ctxt->namespaces[i]->href);
5162 }
5163 }
Owen Taylor3473f882001-02-23 17:55:21 +00005164
5165 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5166}
5167
5168/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005169 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00005170 * @ctxt: the XPath context
5171 *
5172 * Cleanup the XPath context data associated to registered variables
5173 */
5174void
5175xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5176 if (ctxt == NULL)
5177 return;
5178
Nick Wellnhofere03f0a12017-11-09 16:42:47 +01005179 xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
Owen Taylor3473f882001-02-23 17:55:21 +00005180 ctxt->nsHash = NULL;
5181}
5182
5183/************************************************************************
5184 * *
5185 * Routines to handle Values *
5186 * *
5187 ************************************************************************/
5188
William M. Brack08171912003-12-29 02:52:11 +00005189/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005190
5191/**
5192 * xmlXPathNewFloat:
5193 * @val: the double value
5194 *
5195 * Create a new xmlXPathObjectPtr of type double and of value @val
5196 *
5197 * Returns the newly created object.
5198 */
5199xmlXPathObjectPtr
5200xmlXPathNewFloat(double val) {
5201 xmlXPathObjectPtr ret;
5202
5203 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5204 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005205 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005206 return(NULL);
5207 }
5208 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5209 ret->type = XPATH_NUMBER;
5210 ret->floatval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005211#ifdef XP_DEBUG_OBJ_USAGE
5212 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5213#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005214 return(ret);
5215}
5216
5217/**
5218 * xmlXPathNewBoolean:
5219 * @val: the boolean value
5220 *
5221 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5222 *
5223 * Returns the newly created object.
5224 */
5225xmlXPathObjectPtr
5226xmlXPathNewBoolean(int val) {
5227 xmlXPathObjectPtr ret;
5228
5229 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5230 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005231 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005232 return(NULL);
5233 }
5234 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5235 ret->type = XPATH_BOOLEAN;
5236 ret->boolval = (val != 0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005237#ifdef XP_DEBUG_OBJ_USAGE
5238 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5239#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005240 return(ret);
5241}
5242
5243/**
5244 * xmlXPathNewString:
5245 * @val: the xmlChar * value
5246 *
5247 * Create a new xmlXPathObjectPtr of type string and of value @val
5248 *
5249 * Returns the newly created object.
5250 */
5251xmlXPathObjectPtr
5252xmlXPathNewString(const xmlChar *val) {
5253 xmlXPathObjectPtr ret;
5254
5255 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5256 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005257 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005258 return(NULL);
5259 }
5260 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5261 ret->type = XPATH_STRING;
5262 if (val != NULL)
5263 ret->stringval = xmlStrdup(val);
5264 else
5265 ret->stringval = xmlStrdup((const xmlChar *)"");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005266#ifdef XP_DEBUG_OBJ_USAGE
5267 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5268#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005269 return(ret);
5270}
5271
5272/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005273 * xmlXPathWrapString:
5274 * @val: the xmlChar * value
5275 *
5276 * Wraps the @val string into an XPath object.
5277 *
5278 * Returns the newly created object.
5279 */
5280xmlXPathObjectPtr
5281xmlXPathWrapString (xmlChar *val) {
5282 xmlXPathObjectPtr ret;
5283
5284 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5285 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005286 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005287 return(NULL);
5288 }
5289 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5290 ret->type = XPATH_STRING;
5291 ret->stringval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005292#ifdef XP_DEBUG_OBJ_USAGE
5293 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5294#endif
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005295 return(ret);
5296}
5297
5298/**
Owen Taylor3473f882001-02-23 17:55:21 +00005299 * xmlXPathNewCString:
5300 * @val: the char * value
5301 *
5302 * Create a new xmlXPathObjectPtr of type string and of value @val
5303 *
5304 * Returns the newly created object.
5305 */
5306xmlXPathObjectPtr
5307xmlXPathNewCString(const char *val) {
5308 xmlXPathObjectPtr ret;
5309
5310 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5311 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005312 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005313 return(NULL);
5314 }
5315 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5316 ret->type = XPATH_STRING;
5317 ret->stringval = xmlStrdup(BAD_CAST val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005318#ifdef XP_DEBUG_OBJ_USAGE
5319 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5320#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005321 return(ret);
5322}
5323
5324/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005325 * xmlXPathWrapCString:
5326 * @val: the char * value
5327 *
5328 * Wraps a string into an XPath object.
5329 *
5330 * Returns the newly created object.
5331 */
5332xmlXPathObjectPtr
5333xmlXPathWrapCString (char * val) {
5334 return(xmlXPathWrapString((xmlChar *)(val)));
5335}
5336
5337/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005338 * xmlXPathWrapExternal:
5339 * @val: the user data
5340 *
5341 * Wraps the @val data into an XPath object.
5342 *
5343 * Returns the newly created object.
5344 */
5345xmlXPathObjectPtr
5346xmlXPathWrapExternal (void *val) {
5347 xmlXPathObjectPtr ret;
5348
5349 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5350 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005351 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005352 return(NULL);
5353 }
5354 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5355 ret->type = XPATH_USERS;
5356 ret->user = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005357#ifdef XP_DEBUG_OBJ_USAGE
5358 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5359#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005360 return(ret);
5361}
5362
5363/**
Owen Taylor3473f882001-02-23 17:55:21 +00005364 * xmlXPathObjectCopy:
5365 * @val: the original object
5366 *
5367 * allocate a new copy of a given object
5368 *
5369 * Returns the newly created object.
5370 */
5371xmlXPathObjectPtr
5372xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5373 xmlXPathObjectPtr ret;
5374
5375 if (val == NULL)
5376 return(NULL);
5377
5378 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5379 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005380 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005381 return(NULL);
5382 }
5383 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005384#ifdef XP_DEBUG_OBJ_USAGE
5385 xmlXPathDebugObjUsageRequested(NULL, val->type);
5386#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005387 switch (val->type) {
5388 case XPATH_BOOLEAN:
5389 case XPATH_NUMBER:
5390 case XPATH_POINT:
5391 case XPATH_RANGE:
5392 break;
5393 case XPATH_STRING:
5394 ret->stringval = xmlStrdup(val->stringval);
5395 break;
5396 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00005397#if 0
5398/*
5399 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5400 this previous handling is no longer correct, and can cause some serious
5401 problems (ref. bug 145547)
5402*/
Owen Taylor3473f882001-02-23 17:55:21 +00005403 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005404 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005405 xmlNodePtr cur, tmp;
5406 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005407
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005408 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005409 top = xmlNewDoc(NULL);
5410 top->name = (char *)
5411 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005412 ret->user = top;
5413 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005414 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005415 cur = val->nodesetval->nodeTab[0]->children;
5416 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005417 tmp = xmlDocCopyNode(cur, top, 1);
5418 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005419 cur = cur->next;
5420 }
5421 }
William M. Bracke9449c52004-07-11 14:41:20 +00005422
Daniel Veillard9adc0462003-03-24 18:39:54 +00005423 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005424 } else
Owen Taylor3473f882001-02-23 17:55:21 +00005425 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005426 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00005427 break;
William M. Bracke9449c52004-07-11 14:41:20 +00005428#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005429 case XPATH_NODESET:
Haibo Huangcfd91dc2020-07-30 23:01:33 -07005430 /* TODO: Check memory error. */
Owen Taylor3473f882001-02-23 17:55:21 +00005431 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005432 /* Do not deallocate the copied tree value */
5433 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005434 break;
5435 case XPATH_LOCATIONSET:
5436#ifdef LIBXML_XPTR_ENABLED
5437 {
5438 xmlLocationSetPtr loc = val->user;
5439 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5440 break;
5441 }
5442#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00005443 case XPATH_USERS:
5444 ret->user = val->user;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005445 break;
Thomas Broyer47334c02001-10-07 16:41:52 +00005446 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00005447 xmlGenericError(xmlGenericErrorContext,
5448 "xmlXPathObjectCopy: unsupported type %d\n",
5449 val->type);
5450 break;
5451 }
5452 return(ret);
5453}
5454
5455/**
5456 * xmlXPathFreeObject:
5457 * @obj: the object to free
5458 *
5459 * Free up an xmlXPathObjectPtr object.
5460 */
5461void
5462xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5463 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005464 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00005465 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00005466#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005467 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005468 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00005469 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00005470 } else
5471#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005472 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
William M. Bracke9449c52004-07-11 14:41:20 +00005473 if (obj->nodesetval != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00005474 xmlXPathFreeValueTree(obj->nodesetval);
Daniel Veillard77851712001-02-27 21:54:07 +00005475 } else {
5476 if (obj->nodesetval != NULL)
5477 xmlXPathFreeNodeSet(obj->nodesetval);
5478 }
Owen Taylor3473f882001-02-23 17:55:21 +00005479#ifdef LIBXML_XPTR_ENABLED
5480 } else if (obj->type == XPATH_LOCATIONSET) {
5481 if (obj->user != NULL)
5482 xmlXPtrFreeLocationSet(obj->user);
5483#endif
5484 } else if (obj->type == XPATH_STRING) {
5485 if (obj->stringval != NULL)
5486 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005487 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005488#ifdef XP_DEBUG_OBJ_USAGE
5489 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5490#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00005491 xmlFree(obj);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005492}
Owen Taylor3473f882001-02-23 17:55:21 +00005493
Nick Wellnhofere03f0a12017-11-09 16:42:47 +01005494static void
5495xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
5496 xmlXPathFreeObject((xmlXPathObjectPtr) obj);
5497}
5498
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005499/**
5500 * xmlXPathReleaseObject:
5501 * @obj: the xmlXPathObjectPtr to free or to cache
5502 *
5503 * Depending on the state of the cache this frees the given
5504 * XPath object or stores it in the cache.
5505 */
5506static void
5507xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5508{
5509#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5510 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5511 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5512
5513#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5514
5515 if (obj == NULL)
5516 return;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005517 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005518 xmlXPathFreeObject(obj);
Daniel Veillard45490ae2008-07-29 09:13:19 +00005519 } else {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005520 xmlXPathContextCachePtr cache =
5521 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005522
5523 switch (obj->type) {
5524 case XPATH_NODESET:
5525 case XPATH_XSLT_TREE:
5526 if (obj->nodesetval != NULL) {
5527 if (obj->boolval) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00005528 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005529 * It looks like the @boolval is used for
5530 * evaluation if this an XSLT Result Tree Fragment.
5531 * TODO: Check if this assumption is correct.
5532 */
5533 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5534 xmlXPathFreeValueTree(obj->nodesetval);
5535 obj->nodesetval = NULL;
5536 } else if ((obj->nodesetval->nodeMax <= 40) &&
5537 (XP_CACHE_WANTS(cache->nodesetObjs,
5538 cache->maxNodeset)))
5539 {
5540 XP_CACHE_ADD(cache->nodesetObjs, obj);
5541 goto obj_cached;
5542 } else {
5543 xmlXPathFreeNodeSet(obj->nodesetval);
5544 obj->nodesetval = NULL;
5545 }
5546 }
5547 break;
5548 case XPATH_STRING:
5549 if (obj->stringval != NULL)
5550 xmlFree(obj->stringval);
5551
5552 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5553 XP_CACHE_ADD(cache->stringObjs, obj);
5554 goto obj_cached;
5555 }
5556 break;
5557 case XPATH_BOOLEAN:
5558 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5559 XP_CACHE_ADD(cache->booleanObjs, obj);
5560 goto obj_cached;
5561 }
5562 break;
5563 case XPATH_NUMBER:
5564 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5565 XP_CACHE_ADD(cache->numberObjs, obj);
5566 goto obj_cached;
5567 }
5568 break;
5569#ifdef LIBXML_XPTR_ENABLED
5570 case XPATH_LOCATIONSET:
5571 if (obj->user != NULL) {
5572 xmlXPtrFreeLocationSet(obj->user);
5573 }
5574 goto free_obj;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005575#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005576 default:
5577 goto free_obj;
5578 }
5579
5580 /*
5581 * Fallback to adding to the misc-objects slot.
5582 */
5583 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5584 XP_CACHE_ADD(cache->miscObjs, obj);
5585 } else
5586 goto free_obj;
5587
5588obj_cached:
5589
5590#ifdef XP_DEBUG_OBJ_USAGE
5591 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5592#endif
5593
5594 if (obj->nodesetval != NULL) {
5595 xmlNodeSetPtr tmpset = obj->nodesetval;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005596
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005597 /*
5598 * TODO: Due to those nasty ns-nodes, we need to traverse
5599 * the list and free the ns-nodes.
5600 * URGENT TODO: Check if it's actually slowing things down.
5601 * Maybe we shouldn't try to preserve the list.
5602 */
5603 if (tmpset->nodeNr > 1) {
5604 int i;
5605 xmlNodePtr node;
5606
5607 for (i = 0; i < tmpset->nodeNr; i++) {
5608 node = tmpset->nodeTab[i];
5609 if ((node != NULL) &&
5610 (node->type == XML_NAMESPACE_DECL))
5611 {
5612 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5613 }
5614 }
5615 } else if (tmpset->nodeNr == 1) {
5616 if ((tmpset->nodeTab[0] != NULL) &&
5617 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5618 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
Daniel Veillard45490ae2008-07-29 09:13:19 +00005619 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005620 tmpset->nodeNr = 0;
5621 memset(obj, 0, sizeof(xmlXPathObject));
5622 obj->nodesetval = tmpset;
5623 } else
5624 memset(obj, 0, sizeof(xmlXPathObject));
5625
5626 return;
5627
5628free_obj:
5629 /*
5630 * Cache is full; free the object.
Daniel Veillard45490ae2008-07-29 09:13:19 +00005631 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005632 if (obj->nodesetval != NULL)
5633 xmlXPathFreeNodeSet(obj->nodesetval);
5634#ifdef XP_DEBUG_OBJ_USAGE
5635 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5636#endif
5637 xmlFree(obj);
5638 }
5639 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005640}
5641
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005642
5643/************************************************************************
5644 * *
5645 * Type Casting Routines *
5646 * *
5647 ************************************************************************/
5648
5649/**
5650 * xmlXPathCastBooleanToString:
5651 * @val: a boolean
5652 *
5653 * Converts a boolean to its string value.
5654 *
5655 * Returns a newly allocated string.
5656 */
5657xmlChar *
5658xmlXPathCastBooleanToString (int val) {
5659 xmlChar *ret;
5660 if (val)
5661 ret = xmlStrdup((const xmlChar *) "true");
5662 else
5663 ret = xmlStrdup((const xmlChar *) "false");
5664 return(ret);
5665}
5666
5667/**
5668 * xmlXPathCastNumberToString:
5669 * @val: a number
5670 *
5671 * Converts a number to its string value.
5672 *
5673 * Returns a newly allocated string.
5674 */
5675xmlChar *
5676xmlXPathCastNumberToString (double val) {
5677 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00005678 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005679 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005680 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005681 break;
5682 case -1:
5683 ret = xmlStrdup((const xmlChar *) "-Infinity");
5684 break;
5685 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00005686 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005687 ret = xmlStrdup((const xmlChar *) "NaN");
Nick Wellnhofer8813f392017-09-21 00:11:26 +02005688 } else if (val == 0) {
5689 /* Omit sign for negative zero. */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005690 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005691 } else {
5692 /* could be improved */
5693 char buf[100];
Daniel Veillard11ce4002006-03-10 00:36:23 +00005694 xmlXPathFormatNumber(val, buf, 99);
5695 buf[99] = 0;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005696 ret = xmlStrdup((const xmlChar *) buf);
5697 }
5698 }
5699 return(ret);
5700}
5701
5702/**
5703 * xmlXPathCastNodeToString:
5704 * @node: a node
5705 *
5706 * Converts a node to its string value.
5707 *
5708 * Returns a newly allocated string.
5709 */
5710xmlChar *
5711xmlXPathCastNodeToString (xmlNodePtr node) {
William M. Brackd611c882007-05-31 05:07:17 +00005712xmlChar *ret;
5713 if ((ret = xmlNodeGetContent(node)) == NULL)
5714 ret = xmlStrdup((const xmlChar *) "");
5715 return(ret);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005716}
5717
5718/**
5719 * xmlXPathCastNodeSetToString:
5720 * @ns: a node-set
5721 *
5722 * Converts a node-set to its string value.
5723 *
5724 * Returns a newly allocated string.
5725 */
5726xmlChar *
5727xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5728 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5729 return(xmlStrdup((const xmlChar *) ""));
5730
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00005731 if (ns->nodeNr > 1)
5732 xmlXPathNodeSetSort(ns);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005733 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5734}
5735
5736/**
5737 * xmlXPathCastToString:
5738 * @val: an XPath object
5739 *
5740 * Converts an existing object to its string() equivalent
5741 *
Kasimier T. Buchcik50128ad2006-08-15 13:04:07 +00005742 * Returns the allocated string value of the object, NULL in case of error.
Daniel Veillard45490ae2008-07-29 09:13:19 +00005743 * It's up to the caller to free the string memory with xmlFree().
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005744 */
5745xmlChar *
5746xmlXPathCastToString(xmlXPathObjectPtr val) {
5747 xmlChar *ret = NULL;
5748
5749 if (val == NULL)
5750 return(xmlStrdup((const xmlChar *) ""));
5751 switch (val->type) {
5752 case XPATH_UNDEFINED:
5753#ifdef DEBUG_EXPR
5754 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5755#endif
5756 ret = xmlStrdup((const xmlChar *) "");
5757 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005758 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005759 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005760 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5761 break;
5762 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00005763 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005764 case XPATH_BOOLEAN:
5765 ret = xmlXPathCastBooleanToString(val->boolval);
5766 break;
5767 case XPATH_NUMBER: {
5768 ret = xmlXPathCastNumberToString(val->floatval);
5769 break;
5770 }
5771 case XPATH_USERS:
5772 case XPATH_POINT:
5773 case XPATH_RANGE:
5774 case XPATH_LOCATIONSET:
5775 TODO
5776 ret = xmlStrdup((const xmlChar *) "");
5777 break;
5778 }
5779 return(ret);
5780}
5781
5782/**
5783 * xmlXPathConvertString:
5784 * @val: an XPath object
5785 *
5786 * Converts an existing object to its string() equivalent
5787 *
5788 * Returns the new object, the old one is freed (or the operation
5789 * is done directly on @val)
5790 */
5791xmlXPathObjectPtr
5792xmlXPathConvertString(xmlXPathObjectPtr val) {
5793 xmlChar *res = NULL;
5794
5795 if (val == NULL)
5796 return(xmlXPathNewCString(""));
5797
5798 switch (val->type) {
5799 case XPATH_UNDEFINED:
5800#ifdef DEBUG_EXPR
5801 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5802#endif
5803 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005804 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005805 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005806 res = xmlXPathCastNodeSetToString(val->nodesetval);
5807 break;
5808 case XPATH_STRING:
5809 return(val);
5810 case XPATH_BOOLEAN:
5811 res = xmlXPathCastBooleanToString(val->boolval);
5812 break;
5813 case XPATH_NUMBER:
5814 res = xmlXPathCastNumberToString(val->floatval);
5815 break;
5816 case XPATH_USERS:
5817 case XPATH_POINT:
5818 case XPATH_RANGE:
5819 case XPATH_LOCATIONSET:
5820 TODO;
5821 break;
5822 }
5823 xmlXPathFreeObject(val);
5824 if (res == NULL)
5825 return(xmlXPathNewCString(""));
5826 return(xmlXPathWrapString(res));
5827}
5828
5829/**
5830 * xmlXPathCastBooleanToNumber:
5831 * @val: a boolean
5832 *
5833 * Converts a boolean to its number value
5834 *
5835 * Returns the number value
5836 */
5837double
5838xmlXPathCastBooleanToNumber(int val) {
5839 if (val)
5840 return(1.0);
5841 return(0.0);
5842}
5843
5844/**
5845 * xmlXPathCastStringToNumber:
5846 * @val: a string
5847 *
5848 * Converts a string to its number value
5849 *
5850 * Returns the number value
5851 */
5852double
5853xmlXPathCastStringToNumber(const xmlChar * val) {
5854 return(xmlXPathStringEvalNumber(val));
5855}
5856
5857/**
5858 * xmlXPathCastNodeToNumber:
5859 * @node: a node
5860 *
5861 * Converts a node to its number value
5862 *
5863 * Returns the number value
5864 */
5865double
5866xmlXPathCastNodeToNumber (xmlNodePtr node) {
5867 xmlChar *strval;
5868 double ret;
5869
5870 if (node == NULL)
Elliott Hughes5cefca72021-05-06 13:23:15 -07005871 return(xmlXPathNAN);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005872 strval = xmlXPathCastNodeToString(node);
5873 if (strval == NULL)
Elliott Hughes5cefca72021-05-06 13:23:15 -07005874 return(xmlXPathNAN);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005875 ret = xmlXPathCastStringToNumber(strval);
5876 xmlFree(strval);
5877
5878 return(ret);
5879}
5880
5881/**
5882 * xmlXPathCastNodeSetToNumber:
5883 * @ns: a node-set
5884 *
5885 * Converts a node-set to its number value
5886 *
5887 * Returns the number value
5888 */
5889double
5890xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5891 xmlChar *str;
5892 double ret;
5893
5894 if (ns == NULL)
Elliott Hughes5cefca72021-05-06 13:23:15 -07005895 return(xmlXPathNAN);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005896 str = xmlXPathCastNodeSetToString(ns);
5897 ret = xmlXPathCastStringToNumber(str);
5898 xmlFree(str);
5899 return(ret);
5900}
5901
5902/**
5903 * xmlXPathCastToNumber:
5904 * @val: an XPath object
5905 *
5906 * Converts an XPath object to its number value
5907 *
5908 * Returns the number value
5909 */
5910double
5911xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5912 double ret = 0.0;
5913
5914 if (val == NULL)
Elliott Hughes5cefca72021-05-06 13:23:15 -07005915 return(xmlXPathNAN);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005916 switch (val->type) {
5917 case XPATH_UNDEFINED:
Haibo Huangcfd91dc2020-07-30 23:01:33 -07005918#ifdef DEBUG_EXPR
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005919 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5920#endif
Elliott Hughes5cefca72021-05-06 13:23:15 -07005921 ret = xmlXPathNAN;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005922 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005923 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005924 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005925 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5926 break;
5927 case XPATH_STRING:
5928 ret = xmlXPathCastStringToNumber(val->stringval);
5929 break;
5930 case XPATH_NUMBER:
5931 ret = val->floatval;
5932 break;
5933 case XPATH_BOOLEAN:
5934 ret = xmlXPathCastBooleanToNumber(val->boolval);
5935 break;
5936 case XPATH_USERS:
5937 case XPATH_POINT:
5938 case XPATH_RANGE:
5939 case XPATH_LOCATIONSET:
5940 TODO;
Elliott Hughes5cefca72021-05-06 13:23:15 -07005941 ret = xmlXPathNAN;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005942 break;
5943 }
5944 return(ret);
5945}
5946
5947/**
5948 * xmlXPathConvertNumber:
5949 * @val: an XPath object
5950 *
5951 * Converts an existing object to its number() equivalent
5952 *
5953 * Returns the new object, the old one is freed (or the operation
5954 * is done directly on @val)
5955 */
5956xmlXPathObjectPtr
5957xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5958 xmlXPathObjectPtr ret;
5959
5960 if (val == NULL)
5961 return(xmlXPathNewFloat(0.0));
5962 if (val->type == XPATH_NUMBER)
5963 return(val);
5964 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5965 xmlXPathFreeObject(val);
5966 return(ret);
5967}
5968
5969/**
5970 * xmlXPathCastNumberToBoolean:
5971 * @val: a number
5972 *
5973 * Converts a number to its boolean value
5974 *
5975 * Returns the boolean value
5976 */
5977int
5978xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00005979 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005980 return(0);
5981 return(1);
5982}
5983
5984/**
5985 * xmlXPathCastStringToBoolean:
5986 * @val: a string
5987 *
5988 * Converts a string to its boolean value
5989 *
5990 * Returns the boolean value
5991 */
5992int
5993xmlXPathCastStringToBoolean (const xmlChar *val) {
5994 if ((val == NULL) || (xmlStrlen(val) == 0))
5995 return(0);
5996 return(1);
5997}
5998
5999/**
6000 * xmlXPathCastNodeSetToBoolean:
6001 * @ns: a node-set
6002 *
6003 * Converts a node-set to its boolean value
6004 *
6005 * Returns the boolean value
6006 */
6007int
6008xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6009 if ((ns == NULL) || (ns->nodeNr == 0))
6010 return(0);
6011 return(1);
6012}
6013
6014/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006015 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006016 * @val: an XPath object
6017 *
6018 * Converts an XPath object to its boolean value
6019 *
6020 * Returns the boolean value
6021 */
6022int
6023xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6024 int ret = 0;
6025
6026 if (val == NULL)
6027 return(0);
6028 switch (val->type) {
6029 case XPATH_UNDEFINED:
6030#ifdef DEBUG_EXPR
6031 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6032#endif
6033 ret = 0;
6034 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006035 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00006036 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006037 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6038 break;
6039 case XPATH_STRING:
6040 ret = xmlXPathCastStringToBoolean(val->stringval);
6041 break;
6042 case XPATH_NUMBER:
6043 ret = xmlXPathCastNumberToBoolean(val->floatval);
6044 break;
6045 case XPATH_BOOLEAN:
6046 ret = val->boolval;
6047 break;
6048 case XPATH_USERS:
6049 case XPATH_POINT:
6050 case XPATH_RANGE:
6051 case XPATH_LOCATIONSET:
6052 TODO;
6053 ret = 0;
6054 break;
6055 }
6056 return(ret);
6057}
6058
6059
6060/**
6061 * xmlXPathConvertBoolean:
6062 * @val: an XPath object
6063 *
6064 * Converts an existing object to its boolean() equivalent
6065 *
6066 * Returns the new object, the old one is freed (or the operation
6067 * is done directly on @val)
6068 */
6069xmlXPathObjectPtr
6070xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6071 xmlXPathObjectPtr ret;
6072
6073 if (val == NULL)
6074 return(xmlXPathNewBoolean(0));
6075 if (val->type == XPATH_BOOLEAN)
6076 return(val);
6077 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6078 xmlXPathFreeObject(val);
6079 return(ret);
6080}
6081
Owen Taylor3473f882001-02-23 17:55:21 +00006082/************************************************************************
6083 * *
6084 * Routines to handle XPath contexts *
6085 * *
6086 ************************************************************************/
6087
6088/**
6089 * xmlXPathNewContext:
6090 * @doc: the XML document
6091 *
6092 * Create a new xmlXPathContext
6093 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00006094 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00006095 */
6096xmlXPathContextPtr
6097xmlXPathNewContext(xmlDocPtr doc) {
6098 xmlXPathContextPtr ret;
6099
6100 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6101 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006102 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006103 return(NULL);
6104 }
6105 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6106 ret->doc = doc;
6107 ret->node = NULL;
6108
6109 ret->varHash = NULL;
6110
6111 ret->nb_types = 0;
6112 ret->max_types = 0;
6113 ret->types = NULL;
6114
6115 ret->funcHash = xmlHashCreate(0);
6116
6117 ret->nb_axis = 0;
6118 ret->max_axis = 0;
6119 ret->axis = NULL;
6120
6121 ret->nsHash = NULL;
6122 ret->user = NULL;
6123
6124 ret->contextSize = -1;
6125 ret->proximityPosition = -1;
6126
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006127#ifdef XP_DEFAULT_CACHE_ON
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006128 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006129 xmlXPathFreeContext(ret);
6130 return(NULL);
6131 }
6132#endif
6133
Daniel Veillard45490ae2008-07-29 09:13:19 +00006134 xmlXPathRegisterAllFunctions(ret);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006135
Owen Taylor3473f882001-02-23 17:55:21 +00006136 return(ret);
6137}
6138
6139/**
6140 * xmlXPathFreeContext:
6141 * @ctxt: the context to free
6142 *
6143 * Free up an xmlXPathContext
6144 */
6145void
6146xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006147 if (ctxt == NULL) return;
6148
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006149 if (ctxt->cache != NULL)
6150 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
Owen Taylor3473f882001-02-23 17:55:21 +00006151 xmlXPathRegisteredNsCleanup(ctxt);
6152 xmlXPathRegisteredFuncsCleanup(ctxt);
6153 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006154 xmlResetError(&ctxt->lastError);
Owen Taylor3473f882001-02-23 17:55:21 +00006155 xmlFree(ctxt);
6156}
6157
6158/************************************************************************
6159 * *
6160 * Routines to handle XPath parser contexts *
6161 * *
6162 ************************************************************************/
6163
6164#define CHECK_CTXT(ctxt) \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006165 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00006166 __xmlRaiseError(NULL, NULL, NULL, \
6167 NULL, NULL, XML_FROM_XPATH, \
6168 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6169 __FILE__, __LINE__, \
6170 NULL, NULL, NULL, 0, 0, \
6171 "NULL context pointer\n"); \
6172 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00006173 } \
6174
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006175#define CHECK_CTXT_NEG(ctxt) \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006176 if (ctxt == NULL) { \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006177 __xmlRaiseError(NULL, NULL, NULL, \
6178 NULL, NULL, XML_FROM_XPATH, \
6179 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6180 __FILE__, __LINE__, \
6181 NULL, NULL, NULL, 0, 0, \
6182 "NULL context pointer\n"); \
6183 return(-1); \
6184 } \
6185
Owen Taylor3473f882001-02-23 17:55:21 +00006186
6187#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00006188 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006189 (ctxt->doc->children == NULL)) { \
Daniel Veillard57b25162004-11-06 14:50:18 +00006190 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00006191 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00006192 }
Owen Taylor3473f882001-02-23 17:55:21 +00006193
6194
6195/**
6196 * xmlXPathNewParserContext:
6197 * @str: the XPath expression
6198 * @ctxt: the XPath context
6199 *
6200 * Create a new xmlXPathParserContext
6201 *
6202 * Returns the xmlXPathParserContext just allocated.
6203 */
6204xmlXPathParserContextPtr
6205xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6206 xmlXPathParserContextPtr ret;
6207
6208 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6209 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006210 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006211 return(NULL);
6212 }
6213 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6214 ret->cur = ret->base = str;
6215 ret->context = ctxt;
6216
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006217 ret->comp = xmlXPathNewCompExpr();
6218 if (ret->comp == NULL) {
6219 xmlFree(ret->valueTab);
6220 xmlFree(ret);
6221 return(NULL);
6222 }
Daniel Veillard4773df22004-01-23 13:15:13 +00006223 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6224 ret->comp->dict = ctxt->dict;
6225 xmlDictReference(ret->comp->dict);
6226 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006227
6228 return(ret);
6229}
6230
6231/**
6232 * xmlXPathCompParserContext:
6233 * @comp: the XPath compiled expression
6234 * @ctxt: the XPath context
6235 *
6236 * Create a new xmlXPathParserContext when processing a compiled expression
6237 *
6238 * Returns the xmlXPathParserContext just allocated.
6239 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006240static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006241xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6242 xmlXPathParserContextPtr ret;
6243
6244 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6245 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006246 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006247 return(NULL);
6248 }
6249 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6250
Owen Taylor3473f882001-02-23 17:55:21 +00006251 /* Allocate the value stack */
Daniel Veillard45490ae2008-07-29 09:13:19 +00006252 ret->valueTab = (xmlXPathObjectPtr *)
Owen Taylor3473f882001-02-23 17:55:21 +00006253 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006254 if (ret->valueTab == NULL) {
6255 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006256 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006257 return(NULL);
6258 }
Owen Taylor3473f882001-02-23 17:55:21 +00006259 ret->valueNr = 0;
6260 ret->valueMax = 10;
6261 ret->value = NULL;
Daniel Veillardf5048b32011-08-18 17:10:13 +08006262 ret->valueFrame = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006263
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006264 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006265 ret->comp = comp;
6266
Owen Taylor3473f882001-02-23 17:55:21 +00006267 return(ret);
6268}
6269
6270/**
6271 * xmlXPathFreeParserContext:
6272 * @ctxt: the context to free
6273 *
6274 * Free up an xmlXPathParserContext
6275 */
6276void
6277xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
Nick Wellnhoferc8519702017-05-27 15:26:11 +02006278 int i;
6279
Owen Taylor3473f882001-02-23 17:55:21 +00006280 if (ctxt->valueTab != NULL) {
Nick Wellnhoferc8519702017-05-27 15:26:11 +02006281 for (i = 0; i < ctxt->valueNr; i++) {
6282 if (ctxt->context)
6283 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6284 else
6285 xmlXPathFreeObject(ctxt->valueTab[i]);
6286 }
Owen Taylor3473f882001-02-23 17:55:21 +00006287 xmlFree(ctxt->valueTab);
6288 }
Daniel Veillard56de87e2005-02-16 00:22:29 +00006289 if (ctxt->comp != NULL) {
6290#ifdef XPATH_STREAMING
6291 if (ctxt->comp->stream != NULL) {
6292 xmlFreePatternList(ctxt->comp->stream);
6293 ctxt->comp->stream = NULL;
6294 }
6295#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006296 xmlXPathFreeCompExpr(ctxt->comp);
Daniel Veillard56de87e2005-02-16 00:22:29 +00006297 }
Owen Taylor3473f882001-02-23 17:55:21 +00006298 xmlFree(ctxt);
6299}
6300
6301/************************************************************************
6302 * *
6303 * The implicit core function library *
6304 * *
6305 ************************************************************************/
6306
Owen Taylor3473f882001-02-23 17:55:21 +00006307/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006308 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00006309 * @node: a node pointer
6310 *
6311 * Function computing the beginning of the string value of the node,
6312 * used to speed up comparisons
6313 *
6314 * Returns an int usable as a hash
6315 */
6316static unsigned int
6317xmlXPathNodeValHash(xmlNodePtr node) {
6318 int len = 2;
6319 const xmlChar * string = NULL;
6320 xmlNodePtr tmp = NULL;
6321 unsigned int ret = 0;
6322
6323 if (node == NULL)
6324 return(0);
6325
Daniel Veillard9adc0462003-03-24 18:39:54 +00006326 if (node->type == XML_DOCUMENT_NODE) {
6327 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6328 if (tmp == NULL)
6329 node = node->children;
6330 else
6331 node = tmp;
6332
6333 if (node == NULL)
6334 return(0);
6335 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006336
6337 switch (node->type) {
6338 case XML_COMMENT_NODE:
6339 case XML_PI_NODE:
6340 case XML_CDATA_SECTION_NODE:
6341 case XML_TEXT_NODE:
6342 string = node->content;
6343 if (string == NULL)
6344 return(0);
6345 if (string[0] == 0)
6346 return(0);
6347 return(((unsigned int) string[0]) +
6348 (((unsigned int) string[1]) << 8));
6349 case XML_NAMESPACE_DECL:
6350 string = ((xmlNsPtr)node)->href;
6351 if (string == NULL)
6352 return(0);
6353 if (string[0] == 0)
6354 return(0);
6355 return(((unsigned int) string[0]) +
6356 (((unsigned int) string[1]) << 8));
6357 case XML_ATTRIBUTE_NODE:
6358 tmp = ((xmlAttrPtr) node)->children;
6359 break;
6360 case XML_ELEMENT_NODE:
6361 tmp = node->children;
6362 break;
6363 default:
6364 return(0);
6365 }
6366 while (tmp != NULL) {
6367 switch (tmp->type) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006368 case XML_CDATA_SECTION_NODE:
6369 case XML_TEXT_NODE:
6370 string = tmp->content;
6371 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006372 default:
Nick Wellnhofer5af594d2017-10-07 14:54:45 +02006373 string = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006374 break;
6375 }
6376 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006377 if (len == 1) {
6378 return(ret + (((unsigned int) string[0]) << 8));
6379 }
6380 if (string[1] == 0) {
6381 len = 1;
6382 ret = (unsigned int) string[0];
6383 } else {
6384 return(((unsigned int) string[0]) +
6385 (((unsigned int) string[1]) << 8));
6386 }
6387 }
6388 /*
6389 * Skip to next node
6390 */
6391 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6392 if (tmp->children->type != XML_ENTITY_DECL) {
6393 tmp = tmp->children;
6394 continue;
6395 }
6396 }
6397 if (tmp == node)
6398 break;
6399
6400 if (tmp->next != NULL) {
6401 tmp = tmp->next;
6402 continue;
6403 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00006404
Daniel Veillardf06307e2001-07-03 10:35:50 +00006405 do {
6406 tmp = tmp->parent;
6407 if (tmp == NULL)
6408 break;
6409 if (tmp == node) {
6410 tmp = NULL;
6411 break;
6412 }
6413 if (tmp->next != NULL) {
6414 tmp = tmp->next;
6415 break;
6416 }
6417 } while (tmp != NULL);
6418 }
6419 return(ret);
6420}
6421
6422/**
6423 * xmlXPathStringHash:
6424 * @string: a string
6425 *
6426 * Function computing the beginning of the string value of the node,
6427 * used to speed up comparisons
6428 *
6429 * Returns an int usable as a hash
6430 */
6431static unsigned int
6432xmlXPathStringHash(const xmlChar * string) {
6433 if (string == NULL)
6434 return((unsigned int) 0);
6435 if (string[0] == 0)
6436 return(0);
6437 return(((unsigned int) string[0]) +
6438 (((unsigned int) string[1]) << 8));
6439}
6440
6441/**
Owen Taylor3473f882001-02-23 17:55:21 +00006442 * xmlXPathCompareNodeSetFloat:
6443 * @ctxt: the XPath Parser context
6444 * @inf: less than (1) or greater than (0)
6445 * @strict: is the comparison strict
6446 * @arg: the node set
6447 * @f: the value
6448 *
6449 * Implement the compare operation between a nodeset and a number
6450 * @ns < @val (1, 1, ...
6451 * @ns <= @val (1, 0, ...
6452 * @ns > @val (0, 1, ...
6453 * @ns >= @val (0, 0, ...
6454 *
6455 * If one object to be compared is a node-set and the other is a number,
6456 * then the comparison will be true if and only if there is a node in the
6457 * node-set such that the result of performing the comparison on the number
6458 * to be compared and on the result of converting the string-value of that
6459 * node to a number using the number function is true.
6460 *
6461 * Returns 0 or 1 depending on the results of the test.
6462 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006463static int
Owen Taylor3473f882001-02-23 17:55:21 +00006464xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6465 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6466 int i, ret = 0;
6467 xmlNodeSetPtr ns;
6468 xmlChar *str2;
6469
6470 if ((f == NULL) || (arg == NULL) ||
6471 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006472 xmlXPathReleaseObject(ctxt->context, arg);
6473 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006474 return(0);
6475 }
6476 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006477 if (ns != NULL) {
6478 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006479 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006480 if (str2 != NULL) {
6481 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006482 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006483 xmlFree(str2);
6484 xmlXPathNumberFunction(ctxt, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006485 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006486 ret = xmlXPathCompareValues(ctxt, inf, strict);
6487 if (ret)
6488 break;
6489 }
6490 }
Owen Taylor3473f882001-02-23 17:55:21 +00006491 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006492 xmlXPathReleaseObject(ctxt->context, arg);
6493 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006494 return(ret);
6495}
6496
6497/**
6498 * xmlXPathCompareNodeSetString:
6499 * @ctxt: the XPath Parser context
6500 * @inf: less than (1) or greater than (0)
6501 * @strict: is the comparison strict
6502 * @arg: the node set
6503 * @s: the value
6504 *
6505 * Implement the compare operation between a nodeset and a string
6506 * @ns < @val (1, 1, ...
6507 * @ns <= @val (1, 0, ...
6508 * @ns > @val (0, 1, ...
6509 * @ns >= @val (0, 0, ...
6510 *
6511 * If one object to be compared is a node-set and the other is a string,
6512 * then the comparison will be true if and only if there is a node in
6513 * the node-set such that the result of performing the comparison on the
6514 * string-value of the node and the other string is true.
6515 *
6516 * Returns 0 or 1 depending on the results of the test.
6517 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006518static int
Owen Taylor3473f882001-02-23 17:55:21 +00006519xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6520 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6521 int i, ret = 0;
6522 xmlNodeSetPtr ns;
6523 xmlChar *str2;
6524
6525 if ((s == NULL) || (arg == NULL) ||
6526 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006527 xmlXPathReleaseObject(ctxt->context, arg);
6528 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006529 return(0);
6530 }
6531 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006532 if (ns != NULL) {
6533 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006534 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006535 if (str2 != NULL) {
6536 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006537 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006538 xmlFree(str2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006539 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006540 ret = xmlXPathCompareValues(ctxt, inf, strict);
6541 if (ret)
6542 break;
6543 }
6544 }
Owen Taylor3473f882001-02-23 17:55:21 +00006545 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006546 xmlXPathReleaseObject(ctxt->context, arg);
6547 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006548 return(ret);
6549}
6550
6551/**
6552 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006553 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00006554 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006555 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00006556 * @arg2: the second node set object
6557 *
6558 * Implement the compare operation on nodesets:
6559 *
6560 * If both objects to be compared are node-sets, then the comparison
6561 * will be true if and only if there is a node in the first node-set
6562 * and a node in the second node-set such that the result of performing
Daniel Veillard45490ae2008-07-29 09:13:19 +00006563 * the comparison on the string-values of the two nodes is true.
Owen Taylor3473f882001-02-23 17:55:21 +00006564 * ....
6565 * When neither object to be compared is a node-set and the operator
6566 * is <=, <, >= or >, then the objects are compared by converting both
6567 * objects to numbers and comparing the numbers according to IEEE 754.
6568 * ....
6569 * The number function converts its argument to a number as follows:
6570 * - a string that consists of optional whitespace followed by an
6571 * optional minus sign followed by a Number followed by whitespace
6572 * is converted to the IEEE 754 number that is nearest (according
6573 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6574 * represented by the string; any other string is converted to NaN
6575 *
6576 * Conclusion all nodes need to be converted first to their string value
Daniel Veillard45490ae2008-07-29 09:13:19 +00006577 * and then the comparison must be done when possible
Owen Taylor3473f882001-02-23 17:55:21 +00006578 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006579static int
6580xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00006581 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6582 int i, j, init = 0;
6583 double val1;
6584 double *values2;
6585 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006586 xmlNodeSetPtr ns1;
6587 xmlNodeSetPtr ns2;
6588
6589 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006590 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6591 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006592 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006593 }
Owen Taylor3473f882001-02-23 17:55:21 +00006594 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006595 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6596 xmlXPathFreeObject(arg1);
6597 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006598 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006599 }
Owen Taylor3473f882001-02-23 17:55:21 +00006600
6601 ns1 = arg1->nodesetval;
6602 ns2 = arg2->nodesetval;
6603
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006604 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006605 xmlXPathFreeObject(arg1);
6606 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006607 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006608 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006609 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006610 xmlXPathFreeObject(arg1);
6611 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006612 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006613 }
Owen Taylor3473f882001-02-23 17:55:21 +00006614
6615 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6616 if (values2 == NULL) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07006617 /* TODO: Propagate memory error. */
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006618 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00006619 xmlXPathFreeObject(arg1);
6620 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006621 return(0);
6622 }
6623 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006624 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00006625 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00006626 continue;
6627 for (j = 0;j < ns2->nodeNr;j++) {
6628 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006629 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00006630 }
Daniel Veillardcda96922001-08-21 10:56:31 +00006631 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00006632 continue;
Daniel Veillard45490ae2008-07-29 09:13:19 +00006633 if (inf && strict)
Owen Taylor3473f882001-02-23 17:55:21 +00006634 ret = (val1 < values2[j]);
6635 else if (inf && !strict)
6636 ret = (val1 <= values2[j]);
6637 else if (!inf && strict)
6638 ret = (val1 > values2[j]);
6639 else if (!inf && !strict)
6640 ret = (val1 >= values2[j]);
6641 if (ret)
6642 break;
6643 }
6644 if (ret)
6645 break;
6646 init = 1;
6647 }
6648 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006649 xmlXPathFreeObject(arg1);
6650 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006651 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006652}
6653
6654/**
6655 * xmlXPathCompareNodeSetValue:
6656 * @ctxt: the XPath Parser context
6657 * @inf: less than (1) or greater than (0)
6658 * @strict: is the comparison strict
6659 * @arg: the node set
6660 * @val: the value
6661 *
6662 * Implement the compare operation between a nodeset and a value
6663 * @ns < @val (1, 1, ...
6664 * @ns <= @val (1, 0, ...
6665 * @ns > @val (0, 1, ...
6666 * @ns >= @val (0, 0, ...
6667 *
6668 * If one object to be compared is a node-set and the other is a boolean,
6669 * then the comparison will be true if and only if the result of performing
6670 * the comparison on the boolean and on the result of converting
6671 * the node-set to a boolean using the boolean function is true.
6672 *
6673 * Returns 0 or 1 depending on the results of the test.
6674 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006675static int
Owen Taylor3473f882001-02-23 17:55:21 +00006676xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6677 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6678 if ((val == NULL) || (arg == NULL) ||
6679 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6680 return(0);
6681
6682 switch(val->type) {
6683 case XPATH_NUMBER:
6684 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6685 case XPATH_NODESET:
6686 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006687 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00006688 case XPATH_STRING:
6689 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6690 case XPATH_BOOLEAN:
6691 valuePush(ctxt, arg);
6692 xmlXPathBooleanFunction(ctxt, 1);
6693 valuePush(ctxt, val);
6694 return(xmlXPathCompareValues(ctxt, inf, strict));
6695 default:
Nick Wellnhofercf60dbe2017-05-25 16:20:56 +02006696 xmlGenericError(xmlGenericErrorContext,
6697 "xmlXPathCompareNodeSetValue: Can't compare node set "
6698 "and object of type %d\n",
6699 val->type);
6700 xmlXPathReleaseObject(ctxt->context, arg);
6701 xmlXPathReleaseObject(ctxt->context, val);
6702 XP_ERROR0(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006703 }
6704 return(0);
6705}
6706
6707/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006708 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00006709 * @arg: the nodeset object argument
6710 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00006711 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006712 *
6713 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6714 * If one object to be compared is a node-set and the other is a string,
6715 * then the comparison will be true if and only if there is a node in
6716 * the node-set such that the result of performing the comparison on the
6717 * string-value of the node and the other string is true.
6718 *
6719 * Returns 0 or 1 depending on the results of the test.
6720 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006721static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006722xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006723{
Owen Taylor3473f882001-02-23 17:55:21 +00006724 int i;
6725 xmlNodeSetPtr ns;
6726 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006727 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00006728
6729 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00006730 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6731 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006732 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00006733 /*
6734 * A NULL nodeset compared with a string is always false
6735 * (since there is no node equal, and no node not equal)
6736 */
6737 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00006738 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00006739 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006740 for (i = 0; i < ns->nodeNr; i++) {
6741 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6742 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6743 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6744 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006745 if (neq)
6746 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006747 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00006748 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6749 if (neq)
6750 continue;
6751 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006752 } else if (neq) {
6753 if (str2 != NULL)
6754 xmlFree(str2);
6755 return (1);
6756 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006757 if (str2 != NULL)
6758 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006759 } else if (neq)
6760 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00006761 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006762 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006763}
6764
6765/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006766 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00006767 * @arg: the nodeset object argument
6768 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00006769 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006770 *
6771 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6772 * If one object to be compared is a node-set and the other is a number,
6773 * then the comparison will be true if and only if there is a node in
6774 * the node-set such that the result of performing the comparison on the
6775 * number to be compared and on the result of converting the string-value
6776 * of that node to a number using the number function is true.
6777 *
6778 * Returns 0 or 1 depending on the results of the test.
6779 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006780static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006781xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6782 xmlXPathObjectPtr arg, double f, int neq) {
6783 int i, ret=0;
6784 xmlNodeSetPtr ns;
6785 xmlChar *str2;
6786 xmlXPathObjectPtr val;
6787 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00006788
6789 if ((arg == NULL) ||
6790 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6791 return(0);
6792
William M. Brack0c022ad2002-07-12 00:56:01 +00006793 ns = arg->nodesetval;
6794 if (ns != NULL) {
6795 for (i=0;i<ns->nodeNr;i++) {
6796 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6797 if (str2 != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006798 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
William M. Brack0c022ad2002-07-12 00:56:01 +00006799 xmlFree(str2);
6800 xmlXPathNumberFunction(ctxt, 1);
6801 val = valuePop(ctxt);
6802 v = val->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006803 xmlXPathReleaseObject(ctxt->context, val);
William M. Brack0c022ad2002-07-12 00:56:01 +00006804 if (!xmlXPathIsNaN(v)) {
6805 if ((!neq) && (v==f)) {
6806 ret = 1;
6807 break;
6808 } else if ((neq) && (v!=f)) {
6809 ret = 1;
6810 break;
6811 }
William M. Brack32f0f712005-07-14 07:00:33 +00006812 } else { /* NaN is unequal to any value */
6813 if (neq)
6814 ret = 1;
William M. Brack0c022ad2002-07-12 00:56:01 +00006815 }
6816 }
6817 }
6818 }
6819
6820 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006821}
6822
6823
6824/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006825 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00006826 * @arg1: first nodeset object argument
6827 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00006828 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006829 *
William M. Brack0c022ad2002-07-12 00:56:01 +00006830 * Implement the equal / not equal operation on XPath nodesets:
6831 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00006832 * If both objects to be compared are node-sets, then the comparison
6833 * will be true if and only if there is a node in the first node-set and
6834 * a node in the second node-set such that the result of performing the
6835 * comparison on the string-values of the two nodes is true.
6836 *
6837 * (needless to say, this is a costly operation)
6838 *
6839 * Returns 0 or 1 depending on the results of the test.
6840 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006841static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006842xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00006843 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006844 unsigned int *hashs1;
6845 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00006846 xmlChar **values1;
6847 xmlChar **values2;
6848 int ret = 0;
6849 xmlNodeSetPtr ns1;
6850 xmlNodeSetPtr ns2;
6851
6852 if ((arg1 == NULL) ||
6853 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6854 return(0);
6855 if ((arg2 == NULL) ||
6856 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6857 return(0);
6858
6859 ns1 = arg1->nodesetval;
6860 ns2 = arg2->nodesetval;
6861
Daniel Veillard911f49a2001-04-07 15:39:35 +00006862 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006863 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006864 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006865 return(0);
6866
6867 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00006868 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00006869 */
William M. Brack0c022ad2002-07-12 00:56:01 +00006870 if (neq == 0)
6871 for (i = 0;i < ns1->nodeNr;i++)
6872 for (j = 0;j < ns2->nodeNr;j++)
6873 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6874 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006875
6876 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006877 if (values1 == NULL) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07006878 /* TODO: Propagate memory error. */
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006879 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006880 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006881 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006882 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6883 if (hashs1 == NULL) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07006884 /* TODO: Propagate memory error. */
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006885 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006886 xmlFree(values1);
6887 return(0);
6888 }
Owen Taylor3473f882001-02-23 17:55:21 +00006889 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6890 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6891 if (values2 == NULL) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07006892 /* TODO: Propagate memory error. */
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006893 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006894 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00006895 xmlFree(values1);
6896 return(0);
6897 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006898 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6899 if (hashs2 == NULL) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07006900 /* TODO: Propagate memory error. */
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006901 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006902 xmlFree(hashs1);
6903 xmlFree(values1);
6904 xmlFree(values2);
6905 return(0);
6906 }
Owen Taylor3473f882001-02-23 17:55:21 +00006907 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6908 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006909 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006910 for (j = 0;j < ns2->nodeNr;j++) {
6911 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006912 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006913 if (hashs1[i] != hashs2[j]) {
6914 if (neq) {
6915 ret = 1;
6916 break;
6917 }
6918 }
6919 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006920 if (values1[i] == NULL)
6921 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6922 if (values2[j] == NULL)
6923 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006924 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006925 if (ret)
6926 break;
6927 }
Owen Taylor3473f882001-02-23 17:55:21 +00006928 }
6929 if (ret)
6930 break;
6931 }
6932 for (i = 0;i < ns1->nodeNr;i++)
6933 if (values1[i] != NULL)
6934 xmlFree(values1[i]);
6935 for (j = 0;j < ns2->nodeNr;j++)
6936 if (values2[j] != NULL)
6937 xmlFree(values2[j]);
6938 xmlFree(values1);
6939 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006940 xmlFree(hashs1);
6941 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00006942 return(ret);
6943}
6944
William M. Brack0c022ad2002-07-12 00:56:01 +00006945static int
6946xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6947 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00006948 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00006949 /*
6950 *At this point we are assured neither arg1 nor arg2
6951 *is a nodeset, so we can just pick the appropriate routine.
6952 */
Owen Taylor3473f882001-02-23 17:55:21 +00006953 switch (arg1->type) {
6954 case XPATH_UNDEFINED:
6955#ifdef DEBUG_EXPR
6956 xmlGenericError(xmlGenericErrorContext,
6957 "Equal: undefined\n");
6958#endif
6959 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006960 case XPATH_BOOLEAN:
6961 switch (arg2->type) {
6962 case XPATH_UNDEFINED:
6963#ifdef DEBUG_EXPR
6964 xmlGenericError(xmlGenericErrorContext,
6965 "Equal: undefined\n");
6966#endif
6967 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006968 case XPATH_BOOLEAN:
6969#ifdef DEBUG_EXPR
6970 xmlGenericError(xmlGenericErrorContext,
6971 "Equal: %d boolean %d \n",
6972 arg1->boolval, arg2->boolval);
6973#endif
6974 ret = (arg1->boolval == arg2->boolval);
6975 break;
6976 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00006977 ret = (arg1->boolval ==
6978 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006979 break;
6980 case XPATH_STRING:
6981 if ((arg2->stringval == NULL) ||
6982 (arg2->stringval[0] == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00006983 else
Owen Taylor3473f882001-02-23 17:55:21 +00006984 ret = 1;
6985 ret = (arg1->boolval == ret);
6986 break;
6987 case XPATH_USERS:
6988 case XPATH_POINT:
6989 case XPATH_RANGE:
6990 case XPATH_LOCATIONSET:
6991 TODO
6992 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006993 case XPATH_NODESET:
6994 case XPATH_XSLT_TREE:
6995 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006996 }
6997 break;
6998 case XPATH_NUMBER:
6999 switch (arg2->type) {
7000 case XPATH_UNDEFINED:
7001#ifdef DEBUG_EXPR
7002 xmlGenericError(xmlGenericErrorContext,
7003 "Equal: undefined\n");
7004#endif
7005 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007006 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00007007 ret = (arg2->boolval==
7008 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00007009 break;
7010 case XPATH_STRING:
7011 valuePush(ctxt, arg2);
7012 xmlXPathNumberFunction(ctxt, 1);
7013 arg2 = valuePop(ctxt);
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +02007014 /* Falls through. */
Owen Taylor3473f882001-02-23 17:55:21 +00007015 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007016 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00007017 if (xmlXPathIsNaN(arg1->floatval) ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00007018 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00007019 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007020 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7021 if (xmlXPathIsInf(arg2->floatval) == 1)
7022 ret = 1;
7023 else
7024 ret = 0;
7025 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7026 if (xmlXPathIsInf(arg2->floatval) == -1)
7027 ret = 1;
7028 else
7029 ret = 0;
7030 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7031 if (xmlXPathIsInf(arg1->floatval) == 1)
7032 ret = 1;
7033 else
7034 ret = 0;
7035 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7036 if (xmlXPathIsInf(arg1->floatval) == -1)
7037 ret = 1;
7038 else
7039 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007040 } else {
7041 ret = (arg1->floatval == arg2->floatval);
7042 }
Owen Taylor3473f882001-02-23 17:55:21 +00007043 break;
7044 case XPATH_USERS:
7045 case XPATH_POINT:
7046 case XPATH_RANGE:
7047 case XPATH_LOCATIONSET:
7048 TODO
7049 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007050 case XPATH_NODESET:
7051 case XPATH_XSLT_TREE:
7052 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007053 }
7054 break;
7055 case XPATH_STRING:
7056 switch (arg2->type) {
7057 case XPATH_UNDEFINED:
7058#ifdef DEBUG_EXPR
7059 xmlGenericError(xmlGenericErrorContext,
7060 "Equal: undefined\n");
7061#endif
7062 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007063 case XPATH_BOOLEAN:
7064 if ((arg1->stringval == NULL) ||
7065 (arg1->stringval[0] == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007066 else
Owen Taylor3473f882001-02-23 17:55:21 +00007067 ret = 1;
7068 ret = (arg2->boolval == ret);
7069 break;
7070 case XPATH_STRING:
7071 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7072 break;
7073 case XPATH_NUMBER:
7074 valuePush(ctxt, arg1);
7075 xmlXPathNumberFunction(ctxt, 1);
7076 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007077 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00007078 if (xmlXPathIsNaN(arg1->floatval) ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00007079 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00007080 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007081 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7082 if (xmlXPathIsInf(arg2->floatval) == 1)
7083 ret = 1;
7084 else
7085 ret = 0;
7086 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7087 if (xmlXPathIsInf(arg2->floatval) == -1)
7088 ret = 1;
7089 else
7090 ret = 0;
7091 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7092 if (xmlXPathIsInf(arg1->floatval) == 1)
7093 ret = 1;
7094 else
7095 ret = 0;
7096 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7097 if (xmlXPathIsInf(arg1->floatval) == -1)
7098 ret = 1;
7099 else
7100 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007101 } else {
7102 ret = (arg1->floatval == arg2->floatval);
7103 }
Owen Taylor3473f882001-02-23 17:55:21 +00007104 break;
7105 case XPATH_USERS:
7106 case XPATH_POINT:
7107 case XPATH_RANGE:
7108 case XPATH_LOCATIONSET:
7109 TODO
7110 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007111 case XPATH_NODESET:
7112 case XPATH_XSLT_TREE:
7113 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007114 }
7115 break;
7116 case XPATH_USERS:
7117 case XPATH_POINT:
7118 case XPATH_RANGE:
7119 case XPATH_LOCATIONSET:
7120 TODO
7121 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007122 case XPATH_NODESET:
7123 case XPATH_XSLT_TREE:
7124 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007125 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007126 xmlXPathReleaseObject(ctxt->context, arg1);
7127 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007128 return(ret);
7129}
7130
William M. Brack0c022ad2002-07-12 00:56:01 +00007131/**
7132 * xmlXPathEqualValues:
7133 * @ctxt: the XPath Parser context
7134 *
7135 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7136 *
7137 * Returns 0 or 1 depending on the results of the test.
7138 */
7139int
7140xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7141 xmlXPathObjectPtr arg1, arg2, argtmp;
7142 int ret = 0;
7143
Daniel Veillard6128c012004-11-08 17:16:15 +00007144 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007145 arg2 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007146 arg1 = valuePop(ctxt);
7147 if ((arg1 == NULL) || (arg2 == NULL)) {
7148 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007149 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007150 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007151 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007152 XP_ERROR0(XPATH_INVALID_OPERAND);
7153 }
7154
7155 if (arg1 == arg2) {
7156#ifdef DEBUG_EXPR
7157 xmlGenericError(xmlGenericErrorContext,
7158 "Equal: by pointer\n");
7159#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00007160 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007161 return(1);
7162 }
7163
7164 /*
7165 *If either argument is a nodeset, it's a 'special case'
7166 */
7167 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7168 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7169 /*
7170 *Hack it to assure arg1 is the nodeset
7171 */
7172 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7173 argtmp = arg2;
7174 arg2 = arg1;
7175 arg1 = argtmp;
7176 }
7177 switch (arg2->type) {
7178 case XPATH_UNDEFINED:
7179#ifdef DEBUG_EXPR
7180 xmlGenericError(xmlGenericErrorContext,
7181 "Equal: undefined\n");
7182#endif
7183 break;
7184 case XPATH_NODESET:
7185 case XPATH_XSLT_TREE:
7186 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7187 break;
7188 case XPATH_BOOLEAN:
7189 if ((arg1->nodesetval == NULL) ||
7190 (arg1->nodesetval->nodeNr == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007191 else
William M. Brack0c022ad2002-07-12 00:56:01 +00007192 ret = 1;
7193 ret = (ret == arg2->boolval);
7194 break;
7195 case XPATH_NUMBER:
7196 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7197 break;
7198 case XPATH_STRING:
7199 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7200 break;
7201 case XPATH_USERS:
7202 case XPATH_POINT:
7203 case XPATH_RANGE:
7204 case XPATH_LOCATIONSET:
7205 TODO
7206 break;
7207 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007208 xmlXPathReleaseObject(ctxt->context, arg1);
7209 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007210 return(ret);
7211 }
7212
7213 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7214}
7215
7216/**
7217 * xmlXPathNotEqualValues:
7218 * @ctxt: the XPath Parser context
7219 *
7220 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7221 *
7222 * Returns 0 or 1 depending on the results of the test.
7223 */
7224int
7225xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7226 xmlXPathObjectPtr arg1, arg2, argtmp;
7227 int ret = 0;
7228
Daniel Veillard6128c012004-11-08 17:16:15 +00007229 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007230 arg2 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007231 arg1 = valuePop(ctxt);
7232 if ((arg1 == NULL) || (arg2 == NULL)) {
7233 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007234 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007235 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007236 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007237 XP_ERROR0(XPATH_INVALID_OPERAND);
7238 }
7239
7240 if (arg1 == arg2) {
7241#ifdef DEBUG_EXPR
7242 xmlGenericError(xmlGenericErrorContext,
7243 "NotEqual: by pointer\n");
7244#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007245 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007246 return(0);
7247 }
7248
7249 /*
7250 *If either argument is a nodeset, it's a 'special case'
7251 */
7252 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7253 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7254 /*
7255 *Hack it to assure arg1 is the nodeset
7256 */
7257 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7258 argtmp = arg2;
7259 arg2 = arg1;
7260 arg1 = argtmp;
7261 }
7262 switch (arg2->type) {
7263 case XPATH_UNDEFINED:
7264#ifdef DEBUG_EXPR
7265 xmlGenericError(xmlGenericErrorContext,
7266 "NotEqual: undefined\n");
7267#endif
7268 break;
7269 case XPATH_NODESET:
7270 case XPATH_XSLT_TREE:
7271 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7272 break;
7273 case XPATH_BOOLEAN:
7274 if ((arg1->nodesetval == NULL) ||
7275 (arg1->nodesetval->nodeNr == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007276 else
William M. Brack0c022ad2002-07-12 00:56:01 +00007277 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00007278 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00007279 break;
7280 case XPATH_NUMBER:
7281 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7282 break;
7283 case XPATH_STRING:
7284 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7285 break;
7286 case XPATH_USERS:
7287 case XPATH_POINT:
7288 case XPATH_RANGE:
7289 case XPATH_LOCATIONSET:
7290 TODO
7291 break;
7292 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007293 xmlXPathReleaseObject(ctxt->context, arg1);
7294 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007295 return(ret);
7296 }
7297
7298 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7299}
Owen Taylor3473f882001-02-23 17:55:21 +00007300
7301/**
7302 * xmlXPathCompareValues:
7303 * @ctxt: the XPath Parser context
7304 * @inf: less than (1) or greater than (0)
7305 * @strict: is the comparison strict
7306 *
Daniel Veillard45490ae2008-07-29 09:13:19 +00007307 * Implement the compare operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007308 * @arg1 < @arg2 (1, 1, ...
7309 * @arg1 <= @arg2 (1, 0, ...
7310 * @arg1 > @arg2 (0, 1, ...
7311 * @arg1 >= @arg2 (0, 0, ...
7312 *
7313 * When neither object to be compared is a node-set and the operator is
7314 * <=, <, >=, >, then the objects are compared by converted both objects
7315 * to numbers and comparing the numbers according to IEEE 754. The <
7316 * comparison will be true if and only if the first number is less than the
7317 * second number. The <= comparison will be true if and only if the first
7318 * number is less than or equal to the second number. The > comparison
7319 * will be true if and only if the first number is greater than the second
7320 * number. The >= comparison will be true if and only if the first number
7321 * is greater than or equal to the second number.
7322 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007323 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00007324 */
7325int
7326xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007327 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007328 xmlXPathObjectPtr arg1, arg2;
7329
Daniel Veillard6128c012004-11-08 17:16:15 +00007330 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007331 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007332 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007333 if ((arg1 == NULL) || (arg2 == NULL)) {
7334 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007335 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007336 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007337 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007338 XP_ERROR0(XPATH_INVALID_OPERAND);
7339 }
7340
William M. Brack0c022ad2002-07-12 00:56:01 +00007341 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7342 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
William M. Brackd6e347e2005-04-15 01:34:41 +00007343 /*
7344 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7345 * are not freed from within this routine; they will be freed from the
7346 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7347 */
William M. Brack0c022ad2002-07-12 00:56:01 +00007348 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7349 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007350 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007351 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00007352 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007353 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7354 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007355 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007356 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7357 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00007358 }
7359 }
7360 return(ret);
7361 }
7362
7363 if (arg1->type != XPATH_NUMBER) {
7364 valuePush(ctxt, arg1);
7365 xmlXPathNumberFunction(ctxt, 1);
7366 arg1 = valuePop(ctxt);
7367 }
7368 if (arg1->type != XPATH_NUMBER) {
7369 xmlXPathFreeObject(arg1);
7370 xmlXPathFreeObject(arg2);
7371 XP_ERROR0(XPATH_INVALID_OPERAND);
7372 }
7373 if (arg2->type != XPATH_NUMBER) {
7374 valuePush(ctxt, arg2);
7375 xmlXPathNumberFunction(ctxt, 1);
7376 arg2 = valuePop(ctxt);
7377 }
7378 if (arg2->type != XPATH_NUMBER) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007379 xmlXPathReleaseObject(ctxt->context, arg1);
7380 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007381 XP_ERROR0(XPATH_INVALID_OPERAND);
7382 }
7383 /*
7384 * Add tests for infinity and nan
7385 * => feedback on 3.4 for Inf and NaN
7386 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007387 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00007388 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007389 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007390 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007391 arg1i=xmlXPathIsInf(arg1->floatval);
7392 arg2i=xmlXPathIsInf(arg2->floatval);
7393 if (inf && strict) {
7394 if ((arg1i == -1 && arg2i != -1) ||
7395 (arg2i == 1 && arg1i != 1)) {
7396 ret = 1;
7397 } else if (arg1i == 0 && arg2i == 0) {
7398 ret = (arg1->floatval < arg2->floatval);
7399 } else {
7400 ret = 0;
7401 }
7402 }
7403 else if (inf && !strict) {
7404 if (arg1i == -1 || arg2i == 1) {
7405 ret = 1;
7406 } else if (arg1i == 0 && arg2i == 0) {
7407 ret = (arg1->floatval <= arg2->floatval);
7408 } else {
7409 ret = 0;
7410 }
7411 }
7412 else if (!inf && strict) {
7413 if ((arg1i == 1 && arg2i != 1) ||
7414 (arg2i == -1 && arg1i != -1)) {
7415 ret = 1;
7416 } else if (arg1i == 0 && arg2i == 0) {
7417 ret = (arg1->floatval > arg2->floatval);
7418 } else {
7419 ret = 0;
7420 }
7421 }
7422 else if (!inf && !strict) {
7423 if (arg1i == 1 || arg2i == -1) {
7424 ret = 1;
7425 } else if (arg1i == 0 && arg2i == 0) {
7426 ret = (arg1->floatval >= arg2->floatval);
7427 } else {
7428 ret = 0;
7429 }
7430 }
Daniel Veillard21458c82002-03-27 16:12:22 +00007431 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007432 xmlXPathReleaseObject(ctxt->context, arg1);
7433 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007434 return(ret);
7435}
7436
7437/**
7438 * xmlXPathValueFlipSign:
7439 * @ctxt: the XPath Parser context
7440 *
7441 * Implement the unary - operation on an XPath object
7442 * The numeric operators convert their operands to numbers as if
7443 * by calling the number function.
7444 */
7445void
7446xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007447 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007448 CAST_TO_NUMBER;
7449 CHECK_TYPE(XPATH_NUMBER);
Nick Wellnhofer8813f392017-09-21 00:11:26 +02007450 ctxt->value->floatval = -ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00007451}
7452
7453/**
7454 * xmlXPathAddValues:
7455 * @ctxt: the XPath Parser context
7456 *
7457 * Implement the add operation on XPath objects:
7458 * The numeric operators convert their operands to numbers as if
7459 * by calling the number function.
7460 */
7461void
7462xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7463 xmlXPathObjectPtr arg;
7464 double val;
7465
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007466 arg = valuePop(ctxt);
7467 if (arg == NULL)
7468 XP_ERROR(XPATH_INVALID_OPERAND);
7469 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007470 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007471 CAST_TO_NUMBER;
7472 CHECK_TYPE(XPATH_NUMBER);
7473 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00007474}
7475
7476/**
7477 * xmlXPathSubValues:
7478 * @ctxt: the XPath Parser context
7479 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007480 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007481 * The numeric operators convert their operands to numbers as if
7482 * by calling the number function.
7483 */
7484void
7485xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7486 xmlXPathObjectPtr arg;
7487 double val;
7488
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007489 arg = valuePop(ctxt);
7490 if (arg == NULL)
7491 XP_ERROR(XPATH_INVALID_OPERAND);
7492 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007493 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007494 CAST_TO_NUMBER;
7495 CHECK_TYPE(XPATH_NUMBER);
7496 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007497}
7498
7499/**
7500 * xmlXPathMultValues:
7501 * @ctxt: the XPath Parser context
7502 *
7503 * Implement the multiply operation on XPath objects:
7504 * The numeric operators convert their operands to numbers as if
7505 * by calling the number function.
7506 */
7507void
7508xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7509 xmlXPathObjectPtr arg;
7510 double val;
7511
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007512 arg = valuePop(ctxt);
7513 if (arg == NULL)
7514 XP_ERROR(XPATH_INVALID_OPERAND);
7515 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007516 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007517 CAST_TO_NUMBER;
7518 CHECK_TYPE(XPATH_NUMBER);
7519 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007520}
7521
7522/**
7523 * xmlXPathDivValues:
7524 * @ctxt: the XPath Parser context
7525 *
7526 * Implement the div operation on XPath objects @arg1 / @arg2:
7527 * The numeric operators convert their operands to numbers as if
7528 * by calling the number function.
7529 */
Haibo Huangcfd91dc2020-07-30 23:01:33 -07007530ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
Owen Taylor3473f882001-02-23 17:55:21 +00007531void
7532xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7533 xmlXPathObjectPtr arg;
7534 double val;
7535
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007536 arg = valuePop(ctxt);
7537 if (arg == NULL)
7538 XP_ERROR(XPATH_INVALID_OPERAND);
7539 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007540 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007541 CAST_TO_NUMBER;
7542 CHECK_TYPE(XPATH_NUMBER);
Nick Wellnhofer8813f392017-09-21 00:11:26 +02007543 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007544}
7545
7546/**
7547 * xmlXPathModValues:
7548 * @ctxt: the XPath Parser context
7549 *
7550 * Implement the mod operation on XPath objects: @arg1 / @arg2
7551 * The numeric operators convert their operands to numbers as if
7552 * by calling the number function.
7553 */
7554void
7555xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7556 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00007557 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00007558
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007559 arg = valuePop(ctxt);
7560 if (arg == NULL)
7561 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007562 arg2 = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007563 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007564 CAST_TO_NUMBER;
7565 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007566 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00007567 if (arg2 == 0)
Elliott Hughes5cefca72021-05-06 13:23:15 -07007568 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007569 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00007570 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007571 }
Owen Taylor3473f882001-02-23 17:55:21 +00007572}
7573
7574/************************************************************************
7575 * *
7576 * The traversal functions *
7577 * *
7578 ************************************************************************/
7579
Owen Taylor3473f882001-02-23 17:55:21 +00007580/*
7581 * A traversal function enumerates nodes along an axis.
7582 * Initially it must be called with NULL, and it indicates
7583 * termination on the axis by returning NULL.
7584 */
7585typedef xmlNodePtr (*xmlXPathTraversalFunction)
7586 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7587
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007588/*
7589 * xmlXPathTraversalFunctionExt:
7590 * A traversal function enumerates nodes along an axis.
7591 * Initially it must be called with NULL, and it indicates
7592 * termination on the axis by returning NULL.
7593 * The context node of the traversal is specified via @contextNode.
7594 */
7595typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7596 (xmlNodePtr cur, xmlNodePtr contextNode);
7597
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00007598/*
7599 * xmlXPathNodeSetMergeFunction:
7600 * Used for merging node sets in xmlXPathCollectAndTest().
7601 */
7602typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
Haibo Huangcfd91dc2020-07-30 23:01:33 -07007603 (xmlNodeSetPtr, xmlNodeSetPtr);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00007604
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007605
Owen Taylor3473f882001-02-23 17:55:21 +00007606/**
7607 * xmlXPathNextSelf:
7608 * @ctxt: the XPath Parser context
7609 * @cur: the current node in the traversal
7610 *
7611 * Traversal function for the "self" direction
7612 * The self axis contains just the context node itself
7613 *
7614 * Returns the next element following that axis
7615 */
7616xmlNodePtr
7617xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007618 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007619 if (cur == NULL)
7620 return(ctxt->context->node);
7621 return(NULL);
7622}
7623
7624/**
7625 * xmlXPathNextChild:
7626 * @ctxt: the XPath Parser context
7627 * @cur: the current node in the traversal
7628 *
7629 * Traversal function for the "child" direction
7630 * The child axis contains the children of the context node in document order.
7631 *
7632 * Returns the next element following that axis
7633 */
7634xmlNodePtr
7635xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007636 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007637 if (cur == NULL) {
7638 if (ctxt->context->node == NULL) return(NULL);
7639 switch (ctxt->context->node->type) {
7640 case XML_ELEMENT_NODE:
7641 case XML_TEXT_NODE:
7642 case XML_CDATA_SECTION_NODE:
7643 case XML_ENTITY_REF_NODE:
7644 case XML_ENTITY_NODE:
7645 case XML_PI_NODE:
7646 case XML_COMMENT_NODE:
7647 case XML_NOTATION_NODE:
7648 case XML_DTD_NODE:
7649 return(ctxt->context->node->children);
7650 case XML_DOCUMENT_NODE:
7651 case XML_DOCUMENT_TYPE_NODE:
7652 case XML_DOCUMENT_FRAG_NODE:
7653 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007654#ifdef LIBXML_DOCB_ENABLED
7655 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007656#endif
7657 return(((xmlDocPtr) ctxt->context->node)->children);
7658 case XML_ELEMENT_DECL:
7659 case XML_ATTRIBUTE_DECL:
7660 case XML_ENTITY_DECL:
7661 case XML_ATTRIBUTE_NODE:
7662 case XML_NAMESPACE_DECL:
7663 case XML_XINCLUDE_START:
7664 case XML_XINCLUDE_END:
7665 return(NULL);
7666 }
7667 return(NULL);
7668 }
7669 if ((cur->type == XML_DOCUMENT_NODE) ||
7670 (cur->type == XML_HTML_DOCUMENT_NODE))
7671 return(NULL);
7672 return(cur->next);
7673}
7674
7675/**
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00007676 * xmlXPathNextChildElement:
7677 * @ctxt: the XPath Parser context
7678 * @cur: the current node in the traversal
7679 *
7680 * Traversal function for the "child" direction and nodes of type element.
7681 * The child axis contains the children of the context node in document order.
7682 *
7683 * Returns the next element following that axis
7684 */
7685static xmlNodePtr
7686xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7687 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7688 if (cur == NULL) {
7689 cur = ctxt->context->node;
7690 if (cur == NULL) return(NULL);
7691 /*
7692 * Get the first element child.
7693 */
7694 switch (cur->type) {
7695 case XML_ELEMENT_NODE:
7696 case XML_DOCUMENT_FRAG_NODE:
7697 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7698 case XML_ENTITY_NODE:
7699 cur = cur->children;
7700 if (cur != NULL) {
7701 if (cur->type == XML_ELEMENT_NODE)
7702 return(cur);
7703 do {
7704 cur = cur->next;
7705 } while ((cur != NULL) &&
7706 (cur->type != XML_ELEMENT_NODE));
7707 return(cur);
7708 }
7709 return(NULL);
7710 case XML_DOCUMENT_NODE:
7711 case XML_HTML_DOCUMENT_NODE:
7712#ifdef LIBXML_DOCB_ENABLED
7713 case XML_DOCB_DOCUMENT_NODE:
7714#endif
7715 return(xmlDocGetRootElement((xmlDocPtr) cur));
7716 default:
7717 return(NULL);
7718 }
7719 return(NULL);
7720 }
7721 /*
7722 * Get the next sibling element node.
7723 */
7724 switch (cur->type) {
7725 case XML_ELEMENT_NODE:
7726 case XML_TEXT_NODE:
7727 case XML_ENTITY_REF_NODE:
7728 case XML_ENTITY_NODE:
7729 case XML_CDATA_SECTION_NODE:
7730 case XML_PI_NODE:
7731 case XML_COMMENT_NODE:
7732 case XML_XINCLUDE_END:
7733 break;
7734 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7735 default:
7736 return(NULL);
7737 }
7738 if (cur->next != NULL) {
7739 if (cur->next->type == XML_ELEMENT_NODE)
7740 return(cur->next);
7741 cur = cur->next;
7742 do {
7743 cur = cur->next;
7744 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7745 return(cur);
7746 }
7747 return(NULL);
7748}
7749
Daniel Veillard76516062012-09-11 14:02:08 +08007750#if 0
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00007751/**
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007752 * xmlXPathNextDescendantOrSelfElemParent:
7753 * @ctxt: the XPath Parser context
7754 * @cur: the current node in the traversal
7755 *
7756 * Traversal function for the "descendant-or-self" axis.
7757 * Additionally it returns only nodes which can be parents of
7758 * element nodes.
7759 *
7760 *
7761 * Returns the next element following that axis
7762 */
7763static xmlNodePtr
7764xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7765 xmlNodePtr contextNode)
7766{
7767 if (cur == NULL) {
7768 if (contextNode == NULL)
7769 return(NULL);
7770 switch (contextNode->type) {
7771 case XML_ELEMENT_NODE:
7772 case XML_XINCLUDE_START:
7773 case XML_DOCUMENT_FRAG_NODE:
7774 case XML_DOCUMENT_NODE:
7775#ifdef LIBXML_DOCB_ENABLED
7776 case XML_DOCB_DOCUMENT_NODE:
7777#endif
Daniel Veillardf8e3db02012-09-11 13:26:36 +08007778 case XML_HTML_DOCUMENT_NODE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007779 return(contextNode);
7780 default:
Daniel Veillard45490ae2008-07-29 09:13:19 +00007781 return(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007782 }
7783 return(NULL);
7784 } else {
7785 xmlNodePtr start = cur;
7786
7787 while (cur != NULL) {
7788 switch (cur->type) {
7789 case XML_ELEMENT_NODE:
7790 /* TODO: OK to have XInclude here? */
7791 case XML_XINCLUDE_START:
Daniel Veillard45490ae2008-07-29 09:13:19 +00007792 case XML_DOCUMENT_FRAG_NODE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007793 if (cur != start)
7794 return(cur);
7795 if (cur->children != NULL) {
7796 cur = cur->children;
7797 continue;
7798 }
7799 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007800 /* Not sure if we need those here. */
7801 case XML_DOCUMENT_NODE:
Daniel Veillard17970a72006-10-26 08:55:47 +00007802#ifdef LIBXML_DOCB_ENABLED
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007803 case XML_DOCB_DOCUMENT_NODE:
7804#endif
7805 case XML_HTML_DOCUMENT_NODE:
7806 if (cur != start)
7807 return(cur);
7808 return(xmlDocGetRootElement((xmlDocPtr) cur));
7809 default:
7810 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007811 }
7812
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007813next_sibling:
7814 if ((cur == NULL) || (cur == contextNode))
Daniel Veillard45490ae2008-07-29 09:13:19 +00007815 return(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007816 if (cur->next != NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00007817 cur = cur->next;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007818 } else {
7819 cur = cur->parent;
7820 goto next_sibling;
7821 }
7822 }
7823 }
7824 return(NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007825}
Daniel Veillard76516062012-09-11 14:02:08 +08007826#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007827
7828/**
Owen Taylor3473f882001-02-23 17:55:21 +00007829 * xmlXPathNextDescendant:
7830 * @ctxt: the XPath Parser context
7831 * @cur: the current node in the traversal
7832 *
7833 * Traversal function for the "descendant" direction
7834 * the descendant axis contains the descendants of the context node in document
7835 * order; a descendant is a child or a child of a child and so on.
7836 *
7837 * Returns the next element following that axis
7838 */
7839xmlNodePtr
7840xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007841 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007842 if (cur == NULL) {
7843 if (ctxt->context->node == NULL)
7844 return(NULL);
7845 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7846 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7847 return(NULL);
7848
7849 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7850 return(ctxt->context->doc->children);
7851 return(ctxt->context->node->children);
7852 }
7853
Daniel Veillard3e62adb2012-08-09 14:24:02 +08007854 if (cur->type == XML_NAMESPACE_DECL)
7855 return(NULL);
Daniel Veillard567e1b42001-08-01 15:53:47 +00007856 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007857 /*
7858 * Do not descend on entities declarations
7859 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00007860 if (cur->children->type != XML_ENTITY_DECL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007861 cur = cur->children;
7862 /*
7863 * Skip DTDs
7864 */
7865 if (cur->type != XML_DTD_NODE)
7866 return(cur);
7867 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00007868 }
7869
7870 if (cur == ctxt->context->node) return(NULL);
7871
Daniel Veillard68e9e742002-11-16 15:35:11 +00007872 while (cur->next != NULL) {
7873 cur = cur->next;
7874 if ((cur->type != XML_ENTITY_DECL) &&
7875 (cur->type != XML_DTD_NODE))
7876 return(cur);
7877 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00007878
Owen Taylor3473f882001-02-23 17:55:21 +00007879 do {
7880 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00007881 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00007882 if (cur == ctxt->context->node) return(NULL);
7883 if (cur->next != NULL) {
7884 cur = cur->next;
7885 return(cur);
7886 }
7887 } while (cur != NULL);
7888 return(cur);
7889}
7890
7891/**
7892 * xmlXPathNextDescendantOrSelf:
7893 * @ctxt: the XPath Parser context
7894 * @cur: the current node in the traversal
7895 *
7896 * Traversal function for the "descendant-or-self" direction
7897 * the descendant-or-self axis contains the context node and the descendants
7898 * of the context node in document order; thus the context node is the first
7899 * node on the axis, and the first child of the context node is the second node
7900 * on the axis
7901 *
7902 * Returns the next element following that axis
7903 */
7904xmlNodePtr
7905xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007906 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Nick Wellnhoferf6aaabc2015-03-08 16:05:26 +01007907 if (cur == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00007908 return(ctxt->context->node);
Nick Wellnhoferf6aaabc2015-03-08 16:05:26 +01007909
7910 if (ctxt->context->node == NULL)
7911 return(NULL);
7912 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7913 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7914 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007915
7916 return(xmlXPathNextDescendant(ctxt, cur));
7917}
7918
7919/**
7920 * xmlXPathNextParent:
7921 * @ctxt: the XPath Parser context
7922 * @cur: the current node in the traversal
7923 *
7924 * Traversal function for the "parent" direction
7925 * The parent axis contains the parent of the context node, if there is one.
7926 *
7927 * Returns the next element following that axis
7928 */
7929xmlNodePtr
7930xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007931 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007932 /*
7933 * the parent of an attribute or namespace node is the element
7934 * to which the attribute or namespace node is attached
7935 * Namespace handling !!!
7936 */
7937 if (cur == NULL) {
7938 if (ctxt->context->node == NULL) return(NULL);
7939 switch (ctxt->context->node->type) {
7940 case XML_ELEMENT_NODE:
7941 case XML_TEXT_NODE:
7942 case XML_CDATA_SECTION_NODE:
7943 case XML_ENTITY_REF_NODE:
7944 case XML_ENTITY_NODE:
7945 case XML_PI_NODE:
7946 case XML_COMMENT_NODE:
7947 case XML_NOTATION_NODE:
7948 case XML_DTD_NODE:
7949 case XML_ELEMENT_DECL:
7950 case XML_ATTRIBUTE_DECL:
7951 case XML_XINCLUDE_START:
7952 case XML_XINCLUDE_END:
7953 case XML_ENTITY_DECL:
7954 if (ctxt->context->node->parent == NULL)
7955 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007956 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007957 ((ctxt->context->node->parent->name[0] == ' ') ||
7958 (xmlStrEqual(ctxt->context->node->parent->name,
7959 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007960 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007961 return(ctxt->context->node->parent);
7962 case XML_ATTRIBUTE_NODE: {
7963 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7964
7965 return(att->parent);
7966 }
7967 case XML_DOCUMENT_NODE:
7968 case XML_DOCUMENT_TYPE_NODE:
7969 case XML_DOCUMENT_FRAG_NODE:
7970 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007971#ifdef LIBXML_DOCB_ENABLED
7972 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007973#endif
7974 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007975 case XML_NAMESPACE_DECL: {
7976 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007977
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007978 if ((ns->next != NULL) &&
7979 (ns->next->type != XML_NAMESPACE_DECL))
7980 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00007981 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007982 }
Owen Taylor3473f882001-02-23 17:55:21 +00007983 }
7984 }
7985 return(NULL);
7986}
7987
7988/**
7989 * xmlXPathNextAncestor:
7990 * @ctxt: the XPath Parser context
7991 * @cur: the current node in the traversal
7992 *
7993 * Traversal function for the "ancestor" direction
7994 * the ancestor axis contains the ancestors of the context node; the ancestors
7995 * of the context node consist of the parent of context node and the parent's
7996 * parent and so on; the nodes are ordered in reverse document order; thus the
7997 * parent is the first node on the axis, and the parent's parent is the second
7998 * node on the axis
7999 *
8000 * Returns the next element following that axis
8001 */
8002xmlNodePtr
8003xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008004 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008005 /*
8006 * the parent of an attribute or namespace node is the element
8007 * to which the attribute or namespace node is attached
8008 * !!!!!!!!!!!!!
8009 */
8010 if (cur == NULL) {
8011 if (ctxt->context->node == NULL) return(NULL);
8012 switch (ctxt->context->node->type) {
8013 case XML_ELEMENT_NODE:
8014 case XML_TEXT_NODE:
8015 case XML_CDATA_SECTION_NODE:
8016 case XML_ENTITY_REF_NODE:
8017 case XML_ENTITY_NODE:
8018 case XML_PI_NODE:
8019 case XML_COMMENT_NODE:
8020 case XML_DTD_NODE:
8021 case XML_ELEMENT_DECL:
8022 case XML_ATTRIBUTE_DECL:
8023 case XML_ENTITY_DECL:
8024 case XML_NOTATION_NODE:
8025 case XML_XINCLUDE_START:
8026 case XML_XINCLUDE_END:
8027 if (ctxt->context->node->parent == NULL)
8028 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008029 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00008030 ((ctxt->context->node->parent->name[0] == ' ') ||
8031 (xmlStrEqual(ctxt->context->node->parent->name,
8032 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008033 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008034 return(ctxt->context->node->parent);
8035 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008036 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00008037
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008038 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00008039 }
8040 case XML_DOCUMENT_NODE:
8041 case XML_DOCUMENT_TYPE_NODE:
8042 case XML_DOCUMENT_FRAG_NODE:
8043 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00008044#ifdef LIBXML_DOCB_ENABLED
8045 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00008046#endif
8047 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008048 case XML_NAMESPACE_DECL: {
8049 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008050
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008051 if ((ns->next != NULL) &&
8052 (ns->next->type != XML_NAMESPACE_DECL))
8053 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00008054 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00008055 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008056 }
Owen Taylor3473f882001-02-23 17:55:21 +00008057 }
8058 return(NULL);
8059 }
8060 if (cur == ctxt->context->doc->children)
8061 return((xmlNodePtr) ctxt->context->doc);
8062 if (cur == (xmlNodePtr) ctxt->context->doc)
8063 return(NULL);
8064 switch (cur->type) {
8065 case XML_ELEMENT_NODE:
8066 case XML_TEXT_NODE:
8067 case XML_CDATA_SECTION_NODE:
8068 case XML_ENTITY_REF_NODE:
8069 case XML_ENTITY_NODE:
8070 case XML_PI_NODE:
8071 case XML_COMMENT_NODE:
8072 case XML_NOTATION_NODE:
8073 case XML_DTD_NODE:
8074 case XML_ELEMENT_DECL:
8075 case XML_ATTRIBUTE_DECL:
8076 case XML_ENTITY_DECL:
8077 case XML_XINCLUDE_START:
8078 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008079 if (cur->parent == NULL)
8080 return(NULL);
8081 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00008082 ((cur->parent->name[0] == ' ') ||
8083 (xmlStrEqual(cur->parent->name,
8084 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008085 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008086 return(cur->parent);
8087 case XML_ATTRIBUTE_NODE: {
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008088 xmlAttrPtr att = (xmlAttrPtr) cur;
Owen Taylor3473f882001-02-23 17:55:21 +00008089
8090 return(att->parent);
8091 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008092 case XML_NAMESPACE_DECL: {
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008093 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008094
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008095 if ((ns->next != NULL) &&
8096 (ns->next->type != XML_NAMESPACE_DECL))
8097 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00008098 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008099 return(NULL);
8100 }
Owen Taylor3473f882001-02-23 17:55:21 +00008101 case XML_DOCUMENT_NODE:
8102 case XML_DOCUMENT_TYPE_NODE:
8103 case XML_DOCUMENT_FRAG_NODE:
8104 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00008105#ifdef LIBXML_DOCB_ENABLED
8106 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00008107#endif
8108 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008109 }
8110 return(NULL);
8111}
8112
8113/**
8114 * xmlXPathNextAncestorOrSelf:
8115 * @ctxt: the XPath Parser context
8116 * @cur: the current node in the traversal
8117 *
8118 * Traversal function for the "ancestor-or-self" direction
8119 * he ancestor-or-self axis contains the context node and ancestors of
8120 * the context node in reverse document order; thus the context node is
8121 * the first node on the axis, and the context node's parent the second;
8122 * parent here is defined the same as with the parent axis.
8123 *
8124 * Returns the next element following that axis
8125 */
8126xmlNodePtr
8127xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008128 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008129 if (cur == NULL)
8130 return(ctxt->context->node);
8131 return(xmlXPathNextAncestor(ctxt, cur));
8132}
8133
8134/**
8135 * xmlXPathNextFollowingSibling:
8136 * @ctxt: the XPath Parser context
8137 * @cur: the current node in the traversal
8138 *
8139 * Traversal function for the "following-sibling" direction
8140 * The following-sibling axis contains the following siblings of the context
8141 * node in document order.
8142 *
8143 * Returns the next element following that axis
8144 */
8145xmlNodePtr
8146xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008147 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008148 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8149 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8150 return(NULL);
8151 if (cur == (xmlNodePtr) ctxt->context->doc)
8152 return(NULL);
8153 if (cur == NULL)
8154 return(ctxt->context->node->next);
8155 return(cur->next);
8156}
8157
8158/**
8159 * xmlXPathNextPrecedingSibling:
8160 * @ctxt: the XPath Parser context
8161 * @cur: the current node in the traversal
8162 *
8163 * Traversal function for the "preceding-sibling" direction
8164 * The preceding-sibling axis contains the preceding siblings of the context
8165 * node in reverse document order; the first preceding sibling is first on the
8166 * axis; the sibling preceding that node is the second on the axis and so on.
8167 *
8168 * Returns the next element following that axis
8169 */
8170xmlNodePtr
8171xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008172 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008173 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8174 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8175 return(NULL);
8176 if (cur == (xmlNodePtr) ctxt->context->doc)
8177 return(NULL);
8178 if (cur == NULL)
8179 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008180 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8181 cur = cur->prev;
8182 if (cur == NULL)
8183 return(ctxt->context->node->prev);
8184 }
Owen Taylor3473f882001-02-23 17:55:21 +00008185 return(cur->prev);
8186}
8187
8188/**
8189 * xmlXPathNextFollowing:
8190 * @ctxt: the XPath Parser context
8191 * @cur: the current node in the traversal
8192 *
8193 * Traversal function for the "following" direction
8194 * The following axis contains all nodes in the same document as the context
8195 * node that are after the context node in document order, excluding any
8196 * descendants and excluding attribute nodes and namespace nodes; the nodes
8197 * are ordered in document order
8198 *
8199 * Returns the next element following that axis
8200 */
8201xmlNodePtr
8202xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008203 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008204 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
8205 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8206 return(cur->children);
8207
8208 if (cur == NULL) {
8209 cur = ctxt->context->node;
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008210 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardea90b892010-10-22 15:50:50 +02008211 cur = cur->parent;
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008212 } else if (cur->type == XML_NAMESPACE_DECL) {
8213 xmlNsPtr ns = (xmlNsPtr) cur;
8214
8215 if ((ns->next == NULL) ||
8216 (ns->next->type == XML_NAMESPACE_DECL))
8217 return (NULL);
8218 cur = (xmlNodePtr) ns->next;
8219 }
Daniel Veillard91d19752010-10-15 14:30:52 +02008220 }
Owen Taylor3473f882001-02-23 17:55:21 +00008221 if (cur == NULL) return(NULL) ; /* ERROR */
8222 if (cur->next != NULL) return(cur->next) ;
8223 do {
8224 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00008225 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00008226 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8227 if (cur->next != NULL) return(cur->next);
8228 } while (cur != NULL);
8229 return(cur);
8230}
8231
8232/*
8233 * xmlXPathIsAncestor:
8234 * @ancestor: the ancestor node
8235 * @node: the current node
8236 *
8237 * Check that @ancestor is a @node's ancestor
8238 *
8239 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8240 */
8241static int
8242xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8243 if ((ancestor == NULL) || (node == NULL)) return(0);
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008244 if (node->type == XML_NAMESPACE_DECL)
8245 return(0);
8246 if (ancestor->type == XML_NAMESPACE_DECL)
8247 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00008248 /* nodes need to be in the same document */
8249 if (ancestor->doc != node->doc) return(0);
8250 /* avoid searching if ancestor or node is the root node */
8251 if (ancestor == (xmlNodePtr) node->doc) return(1);
8252 if (node == (xmlNodePtr) ancestor->doc) return(0);
8253 while (node->parent != NULL) {
8254 if (node->parent == ancestor)
8255 return(1);
8256 node = node->parent;
8257 }
8258 return(0);
8259}
8260
8261/**
8262 * xmlXPathNextPreceding:
8263 * @ctxt: the XPath Parser context
8264 * @cur: the current node in the traversal
8265 *
8266 * Traversal function for the "preceding" direction
8267 * the preceding axis contains all nodes in the same document as the context
8268 * node that are before the context node in document order, excluding any
8269 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8270 * ordered in reverse document order
8271 *
8272 * Returns the next element following that axis
8273 */
8274xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00008275xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8276{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008277 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008278 if (cur == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008279 cur = ctxt->context->node;
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008280 if (cur->type == XML_ATTRIBUTE_NODE) {
8281 cur = cur->parent;
8282 } else if (cur->type == XML_NAMESPACE_DECL) {
8283 xmlNsPtr ns = (xmlNsPtr) cur;
8284
8285 if ((ns->next == NULL) ||
8286 (ns->next->type == XML_NAMESPACE_DECL))
8287 return (NULL);
8288 cur = (xmlNodePtr) ns->next;
8289 }
Daniel Veillardea90b892010-10-22 15:50:50 +02008290 }
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008291 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
Daniel Veillardf06307e2001-07-03 10:35:50 +00008292 return (NULL);
8293 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8294 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00008295 do {
8296 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008297 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8298 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008299 }
8300
8301 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008302 if (cur == NULL)
8303 return (NULL);
8304 if (cur == ctxt->context->doc->children)
8305 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008306 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00008307 return (cur);
8308}
8309
8310/**
8311 * xmlXPathNextPrecedingInternal:
8312 * @ctxt: the XPath Parser context
8313 * @cur: the current node in the traversal
8314 *
8315 * Traversal function for the "preceding" direction
8316 * the preceding axis contains all nodes in the same document as the context
8317 * node that are before the context node in document order, excluding any
8318 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8319 * ordered in reverse document order
Daniel Veillard45490ae2008-07-29 09:13:19 +00008320 * This is a faster implementation but internal only since it requires a
Daniel Veillardf06307e2001-07-03 10:35:50 +00008321 * state kept in the parser context: ctxt->ancestor.
8322 *
8323 * Returns the next element following that axis
8324 */
8325static xmlNodePtr
8326xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8327 xmlNodePtr cur)
8328{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008329 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008330 if (cur == NULL) {
8331 cur = ctxt->context->node;
8332 if (cur == NULL)
8333 return (NULL);
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008334 if (cur->type == XML_ATTRIBUTE_NODE) {
8335 cur = cur->parent;
8336 } else if (cur->type == XML_NAMESPACE_DECL) {
8337 xmlNsPtr ns = (xmlNsPtr) cur;
8338
8339 if ((ns->next == NULL) ||
8340 (ns->next->type == XML_NAMESPACE_DECL))
8341 return (NULL);
8342 cur = (xmlNodePtr) ns->next;
8343 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00008344 ctxt->ancestor = cur->parent;
8345 }
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008346 if (cur->type == XML_NAMESPACE_DECL)
8347 return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008348 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8349 cur = cur->prev;
8350 while (cur->prev == NULL) {
8351 cur = cur->parent;
8352 if (cur == NULL)
8353 return (NULL);
8354 if (cur == ctxt->context->doc->children)
8355 return (NULL);
8356 if (cur != ctxt->ancestor)
8357 return (cur);
8358 ctxt->ancestor = cur->parent;
8359 }
8360 cur = cur->prev;
8361 while (cur->last != NULL)
8362 cur = cur->last;
8363 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008364}
8365
8366/**
8367 * xmlXPathNextNamespace:
8368 * @ctxt: the XPath Parser context
8369 * @cur: the current attribute in the traversal
8370 *
8371 * Traversal function for the "namespace" direction
8372 * the namespace axis contains the namespace nodes of the context node;
8373 * the order of nodes on this axis is implementation-defined; the axis will
8374 * be empty unless the context node is an element
8375 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008376 * We keep the XML namespace node at the end of the list.
8377 *
Owen Taylor3473f882001-02-23 17:55:21 +00008378 * Returns the next element following that axis
8379 */
8380xmlNodePtr
8381xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008382 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008383 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Nick Wellnhofer82b73032016-04-30 17:53:10 +02008384 if (cur == NULL) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008385 if (ctxt->context->tmpNsList != NULL)
8386 xmlFree(ctxt->context->tmpNsList);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008387 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00008388 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008389 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00008390 if (ctxt->context->tmpNsList != NULL) {
8391 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8392 ctxt->context->tmpNsNr++;
8393 }
8394 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008395 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008396 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00008397 if (ctxt->context->tmpNsNr > 0) {
8398 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8399 } else {
8400 if (ctxt->context->tmpNsList != NULL)
8401 xmlFree(ctxt->context->tmpNsList);
8402 ctxt->context->tmpNsList = NULL;
8403 return(NULL);
8404 }
Owen Taylor3473f882001-02-23 17:55:21 +00008405}
8406
8407/**
8408 * xmlXPathNextAttribute:
8409 * @ctxt: the XPath Parser context
8410 * @cur: the current attribute in the traversal
8411 *
8412 * Traversal function for the "attribute" direction
8413 * TODO: support DTD inherited default attributes
8414 *
8415 * Returns the next element following that axis
8416 */
8417xmlNodePtr
8418xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008419 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00008420 if (ctxt->context->node == NULL)
8421 return(NULL);
8422 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8423 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008424 if (cur == NULL) {
8425 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8426 return(NULL);
8427 return((xmlNodePtr)ctxt->context->node->properties);
8428 }
8429 return((xmlNodePtr)cur->next);
8430}
8431
8432/************************************************************************
8433 * *
8434 * NodeTest Functions *
8435 * *
8436 ************************************************************************/
8437
Owen Taylor3473f882001-02-23 17:55:21 +00008438#define IS_FUNCTION 200
8439
Owen Taylor3473f882001-02-23 17:55:21 +00008440
8441/************************************************************************
8442 * *
8443 * Implicit tree core function library *
8444 * *
8445 ************************************************************************/
8446
8447/**
8448 * xmlXPathRoot:
8449 * @ctxt: the XPath Parser context
8450 *
8451 * Initialize the context to the root of the document
8452 */
8453void
8454xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008455 if ((ctxt == NULL) || (ctxt->context == NULL))
8456 return;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008457 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
Elliott Hughes7fbecab2019-01-10 16:42:03 -08008458 (xmlNodePtr) ctxt->context->doc));
Owen Taylor3473f882001-02-23 17:55:21 +00008459}
8460
8461/************************************************************************
8462 * *
8463 * The explicit core function library *
8464 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8465 * *
8466 ************************************************************************/
8467
8468
8469/**
8470 * xmlXPathLastFunction:
8471 * @ctxt: the XPath Parser context
8472 * @nargs: the number of arguments
8473 *
8474 * Implement the last() XPath function
8475 * number last()
8476 * The last function returns the number of nodes in the context node list.
8477 */
8478void
8479xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8480 CHECK_ARITY(0);
8481 if (ctxt->context->contextSize >= 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008482 valuePush(ctxt,
8483 xmlXPathCacheNewFloat(ctxt->context,
8484 (double) ctxt->context->contextSize));
Owen Taylor3473f882001-02-23 17:55:21 +00008485#ifdef DEBUG_EXPR
8486 xmlGenericError(xmlGenericErrorContext,
8487 "last() : %d\n", ctxt->context->contextSize);
8488#endif
8489 } else {
8490 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8491 }
8492}
8493
8494/**
8495 * xmlXPathPositionFunction:
8496 * @ctxt: the XPath Parser context
8497 * @nargs: the number of arguments
8498 *
8499 * Implement the position() XPath function
8500 * number position()
8501 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008502 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00008503 * will be equal to last().
8504 */
8505void
8506xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8507 CHECK_ARITY(0);
8508 if (ctxt->context->proximityPosition >= 0) {
8509 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008510 xmlXPathCacheNewFloat(ctxt->context,
8511 (double) ctxt->context->proximityPosition));
Owen Taylor3473f882001-02-23 17:55:21 +00008512#ifdef DEBUG_EXPR
8513 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8514 ctxt->context->proximityPosition);
8515#endif
8516 } else {
8517 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8518 }
8519}
8520
8521/**
8522 * xmlXPathCountFunction:
8523 * @ctxt: the XPath Parser context
8524 * @nargs: the number of arguments
8525 *
8526 * Implement the count() XPath function
8527 * number count(node-set)
8528 */
8529void
8530xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8531 xmlXPathObjectPtr cur;
8532
8533 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008534 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008535 ((ctxt->value->type != XPATH_NODESET) &&
8536 (ctxt->value->type != XPATH_XSLT_TREE)))
8537 XP_ERROR(XPATH_INVALID_TYPE);
8538 cur = valuePop(ctxt);
8539
Daniel Veillard911f49a2001-04-07 15:39:35 +00008540 if ((cur == NULL) || (cur->nodesetval == NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008541 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
Haibo Huangcfd91dc2020-07-30 23:01:33 -07008542 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008543 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8544 (double) cur->nodesetval->nodeNr));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008545 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008546}
8547
8548/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008549 * xmlXPathGetElementsByIds:
8550 * @doc: the document
8551 * @ids: a whitespace separated list of IDs
8552 *
8553 * Selects elements by their unique ID.
8554 *
8555 * Returns a node-set of selected elements.
8556 */
8557static xmlNodeSetPtr
8558xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8559 xmlNodeSetPtr ret;
8560 const xmlChar *cur = ids;
8561 xmlChar *ID;
8562 xmlAttrPtr attr;
8563 xmlNodePtr elem = NULL;
8564
Daniel Veillard7a985a12003-07-06 17:57:42 +00008565 if (ids == NULL) return(NULL);
8566
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008567 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00008568 if (ret == NULL)
8569 return(ret);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008570
William M. Brack76e95df2003-10-18 16:20:14 +00008571 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008572 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008573 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00008574 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008575
8576 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00008577 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00008578 /*
8579 * We used to check the fact that the value passed
8580 * was an NCName, but this generated much troubles for
8581 * me and Aleksey Sanin, people blatantly violated that
Haibo Huangcfd91dc2020-07-30 23:01:33 -07008582 * constraint, like Visa3D spec.
Daniel Veillard68cb4b22004-04-18 20:55:39 +00008583 * if (xmlValidateNCName(ID, 1) == 0)
8584 */
8585 attr = xmlGetID(doc, ID);
8586 if (attr != NULL) {
8587 if (attr->type == XML_ATTRIBUTE_NODE)
8588 elem = attr->parent;
8589 else if (attr->type == XML_ELEMENT_NODE)
8590 elem = (xmlNodePtr) attr;
8591 else
8592 elem = NULL;
Haibo Huangcfd91dc2020-07-30 23:01:33 -07008593 /* TODO: Check memory error. */
Daniel Veillard68cb4b22004-04-18 20:55:39 +00008594 if (elem != NULL)
8595 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00008596 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008597 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00008598 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008599
William M. Brack76e95df2003-10-18 16:20:14 +00008600 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008601 ids = cur;
8602 }
8603 return(ret);
8604}
8605
8606/**
Owen Taylor3473f882001-02-23 17:55:21 +00008607 * xmlXPathIdFunction:
8608 * @ctxt: the XPath Parser context
8609 * @nargs: the number of arguments
8610 *
8611 * Implement the id() XPath function
8612 * node-set id(object)
8613 * The id function selects elements by their unique ID
8614 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8615 * then the result is the union of the result of applying id to the
8616 * string value of each of the nodes in the argument node-set. When the
8617 * argument to id is of any other type, the argument is converted to a
8618 * string as if by a call to the string function; the string is split
8619 * into a whitespace-separated list of tokens (whitespace is any sequence
8620 * of characters matching the production S); the result is a node-set
8621 * containing the elements in the same document as the context node that
8622 * have a unique ID equal to any of the tokens in the list.
8623 */
8624void
8625xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008626 xmlChar *tokens;
8627 xmlNodeSetPtr ret;
8628 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00008629
8630 CHECK_ARITY(1);
8631 obj = valuePop(ctxt);
8632 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00008633 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008634 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00008635 int i;
8636
Haibo Huangcfd91dc2020-07-30 23:01:33 -07008637 /* TODO: Check memory error. */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008638 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008639
Daniel Veillard911f49a2001-04-07 15:39:35 +00008640 if (obj->nodesetval != NULL) {
8641 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008642 tokens =
8643 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8644 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
Haibo Huangcfd91dc2020-07-30 23:01:33 -07008645 /* TODO: Check memory error. */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008646 ret = xmlXPathNodeSetMerge(ret, ns);
8647 xmlXPathFreeNodeSet(ns);
8648 if (tokens != NULL)
8649 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00008650 }
Owen Taylor3473f882001-02-23 17:55:21 +00008651 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008652 xmlXPathReleaseObject(ctxt->context, obj);
8653 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00008654 return;
8655 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008656 obj = xmlXPathCacheConvertString(ctxt->context, obj);
Haibo Huangcfd91dc2020-07-30 23:01:33 -07008657 if (obj == NULL) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008658 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008659 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008660 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00008661 return;
8662}
8663
8664/**
8665 * xmlXPathLocalNameFunction:
8666 * @ctxt: the XPath Parser context
8667 * @nargs: the number of arguments
8668 *
8669 * Implement the local-name() XPath function
8670 * string local-name(node-set?)
8671 * The local-name function returns a string containing the local part
8672 * of the name of the node in the argument node-set that is first in
8673 * document order. If the node-set is empty or the first node has no
8674 * name, an empty string is returned. If the argument is omitted it
8675 * defaults to the context node.
8676 */
8677void
8678xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8679 xmlXPathObjectPtr cur;
8680
Daniel Veillarda82b1822004-11-08 16:24:57 +00008681 if (ctxt == NULL) return;
8682
Owen Taylor3473f882001-02-23 17:55:21 +00008683 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008684 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8685 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008686 nargs = 1;
8687 }
8688
8689 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008690 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008691 ((ctxt->value->type != XPATH_NODESET) &&
8692 (ctxt->value->type != XPATH_XSLT_TREE)))
8693 XP_ERROR(XPATH_INVALID_TYPE);
8694 cur = valuePop(ctxt);
8695
Daniel Veillard911f49a2001-04-07 15:39:35 +00008696 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008697 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008698 } else {
8699 int i = 0; /* Should be first in document order !!!!! */
8700 switch (cur->nodesetval->nodeTab[i]->type) {
8701 case XML_ELEMENT_NODE:
8702 case XML_ATTRIBUTE_NODE:
8703 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008704 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008705 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008706 else
8707 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008708 xmlXPathCacheNewString(ctxt->context,
8709 cur->nodesetval->nodeTab[i]->name));
Owen Taylor3473f882001-02-23 17:55:21 +00008710 break;
8711 case XML_NAMESPACE_DECL:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008712 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008713 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8714 break;
8715 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008716 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008717 }
8718 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008719 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008720}
8721
8722/**
8723 * xmlXPathNamespaceURIFunction:
8724 * @ctxt: the XPath Parser context
8725 * @nargs: the number of arguments
8726 *
8727 * Implement the namespace-uri() XPath function
8728 * string namespace-uri(node-set?)
8729 * The namespace-uri function returns a string containing the
8730 * namespace URI of the expanded name of the node in the argument
8731 * node-set that is first in document order. If the node-set is empty,
8732 * the first node has no name, or the expanded name has no namespace
8733 * URI, an empty string is returned. If the argument is omitted it
8734 * defaults to the context node.
8735 */
8736void
8737xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8738 xmlXPathObjectPtr cur;
8739
Daniel Veillarda82b1822004-11-08 16:24:57 +00008740 if (ctxt == NULL) return;
8741
Owen Taylor3473f882001-02-23 17:55:21 +00008742 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008743 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8744 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008745 nargs = 1;
8746 }
8747 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008748 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008749 ((ctxt->value->type != XPATH_NODESET) &&
8750 (ctxt->value->type != XPATH_XSLT_TREE)))
8751 XP_ERROR(XPATH_INVALID_TYPE);
8752 cur = valuePop(ctxt);
8753
Daniel Veillard911f49a2001-04-07 15:39:35 +00008754 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008755 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008756 } else {
8757 int i = 0; /* Should be first in document order !!!!! */
8758 switch (cur->nodesetval->nodeTab[i]->type) {
8759 case XML_ELEMENT_NODE:
8760 case XML_ATTRIBUTE_NODE:
8761 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008762 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008763 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008764 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008765 cur->nodesetval->nodeTab[i]->ns->href));
8766 break;
8767 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008768 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008769 }
8770 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008771 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008772}
8773
8774/**
8775 * xmlXPathNameFunction:
8776 * @ctxt: the XPath Parser context
8777 * @nargs: the number of arguments
8778 *
8779 * Implement the name() XPath function
8780 * string name(node-set?)
8781 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008782 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00008783 * order. The QName must represent the name with respect to the namespace
8784 * declarations in effect on the node whose name is being represented.
8785 * Typically, this will be the form in which the name occurred in the XML
8786 * source. This need not be the case if there are namespace declarations
8787 * in effect on the node that associate multiple prefixes with the same
8788 * namespace. However, an implementation may include information about
8789 * the original prefix in its representation of nodes; in this case, an
8790 * implementation can ensure that the returned string is always the same
8791 * as the QName used in the XML source. If the argument it omitted it
8792 * defaults to the context node.
8793 * Libxml keep the original prefix so the "real qualified name" used is
8794 * returned.
8795 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008796static void
Daniel Veillard04383752001-07-08 14:27:15 +00008797xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8798{
Owen Taylor3473f882001-02-23 17:55:21 +00008799 xmlXPathObjectPtr cur;
8800
8801 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008802 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8803 ctxt->context->node));
Daniel Veillard04383752001-07-08 14:27:15 +00008804 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008805 }
8806
8807 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00008808 if ((ctxt->value == NULL) ||
8809 ((ctxt->value->type != XPATH_NODESET) &&
8810 (ctxt->value->type != XPATH_XSLT_TREE)))
8811 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00008812 cur = valuePop(ctxt);
8813
Daniel Veillard911f49a2001-04-07 15:39:35 +00008814 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008815 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008816 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00008817 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00008818
Daniel Veillard04383752001-07-08 14:27:15 +00008819 switch (cur->nodesetval->nodeTab[i]->type) {
8820 case XML_ELEMENT_NODE:
8821 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008822 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008823 valuePush(ctxt,
8824 xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008825 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8826 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008827 valuePush(ctxt,
8828 xmlXPathCacheNewString(ctxt->context,
8829 cur->nodesetval->nodeTab[i]->name));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008830 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00008831 xmlChar *fullname;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008832
Daniel Veillardc00cda82003-04-07 10:22:39 +00008833 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8834 cur->nodesetval->nodeTab[i]->ns->prefix,
8835 NULL, 0);
8836 if (fullname == cur->nodesetval->nodeTab[i]->name)
8837 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8838 if (fullname == NULL) {
8839 XP_ERROR(XPATH_MEMORY_ERROR);
8840 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008841 valuePush(ctxt, xmlXPathCacheWrapString(
8842 ctxt->context, fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00008843 }
8844 break;
8845 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008846 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8847 cur->nodesetval->nodeTab[i]));
Daniel Veillard04383752001-07-08 14:27:15 +00008848 xmlXPathLocalNameFunction(ctxt, 1);
8849 }
Owen Taylor3473f882001-02-23 17:55:21 +00008850 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008851 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008852}
8853
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008854
8855/**
Owen Taylor3473f882001-02-23 17:55:21 +00008856 * xmlXPathStringFunction:
8857 * @ctxt: the XPath Parser context
8858 * @nargs: the number of arguments
8859 *
8860 * Implement the string() XPath function
8861 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00008862 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00008863 * - A node-set is converted to a string by returning the value of
8864 * the node in the node-set that is first in document order.
8865 * If the node-set is empty, an empty string is returned.
8866 * - A number is converted to a string as follows
Daniel Veillard45490ae2008-07-29 09:13:19 +00008867 * + NaN is converted to the string NaN
8868 * + positive zero is converted to the string 0
8869 * + negative zero is converted to the string 0
8870 * + positive infinity is converted to the string Infinity
8871 * + negative infinity is converted to the string -Infinity
Owen Taylor3473f882001-02-23 17:55:21 +00008872 * + if the number is an integer, the number is represented in
8873 * decimal form as a Number with no decimal point and no leading
8874 * zeros, preceded by a minus sign (-) if the number is negative
8875 * + otherwise, the number is represented in decimal form as a
8876 * Number including a decimal point with at least one digit
8877 * before the decimal point and at least one digit after the
8878 * decimal point, preceded by a minus sign (-) if the number
8879 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008880 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00008881 * before the decimal point; beyond the one required digit
8882 * after the decimal point there must be as many, but only as
8883 * many, more digits as are needed to uniquely distinguish the
8884 * number from all other IEEE 754 numeric values.
8885 * - The boolean false value is converted to the string false.
8886 * The boolean true value is converted to the string true.
8887 *
8888 * If the argument is omitted, it defaults to a node-set with the
8889 * context node as its only member.
8890 */
8891void
8892xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8893 xmlXPathObjectPtr cur;
8894
Daniel Veillarda82b1822004-11-08 16:24:57 +00008895 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008896 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008897 valuePush(ctxt,
8898 xmlXPathCacheWrapString(ctxt->context,
8899 xmlXPathCastNodeToString(ctxt->context->node)));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008900 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008901 }
8902
8903 CHECK_ARITY(1);
8904 cur = valuePop(ctxt);
8905 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008906 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00008907}
8908
8909/**
8910 * xmlXPathStringLengthFunction:
8911 * @ctxt: the XPath Parser context
8912 * @nargs: the number of arguments
8913 *
8914 * Implement the string-length() XPath function
8915 * number string-length(string?)
8916 * The string-length returns the number of characters in the string
8917 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8918 * the context node converted to a string, in other words the value
8919 * of the context node.
8920 */
8921void
8922xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8923 xmlXPathObjectPtr cur;
8924
8925 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008926 if ((ctxt == NULL) || (ctxt->context == NULL))
8927 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008928 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008929 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008930 } else {
8931 xmlChar *content;
8932
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008933 content = xmlXPathCastNodeToString(ctxt->context->node);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008934 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8935 xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00008936 xmlFree(content);
8937 }
8938 return;
8939 }
8940 CHECK_ARITY(1);
8941 CAST_TO_STRING;
8942 CHECK_TYPE(XPATH_STRING);
8943 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008944 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
Daniel Veillard45490ae2008-07-29 09:13:19 +00008945 xmlUTF8Strlen(cur->stringval)));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008946 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008947}
8948
8949/**
8950 * xmlXPathConcatFunction:
8951 * @ctxt: the XPath Parser context
8952 * @nargs: the number of arguments
8953 *
8954 * Implement the concat() XPath function
8955 * string concat(string, string, string*)
8956 * The concat function returns the concatenation of its arguments.
8957 */
8958void
8959xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8960 xmlXPathObjectPtr cur, newobj;
8961 xmlChar *tmp;
8962
Daniel Veillarda82b1822004-11-08 16:24:57 +00008963 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008964 if (nargs < 2) {
8965 CHECK_ARITY(2);
8966 }
8967
8968 CAST_TO_STRING;
8969 cur = valuePop(ctxt);
8970 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008971 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008972 return;
8973 }
8974 nargs--;
8975
8976 while (nargs > 0) {
8977 CAST_TO_STRING;
8978 newobj = valuePop(ctxt);
8979 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008980 xmlXPathReleaseObject(ctxt->context, newobj);
8981 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008982 XP_ERROR(XPATH_INVALID_TYPE);
8983 }
8984 tmp = xmlStrcat(newobj->stringval, cur->stringval);
8985 newobj->stringval = cur->stringval;
8986 cur->stringval = tmp;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008987 xmlXPathReleaseObject(ctxt->context, newobj);
Owen Taylor3473f882001-02-23 17:55:21 +00008988 nargs--;
8989 }
8990 valuePush(ctxt, cur);
8991}
8992
8993/**
8994 * xmlXPathContainsFunction:
8995 * @ctxt: the XPath Parser context
8996 * @nargs: the number of arguments
8997 *
8998 * Implement the contains() XPath function
8999 * boolean contains(string, string)
9000 * The contains function returns true if the first argument string
9001 * contains the second argument string, and otherwise returns false.
9002 */
9003void
9004xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9005 xmlXPathObjectPtr hay, needle;
9006
9007 CHECK_ARITY(2);
9008 CAST_TO_STRING;
9009 CHECK_TYPE(XPATH_STRING);
9010 needle = valuePop(ctxt);
9011 CAST_TO_STRING;
9012 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009013
Owen Taylor3473f882001-02-23 17:55:21 +00009014 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009015 xmlXPathReleaseObject(ctxt->context, hay);
9016 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009017 XP_ERROR(XPATH_INVALID_TYPE);
9018 }
9019 if (xmlStrstr(hay->stringval, needle->stringval))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009020 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009021 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009022 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9023 xmlXPathReleaseObject(ctxt->context, hay);
9024 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009025}
9026
9027/**
9028 * xmlXPathStartsWithFunction:
9029 * @ctxt: the XPath Parser context
9030 * @nargs: the number of arguments
9031 *
9032 * Implement the starts-with() XPath function
9033 * boolean starts-with(string, string)
9034 * The starts-with function returns true if the first argument string
9035 * starts with the second argument string, and otherwise returns false.
9036 */
9037void
9038xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9039 xmlXPathObjectPtr hay, needle;
9040 int n;
9041
9042 CHECK_ARITY(2);
9043 CAST_TO_STRING;
9044 CHECK_TYPE(XPATH_STRING);
9045 needle = valuePop(ctxt);
9046 CAST_TO_STRING;
9047 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009048
Owen Taylor3473f882001-02-23 17:55:21 +00009049 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009050 xmlXPathReleaseObject(ctxt->context, hay);
9051 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009052 XP_ERROR(XPATH_INVALID_TYPE);
9053 }
9054 n = xmlStrlen(needle->stringval);
9055 if (xmlStrncmp(hay->stringval, needle->stringval, n))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009056 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009057 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009058 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9059 xmlXPathReleaseObject(ctxt->context, hay);
9060 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009061}
9062
9063/**
9064 * xmlXPathSubstringFunction:
9065 * @ctxt: the XPath Parser context
9066 * @nargs: the number of arguments
9067 *
9068 * Implement the substring() XPath function
9069 * string substring(string, number, number?)
9070 * The substring function returns the substring of the first argument
9071 * starting at the position specified in the second argument with
9072 * length specified in the third argument. For example,
9073 * substring("12345",2,3) returns "234". If the third argument is not
9074 * specified, it returns the substring starting at the position specified
9075 * in the second argument and continuing to the end of the string. For
9076 * example, substring("12345",2) returns "2345". More precisely, each
9077 * character in the string (see [3.6 Strings]) is considered to have a
9078 * numeric position: the position of the first character is 1, the position
9079 * of the second character is 2 and so on. The returned substring contains
9080 * those characters for which the position of the character is greater than
9081 * or equal to the second argument and, if the third argument is specified,
9082 * less than the sum of the second and third arguments; the comparisons
9083 * and addition used for the above follow the standard IEEE 754 rules. Thus:
Daniel Veillard45490ae2008-07-29 09:13:19 +00009084 * - substring("12345", 1.5, 2.6) returns "234"
9085 * - substring("12345", 0, 3) returns "12"
9086 * - substring("12345", 0 div 0, 3) returns ""
9087 * - substring("12345", 1, 0 div 0) returns ""
9088 * - substring("12345", -42, 1 div 0) returns "12345"
9089 * - substring("12345", -1 div 0, 1 div 0) returns ""
Owen Taylor3473f882001-02-23 17:55:21 +00009090 */
9091void
9092xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9093 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009094 double le=0, in;
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009095 int i = 1, j = INT_MAX;
Owen Taylor3473f882001-02-23 17:55:21 +00009096
Owen Taylor3473f882001-02-23 17:55:21 +00009097 if (nargs < 2) {
9098 CHECK_ARITY(2);
9099 }
9100 if (nargs > 3) {
9101 CHECK_ARITY(3);
9102 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009103 /*
9104 * take care of possible last (position) argument
9105 */
Owen Taylor3473f882001-02-23 17:55:21 +00009106 if (nargs == 3) {
9107 CAST_TO_NUMBER;
9108 CHECK_TYPE(XPATH_NUMBER);
9109 len = valuePop(ctxt);
9110 le = len->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009111 xmlXPathReleaseObject(ctxt->context, len);
Owen Taylor3473f882001-02-23 17:55:21 +00009112 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009113
Owen Taylor3473f882001-02-23 17:55:21 +00009114 CAST_TO_NUMBER;
9115 CHECK_TYPE(XPATH_NUMBER);
9116 start = valuePop(ctxt);
9117 in = start->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009118 xmlXPathReleaseObject(ctxt->context, start);
Owen Taylor3473f882001-02-23 17:55:21 +00009119 CAST_TO_STRING;
9120 CHECK_TYPE(XPATH_STRING);
9121 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009122
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009123 if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
9124 i = INT_MAX;
9125 } else if (in >= 1.0) {
9126 i = (int)in;
9127 if (in - floor(in) >= 0.5)
9128 i += 1;
Daniel Veillard9e412302002-06-10 15:59:44 +00009129 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009130
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009131 if (nargs == 3) {
9132 double rin, rle, end;
Owen Taylor3473f882001-02-23 17:55:21 +00009133
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009134 rin = floor(in);
9135 if (in - rin >= 0.5)
9136 rin += 1.0;
Daniel Veillard9e412302002-06-10 15:59:44 +00009137
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009138 rle = floor(le);
9139 if (le - rle >= 0.5)
9140 rle += 1.0;
Owen Taylor3473f882001-02-23 17:55:21 +00009141
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009142 end = rin + rle;
9143 if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
9144 j = 1;
9145 } else if (end < INT_MAX) {
9146 j = (int)end;
9147 }
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009148 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009149
9150 if (i < j) {
9151 xmlChar *ret = xmlUTF8Strsub(str->stringval, i - 1, j - i);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009152 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009153 xmlFree(ret);
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009154 } else {
9155 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00009156 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009157
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009158 xmlXPathReleaseObject(ctxt->context, str);
Owen Taylor3473f882001-02-23 17:55:21 +00009159}
9160
9161/**
9162 * xmlXPathSubstringBeforeFunction:
9163 * @ctxt: the XPath Parser context
9164 * @nargs: the number of arguments
9165 *
9166 * Implement the substring-before() XPath function
9167 * string substring-before(string, string)
9168 * The substring-before function returns the substring of the first
9169 * argument string that precedes the first occurrence of the second
9170 * argument string in the first argument string, or the empty string
9171 * if the first argument string does not contain the second argument
9172 * string. For example, substring-before("1999/04/01","/") returns 1999.
9173 */
9174void
9175xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9176 xmlXPathObjectPtr str;
9177 xmlXPathObjectPtr find;
Daniel Veillardade10f22012-07-12 09:43:27 +08009178 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009179 const xmlChar *point;
9180 int offset;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009181
Owen Taylor3473f882001-02-23 17:55:21 +00009182 CHECK_ARITY(2);
9183 CAST_TO_STRING;
9184 find = valuePop(ctxt);
9185 CAST_TO_STRING;
9186 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009187
Daniel Veillardade10f22012-07-12 09:43:27 +08009188 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009189 if (target) {
9190 point = xmlStrstr(str->stringval, find->stringval);
9191 if (point) {
9192 offset = (int)(point - str->stringval);
Daniel Veillardade10f22012-07-12 09:43:27 +08009193 xmlBufAdd(target, str->stringval, offset);
Owen Taylor3473f882001-02-23 17:55:21 +00009194 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009195 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009196 xmlBufContent(target)));
9197 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009198 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009199 xmlXPathReleaseObject(ctxt->context, str);
9200 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009201}
9202
9203/**
9204 * xmlXPathSubstringAfterFunction:
9205 * @ctxt: the XPath Parser context
9206 * @nargs: the number of arguments
9207 *
9208 * Implement the substring-after() XPath function
9209 * string substring-after(string, string)
9210 * The substring-after function returns the substring of the first
9211 * argument string that follows the first occurrence of the second
9212 * argument string in the first argument string, or the empty stringi
9213 * if the first argument string does not contain the second argument
9214 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9215 * and substring-after("1999/04/01","19") returns 99/04/01.
9216 */
9217void
9218xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9219 xmlXPathObjectPtr str;
9220 xmlXPathObjectPtr find;
Daniel Veillardade10f22012-07-12 09:43:27 +08009221 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009222 const xmlChar *point;
9223 int offset;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009224
Owen Taylor3473f882001-02-23 17:55:21 +00009225 CHECK_ARITY(2);
9226 CAST_TO_STRING;
9227 find = valuePop(ctxt);
9228 CAST_TO_STRING;
9229 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009230
Daniel Veillardade10f22012-07-12 09:43:27 +08009231 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009232 if (target) {
9233 point = xmlStrstr(str->stringval, find->stringval);
9234 if (point) {
9235 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
Daniel Veillardade10f22012-07-12 09:43:27 +08009236 xmlBufAdd(target, &str->stringval[offset],
Owen Taylor3473f882001-02-23 17:55:21 +00009237 xmlStrlen(str->stringval) - offset);
9238 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009239 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009240 xmlBufContent(target)));
9241 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009242 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009243 xmlXPathReleaseObject(ctxt->context, str);
9244 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009245}
9246
9247/**
9248 * xmlXPathNormalizeFunction:
9249 * @ctxt: the XPath Parser context
9250 * @nargs: the number of arguments
9251 *
9252 * Implement the normalize-space() XPath function
9253 * string normalize-space(string?)
9254 * The normalize-space function returns the argument string with white
9255 * space normalized by stripping leading and trailing whitespace
9256 * and replacing sequences of whitespace characters by a single
9257 * space. Whitespace characters are the same allowed by the S production
9258 * in XML. If the argument is omitted, it defaults to the context
9259 * node converted to a string, in other words the value of the context node.
9260 */
9261void
9262xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9263 xmlXPathObjectPtr obj = NULL;
9264 xmlChar *source = NULL;
Daniel Veillardade10f22012-07-12 09:43:27 +08009265 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009266 xmlChar blank;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009267
Daniel Veillarda82b1822004-11-08 16:24:57 +00009268 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009269 if (nargs == 0) {
9270 /* Use current context node */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009271 valuePush(ctxt,
9272 xmlXPathCacheWrapString(ctxt->context,
9273 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00009274 nargs = 1;
9275 }
9276
9277 CHECK_ARITY(1);
9278 CAST_TO_STRING;
9279 CHECK_TYPE(XPATH_STRING);
9280 obj = valuePop(ctxt);
9281 source = obj->stringval;
9282
Daniel Veillardade10f22012-07-12 09:43:27 +08009283 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009284 if (target && source) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00009285
Owen Taylor3473f882001-02-23 17:55:21 +00009286 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00009287 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00009288 source++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009289
Owen Taylor3473f882001-02-23 17:55:21 +00009290 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9291 blank = 0;
9292 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00009293 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009294 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00009295 } else {
9296 if (blank) {
Daniel Veillardade10f22012-07-12 09:43:27 +08009297 xmlBufAdd(target, &blank, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00009298 blank = 0;
9299 }
Daniel Veillardade10f22012-07-12 09:43:27 +08009300 xmlBufAdd(target, source, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00009301 }
9302 source++;
9303 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009304 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009305 xmlBufContent(target)));
9306 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009307 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009308 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00009309}
9310
9311/**
9312 * xmlXPathTranslateFunction:
9313 * @ctxt: the XPath Parser context
9314 * @nargs: the number of arguments
9315 *
9316 * Implement the translate() XPath function
9317 * string translate(string, string, string)
9318 * The translate function returns the first argument string with
9319 * occurrences of characters in the second argument string replaced
9320 * by the character at the corresponding position in the third argument
9321 * string. For example, translate("bar","abc","ABC") returns the string
9322 * BAr. If there is a character in the second argument string with no
9323 * character at a corresponding position in the third argument string
9324 * (because the second argument string is longer than the third argument
9325 * string), then occurrences of that character in the first argument
9326 * string are removed. For example, translate("--aaa--","abc-","ABC")
9327 * returns "AAA". If a character occurs more than once in second
9328 * argument string, then the first occurrence determines the replacement
9329 * character. If the third argument string is longer than the second
9330 * argument string, then excess characters are ignored.
9331 */
9332void
9333xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00009334 xmlXPathObjectPtr str;
9335 xmlXPathObjectPtr from;
9336 xmlXPathObjectPtr to;
Daniel Veillardade10f22012-07-12 09:43:27 +08009337 xmlBufPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009338 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009339 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00009340 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009341 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00009342
Daniel Veillarde043ee12001-04-16 14:08:07 +00009343 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00009344
Daniel Veillarde043ee12001-04-16 14:08:07 +00009345 CAST_TO_STRING;
9346 to = valuePop(ctxt);
9347 CAST_TO_STRING;
9348 from = valuePop(ctxt);
9349 CAST_TO_STRING;
9350 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009351
Daniel Veillardade10f22012-07-12 09:43:27 +08009352 target = xmlBufCreate();
Daniel Veillarde043ee12001-04-16 14:08:07 +00009353 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009354 max = xmlUTF8Strlen(to->stringval);
9355 for (cptr = str->stringval; (ch=*cptr); ) {
9356 offset = xmlUTF8Strloc(from->stringval, cptr);
9357 if (offset >= 0) {
9358 if (offset < max) {
9359 point = xmlUTF8Strpos(to->stringval, offset);
9360 if (point)
Daniel Veillardade10f22012-07-12 09:43:27 +08009361 xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
Daniel Veillard97ac1312001-05-30 19:14:17 +00009362 }
9363 } else
Daniel Veillardade10f22012-07-12 09:43:27 +08009364 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
Daniel Veillard97ac1312001-05-30 19:14:17 +00009365
9366 /* Step to next character in input */
9367 cptr++;
9368 if ( ch & 0x80 ) {
9369 /* if not simple ascii, verify proper format */
9370 if ( (ch & 0xc0) != 0xc0 ) {
9371 xmlGenericError(xmlGenericErrorContext,
9372 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08009373 /* not asserting an XPath error is probably better */
Daniel Veillard97ac1312001-05-30 19:14:17 +00009374 break;
9375 }
9376 /* then skip over remaining bytes for this char */
9377 while ( (ch <<= 1) & 0x80 )
9378 if ( (*cptr++ & 0xc0) != 0x80 ) {
9379 xmlGenericError(xmlGenericErrorContext,
9380 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08009381 /* not asserting an XPath error is probably better */
Daniel Veillard97ac1312001-05-30 19:14:17 +00009382 break;
9383 }
9384 if (ch & 0x80) /* must have had error encountered */
9385 break;
9386 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00009387 }
Owen Taylor3473f882001-02-23 17:55:21 +00009388 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009389 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009390 xmlBufContent(target)));
9391 xmlBufFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009392 xmlXPathReleaseObject(ctxt->context, str);
9393 xmlXPathReleaseObject(ctxt->context, from);
9394 xmlXPathReleaseObject(ctxt->context, to);
Owen Taylor3473f882001-02-23 17:55:21 +00009395}
9396
9397/**
9398 * xmlXPathBooleanFunction:
9399 * @ctxt: the XPath Parser context
9400 * @nargs: the number of arguments
9401 *
9402 * Implement the boolean() XPath function
9403 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00009404 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00009405 * - a number is true if and only if it is neither positive or
9406 * negative zero nor NaN
9407 * - a node-set is true if and only if it is non-empty
9408 * - a string is true if and only if its length is non-zero
9409 */
9410void
9411xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9412 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00009413
9414 CHECK_ARITY(1);
9415 cur = valuePop(ctxt);
9416 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009417 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009418 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009419}
9420
9421/**
9422 * xmlXPathNotFunction:
9423 * @ctxt: the XPath Parser context
9424 * @nargs: the number of arguments
9425 *
9426 * Implement the not() XPath function
9427 * boolean not(boolean)
9428 * The not function returns true if its argument is false,
9429 * and false otherwise.
9430 */
9431void
9432xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9433 CHECK_ARITY(1);
9434 CAST_TO_BOOLEAN;
9435 CHECK_TYPE(XPATH_BOOLEAN);
9436 ctxt->value->boolval = ! ctxt->value->boolval;
9437}
9438
9439/**
9440 * xmlXPathTrueFunction:
9441 * @ctxt: the XPath Parser context
9442 * @nargs: the number of arguments
9443 *
9444 * Implement the true() XPath function
9445 * boolean true()
9446 */
9447void
9448xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9449 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009450 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009451}
9452
9453/**
9454 * xmlXPathFalseFunction:
9455 * @ctxt: the XPath Parser context
9456 * @nargs: the number of arguments
9457 *
9458 * Implement the false() XPath function
9459 * boolean false()
9460 */
9461void
9462xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9463 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009464 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009465}
9466
9467/**
9468 * xmlXPathLangFunction:
9469 * @ctxt: the XPath Parser context
9470 * @nargs: the number of arguments
9471 *
9472 * Implement the lang() XPath function
9473 * boolean lang(string)
9474 * The lang function returns true or false depending on whether the
9475 * language of the context node as specified by xml:lang attributes
9476 * is the same as or is a sublanguage of the language specified by
9477 * the argument string. The language of the context node is determined
9478 * by the value of the xml:lang attribute on the context node, or, if
9479 * the context node has no xml:lang attribute, by the value of the
9480 * xml:lang attribute on the nearest ancestor of the context node that
9481 * has an xml:lang attribute. If there is no such attribute, then lang
9482 * returns false. If there is such an attribute, then lang returns
9483 * true if the attribute value is equal to the argument ignoring case,
9484 * or if there is some suffix starting with - such that the attribute
9485 * value is equal to the argument ignoring that suffix of the attribute
9486 * value and ignoring case.
9487 */
9488void
9489xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009490 xmlXPathObjectPtr val = NULL;
9491 const xmlChar *theLang = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009492 const xmlChar *lang;
9493 int ret = 0;
9494 int i;
9495
9496 CHECK_ARITY(1);
9497 CAST_TO_STRING;
9498 CHECK_TYPE(XPATH_STRING);
9499 val = valuePop(ctxt);
9500 lang = val->stringval;
9501 theLang = xmlNodeGetLang(ctxt->context->node);
9502 if ((theLang != NULL) && (lang != NULL)) {
9503 for (i = 0;lang[i] != 0;i++)
9504 if (toupper(lang[i]) != toupper(theLang[i]))
9505 goto not_equal;
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009506 if ((theLang[i] == 0) || (theLang[i] == '-'))
9507 ret = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009508 }
9509not_equal:
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009510 if (theLang != NULL)
9511 xmlFree((void *)theLang);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009512
9513 xmlXPathReleaseObject(ctxt->context, val);
9514 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009515}
9516
9517/**
9518 * xmlXPathNumberFunction:
9519 * @ctxt: the XPath Parser context
9520 * @nargs: the number of arguments
9521 *
9522 * Implement the number() XPath function
9523 * number number(object?)
9524 */
9525void
9526xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9527 xmlXPathObjectPtr cur;
9528 double res;
9529
Daniel Veillarda82b1822004-11-08 16:24:57 +00009530 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009531 if (nargs == 0) {
9532 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009533 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
Owen Taylor3473f882001-02-23 17:55:21 +00009534 } else {
9535 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9536
9537 res = xmlXPathStringEvalNumber(content);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009538 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
Owen Taylor3473f882001-02-23 17:55:21 +00009539 xmlFree(content);
9540 }
9541 return;
9542 }
9543
9544 CHECK_ARITY(1);
9545 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009546 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00009547}
9548
9549/**
9550 * xmlXPathSumFunction:
9551 * @ctxt: the XPath Parser context
9552 * @nargs: the number of arguments
9553 *
9554 * Implement the sum() XPath function
9555 * number sum(node-set)
9556 * The sum function returns the sum of the values of the nodes in
9557 * the argument node-set.
9558 */
9559void
9560xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9561 xmlXPathObjectPtr cur;
9562 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009563 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00009564
9565 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009566 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009567 ((ctxt->value->type != XPATH_NODESET) &&
9568 (ctxt->value->type != XPATH_XSLT_TREE)))
9569 XP_ERROR(XPATH_INVALID_TYPE);
9570 cur = valuePop(ctxt);
9571
William M. Brack08171912003-12-29 02:52:11 +00009572 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009573 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9574 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00009575 }
9576 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009577 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9578 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009579}
9580
9581/**
9582 * xmlXPathFloorFunction:
9583 * @ctxt: the XPath Parser context
9584 * @nargs: the number of arguments
9585 *
9586 * Implement the floor() XPath function
9587 * number floor(number)
9588 * The floor function returns the largest (closest to positive infinity)
9589 * number that is not greater than the argument and that is an integer.
9590 */
9591void
9592xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9593 CHECK_ARITY(1);
9594 CAST_TO_NUMBER;
9595 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009596
Nick Wellnhofer4bebb032016-04-21 13:41:09 +02009597 ctxt->value->floatval = floor(ctxt->value->floatval);
Owen Taylor3473f882001-02-23 17:55:21 +00009598}
9599
9600/**
9601 * xmlXPathCeilingFunction:
9602 * @ctxt: the XPath Parser context
9603 * @nargs: the number of arguments
9604 *
9605 * Implement the ceiling() XPath function
9606 * number ceiling(number)
9607 * The ceiling function returns the smallest (closest to negative infinity)
9608 * number that is not less than the argument and that is an integer.
9609 */
9610void
9611xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Owen Taylor3473f882001-02-23 17:55:21 +00009612 CHECK_ARITY(1);
9613 CAST_TO_NUMBER;
9614 CHECK_TYPE(XPATH_NUMBER);
9615
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009616#ifdef _AIX
9617 /* Work around buggy ceil() function on AIX */
9618 ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
9619#else
Owen Taylor3473f882001-02-23 17:55:21 +00009620 ctxt->value->floatval = ceil(ctxt->value->floatval);
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009621#endif
Owen Taylor3473f882001-02-23 17:55:21 +00009622}
9623
9624/**
9625 * xmlXPathRoundFunction:
9626 * @ctxt: the XPath Parser context
9627 * @nargs: the number of arguments
9628 *
9629 * Implement the round() XPath function
9630 * number round(number)
9631 * The round function returns the number that is closest to the
9632 * argument and that is an integer. If there are two such numbers,
Nick Wellnhofer4bebb032016-04-21 13:41:09 +02009633 * then the one that is closest to positive infinity is returned.
Owen Taylor3473f882001-02-23 17:55:21 +00009634 */
9635void
9636xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9637 double f;
9638
9639 CHECK_ARITY(1);
9640 CAST_TO_NUMBER;
9641 CHECK_TYPE(XPATH_NUMBER);
9642
Nick Wellnhofer4bebb032016-04-21 13:41:09 +02009643 f = ctxt->value->floatval;
9644
Nick Wellnhofer8813f392017-09-21 00:11:26 +02009645 if ((f >= -0.5) && (f < 0.5)) {
9646 /* Handles negative zero. */
9647 ctxt->value->floatval *= 0.0;
Nick Wellnhofer4bebb032016-04-21 13:41:09 +02009648 }
9649 else {
9650 double rounded = floor(f);
9651 if (f - rounded >= 0.5)
9652 rounded += 1.0;
9653 ctxt->value->floatval = rounded;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009654 }
Owen Taylor3473f882001-02-23 17:55:21 +00009655}
9656
9657/************************************************************************
9658 * *
9659 * The Parser *
9660 * *
9661 ************************************************************************/
9662
9663/*
William M. Brack08171912003-12-29 02:52:11 +00009664 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00009665 * implementation.
9666 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009667static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009668static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009669static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009670static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00009671static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9672 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00009673
9674/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00009675 * xmlXPathCurrentChar:
9676 * @ctxt: the XPath parser context
9677 * @cur: pointer to the beginning of the char
9678 * @len: pointer to the length of the char read
9679 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009680 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00009681 * bytes in the input buffer.
9682 *
Daniel Veillard60087f32001-10-10 09:45:09 +00009683 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00009684 */
9685
9686static int
9687xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9688 unsigned char c;
9689 unsigned int val;
9690 const xmlChar *cur;
9691
9692 if (ctxt == NULL)
9693 return(0);
9694 cur = ctxt->cur;
9695
9696 /*
9697 * We are supposed to handle UTF8, check it's valid
9698 * From rfc2044: encoding of the Unicode values on UTF-8:
9699 *
9700 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9701 * 0000 0000-0000 007F 0xxxxxxx
9702 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
Daniel Veillard45490ae2008-07-29 09:13:19 +00009703 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
Daniel Veillard61d80a22001-04-27 17:13:01 +00009704 *
9705 * Check for the 0x110000 limit too
9706 */
9707 c = *cur;
9708 if (c & 0x80) {
9709 if ((cur[1] & 0xc0) != 0x80)
9710 goto encoding_error;
9711 if ((c & 0xe0) == 0xe0) {
9712
9713 if ((cur[2] & 0xc0) != 0x80)
9714 goto encoding_error;
9715 if ((c & 0xf0) == 0xf0) {
9716 if (((c & 0xf8) != 0xf0) ||
9717 ((cur[3] & 0xc0) != 0x80))
9718 goto encoding_error;
9719 /* 4-byte code */
9720 *len = 4;
9721 val = (cur[0] & 0x7) << 18;
9722 val |= (cur[1] & 0x3f) << 12;
9723 val |= (cur[2] & 0x3f) << 6;
9724 val |= cur[3] & 0x3f;
9725 } else {
9726 /* 3-byte code */
9727 *len = 3;
9728 val = (cur[0] & 0xf) << 12;
9729 val |= (cur[1] & 0x3f) << 6;
9730 val |= cur[2] & 0x3f;
9731 }
9732 } else {
9733 /* 2-byte code */
9734 *len = 2;
9735 val = (cur[0] & 0x1f) << 6;
9736 val |= cur[1] & 0x3f;
9737 }
9738 if (!IS_CHAR(val)) {
9739 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009740 }
Daniel Veillard61d80a22001-04-27 17:13:01 +00009741 return(val);
9742 } else {
9743 /* 1-byte code */
9744 *len = 1;
9745 return((int) *cur);
9746 }
9747encoding_error:
9748 /*
William M. Brack08171912003-12-29 02:52:11 +00009749 * If we detect an UTF8 error that probably means that the
9750 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00009751 * declaration header. Report the error and switch the encoding
9752 * to ISO-Latin-1 (if you don't like this policy, just declare the
9753 * encoding !)
9754 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00009755 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00009756 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009757}
9758
9759/**
Owen Taylor3473f882001-02-23 17:55:21 +00009760 * xmlXPathParseNCName:
9761 * @ctxt: the XPath Parser context
9762 *
9763 * parse an XML namespace non qualified name.
9764 *
9765 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9766 *
9767 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9768 * CombiningChar | Extender
9769 *
9770 * Returns the namespace name or NULL
9771 */
9772
9773xmlChar *
9774xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00009775 const xmlChar *in;
9776 xmlChar *ret;
9777 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009778
Daniel Veillarda82b1822004-11-08 16:24:57 +00009779 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00009780 /*
9781 * Accelerator for simple ASCII names
9782 */
9783 in = ctxt->cur;
9784 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9785 ((*in >= 0x41) && (*in <= 0x5A)) ||
9786 (*in == '_')) {
9787 in++;
9788 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9789 ((*in >= 0x41) && (*in <= 0x5A)) ||
9790 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00009791 (*in == '_') || (*in == '.') ||
9792 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00009793 in++;
9794 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9795 (*in == '[') || (*in == ']') || (*in == ':') ||
9796 (*in == '@') || (*in == '*')) {
9797 count = in - ctxt->cur;
9798 if (count == 0)
9799 return(NULL);
9800 ret = xmlStrndup(ctxt->cur, count);
9801 ctxt->cur = in;
9802 return(ret);
9803 }
9804 }
9805 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009806}
9807
Daniel Veillard2156a562001-04-28 12:24:34 +00009808
Owen Taylor3473f882001-02-23 17:55:21 +00009809/**
9810 * xmlXPathParseQName:
9811 * @ctxt: the XPath Parser context
Daniel Veillard45490ae2008-07-29 09:13:19 +00009812 * @prefix: a xmlChar **
Owen Taylor3473f882001-02-23 17:55:21 +00009813 *
9814 * parse an XML qualified name
9815 *
9816 * [NS 5] QName ::= (Prefix ':')? LocalPart
9817 *
9818 * [NS 6] Prefix ::= NCName
9819 *
9820 * [NS 7] LocalPart ::= NCName
9821 *
9822 * Returns the function returns the local part, and prefix is updated
9823 * to get the Prefix if any.
9824 */
9825
Daniel Veillard56a4cb82001-03-24 17:00:36 +00009826static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00009827xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9828 xmlChar *ret = NULL;
9829
9830 *prefix = NULL;
9831 ret = xmlXPathParseNCName(ctxt);
Daniel Veillard074f37e2008-09-01 13:38:22 +00009832 if (ret && CUR == ':') {
Owen Taylor3473f882001-02-23 17:55:21 +00009833 *prefix = ret;
9834 NEXT;
9835 ret = xmlXPathParseNCName(ctxt);
9836 }
9837 return(ret);
9838}
9839
9840/**
9841 * xmlXPathParseName:
9842 * @ctxt: the XPath Parser context
9843 *
9844 * parse an XML name
9845 *
9846 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9847 * CombiningChar | Extender
9848 *
9849 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9850 *
9851 * Returns the namespace name or NULL
9852 */
9853
9854xmlChar *
9855xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009856 const xmlChar *in;
9857 xmlChar *ret;
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009858 size_t count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009859
Daniel Veillarda82b1822004-11-08 16:24:57 +00009860 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009861 /*
9862 * Accelerator for simple ASCII names
9863 */
9864 in = ctxt->cur;
9865 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9866 ((*in >= 0x41) && (*in <= 0x5A)) ||
9867 (*in == '_') || (*in == ':')) {
9868 in++;
9869 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9870 ((*in >= 0x41) && (*in <= 0x5A)) ||
9871 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00009872 (*in == '_') || (*in == '-') ||
9873 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00009874 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00009875 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009876 count = in - ctxt->cur;
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009877 if (count > XML_MAX_NAME_LENGTH) {
9878 ctxt->cur = in;
9879 XP_ERRORNULL(XPATH_EXPR_ERROR);
9880 }
Daniel Veillard61d80a22001-04-27 17:13:01 +00009881 ret = xmlStrndup(ctxt->cur, count);
9882 ctxt->cur = in;
9883 return(ret);
9884 }
9885 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009886 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009887}
9888
Daniel Veillard61d80a22001-04-27 17:13:01 +00009889static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00009890xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009891 xmlChar buf[XML_MAX_NAMELEN + 5];
9892 int len = 0, l;
9893 int c;
9894
9895 /*
9896 * Handler for more complex cases
9897 */
9898 c = CUR_CHAR(l);
9899 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00009900 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9901 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00009902 (!IS_LETTER(c) && (c != '_') &&
Nick Wellnhofere2893902016-04-21 19:19:23 +02009903 ((!qualified) || (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009904 return(NULL);
9905 }
9906
9907 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9908 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9909 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00009910 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009911 (IS_COMBINING(c)) ||
9912 (IS_EXTENDER(c)))) {
9913 COPY_BUF(l,buf,len,c);
9914 NEXTL(l);
9915 c = CUR_CHAR(l);
9916 if (len >= XML_MAX_NAMELEN) {
9917 /*
9918 * Okay someone managed to make a huge name, so he's ready to pay
9919 * for the processing speed.
9920 */
9921 xmlChar *buffer;
9922 int max = len * 2;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009923
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009924 if (len > XML_MAX_NAME_LENGTH) {
9925 XP_ERRORNULL(XPATH_EXPR_ERROR);
9926 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00009927 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009928 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009929 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009930 }
9931 memcpy(buffer, buf, len);
9932 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9933 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00009934 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009935 (IS_COMBINING(c)) ||
9936 (IS_EXTENDER(c))) {
9937 if (len + 10 > max) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009938 xmlChar *tmp;
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009939 if (max > XML_MAX_NAME_LENGTH) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009940 xmlFree(buffer);
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009941 XP_ERRORNULL(XPATH_EXPR_ERROR);
9942 }
Daniel Veillard61d80a22001-04-27 17:13:01 +00009943 max *= 2;
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009944 tmp = (xmlChar *) xmlRealloc(buffer,
9945 max * sizeof(xmlChar));
9946 if (tmp == NULL) {
9947 xmlFree(buffer);
Daniel Veillard24505b02005-07-28 23:49:35 +00009948 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009949 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009950 buffer = tmp;
Daniel Veillard61d80a22001-04-27 17:13:01 +00009951 }
9952 COPY_BUF(l,buffer,len,c);
9953 NEXTL(l);
9954 c = CUR_CHAR(l);
9955 }
9956 buffer[len] = 0;
9957 return(buffer);
9958 }
9959 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009960 if (len == 0)
9961 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009962 return(xmlStrndup(buf, len));
9963}
Daniel Veillard3cd72402002-05-13 10:33:30 +00009964
9965#define MAX_FRAC 20
9966
Owen Taylor3473f882001-02-23 17:55:21 +00009967/**
9968 * xmlXPathStringEvalNumber:
9969 * @str: A string to scan
9970 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00009971 * [30a] Float ::= Number ('e' Digits?)?
9972 *
Owen Taylor3473f882001-02-23 17:55:21 +00009973 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard45490ae2008-07-29 09:13:19 +00009974 * | '.' Digits
Owen Taylor3473f882001-02-23 17:55:21 +00009975 * [31] Digits ::= [0-9]+
9976 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009977 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00009978 * In complement of the Number expression, this function also handles
9979 * negative values : '-' Number.
9980 *
9981 * Returns the double value.
9982 */
9983double
9984xmlXPathStringEvalNumber(const xmlChar *str) {
9985 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00009986 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009987 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009988 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009989 int exponent = 0;
9990 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009991#ifdef __GNUC__
9992 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00009993 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009994#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00009995 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00009996 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009997 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
Elliott Hughes5cefca72021-05-06 13:23:15 -07009998 return(xmlXPathNAN);
Owen Taylor3473f882001-02-23 17:55:21 +00009999 }
10000 if (*cur == '-') {
10001 isneg = 1;
10002 cur++;
10003 }
Daniel Veillardb06c6142001-08-27 14:26:30 +000010004
10005#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010006 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010007 * tmp/temp is a workaround against a gcc compiler bug
10008 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010009 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010010 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010011 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010012 ret = ret * 10;
10013 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +000010014 ok = 1;
10015 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +000010016 temp = (double) tmp;
10017 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010018 }
Daniel Veillardb06c6142001-08-27 14:26:30 +000010019#else
Daniel Veillard7b416132002-03-07 08:36:03 +000010020 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010021 while ((*cur >= '0') && (*cur <= '9')) {
10022 ret = ret * 10 + (*cur - '0');
10023 ok = 1;
10024 cur++;
10025 }
10026#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010027
Owen Taylor3473f882001-02-23 17:55:21 +000010028 if (*cur == '.') {
Nick Wellnhofera8518682017-05-29 20:14:42 +020010029 int v, frac = 0, max;
Daniel Veillard3cd72402002-05-13 10:33:30 +000010030 double fraction = 0;
10031
Owen Taylor3473f882001-02-23 17:55:21 +000010032 cur++;
10033 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
Elliott Hughes5cefca72021-05-06 13:23:15 -070010034 return(xmlXPathNAN);
Owen Taylor3473f882001-02-23 17:55:21 +000010035 }
Nick Wellnhofera8518682017-05-29 20:14:42 +020010036 while (*cur == '0') {
10037 frac = frac + 1;
10038 cur++;
10039 }
10040 max = frac + MAX_FRAC;
10041 while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
Daniel Veillard3cd72402002-05-13 10:33:30 +000010042 v = (*cur - '0');
10043 fraction = fraction * 10 + v;
10044 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010045 cur++;
10046 }
Nick Wellnhofera8518682017-05-29 20:14:42 +020010047 fraction /= pow(10.0, frac);
Daniel Veillard3cd72402002-05-13 10:33:30 +000010048 ret = ret + fraction;
10049 while ((*cur >= '0') && (*cur <= '9'))
10050 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010051 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010052 if ((*cur == 'e') || (*cur == 'E')) {
10053 cur++;
10054 if (*cur == '-') {
10055 is_exponent_negative = 1;
10056 cur++;
William M. Brack99127052004-05-24 02:52:28 +000010057 } else if (*cur == '+') {
10058 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010059 }
10060 while ((*cur >= '0') && (*cur <= '9')) {
Nick Wellnhoferf4029cd2016-04-21 16:37:26 +020010061 if (exponent < 1000000)
10062 exponent = exponent * 10 + (*cur - '0');
Bjorn Reese70a9da52001-04-21 16:57:29 +000010063 cur++;
10064 }
10065 }
William M. Brack76e95df2003-10-18 16:20:14 +000010066 while (IS_BLANK_CH(*cur)) cur++;
Elliott Hughes5cefca72021-05-06 13:23:15 -070010067 if (*cur != 0) return(xmlXPathNAN);
Owen Taylor3473f882001-02-23 17:55:21 +000010068 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010069 if (is_exponent_negative) exponent = -exponent;
10070 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +000010071 return(ret);
10072}
10073
10074/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010075 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +000010076 * @ctxt: the XPath Parser context
10077 *
10078 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard45490ae2008-07-29 09:13:19 +000010079 * | '.' Digits
Owen Taylor3473f882001-02-23 17:55:21 +000010080 * [31] Digits ::= [0-9]+
10081 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010082 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +000010083 *
10084 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010085static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010086xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10087{
Owen Taylor3473f882001-02-23 17:55:21 +000010088 double ret = 0.0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010089 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010090 int exponent = 0;
10091 int is_exponent_negative = 0;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070010092 xmlXPathObjectPtr num;
Daniel Veillard7b416132002-03-07 08:36:03 +000010093#ifdef __GNUC__
10094 unsigned long tmp = 0;
10095 double temp;
10096#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010097
10098 CHECK_ERROR;
10099 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10100 XP_ERROR(XPATH_NUMBER_ERROR);
10101 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010102#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010103 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010104 * tmp/temp is a workaround against a gcc compiler bug
10105 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010106 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010107 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010108 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010109 ret = ret * 10;
10110 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010111 ok = 1;
10112 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +000010113 temp = (double) tmp;
10114 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010115 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010116#else
10117 ret = 0;
10118 while ((CUR >= '0') && (CUR <= '9')) {
10119 ret = ret * 10 + (CUR - '0');
10120 ok = 1;
10121 NEXT;
10122 }
10123#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010124 if (CUR == '.') {
Nick Wellnhofera8518682017-05-29 20:14:42 +020010125 int v, frac = 0, max;
Phil Shaferee32ad32010-11-03 20:53:55 +010010126 double fraction = 0;
10127
Owen Taylor3473f882001-02-23 17:55:21 +000010128 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010129 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10130 XP_ERROR(XPATH_NUMBER_ERROR);
10131 }
Nick Wellnhofera8518682017-05-29 20:14:42 +020010132 while (CUR == '0') {
10133 frac = frac + 1;
10134 NEXT;
10135 }
10136 max = frac + MAX_FRAC;
10137 while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
Phil Shaferee32ad32010-11-03 20:53:55 +010010138 v = (CUR - '0');
10139 fraction = fraction * 10 + v;
10140 frac = frac + 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010141 NEXT;
10142 }
Nick Wellnhofera8518682017-05-29 20:14:42 +020010143 fraction /= pow(10.0, frac);
Phil Shaferee32ad32010-11-03 20:53:55 +010010144 ret = ret + fraction;
10145 while ((CUR >= '0') && (CUR <= '9'))
10146 NEXT;
Owen Taylor3473f882001-02-23 17:55:21 +000010147 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010148 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010149 NEXT;
10150 if (CUR == '-') {
10151 is_exponent_negative = 1;
10152 NEXT;
William M. Brack99127052004-05-24 02:52:28 +000010153 } else if (CUR == '+') {
10154 NEXT;
10155 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010156 while ((CUR >= '0') && (CUR <= '9')) {
Nick Wellnhoferf4029cd2016-04-21 16:37:26 +020010157 if (exponent < 1000000)
10158 exponent = exponent * 10 + (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010159 NEXT;
10160 }
10161 if (is_exponent_negative)
10162 exponent = -exponent;
10163 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +000010164 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070010165 num = xmlXPathCacheNewFloat(ctxt->context, ret);
10166 if (num == NULL) {
10167 ctxt->error = XPATH_MEMORY_ERROR;
10168 } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
10169 NULL) == -1) {
10170 xmlXPathReleaseObject(ctxt->context, num);
10171 }
Owen Taylor3473f882001-02-23 17:55:21 +000010172}
10173
10174/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010175 * xmlXPathParseLiteral:
10176 * @ctxt: the XPath Parser context
10177 *
10178 * Parse a Literal
10179 *
10180 * [29] Literal ::= '"' [^"]* '"'
10181 * | "'" [^']* "'"
10182 *
10183 * Returns the value found or NULL in case of error
10184 */
10185static xmlChar *
10186xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10187 const xmlChar *q;
10188 xmlChar *ret = NULL;
10189
10190 if (CUR == '"') {
10191 NEXT;
10192 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010193 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010194 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010195 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010196 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010197 } else {
10198 ret = xmlStrndup(q, CUR_PTR - q);
10199 NEXT;
10200 }
10201 } else if (CUR == '\'') {
10202 NEXT;
10203 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010204 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010205 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010206 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010207 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010208 } else {
10209 ret = xmlStrndup(q, CUR_PTR - q);
10210 NEXT;
10211 }
10212 } else {
Daniel Veillard24505b02005-07-28 23:49:35 +000010213 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010214 }
10215 return(ret);
10216}
10217
10218/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010219 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +000010220 * @ctxt: the XPath Parser context
10221 *
10222 * Parse a Literal and push it on the stack.
10223 *
10224 * [29] Literal ::= '"' [^"]* '"'
10225 * | "'" [^']* "'"
10226 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010227 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +000010228 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010229static void
10230xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010231 const xmlChar *q;
10232 xmlChar *ret = NULL;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070010233 xmlXPathObjectPtr lit;
Owen Taylor3473f882001-02-23 17:55:21 +000010234
10235 if (CUR == '"') {
10236 NEXT;
10237 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010238 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +000010239 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010240 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010241 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10242 } else {
10243 ret = xmlStrndup(q, CUR_PTR - q);
10244 NEXT;
10245 }
10246 } else if (CUR == '\'') {
10247 NEXT;
10248 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010249 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +000010250 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010251 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010252 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10253 } else {
10254 ret = xmlStrndup(q, CUR_PTR - q);
10255 NEXT;
10256 }
10257 } else {
10258 XP_ERROR(XPATH_START_LITERAL_ERROR);
10259 }
10260 if (ret == NULL) return;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070010261 lit = xmlXPathCacheNewString(ctxt->context, ret);
10262 if (lit == NULL) {
10263 ctxt->error = XPATH_MEMORY_ERROR;
10264 } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
10265 NULL) == -1) {
10266 xmlXPathReleaseObject(ctxt->context, lit);
10267 }
Owen Taylor3473f882001-02-23 17:55:21 +000010268 xmlFree(ret);
10269}
10270
10271/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010272 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +000010273 * @ctxt: the XPath Parser context
10274 *
10275 * Parse a VariableReference, evaluate it and push it on the stack.
10276 *
10277 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +000010278 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +000010279 * of any of the types that are possible for the value of an expression,
10280 * and may also be of additional types not specified here.
10281 *
10282 * Early evaluation is possible since:
10283 * The variable bindings [...] used to evaluate a subexpression are
Daniel Veillard45490ae2008-07-29 09:13:19 +000010284 * always the same as those used to evaluate the containing expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010285 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010286 * [36] VariableReference ::= '$' QName
Owen Taylor3473f882001-02-23 17:55:21 +000010287 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010288static void
10289xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010290 xmlChar *name;
10291 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010292
10293 SKIP_BLANKS;
10294 if (CUR != '$') {
10295 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10296 }
10297 NEXT;
10298 name = xmlXPathParseQName(ctxt, &prefix);
10299 if (name == NULL) {
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020010300 xmlFree(prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010301 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10302 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010303 ctxt->comp->last = -1;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070010304 if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
10305 xmlFree(prefix);
10306 xmlFree(name);
10307 }
Owen Taylor3473f882001-02-23 17:55:21 +000010308 SKIP_BLANKS;
Daniel Veillardb3d14912005-09-04 20:47:39 +000010309 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
Daniel Veillard47881282012-09-07 14:24:50 +080010310 XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
Daniel Veillardb3d14912005-09-04 20:47:39 +000010311 }
Owen Taylor3473f882001-02-23 17:55:21 +000010312}
10313
10314/**
10315 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +000010316 * @name: a name string
10317 *
10318 * Is the name given a NodeType one.
10319 *
10320 * [38] NodeType ::= 'comment'
10321 * | 'text'
10322 * | 'processing-instruction'
10323 * | 'node'
10324 *
10325 * Returns 1 if true 0 otherwise
10326 */
10327int
10328xmlXPathIsNodeType(const xmlChar *name) {
10329 if (name == NULL)
10330 return(0);
10331
Daniel Veillard1971ee22002-01-31 20:29:19 +000010332 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +000010333 return(1);
10334 if (xmlStrEqual(name, BAD_CAST "text"))
10335 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010336 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +000010337 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010338 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +000010339 return(1);
10340 return(0);
10341}
10342
10343/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010344 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +000010345 * @ctxt: the XPath Parser context
10346 *
10347 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010348 * [17] Argument ::= Expr
Owen Taylor3473f882001-02-23 17:55:21 +000010349 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010350 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +000010351 * pushed on the stack
10352 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010353static void
10354xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010355 xmlChar *name;
10356 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010357 int nbargs = 0;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010358 int sort = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010359
10360 name = xmlXPathParseQName(ctxt, &prefix);
10361 if (name == NULL) {
Daniel Veillard074f37e2008-09-01 13:38:22 +000010362 xmlFree(prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010363 XP_ERROR(XPATH_EXPR_ERROR);
10364 }
10365 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010366#ifdef DEBUG_EXPR
10367 if (prefix == NULL)
10368 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10369 name);
10370 else
10371 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10372 prefix, name);
10373#endif
10374
Owen Taylor3473f882001-02-23 17:55:21 +000010375 if (CUR != '(') {
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020010376 xmlFree(name);
10377 xmlFree(prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010378 XP_ERROR(XPATH_EXPR_ERROR);
10379 }
10380 NEXT;
10381 SKIP_BLANKS;
10382
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010383 /*
10384 * Optimization for count(): we don't need the node-set to be sorted.
10385 */
10386 if ((prefix == NULL) && (name[0] == 'c') &&
10387 xmlStrEqual(name, BAD_CAST "count"))
10388 {
10389 sort = 0;
10390 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010391 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +000010392 if (CUR != ')') {
10393 while (CUR != 0) {
10394 int op1 = ctxt->comp->last;
10395 ctxt->comp->last = -1;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010396 xmlXPathCompileExpr(ctxt, sort);
Daniel Veillard074f37e2008-09-01 13:38:22 +000010397 if (ctxt->error != XPATH_EXPRESSION_OK) {
10398 xmlFree(name);
10399 xmlFree(prefix);
10400 return;
10401 }
Daniel Veillard71f9d732003-01-14 16:07:16 +000010402 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10403 nbargs++;
10404 if (CUR == ')') break;
10405 if (CUR != ',') {
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020010406 xmlFree(name);
10407 xmlFree(prefix);
Daniel Veillard71f9d732003-01-14 16:07:16 +000010408 XP_ERROR(XPATH_EXPR_ERROR);
10409 }
10410 NEXT;
10411 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010412 }
Owen Taylor3473f882001-02-23 17:55:21 +000010413 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070010414 if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
10415 xmlFree(prefix);
10416 xmlFree(name);
10417 }
Owen Taylor3473f882001-02-23 17:55:21 +000010418 NEXT;
10419 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010420}
10421
10422/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010423 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010424 * @ctxt: the XPath Parser context
10425 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010426 * [15] PrimaryExpr ::= VariableReference
Owen Taylor3473f882001-02-23 17:55:21 +000010427 * | '(' Expr ')'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010428 * | Literal
10429 * | Number
10430 * | FunctionCall
Owen Taylor3473f882001-02-23 17:55:21 +000010431 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010432 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010433 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010434static void
10435xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010436 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010437 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010438 else if (CUR == '(') {
10439 NEXT;
10440 SKIP_BLANKS;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010441 xmlXPathCompileExpr(ctxt, 1);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010442 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000010443 if (CUR != ')') {
10444 XP_ERROR(XPATH_EXPR_ERROR);
10445 }
10446 NEXT;
10447 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010448 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010449 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010450 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010451 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010452 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010453 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010454 }
10455 SKIP_BLANKS;
10456}
10457
10458/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010459 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010460 * @ctxt: the XPath Parser context
10461 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010462 * [20] FilterExpr ::= PrimaryExpr
10463 * | FilterExpr Predicate
Owen Taylor3473f882001-02-23 17:55:21 +000010464 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010465 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010466 * Square brackets are used to filter expressions in the same way that
10467 * they are used in location paths. It is an error if the expression to
10468 * be filtered does not evaluate to a node-set. The context node list
10469 * used for evaluating the expression in square brackets is the node-set
10470 * to be filtered listed in document order.
10471 */
10472
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010473static void
10474xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10475 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010476 CHECK_ERROR;
10477 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010478
Owen Taylor3473f882001-02-23 17:55:21 +000010479 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010480 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +000010481 SKIP_BLANKS;
10482 }
10483
Daniel Veillard45490ae2008-07-29 09:13:19 +000010484
Owen Taylor3473f882001-02-23 17:55:21 +000010485}
10486
10487/**
10488 * xmlXPathScanName:
10489 * @ctxt: the XPath Parser context
10490 *
10491 * Trickery: parse an XML name but without consuming the input flow
10492 * Needed to avoid insanity in the parser state.
10493 *
10494 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10495 * CombiningChar | Extender
10496 *
10497 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10498 *
10499 * [6] Names ::= Name (S Name)*
10500 *
10501 * Returns the Name parsed or NULL
10502 */
10503
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010504static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +000010505xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +000010506 int len = 0, l;
10507 int c;
Daniel Veillard03226812004-11-01 14:55:21 +000010508 const xmlChar *cur;
10509 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +000010510
Daniel Veillard03226812004-11-01 14:55:21 +000010511 cur = ctxt->cur;
10512
10513 c = CUR_CHAR(l);
10514 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10515 (!IS_LETTER(c) && (c != '_') &&
10516 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010517 return(NULL);
10518 }
10519
Daniel Veillard03226812004-11-01 14:55:21 +000010520 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10521 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10522 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000010523 (c == '_') || (c == ':') ||
Daniel Veillard03226812004-11-01 14:55:21 +000010524 (IS_COMBINING(c)) ||
10525 (IS_EXTENDER(c)))) {
10526 len += l;
10527 NEXTL(l);
10528 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +000010529 }
Daniel Veillard03226812004-11-01 14:55:21 +000010530 ret = xmlStrndup(cur, ctxt->cur - cur);
10531 ctxt->cur = cur;
10532 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +000010533}
10534
10535/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010536 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010537 * @ctxt: the XPath Parser context
10538 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010539 * [19] PathExpr ::= LocationPath
10540 * | FilterExpr
10541 * | FilterExpr '/' RelativeLocationPath
10542 * | FilterExpr '//' RelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000010543 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010544 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010545 * The / operator and // operators combine an arbitrary expression
10546 * and a relative location path. It is an error if the expression
10547 * does not evaluate to a node-set.
10548 * The / operator does composition in the same way as when / is
10549 * used in a location path. As in location paths, // is short for
10550 * /descendant-or-self::node()/.
10551 */
10552
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010553static void
10554xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010555 int lc = 1; /* Should we branch to LocationPath ? */
10556 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10557
10558 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010559 if ((CUR == '$') || (CUR == '(') ||
10560 (IS_ASCII_DIGIT(CUR)) ||
William M. Brackd1757ab2004-10-02 22:07:48 +000010561 (CUR == '\'') || (CUR == '"') ||
10562 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010563 lc = 0;
10564 } else if (CUR == '*') {
10565 /* relative or absolute location path */
10566 lc = 1;
10567 } else if (CUR == '/') {
10568 /* relative or absolute location path */
10569 lc = 1;
10570 } else if (CUR == '@') {
10571 /* relative abbreviated attribute location path */
10572 lc = 1;
10573 } else if (CUR == '.') {
10574 /* relative abbreviated attribute location path */
10575 lc = 1;
10576 } else {
10577 /*
10578 * Problem is finding if we have a name here whether it's:
10579 * - a nodetype
10580 * - a function call in which case it's followed by '('
10581 * - an axis in which case it's followed by ':'
10582 * - a element name
10583 * We do an a priori analysis here rather than having to
10584 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +000010585 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +000010586 * read/write/debug.
10587 */
10588 SKIP_BLANKS;
10589 name = xmlXPathScanName(ctxt);
10590 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10591#ifdef DEBUG_STEP
10592 xmlGenericError(xmlGenericErrorContext,
10593 "PathExpr: Axis\n");
10594#endif
10595 lc = 1;
10596 xmlFree(name);
10597 } else if (name != NULL) {
10598 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +000010599
Daniel Veillard45490ae2008-07-29 09:13:19 +000010600
Owen Taylor3473f882001-02-23 17:55:21 +000010601 while (NXT(len) != 0) {
10602 if (NXT(len) == '/') {
10603 /* element name */
10604#ifdef DEBUG_STEP
10605 xmlGenericError(xmlGenericErrorContext,
10606 "PathExpr: AbbrRelLocation\n");
10607#endif
10608 lc = 1;
10609 break;
William M. Brack76e95df2003-10-18 16:20:14 +000010610 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +000010611 /* ignore blanks */
10612 ;
Owen Taylor3473f882001-02-23 17:55:21 +000010613 } else if (NXT(len) == ':') {
10614#ifdef DEBUG_STEP
10615 xmlGenericError(xmlGenericErrorContext,
10616 "PathExpr: AbbrRelLocation\n");
10617#endif
10618 lc = 1;
10619 break;
10620 } else if ((NXT(len) == '(')) {
Brian C. Young01c35762017-04-03 12:46:02 -070010621 /* Node Type or Function */
Owen Taylor3473f882001-02-23 17:55:21 +000010622 if (xmlXPathIsNodeType(name)) {
10623#ifdef DEBUG_STEP
10624 xmlGenericError(xmlGenericErrorContext,
10625 "PathExpr: Type search\n");
10626#endif
10627 lc = 1;
Brian C. Young01c35762017-04-03 12:46:02 -070010628#ifdef LIBXML_XPTR_ENABLED
10629 } else if (ctxt->xptr &&
10630 xmlStrEqual(name, BAD_CAST "range-to")) {
10631 lc = 1;
10632#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010633 } else {
10634#ifdef DEBUG_STEP
10635 xmlGenericError(xmlGenericErrorContext,
10636 "PathExpr: function call\n");
10637#endif
10638 lc = 0;
10639 }
10640 break;
10641 } else if ((NXT(len) == '[')) {
10642 /* element name */
10643#ifdef DEBUG_STEP
10644 xmlGenericError(xmlGenericErrorContext,
10645 "PathExpr: AbbrRelLocation\n");
10646#endif
10647 lc = 1;
10648 break;
10649 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10650 (NXT(len) == '=')) {
10651 lc = 1;
10652 break;
10653 } else {
10654 lc = 1;
10655 break;
10656 }
10657 len++;
10658 }
10659 if (NXT(len) == 0) {
10660#ifdef DEBUG_STEP
10661 xmlGenericError(xmlGenericErrorContext,
10662 "PathExpr: AbbrRelLocation\n");
10663#endif
10664 /* element name */
10665 lc = 1;
10666 }
10667 xmlFree(name);
10668 } else {
William M. Brack08171912003-12-29 02:52:11 +000010669 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +000010670 XP_ERROR(XPATH_EXPR_ERROR);
10671 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000010672 }
Owen Taylor3473f882001-02-23 17:55:21 +000010673
10674 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010675 if (CUR == '/') {
10676 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10677 } else {
10678 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010679 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010680 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010681 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010682 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010683 CHECK_ERROR;
10684 if ((CUR == '/') && (NXT(1) == '/')) {
10685 SKIP(2);
10686 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010687
10688 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10689 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010690
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010691 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010692 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010693 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010694 }
10695 }
10696 SKIP_BLANKS;
10697}
10698
10699/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010700 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010701 * @ctxt: the XPath Parser context
10702 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010703 * [18] UnionExpr ::= PathExpr
10704 * | UnionExpr '|' PathExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010705 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010706 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010707 */
10708
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010709static void
10710xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10711 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010712 CHECK_ERROR;
10713 SKIP_BLANKS;
10714 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010715 int op1 = ctxt->comp->last;
10716 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010717
10718 NEXT;
10719 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010720 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010721
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010722 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10723
Owen Taylor3473f882001-02-23 17:55:21 +000010724 SKIP_BLANKS;
10725 }
Owen Taylor3473f882001-02-23 17:55:21 +000010726}
10727
10728/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010729 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010730 * @ctxt: the XPath Parser context
10731 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010732 * [27] UnaryExpr ::= UnionExpr
10733 * | '-' UnaryExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010734 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010735 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010736 */
10737
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010738static void
10739xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010740 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010741 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010742
10743 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +000010744 while (CUR == '-') {
10745 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010746 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010747 NEXT;
10748 SKIP_BLANKS;
10749 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010750
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010751 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010752 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010753 if (found) {
10754 if (minus)
10755 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10756 else
10757 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010758 }
10759}
10760
10761/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010762 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010763 * @ctxt: the XPath Parser context
10764 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010765 * [26] MultiplicativeExpr ::= UnaryExpr
10766 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10767 * | MultiplicativeExpr 'div' UnaryExpr
10768 * | MultiplicativeExpr 'mod' UnaryExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010769 * [34] MultiplyOperator ::= '*'
10770 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010771 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010772 */
10773
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010774static void
10775xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10776 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010777 CHECK_ERROR;
10778 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010779 while ((CUR == '*') ||
Owen Taylor3473f882001-02-23 17:55:21 +000010780 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10781 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10782 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010783 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010784
10785 if (CUR == '*') {
10786 op = 0;
10787 NEXT;
10788 } else if (CUR == 'd') {
10789 op = 1;
10790 SKIP(3);
10791 } else if (CUR == 'm') {
10792 op = 2;
10793 SKIP(3);
10794 }
10795 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010796 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010797 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010798 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010799 SKIP_BLANKS;
10800 }
10801}
10802
10803/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010804 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010805 * @ctxt: the XPath Parser context
10806 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010807 * [25] AdditiveExpr ::= MultiplicativeExpr
10808 * | AdditiveExpr '+' MultiplicativeExpr
10809 * | AdditiveExpr '-' MultiplicativeExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010810 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010811 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010812 */
10813
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010814static void
10815xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010816
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010817 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010818 CHECK_ERROR;
10819 SKIP_BLANKS;
10820 while ((CUR == '+') || (CUR == '-')) {
10821 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010822 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010823
10824 if (CUR == '+') plus = 1;
10825 else plus = 0;
10826 NEXT;
10827 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010828 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010829 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010830 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010831 SKIP_BLANKS;
10832 }
10833}
10834
10835/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010836 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010837 * @ctxt: the XPath Parser context
10838 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010839 * [24] RelationalExpr ::= AdditiveExpr
10840 * | RelationalExpr '<' AdditiveExpr
10841 * | RelationalExpr '>' AdditiveExpr
10842 * | RelationalExpr '<=' AdditiveExpr
10843 * | RelationalExpr '>=' AdditiveExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010844 *
10845 * A <= B > C is allowed ? Answer from James, yes with
10846 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10847 * which is basically what got implemented.
10848 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010849 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +000010850 * on the stack
10851 */
10852
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010853static void
10854xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10855 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010856 CHECK_ERROR;
10857 SKIP_BLANKS;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070010858 while ((CUR == '<') || (CUR == '>')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010859 int inf, strict;
10860 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010861
10862 if (CUR == '<') inf = 1;
10863 else inf = 0;
10864 if (NXT(1) == '=') strict = 0;
10865 else strict = 1;
10866 NEXT;
10867 if (!strict) NEXT;
10868 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010869 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010870 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010871 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +000010872 SKIP_BLANKS;
10873 }
10874}
10875
10876/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010877 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010878 * @ctxt: the XPath Parser context
10879 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010880 * [23] EqualityExpr ::= RelationalExpr
10881 * | EqualityExpr '=' RelationalExpr
10882 * | EqualityExpr '!=' RelationalExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010883 *
10884 * A != B != C is allowed ? Answer from James, yes with
10885 * (RelationalExpr = RelationalExpr) = RelationalExpr
10886 * (RelationalExpr != RelationalExpr) != RelationalExpr
10887 * which is basically what got implemented.
10888 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010889 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010890 *
10891 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010892static void
10893xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10894 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010895 CHECK_ERROR;
10896 SKIP_BLANKS;
10897 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010898 int eq;
10899 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010900
10901 if (CUR == '=') eq = 1;
10902 else eq = 0;
10903 NEXT;
10904 if (!eq) NEXT;
10905 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010906 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010907 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010908 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010909 SKIP_BLANKS;
10910 }
10911}
10912
10913/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010914 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010915 * @ctxt: the XPath Parser context
10916 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010917 * [22] AndExpr ::= EqualityExpr
10918 * | AndExpr 'and' EqualityExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010919 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010920 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010921 *
10922 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010923static void
10924xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10925 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010926 CHECK_ERROR;
10927 SKIP_BLANKS;
10928 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010929 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010930 SKIP(3);
10931 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010932 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010933 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010934 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010935 SKIP_BLANKS;
10936 }
10937}
10938
10939/**
Daniel Veillard591b4be2003-02-09 23:33:36 +000010940 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010941 * @ctxt: the XPath Parser context
10942 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010943 * [14] Expr ::= OrExpr
10944 * [21] OrExpr ::= AndExpr
10945 * | OrExpr 'or' AndExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010946 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010947 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +000010948 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010949static void
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010950xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -070010951 xmlXPathContextPtr xpctxt = ctxt->context;
10952
10953 if (xpctxt != NULL) {
Haibo Huangf0a546b2020-09-01 20:28:19 -070010954 if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
Haibo Huangcfd91dc2020-07-30 23:01:33 -070010955 XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
Haibo Huangf0a546b2020-09-01 20:28:19 -070010956 /*
10957 * Parsing a single '(' pushes about 10 functions on the call stack
10958 * before recursing!
10959 */
10960 xpctxt->depth += 10;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070010961 }
10962
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010963 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010964 CHECK_ERROR;
10965 SKIP_BLANKS;
10966 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010967 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010968 SKIP(2);
10969 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010970 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010971 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010972 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010973 SKIP_BLANKS;
10974 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010975 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010976 /* more ops could be optimized too */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010977 /*
10978 * This is the main place to eliminate sorting for
10979 * operations which don't require a sorted node-set.
10980 * E.g. count().
10981 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010982 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10983 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070010984
10985 if (xpctxt != NULL)
Elliott Hughes60f5c162021-08-20 17:09:52 -070010986 xpctxt->depth -= 10;
Owen Taylor3473f882001-02-23 17:55:21 +000010987}
10988
10989/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010990 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +000010991 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010992 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +000010993 *
10994 * [8] Predicate ::= '[' PredicateExpr ']'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010995 * [9] PredicateExpr ::= Expr
Owen Taylor3473f882001-02-23 17:55:21 +000010996 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010997 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +000010998 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010999static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011000xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011001 int op1 = ctxt->comp->last;
11002
11003 SKIP_BLANKS;
11004 if (CUR != '[') {
11005 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11006 }
11007 NEXT;
11008 SKIP_BLANKS;
11009
11010 ctxt->comp->last = -1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011011 /*
11012 * This call to xmlXPathCompileExpr() will deactivate sorting
11013 * of the predicate result.
11014 * TODO: Sorting is still activated for filters, since I'm not
11015 * sure if needed. Normally sorting should not be needed, since
11016 * a filter can only diminish the number of items in a sequence,
11017 * but won't change its order; so if the initial sequence is sorted,
11018 * subsequent sorting is not needed.
11019 */
11020 if (! filter)
11021 xmlXPathCompileExpr(ctxt, 0);
11022 else
11023 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011024 CHECK_ERROR;
11025
11026 if (CUR != ']') {
11027 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11028 }
11029
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011030 if (filter)
11031 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11032 else
11033 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011034
11035 NEXT;
11036 SKIP_BLANKS;
11037}
11038
11039/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011040 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +000011041 * @ctxt: the XPath Parser context
11042 * @test: pointer to a xmlXPathTestVal
11043 * @type: pointer to a xmlXPathTypeVal
11044 * @prefix: placeholder for a possible name prefix
11045 *
11046 * [7] NodeTest ::= NameTest
11047 * | NodeType '(' ')'
11048 * | 'processing-instruction' '(' Literal ')'
11049 *
11050 * [37] NameTest ::= '*'
11051 * | NCName ':' '*'
11052 * | QName
11053 * [38] NodeType ::= 'comment'
11054 * | 'text'
11055 * | 'processing-instruction'
11056 * | 'node'
11057 *
William M. Brack08171912003-12-29 02:52:11 +000011058 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +000011059 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011060static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011061xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
Haibo Huangcfd91dc2020-07-30 23:01:33 -070011062 xmlXPathTypeVal *type, xmlChar **prefix,
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011063 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +000011064 int blanks;
11065
11066 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11067 STRANGE;
11068 return(NULL);
11069 }
William M. Brack78637da2003-07-31 14:47:38 +000011070 *type = (xmlXPathTypeVal) 0;
11071 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011072 *prefix = NULL;
11073 SKIP_BLANKS;
11074
11075 if ((name == NULL) && (CUR == '*')) {
11076 /*
11077 * All elements
11078 */
11079 NEXT;
11080 *test = NODE_TEST_ALL;
11081 return(NULL);
11082 }
11083
11084 if (name == NULL)
11085 name = xmlXPathParseNCName(ctxt);
11086 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011087 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011088 }
11089
William M. Brack76e95df2003-10-18 16:20:14 +000011090 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +000011091 SKIP_BLANKS;
11092 if (CUR == '(') {
11093 NEXT;
11094 /*
11095 * NodeType or PI search
11096 */
11097 if (xmlStrEqual(name, BAD_CAST "comment"))
11098 *type = NODE_TYPE_COMMENT;
11099 else if (xmlStrEqual(name, BAD_CAST "node"))
11100 *type = NODE_TYPE_NODE;
11101 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11102 *type = NODE_TYPE_PI;
11103 else if (xmlStrEqual(name, BAD_CAST "text"))
11104 *type = NODE_TYPE_TEXT;
11105 else {
11106 if (name != NULL)
11107 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000011108 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011109 }
11110
11111 *test = NODE_TEST_TYPE;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011112
Owen Taylor3473f882001-02-23 17:55:21 +000011113 SKIP_BLANKS;
11114 if (*type == NODE_TYPE_PI) {
11115 /*
11116 * Specific case: search a PI by name.
11117 */
Owen Taylor3473f882001-02-23 17:55:21 +000011118 if (name != NULL)
11119 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +000011120 name = NULL;
11121 if (CUR != ')') {
11122 name = xmlXPathParseLiteral(ctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000011123 CHECK_ERROR NULL;
Daniel Veillarded23b7d2002-05-27 12:16:02 +000011124 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +000011125 SKIP_BLANKS;
11126 }
Owen Taylor3473f882001-02-23 17:55:21 +000011127 }
11128 if (CUR != ')') {
11129 if (name != NULL)
11130 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000011131 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011132 }
11133 NEXT;
11134 return(name);
11135 }
11136 *test = NODE_TEST_NAME;
11137 if ((!blanks) && (CUR == ':')) {
11138 NEXT;
11139
11140 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011141 * Since currently the parser context don't have a
11142 * namespace list associated:
11143 * The namespace name for this prefix can be computed
11144 * only at evaluation time. The compilation is done
11145 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +000011146 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011147#if 0
Owen Taylor3473f882001-02-23 17:55:21 +000011148 *prefix = xmlXPathNsLookup(ctxt->context, name);
11149 if (name != NULL)
11150 xmlFree(name);
11151 if (*prefix == NULL) {
11152 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11153 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011154#else
11155 *prefix = name;
11156#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011157
11158 if (CUR == '*') {
11159 /*
11160 * All elements
11161 */
11162 NEXT;
11163 *test = NODE_TEST_ALL;
11164 return(NULL);
11165 }
11166
11167 name = xmlXPathParseNCName(ctxt);
11168 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011169 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011170 }
11171 }
11172 return(name);
11173}
11174
11175/**
11176 * xmlXPathIsAxisName:
11177 * @name: a preparsed name token
11178 *
11179 * [6] AxisName ::= 'ancestor'
11180 * | 'ancestor-or-self'
11181 * | 'attribute'
11182 * | 'child'
11183 * | 'descendant'
11184 * | 'descendant-or-self'
11185 * | 'following'
11186 * | 'following-sibling'
11187 * | 'namespace'
11188 * | 'parent'
11189 * | 'preceding'
11190 * | 'preceding-sibling'
11191 * | 'self'
11192 *
11193 * Returns the axis or 0
11194 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011195static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +000011196xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +000011197 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011198 switch (name[0]) {
11199 case 'a':
11200 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11201 ret = AXIS_ANCESTOR;
11202 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11203 ret = AXIS_ANCESTOR_OR_SELF;
11204 if (xmlStrEqual(name, BAD_CAST "attribute"))
11205 ret = AXIS_ATTRIBUTE;
11206 break;
11207 case 'c':
11208 if (xmlStrEqual(name, BAD_CAST "child"))
11209 ret = AXIS_CHILD;
11210 break;
11211 case 'd':
11212 if (xmlStrEqual(name, BAD_CAST "descendant"))
11213 ret = AXIS_DESCENDANT;
11214 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11215 ret = AXIS_DESCENDANT_OR_SELF;
11216 break;
11217 case 'f':
11218 if (xmlStrEqual(name, BAD_CAST "following"))
11219 ret = AXIS_FOLLOWING;
11220 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11221 ret = AXIS_FOLLOWING_SIBLING;
11222 break;
11223 case 'n':
11224 if (xmlStrEqual(name, BAD_CAST "namespace"))
11225 ret = AXIS_NAMESPACE;
11226 break;
11227 case 'p':
11228 if (xmlStrEqual(name, BAD_CAST "parent"))
11229 ret = AXIS_PARENT;
11230 if (xmlStrEqual(name, BAD_CAST "preceding"))
11231 ret = AXIS_PRECEDING;
11232 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11233 ret = AXIS_PRECEDING_SIBLING;
11234 break;
11235 case 's':
11236 if (xmlStrEqual(name, BAD_CAST "self"))
11237 ret = AXIS_SELF;
11238 break;
11239 }
11240 return(ret);
11241}
11242
11243/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011244 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +000011245 * @ctxt: the XPath Parser context
11246 *
11247 * [4] Step ::= AxisSpecifier NodeTest Predicate*
Daniel Veillard45490ae2008-07-29 09:13:19 +000011248 * | AbbreviatedStep
Owen Taylor3473f882001-02-23 17:55:21 +000011249 *
11250 * [12] AbbreviatedStep ::= '.' | '..'
11251 *
11252 * [5] AxisSpecifier ::= AxisName '::'
11253 * | AbbreviatedAxisSpecifier
11254 *
11255 * [13] AbbreviatedAxisSpecifier ::= '@'?
11256 *
11257 * Modified for XPtr range support as:
11258 *
11259 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11260 * | AbbreviatedStep
11261 * | 'range-to' '(' Expr ')' Predicate*
11262 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011263 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +000011264 * A location step of . is short for self::node(). This is
11265 * particularly useful in conjunction with //. For example, the
11266 * location path .//para is short for
11267 * self::node()/descendant-or-self::node()/child::para
11268 * and so will select all para descendant elements of the context
11269 * node.
11270 * Similarly, a location step of .. is short for parent::node().
11271 * For example, ../title is short for parent::node()/child::title
11272 * and so will select the title children of the parent of the context
11273 * node.
11274 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011275static void
11276xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011277#ifdef LIBXML_XPTR_ENABLED
11278 int rangeto = 0;
11279 int op2 = -1;
11280#endif
11281
Owen Taylor3473f882001-02-23 17:55:21 +000011282 SKIP_BLANKS;
11283 if ((CUR == '.') && (NXT(1) == '.')) {
11284 SKIP(2);
11285 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011286 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11287 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011288 } else if (CUR == '.') {
11289 NEXT;
11290 SKIP_BLANKS;
11291 } else {
11292 xmlChar *name = NULL;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070011293 xmlChar *prefix = NULL;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011294 xmlXPathTestVal test = (xmlXPathTestVal) 0;
William M. Brack78637da2003-07-31 14:47:38 +000011295 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011296 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011297 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +000011298
11299 /*
11300 * The modification needed for XPointer change to the production
11301 */
11302#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011303 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +000011304 name = xmlXPathParseNCName(ctxt);
11305 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011306 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000011307 xmlFree(name);
11308 SKIP_BLANKS;
11309 if (CUR != '(') {
11310 XP_ERROR(XPATH_EXPR_ERROR);
11311 }
11312 NEXT;
11313 SKIP_BLANKS;
11314
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011315 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011316 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +000011317 CHECK_ERROR;
11318
11319 SKIP_BLANKS;
11320 if (CUR != ')') {
11321 XP_ERROR(XPATH_EXPR_ERROR);
11322 }
11323 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011324 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000011325 goto eval_predicates;
11326 }
11327 }
11328#endif
Daniel Veillard2156a562001-04-28 12:24:34 +000011329 if (CUR == '*') {
11330 axis = AXIS_CHILD;
11331 } else {
11332 if (name == NULL)
11333 name = xmlXPathParseNCName(ctxt);
11334 if (name != NULL) {
11335 axis = xmlXPathIsAxisName(name);
11336 if (axis != 0) {
11337 SKIP_BLANKS;
11338 if ((CUR == ':') && (NXT(1) == ':')) {
11339 SKIP(2);
11340 xmlFree(name);
11341 name = NULL;
11342 } else {
11343 /* an element name can conflict with an axis one :-\ */
11344 axis = AXIS_CHILD;
11345 }
Owen Taylor3473f882001-02-23 17:55:21 +000011346 } else {
Owen Taylor3473f882001-02-23 17:55:21 +000011347 axis = AXIS_CHILD;
11348 }
Daniel Veillard2156a562001-04-28 12:24:34 +000011349 } else if (CUR == '@') {
11350 NEXT;
11351 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +000011352 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +000011353 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +000011354 }
Owen Taylor3473f882001-02-23 17:55:21 +000011355 }
11356
Daniel Veillard2f3523f2010-10-15 18:30:29 +020011357 if (ctxt->error != XPATH_EXPRESSION_OK) {
11358 xmlFree(name);
11359 return;
11360 }
Owen Taylor3473f882001-02-23 17:55:21 +000011361
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011362 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +000011363 if (test == 0)
11364 return;
11365
Daniel Veillarded6c5492005-07-23 15:00:22 +000011366 if ((prefix != NULL) && (ctxt->context != NULL) &&
11367 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11368 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11369 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11370 }
11371 }
Owen Taylor3473f882001-02-23 17:55:21 +000011372#ifdef DEBUG_STEP
11373 xmlGenericError(xmlGenericErrorContext,
11374 "Basis : computing new set\n");
11375#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011376
Owen Taylor3473f882001-02-23 17:55:21 +000011377#ifdef DEBUG_STEP
11378 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011379 if (ctxt->value == NULL)
11380 xmlGenericError(xmlGenericErrorContext, "no value\n");
11381 else if (ctxt->value->nodesetval == NULL)
11382 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11383 else
11384 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011385#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011386
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011387#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +000011388eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011389#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011390 op1 = ctxt->comp->last;
11391 ctxt->comp->last = -1;
11392
Owen Taylor3473f882001-02-23 17:55:21 +000011393 SKIP_BLANKS;
11394 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011395 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011396 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011397
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011398#ifdef LIBXML_XPTR_ENABLED
11399 if (rangeto) {
11400 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11401 } else
11402#endif
Haibo Huangcfd91dc2020-07-30 23:01:33 -070011403 if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11404 test, type, (void *)prefix, (void *)name) == -1) {
11405 xmlFree(prefix);
11406 xmlFree(name);
11407 }
Owen Taylor3473f882001-02-23 17:55:21 +000011408 }
11409#ifdef DEBUG_STEP
11410 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011411 if (ctxt->value == NULL)
11412 xmlGenericError(xmlGenericErrorContext, "no value\n");
11413 else if (ctxt->value->nodesetval == NULL)
11414 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11415 else
11416 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11417 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011418#endif
11419}
11420
11421/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011422 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011423 * @ctxt: the XPath Parser context
11424 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011425 * [3] RelativeLocationPath ::= Step
11426 * | RelativeLocationPath '/' Step
11427 * | AbbreviatedRelativeLocationPath
11428 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
Owen Taylor3473f882001-02-23 17:55:21 +000011429 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011430 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +000011431 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011432static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011433xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011434(xmlXPathParserContextPtr ctxt) {
11435 SKIP_BLANKS;
11436 if ((CUR == '/') && (NXT(1) == '/')) {
11437 SKIP(2);
11438 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011439 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11440 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011441 } else if (CUR == '/') {
11442 NEXT;
11443 SKIP_BLANKS;
11444 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011445 xmlXPathCompStep(ctxt);
Martin729601f2009-10-12 22:42:26 +020011446 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000011447 SKIP_BLANKS;
11448 while (CUR == '/') {
11449 if ((CUR == '/') && (NXT(1) == '/')) {
11450 SKIP(2);
11451 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011452 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +000011453 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011454 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011455 } else if (CUR == '/') {
11456 NEXT;
11457 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011458 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011459 }
11460 SKIP_BLANKS;
11461 }
11462}
11463
11464/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011465 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011466 * @ctxt: the XPath Parser context
11467 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011468 * [1] LocationPath ::= RelativeLocationPath
11469 * | AbsoluteLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011470 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
Daniel Veillard45490ae2008-07-29 09:13:19 +000011471 * | AbbreviatedAbsoluteLocationPath
11472 * [10] AbbreviatedAbsoluteLocationPath ::=
11473 * '//' RelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011474 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011475 * Compile a location path
11476 *
Owen Taylor3473f882001-02-23 17:55:21 +000011477 * // is short for /descendant-or-self::node()/. For example,
11478 * //para is short for /descendant-or-self::node()/child::para and
11479 * so will select any para element in the document (even a para element
11480 * that is a document element will be selected by //para since the
11481 * document element node is a child of the root node); div//para is
11482 * short for div/descendant-or-self::node()/child::para and so will
11483 * select all para descendants of div children.
11484 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011485static void
11486xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000011487 SKIP_BLANKS;
11488 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011489 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011490 } else {
11491 while (CUR == '/') {
11492 if ((CUR == '/') && (NXT(1) == '/')) {
11493 SKIP(2);
11494 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011495 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11496 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011497 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011498 } else if (CUR == '/') {
11499 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +000011500 SKIP_BLANKS;
11501 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +000011502 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +000011503 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011504 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011505 }
Martin729601f2009-10-12 22:42:26 +020011506 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000011507 }
11508 }
11509}
11510
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011511/************************************************************************
11512 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011513 * XPath precompiled expression evaluation *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011514 * *
11515 ************************************************************************/
11516
Daniel Veillardf06307e2001-07-03 10:35:50 +000011517static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011518xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11519
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011520#ifdef DEBUG_STEP
11521static void
Daniel Veillard074f37e2008-09-01 13:38:22 +000011522xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011523 int nbNodes)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011524{
Daniel Veillardf06307e2001-07-03 10:35:50 +000011525 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillard074f37e2008-09-01 13:38:22 +000011526 switch (op->value) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011527 case AXIS_ANCESTOR:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011528 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011529 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011530 case AXIS_ANCESTOR_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011531 xmlGenericError(xmlGenericErrorContext,
11532 "axis 'ancestors-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011533 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011534 case AXIS_ATTRIBUTE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011535 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011536 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011537 case AXIS_CHILD:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011538 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011539 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011540 case AXIS_DESCENDANT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011541 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011542 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011543 case AXIS_DESCENDANT_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011544 xmlGenericError(xmlGenericErrorContext,
11545 "axis 'descendant-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011546 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011547 case AXIS_FOLLOWING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011548 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011549 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011550 case AXIS_FOLLOWING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011551 xmlGenericError(xmlGenericErrorContext,
11552 "axis 'following-siblings' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011553 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011554 case AXIS_NAMESPACE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011555 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011556 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011557 case AXIS_PARENT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011558 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011559 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011560 case AXIS_PRECEDING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011561 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011562 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011563 case AXIS_PRECEDING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011564 xmlGenericError(xmlGenericErrorContext,
11565 "axis 'preceding-sibling' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011566 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011567 case AXIS_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011568 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011569 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011570 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011571 xmlGenericError(xmlGenericErrorContext,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011572 " context contains %d nodes\n", nbNodes);
Daniel Veillard074f37e2008-09-01 13:38:22 +000011573 switch (op->value2) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011574 case NODE_TEST_NONE:
11575 xmlGenericError(xmlGenericErrorContext,
11576 " searching for none !!!\n");
11577 break;
11578 case NODE_TEST_TYPE:
11579 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011580 " searching for type %d\n", op->value3);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011581 break;
11582 case NODE_TEST_PI:
11583 xmlGenericError(xmlGenericErrorContext,
11584 " searching for PI !!!\n");
11585 break;
11586 case NODE_TEST_ALL:
11587 xmlGenericError(xmlGenericErrorContext,
11588 " searching for *\n");
11589 break;
11590 case NODE_TEST_NS:
11591 xmlGenericError(xmlGenericErrorContext,
11592 " searching for namespace %s\n",
Daniel Veillard074f37e2008-09-01 13:38:22 +000011593 op->value5);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011594 break;
11595 case NODE_TEST_NAME:
11596 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011597 " searching for name %s\n", op->value5);
11598 if (op->value4)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011599 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011600 " with namespace %s\n", op->value4);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011601 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011602 }
11603 xmlGenericError(xmlGenericErrorContext, "Testing : ");
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011604}
11605#endif /* DEBUG_STEP */
11606
Haibo Huangcfd91dc2020-07-30 23:01:33 -070011607/**
11608 * xmlXPathNodeSetFilter:
11609 * @ctxt: the XPath Parser context
11610 * @set: the node set to filter
11611 * @filterOpIndex: the index of the predicate/filter op
11612 * @minPos: minimum position in the filtered set (1-based)
11613 * @maxPos: maximum position in the filtered set (1-based)
11614 * @hasNsNodes: true if the node set may contain namespace nodes
11615 *
11616 * Filter a node set, keeping only nodes for which the predicate expression
11617 * matches. Afterwards, keep only nodes between minPos and maxPos in the
11618 * filtered result.
11619 */
11620static void
11621xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
11622 xmlNodeSetPtr set,
11623 int filterOpIndex,
11624 int minPos, int maxPos,
11625 int hasNsNodes)
11626{
11627 xmlXPathContextPtr xpctxt;
11628 xmlNodePtr oldnode;
11629 xmlDocPtr olddoc;
11630 xmlXPathStepOpPtr filterOp;
11631 int oldcs, oldpp;
11632 int i, j, pos;
11633
11634 if ((set == NULL) || (set->nodeNr == 0))
11635 return;
11636
11637 /*
11638 * Check if the node set contains a sufficient number of nodes for
11639 * the requested range.
11640 */
11641 if (set->nodeNr < minPos) {
11642 xmlXPathNodeSetClear(set, hasNsNodes);
11643 return;
11644 }
11645
11646 xpctxt = ctxt->context;
11647 oldnode = xpctxt->node;
11648 olddoc = xpctxt->doc;
11649 oldcs = xpctxt->contextSize;
11650 oldpp = xpctxt->proximityPosition;
11651 filterOp = &ctxt->comp->steps[filterOpIndex];
11652
11653 xpctxt->contextSize = set->nodeNr;
11654
11655 for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
11656 xmlNodePtr node = set->nodeTab[i];
11657 int res;
11658
11659 xpctxt->node = node;
11660 xpctxt->proximityPosition = i + 1;
11661
11662 /*
11663 * Also set the xpath document in case things like
11664 * key() are evaluated in the predicate.
11665 *
11666 * TODO: Get real doc for namespace nodes.
11667 */
11668 if ((node->type != XML_NAMESPACE_DECL) &&
11669 (node->doc != NULL))
11670 xpctxt->doc = node->doc;
11671
11672 res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11673
11674 if (ctxt->error != XPATH_EXPRESSION_OK)
Haibo Huangd23e46c2020-10-28 22:26:09 -070011675 break;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070011676 if (res < 0) {
11677 /* Shouldn't happen */
11678 xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
Haibo Huangd23e46c2020-10-28 22:26:09 -070011679 break;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070011680 }
11681
11682 if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11683 if (i != j) {
11684 set->nodeTab[j] = node;
11685 set->nodeTab[i] = NULL;
11686 }
11687
11688 j += 1;
11689 } else {
11690 /* Remove the entry from the initial node set. */
11691 set->nodeTab[i] = NULL;
11692 if (node->type == XML_NAMESPACE_DECL)
11693 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11694 }
11695
11696 if (res != 0) {
11697 if (pos == maxPos) {
Haibo Huangd23e46c2020-10-28 22:26:09 -070011698 i += 1;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070011699 break;
11700 }
11701
11702 pos += 1;
11703 }
11704 }
11705
Haibo Huangd23e46c2020-10-28 22:26:09 -070011706 /* Free remaining nodes. */
11707 if (hasNsNodes) {
11708 for (; i < set->nodeNr; i++) {
11709 xmlNodePtr node = set->nodeTab[i];
11710 if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
11711 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11712 }
11713 }
11714
Haibo Huangcfd91dc2020-07-30 23:01:33 -070011715 set->nodeNr = j;
11716
11717 /* If too many elements were removed, shrink table to preserve memory. */
11718 if ((set->nodeMax > XML_NODESET_DEFAULT) &&
11719 (set->nodeNr < set->nodeMax / 2)) {
11720 xmlNodePtr *tmp;
11721 int nodeMax = set->nodeNr;
11722
11723 if (nodeMax < XML_NODESET_DEFAULT)
11724 nodeMax = XML_NODESET_DEFAULT;
11725 tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
11726 nodeMax * sizeof(xmlNodePtr));
11727 if (tmp == NULL) {
11728 xmlXPathPErrMemory(ctxt, "shrinking nodeset\n");
11729 } else {
11730 set->nodeTab = tmp;
11731 set->nodeMax = nodeMax;
11732 }
11733 }
11734
Haibo Huangcfd91dc2020-07-30 23:01:33 -070011735 xpctxt->node = oldnode;
11736 xpctxt->doc = olddoc;
11737 xpctxt->contextSize = oldcs;
11738 xpctxt->proximityPosition = oldpp;
11739}
11740
11741#ifdef LIBXML_XPTR_ENABLED
11742/**
11743 * xmlXPathLocationSetFilter:
11744 * @ctxt: the XPath Parser context
11745 * @locset: the location set to filter
11746 * @filterOpIndex: the index of the predicate/filter op
11747 * @minPos: minimum position in the filtered set (1-based)
11748 * @maxPos: maximum position in the filtered set (1-based)
11749 *
11750 * Filter a location set, keeping only nodes for which the predicate
11751 * expression matches. Afterwards, keep only nodes between minPos and maxPos
11752 * in the filtered result.
11753 */
11754static void
11755xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
11756 xmlLocationSetPtr locset,
11757 int filterOpIndex,
11758 int minPos, int maxPos)
11759{
11760 xmlXPathContextPtr xpctxt;
11761 xmlNodePtr oldnode;
11762 xmlDocPtr olddoc;
11763 xmlXPathStepOpPtr filterOp;
11764 int oldcs, oldpp;
11765 int i, j, pos;
11766
11767 if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1))
11768 return;
11769
11770 xpctxt = ctxt->context;
11771 oldnode = xpctxt->node;
11772 olddoc = xpctxt->doc;
11773 oldcs = xpctxt->contextSize;
11774 oldpp = xpctxt->proximityPosition;
11775 filterOp = &ctxt->comp->steps[filterOpIndex];
11776
11777 xpctxt->contextSize = locset->locNr;
11778
11779 for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) {
11780 xmlNodePtr contextNode = locset->locTab[i]->user;
11781 int res;
11782
11783 xpctxt->node = contextNode;
11784 xpctxt->proximityPosition = i + 1;
11785
11786 /*
11787 * Also set the xpath document in case things like
11788 * key() are evaluated in the predicate.
11789 *
11790 * TODO: Get real doc for namespace nodes.
11791 */
11792 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11793 (contextNode->doc != NULL))
11794 xpctxt->doc = contextNode->doc;
11795
11796 res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11797
11798 if (ctxt->error != XPATH_EXPRESSION_OK)
Haibo Huangd23e46c2020-10-28 22:26:09 -070011799 break;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070011800 if (res < 0) {
11801 /* Shouldn't happen */
11802 xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
Haibo Huangd23e46c2020-10-28 22:26:09 -070011803 break;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070011804 }
11805
11806 if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11807 if (i != j) {
11808 locset->locTab[j] = locset->locTab[i];
11809 locset->locTab[i] = NULL;
11810 }
11811
11812 j += 1;
11813 } else {
11814 /* Remove the entry from the initial location set. */
11815 xmlXPathFreeObject(locset->locTab[i]);
11816 locset->locTab[i] = NULL;
11817 }
11818
11819 if (res != 0) {
11820 if (pos == maxPos) {
Haibo Huangd23e46c2020-10-28 22:26:09 -070011821 i += 1;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070011822 break;
11823 }
11824
11825 pos += 1;
11826 }
11827 }
11828
Haibo Huangd23e46c2020-10-28 22:26:09 -070011829 /* Free remaining nodes. */
11830 for (; i < locset->locNr; i++)
11831 xmlXPathFreeObject(locset->locTab[i]);
11832
Haibo Huangcfd91dc2020-07-30 23:01:33 -070011833 locset->locNr = j;
11834
11835 /* If too many elements were removed, shrink table to preserve memory. */
11836 if ((locset->locMax > XML_NODESET_DEFAULT) &&
11837 (locset->locNr < locset->locMax / 2)) {
11838 xmlXPathObjectPtr *tmp;
11839 int locMax = locset->locNr;
11840
11841 if (locMax < XML_NODESET_DEFAULT)
11842 locMax = XML_NODESET_DEFAULT;
11843 tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,
11844 locMax * sizeof(xmlXPathObjectPtr));
11845 if (tmp == NULL) {
11846 xmlXPathPErrMemory(ctxt, "shrinking locset\n");
11847 } else {
11848 locset->locTab = tmp;
11849 locset->locMax = locMax;
11850 }
11851 }
11852
Haibo Huangcfd91dc2020-07-30 23:01:33 -070011853 xpctxt->node = oldnode;
11854 xpctxt->doc = olddoc;
11855 xpctxt->contextSize = oldcs;
11856 xpctxt->proximityPosition = oldpp;
11857}
11858#endif /* LIBXML_XPTR_ENABLED */
11859
11860/**
11861 * xmlXPathCompOpEvalPredicate:
11862 * @ctxt: the XPath Parser context
11863 * @op: the predicate op
11864 * @set: the node set to filter
11865 * @minPos: minimum position in the filtered set (1-based)
11866 * @maxPos: maximum position in the filtered set (1-based)
11867 * @hasNsNodes: true if the node set may contain namespace nodes
11868 *
11869 * Filter a node set, keeping only nodes for which the sequence of predicate
11870 * expressions matches. Afterwards, keep only nodes between minPos and maxPos
11871 * in the filtered result.
11872 */
11873static void
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011874xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11875 xmlXPathStepOpPtr op,
11876 xmlNodeSetPtr set,
Haibo Huangcfd91dc2020-07-30 23:01:33 -070011877 int minPos, int maxPos,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011878 int hasNsNodes)
11879{
11880 if (op->ch1 != -1) {
11881 xmlXPathCompExprPtr comp = ctxt->comp;
11882 /*
11883 * Process inner predicates first.
11884 */
11885 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -070011886 xmlGenericError(xmlGenericErrorContext,
11887 "xmlXPathCompOpEvalPredicate: Expected a predicate\n");
11888 XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011889 }
Haibo Huangf0a546b2020-09-01 20:28:19 -070011890 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
Haibo Huangcfd91dc2020-07-30 23:01:33 -070011891 XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
11892 ctxt->context->depth += 1;
11893 xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
11894 1, set->nodeNr, hasNsNodes);
11895 ctxt->context->depth -= 1;
11896 CHECK_ERROR;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011897 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011898
Haibo Huangcfd91dc2020-07-30 23:01:33 -070011899 if (op->ch2 != -1)
11900 xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011901}
11902
11903static int
11904xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
Daniel Veillard45490ae2008-07-29 09:13:19 +000011905 xmlXPathStepOpPtr op,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011906 int *maxPos)
11907{
11908
11909 xmlXPathStepOpPtr exprOp;
11910
11911 /*
11912 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11913 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000011914
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011915 /*
11916 * If not -1, then ch1 will point to:
11917 * 1) For predicates (XPATH_OP_PREDICATE):
11918 * - an inner predicate operator
11919 * 2) For filters (XPATH_OP_FILTER):
Haibo Huangcfd91dc2020-07-30 23:01:33 -070011920 * - an inner filter operator OR
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011921 * - an expression selecting the node set.
11922 * E.g. "key('a', 'b')" or "(//foo | //bar)".
Daniel Veillard45490ae2008-07-29 09:13:19 +000011923 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011924 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11925 return(0);
11926
11927 if (op->ch2 != -1) {
11928 exprOp = &ctxt->comp->steps[op->ch2];
Daniel Veillard45490ae2008-07-29 09:13:19 +000011929 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011930 return(0);
11931
11932 if ((exprOp != NULL) &&
11933 (exprOp->op == XPATH_OP_VALUE) &&
11934 (exprOp->value4 != NULL) &&
11935 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11936 {
Nick Wellnhofera58331a2017-05-29 21:02:21 +020011937 double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11938
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011939 /*
11940 * We have a "[n]" predicate here.
11941 * TODO: Unfortunately this simplistic test here is not
11942 * able to detect a position() predicate in compound
11943 * expressions like "[@attr = 'a" and position() = 1],
11944 * and even not the usage of position() in
11945 * "[position() = 1]"; thus - obviously - a position-range,
11946 * like it "[position() < 5]", is also not detected.
11947 * Maybe we could rewrite the AST to ease the optimization.
11948 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000011949
Nick Wellnhofera58331a2017-05-29 21:02:21 +020011950 if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
11951 *maxPos = (int) floatval;
11952 if (floatval == (double) *maxPos)
11953 return(1);
11954 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011955 }
11956 return(0);
11957}
11958
11959static int
11960xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11961 xmlXPathStepOpPtr op,
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011962 xmlNodePtr * first, xmlNodePtr * last,
11963 int toBool)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011964{
11965
11966#define XP_TEST_HIT \
11967 if (hasAxisRange != 0) { \
11968 if (++pos == maxPos) { \
Daniel Veillard1bd45d12012-09-05 15:35:19 +080011969 if (addNode(seq, cur) < 0) \
11970 ctxt->error = XPATH_MEMORY_ERROR; \
11971 goto axis_range_end; } \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011972 } else { \
Daniel Veillard1bd45d12012-09-05 15:35:19 +080011973 if (addNode(seq, cur) < 0) \
11974 ctxt->error = XPATH_MEMORY_ERROR; \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011975 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011976
11977#define XP_TEST_HIT_NS \
11978 if (hasAxisRange != 0) { \
11979 if (++pos == maxPos) { \
11980 hasNsNodes = 1; \
Daniel Veillard1bd45d12012-09-05 15:35:19 +080011981 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11982 ctxt->error = XPATH_MEMORY_ERROR; \
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011983 goto axis_range_end; } \
11984 } else { \
11985 hasNsNodes = 1; \
Daniel Veillard1bd45d12012-09-05 15:35:19 +080011986 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11987 ctxt->error = XPATH_MEMORY_ERROR; \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011988 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011989
11990 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11991 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11992 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11993 const xmlChar *prefix = op->value4;
11994 const xmlChar *name = op->value5;
11995 const xmlChar *URI = NULL;
11996
11997#ifdef DEBUG_STEP
11998 int nbMatches = 0, prevMatches = 0;
11999#endif
12000 int total = 0, hasNsNodes = 0;
12001 /* The popped object holding the context nodes */
12002 xmlXPathObjectPtr obj;
12003 /* The set of context nodes for the node tests */
12004 xmlNodeSetPtr contextSeq;
12005 int contextIdx;
12006 xmlNodePtr contextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012007 /* The final resulting node set wrt to all context nodes */
12008 xmlNodeSetPtr outSeq;
12009 /*
12010 * The temporary resulting node set wrt 1 context node.
12011 * Used to feed predicate evaluation.
12012 */
12013 xmlNodeSetPtr seq;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012014 xmlNodePtr cur;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012015 /* First predicate operator */
12016 xmlXPathStepOpPtr predOp;
12017 int maxPos; /* The requested position() (when a "[n]" predicate) */
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012018 int hasPredicateRange, hasAxisRange, pos;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012019 int breakOnFirstHit;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012020
12021 xmlXPathTraversalFunction next = NULL;
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012022 int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012023 xmlXPathNodeSetMergeFunction mergeAndClear;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012024 xmlNodePtr oldContextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012025 xmlXPathContextPtr xpctxt = ctxt->context;
12026
12027
12028 CHECK_TYPE0(XPATH_NODESET);
12029 obj = valuePop(ctxt);
12030 /*
12031 * Setup namespaces.
12032 */
12033 if (prefix != NULL) {
12034 URI = xmlXPathNsLookup(xpctxt, prefix);
12035 if (URI == NULL) {
12036 xmlXPathReleaseObject(xpctxt, obj);
12037 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12038 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012039 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012040 /*
12041 * Setup axis.
12042 *
12043 * MAYBE FUTURE TODO: merging optimizations:
12044 * - If the nodes to be traversed wrt to the initial nodes and
12045 * the current axis cannot overlap, then we could avoid searching
12046 * for duplicates during the merge.
12047 * But the question is how/when to evaluate if they cannot overlap.
12048 * Example: if we know that for two initial nodes, the one is
12049 * not in the ancestor-or-self axis of the other, then we could safely
12050 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12051 * the descendant-or-self axis.
12052 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012053 mergeAndClear = xmlXPathNodeSetMergeAndClear;
12054 switch (axis) {
12055 case AXIS_ANCESTOR:
12056 first = NULL;
12057 next = xmlXPathNextAncestor;
12058 break;
12059 case AXIS_ANCESTOR_OR_SELF:
12060 first = NULL;
12061 next = xmlXPathNextAncestorOrSelf;
12062 break;
12063 case AXIS_ATTRIBUTE:
12064 first = NULL;
12065 last = NULL;
12066 next = xmlXPathNextAttribute;
12067 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12068 break;
12069 case AXIS_CHILD:
12070 last = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012071 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12072 (type == NODE_TYPE_NODE))
12073 {
12074 /*
12075 * Optimization if an element node type is 'element'.
12076 */
12077 next = xmlXPathNextChildElement;
12078 } else
12079 next = xmlXPathNextChild;
12080 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12081 break;
12082 case AXIS_DESCENDANT:
12083 last = NULL;
12084 next = xmlXPathNextDescendant;
12085 break;
12086 case AXIS_DESCENDANT_OR_SELF:
12087 last = NULL;
12088 next = xmlXPathNextDescendantOrSelf;
12089 break;
12090 case AXIS_FOLLOWING:
12091 last = NULL;
12092 next = xmlXPathNextFollowing;
12093 break;
12094 case AXIS_FOLLOWING_SIBLING:
12095 last = NULL;
12096 next = xmlXPathNextFollowingSibling;
12097 break;
12098 case AXIS_NAMESPACE:
12099 first = NULL;
12100 last = NULL;
12101 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12102 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12103 break;
12104 case AXIS_PARENT:
12105 first = NULL;
12106 next = xmlXPathNextParent;
12107 break;
12108 case AXIS_PRECEDING:
12109 first = NULL;
12110 next = xmlXPathNextPrecedingInternal;
12111 break;
12112 case AXIS_PRECEDING_SIBLING:
12113 first = NULL;
12114 next = xmlXPathNextPrecedingSibling;
12115 break;
12116 case AXIS_SELF:
12117 first = NULL;
12118 last = NULL;
12119 next = xmlXPathNextSelf;
12120 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12121 break;
12122 }
12123
12124#ifdef DEBUG_STEP
Daniel Veillard074f37e2008-09-01 13:38:22 +000012125 xmlXPathDebugDumpStepAxis(op,
12126 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012127#endif
12128
12129 if (next == NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000012130 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012131 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012132 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012133 contextSeq = obj->nodesetval;
12134 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12135 xmlXPathReleaseObject(xpctxt, obj);
12136 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12137 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012138 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012139 /*
12140 * Predicate optimization ---------------------------------------------
12141 * If this step has a last predicate, which contains a position(),
12142 * then we'll optimize (although not exactly "position()", but only
12143 * the short-hand form, i.e., "[n]".
12144 *
12145 * Example - expression "/foo[parent::bar][1]":
Daniel Veillard45490ae2008-07-29 09:13:19 +000012146 *
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012147 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12148 * ROOT -- op->ch1
12149 * PREDICATE -- op->ch2 (predOp)
12150 * PREDICATE -- predOp->ch1 = [parent::bar]
12151 * SORT
12152 * COLLECT 'parent' 'name' 'node' bar
12153 * NODE
12154 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12155 *
12156 */
12157 maxPos = 0;
12158 predOp = NULL;
12159 hasPredicateRange = 0;
12160 hasAxisRange = 0;
12161 if (op->ch2 != -1) {
12162 /*
12163 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12164 */
12165 predOp = &ctxt->comp->steps[op->ch2];
12166 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12167 if (predOp->ch1 != -1) {
12168 /*
12169 * Use the next inner predicate operator.
12170 */
12171 predOp = &ctxt->comp->steps[predOp->ch1];
12172 hasPredicateRange = 1;
12173 } else {
12174 /*
12175 * There's no other predicate than the [n] predicate.
12176 */
12177 predOp = NULL;
12178 hasAxisRange = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012179 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012180 }
12181 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012182 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012183 /*
12184 * Axis traversal -----------------------------------------------------
12185 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012186 /*
12187 * 2.3 Node Tests
Daniel Veillard45490ae2008-07-29 09:13:19 +000012188 * - For the attribute axis, the principal node type is attribute.
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012189 * - For the namespace axis, the principal node type is namespace.
12190 * - For other axes, the principal node type is element.
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012191 *
12192 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012193 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012194 * select all element children of the context node
12195 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012196 oldContextNode = xpctxt->node;
12197 addNode = xmlXPathNodeSetAddUnique;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012198 outSeq = NULL;
12199 seq = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012200 contextNode = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012201 contextIdx = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012202
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012203
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012204 while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12205 (ctxt->error == XPATH_EXPRESSION_OK)) {
Nick Wellnhofer62270532012-08-19 19:42:38 +020012206 xpctxt->node = contextSeq->nodeTab[contextIdx++];
Daniel Veillard45490ae2008-07-29 09:13:19 +000012207
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012208 if (seq == NULL) {
12209 seq = xmlXPathNodeSetCreate(NULL);
12210 if (seq == NULL) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012211 /* TODO: Propagate memory error. */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012212 total = 0;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012213 goto error;
12214 }
12215 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012216 /*
12217 * Traverse the axis and test the nodes.
12218 */
12219 pos = 0;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012220 cur = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012221 hasNsNodes = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012222 do {
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012223 if (OP_LIMIT_EXCEEDED(ctxt, 1))
12224 goto error;
12225
Daniel Veillardf06307e2001-07-03 10:35:50 +000012226 cur = next(ctxt, cur);
12227 if (cur == NULL)
12228 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012229
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012230 /*
12231 * QUESTION TODO: What does the "first" and "last" stuff do?
12232 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012233 if ((first != NULL) && (*first != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012234 if (*first == cur)
12235 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012236 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012237#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012238 (xmlXPathCmpNodesExt(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012239#else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012240 (xmlXPathCmpNodes(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012241#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012242 {
12243 break;
12244 }
12245 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012246 if ((last != NULL) && (*last != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012247 if (*last == cur)
12248 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012249 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012250#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012251 (xmlXPathCmpNodesExt(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012252#else
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012253 (xmlXPathCmpNodes(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012254#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012255 {
12256 break;
12257 }
12258 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012259
12260 total++;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012261
Daniel Veillardf06307e2001-07-03 10:35:50 +000012262#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012263 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12264#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +000012265
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012266 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012267 case NODE_TEST_NONE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012268 total = 0;
12269 STRANGE
12270 goto error;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012271 case NODE_TEST_TYPE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012272 if (type == NODE_TYPE_NODE) {
12273 switch (cur->type) {
12274 case XML_DOCUMENT_NODE:
12275 case XML_HTML_DOCUMENT_NODE:
12276#ifdef LIBXML_DOCB_ENABLED
12277 case XML_DOCB_DOCUMENT_NODE:
12278#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +000012279 case XML_ELEMENT_NODE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012280 case XML_ATTRIBUTE_NODE:
12281 case XML_PI_NODE:
12282 case XML_COMMENT_NODE:
12283 case XML_CDATA_SECTION_NODE:
12284 case XML_TEXT_NODE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012285 XP_TEST_HIT
12286 break;
Nick Wellnhoferf39fd662016-04-27 03:01:16 +020012287 case XML_NAMESPACE_DECL: {
12288 if (axis == AXIS_NAMESPACE) {
12289 XP_TEST_HIT_NS
12290 } else {
Nick Wellnhofer6eb08942016-05-05 16:49:00 +020012291 hasNsNodes = 1;
Nick Wellnhoferf39fd662016-04-27 03:01:16 +020012292 XP_TEST_HIT
12293 }
12294 break;
12295 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012296 default:
12297 break;
12298 }
Nick Wellnhoferb2189572017-11-13 21:23:17 +010012299 } else if (cur->type == (xmlElementType) type) {
Daniel Veillard713434d2012-09-26 10:21:06 +080012300 if (cur->type == XML_NAMESPACE_DECL)
Kasimier T. Buchcik889b7622006-07-03 11:44:13 +000012301 XP_TEST_HIT_NS
12302 else
12303 XP_TEST_HIT
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012304 } else if ((type == NODE_TYPE_TEXT) &&
12305 (cur->type == XML_CDATA_SECTION_NODE))
12306 {
12307 XP_TEST_HIT
12308 }
12309 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012310 case NODE_TEST_PI:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012311 if ((cur->type == XML_PI_NODE) &&
12312 ((name == NULL) || xmlStrEqual(name, cur->name)))
12313 {
12314 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012315 }
12316 break;
12317 case NODE_TEST_ALL:
12318 if (axis == AXIS_ATTRIBUTE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012319 if (cur->type == XML_ATTRIBUTE_NODE)
12320 {
Nick Wellnhofere8de99f2013-08-05 01:26:25 +020012321 if (prefix == NULL)
12322 {
12323 XP_TEST_HIT
12324 } else if ((cur->ns != NULL) &&
12325 (xmlStrEqual(URI, cur->ns->href)))
12326 {
12327 XP_TEST_HIT
12328 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012329 }
12330 } else if (axis == AXIS_NAMESPACE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012331 if (cur->type == XML_NAMESPACE_DECL)
12332 {
12333 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012334 }
12335 } else {
12336 if (cur->type == XML_ELEMENT_NODE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012337 if (prefix == NULL)
12338 {
12339 XP_TEST_HIT
12340
Daniel Veillardf06307e2001-07-03 10:35:50 +000012341 } else if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012342 (xmlStrEqual(URI, cur->ns->href)))
12343 {
12344 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012345 }
12346 }
12347 }
12348 break;
12349 case NODE_TEST_NS:{
12350 TODO;
12351 break;
12352 }
12353 case NODE_TEST_NAME:
Daniel Veillardfe3970e2006-11-23 16:08:30 +000012354 if (axis == AXIS_ATTRIBUTE) {
12355 if (cur->type != XML_ATTRIBUTE_NODE)
12356 break;
12357 } else if (axis == AXIS_NAMESPACE) {
12358 if (cur->type != XML_NAMESPACE_DECL)
12359 break;
12360 } else {
12361 if (cur->type != XML_ELEMENT_NODE)
12362 break;
12363 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012364 switch (cur->type) {
12365 case XML_ELEMENT_NODE:
12366 if (xmlStrEqual(name, cur->name)) {
12367 if (prefix == NULL) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012368 if (cur->ns == NULL)
12369 {
12370 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012371 }
12372 } else {
12373 if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012374 (xmlStrEqual(URI, cur->ns->href)))
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012375 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012376 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012377 }
12378 }
12379 }
12380 break;
12381 case XML_ATTRIBUTE_NODE:{
12382 xmlAttrPtr attr = (xmlAttrPtr) cur;
12383
12384 if (xmlStrEqual(name, attr->name)) {
12385 if (prefix == NULL) {
12386 if ((attr->ns == NULL) ||
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012387 (attr->ns->prefix == NULL))
12388 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012389 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012390 }
12391 } else {
12392 if ((attr->ns != NULL) &&
12393 (xmlStrEqual(URI,
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012394 attr->ns->href)))
12395 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012396 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012397 }
12398 }
12399 }
12400 break;
12401 }
12402 case XML_NAMESPACE_DECL:
12403 if (cur->type == XML_NAMESPACE_DECL) {
12404 xmlNsPtr ns = (xmlNsPtr) cur;
12405
12406 if ((ns->prefix != NULL) && (name != NULL)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012407 && (xmlStrEqual(ns->prefix, name)))
12408 {
12409 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012410 }
12411 }
12412 break;
12413 default:
12414 break;
12415 }
12416 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012417 } /* switch(test) */
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012418 } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012419
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012420 goto apply_predicates;
12421
Daniel Veillard45490ae2008-07-29 09:13:19 +000012422axis_range_end: /* ----------------------------------------------------- */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012423 /*
12424 * We have a "/foo[n]", and position() = n was reached.
12425 * Note that we can have as well "/foo/::parent::foo[1]", so
12426 * a duplicate-aware merge is still needed.
12427 * Merge with the result.
12428 */
12429 if (outSeq == NULL) {
12430 outSeq = seq;
12431 seq = NULL;
12432 } else
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012433 /* TODO: Check memory error. */
12434 outSeq = mergeAndClear(outSeq, seq);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012435 /*
12436 * Break if only a true/false result was requested.
12437 */
12438 if (toBool)
12439 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012440 continue;
12441
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012442first_hit: /* ---------------------------------------------------------- */
12443 /*
12444 * Break if only a true/false result was requested and
12445 * no predicates existed and a node test succeeded.
12446 */
12447 if (outSeq == NULL) {
12448 outSeq = seq;
12449 seq = NULL;
12450 } else
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012451 /* TODO: Check memory error. */
12452 outSeq = mergeAndClear(outSeq, seq);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012453 break;
12454
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012455#ifdef DEBUG_STEP
12456 if (seq != NULL)
12457 nbMatches += seq->nodeNr;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012458#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012459
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012460apply_predicates: /* --------------------------------------------------- */
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012461 if (ctxt->error != XPATH_EXPRESSION_OK)
12462 goto error;
12463
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012464 /*
12465 * Apply predicates.
Daniel Veillard45490ae2008-07-29 09:13:19 +000012466 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012467 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12468 /*
12469 * E.g. when we have a "/foo[some expression][n]".
Daniel Veillardf8e3db02012-09-11 13:26:36 +080012470 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012471 /*
12472 * QUESTION TODO: The old predicate evaluation took into
12473 * account location-sets.
12474 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12475 * Do we expect such a set here?
12476 * All what I learned now from the evaluation semantics
12477 * does not indicate that a location-set will be processed
12478 * here, so this looks OK.
Daniel Veillardf8e3db02012-09-11 13:26:36 +080012479 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012480 /*
12481 * Iterate over all predicates, starting with the outermost
12482 * predicate.
12483 * TODO: Problem: we cannot execute the inner predicates first
12484 * since we cannot go back *up* the operator tree!
12485 * Options we have:
12486 * 1) Use of recursive functions (like is it currently done
12487 * via xmlXPathCompOpEval())
12488 * 2) Add a predicate evaluation information stack to the
12489 * context struct
12490 * 3) Change the way the operators are linked; we need a
12491 * "parent" field on xmlXPathStepOp
12492 *
12493 * For the moment, I'll try to solve this with a recursive
12494 * function: xmlXPathCompOpEvalPredicate().
Daniel Veillard45490ae2008-07-29 09:13:19 +000012495 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012496 if (hasPredicateRange != 0)
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012497 xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
12498 hasNsNodes);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012499 else
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012500 xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
12501 hasNsNodes);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012502
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012503 if (ctxt->error != XPATH_EXPRESSION_OK) {
12504 total = 0;
12505 goto error;
12506 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012507 }
12508
12509 if (seq->nodeNr > 0) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012510 /*
12511 * Add to result set.
12512 */
12513 if (outSeq == NULL) {
12514 outSeq = seq;
12515 seq = NULL;
12516 } else {
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012517 /* TODO: Check memory error. */
12518 outSeq = mergeAndClear(outSeq, seq);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012519 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012520
12521 if (toBool)
12522 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012523 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012524 }
12525
12526error:
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012527 if ((obj->boolval) && (obj->user != NULL)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012528 /*
12529 * QUESTION TODO: What does this do and why?
12530 * TODO: Do we have to do this also for the "error"
12531 * cleanup further down?
12532 */
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012533 ctxt->value->boolval = 1;
12534 ctxt->value->user = obj->user;
12535 obj->user = NULL;
12536 obj->boolval = 0;
12537 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012538 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012539
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012540 /*
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012541 * Ensure we return at least an empty set.
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012542 */
12543 if (outSeq == NULL) {
12544 if ((seq != NULL) && (seq->nodeNr == 0))
12545 outSeq = seq;
12546 else
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012547 /* TODO: Check memory error. */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012548 outSeq = xmlXPathNodeSetCreate(NULL);
12549 }
12550 if ((seq != NULL) && (seq != outSeq)) {
12551 xmlXPathFreeNodeSet(seq);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012552 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012553 /*
12554 * Hand over the result. Better to push the set also in
12555 * case of errors.
12556 */
12557 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12558 /*
12559 * Reset the context node.
12560 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012561 xpctxt->node = oldContextNode;
Nick Wellnhofer82b73032016-04-30 17:53:10 +020012562 /*
12563 * When traversing the namespace axis in "toBool" mode, it's
12564 * possible that tmpNsList wasn't freed.
12565 */
12566 if (xpctxt->tmpNsList != NULL) {
12567 xmlFree(xpctxt->tmpNsList);
12568 xpctxt->tmpNsList = NULL;
12569 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012570
12571#ifdef DEBUG_STEP
12572 xmlGenericError(xmlGenericErrorContext,
12573 "\nExamined %d nodes, found %d nodes at that step\n",
12574 total, nbMatches);
12575#endif
12576
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012577 return(total);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012578}
12579
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012580static int
12581xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12582 xmlXPathStepOpPtr op, xmlNodePtr * first);
12583
Daniel Veillardf06307e2001-07-03 10:35:50 +000012584/**
12585 * xmlXPathCompOpEvalFirst:
12586 * @ctxt: the XPath parser context with the compiled expression
12587 * @op: an XPath compiled operation
12588 * @first: the first elem found so far
12589 *
12590 * Evaluate the Precompiled XPath operation searching only the first
12591 * element in document order
12592 *
12593 * Returns the number of examined objects.
12594 */
12595static int
12596xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12597 xmlXPathStepOpPtr op, xmlNodePtr * first)
12598{
12599 int total = 0, cur;
12600 xmlXPathCompExprPtr comp;
12601 xmlXPathObjectPtr arg1, arg2;
12602
Daniel Veillard556c6682001-10-06 09:59:51 +000012603 CHECK_ERROR0;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012604 if (OP_LIMIT_EXCEEDED(ctxt, 1))
12605 return(0);
Haibo Huangf0a546b2020-09-01 20:28:19 -070012606 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012607 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12608 ctxt->context->depth += 1;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012609 comp = ctxt->comp;
12610 switch (op->op) {
12611 case XPATH_OP_END:
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012612 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012613 case XPATH_OP_UNION:
12614 total =
12615 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12616 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012617 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012618 if ((ctxt->value != NULL)
12619 && (ctxt->value->type == XPATH_NODESET)
12620 && (ctxt->value->nodesetval != NULL)
12621 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12622 /*
12623 * limit tree traversing to first node in the result
12624 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012625 /*
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012626 * OPTIMIZE TODO: This implicitly sorts
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012627 * the result, even if not needed. E.g. if the argument
12628 * of the count() function, no sorting is needed.
12629 * OPTIMIZE TODO: How do we know if the node-list wasn't
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012630 * already sorted?
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012631 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012632 if (ctxt->value->nodesetval->nodeNr > 1)
12633 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012634 *first = ctxt->value->nodesetval->nodeTab[0];
12635 }
12636 cur =
12637 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12638 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012639 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012640
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020012641 arg2 = valuePop(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012642 arg1 = valuePop(ctxt);
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020012643 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12644 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12645 xmlXPathReleaseObject(ctxt->context, arg1);
12646 xmlXPathReleaseObject(ctxt->context, arg2);
12647 XP_ERROR0(XPATH_INVALID_TYPE);
12648 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012649 if ((ctxt->context->opLimit != 0) &&
12650 (((arg1->nodesetval != NULL) &&
12651 (xmlXPathCheckOpLimit(ctxt,
12652 arg1->nodesetval->nodeNr) < 0)) ||
12653 ((arg2->nodesetval != NULL) &&
12654 (xmlXPathCheckOpLimit(ctxt,
12655 arg2->nodesetval->nodeNr) < 0)))) {
12656 xmlXPathReleaseObject(ctxt->context, arg1);
12657 xmlXPathReleaseObject(ctxt->context, arg2);
12658 break;
12659 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012660
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012661 /* TODO: Check memory error. */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012662 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12663 arg2->nodesetval);
12664 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012665 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012666 /* optimizer */
12667 if (total > cur)
12668 xmlXPathCompSwap(op);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012669 total += cur;
12670 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012671 case XPATH_OP_ROOT:
12672 xmlXPathRoot(ctxt);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012673 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012674 case XPATH_OP_NODE:
12675 if (op->ch1 != -1)
12676 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012677 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012678 if (op->ch2 != -1)
12679 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012680 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012681 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12682 ctxt->context->node));
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012683 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012684 case XPATH_OP_COLLECT:{
12685 if (op->ch1 == -1)
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012686 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012687
12688 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012689 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012690
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012691 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012692 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012693 }
12694 case XPATH_OP_VALUE:
12695 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012696 xmlXPathCacheObjectCopy(ctxt->context,
12697 (xmlXPathObjectPtr) op->value4));
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012698 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012699 case XPATH_OP_SORT:
12700 if (op->ch1 != -1)
12701 total +=
12702 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12703 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012704 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012705 if ((ctxt->value != NULL)
12706 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012707 && (ctxt->value->nodesetval != NULL)
12708 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012709 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012710 break;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012711#ifdef XP_OPTIMIZED_FILTER_FIRST
12712 case XPATH_OP_FILTER:
Marius Wachtler2ddecc22010-10-12 09:09:07 +020012713 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012714 break;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012715#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000012716 default:
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012717 total += xmlXPathCompOpEval(ctxt, op);
12718 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012719 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012720
12721 ctxt->context->depth -= 1;
12722 return(total);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012723}
12724
12725/**
12726 * xmlXPathCompOpEvalLast:
12727 * @ctxt: the XPath parser context with the compiled expression
12728 * @op: an XPath compiled operation
12729 * @last: the last elem found so far
12730 *
12731 * Evaluate the Precompiled XPath operation searching only the last
12732 * element in document order
12733 *
William M. Brack08171912003-12-29 02:52:11 +000012734 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +000012735 */
12736static int
12737xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12738 xmlNodePtr * last)
12739{
12740 int total = 0, cur;
12741 xmlXPathCompExprPtr comp;
12742 xmlXPathObjectPtr arg1, arg2;
12743
Daniel Veillard556c6682001-10-06 09:59:51 +000012744 CHECK_ERROR0;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012745 if (OP_LIMIT_EXCEEDED(ctxt, 1))
12746 return(0);
Haibo Huangf0a546b2020-09-01 20:28:19 -070012747 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012748 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12749 ctxt->context->depth += 1;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012750 comp = ctxt->comp;
12751 switch (op->op) {
12752 case XPATH_OP_END:
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012753 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012754 case XPATH_OP_UNION:
12755 total =
12756 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012757 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012758 if ((ctxt->value != NULL)
12759 && (ctxt->value->type == XPATH_NODESET)
12760 && (ctxt->value->nodesetval != NULL)
12761 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12762 /*
12763 * limit tree traversing to first node in the result
12764 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012765 if (ctxt->value->nodesetval->nodeNr > 1)
12766 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012767 *last =
12768 ctxt->value->nodesetval->nodeTab[ctxt->value->
12769 nodesetval->nodeNr -
12770 1];
12771 }
12772 cur =
12773 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012774 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012775 if ((ctxt->value != NULL)
12776 && (ctxt->value->type == XPATH_NODESET)
12777 && (ctxt->value->nodesetval != NULL)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012778 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012779 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012780
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020012781 arg2 = valuePop(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012782 arg1 = valuePop(ctxt);
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020012783 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12784 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12785 xmlXPathReleaseObject(ctxt->context, arg1);
12786 xmlXPathReleaseObject(ctxt->context, arg2);
12787 XP_ERROR0(XPATH_INVALID_TYPE);
12788 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012789 if ((ctxt->context->opLimit != 0) &&
12790 (((arg1->nodesetval != NULL) &&
12791 (xmlXPathCheckOpLimit(ctxt,
12792 arg1->nodesetval->nodeNr) < 0)) ||
12793 ((arg2->nodesetval != NULL) &&
12794 (xmlXPathCheckOpLimit(ctxt,
12795 arg2->nodesetval->nodeNr) < 0)))) {
12796 xmlXPathReleaseObject(ctxt->context, arg1);
12797 xmlXPathReleaseObject(ctxt->context, arg2);
12798 break;
12799 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012800
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012801 /* TODO: Check memory error. */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012802 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12803 arg2->nodesetval);
12804 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012805 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012806 /* optimizer */
12807 if (total > cur)
12808 xmlXPathCompSwap(op);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012809 total += cur;
12810 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012811 case XPATH_OP_ROOT:
12812 xmlXPathRoot(ctxt);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012813 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012814 case XPATH_OP_NODE:
12815 if (op->ch1 != -1)
12816 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012817 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012818 if (op->ch2 != -1)
12819 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012820 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012821 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12822 ctxt->context->node));
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012823 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012824 case XPATH_OP_COLLECT:{
12825 if (op->ch1 == -1)
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012826 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012827
12828 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012829 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012830
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012831 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012832 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012833 }
12834 case XPATH_OP_VALUE:
12835 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012836 xmlXPathCacheObjectCopy(ctxt->context,
12837 (xmlXPathObjectPtr) op->value4));
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012838 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012839 case XPATH_OP_SORT:
12840 if (op->ch1 != -1)
12841 total +=
12842 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12843 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012844 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012845 if ((ctxt->value != NULL)
12846 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012847 && (ctxt->value->nodesetval != NULL)
12848 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012849 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012850 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012851 default:
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012852 total += xmlXPathCompOpEval(ctxt, op);
12853 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012854 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012855
12856 ctxt->context->depth -= 1;
12857 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012858}
12859
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012860#ifdef XP_OPTIMIZED_FILTER_FIRST
12861static int
12862xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12863 xmlXPathStepOpPtr op, xmlNodePtr * first)
12864{
12865 int total = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012866 xmlXPathCompExprPtr comp;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012867 xmlNodeSetPtr set;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012868
12869 CHECK_ERROR0;
12870 comp = ctxt->comp;
12871 /*
12872 * Optimization for ()[last()] selection i.e. the last elem
12873 */
12874 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12875 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12876 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12877 int f = comp->steps[op->ch2].ch1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012878
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012879 if ((f != -1) &&
12880 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12881 (comp->steps[f].value5 == NULL) &&
12882 (comp->steps[f].value == 0) &&
12883 (comp->steps[f].value4 != NULL) &&
12884 (xmlStrEqual
12885 (comp->steps[f].value4, BAD_CAST "last"))) {
12886 xmlNodePtr last = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012887
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012888 total +=
12889 xmlXPathCompOpEvalLast(ctxt,
12890 &comp->steps[op->ch1],
12891 &last);
12892 CHECK_ERROR0;
12893 /*
12894 * The nodeset should be in document order,
12895 * Keep only the last value
12896 */
12897 if ((ctxt->value != NULL) &&
12898 (ctxt->value->type == XPATH_NODESET) &&
12899 (ctxt->value->nodesetval != NULL) &&
12900 (ctxt->value->nodesetval->nodeTab != NULL) &&
12901 (ctxt->value->nodesetval->nodeNr > 1)) {
Nick Wellnhofer95a92492017-05-21 15:18:58 +020012902 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012903 *first = *(ctxt->value->nodesetval->nodeTab);
12904 }
12905 return (total);
12906 }
12907 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012908
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012909 if (op->ch1 != -1)
12910 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12911 CHECK_ERROR0;
12912 if (op->ch2 == -1)
12913 return (total);
12914 if (ctxt->value == NULL)
12915 return (total);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012916
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012917#ifdef LIBXML_XPTR_ENABLED
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012918 /*
12919 * Hum are we filtering the result of an XPointer expression
12920 */
12921 if (ctxt->value->type == XPATH_LOCATIONSET) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012922 xmlLocationSetPtr locset = ctxt->value->user;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012923
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012924 if (locset != NULL) {
12925 xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1);
12926 if (locset->locNr > 0)
12927 *first = (xmlNodePtr) locset->locTab[0]->user;
12928 }
Elliott Hughes7fbecab2019-01-10 16:42:03 -080012929
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012930 return (total);
12931 }
12932#endif /* LIBXML_XPTR_ENABLED */
Daniel Veillard45490ae2008-07-29 09:13:19 +000012933
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012934 CHECK_TYPE0(XPATH_NODESET);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012935 set = ctxt->value->nodesetval;
12936 if (set != NULL) {
12937 xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
12938 if (set->nodeNr > 0)
12939 *first = set->nodeTab[0];
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012940 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012941
12942 return (total);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012943}
12944#endif /* XP_OPTIMIZED_FILTER_FIRST */
12945
Owen Taylor3473f882001-02-23 17:55:21 +000012946/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012947 * xmlXPathCompOpEval:
12948 * @ctxt: the XPath parser context with the compiled expression
12949 * @op: an XPath compiled operation
12950 *
12951 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000012952 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012953 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012954static int
12955xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
12956{
12957 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012958 int equal, ret;
12959 xmlXPathCompExprPtr comp;
12960 xmlXPathObjectPtr arg1, arg2;
12961
Daniel Veillard556c6682001-10-06 09:59:51 +000012962 CHECK_ERROR0;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012963 if (OP_LIMIT_EXCEEDED(ctxt, 1))
12964 return(0);
Haibo Huangf0a546b2020-09-01 20:28:19 -070012965 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012966 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12967 ctxt->context->depth += 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012968 comp = ctxt->comp;
12969 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012970 case XPATH_OP_END:
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012971 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012972 case XPATH_OP_AND:
12973 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012974 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012975 xmlXPathBooleanFunction(ctxt, 1);
12976 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012977 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012978 arg2 = valuePop(ctxt);
12979 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012980 if (ctxt->error) {
12981 xmlXPathFreeObject(arg2);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012982 break;
Daniel Veillard556c6682001-10-06 09:59:51 +000012983 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012984 xmlXPathBooleanFunction(ctxt, 1);
Elliott Hughes7fbecab2019-01-10 16:42:03 -080012985 if (ctxt->value != NULL)
12986 ctxt->value->boolval &= arg2->boolval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012987 xmlXPathReleaseObject(ctxt->context, arg2);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012988 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012989 case XPATH_OP_OR:
12990 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012991 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012992 xmlXPathBooleanFunction(ctxt, 1);
12993 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012994 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012995 arg2 = valuePop(ctxt);
12996 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012997 if (ctxt->error) {
12998 xmlXPathFreeObject(arg2);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012999 break;
Daniel Veillard556c6682001-10-06 09:59:51 +000013000 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013001 xmlXPathBooleanFunction(ctxt, 1);
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013002 if (ctxt->value != NULL)
13003 ctxt->value->boolval |= arg2->boolval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013004 xmlXPathReleaseObject(ctxt->context, arg2);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013005 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013006 case XPATH_OP_EQUAL:
13007 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013008 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013009 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013010 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000013011 if (op->value)
Daniel Veillard45490ae2008-07-29 09:13:19 +000013012 equal = xmlXPathEqualValues(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +000013013 else
13014 equal = xmlXPathNotEqualValues(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013015 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013016 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013017 case XPATH_OP_CMP:
13018 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013019 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013020 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013021 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013022 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013023 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013024 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013025 case XPATH_OP_PLUS:
13026 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013027 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013028 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013029 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013030 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013031 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013032 if (op->value == 0)
13033 xmlXPathSubValues(ctxt);
13034 else if (op->value == 1)
13035 xmlXPathAddValues(ctxt);
13036 else if (op->value == 2)
13037 xmlXPathValueFlipSign(ctxt);
13038 else if (op->value == 3) {
13039 CAST_TO_NUMBER;
13040 CHECK_TYPE0(XPATH_NUMBER);
13041 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013042 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013043 case XPATH_OP_MULT:
13044 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013045 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013046 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013047 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013048 if (op->value == 0)
13049 xmlXPathMultValues(ctxt);
13050 else if (op->value == 1)
13051 xmlXPathDivValues(ctxt);
13052 else if (op->value == 2)
13053 xmlXPathModValues(ctxt);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013054 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013055 case XPATH_OP_UNION:
13056 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013057 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013058 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013059 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013060
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020013061 arg2 = valuePop(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013062 arg1 = valuePop(ctxt);
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020013063 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13064 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13065 xmlXPathReleaseObject(ctxt->context, arg1);
13066 xmlXPathReleaseObject(ctxt->context, arg2);
13067 XP_ERROR0(XPATH_INVALID_TYPE);
13068 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013069 if ((ctxt->context->opLimit != 0) &&
13070 (((arg1->nodesetval != NULL) &&
13071 (xmlXPathCheckOpLimit(ctxt,
13072 arg1->nodesetval->nodeNr) < 0)) ||
13073 ((arg2->nodesetval != NULL) &&
13074 (xmlXPathCheckOpLimit(ctxt,
13075 arg2->nodesetval->nodeNr) < 0)))) {
13076 xmlXPathReleaseObject(ctxt->context, arg1);
13077 xmlXPathReleaseObject(ctxt->context, arg2);
13078 break;
13079 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013080
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013081 if ((arg1->nodesetval == NULL) ||
13082 ((arg2->nodesetval != NULL) &&
13083 (arg2->nodesetval->nodeNr != 0)))
13084 {
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013085 /* TODO: Check memory error. */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013086 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13087 arg2->nodesetval);
13088 }
13089
Daniel Veillardf06307e2001-07-03 10:35:50 +000013090 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013091 xmlXPathReleaseObject(ctxt->context, arg2);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013092 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013093 case XPATH_OP_ROOT:
13094 xmlXPathRoot(ctxt);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013095 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013096 case XPATH_OP_NODE:
13097 if (op->ch1 != -1)
13098 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013099 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013100 if (op->ch2 != -1)
13101 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013102 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013103 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13104 ctxt->context->node));
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013105 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013106 case XPATH_OP_COLLECT:{
13107 if (op->ch1 == -1)
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013108 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000013109
Daniel Veillardf06307e2001-07-03 10:35:50 +000013110 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013111 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013112
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013113 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013114 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013115 }
13116 case XPATH_OP_VALUE:
13117 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013118 xmlXPathCacheObjectCopy(ctxt->context,
13119 (xmlXPathObjectPtr) op->value4));
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013120 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013121 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000013122 xmlXPathObjectPtr val;
13123
Daniel Veillardf06307e2001-07-03 10:35:50 +000013124 if (op->ch1 != -1)
13125 total +=
13126 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013127 if (op->value5 == NULL) {
13128 val = xmlXPathVariableLookup(ctxt->context, op->value4);
Nick Wellnhofer3157cf42017-09-20 16:13:29 +020013129 if (val == NULL)
13130 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
Daniel Veillard556c6682001-10-06 09:59:51 +000013131 valuePush(ctxt, val);
13132 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013133 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013134
Daniel Veillardf06307e2001-07-03 10:35:50 +000013135 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13136 if (URI == NULL) {
13137 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013138 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13139 (char *) op->value4, (char *)op->value5);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080013140 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013141 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013142 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013143 val = xmlXPathVariableLookupNS(ctxt->context,
13144 op->value4, URI);
Nick Wellnhofer3157cf42017-09-20 16:13:29 +020013145 if (val == NULL)
13146 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
Daniel Veillard556c6682001-10-06 09:59:51 +000013147 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013148 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013149 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013150 }
13151 case XPATH_OP_FUNCTION:{
13152 xmlXPathFunction func;
13153 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000013154 int i;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013155 int frame;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013156
Daniel Veillardf5048b32011-08-18 17:10:13 +080013157 frame = xmlXPathSetFrame(ctxt);
Nick Wellnhofer03c67232013-12-20 00:01:53 +010013158 if (op->ch1 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013159 total +=
13160 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Nick Wellnhofer03c67232013-12-20 00:01:53 +010013161 if (ctxt->error != XPATH_EXPRESSION_OK) {
13162 xmlXPathPopFrame(ctxt, frame);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013163 break;
Nick Wellnhofer03c67232013-12-20 00:01:53 +010013164 }
13165 }
13166 if (ctxt->valueNr < ctxt->valueFrame + op->value) {
Daniel Veillard556c6682001-10-06 09:59:51 +000013167 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013168 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013169 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013170 xmlXPathPopFrame(ctxt, frame);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013171 break;
Daniel Veillard556c6682001-10-06 09:59:51 +000013172 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080013173 for (i = 0; i < op->value; i++) {
Daniel Veillard556c6682001-10-06 09:59:51 +000013174 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13175 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013176 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013177 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013178 xmlXPathPopFrame(ctxt, frame);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013179 break;
Daniel Veillard556c6682001-10-06 09:59:51 +000013180 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080013181 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013182 if (op->cache != NULL)
Nick Wellnhofer229d1f92016-08-22 13:21:57 +020013183 func = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013184 else {
13185 const xmlChar *URI = NULL;
13186
13187 if (op->value5 == NULL)
13188 func =
13189 xmlXPathFunctionLookup(ctxt->context,
13190 op->value4);
13191 else {
13192 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13193 if (URI == NULL) {
13194 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013195 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13196 (char *)op->value4, (char *)op->value5);
Daniel Veillardf5048b32011-08-18 17:10:13 +080013197 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080013198 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013199 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013200 }
13201 func = xmlXPathFunctionLookupNS(ctxt->context,
13202 op->value4, URI);
13203 }
13204 if (func == NULL) {
13205 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013206 "xmlXPathCompOpEval: function %s not found\n",
13207 (char *)op->value4);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013208 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013209 }
Nick Wellnhofer229d1f92016-08-22 13:21:57 +020013210 op->cache = func;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013211 op->cacheURI = (void *) URI;
13212 }
13213 oldFunc = ctxt->context->function;
13214 oldFuncURI = ctxt->context->functionURI;
13215 ctxt->context->function = op->value4;
13216 ctxt->context->functionURI = op->cacheURI;
13217 func(ctxt, op->value);
13218 ctxt->context->function = oldFunc;
13219 ctxt->context->functionURI = oldFuncURI;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013220 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
13221 (ctxt->valueNr != ctxt->valueFrame + 1))
13222 XP_ERROR0(XPATH_STACK_ERROR);
Daniel Veillardf5048b32011-08-18 17:10:13 +080013223 xmlXPathPopFrame(ctxt, frame);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013224 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013225 }
13226 case XPATH_OP_ARG:
Nick Wellnhofer07def302014-03-21 19:38:08 +010013227 if (op->ch1 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013228 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Nick Wellnhofer07def302014-03-21 19:38:08 +010013229 CHECK_ERROR0;
13230 }
William M. Brack72ee48d2003-12-30 08:30:19 +000013231 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013232 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000013233 CHECK_ERROR0;
13234 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013235 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013236 case XPATH_OP_PREDICATE:
13237 case XPATH_OP_FILTER:{
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013238 xmlNodeSetPtr set;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013239
13240 /*
13241 * Optimization for ()[1] selection i.e. the first elem
13242 */
13243 if ((op->ch1 != -1) && (op->ch2 != -1) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013244#ifdef XP_OPTIMIZED_FILTER_FIRST
13245 /*
13246 * FILTER TODO: Can we assume that the inner processing
13247 * will result in an ordered list if we have an
13248 * XPATH_OP_FILTER?
13249 * What about an additional field or flag on
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013250 * xmlXPathObject like @sorted ? This way we wouldn't need
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013251 * to assume anything, so it would be more robust and
13252 * easier to optimize.
13253 */
13254 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13255 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13256#else
13257 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13258#endif
13259 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013260 xmlXPathObjectPtr val;
13261
13262 val = comp->steps[op->ch2].value4;
13263 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13264 (val->floatval == 1.0)) {
13265 xmlNodePtr first = NULL;
13266
13267 total +=
13268 xmlXPathCompOpEvalFirst(ctxt,
13269 &comp->steps[op->ch1],
13270 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000013271 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013272 /*
13273 * The nodeset should be in document order,
13274 * Keep only the first value
13275 */
13276 if ((ctxt->value != NULL) &&
13277 (ctxt->value->type == XPATH_NODESET) &&
13278 (ctxt->value->nodesetval != NULL) &&
13279 (ctxt->value->nodesetval->nodeNr > 1))
Nick Wellnhofer95a92492017-05-21 15:18:58 +020013280 xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13281 1, 1);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013282 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013283 }
13284 }
13285 /*
13286 * Optimization for ()[last()] selection i.e. the last elem
13287 */
13288 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13289 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13290 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13291 int f = comp->steps[op->ch2].ch1;
13292
13293 if ((f != -1) &&
13294 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13295 (comp->steps[f].value5 == NULL) &&
13296 (comp->steps[f].value == 0) &&
13297 (comp->steps[f].value4 != NULL) &&
13298 (xmlStrEqual
13299 (comp->steps[f].value4, BAD_CAST "last"))) {
13300 xmlNodePtr last = NULL;
13301
13302 total +=
13303 xmlXPathCompOpEvalLast(ctxt,
13304 &comp->steps[op->ch1],
13305 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000013306 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013307 /*
13308 * The nodeset should be in document order,
13309 * Keep only the last value
13310 */
13311 if ((ctxt->value != NULL) &&
13312 (ctxt->value->type == XPATH_NODESET) &&
13313 (ctxt->value->nodesetval != NULL) &&
13314 (ctxt->value->nodesetval->nodeTab != NULL) &&
Nick Wellnhofer95a92492017-05-21 15:18:58 +020013315 (ctxt->value->nodesetval->nodeNr > 1))
13316 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013317 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013318 }
13319 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013320 /*
13321 * Process inner predicates first.
13322 * Example "index[parent::book][1]":
13323 * ...
13324 * PREDICATE <-- we are here "[1]"
13325 * PREDICATE <-- process "[parent::book]" first
13326 * SORT
13327 * COLLECT 'parent' 'name' 'node' book
13328 * NODE
13329 * ELEM Object is a number : 1
13330 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013331 if (op->ch1 != -1)
13332 total +=
13333 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013334 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013335 if (op->ch2 == -1)
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013336 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013337 if (ctxt->value == NULL)
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013338 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013339
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013340#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013341 /*
13342 * Hum are we filtering the result of an XPointer expression
13343 */
13344 if (ctxt->value->type == XPATH_LOCATIONSET) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013345 xmlLocationSetPtr locset = ctxt->value->user;
13346 xmlXPathLocationSetFilter(ctxt, locset, op->ch2,
13347 1, locset->locNr);
13348 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013349 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013350#endif /* LIBXML_XPTR_ENABLED */
13351
Daniel Veillardf06307e2001-07-03 10:35:50 +000013352 CHECK_TYPE0(XPATH_NODESET);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013353 set = ctxt->value->nodesetval;
13354 if (set != NULL)
13355 xmlXPathNodeSetFilter(ctxt, set, op->ch2,
13356 1, set->nodeNr, 1);
13357 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013358 }
13359 case XPATH_OP_SORT:
13360 if (op->ch1 != -1)
13361 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013362 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013363 if ((ctxt->value != NULL) &&
13364 (ctxt->value->type == XPATH_NODESET) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013365 (ctxt->value->nodesetval != NULL) &&
13366 (ctxt->value->nodesetval->nodeNr > 1))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013367 {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013368 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013369 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013370 break;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013371#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013372 case XPATH_OP_RANGETO:{
13373 xmlXPathObjectPtr range;
13374 xmlXPathObjectPtr res, obj;
13375 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000013376 xmlLocationSetPtr newlocset = NULL;
13377 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013378 xmlNodeSetPtr oldset;
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013379 xmlNodePtr oldnode = ctxt->context->node;
13380 int oldcs = ctxt->context->contextSize;
13381 int oldpp = ctxt->context->proximityPosition;
William M. Brack72ee48d2003-12-30 08:30:19 +000013382 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013383
Nick Wellnhoferd8083bf2016-06-25 12:35:50 +020013384 if (op->ch1 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013385 total +=
13386 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Nick Wellnhoferd8083bf2016-06-25 12:35:50 +020013387 CHECK_ERROR0;
13388 }
13389 if (ctxt->value == NULL) {
13390 XP_ERROR0(XPATH_INVALID_OPERAND);
13391 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013392 if (op->ch2 == -1)
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013393 break;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013394
William M. Brack08171912003-12-29 02:52:11 +000013395 if (ctxt->value->type == XPATH_LOCATIONSET) {
13396 /*
13397 * Extract the old locset, and then evaluate the result of the
13398 * expression for all the element in the locset. use it to grow
13399 * up a new locset.
13400 */
13401 CHECK_TYPE0(XPATH_LOCATIONSET);
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013402
13403 if ((ctxt->value->user == NULL) ||
13404 (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013405 break;
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013406
William M. Brack08171912003-12-29 02:52:11 +000013407 obj = valuePop(ctxt);
13408 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013409
William M. Brack08171912003-12-29 02:52:11 +000013410 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013411
William M. Brack08171912003-12-29 02:52:11 +000013412 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013413 /*
William M. Brack08171912003-12-29 02:52:11 +000013414 * Run the evaluation with a node list made of a
13415 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000013416 */
William M. Brackf7eb7942003-12-31 07:59:17 +000013417 ctxt->context->node = oldlocset->locTab[i]->user;
13418 ctxt->context->contextSize = oldlocset->locNr;
13419 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013420 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13421 ctxt->context->node);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013422 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013423
Daniel Veillardf06307e2001-07-03 10:35:50 +000013424 if (op->ch2 != -1)
13425 total +=
13426 xmlXPathCompOpEval(ctxt,
13427 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013428 if (ctxt->error != XPATH_EXPRESSION_OK) {
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013429 xmlXPtrFreeLocationSet(newlocset);
13430 goto rangeto_error;
William M. Brack2c19a7b2005-04-10 01:03:23 +000013431 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013432
Daniel Veillardf06307e2001-07-03 10:35:50 +000013433 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000013434 if (res->type == XPATH_LOCATIONSET) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000013435 xmlLocationSetPtr rloc =
William M. Brack72ee48d2003-12-30 08:30:19 +000013436 (xmlLocationSetPtr)res->user;
13437 for (j=0; j<rloc->locNr; j++) {
13438 range = xmlXPtrNewRange(
13439 oldlocset->locTab[i]->user,
13440 oldlocset->locTab[i]->index,
13441 rloc->locTab[j]->user2,
13442 rloc->locTab[j]->index2);
13443 if (range != NULL) {
13444 xmlXPtrLocationSetAdd(newlocset, range);
13445 }
13446 }
13447 } else {
13448 range = xmlXPtrNewRangeNodeObject(
13449 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13450 if (range != NULL) {
13451 xmlXPtrLocationSetAdd(newlocset,range);
13452 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013453 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013454
Daniel Veillardf06307e2001-07-03 10:35:50 +000013455 /*
13456 * Cleanup
13457 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013458 if (res != NULL) {
13459 xmlXPathReleaseObject(ctxt->context, res);
13460 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013461 if (ctxt->value == tmp) {
13462 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013463 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013464 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013465 }
William M. Brack72ee48d2003-12-30 08:30:19 +000013466 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000013467 CHECK_TYPE0(XPATH_NODESET);
13468 obj = valuePop(ctxt);
13469 oldset = obj->nodesetval;
William M. Brack08171912003-12-29 02:52:11 +000013470
13471 newlocset = xmlXPtrLocationSetCreate(NULL);
13472
13473 if (oldset != NULL) {
13474 for (i = 0; i < oldset->nodeNr; i++) {
13475 /*
13476 * Run the evaluation with a node list made of a single item
13477 * in the nodeset.
13478 */
13479 ctxt->context->node = oldset->nodeTab[i];
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013480 /*
13481 * OPTIMIZE TODO: Avoid recreation for every iteration.
13482 */
13483 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13484 ctxt->context->node);
William M. Brack08171912003-12-29 02:52:11 +000013485 valuePush(ctxt, tmp);
13486
13487 if (op->ch2 != -1)
13488 total +=
13489 xmlXPathCompOpEval(ctxt,
13490 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013491 if (ctxt->error != XPATH_EXPRESSION_OK) {
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013492 xmlXPtrFreeLocationSet(newlocset);
13493 goto rangeto_error;
William M. Brack2c19a7b2005-04-10 01:03:23 +000013494 }
William M. Brack08171912003-12-29 02:52:11 +000013495
William M. Brack08171912003-12-29 02:52:11 +000013496 res = valuePop(ctxt);
13497 range =
13498 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13499 res);
13500 if (range != NULL) {
13501 xmlXPtrLocationSetAdd(newlocset, range);
13502 }
13503
13504 /*
13505 * Cleanup
13506 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013507 if (res != NULL) {
13508 xmlXPathReleaseObject(ctxt->context, res);
13509 }
William M. Brack08171912003-12-29 02:52:11 +000013510 if (ctxt->value == tmp) {
13511 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013512 xmlXPathReleaseObject(ctxt->context, res);
William M. Brack08171912003-12-29 02:52:11 +000013513 }
William M. Brack08171912003-12-29 02:52:11 +000013514 }
13515 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013516 }
13517
13518 /*
13519 * The result is used as the new evaluation set.
13520 */
William M. Brack08171912003-12-29 02:52:11 +000013521 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013522rangeto_error:
13523 xmlXPathReleaseObject(ctxt->context, obj);
13524 ctxt->context->node = oldnode;
13525 ctxt->context->contextSize = oldcs;
13526 ctxt->context->proximityPosition = oldpp;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013527 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013528 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013529#endif /* LIBXML_XPTR_ENABLED */
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013530 default:
13531 xmlGenericError(xmlGenericErrorContext,
13532 "XPath: unknown precompiled operation %d\n", op->op);
13533 ctxt->error = XPATH_INVALID_OPERAND;
13534 break;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013535 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013536
13537 ctxt->context->depth -= 1;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013538 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013539}
13540
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013541/**
13542 * xmlXPathCompOpEvalToBoolean:
13543 * @ctxt: the XPath parser context
13544 *
13545 * Evaluates if the expression evaluates to true.
13546 *
13547 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13548 */
13549static int
13550xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013551 xmlXPathStepOpPtr op,
13552 int isPredicate)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013553{
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013554 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013555
13556start:
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013557 if (OP_LIMIT_EXCEEDED(ctxt, 1))
13558 return(0);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013559 /* comp = ctxt->comp; */
13560 switch (op->op) {
13561 case XPATH_OP_END:
13562 return (0);
13563 case XPATH_OP_VALUE:
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013564 resObj = (xmlXPathObjectPtr) op->value4;
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000013565 if (isPredicate)
13566 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13567 return(xmlXPathCastToBoolean(resObj));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013568 case XPATH_OP_SORT:
13569 /*
13570 * We don't need sorting for boolean results. Skip this one.
13571 */
13572 if (op->ch1 != -1) {
13573 op = &ctxt->comp->steps[op->ch1];
13574 goto start;
13575 }
13576 return(0);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013577 case XPATH_OP_COLLECT:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013578 if (op->ch1 == -1)
13579 return(0);
13580
13581 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13582 if (ctxt->error != XPATH_EXPRESSION_OK)
13583 return(-1);
13584
13585 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13586 if (ctxt->error != XPATH_EXPRESSION_OK)
13587 return(-1);
13588
13589 resObj = valuePop(ctxt);
13590 if (resObj == NULL)
13591 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013592 break;
13593 default:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013594 /*
13595 * Fallback to call xmlXPathCompOpEval().
13596 */
13597 xmlXPathCompOpEval(ctxt, op);
13598 if (ctxt->error != XPATH_EXPRESSION_OK)
13599 return(-1);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013600
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013601 resObj = valuePop(ctxt);
13602 if (resObj == NULL)
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000013603 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013604 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013605 }
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013606
13607 if (resObj) {
13608 int res;
13609
13610 if (resObj->type == XPATH_BOOLEAN) {
13611 res = resObj->boolval;
13612 } else if (isPredicate) {
13613 /*
13614 * For predicates a result of type "number" is handled
13615 * differently:
13616 * SPEC XPath 1.0:
13617 * "If the result is a number, the result will be converted
13618 * to true if the number is equal to the context position
13619 * and will be converted to false otherwise;"
13620 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000013621 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013622 } else {
13623 res = xmlXPathCastToBoolean(resObj);
13624 }
13625 xmlXPathReleaseObject(ctxt->context, resObj);
13626 return(res);
13627 }
13628
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013629 return(0);
13630}
13631
Daniel Veillard56de87e2005-02-16 00:22:29 +000013632#ifdef XPATH_STREAMING
13633/**
13634 * xmlXPathRunStreamEval:
13635 * @ctxt: the XPath parser context with the compiled expression
13636 *
13637 * Evaluate the Precompiled Streamable XPath expression in the given context.
13638 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013639static int
13640xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
13641 xmlXPathObjectPtr *resultSeq, int toBool)
13642{
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013643 int max_depth, min_depth;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013644 int from_root;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013645 int ret, depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013646 int eval_all_nodes;
William M. Brack12d37ab2005-02-21 13:54:07 +000013647 xmlNodePtr cur = NULL, limit = NULL;
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000013648 xmlStreamCtxtPtr patstream = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013649
13650 int nb_nodes = 0;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013651
13652 if ((ctxt == NULL) || (comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013653 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000013654 max_depth = xmlPatternMaxDepth(comp);
13655 if (max_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013656 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000013657 if (max_depth == -2)
13658 max_depth = 10000;
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013659 min_depth = xmlPatternMinDepth(comp);
13660 if (min_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013661 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000013662 from_root = xmlPatternFromRoot(comp);
13663 if (from_root < 0)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013664 return(-1);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000013665#if 0
13666 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
13667#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000013668
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013669 if (! toBool) {
13670 if (resultSeq == NULL)
13671 return(-1);
13672 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
13673 if (*resultSeq == NULL)
13674 return(-1);
13675 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000013676
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013677 /*
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000013678 * handle the special cases of "/" amd "." being matched
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013679 */
13680 if (min_depth == 0) {
13681 if (from_root) {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000013682 /* Select "/" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013683 if (toBool)
13684 return(1);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013685 /* TODO: Check memory error. */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013686 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013687 (xmlNodePtr) ctxt->doc);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013688 } else {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000013689 /* Select "self::node()" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013690 if (toBool)
13691 return(1);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013692 /* TODO: Check memory error. */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013693 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013694 }
13695 }
13696 if (max_depth == 0) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013697 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000013698 }
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013699
Daniel Veillard56de87e2005-02-16 00:22:29 +000013700 if (from_root) {
William M. Brack12d37ab2005-02-21 13:54:07 +000013701 cur = (xmlNodePtr)ctxt->doc;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013702 } else if (ctxt->node != NULL) {
13703 switch (ctxt->node->type) {
13704 case XML_ELEMENT_NODE:
13705 case XML_DOCUMENT_NODE:
13706 case XML_DOCUMENT_FRAG_NODE:
13707 case XML_HTML_DOCUMENT_NODE:
13708#ifdef LIBXML_DOCB_ENABLED
13709 case XML_DOCB_DOCUMENT_NODE:
13710#endif
13711 cur = ctxt->node;
13712 break;
13713 case XML_ATTRIBUTE_NODE:
13714 case XML_TEXT_NODE:
13715 case XML_CDATA_SECTION_NODE:
13716 case XML_ENTITY_REF_NODE:
13717 case XML_ENTITY_NODE:
13718 case XML_PI_NODE:
13719 case XML_COMMENT_NODE:
13720 case XML_NOTATION_NODE:
13721 case XML_DTD_NODE:
13722 case XML_DOCUMENT_TYPE_NODE:
13723 case XML_ELEMENT_DECL:
13724 case XML_ATTRIBUTE_DECL:
13725 case XML_ENTITY_DECL:
13726 case XML_NAMESPACE_DECL:
13727 case XML_XINCLUDE_START:
13728 case XML_XINCLUDE_END:
Daniel Veillard56de87e2005-02-16 00:22:29 +000013729 break;
13730 }
13731 limit = cur;
13732 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013733 if (cur == NULL) {
13734 return(0);
13735 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000013736
13737 patstream = xmlPatternGetStreamCtxt(comp);
13738 if (patstream == NULL) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013739 /*
13740 * QUESTION TODO: Is this an error?
13741 */
13742 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000013743 }
13744
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013745 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013746
Daniel Veillard56de87e2005-02-16 00:22:29 +000013747 if (from_root) {
13748 ret = xmlStreamPush(patstream, NULL, NULL);
13749 if (ret < 0) {
13750 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013751 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000013752 goto return_1;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013753 /* TODO: Check memory error. */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013754 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Daniel Veillard56de87e2005-02-16 00:22:29 +000013755 }
13756 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000013757 depth = 0;
13758 goto scan_children;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013759next_node:
Daniel Veillardd3ff7ef2006-02-27 19:43:17 +000013760 do {
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013761 if (ctxt->opLimit != 0) {
13762 if (ctxt->opCount >= ctxt->opLimit) {
13763 xmlGenericError(xmlGenericErrorContext,
13764 "XPath operation limit exceeded\n");
13765 xmlFreeStreamCtxt(patstream);
13766 return(-1);
13767 }
13768 ctxt->opCount++;
13769 }
13770
Daniel Veillard56de87e2005-02-16 00:22:29 +000013771 nb_nodes++;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013772
13773 switch (cur->type) {
13774 case XML_ELEMENT_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013775 case XML_TEXT_NODE:
13776 case XML_CDATA_SECTION_NODE:
13777 case XML_COMMENT_NODE:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013778 case XML_PI_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013779 if (cur->type == XML_ELEMENT_NODE) {
13780 ret = xmlStreamPush(patstream, cur->name,
Daniel Veillard56de87e2005-02-16 00:22:29 +000013781 (cur->ns ? cur->ns->href : NULL));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013782 } else if (eval_all_nodes)
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013783 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
13784 else
13785 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013786
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013787 if (ret < 0) {
13788 /* NOP. */
13789 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013790 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000013791 goto return_1;
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013792 if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
13793 < 0) {
13794 ctxt->lastError.domain = XML_FROM_XPATH;
13795 ctxt->lastError.code = XML_ERR_NO_MEMORY;
13796 }
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013797 }
13798 if ((cur->children == NULL) || (depth >= max_depth)) {
13799 ret = xmlStreamPop(patstream);
13800 while (cur->next != NULL) {
13801 cur = cur->next;
13802 if ((cur->type != XML_ENTITY_DECL) &&
13803 (cur->type != XML_DTD_NODE))
13804 goto next_node;
13805 }
13806 }
13807 default:
13808 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013809 }
13810
Daniel Veillard56de87e2005-02-16 00:22:29 +000013811scan_children:
Daniel Veillard3e62adb2012-08-09 14:24:02 +080013812 if (cur->type == XML_NAMESPACE_DECL) break;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013813 if ((cur->children != NULL) && (depth < max_depth)) {
13814 /*
Daniel Veillard45490ae2008-07-29 09:13:19 +000013815 * Do not descend on entities declarations
Daniel Veillard56de87e2005-02-16 00:22:29 +000013816 */
13817 if (cur->children->type != XML_ENTITY_DECL) {
13818 cur = cur->children;
13819 depth++;
13820 /*
13821 * Skip DTDs
13822 */
13823 if (cur->type != XML_DTD_NODE)
13824 continue;
13825 }
13826 }
13827
13828 if (cur == limit)
13829 break;
13830
13831 while (cur->next != NULL) {
13832 cur = cur->next;
13833 if ((cur->type != XML_ENTITY_DECL) &&
13834 (cur->type != XML_DTD_NODE))
13835 goto next_node;
13836 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000013837
Daniel Veillard56de87e2005-02-16 00:22:29 +000013838 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000013839 cur = cur->parent;
13840 depth--;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013841 if ((cur == NULL) || (cur == limit) ||
13842 (cur->type == XML_DOCUMENT_NODE))
Daniel Veillard56de87e2005-02-16 00:22:29 +000013843 goto done;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013844 if (cur->type == XML_ELEMENT_NODE) {
13845 ret = xmlStreamPop(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013846 } else if ((eval_all_nodes) &&
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013847 ((cur->type == XML_TEXT_NODE) ||
13848 (cur->type == XML_CDATA_SECTION_NODE) ||
13849 (cur->type == XML_COMMENT_NODE) ||
13850 (cur->type == XML_PI_NODE)))
13851 {
13852 ret = xmlStreamPop(patstream);
13853 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000013854 if (cur->next != NULL) {
13855 cur = cur->next;
13856 break;
13857 }
13858 } while (cur != NULL);
13859
13860 } while ((cur != NULL) && (depth >= 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013861
Daniel Veillard56de87e2005-02-16 00:22:29 +000013862done:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013863
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000013864#if 0
13865 printf("stream eval: checked %d nodes selected %d\n",
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013866 nb_nodes, retObj->nodesetval->nodeNr);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000013867#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013868
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000013869 if (patstream)
13870 xmlFreeStreamCtxt(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013871 return(0);
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000013872
13873return_1:
13874 if (patstream)
13875 xmlFreeStreamCtxt(patstream);
13876 return(1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000013877}
13878#endif /* XPATH_STREAMING */
13879
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013880/**
13881 * xmlXPathRunEval:
13882 * @ctxt: the XPath parser context with the compiled expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013883 * @toBool: evaluate to a boolean result
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013884 *
13885 * Evaluate the Precompiled XPath expression in the given context.
13886 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013887static int
13888xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
13889{
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013890 xmlXPathCompExprPtr comp;
13891
13892 if ((ctxt == NULL) || (ctxt->comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013893 return(-1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013894
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013895 ctxt->context->depth = 0;
13896
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013897 if (ctxt->valueTab == NULL) {
13898 /* Allocate the value stack */
Daniel Veillard45490ae2008-07-29 09:13:19 +000013899 ctxt->valueTab = (xmlXPathObjectPtr *)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013900 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
13901 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000013902 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013903 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013904 }
13905 ctxt->valueNr = 0;
13906 ctxt->valueMax = 10;
13907 ctxt->value = NULL;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013908 ctxt->valueFrame = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013909 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000013910#ifdef XPATH_STREAMING
13911 if (ctxt->comp->stream) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013912 int res;
13913
13914 if (toBool) {
13915 /*
13916 * Evaluation to boolean result.
13917 */
13918 res = xmlXPathRunStreamEval(ctxt->context,
13919 ctxt->comp->stream, NULL, 1);
13920 if (res != -1)
13921 return(res);
13922 } else {
Daniel Veillard45490ae2008-07-29 09:13:19 +000013923 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013924
13925 /*
13926 * Evaluation to a sequence.
13927 */
13928 res = xmlXPathRunStreamEval(ctxt->context,
13929 ctxt->comp->stream, &resObj, 0);
13930
13931 if ((res != -1) && (resObj != NULL)) {
13932 valuePush(ctxt, resObj);
13933 return(0);
13934 }
13935 if (resObj != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +000013936 xmlXPathReleaseObject(ctxt->context, resObj);
Daniel Veillard56de87e2005-02-16 00:22:29 +000013937 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013938 /*
13939 * QUESTION TODO: This falls back to normal XPath evaluation
13940 * if res == -1. Is this intended?
13941 */
Daniel Veillard56de87e2005-02-16 00:22:29 +000013942 }
13943#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013944 comp = ctxt->comp;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013945 if (comp->last < 0) {
Aleksey Sanin29b6f762002-05-05 06:59:57 +000013946 xmlGenericError(xmlGenericErrorContext,
13947 "xmlXPathRunEval: last is less than zero\n");
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013948 return(-1);
Aleksey Sanin29b6f762002-05-05 06:59:57 +000013949 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013950 if (toBool)
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013951 return(xmlXPathCompOpEvalToBoolean(ctxt,
13952 &comp->steps[comp->last], 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013953 else
13954 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
13955
13956 return(0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013957}
13958
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013959/************************************************************************
13960 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +000013961 * Public interfaces *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013962 * *
13963 ************************************************************************/
13964
13965/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000013966 * xmlXPathEvalPredicate:
13967 * @ctxt: the XPath context
13968 * @res: the Predicate Expression evaluation result
13969 *
13970 * Evaluate a predicate result for the current node.
13971 * A PredicateExpr is evaluated by evaluating the Expr and converting
13972 * the result to a boolean. If the result is a number, the result will
13973 * be converted to true if the number is equal to the position of the
13974 * context node in the context node list (as returned by the position
13975 * function) and will be converted to false otherwise; if the result
13976 * is not a number, then the result will be converted as if by a call
Daniel Veillard45490ae2008-07-29 09:13:19 +000013977 * to the boolean function.
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000013978 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013979 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000013980 */
13981int
13982xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000013983 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000013984 switch (res->type) {
13985 case XPATH_BOOLEAN:
13986 return(res->boolval);
13987 case XPATH_NUMBER:
13988 return(res->floatval == ctxt->proximityPosition);
13989 case XPATH_NODESET:
13990 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000013991 if (res->nodesetval == NULL)
13992 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000013993 return(res->nodesetval->nodeNr != 0);
13994 case XPATH_STRING:
13995 return((res->stringval != NULL) &&
13996 (xmlStrlen(res->stringval) != 0));
13997 default:
13998 STRANGE
13999 }
14000 return(0);
14001}
14002
14003/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014004 * xmlXPathEvaluatePredicateResult:
14005 * @ctxt: the XPath Parser context
14006 * @res: the Predicate Expression evaluation result
14007 *
14008 * Evaluate a predicate result for the current node.
14009 * A PredicateExpr is evaluated by evaluating the Expr and converting
14010 * the result to a boolean. If the result is a number, the result will
14011 * be converted to true if the number is equal to the position of the
14012 * context node in the context node list (as returned by the position
14013 * function) and will be converted to false otherwise; if the result
14014 * is not a number, then the result will be converted as if by a call
Daniel Veillard45490ae2008-07-29 09:13:19 +000014015 * to the boolean function.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014016 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014017 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014018 */
14019int
Daniel Veillard45490ae2008-07-29 09:13:19 +000014020xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014021 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014022 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014023 switch (res->type) {
14024 case XPATH_BOOLEAN:
14025 return(res->boolval);
14026 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000014027#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000014028 return((res->floatval == ctxt->context->proximityPosition) &&
14029 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000014030#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014031 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000014032#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014033 case XPATH_NODESET:
14034 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000014035 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000014036 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014037 return(res->nodesetval->nodeNr != 0);
14038 case XPATH_STRING:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014039 return((res->stringval != NULL) && (res->stringval[0] != 0));
William M. Brack08171912003-12-29 02:52:11 +000014040#ifdef LIBXML_XPTR_ENABLED
14041 case XPATH_LOCATIONSET:{
14042 xmlLocationSetPtr ptr = res->user;
14043 if (ptr == NULL)
14044 return(0);
14045 return (ptr->locNr != 0);
14046 }
14047#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014048 default:
14049 STRANGE
14050 }
14051 return(0);
14052}
14053
Daniel Veillard56de87e2005-02-16 00:22:29 +000014054#ifdef XPATH_STREAMING
14055/**
14056 * xmlXPathTryStreamCompile:
14057 * @ctxt: an XPath context
14058 * @str: the XPath expression
14059 *
14060 * Try to compile the XPath expression as a streamable subset.
14061 *
14062 * Returns the compiled expression or NULL if failed to compile.
14063 */
14064static xmlXPathCompExprPtr
14065xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14066 /*
14067 * Optimization: use streaming patterns when the XPath expression can
14068 * be compiled to a stream lookup
14069 */
14070 xmlPatternPtr stream;
14071 xmlXPathCompExprPtr comp;
14072 xmlDictPtr dict = NULL;
14073 const xmlChar **namespaces = NULL;
14074 xmlNsPtr ns;
14075 int i, j;
14076
14077 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14078 (!xmlStrchr(str, '@'))) {
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014079 const xmlChar *tmp;
14080
14081 /*
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014082 * We don't try to handle expressions using the verbose axis
Haibo Huangcfd91dc2020-07-30 23:01:33 -070014083 * specifiers ("::"), just the simplified form at this point.
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014084 * Additionally, if there is no list of namespaces available and
14085 * there's a ":" in the expression, indicating a prefixed QName,
14086 * then we won't try to compile either. xmlPatterncompile() needs
14087 * to have a list of namespaces at compilation time in order to
14088 * compile prefixed name tests.
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014089 */
14090 tmp = xmlStrchr(str, ':');
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014091 if ((tmp != NULL) &&
14092 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
Daniel Veillard45490ae2008-07-29 09:13:19 +000014093 return(NULL);
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014094
Daniel Veillard56de87e2005-02-16 00:22:29 +000014095 if (ctxt != NULL) {
14096 dict = ctxt->dict;
14097 if (ctxt->nsNr > 0) {
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000014098 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
Daniel Veillard56de87e2005-02-16 00:22:29 +000014099 if (namespaces == NULL) {
14100 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14101 return(NULL);
14102 }
14103 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14104 ns = ctxt->namespaces[j];
14105 namespaces[i++] = ns->href;
14106 namespaces[i++] = ns->prefix;
14107 }
14108 namespaces[i++] = NULL;
Daniel Veillard13cee4e2009-09-05 14:52:55 +020014109 namespaces[i] = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014110 }
14111 }
14112
Haibo Huangcfd91dc2020-07-30 23:01:33 -070014113 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces);
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014114 if (namespaces != NULL) {
14115 xmlFree((xmlChar **)namespaces);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014116 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014117 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14118 comp = xmlXPathNewCompExpr();
14119 if (comp == NULL) {
14120 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14121 return(NULL);
14122 }
14123 comp->stream = stream;
14124 comp->dict = dict;
14125 if (comp->dict)
14126 xmlDictReference(comp->dict);
14127 return(comp);
14128 }
14129 xmlFreePattern(stream);
14130 }
14131 return(NULL);
14132}
14133#endif /* XPATH_STREAMING */
14134
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014135static void
Haibo Huangcfd91dc2020-07-30 23:01:33 -070014136xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
14137 xmlXPathStepOpPtr op)
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014138{
Haibo Huangcfd91dc2020-07-30 23:01:33 -070014139 xmlXPathCompExprPtr comp = pctxt->comp;
14140 xmlXPathContextPtr ctxt;
14141
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014142 /*
14143 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14144 * internal representation.
14145 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014146
Nick Wellnhoferb4bcba22013-08-05 00:15:11 +020014147 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14148 (op->ch1 != -1) &&
14149 (op->ch2 == -1 /* no predicate */))
Nick Wellnhofer62270532012-08-19 19:42:38 +020014150 {
14151 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14152
14153 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14154 ((xmlXPathAxisVal) prevop->value ==
14155 AXIS_DESCENDANT_OR_SELF) &&
14156 (prevop->ch2 == -1) &&
14157 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14158 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14159 {
14160 /*
14161 * This is a "descendant-or-self::node()" without predicates.
14162 * Try to eliminate it.
14163 */
14164
14165 switch ((xmlXPathAxisVal) op->value) {
14166 case AXIS_CHILD:
14167 case AXIS_DESCENDANT:
14168 /*
14169 * Convert "descendant-or-self::node()/child::" or
14170 * "descendant-or-self::node()/descendant::" to
14171 * "descendant::"
14172 */
14173 op->ch1 = prevop->ch1;
14174 op->value = AXIS_DESCENDANT;
14175 break;
14176 case AXIS_SELF:
14177 case AXIS_DESCENDANT_OR_SELF:
14178 /*
14179 * Convert "descendant-or-self::node()/self::" or
14180 * "descendant-or-self::node()/descendant-or-self::" to
14181 * to "descendant-or-self::"
14182 */
14183 op->ch1 = prevop->ch1;
14184 op->value = AXIS_DESCENDANT_OR_SELF;
14185 break;
14186 default:
14187 break;
14188 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014189 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014190 }
Nick Wellnhofer62270532012-08-19 19:42:38 +020014191
Nick Wellnhofer839689a2016-04-27 18:00:12 +020014192 /* OP_VALUE has invalid ch1. */
14193 if (op->op == XPATH_OP_VALUE)
14194 return;
14195
Nick Wellnhofer62270532012-08-19 19:42:38 +020014196 /* Recurse */
Haibo Huangcfd91dc2020-07-30 23:01:33 -070014197 ctxt = pctxt->context;
14198 if (ctxt != NULL) {
Haibo Huangf0a546b2020-09-01 20:28:19 -070014199 if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
Haibo Huangcfd91dc2020-07-30 23:01:33 -070014200 return;
14201 ctxt->depth += 1;
14202 }
Nick Wellnhofer62270532012-08-19 19:42:38 +020014203 if (op->ch1 != -1)
Haibo Huangcfd91dc2020-07-30 23:01:33 -070014204 xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014205 if (op->ch2 != -1)
Haibo Huangcfd91dc2020-07-30 23:01:33 -070014206 xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
14207 if (ctxt != NULL)
14208 ctxt->depth -= 1;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014209}
14210
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014211/**
Daniel Veillard4773df22004-01-23 13:15:13 +000014212 * xmlXPathCtxtCompile:
14213 * @ctxt: an XPath context
14214 * @str: the XPath expression
14215 *
14216 * Compile an XPath expression
14217 *
14218 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14219 * the caller has to free the object.
14220 */
14221xmlXPathCompExprPtr
14222xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14223 xmlXPathParserContextPtr pctxt;
14224 xmlXPathCompExprPtr comp;
14225
Daniel Veillard56de87e2005-02-16 00:22:29 +000014226#ifdef XPATH_STREAMING
14227 comp = xmlXPathTryStreamCompile(ctxt, str);
14228 if (comp != NULL)
14229 return(comp);
14230#endif
14231
Haibo Huangd23e46c2020-10-28 22:26:09 -070014232 xmlInitParser();
Daniel Veillard4773df22004-01-23 13:15:13 +000014233
14234 pctxt = xmlXPathNewParserContext(str, ctxt);
William M. Brack11be2d02007-01-24 19:17:19 +000014235 if (pctxt == NULL)
14236 return NULL;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070014237 if (ctxt != NULL)
14238 ctxt->depth = 0;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014239 xmlXPathCompileExpr(pctxt, 1);
Daniel Veillard4773df22004-01-23 13:15:13 +000014240
14241 if( pctxt->error != XPATH_EXPRESSION_OK )
14242 {
14243 xmlXPathFreeParserContext(pctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000014244 return(NULL);
Daniel Veillard4773df22004-01-23 13:15:13 +000014245 }
14246
14247 if (*pctxt->cur != 0) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014248 /*
Daniel Veillard4773df22004-01-23 13:15:13 +000014249 * aleksey: in some cases this line prints *second* error message
14250 * (see bug #78858) and probably this should be fixed.
14251 * However, we are not sure that all error messages are printed
14252 * out in other places. It's not critical so we leave it as-is for now
14253 */
14254 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14255 comp = NULL;
14256 } else {
14257 comp = pctxt->comp;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070014258 if ((comp->nbStep > 1) && (comp->last >= 0)) {
14259 if (ctxt != NULL)
14260 ctxt->depth = 0;
14261 xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
14262 }
Daniel Veillard4773df22004-01-23 13:15:13 +000014263 pctxt->comp = NULL;
14264 }
14265 xmlXPathFreeParserContext(pctxt);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014266
Daniel Veillard4773df22004-01-23 13:15:13 +000014267 if (comp != NULL) {
14268 comp->expr = xmlStrdup(str);
14269#ifdef DEBUG_EVAL_COUNTS
14270 comp->string = xmlStrdup(str);
14271 comp->nb = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014272#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014273 }
Daniel Veillard4773df22004-01-23 13:15:13 +000014274 return(comp);
14275}
14276
14277/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014278 * xmlXPathCompile:
14279 * @str: the XPath expression
14280 *
14281 * Compile an XPath expression
14282 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000014283 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014284 * the caller has to free the object.
14285 */
14286xmlXPathCompExprPtr
14287xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000014288 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014289}
14290
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014291/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014292 * xmlXPathCompiledEvalInternal:
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014293 * @comp: the compiled XPath expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014294 * @ctxt: the XPath context
14295 * @resObj: the resulting XPath object or NULL
14296 * @toBool: 1 if only a boolean result is requested
Owen Taylor3473f882001-02-23 17:55:21 +000014297 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014298 * Evaluate the Precompiled XPath expression in the given context.
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014299 * The caller has to free @resObj.
Owen Taylor3473f882001-02-23 17:55:21 +000014300 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014301 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000014302 * the caller has to free the object.
14303 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014304static int
14305xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14306 xmlXPathContextPtr ctxt,
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014307 xmlXPathObjectPtr *resObjPtr,
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014308 int toBool)
14309{
Daniel Veillard45490ae2008-07-29 09:13:19 +000014310 xmlXPathParserContextPtr pctxt;
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014311 xmlXPathObjectPtr resObj;
Daniel Veillard81463942001-10-16 12:34:39 +000014312#ifndef LIBXML_THREAD_ENABLED
14313 static int reentance = 0;
14314#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014315 int res;
Owen Taylor3473f882001-02-23 17:55:21 +000014316
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014317 CHECK_CTXT_NEG(ctxt)
William M. Brackf13f77f2004-11-12 16:03:48 +000014318
14319 if (comp == NULL)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014320 return(-1);
Haibo Huangd23e46c2020-10-28 22:26:09 -070014321 xmlInitParser();
Owen Taylor3473f882001-02-23 17:55:21 +000014322
Daniel Veillard81463942001-10-16 12:34:39 +000014323#ifndef LIBXML_THREAD_ENABLED
14324 reentance++;
14325 if (reentance > 1)
14326 xmlXPathDisableOptimizer = 1;
14327#endif
14328
Daniel Veillardf06307e2001-07-03 10:35:50 +000014329#ifdef DEBUG_EVAL_COUNTS
14330 comp->nb++;
14331 if ((comp->string != NULL) && (comp->nb > 100)) {
14332 fprintf(stderr, "100 x %s\n", comp->string);
14333 comp->nb = 0;
14334 }
14335#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014336 pctxt = xmlXPathCompParserContext(comp, ctxt);
14337 res = xmlXPathRunEval(pctxt, toBool);
Owen Taylor3473f882001-02-23 17:55:21 +000014338
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014339 if (pctxt->error != XPATH_EXPRESSION_OK) {
14340 resObj = NULL;
14341 } else {
14342 resObj = valuePop(pctxt);
14343 if (resObj == NULL) {
Nick Wellnhofera07a4e92017-05-27 17:04:12 +020014344 if (!toBool)
14345 xmlGenericError(xmlGenericErrorContext,
14346 "xmlXPathCompiledEval: No result on the stack.\n");
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014347 } else if (pctxt->valueNr > 0) {
14348 xmlGenericError(xmlGenericErrorContext,
14349 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14350 pctxt->valueNr);
14351 }
Owen Taylor3473f882001-02-23 17:55:21 +000014352 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014353
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014354 if (resObjPtr)
14355 *resObjPtr = resObj;
14356 else
14357 xmlXPathReleaseObject(ctxt, resObj);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014358
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014359 pctxt->comp = NULL;
14360 xmlXPathFreeParserContext(pctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000014361#ifndef LIBXML_THREAD_ENABLED
14362 reentance--;
14363#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014364
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014365 return(res);
14366}
14367
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014368/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014369 * xmlXPathCompiledEval:
14370 * @comp: the compiled XPath expression
14371 * @ctx: the XPath context
14372 *
14373 * Evaluate the Precompiled XPath expression in the given context.
14374 *
14375 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14376 * the caller has to free the object.
14377 */
14378xmlXPathObjectPtr
14379xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14380{
14381 xmlXPathObjectPtr res = NULL;
14382
14383 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14384 return(res);
14385}
14386
14387/**
14388 * xmlXPathCompiledEvalToBoolean:
14389 * @comp: the compiled XPath expression
14390 * @ctxt: the XPath context
14391 *
14392 * Applies the XPath boolean() function on the result of the given
14393 * compiled expression.
14394 *
14395 * Returns 1 if the expression evaluated to true, 0 if to false and
14396 * -1 in API and internal errors.
14397 */
14398int
14399xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14400 xmlXPathContextPtr ctxt)
14401{
14402 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14403}
14404
14405/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014406 * xmlXPathEvalExpr:
14407 * @ctxt: the XPath Parser context
14408 *
14409 * Parse and evaluate an XPath expression in the given context,
14410 * then push the result on the context stack
14411 */
14412void
14413xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014414#ifdef XPATH_STREAMING
14415 xmlXPathCompExprPtr comp;
14416#endif
14417
Daniel Veillarda82b1822004-11-08 16:24:57 +000014418 if (ctxt == NULL) return;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014419
Daniel Veillard56de87e2005-02-16 00:22:29 +000014420#ifdef XPATH_STREAMING
14421 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14422 if (comp != NULL) {
14423 if (ctxt->comp != NULL)
14424 xmlXPathFreeCompExpr(ctxt->comp);
14425 ctxt->comp = comp;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014426 } else
14427#endif
14428 {
Haibo Huangcfd91dc2020-07-30 23:01:33 -070014429 if (ctxt->context != NULL)
14430 ctxt->context->depth = 0;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014431 xmlXPathCompileExpr(ctxt, 1);
Nick Wellnhoferaed407c2017-05-25 16:57:14 +020014432 CHECK_ERROR;
14433
14434 /* Check for trailing characters. */
14435 if (*ctxt->cur != 0)
14436 XP_ERROR(XPATH_EXPR_ERROR);
14437
Haibo Huangcfd91dc2020-07-30 23:01:33 -070014438 if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
14439 if (ctxt->context != NULL)
14440 ctxt->context->depth = 0;
14441 xmlXPathOptimizeExpression(ctxt,
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014442 &ctxt->comp->steps[ctxt->comp->last]);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070014443 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014444 }
Nick Wellnhoferaed407c2017-05-25 16:57:14 +020014445
Daniel Veillard45490ae2008-07-29 09:13:19 +000014446 xmlXPathRunEval(ctxt, 0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014447}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014448
14449/**
14450 * xmlXPathEval:
14451 * @str: the XPath expression
14452 * @ctx: the XPath context
14453 *
14454 * Evaluate the XPath Location Path in the given context.
14455 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014456 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014457 * the caller has to free the object.
14458 */
14459xmlXPathObjectPtr
14460xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14461 xmlXPathParserContextPtr ctxt;
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014462 xmlXPathObjectPtr res;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014463
William M. Brackf13f77f2004-11-12 16:03:48 +000014464 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014465
Haibo Huangd23e46c2020-10-28 22:26:09 -070014466 xmlInitParser();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014467
14468 ctxt = xmlXPathNewParserContext(str, ctx);
William M. Brack11be2d02007-01-24 19:17:19 +000014469 if (ctxt == NULL)
14470 return NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014471 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014472
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014473 if (ctxt->error != XPATH_EXPRESSION_OK) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014474 res = NULL;
14475 } else {
14476 res = valuePop(ctxt);
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014477 if (res == NULL) {
14478 xmlGenericError(xmlGenericErrorContext,
14479 "xmlXPathCompiledEval: No result on the stack.\n");
14480 } else if (ctxt->valueNr > 0) {
14481 xmlGenericError(xmlGenericErrorContext,
14482 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14483 ctxt->valueNr);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014484 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014485 }
14486
Owen Taylor3473f882001-02-23 17:55:21 +000014487 xmlXPathFreeParserContext(ctxt);
14488 return(res);
14489}
14490
14491/**
Alex Bligh28876af2013-03-23 17:23:27 +000014492 * xmlXPathSetContextNode:
14493 * @node: the node to to use as the context node
14494 * @ctx: the XPath context
14495 *
14496 * Sets 'node' as the context node. The node must be in the same
14497 * document as that associated with the context.
14498 *
14499 * Returns -1 in case of error or 0 if successful
14500 */
14501int
14502xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
14503 if ((node == NULL) || (ctx == NULL))
14504 return(-1);
14505
14506 if (node->doc == ctx->doc) {
14507 ctx->node = node;
14508 return(0);
14509 }
14510 return(-1);
14511}
14512
14513/**
14514 * xmlXPathNodeEval:
14515 * @node: the node to to use as the context node
14516 * @str: the XPath expression
14517 * @ctx: the XPath context
14518 *
14519 * Evaluate the XPath Location Path in the given context. The node 'node'
14520 * is set as the context node. The context node is not restored.
14521 *
14522 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14523 * the caller has to free the object.
14524 */
14525xmlXPathObjectPtr
14526xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
14527 if (str == NULL)
14528 return(NULL);
14529 if (xmlXPathSetContextNode(node, ctx) < 0)
14530 return(NULL);
14531 return(xmlXPathEval(str, ctx));
14532}
14533
14534/**
Owen Taylor3473f882001-02-23 17:55:21 +000014535 * xmlXPathEvalExpression:
14536 * @str: the XPath expression
14537 * @ctxt: the XPath context
14538 *
Daniel Veillarddbb828f2017-08-28 20:38:53 +020014539 * Alias for xmlXPathEval().
Owen Taylor3473f882001-02-23 17:55:21 +000014540 *
14541 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14542 * the caller has to free the object.
14543 */
14544xmlXPathObjectPtr
14545xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
Nick Wellnhofer640a3682017-05-27 14:59:49 +020014546 return(xmlXPathEval(str, ctxt));
Owen Taylor3473f882001-02-23 17:55:21 +000014547}
14548
Daniel Veillard42766c02002-08-22 20:52:17 +000014549/************************************************************************
14550 * *
14551 * Extra functions not pertaining to the XPath spec *
14552 * *
14553 ************************************************************************/
14554/**
14555 * xmlXPathEscapeUriFunction:
14556 * @ctxt: the XPath Parser context
14557 * @nargs: the number of arguments
14558 *
14559 * Implement the escape-uri() XPath function
14560 * string escape-uri(string $str, bool $escape-reserved)
14561 *
14562 * This function applies the URI escaping rules defined in section 2 of [RFC
14563 * 2396] to the string supplied as $uri-part, which typically represents all
14564 * or part of a URI. The effect of the function is to replace any special
14565 * character in the string by an escape sequence of the form %xx%yy...,
14566 * where xxyy... is the hexadecimal representation of the octets used to
14567 * represent the character in UTF-8.
14568 *
14569 * The set of characters that are escaped depends on the setting of the
14570 * boolean argument $escape-reserved.
14571 *
14572 * If $escape-reserved is true, all characters are escaped other than lower
14573 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14574 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14575 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14576 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14577 * A-F).
14578 *
14579 * If $escape-reserved is false, the behavior differs in that characters
14580 * referred to in [RFC 2396] as reserved characters are not escaped. These
14581 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
Daniel Veillard45490ae2008-07-29 09:13:19 +000014582 *
Daniel Veillard42766c02002-08-22 20:52:17 +000014583 * [RFC 2396] does not define whether escaped URIs should use lower case or
14584 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14585 * compared using string comparison functions, this function must always use
14586 * the upper-case letters A-F.
Daniel Veillard45490ae2008-07-29 09:13:19 +000014587 *
Daniel Veillard42766c02002-08-22 20:52:17 +000014588 * Generally, $escape-reserved should be set to true when escaping a string
14589 * that is to form a single part of a URI, and to false when escaping an
14590 * entire URI or URI reference.
Daniel Veillard45490ae2008-07-29 09:13:19 +000014591 *
14592 * In the case of non-ascii characters, the string is encoded according to
Daniel Veillard42766c02002-08-22 20:52:17 +000014593 * utf-8 and then converted according to RFC 2396.
14594 *
14595 * Examples
Daniel Veillard45490ae2008-07-29 09:13:19 +000014596 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
Daniel Veillard42766c02002-08-22 20:52:17 +000014597 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14598 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14599 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14600 *
14601 */
Daniel Veillard118aed72002-09-24 14:13:13 +000014602static void
Daniel Veillard42766c02002-08-22 20:52:17 +000014603xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14604 xmlXPathObjectPtr str;
14605 int escape_reserved;
Daniel Veillardade10f22012-07-12 09:43:27 +080014606 xmlBufPtr target;
Daniel Veillard42766c02002-08-22 20:52:17 +000014607 xmlChar *cptr;
14608 xmlChar escape[4];
Daniel Veillard45490ae2008-07-29 09:13:19 +000014609
Daniel Veillard42766c02002-08-22 20:52:17 +000014610 CHECK_ARITY(2);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014611
Daniel Veillard42766c02002-08-22 20:52:17 +000014612 escape_reserved = xmlXPathPopBoolean(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014613
Daniel Veillard42766c02002-08-22 20:52:17 +000014614 CAST_TO_STRING;
14615 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014616
Daniel Veillardade10f22012-07-12 09:43:27 +080014617 target = xmlBufCreate();
Daniel Veillard45490ae2008-07-29 09:13:19 +000014618
Daniel Veillard42766c02002-08-22 20:52:17 +000014619 escape[0] = '%';
14620 escape[3] = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014621
Daniel Veillard42766c02002-08-22 20:52:17 +000014622 if (target) {
14623 for (cptr = str->stringval; *cptr; cptr++) {
14624 if ((*cptr >= 'A' && *cptr <= 'Z') ||
14625 (*cptr >= 'a' && *cptr <= 'z') ||
14626 (*cptr >= '0' && *cptr <= '9') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000014627 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
Daniel Veillard42766c02002-08-22 20:52:17 +000014628 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
14629 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000014630 (*cptr == '%' &&
Daniel Veillard42766c02002-08-22 20:52:17 +000014631 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14632 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14633 (cptr[1] >= '0' && cptr[1] <= '9')) &&
14634 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14635 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14636 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14637 (!escape_reserved &&
14638 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
14639 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
14640 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
14641 *cptr == ','))) {
Daniel Veillardade10f22012-07-12 09:43:27 +080014642 xmlBufAdd(target, cptr, 1);
Daniel Veillard42766c02002-08-22 20:52:17 +000014643 } else {
14644 if ((*cptr >> 4) < 10)
14645 escape[1] = '0' + (*cptr >> 4);
14646 else
14647 escape[1] = 'A' - 10 + (*cptr >> 4);
14648 if ((*cptr & 0xF) < 10)
14649 escape[2] = '0' + (*cptr & 0xF);
14650 else
14651 escape[2] = 'A' - 10 + (*cptr & 0xF);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014652
Daniel Veillardade10f22012-07-12 09:43:27 +080014653 xmlBufAdd(target, &escape[0], 3);
Daniel Veillard42766c02002-08-22 20:52:17 +000014654 }
14655 }
14656 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014657 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +080014658 xmlBufContent(target)));
14659 xmlBufFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014660 xmlXPathReleaseObject(ctxt->context, str);
Daniel Veillard42766c02002-08-22 20:52:17 +000014661}
14662
Owen Taylor3473f882001-02-23 17:55:21 +000014663/**
14664 * xmlXPathRegisterAllFunctions:
14665 * @ctxt: the XPath context
14666 *
14667 * Registers all default XPath functions in this context
14668 */
14669void
14670xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
14671{
14672 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
14673 xmlXPathBooleanFunction);
14674 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
14675 xmlXPathCeilingFunction);
14676 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
14677 xmlXPathCountFunction);
14678 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
14679 xmlXPathConcatFunction);
14680 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
14681 xmlXPathContainsFunction);
14682 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
14683 xmlXPathIdFunction);
14684 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
14685 xmlXPathFalseFunction);
14686 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
14687 xmlXPathFloorFunction);
14688 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
14689 xmlXPathLastFunction);
14690 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
14691 xmlXPathLangFunction);
14692 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
14693 xmlXPathLocalNameFunction);
14694 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
14695 xmlXPathNotFunction);
14696 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
14697 xmlXPathNameFunction);
14698 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
14699 xmlXPathNamespaceURIFunction);
14700 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
14701 xmlXPathNormalizeFunction);
14702 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
14703 xmlXPathNumberFunction);
14704 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
14705 xmlXPathPositionFunction);
14706 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
14707 xmlXPathRoundFunction);
14708 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
14709 xmlXPathStringFunction);
14710 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
14711 xmlXPathStringLengthFunction);
14712 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
14713 xmlXPathStartsWithFunction);
14714 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
14715 xmlXPathSubstringFunction);
14716 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
14717 xmlXPathSubstringBeforeFunction);
14718 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
14719 xmlXPathSubstringAfterFunction);
14720 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
14721 xmlXPathSumFunction);
14722 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
14723 xmlXPathTrueFunction);
14724 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
14725 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000014726
14727 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
14728 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
14729 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000014730}
14731
14732#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +000014733#define bottom_xpath
14734#include "elfgcchack.h"