blob: 2850a1ac2980f770be52d1c2b014de78f1b2ef3b [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
Nick Wellnhofer8813f392017-09-21 00:11:26 +0200491#ifndef INFINITY
Elliott Hughes7fbecab2019-01-10 16:42:03 -0800492#define INFINITY (DBL_MAX * DBL_MAX)
Nick Wellnhofer8813f392017-09-21 00:11:26 +0200493#endif
494
Elliott Hughes7fbecab2019-01-10 16:42:03 -0800495#ifndef NAN
496#define NAN (INFINITY / INFINITY)
497#endif
498
499double xmlXPathNAN;
500double xmlXPathPINF;
501double xmlXPathNINF;
Owen Taylor3473f882001-02-23 17:55:21 +0000502
Owen Taylor3473f882001-02-23 17:55:21 +0000503/**
504 * xmlXPathInit:
505 *
506 * Initialize the XPath environment
507 */
508void
509xmlXPathInit(void) {
Elliott Hughes7fbecab2019-01-10 16:42:03 -0800510 xmlXPathNAN = NAN;
511 xmlXPathPINF = INFINITY;
512 xmlXPathNINF = -INFINITY;
Owen Taylor3473f882001-02-23 17:55:21 +0000513}
514
Daniel Veillardcda96922001-08-21 10:56:31 +0000515/**
516 * xmlXPathIsNaN:
517 * @val: a double value
518 *
Daniel Veillardcda96922001-08-21 10:56:31 +0000519 * Returns 1 if the value is a NaN, 0 otherwise
520 */
521int
522xmlXPathIsNaN(double val) {
Nick Wellnhofer8813f392017-09-21 00:11:26 +0200523#ifdef isnan
524 return isnan(val);
525#else
526 return !(val == val);
527#endif
Daniel Veillardcda96922001-08-21 10:56:31 +0000528}
529
530/**
531 * xmlXPathIsInf:
532 * @val: a double value
533 *
Nick Wellnhofer8813f392017-09-21 00:11:26 +0200534 * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
Daniel Veillardcda96922001-08-21 10:56:31 +0000535 */
536int
537xmlXPathIsInf(double val) {
Nick Wellnhofer8813f392017-09-21 00:11:26 +0200538#ifdef isinf
Nick Wellnhoferddbb0752017-11-27 14:30:19 +0100539 return isinf(val) ? (val > 0 ? 1 : -1) : 0;
Nick Wellnhofer8813f392017-09-21 00:11:26 +0200540#else
Elliott Hughes7fbecab2019-01-10 16:42:03 -0800541 if (val >= INFINITY)
Nick Wellnhofer8813f392017-09-21 00:11:26 +0200542 return 1;
Elliott Hughes7fbecab2019-01-10 16:42:03 -0800543 if (val <= -INFINITY)
Nick Wellnhofer8813f392017-09-21 00:11:26 +0200544 return -1;
545 return 0;
546#endif
Daniel Veillardcda96922001-08-21 10:56:31 +0000547}
548
Daniel Veillard4432df22003-09-28 18:58:27 +0000549#endif /* SCHEMAS or XPATH */
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000550
Nick Wellnhofer8813f392017-09-21 00:11:26 +0200551#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000552
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000553/*
554 * TODO: when compatibility allows remove all "fake node libxslt" strings
555 * the test should just be name[0] = ' '
556 */
Daniel Veillard074f37e2008-09-01 13:38:22 +0000557#ifdef DEBUG_XPATH_EXPRESSION
558#define DEBUG_STEP
559#define DEBUG_EXPR
560#define DEBUG_EVAL_COUNTS
561#endif
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000562
563static xmlNs xmlXPathXMLNamespaceStruct = {
564 NULL,
565 XML_NAMESPACE_DECL,
566 XML_XML_NAMESPACE,
567 BAD_CAST "xml",
William M. Brackee0b9822007-03-07 08:15:01 +0000568 NULL,
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000569 NULL
570};
571static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
572#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard45490ae2008-07-29 09:13:19 +0000573/*
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000574 * Optimizer is disabled only when threaded apps are detected while
575 * the library ain't compiled for thread safety.
576 */
577static int xmlXPathDisableOptimizer = 0;
578#endif
579
Owen Taylor3473f882001-02-23 17:55:21 +0000580/************************************************************************
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000581 * *
582 * Error handling routines *
583 * *
584 ************************************************************************/
585
Daniel Veillard24505b02005-07-28 23:49:35 +0000586/**
587 * XP_ERRORNULL:
588 * @X: the error code
589 *
590 * Macro to raise an XPath error and return NULL.
591 */
592#define XP_ERRORNULL(X) \
593 { xmlXPathErr(ctxt, X); return(NULL); }
594
William M. Brack08171912003-12-29 02:52:11 +0000595/*
596 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
597 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000598static const char *xmlXPathErrorMessages[] = {
599 "Ok\n",
600 "Number encoding\n",
601 "Unfinished literal\n",
602 "Start of literal\n",
603 "Expected $ for variable reference\n",
604 "Undefined variable\n",
605 "Invalid predicate\n",
606 "Invalid expression\n",
607 "Missing closing curly brace\n",
608 "Unregistered function\n",
609 "Invalid operand\n",
610 "Invalid type\n",
611 "Invalid number of arguments\n",
612 "Invalid context size\n",
613 "Invalid context position\n",
614 "Memory allocation error\n",
615 "Syntax error\n",
616 "Resource error\n",
617 "Sub resource error\n",
618 "Undefined namespace prefix\n",
619 "Encoding error\n",
Daniel Veillard57b25162004-11-06 14:50:18 +0000620 "Char out of XML range\n",
William M. Brackcd65bc92005-01-06 09:39:18 +0000621 "Invalid or incomplete context\n",
Jan Pokorný75801652013-12-19 15:09:14 +0100622 "Stack usage error\n",
Daniel Veillard47881282012-09-07 14:24:50 +0800623 "Forbidden variable\n",
Haibo Huangcfd91dc2020-07-30 23:01:33 -0700624 "Operation limit exceeded\n",
625 "Recursion limit exceeded\n",
William M. Brackcd65bc92005-01-06 09:39:18 +0000626 "?? Unknown error ??\n" /* Must be last in the list! */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000627};
William M. Brackcd65bc92005-01-06 09:39:18 +0000628#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
629 sizeof(xmlXPathErrorMessages[0])) - 1)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000630/**
631 * xmlXPathErrMemory:
632 * @ctxt: an XPath context
Haibo Huangcfd91dc2020-07-30 23:01:33 -0700633 * @extra: extra information
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000634 *
635 * Handle a redefinition of attribute error
636 */
637static void
638xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
639{
640 if (ctxt != NULL) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -0700641 xmlResetError(&ctxt->lastError);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000642 if (extra) {
643 xmlChar buf[200];
644
645 xmlStrPrintf(buf, 200,
David Kilzer4472c3a2016-05-13 15:13:17 +0800646 "Memory allocation failed : %s\n",
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000647 extra);
648 ctxt->lastError.message = (char *) xmlStrdup(buf);
649 } else {
650 ctxt->lastError.message = (char *)
651 xmlStrdup(BAD_CAST "Memory allocation failed\n");
652 }
653 ctxt->lastError.domain = XML_FROM_XPATH;
654 ctxt->lastError.code = XML_ERR_NO_MEMORY;
655 if (ctxt->error != NULL)
656 ctxt->error(ctxt->userData, &ctxt->lastError);
657 } else {
658 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000659 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000660 NULL, NULL, XML_FROM_XPATH,
661 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
662 extra, NULL, NULL, 0, 0,
663 "Memory allocation failed : %s\n", extra);
664 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000665 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000666 NULL, NULL, XML_FROM_XPATH,
667 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
668 NULL, NULL, NULL, 0, 0,
669 "Memory allocation failed\n");
670 }
671}
672
673/**
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000674 * xmlXPathPErrMemory:
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000675 * @ctxt: an XPath parser context
Haibo Huangcfd91dc2020-07-30 23:01:33 -0700676 * @extra: extra information
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000677 *
678 * Handle a redefinition of attribute error
679 */
680static void
681xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
682{
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000683 if (ctxt == NULL)
684 xmlXPathErrMemory(NULL, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000685 else {
686 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000687 xmlXPathErrMemory(ctxt->context, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000688 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000689}
690
691/**
692 * xmlXPathErr:
693 * @ctxt: a XPath parser context
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000694 * @error: the error code
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000695 *
William M. Brackcd65bc92005-01-06 09:39:18 +0000696 * Handle an XPath error
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000697 */
698void
699xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
700{
William M. Brackcd65bc92005-01-06 09:39:18 +0000701 if ((error < 0) || (error > MAXERRNO))
702 error = MAXERRNO;
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000703 if (ctxt == NULL) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000704 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000705 NULL, NULL, XML_FROM_XPATH,
706 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
707 XML_ERR_ERROR, NULL, 0,
708 NULL, NULL, NULL, 0, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200709 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000710 return;
711 }
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000712 ctxt->error = error;
713 if (ctxt->context == NULL) {
714 __xmlRaiseError(NULL, NULL, NULL,
715 NULL, NULL, XML_FROM_XPATH,
716 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
717 XML_ERR_ERROR, NULL, 0,
718 (const char *) ctxt->base, NULL, NULL,
719 ctxt->cur - ctxt->base, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200720 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000721 return;
722 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +0000723
724 /* cleanup current last error */
Daniel Veillard45490ae2008-07-29 09:13:19 +0000725 xmlResetError(&ctxt->context->lastError);
Aleksey Sanin1b2be102006-05-31 20:53:43 +0000726
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000727 ctxt->context->lastError.domain = XML_FROM_XPATH;
728 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
729 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000730 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000731 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
732 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
733 ctxt->context->lastError.node = ctxt->context->debugNode;
734 if (ctxt->context->error != NULL) {
735 ctxt->context->error(ctxt->context->userData,
736 &ctxt->context->lastError);
737 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000738 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000739 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
740 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
741 XML_ERR_ERROR, NULL, 0,
742 (const char *) ctxt->base, NULL, NULL,
743 ctxt->cur - ctxt->base, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200744 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000745 }
746
747}
748
749/**
750 * xmlXPatherror:
751 * @ctxt: the XPath Parser context
752 * @file: the file name
753 * @line: the line number
754 * @no: the error number
755 *
756 * Formats an error message.
757 */
758void
759xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
760 int line ATTRIBUTE_UNUSED, int no) {
761 xmlXPathErr(ctxt, no);
762}
763
Haibo Huangcfd91dc2020-07-30 23:01:33 -0700764/**
765 * xmlXPathCheckOpLimit:
766 * @ctxt: the XPath Parser context
767 * @opCount: the number of operations to be added
768 *
769 * Adds opCount to the running total of operations and returns -1 if the
770 * operation limit is exceeded. Returns 0 otherwise.
771 */
772static int
773xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
774 xmlXPathContextPtr xpctxt = ctxt->context;
775
776 if ((opCount > xpctxt->opLimit) ||
777 (xpctxt->opCount > xpctxt->opLimit - opCount)) {
778 xpctxt->opCount = xpctxt->opLimit;
779 xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
780 return(-1);
781 }
782
783 xpctxt->opCount += opCount;
784 return(0);
785}
786
787#define OP_LIMIT_EXCEEDED(ctxt, n) \
788 ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
789
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000790/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000791 * *
792 * Utilities *
793 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000794 ************************************************************************/
795
796/**
797 * xsltPointerList:
798 *
799 * Pointer-list for various purposes.
800 */
801typedef struct _xmlPointerList xmlPointerList;
802typedef xmlPointerList *xmlPointerListPtr;
803struct _xmlPointerList {
804 void **items;
805 int number;
806 int size;
807};
808/*
809* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
810* and here, we should make the functions public.
811*/
812static int
Daniel Veillard45490ae2008-07-29 09:13:19 +0000813xmlPointerListAddSize(xmlPointerListPtr list,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000814 void *item,
815 int initialSize)
816{
817 if (list->items == NULL) {
818 if (initialSize <= 0)
819 initialSize = 1;
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800820 list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000821 if (list->items == NULL) {
822 xmlXPathErrMemory(NULL,
823 "xmlPointerListCreate: allocating item\n");
824 return(-1);
825 }
826 list->number = 0;
827 list->size = initialSize;
828 } else if (list->size <= list->number) {
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800829 if (list->size > 50000000) {
830 xmlXPathErrMemory(NULL,
831 "xmlPointerListAddSize: re-allocating item\n");
832 return(-1);
833 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000834 list->size *= 2;
835 list->items = (void **) xmlRealloc(list->items,
836 list->size * sizeof(void *));
837 if (list->items == NULL) {
838 xmlXPathErrMemory(NULL,
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800839 "xmlPointerListAddSize: re-allocating item\n");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000840 list->size = 0;
841 return(-1);
842 }
843 }
844 list->items[list->number++] = item;
845 return(0);
846}
847
848/**
849 * xsltPointerListCreate:
850 *
851 * Creates an xsltPointerList structure.
852 *
853 * Returns a xsltPointerList structure or NULL in case of an error.
854 */
855static xmlPointerListPtr
856xmlPointerListCreate(int initialSize)
857{
858 xmlPointerListPtr ret;
859
860 ret = xmlMalloc(sizeof(xmlPointerList));
861 if (ret == NULL) {
862 xmlXPathErrMemory(NULL,
863 "xmlPointerListCreate: allocating item\n");
864 return (NULL);
865 }
866 memset(ret, 0, sizeof(xmlPointerList));
867 if (initialSize > 0) {
868 xmlPointerListAddSize(ret, NULL, initialSize);
869 ret->number = 0;
870 }
871 return (ret);
872}
873
874/**
875 * xsltPointerListFree:
876 *
877 * Frees the xsltPointerList structure. This does not free
878 * the content of the list.
879 */
880static void
881xmlPointerListFree(xmlPointerListPtr list)
882{
883 if (list == NULL)
884 return;
885 if (list->items != NULL)
886 xmlFree(list->items);
887 xmlFree(list);
888}
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000889
890/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000891 * *
892 * Parser Types *
893 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000894 ************************************************************************/
895
896/*
897 * Types are private:
898 */
899
900typedef enum {
901 XPATH_OP_END=0,
902 XPATH_OP_AND,
903 XPATH_OP_OR,
904 XPATH_OP_EQUAL,
905 XPATH_OP_CMP,
906 XPATH_OP_PLUS,
907 XPATH_OP_MULT,
908 XPATH_OP_UNION,
909 XPATH_OP_ROOT,
910 XPATH_OP_NODE,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000911 XPATH_OP_COLLECT,
Elliott Hughes7fbecab2019-01-10 16:42:03 -0800912 XPATH_OP_VALUE, /* 11 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000913 XPATH_OP_VARIABLE,
914 XPATH_OP_FUNCTION,
915 XPATH_OP_ARG,
916 XPATH_OP_PREDICATE,
Elliott Hughes7fbecab2019-01-10 16:42:03 -0800917 XPATH_OP_FILTER, /* 16 */
918 XPATH_OP_SORT /* 17 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000919#ifdef LIBXML_XPTR_ENABLED
920 ,XPATH_OP_RANGETO
921#endif
922} xmlXPathOp;
923
924typedef enum {
925 AXIS_ANCESTOR = 1,
926 AXIS_ANCESTOR_OR_SELF,
927 AXIS_ATTRIBUTE,
928 AXIS_CHILD,
929 AXIS_DESCENDANT,
930 AXIS_DESCENDANT_OR_SELF,
931 AXIS_FOLLOWING,
932 AXIS_FOLLOWING_SIBLING,
933 AXIS_NAMESPACE,
934 AXIS_PARENT,
935 AXIS_PRECEDING,
936 AXIS_PRECEDING_SIBLING,
Daniel Veillard45490ae2008-07-29 09:13:19 +0000937 AXIS_SELF
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000938} xmlXPathAxisVal;
939
940typedef enum {
941 NODE_TEST_NONE = 0,
942 NODE_TEST_TYPE = 1,
943 NODE_TEST_PI = 2,
944 NODE_TEST_ALL = 3,
945 NODE_TEST_NS = 4,
946 NODE_TEST_NAME = 5
947} xmlXPathTestVal;
948
949typedef enum {
950 NODE_TYPE_NODE = 0,
951 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
952 NODE_TYPE_TEXT = XML_TEXT_NODE,
Daniel Veillard45490ae2008-07-29 09:13:19 +0000953 NODE_TYPE_PI = XML_PI_NODE
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000954} xmlXPathTypeVal;
955
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000956typedef struct _xmlXPathStepOp xmlXPathStepOp;
957typedef xmlXPathStepOp *xmlXPathStepOpPtr;
958struct _xmlXPathStepOp {
William M. Brack08171912003-12-29 02:52:11 +0000959 xmlXPathOp op; /* The identifier of the operation */
960 int ch1; /* First child */
961 int ch2; /* Second child */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000962 int value;
963 int value2;
964 int value3;
965 void *value4;
966 void *value5;
Nick Wellnhofer229d1f92016-08-22 13:21:57 +0200967 xmlXPathFunction cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000968 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000969};
970
971struct _xmlXPathCompExpr {
William M. Brack08171912003-12-29 02:52:11 +0000972 int nbStep; /* Number of steps in this expression */
973 int maxStep; /* Maximum number of steps allocated */
974 xmlXPathStepOp *steps; /* ops for computation of this expression */
975 int last; /* index of last step in expression */
976 xmlChar *expr; /* the expression being computed */
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200977 xmlDictPtr dict; /* the dictionary to use if any */
Daniel Veillardf06307e2001-07-03 10:35:50 +0000978#ifdef DEBUG_EVAL_COUNTS
979 int nb;
980 xmlChar *string;
981#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000982#ifdef XPATH_STREAMING
983 xmlPatternPtr stream;
984#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000985};
986
987/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000988 * *
989 * Forward declarations *
990 * *
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +0000991 ************************************************************************/
992static void
993xmlXPathFreeValueTree(xmlNodeSetPtr obj);
994static void
995xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
996static int
997xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
998 xmlXPathStepOpPtr op, xmlNodePtr *first);
999static int
1000xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +00001001 xmlXPathStepOpPtr op,
1002 int isPredicate);
Nick Wellnhofere03f0a12017-11-09 16:42:47 +01001003static void
1004xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00001005
1006/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +00001007 * *
1008 * Parser Type functions *
1009 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001010 ************************************************************************/
1011
1012/**
1013 * xmlXPathNewCompExpr:
1014 *
1015 * Create a new Xpath component
1016 *
1017 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
1018 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001019static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001020xmlXPathNewCompExpr(void) {
1021 xmlXPathCompExprPtr cur;
1022
1023 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1024 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001025 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001026 return(NULL);
1027 }
1028 memset(cur, 0, sizeof(xmlXPathCompExpr));
1029 cur->maxStep = 10;
1030 cur->nbStep = 0;
1031 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1032 sizeof(xmlXPathStepOp));
1033 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001034 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001035 xmlFree(cur);
1036 return(NULL);
1037 }
1038 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1039 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +00001040#ifdef DEBUG_EVAL_COUNTS
1041 cur->nb = 0;
1042#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001043 return(cur);
1044}
1045
1046/**
1047 * xmlXPathFreeCompExpr:
1048 * @comp: an XPATH comp
1049 *
1050 * Free up the memory allocated by @comp
1051 */
1052void
Daniel Veillardf06307e2001-07-03 10:35:50 +00001053xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1054{
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001055 xmlXPathStepOpPtr op;
1056 int i;
1057
1058 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00001059 return;
Daniel Veillard4773df22004-01-23 13:15:13 +00001060 if (comp->dict == NULL) {
1061 for (i = 0; i < comp->nbStep; i++) {
1062 op = &comp->steps[i];
1063 if (op->value4 != NULL) {
1064 if (op->op == XPATH_OP_VALUE)
1065 xmlXPathFreeObject(op->value4);
1066 else
1067 xmlFree(op->value4);
1068 }
1069 if (op->value5 != NULL)
1070 xmlFree(op->value5);
1071 }
1072 } else {
1073 for (i = 0; i < comp->nbStep; i++) {
1074 op = &comp->steps[i];
1075 if (op->value4 != NULL) {
1076 if (op->op == XPATH_OP_VALUE)
1077 xmlXPathFreeObject(op->value4);
1078 }
1079 }
1080 xmlDictFree(comp->dict);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001081 }
1082 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00001083 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001084 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00001085#ifdef DEBUG_EVAL_COUNTS
1086 if (comp->string != NULL) {
1087 xmlFree(comp->string);
1088 }
1089#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +00001090#ifdef XPATH_STREAMING
1091 if (comp->stream != NULL) {
1092 xmlFreePatternList(comp->stream);
1093 }
1094#endif
Daniel Veillard118aed72002-09-24 14:13:13 +00001095 if (comp->expr != NULL) {
1096 xmlFree(comp->expr);
1097 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00001098
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001099 xmlFree(comp);
1100}
1101
1102/**
1103 * xmlXPathCompExprAdd:
1104 * @comp: the compiled expression
1105 * @ch1: first child index
1106 * @ch2: second child index
1107 * @op: an op
1108 * @value: the first int value
1109 * @value2: the second int value
1110 * @value3: the third int value
1111 * @value4: the first string value
1112 * @value5: the second string value
1113 *
William M. Brack08171912003-12-29 02:52:11 +00001114 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001115 *
1116 * Returns -1 in case of failure, the index otherwise
1117 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001118static int
Haibo Huangcfd91dc2020-07-30 23:01:33 -07001119xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001120 xmlXPathOp op, int value,
1121 int value2, int value3, void *value4, void *value5) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07001122 xmlXPathCompExprPtr comp = ctxt->comp;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001123 if (comp->nbStep >= comp->maxStep) {
1124 xmlXPathStepOp *real;
1125
Daniel Veillardcd852ad2012-07-30 10:12:18 +08001126 if (comp->maxStep >= XPATH_MAX_STEPS) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07001127 xmlXPathPErrMemory(ctxt, "adding step\n");
Daniel Veillardcd852ad2012-07-30 10:12:18 +08001128 return(-1);
1129 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001130 comp->maxStep *= 2;
1131 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1132 comp->maxStep * sizeof(xmlXPathStepOp));
1133 if (real == NULL) {
1134 comp->maxStep /= 2;
Haibo Huangcfd91dc2020-07-30 23:01:33 -07001135 xmlXPathPErrMemory(ctxt, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001136 return(-1);
1137 }
1138 comp->steps = real;
1139 }
1140 comp->last = comp->nbStep;
1141 comp->steps[comp->nbStep].ch1 = ch1;
1142 comp->steps[comp->nbStep].ch2 = ch2;
1143 comp->steps[comp->nbStep].op = op;
1144 comp->steps[comp->nbStep].value = value;
1145 comp->steps[comp->nbStep].value2 = value2;
1146 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +00001147 if ((comp->dict != NULL) &&
1148 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1149 (op == XPATH_OP_COLLECT))) {
1150 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +00001151 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +00001152 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +00001153 xmlFree(value4);
1154 } else
1155 comp->steps[comp->nbStep].value4 = NULL;
1156 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +00001157 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +00001158 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +00001159 xmlFree(value5);
1160 } else
1161 comp->steps[comp->nbStep].value5 = NULL;
1162 } else {
1163 comp->steps[comp->nbStep].value4 = value4;
1164 comp->steps[comp->nbStep].value5 = value5;
1165 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +00001166 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001167 return(comp->nbStep++);
1168}
1169
Daniel Veillardf06307e2001-07-03 10:35:50 +00001170/**
1171 * xmlXPathCompSwap:
1172 * @comp: the compiled expression
1173 * @op: operation index
1174 *
1175 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +00001176 */
1177static void
1178xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1179 int tmp;
1180
Daniel Veillardbc6f7592002-04-16 07:49:59 +00001181#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +00001182 /*
1183 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +00001184 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +00001185 * application
1186 */
1187 if (xmlXPathDisableOptimizer)
1188 return;
1189#endif
1190
Daniel Veillardf06307e2001-07-03 10:35:50 +00001191 tmp = op->ch1;
1192 op->ch1 = op->ch2;
1193 op->ch2 = tmp;
1194}
1195
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001196#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
Haibo Huangcfd91dc2020-07-30 23:01:33 -07001197 xmlXPathCompExprAdd(ctxt, (op1), (op2), \
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001198 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001199#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
Haibo Huangcfd91dc2020-07-30 23:01:33 -07001200 xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1, \
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001201 (op), (val), (val2), (val3), (val4), (val5))
1202
Daniel Veillard45490ae2008-07-29 09:13:19 +00001203#define PUSH_LEAVE_EXPR(op, val, val2) \
Haibo Huangcfd91dc2020-07-30 23:01:33 -07001204xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001205
Daniel Veillard45490ae2008-07-29 09:13:19 +00001206#define PUSH_UNARY_EXPR(op, ch, val, val2) \
Haibo Huangcfd91dc2020-07-30 23:01:33 -07001207xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001208
Daniel Veillard45490ae2008-07-29 09:13:19 +00001209#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
Haibo Huangcfd91dc2020-07-30 23:01:33 -07001210xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op), \
William M. Brack08171912003-12-29 02:52:11 +00001211 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001212
1213/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +00001214 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +00001215 * XPath object cache structures *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001216 * *
1217 ************************************************************************/
1218
1219/* #define XP_DEFAULT_CACHE_ON */
1220
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001221#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001222
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001223typedef struct _xmlXPathContextCache xmlXPathContextCache;
1224typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1225struct _xmlXPathContextCache {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00001226 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
1227 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
1228 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
1229 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
1230 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001231 int maxNodeset;
1232 int maxString;
1233 int maxBoolean;
1234 int maxNumber;
1235 int maxMisc;
1236#ifdef XP_DEBUG_OBJ_USAGE
1237 int dbgCachedAll;
1238 int dbgCachedNodeset;
1239 int dbgCachedString;
1240 int dbgCachedBool;
1241 int dbgCachedNumber;
1242 int dbgCachedPoint;
1243 int dbgCachedRange;
1244 int dbgCachedLocset;
1245 int dbgCachedUsers;
1246 int dbgCachedXSLTTree;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001247 int dbgCachedUndefined;
1248
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001249
1250 int dbgReusedAll;
1251 int dbgReusedNodeset;
1252 int dbgReusedString;
1253 int dbgReusedBool;
1254 int dbgReusedNumber;
1255 int dbgReusedPoint;
1256 int dbgReusedRange;
1257 int dbgReusedLocset;
1258 int dbgReusedUsers;
1259 int dbgReusedXSLTTree;
1260 int dbgReusedUndefined;
1261
1262#endif
1263};
1264
1265/************************************************************************
1266 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +00001267 * Debugging related functions *
Owen Taylor3473f882001-02-23 17:55:21 +00001268 * *
1269 ************************************************************************/
1270
Daniel Veillard45490ae2008-07-29 09:13:19 +00001271#define STRANGE \
Owen Taylor3473f882001-02-23 17:55:21 +00001272 xmlGenericError(xmlGenericErrorContext, \
1273 "Internal error at %s:%d\n", \
1274 __FILE__, __LINE__);
1275
1276#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001277static void
1278xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001279 int i;
1280 char shift[100];
1281
1282 for (i = 0;((i < depth) && (i < 25));i++)
1283 shift[2 * i] = shift[2 * i + 1] = ' ';
1284 shift[2 * i] = shift[2 * i + 1] = 0;
1285 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001286 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001287 fprintf(output, "Node is NULL !\n");
1288 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001289
Owen Taylor3473f882001-02-23 17:55:21 +00001290 }
1291
1292 if ((cur->type == XML_DOCUMENT_NODE) ||
1293 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001294 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001295 fprintf(output, " /\n");
1296 } else if (cur->type == XML_ATTRIBUTE_NODE)
1297 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1298 else
1299 xmlDebugDumpOneNode(output, cur, depth);
1300}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001301static void
1302xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001303 xmlNodePtr tmp;
1304 int i;
1305 char shift[100];
1306
1307 for (i = 0;((i < depth) && (i < 25));i++)
1308 shift[2 * i] = shift[2 * i + 1] = ' ';
1309 shift[2 * i] = shift[2 * i + 1] = 0;
1310 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001311 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001312 fprintf(output, "Node is NULL !\n");
1313 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001314
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001315 }
1316
1317 while (cur != NULL) {
1318 tmp = cur;
1319 cur = cur->next;
1320 xmlDebugDumpOneNode(output, tmp, depth);
1321 }
1322}
Owen Taylor3473f882001-02-23 17:55:21 +00001323
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001324static void
1325xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001326 int i;
1327 char shift[100];
1328
1329 for (i = 0;((i < depth) && (i < 25));i++)
1330 shift[2 * i] = shift[2 * i + 1] = ' ';
1331 shift[2 * i] = shift[2 * i + 1] = 0;
1332
1333 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001334 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001335 fprintf(output, "NodeSet is NULL !\n");
1336 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001337
Owen Taylor3473f882001-02-23 17:55:21 +00001338 }
1339
Daniel Veillard911f49a2001-04-07 15:39:35 +00001340 if (cur != NULL) {
1341 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1342 for (i = 0;i < cur->nodeNr;i++) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001343 fprintf(output, "%s", shift);
Daniel Veillard911f49a2001-04-07 15:39:35 +00001344 fprintf(output, "%d", i + 1);
1345 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1346 }
Owen Taylor3473f882001-02-23 17:55:21 +00001347 }
1348}
1349
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001350static void
1351xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001352 int i;
1353 char shift[100];
1354
1355 for (i = 0;((i < depth) && (i < 25));i++)
1356 shift[2 * i] = shift[2 * i + 1] = ' ';
1357 shift[2 * i] = shift[2 * i + 1] = 0;
1358
1359 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001360 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001361 fprintf(output, "Value Tree is NULL !\n");
1362 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001363
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001364 }
1365
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001366 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001367 fprintf(output, "%d", i + 1);
1368 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1369}
Owen Taylor3473f882001-02-23 17:55:21 +00001370#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001371static void
1372xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001373 int i;
1374 char shift[100];
1375
1376 for (i = 0;((i < depth) && (i < 25));i++)
1377 shift[2 * i] = shift[2 * i + 1] = ' ';
1378 shift[2 * i] = shift[2 * i + 1] = 0;
1379
1380 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001381 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001382 fprintf(output, "LocationSet is NULL !\n");
1383 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001384
Owen Taylor3473f882001-02-23 17:55:21 +00001385 }
1386
1387 for (i = 0;i < cur->locNr;i++) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001388 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001389 fprintf(output, "%d : ", i + 1);
1390 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1391 }
1392}
Daniel Veillard017b1082001-06-21 11:20:21 +00001393#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001394
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00001395/**
1396 * xmlXPathDebugDumpObject:
1397 * @output: the FILE * to dump the output
1398 * @cur: the object to inspect
1399 * @depth: indentation level
1400 *
1401 * Dump the content of the object for debugging purposes
1402 */
1403void
1404xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001405 int i;
1406 char shift[100];
1407
Daniel Veillarda82b1822004-11-08 16:24:57 +00001408 if (output == NULL) return;
1409
Owen Taylor3473f882001-02-23 17:55:21 +00001410 for (i = 0;((i < depth) && (i < 25));i++)
1411 shift[2 * i] = shift[2 * i + 1] = ' ';
1412 shift[2 * i] = shift[2 * i + 1] = 0;
1413
Kasimier T. Buchcik97258712006-01-05 12:30:43 +00001414
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001415 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001416
1417 if (cur == NULL) {
1418 fprintf(output, "Object is empty (NULL)\n");
1419 return;
1420 }
1421 switch(cur->type) {
1422 case XPATH_UNDEFINED:
1423 fprintf(output, "Object is uninitialized\n");
1424 break;
1425 case XPATH_NODESET:
1426 fprintf(output, "Object is a Node Set :\n");
1427 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1428 break;
1429 case XPATH_XSLT_TREE:
1430 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001431 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +00001432 break;
1433 case XPATH_BOOLEAN:
1434 fprintf(output, "Object is a Boolean : ");
1435 if (cur->boolval) fprintf(output, "true\n");
1436 else fprintf(output, "false\n");
1437 break;
1438 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +00001439 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001440 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001441 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001442 break;
1443 case -1:
1444 fprintf(output, "Object is a number : -Infinity\n");
1445 break;
1446 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001447 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001448 fprintf(output, "Object is a number : NaN\n");
Nick Wellnhofer8813f392017-09-21 00:11:26 +02001449 } else if (cur->floatval == 0) {
1450 /* Omit sign for negative zero. */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001451 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001452 } else {
1453 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1454 }
1455 }
Owen Taylor3473f882001-02-23 17:55:21 +00001456 break;
1457 case XPATH_STRING:
1458 fprintf(output, "Object is a string : ");
1459 xmlDebugDumpString(output, cur->stringval);
1460 fprintf(output, "\n");
1461 break;
1462 case XPATH_POINT:
1463 fprintf(output, "Object is a point : index %d in node", cur->index);
1464 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1465 fprintf(output, "\n");
1466 break;
1467 case XPATH_RANGE:
1468 if ((cur->user2 == NULL) ||
1469 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1470 fprintf(output, "Object is a collapsed range :\n");
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001471 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001472 if (cur->index >= 0)
1473 fprintf(output, "index %d in ", cur->index);
1474 fprintf(output, "node\n");
1475 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1476 depth + 1);
1477 } else {
1478 fprintf(output, "Object is a range :\n");
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001479 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001480 fprintf(output, "From ");
1481 if (cur->index >= 0)
1482 fprintf(output, "index %d in ", cur->index);
1483 fprintf(output, "node\n");
1484 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1485 depth + 1);
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001486 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001487 fprintf(output, "To ");
1488 if (cur->index2 >= 0)
1489 fprintf(output, "index %d in ", cur->index2);
1490 fprintf(output, "node\n");
1491 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1492 depth + 1);
1493 fprintf(output, "\n");
1494 }
1495 break;
1496 case XPATH_LOCATIONSET:
1497#if defined(LIBXML_XPTR_ENABLED)
1498 fprintf(output, "Object is a Location Set:\n");
1499 xmlXPathDebugDumpLocationSet(output,
1500 (xmlLocationSetPtr) cur->user, depth);
1501#endif
1502 break;
1503 case XPATH_USERS:
1504 fprintf(output, "Object is user defined\n");
1505 break;
1506 }
1507}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001508
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001509static void
1510xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001511 xmlXPathStepOpPtr op, int depth) {
1512 int i;
1513 char shift[100];
1514
1515 for (i = 0;((i < depth) && (i < 25));i++)
1516 shift[2 * i] = shift[2 * i + 1] = ' ';
1517 shift[2 * i] = shift[2 * i + 1] = 0;
1518
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001519 fprintf(output, "%s", shift);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001520 if (op == NULL) {
1521 fprintf(output, "Step is NULL\n");
1522 return;
1523 }
1524 switch (op->op) {
1525 case XPATH_OP_END:
1526 fprintf(output, "END"); break;
1527 case XPATH_OP_AND:
1528 fprintf(output, "AND"); break;
1529 case XPATH_OP_OR:
1530 fprintf(output, "OR"); break;
1531 case XPATH_OP_EQUAL:
1532 if (op->value)
1533 fprintf(output, "EQUAL =");
1534 else
1535 fprintf(output, "EQUAL !=");
1536 break;
1537 case XPATH_OP_CMP:
1538 if (op->value)
1539 fprintf(output, "CMP <");
1540 else
1541 fprintf(output, "CMP >");
1542 if (!op->value2)
1543 fprintf(output, "=");
1544 break;
1545 case XPATH_OP_PLUS:
1546 if (op->value == 0)
1547 fprintf(output, "PLUS -");
1548 else if (op->value == 1)
1549 fprintf(output, "PLUS +");
1550 else if (op->value == 2)
1551 fprintf(output, "PLUS unary -");
1552 else if (op->value == 3)
1553 fprintf(output, "PLUS unary - -");
1554 break;
1555 case XPATH_OP_MULT:
1556 if (op->value == 0)
1557 fprintf(output, "MULT *");
1558 else if (op->value == 1)
1559 fprintf(output, "MULT div");
1560 else
1561 fprintf(output, "MULT mod");
1562 break;
1563 case XPATH_OP_UNION:
1564 fprintf(output, "UNION"); break;
1565 case XPATH_OP_ROOT:
1566 fprintf(output, "ROOT"); break;
1567 case XPATH_OP_NODE:
1568 fprintf(output, "NODE"); break;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001569 case XPATH_OP_SORT:
1570 fprintf(output, "SORT"); break;
1571 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +00001572 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1573 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1574 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001575 const xmlChar *prefix = op->value4;
1576 const xmlChar *name = op->value5;
1577
1578 fprintf(output, "COLLECT ");
1579 switch (axis) {
1580 case AXIS_ANCESTOR:
1581 fprintf(output, " 'ancestors' "); break;
1582 case AXIS_ANCESTOR_OR_SELF:
1583 fprintf(output, " 'ancestors-or-self' "); break;
1584 case AXIS_ATTRIBUTE:
1585 fprintf(output, " 'attributes' "); break;
1586 case AXIS_CHILD:
1587 fprintf(output, " 'child' "); break;
1588 case AXIS_DESCENDANT:
1589 fprintf(output, " 'descendant' "); break;
1590 case AXIS_DESCENDANT_OR_SELF:
1591 fprintf(output, " 'descendant-or-self' "); break;
1592 case AXIS_FOLLOWING:
1593 fprintf(output, " 'following' "); break;
1594 case AXIS_FOLLOWING_SIBLING:
1595 fprintf(output, " 'following-siblings' "); break;
1596 case AXIS_NAMESPACE:
1597 fprintf(output, " 'namespace' "); break;
1598 case AXIS_PARENT:
1599 fprintf(output, " 'parent' "); break;
1600 case AXIS_PRECEDING:
1601 fprintf(output, " 'preceding' "); break;
1602 case AXIS_PRECEDING_SIBLING:
1603 fprintf(output, " 'preceding-sibling' "); break;
1604 case AXIS_SELF:
1605 fprintf(output, " 'self' "); break;
1606 }
1607 switch (test) {
1608 case NODE_TEST_NONE:
1609 fprintf(output, "'none' "); break;
1610 case NODE_TEST_TYPE:
1611 fprintf(output, "'type' "); break;
1612 case NODE_TEST_PI:
1613 fprintf(output, "'PI' "); break;
1614 case NODE_TEST_ALL:
1615 fprintf(output, "'all' "); break;
1616 case NODE_TEST_NS:
1617 fprintf(output, "'namespace' "); break;
1618 case NODE_TEST_NAME:
1619 fprintf(output, "'name' "); break;
1620 }
1621 switch (type) {
1622 case NODE_TYPE_NODE:
1623 fprintf(output, "'node' "); break;
1624 case NODE_TYPE_COMMENT:
1625 fprintf(output, "'comment' "); break;
1626 case NODE_TYPE_TEXT:
1627 fprintf(output, "'text' "); break;
1628 case NODE_TYPE_PI:
1629 fprintf(output, "'PI' "); break;
1630 }
1631 if (prefix != NULL)
1632 fprintf(output, "%s:", prefix);
1633 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001634 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001635 break;
1636
1637 }
1638 case XPATH_OP_VALUE: {
1639 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1640
1641 fprintf(output, "ELEM ");
1642 xmlXPathDebugDumpObject(output, object, 0);
1643 goto finish;
1644 }
1645 case XPATH_OP_VARIABLE: {
1646 const xmlChar *prefix = op->value5;
1647 const xmlChar *name = op->value4;
1648
1649 if (prefix != NULL)
1650 fprintf(output, "VARIABLE %s:%s", prefix, name);
1651 else
1652 fprintf(output, "VARIABLE %s", name);
1653 break;
1654 }
1655 case XPATH_OP_FUNCTION: {
1656 int nbargs = op->value;
1657 const xmlChar *prefix = op->value5;
1658 const xmlChar *name = op->value4;
1659
1660 if (prefix != NULL)
1661 fprintf(output, "FUNCTION %s:%s(%d args)",
1662 prefix, name, nbargs);
1663 else
1664 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1665 break;
1666 }
1667 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1668 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001669 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001670#ifdef LIBXML_XPTR_ENABLED
1671 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1672#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001673 default:
1674 fprintf(output, "UNKNOWN %d\n", op->op); return;
1675 }
1676 fprintf(output, "\n");
1677finish:
1678 if (op->ch1 >= 0)
1679 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1680 if (op->ch2 >= 0)
1681 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1682}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001683
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001684/**
1685 * xmlXPathDebugDumpCompExpr:
1686 * @output: the FILE * for the output
1687 * @comp: the precompiled XPath expression
1688 * @depth: the indentation level.
1689 *
1690 * Dumps the tree of the compiled XPath expression.
1691 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001692void
1693xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1694 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001695 int i;
1696 char shift[100];
1697
Daniel Veillarda82b1822004-11-08 16:24:57 +00001698 if ((output == NULL) || (comp == NULL)) return;
1699
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001700 for (i = 0;((i < depth) && (i < 25));i++)
1701 shift[2 * i] = shift[2 * i + 1] = ' ';
1702 shift[2 * i] = shift[2 * i + 1] = 0;
1703
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001704 fprintf(output, "%s", shift);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001705
Nick Wellnhoferca8635b2017-09-07 15:46:12 +02001706#ifdef XPATH_STREAMING
1707 if (comp->stream) {
1708 fprintf(output, "Streaming Expression\n");
1709 } else
1710#endif
1711 {
1712 fprintf(output, "Compiled Expression : %d elements\n",
1713 comp->nbStep);
1714 i = comp->last;
1715 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1716 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001717}
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001718
1719#ifdef XP_DEBUG_OBJ_USAGE
1720
1721/*
1722* XPath object usage related debugging variables.
1723*/
1724static int xmlXPathDebugObjCounterUndefined = 0;
1725static int xmlXPathDebugObjCounterNodeset = 0;
1726static int xmlXPathDebugObjCounterBool = 0;
1727static int xmlXPathDebugObjCounterNumber = 0;
1728static int xmlXPathDebugObjCounterString = 0;
1729static int xmlXPathDebugObjCounterPoint = 0;
1730static int xmlXPathDebugObjCounterRange = 0;
1731static int xmlXPathDebugObjCounterLocset = 0;
1732static int xmlXPathDebugObjCounterUsers = 0;
1733static int xmlXPathDebugObjCounterXSLTTree = 0;
1734static int xmlXPathDebugObjCounterAll = 0;
1735
1736static int xmlXPathDebugObjTotalUndefined = 0;
1737static int xmlXPathDebugObjTotalNodeset = 0;
1738static int xmlXPathDebugObjTotalBool = 0;
1739static int xmlXPathDebugObjTotalNumber = 0;
1740static int xmlXPathDebugObjTotalString = 0;
1741static int xmlXPathDebugObjTotalPoint = 0;
1742static int xmlXPathDebugObjTotalRange = 0;
1743static int xmlXPathDebugObjTotalLocset = 0;
1744static int xmlXPathDebugObjTotalUsers = 0;
1745static int xmlXPathDebugObjTotalXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001746static int xmlXPathDebugObjTotalAll = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001747
1748static int xmlXPathDebugObjMaxUndefined = 0;
1749static int xmlXPathDebugObjMaxNodeset = 0;
1750static int xmlXPathDebugObjMaxBool = 0;
1751static int xmlXPathDebugObjMaxNumber = 0;
1752static int xmlXPathDebugObjMaxString = 0;
1753static int xmlXPathDebugObjMaxPoint = 0;
1754static int xmlXPathDebugObjMaxRange = 0;
1755static int xmlXPathDebugObjMaxLocset = 0;
1756static int xmlXPathDebugObjMaxUsers = 0;
1757static int xmlXPathDebugObjMaxXSLTTree = 0;
1758static int xmlXPathDebugObjMaxAll = 0;
1759
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001760static void
1761xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1762{
1763 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001764 if (ctxt->cache != NULL) {
1765 xmlXPathContextCachePtr cache =
1766 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001767
1768 cache->dbgCachedAll = 0;
1769 cache->dbgCachedNodeset = 0;
1770 cache->dbgCachedString = 0;
1771 cache->dbgCachedBool = 0;
1772 cache->dbgCachedNumber = 0;
1773 cache->dbgCachedPoint = 0;
1774 cache->dbgCachedRange = 0;
1775 cache->dbgCachedLocset = 0;
1776 cache->dbgCachedUsers = 0;
1777 cache->dbgCachedXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001778 cache->dbgCachedUndefined = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001779
1780 cache->dbgReusedAll = 0;
1781 cache->dbgReusedNodeset = 0;
1782 cache->dbgReusedString = 0;
1783 cache->dbgReusedBool = 0;
1784 cache->dbgReusedNumber = 0;
1785 cache->dbgReusedPoint = 0;
1786 cache->dbgReusedRange = 0;
1787 cache->dbgReusedLocset = 0;
1788 cache->dbgReusedUsers = 0;
1789 cache->dbgReusedXSLTTree = 0;
1790 cache->dbgReusedUndefined = 0;
1791 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00001792 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001793
1794 xmlXPathDebugObjCounterUndefined = 0;
1795 xmlXPathDebugObjCounterNodeset = 0;
1796 xmlXPathDebugObjCounterBool = 0;
1797 xmlXPathDebugObjCounterNumber = 0;
1798 xmlXPathDebugObjCounterString = 0;
1799 xmlXPathDebugObjCounterPoint = 0;
1800 xmlXPathDebugObjCounterRange = 0;
1801 xmlXPathDebugObjCounterLocset = 0;
1802 xmlXPathDebugObjCounterUsers = 0;
1803 xmlXPathDebugObjCounterXSLTTree = 0;
1804 xmlXPathDebugObjCounterAll = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001805
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001806 xmlXPathDebugObjTotalUndefined = 0;
1807 xmlXPathDebugObjTotalNodeset = 0;
1808 xmlXPathDebugObjTotalBool = 0;
1809 xmlXPathDebugObjTotalNumber = 0;
1810 xmlXPathDebugObjTotalString = 0;
1811 xmlXPathDebugObjTotalPoint = 0;
1812 xmlXPathDebugObjTotalRange = 0;
1813 xmlXPathDebugObjTotalLocset = 0;
1814 xmlXPathDebugObjTotalUsers = 0;
1815 xmlXPathDebugObjTotalXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001816 xmlXPathDebugObjTotalAll = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001817
1818 xmlXPathDebugObjMaxUndefined = 0;
1819 xmlXPathDebugObjMaxNodeset = 0;
1820 xmlXPathDebugObjMaxBool = 0;
1821 xmlXPathDebugObjMaxNumber = 0;
1822 xmlXPathDebugObjMaxString = 0;
1823 xmlXPathDebugObjMaxPoint = 0;
1824 xmlXPathDebugObjMaxRange = 0;
1825 xmlXPathDebugObjMaxLocset = 0;
1826 xmlXPathDebugObjMaxUsers = 0;
1827 xmlXPathDebugObjMaxXSLTTree = 0;
1828 xmlXPathDebugObjMaxAll = 0;
1829
1830}
1831
1832static void
1833xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1834 xmlXPathObjectType objType)
1835{
1836 int isCached = 0;
1837
1838 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001839 if (ctxt->cache != NULL) {
1840 xmlXPathContextCachePtr cache =
1841 (xmlXPathContextCachePtr) ctxt->cache;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001842
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001843 isCached = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001844
1845 cache->dbgReusedAll++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001846 switch (objType) {
1847 case XPATH_UNDEFINED:
1848 cache->dbgReusedUndefined++;
1849 break;
1850 case XPATH_NODESET:
1851 cache->dbgReusedNodeset++;
1852 break;
1853 case XPATH_BOOLEAN:
1854 cache->dbgReusedBool++;
1855 break;
1856 case XPATH_NUMBER:
1857 cache->dbgReusedNumber++;
1858 break;
1859 case XPATH_STRING:
1860 cache->dbgReusedString++;
1861 break;
1862 case XPATH_POINT:
1863 cache->dbgReusedPoint++;
1864 break;
1865 case XPATH_RANGE:
1866 cache->dbgReusedRange++;
1867 break;
1868 case XPATH_LOCATIONSET:
1869 cache->dbgReusedLocset++;
1870 break;
1871 case XPATH_USERS:
1872 cache->dbgReusedUsers++;
1873 break;
1874 case XPATH_XSLT_TREE:
1875 cache->dbgReusedXSLTTree++;
1876 break;
1877 default:
1878 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001879 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001880 }
1881 }
1882
1883 switch (objType) {
1884 case XPATH_UNDEFINED:
1885 if (! isCached)
1886 xmlXPathDebugObjTotalUndefined++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001887 xmlXPathDebugObjCounterUndefined++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001888 if (xmlXPathDebugObjCounterUndefined >
1889 xmlXPathDebugObjMaxUndefined)
1890 xmlXPathDebugObjMaxUndefined =
1891 xmlXPathDebugObjCounterUndefined;
1892 break;
1893 case XPATH_NODESET:
1894 if (! isCached)
1895 xmlXPathDebugObjTotalNodeset++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001896 xmlXPathDebugObjCounterNodeset++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001897 if (xmlXPathDebugObjCounterNodeset >
1898 xmlXPathDebugObjMaxNodeset)
1899 xmlXPathDebugObjMaxNodeset =
1900 xmlXPathDebugObjCounterNodeset;
1901 break;
1902 case XPATH_BOOLEAN:
1903 if (! isCached)
1904 xmlXPathDebugObjTotalBool++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001905 xmlXPathDebugObjCounterBool++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001906 if (xmlXPathDebugObjCounterBool >
1907 xmlXPathDebugObjMaxBool)
1908 xmlXPathDebugObjMaxBool =
1909 xmlXPathDebugObjCounterBool;
1910 break;
1911 case XPATH_NUMBER:
1912 if (! isCached)
1913 xmlXPathDebugObjTotalNumber++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001914 xmlXPathDebugObjCounterNumber++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001915 if (xmlXPathDebugObjCounterNumber >
1916 xmlXPathDebugObjMaxNumber)
1917 xmlXPathDebugObjMaxNumber =
1918 xmlXPathDebugObjCounterNumber;
1919 break;
1920 case XPATH_STRING:
1921 if (! isCached)
1922 xmlXPathDebugObjTotalString++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001923 xmlXPathDebugObjCounterString++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001924 if (xmlXPathDebugObjCounterString >
1925 xmlXPathDebugObjMaxString)
1926 xmlXPathDebugObjMaxString =
1927 xmlXPathDebugObjCounterString;
1928 break;
1929 case XPATH_POINT:
1930 if (! isCached)
1931 xmlXPathDebugObjTotalPoint++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001932 xmlXPathDebugObjCounterPoint++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001933 if (xmlXPathDebugObjCounterPoint >
1934 xmlXPathDebugObjMaxPoint)
1935 xmlXPathDebugObjMaxPoint =
1936 xmlXPathDebugObjCounterPoint;
1937 break;
1938 case XPATH_RANGE:
1939 if (! isCached)
1940 xmlXPathDebugObjTotalRange++;
1941 xmlXPathDebugObjCounterRange++;
1942 if (xmlXPathDebugObjCounterRange >
1943 xmlXPathDebugObjMaxRange)
1944 xmlXPathDebugObjMaxRange =
1945 xmlXPathDebugObjCounterRange;
1946 break;
1947 case XPATH_LOCATIONSET:
1948 if (! isCached)
1949 xmlXPathDebugObjTotalLocset++;
1950 xmlXPathDebugObjCounterLocset++;
1951 if (xmlXPathDebugObjCounterLocset >
1952 xmlXPathDebugObjMaxLocset)
1953 xmlXPathDebugObjMaxLocset =
1954 xmlXPathDebugObjCounterLocset;
1955 break;
1956 case XPATH_USERS:
1957 if (! isCached)
1958 xmlXPathDebugObjTotalUsers++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001959 xmlXPathDebugObjCounterUsers++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001960 if (xmlXPathDebugObjCounterUsers >
1961 xmlXPathDebugObjMaxUsers)
1962 xmlXPathDebugObjMaxUsers =
1963 xmlXPathDebugObjCounterUsers;
1964 break;
1965 case XPATH_XSLT_TREE:
1966 if (! isCached)
1967 xmlXPathDebugObjTotalXSLTTree++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001968 xmlXPathDebugObjCounterXSLTTree++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001969 if (xmlXPathDebugObjCounterXSLTTree >
1970 xmlXPathDebugObjMaxXSLTTree)
1971 xmlXPathDebugObjMaxXSLTTree =
1972 xmlXPathDebugObjCounterXSLTTree;
1973 break;
1974 default:
1975 break;
1976 }
1977 if (! isCached)
1978 xmlXPathDebugObjTotalAll++;
1979 xmlXPathDebugObjCounterAll++;
1980 if (xmlXPathDebugObjCounterAll >
1981 xmlXPathDebugObjMaxAll)
1982 xmlXPathDebugObjMaxAll =
1983 xmlXPathDebugObjCounterAll;
1984}
1985
1986static void
1987xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1988 xmlXPathObjectType objType)
1989{
1990 int isCached = 0;
1991
1992 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001993 if (ctxt->cache != NULL) {
1994 xmlXPathContextCachePtr cache =
1995 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001996
Daniel Veillard45490ae2008-07-29 09:13:19 +00001997 isCached = 1;
1998
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001999 cache->dbgCachedAll++;
2000 switch (objType) {
2001 case XPATH_UNDEFINED:
2002 cache->dbgCachedUndefined++;
2003 break;
2004 case XPATH_NODESET:
2005 cache->dbgCachedNodeset++;
2006 break;
2007 case XPATH_BOOLEAN:
2008 cache->dbgCachedBool++;
2009 break;
2010 case XPATH_NUMBER:
2011 cache->dbgCachedNumber++;
2012 break;
2013 case XPATH_STRING:
2014 cache->dbgCachedString++;
2015 break;
2016 case XPATH_POINT:
2017 cache->dbgCachedPoint++;
2018 break;
2019 case XPATH_RANGE:
2020 cache->dbgCachedRange++;
2021 break;
2022 case XPATH_LOCATIONSET:
2023 cache->dbgCachedLocset++;
2024 break;
2025 case XPATH_USERS:
2026 cache->dbgCachedUsers++;
2027 break;
2028 case XPATH_XSLT_TREE:
2029 cache->dbgCachedXSLTTree++;
2030 break;
2031 default:
2032 break;
2033 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00002034
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002035 }
2036 }
2037 switch (objType) {
2038 case XPATH_UNDEFINED:
2039 xmlXPathDebugObjCounterUndefined--;
2040 break;
2041 case XPATH_NODESET:
2042 xmlXPathDebugObjCounterNodeset--;
2043 break;
2044 case XPATH_BOOLEAN:
2045 xmlXPathDebugObjCounterBool--;
2046 break;
2047 case XPATH_NUMBER:
2048 xmlXPathDebugObjCounterNumber--;
2049 break;
2050 case XPATH_STRING:
2051 xmlXPathDebugObjCounterString--;
2052 break;
2053 case XPATH_POINT:
2054 xmlXPathDebugObjCounterPoint--;
2055 break;
2056 case XPATH_RANGE:
2057 xmlXPathDebugObjCounterRange--;
2058 break;
2059 case XPATH_LOCATIONSET:
2060 xmlXPathDebugObjCounterLocset--;
2061 break;
2062 case XPATH_USERS:
2063 xmlXPathDebugObjCounterUsers--;
2064 break;
2065 case XPATH_XSLT_TREE:
2066 xmlXPathDebugObjCounterXSLTTree--;
2067 break;
2068 default:
2069 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002070 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002071 xmlXPathDebugObjCounterAll--;
2072}
2073
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002074static void
2075xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2076{
2077 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2078 reqXSLTTree, reqUndefined;
2079 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2080 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2081 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2082 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2083 int leftObjs = xmlXPathDebugObjCounterAll;
2084
2085 reqAll = xmlXPathDebugObjTotalAll;
2086 reqNodeset = xmlXPathDebugObjTotalNodeset;
2087 reqString = xmlXPathDebugObjTotalString;
2088 reqBool = xmlXPathDebugObjTotalBool;
2089 reqNumber = xmlXPathDebugObjTotalNumber;
2090 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2091 reqUndefined = xmlXPathDebugObjTotalUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002092
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002093 printf("# XPath object usage:\n");
2094
2095 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002096 if (ctxt->cache != NULL) {
2097 xmlXPathContextCachePtr cache =
2098 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002099
2100 reAll = cache->dbgReusedAll;
2101 reqAll += reAll;
2102 reNodeset = cache->dbgReusedNodeset;
2103 reqNodeset += reNodeset;
2104 reString = cache->dbgReusedString;
2105 reqString += reString;
2106 reBool = cache->dbgReusedBool;
2107 reqBool += reBool;
2108 reNumber = cache->dbgReusedNumber;
2109 reqNumber += reNumber;
2110 reXSLTTree = cache->dbgReusedXSLTTree;
2111 reqXSLTTree += reXSLTTree;
2112 reUndefined = cache->dbgReusedUndefined;
2113 reqUndefined += reUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002114
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002115 caAll = cache->dbgCachedAll;
2116 caBool = cache->dbgCachedBool;
2117 caNodeset = cache->dbgCachedNodeset;
2118 caString = cache->dbgCachedString;
2119 caNumber = cache->dbgCachedNumber;
2120 caXSLTTree = cache->dbgCachedXSLTTree;
2121 caUndefined = cache->dbgCachedUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002122
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002123 if (cache->nodesetObjs)
2124 leftObjs -= cache->nodesetObjs->number;
2125 if (cache->stringObjs)
2126 leftObjs -= cache->stringObjs->number;
2127 if (cache->booleanObjs)
2128 leftObjs -= cache->booleanObjs->number;
2129 if (cache->numberObjs)
2130 leftObjs -= cache->numberObjs->number;
2131 if (cache->miscObjs)
2132 leftObjs -= cache->miscObjs->number;
2133 }
2134 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00002135
2136 printf("# all\n");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002137 printf("# total : %d\n", reqAll);
2138 printf("# left : %d\n", leftObjs);
2139 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
2140 printf("# reused : %d\n", reAll);
2141 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
2142
2143 printf("# node-sets\n");
2144 printf("# total : %d\n", reqNodeset);
2145 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
2146 printf("# reused : %d\n", reNodeset);
2147 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
2148
2149 printf("# strings\n");
2150 printf("# total : %d\n", reqString);
2151 printf("# created: %d\n", xmlXPathDebugObjTotalString);
2152 printf("# reused : %d\n", reString);
2153 printf("# max : %d\n", xmlXPathDebugObjMaxString);
2154
2155 printf("# booleans\n");
2156 printf("# total : %d\n", reqBool);
2157 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
2158 printf("# reused : %d\n", reBool);
2159 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
2160
2161 printf("# numbers\n");
2162 printf("# total : %d\n", reqNumber);
2163 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
2164 printf("# reused : %d\n", reNumber);
2165 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
2166
2167 printf("# XSLT result tree fragments\n");
2168 printf("# total : %d\n", reqXSLTTree);
2169 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2170 printf("# reused : %d\n", reXSLTTree);
2171 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
2172
2173 printf("# undefined\n");
2174 printf("# total : %d\n", reqUndefined);
2175 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
2176 printf("# reused : %d\n", reUndefined);
2177 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
2178
2179}
2180
2181#endif /* XP_DEBUG_OBJ_USAGE */
2182
Daniel Veillard017b1082001-06-21 11:20:21 +00002183#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002184
2185/************************************************************************
2186 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002187 * XPath object caching *
2188 * *
2189 ************************************************************************/
2190
2191/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002192 * xmlXPathNewCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002193 *
2194 * Create a new object cache
2195 *
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002196 * Returns the xmlXPathCache just allocated.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002197 */
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002198static xmlXPathContextCachePtr
2199xmlXPathNewCache(void)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002200{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002201 xmlXPathContextCachePtr ret;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002202
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002203 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002204 if (ret == NULL) {
2205 xmlXPathErrMemory(NULL, "creating object cache\n");
2206 return(NULL);
2207 }
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002208 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002209 ret->maxNodeset = 100;
2210 ret->maxString = 100;
2211 ret->maxBoolean = 100;
2212 ret->maxNumber = 100;
2213 ret->maxMisc = 100;
2214 return(ret);
2215}
2216
2217static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002218xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002219{
2220 int i;
2221 xmlXPathObjectPtr obj;
2222
2223 if (list == NULL)
2224 return;
2225
2226 for (i = 0; i < list->number; i++) {
2227 obj = list->items[i];
2228 /*
2229 * Note that it is already assured that we don't need to
2230 * look out for namespace nodes in the node-set.
2231 */
2232 if (obj->nodesetval != NULL) {
2233 if (obj->nodesetval->nodeTab != NULL)
2234 xmlFree(obj->nodesetval->nodeTab);
2235 xmlFree(obj->nodesetval);
2236 }
2237 xmlFree(obj);
2238#ifdef XP_DEBUG_OBJ_USAGE
2239 xmlXPathDebugObjCounterAll--;
2240#endif
2241 }
2242 xmlPointerListFree(list);
2243}
2244
2245static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002246xmlXPathFreeCache(xmlXPathContextCachePtr cache)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002247{
2248 if (cache == NULL)
2249 return;
2250 if (cache->nodesetObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002251 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002252 if (cache->stringObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002253 xmlXPathCacheFreeObjectList(cache->stringObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002254 if (cache->booleanObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002255 xmlXPathCacheFreeObjectList(cache->booleanObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002256 if (cache->numberObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002257 xmlXPathCacheFreeObjectList(cache->numberObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002258 if (cache->miscObjs)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002259 xmlXPathCacheFreeObjectList(cache->miscObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002260 xmlFree(cache);
2261}
2262
2263/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002264 * xmlXPathContextSetCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002265 *
2266 * @ctxt: the XPath context
2267 * @active: enables/disables (creates/frees) the cache
Haibo Huangcfd91dc2020-07-30 23:01:33 -07002268 * @value: a value with semantics dependent on @options
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002269 * @options: options (currently only the value 0 is used)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002270 *
2271 * Creates/frees an object cache on the XPath context.
2272 * If activates XPath objects (xmlXPathObject) will be cached internally
Aleksey Sanin1b2be102006-05-31 20:53:43 +00002273 * to be reused.
2274 * @options:
2275 * 0: This will set the XPath object caching:
2276 * @value:
2277 * This will set the maximum number of XPath objects
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002278 * to be cached per slot
2279 * There are 5 slots for: node-set, string, number, boolean, and
Aleksey Sanin1b2be102006-05-31 20:53:43 +00002280 * misc objects. Use <0 for the default number (100).
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002281 * Other values for @options have currently no effect.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002282 *
2283 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2284 */
2285int
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002286xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2287 int active,
2288 int value,
2289 int options)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002290{
2291 if (ctxt == NULL)
2292 return(-1);
2293 if (active) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002294 xmlXPathContextCachePtr cache;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002295
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002296 if (ctxt->cache == NULL) {
2297 ctxt->cache = xmlXPathNewCache();
2298 if (ctxt->cache == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002299 return(-1);
2300 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +00002301 cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002302 if (options == 0) {
2303 if (value < 0)
2304 value = 100;
2305 cache->maxNodeset = value;
2306 cache->maxString = value;
2307 cache->maxNumber = value;
2308 cache->maxBoolean = value;
Aleksey Sanin1b2be102006-05-31 20:53:43 +00002309 cache->maxMisc = value;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002310 }
2311 } else if (ctxt->cache != NULL) {
2312 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2313 ctxt->cache = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002314 }
2315 return(0);
2316}
2317
2318/**
2319 * xmlXPathCacheWrapNodeSet:
2320 * @ctxt: the XPath context
2321 * @val: the NodePtr value
2322 *
2323 * This is the cached version of xmlXPathWrapNodeSet().
2324 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2325 *
2326 * Returns the created or reused object.
2327 */
2328static xmlXPathObjectPtr
2329xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002330{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002331 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2332 xmlXPathContextCachePtr cache =
2333 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002334
2335 if ((cache->miscObjs != NULL) &&
2336 (cache->miscObjs->number != 0))
2337 {
2338 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002339
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002340 ret = (xmlXPathObjectPtr)
2341 cache->miscObjs->items[--cache->miscObjs->number];
2342 ret->type = XPATH_NODESET;
2343 ret->nodesetval = val;
2344#ifdef XP_DEBUG_OBJ_USAGE
2345 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2346#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00002347 return(ret);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002348 }
2349 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00002350
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002351 return(xmlXPathWrapNodeSet(val));
Daniel Veillard45490ae2008-07-29 09:13:19 +00002352
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002353}
2354
2355/**
2356 * xmlXPathCacheWrapString:
2357 * @ctxt: the XPath context
2358 * @val: the xmlChar * value
2359 *
2360 * This is the cached version of xmlXPathWrapString().
2361 * Wraps the @val string into an XPath object.
2362 *
2363 * Returns the created or reused object.
2364 */
2365static xmlXPathObjectPtr
2366xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002367{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002368 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2369 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002370
2371 if ((cache->stringObjs != NULL) &&
2372 (cache->stringObjs->number != 0))
2373 {
Daniel Veillard45490ae2008-07-29 09:13:19 +00002374
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002375 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002376
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002377 ret = (xmlXPathObjectPtr)
2378 cache->stringObjs->items[--cache->stringObjs->number];
2379 ret->type = XPATH_STRING;
2380 ret->stringval = val;
2381#ifdef XP_DEBUG_OBJ_USAGE
2382 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2383#endif
2384 return(ret);
2385 } else if ((cache->miscObjs != NULL) &&
2386 (cache->miscObjs->number != 0))
2387 {
2388 xmlXPathObjectPtr ret;
2389 /*
2390 * Fallback to misc-cache.
2391 */
2392 ret = (xmlXPathObjectPtr)
2393 cache->miscObjs->items[--cache->miscObjs->number];
2394
2395 ret->type = XPATH_STRING;
2396 ret->stringval = val;
2397#ifdef XP_DEBUG_OBJ_USAGE
2398 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2399#endif
2400 return(ret);
2401 }
2402 }
2403 return(xmlXPathWrapString(val));
2404}
2405
2406/**
2407 * xmlXPathCacheNewNodeSet:
2408 * @ctxt: the XPath context
2409 * @val: the NodePtr value
2410 *
2411 * This is the cached version of xmlXPathNewNodeSet().
2412 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2413 * it with the single Node @val
2414 *
2415 * Returns the created or reused object.
2416 */
2417static xmlXPathObjectPtr
2418xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2419{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002420 if ((ctxt != NULL) && (ctxt->cache)) {
2421 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002422
2423 if ((cache->nodesetObjs != NULL) &&
2424 (cache->nodesetObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002425 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002426 xmlXPathObjectPtr ret;
2427 /*
Haibo Huangcfd91dc2020-07-30 23:01:33 -07002428 * Use the nodeset-cache.
Daniel Veillard45490ae2008-07-29 09:13:19 +00002429 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002430 ret = (xmlXPathObjectPtr)
2431 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2432 ret->type = XPATH_NODESET;
2433 ret->boolval = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002434 if (val) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002435 if ((ret->nodesetval->nodeMax == 0) ||
2436 (val->type == XML_NAMESPACE_DECL))
2437 {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07002438 /* TODO: Check memory error. */
Daniel Veillard45490ae2008-07-29 09:13:19 +00002439 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002440 } else {
2441 ret->nodesetval->nodeTab[0] = val;
2442 ret->nodesetval->nodeNr = 1;
2443 }
2444 }
2445#ifdef XP_DEBUG_OBJ_USAGE
2446 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2447#endif
2448 return(ret);
2449 } else if ((cache->miscObjs != NULL) &&
2450 (cache->miscObjs->number != 0))
2451 {
2452 xmlXPathObjectPtr ret;
2453 /*
2454 * Fallback to misc-cache.
2455 */
2456
2457 ret = (xmlXPathObjectPtr)
2458 cache->miscObjs->items[--cache->miscObjs->number];
2459
2460 ret->type = XPATH_NODESET;
2461 ret->boolval = 0;
2462 ret->nodesetval = xmlXPathNodeSetCreate(val);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08002463 if (ret->nodesetval == NULL) {
2464 ctxt->lastError.domain = XML_FROM_XPATH;
2465 ctxt->lastError.code = XML_ERR_NO_MEMORY;
2466 return(NULL);
2467 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002468#ifdef XP_DEBUG_OBJ_USAGE
2469 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2470#endif
2471 return(ret);
2472 }
2473 }
2474 return(xmlXPathNewNodeSet(val));
2475}
2476
2477/**
2478 * xmlXPathCacheNewCString:
2479 * @ctxt: the XPath context
2480 * @val: the char * value
2481 *
2482 * This is the cached version of xmlXPathNewCString().
2483 * Acquire an xmlXPathObjectPtr of type string and of value @val
2484 *
2485 * Returns the created or reused object.
2486 */
2487static xmlXPathObjectPtr
2488xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002489{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002490 if ((ctxt != NULL) && (ctxt->cache)) {
2491 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002492
2493 if ((cache->stringObjs != NULL) &&
2494 (cache->stringObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002495 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002496 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002497
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002498 ret = (xmlXPathObjectPtr)
2499 cache->stringObjs->items[--cache->stringObjs->number];
2500
2501 ret->type = XPATH_STRING;
2502 ret->stringval = xmlStrdup(BAD_CAST val);
2503#ifdef XP_DEBUG_OBJ_USAGE
2504 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2505#endif
2506 return(ret);
2507 } else if ((cache->miscObjs != NULL) &&
2508 (cache->miscObjs->number != 0))
2509 {
2510 xmlXPathObjectPtr ret;
2511
2512 ret = (xmlXPathObjectPtr)
2513 cache->miscObjs->items[--cache->miscObjs->number];
2514
2515 ret->type = XPATH_STRING;
2516 ret->stringval = xmlStrdup(BAD_CAST val);
2517#ifdef XP_DEBUG_OBJ_USAGE
2518 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2519#endif
2520 return(ret);
2521 }
2522 }
2523 return(xmlXPathNewCString(val));
2524}
2525
2526/**
2527 * xmlXPathCacheNewString:
2528 * @ctxt: the XPath context
2529 * @val: the xmlChar * value
2530 *
2531 * This is the cached version of xmlXPathNewString().
2532 * Acquire an xmlXPathObjectPtr of type string and of value @val
2533 *
2534 * Returns the created or reused object.
2535 */
2536static xmlXPathObjectPtr
2537xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002538{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002539 if ((ctxt != NULL) && (ctxt->cache)) {
2540 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002541
2542 if ((cache->stringObjs != NULL) &&
2543 (cache->stringObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002544 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002545 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002546
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002547 ret = (xmlXPathObjectPtr)
2548 cache->stringObjs->items[--cache->stringObjs->number];
2549 ret->type = XPATH_STRING;
2550 if (val != NULL)
2551 ret->stringval = xmlStrdup(val);
2552 else
2553 ret->stringval = xmlStrdup((const xmlChar *)"");
2554#ifdef XP_DEBUG_OBJ_USAGE
2555 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2556#endif
2557 return(ret);
2558 } else if ((cache->miscObjs != NULL) &&
2559 (cache->miscObjs->number != 0))
2560 {
2561 xmlXPathObjectPtr ret;
2562
2563 ret = (xmlXPathObjectPtr)
2564 cache->miscObjs->items[--cache->miscObjs->number];
2565
2566 ret->type = XPATH_STRING;
2567 if (val != NULL)
2568 ret->stringval = xmlStrdup(val);
2569 else
2570 ret->stringval = xmlStrdup((const xmlChar *)"");
2571#ifdef XP_DEBUG_OBJ_USAGE
2572 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2573#endif
2574 return(ret);
2575 }
2576 }
2577 return(xmlXPathNewString(val));
2578}
2579
2580/**
2581 * xmlXPathCacheNewBoolean:
2582 * @ctxt: the XPath context
2583 * @val: the boolean value
2584 *
2585 * This is the cached version of xmlXPathNewBoolean().
2586 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2587 *
2588 * Returns the created or reused object.
2589 */
2590static xmlXPathObjectPtr
2591xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002592{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002593 if ((ctxt != NULL) && (ctxt->cache)) {
2594 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002595
2596 if ((cache->booleanObjs != NULL) &&
2597 (cache->booleanObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002598 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002599 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002600
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002601 ret = (xmlXPathObjectPtr)
2602 cache->booleanObjs->items[--cache->booleanObjs->number];
2603 ret->type = XPATH_BOOLEAN;
2604 ret->boolval = (val != 0);
2605#ifdef XP_DEBUG_OBJ_USAGE
2606 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2607#endif
2608 return(ret);
2609 } else if ((cache->miscObjs != NULL) &&
2610 (cache->miscObjs->number != 0))
2611 {
2612 xmlXPathObjectPtr ret;
2613
2614 ret = (xmlXPathObjectPtr)
2615 cache->miscObjs->items[--cache->miscObjs->number];
2616
2617 ret->type = XPATH_BOOLEAN;
2618 ret->boolval = (val != 0);
2619#ifdef XP_DEBUG_OBJ_USAGE
2620 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2621#endif
2622 return(ret);
2623 }
2624 }
2625 return(xmlXPathNewBoolean(val));
2626}
2627
2628/**
2629 * xmlXPathCacheNewFloat:
2630 * @ctxt: the XPath context
2631 * @val: the double value
2632 *
2633 * This is the cached version of xmlXPathNewFloat().
2634 * Acquires an xmlXPathObjectPtr of type double and of value @val
2635 *
2636 * Returns the created or reused object.
2637 */
2638static xmlXPathObjectPtr
2639xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2640{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002641 if ((ctxt != NULL) && (ctxt->cache)) {
2642 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002643
2644 if ((cache->numberObjs != NULL) &&
2645 (cache->numberObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002646 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002647 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002648
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002649 ret = (xmlXPathObjectPtr)
2650 cache->numberObjs->items[--cache->numberObjs->number];
2651 ret->type = XPATH_NUMBER;
2652 ret->floatval = val;
2653#ifdef XP_DEBUG_OBJ_USAGE
2654 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2655#endif
2656 return(ret);
2657 } else if ((cache->miscObjs != NULL) &&
2658 (cache->miscObjs->number != 0))
2659 {
2660 xmlXPathObjectPtr ret;
2661
2662 ret = (xmlXPathObjectPtr)
2663 cache->miscObjs->items[--cache->miscObjs->number];
2664
2665 ret->type = XPATH_NUMBER;
2666 ret->floatval = val;
2667#ifdef XP_DEBUG_OBJ_USAGE
2668 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2669#endif
2670 return(ret);
2671 }
2672 }
2673 return(xmlXPathNewFloat(val));
2674}
2675
2676/**
2677 * xmlXPathCacheConvertString:
2678 * @ctxt: the XPath context
2679 * @val: an XPath object
2680 *
2681 * This is the cached version of xmlXPathConvertString().
2682 * Converts an existing object to its string() equivalent
2683 *
2684 * Returns a created or reused object, the old one is freed (cached)
2685 * (or the operation is done directly on @val)
2686 */
2687
2688static xmlXPathObjectPtr
2689xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00002690 xmlChar *res = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002691
2692 if (val == NULL)
2693 return(xmlXPathCacheNewCString(ctxt, ""));
2694
2695 switch (val->type) {
2696 case XPATH_UNDEFINED:
2697#ifdef DEBUG_EXPR
2698 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2699#endif
2700 break;
2701 case XPATH_NODESET:
2702 case XPATH_XSLT_TREE:
2703 res = xmlXPathCastNodeSetToString(val->nodesetval);
2704 break;
2705 case XPATH_STRING:
2706 return(val);
2707 case XPATH_BOOLEAN:
2708 res = xmlXPathCastBooleanToString(val->boolval);
2709 break;
2710 case XPATH_NUMBER:
2711 res = xmlXPathCastNumberToString(val->floatval);
2712 break;
2713 case XPATH_USERS:
2714 case XPATH_POINT:
2715 case XPATH_RANGE:
2716 case XPATH_LOCATIONSET:
2717 TODO;
2718 break;
2719 }
2720 xmlXPathReleaseObject(ctxt, val);
2721 if (res == NULL)
2722 return(xmlXPathCacheNewCString(ctxt, ""));
2723 return(xmlXPathCacheWrapString(ctxt, res));
2724}
2725
2726/**
2727 * xmlXPathCacheObjectCopy:
2728 * @ctxt: the XPath context
2729 * @val: the original object
2730 *
2731 * This is the cached version of xmlXPathObjectCopy().
2732 * Acquire a copy of a given object
2733 *
2734 * Returns a created or reused created object.
2735 */
2736static xmlXPathObjectPtr
2737xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2738{
2739 if (val == NULL)
2740 return(NULL);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002741
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002742 if (XP_HAS_CACHE(ctxt)) {
2743 switch (val->type) {
2744 case XPATH_NODESET:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002745 return(xmlXPathCacheWrapNodeSet(ctxt,
2746 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002747 case XPATH_STRING:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002748 return(xmlXPathCacheNewString(ctxt, val->stringval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002749 case XPATH_BOOLEAN:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002750 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002751 case XPATH_NUMBER:
2752 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2753 default:
2754 break;
2755 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002756 }
2757 return(xmlXPathObjectCopy(val));
2758}
2759
2760/**
2761 * xmlXPathCacheConvertBoolean:
2762 * @ctxt: the XPath context
2763 * @val: an XPath object
2764 *
2765 * This is the cached version of xmlXPathConvertBoolean().
2766 * Converts an existing object to its boolean() equivalent
2767 *
2768 * Returns a created or reused object, the old one is freed (or the operation
2769 * is done directly on @val)
2770 */
2771static xmlXPathObjectPtr
2772xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2773 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002774
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002775 if (val == NULL)
2776 return(xmlXPathCacheNewBoolean(ctxt, 0));
2777 if (val->type == XPATH_BOOLEAN)
2778 return(val);
2779 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2780 xmlXPathReleaseObject(ctxt, val);
2781 return(ret);
2782}
2783
2784/**
2785 * xmlXPathCacheConvertNumber:
2786 * @ctxt: the XPath context
2787 * @val: an XPath object
2788 *
2789 * This is the cached version of xmlXPathConvertNumber().
2790 * Converts an existing object to its number() equivalent
2791 *
2792 * Returns a created or reused object, the old one is freed (or the operation
2793 * is done directly on @val)
2794 */
2795static xmlXPathObjectPtr
2796xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2797 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002798
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002799 if (val == NULL)
2800 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2801 if (val->type == XPATH_NUMBER)
2802 return(val);
2803 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2804 xmlXPathReleaseObject(ctxt, val);
2805 return(ret);
2806}
2807
2808/************************************************************************
2809 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +00002810 * Parser stacks related functions and macros *
Owen Taylor3473f882001-02-23 17:55:21 +00002811 * *
2812 ************************************************************************/
2813
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002814/**
Daniel Veillardf5048b32011-08-18 17:10:13 +08002815 * xmlXPathSetFrame:
2816 * @ctxt: an XPath parser context
2817 *
2818 * Set the callee evaluation frame
2819 *
2820 * Returns the previous frame value to be restored once done
2821 */
2822static int
2823xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2824 int ret;
2825
2826 if (ctxt == NULL)
2827 return(0);
2828 ret = ctxt->valueFrame;
2829 ctxt->valueFrame = ctxt->valueNr;
2830 return(ret);
2831}
2832
2833/**
2834 * xmlXPathPopFrame:
2835 * @ctxt: an XPath parser context
2836 * @frame: the previous frame value
2837 *
2838 * Remove the callee evaluation frame
2839 */
2840static void
2841xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2842 if (ctxt == NULL)
2843 return;
2844 if (ctxt->valueNr < ctxt->valueFrame) {
2845 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2846 }
2847 ctxt->valueFrame = frame;
2848}
2849
2850/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002851 * valuePop:
2852 * @ctxt: an XPath evaluation context
2853 *
2854 * Pops the top XPath object from the value stack
2855 *
2856 * Returns the XPath object just removed
2857 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002858xmlXPathObjectPtr
Daniel Veillard1c732d22002-11-30 11:22:59 +00002859valuePop(xmlXPathParserContextPtr ctxt)
2860{
2861 xmlXPathObjectPtr ret;
2862
Daniel Veillarda82b1822004-11-08 16:24:57 +00002863 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
Daniel Veillard24505b02005-07-28 23:49:35 +00002864 return (NULL);
Daniel Veillardf5048b32011-08-18 17:10:13 +08002865
2866 if (ctxt->valueNr <= ctxt->valueFrame) {
2867 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2868 return (NULL);
2869 }
2870
Daniel Veillard1c732d22002-11-30 11:22:59 +00002871 ctxt->valueNr--;
2872 if (ctxt->valueNr > 0)
2873 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2874 else
2875 ctxt->value = NULL;
2876 ret = ctxt->valueTab[ctxt->valueNr];
Daniel Veillard24505b02005-07-28 23:49:35 +00002877 ctxt->valueTab[ctxt->valueNr] = NULL;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002878 return (ret);
2879}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002880/**
2881 * valuePush:
2882 * @ctxt: an XPath evaluation context
2883 * @value: the XPath object
2884 *
Haibo Huangcfd91dc2020-07-30 23:01:33 -07002885 * Pushes a new XPath object on top of the value stack. If value is NULL,
2886 * a memory error is recorded in the parser context.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002887 *
Haibo Huangcfd91dc2020-07-30 23:01:33 -07002888 * Returns the number of items on the value stack, or -1 in case of error.
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002889 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002890int
Daniel Veillard1c732d22002-11-30 11:22:59 +00002891valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2892{
Haibo Huangcfd91dc2020-07-30 23:01:33 -07002893 if (ctxt == NULL) return(-1);
2894 if (value == NULL) {
2895 /*
2896 * A NULL value typically indicates that a memory allocation failed,
2897 * so we set ctxt->error here to propagate the error.
2898 */
2899 ctxt->error = XPATH_MEMORY_ERROR;
2900 return(-1);
2901 }
Daniel Veillard1c732d22002-11-30 11:22:59 +00002902 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002903 xmlXPathObjectPtr *tmp;
2904
Daniel Veillardcd852ad2012-07-30 10:12:18 +08002905 if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07002906 xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n");
2907 return (-1);
Daniel Veillardcd852ad2012-07-30 10:12:18 +08002908 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002909 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2910 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00002911 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002912 if (tmp == NULL) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07002913 xmlXPathPErrMemory(ctxt, "pushing value\n");
2914 return (-1);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002915 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002916 ctxt->valueMax *= 2;
2917 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002918 }
2919 ctxt->valueTab[ctxt->valueNr] = value;
2920 ctxt->value = value;
2921 return (ctxt->valueNr++);
2922}
Owen Taylor3473f882001-02-23 17:55:21 +00002923
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002924/**
2925 * xmlXPathPopBoolean:
2926 * @ctxt: an XPath parser context
2927 *
2928 * Pops a boolean from the stack, handling conversion if needed.
2929 * Check error with #xmlXPathCheckError.
2930 *
2931 * Returns the boolean
2932 */
2933int
2934xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2935 xmlXPathObjectPtr obj;
2936 int ret;
2937
2938 obj = valuePop(ctxt);
2939 if (obj == NULL) {
2940 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2941 return(0);
2942 }
William M. Brack08171912003-12-29 02:52:11 +00002943 if (obj->type != XPATH_BOOLEAN)
2944 ret = xmlXPathCastToBoolean(obj);
2945 else
2946 ret = obj->boolval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002947 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002948 return(ret);
2949}
2950
2951/**
2952 * xmlXPathPopNumber:
2953 * @ctxt: an XPath parser context
2954 *
2955 * Pops a number from the stack, handling conversion if needed.
2956 * Check error with #xmlXPathCheckError.
2957 *
2958 * Returns the number
2959 */
2960double
2961xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2962 xmlXPathObjectPtr obj;
2963 double ret;
2964
2965 obj = valuePop(ctxt);
2966 if (obj == NULL) {
2967 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2968 return(0);
2969 }
William M. Brack08171912003-12-29 02:52:11 +00002970 if (obj->type != XPATH_NUMBER)
2971 ret = xmlXPathCastToNumber(obj);
2972 else
2973 ret = obj->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002974 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002975 return(ret);
2976}
2977
2978/**
2979 * xmlXPathPopString:
2980 * @ctxt: an XPath parser context
2981 *
2982 * Pops a string from the stack, handling conversion if needed.
2983 * Check error with #xmlXPathCheckError.
2984 *
2985 * Returns the string
2986 */
2987xmlChar *
2988xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2989 xmlXPathObjectPtr obj;
2990 xmlChar * ret;
2991
2992 obj = valuePop(ctxt);
2993 if (obj == NULL) {
2994 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2995 return(NULL);
2996 }
William M. Brack08171912003-12-29 02:52:11 +00002997 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002998 /* TODO: needs refactoring somewhere else */
2999 if (obj->stringval == ret)
3000 obj->stringval = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003001 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003002 return(ret);
3003}
3004
3005/**
3006 * xmlXPathPopNodeSet:
3007 * @ctxt: an XPath parser context
3008 *
3009 * Pops a node-set from the stack, handling conversion if needed.
3010 * Check error with #xmlXPathCheckError.
3011 *
3012 * Returns the node-set
3013 */
3014xmlNodeSetPtr
3015xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
3016 xmlXPathObjectPtr obj;
3017 xmlNodeSetPtr ret;
3018
Daniel Veillardf2a36f92004-11-08 17:55:01 +00003019 if (ctxt == NULL) return(NULL);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003020 if (ctxt->value == NULL) {
3021 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3022 return(NULL);
3023 }
3024 if (!xmlXPathStackIsNodeSet(ctxt)) {
3025 xmlXPathSetTypeError(ctxt);
3026 return(NULL);
3027 }
3028 obj = valuePop(ctxt);
3029 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00003030#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00003031 /* to fix memory leak of not clearing obj->user */
3032 if (obj->boolval && obj->user != NULL)
3033 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00003034#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003035 obj->nodesetval = NULL;
3036 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003037 return(ret);
3038}
3039
3040/**
3041 * xmlXPathPopExternal:
3042 * @ctxt: an XPath parser context
3043 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003044 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003045 * Check error with #xmlXPathCheckError.
3046 *
3047 * Returns the object
3048 */
3049void *
3050xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3051 xmlXPathObjectPtr obj;
3052 void * ret;
3053
Daniel Veillarda82b1822004-11-08 16:24:57 +00003054 if ((ctxt == NULL) || (ctxt->value == NULL)) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003055 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3056 return(NULL);
3057 }
3058 if (ctxt->value->type != XPATH_USERS) {
3059 xmlXPathSetTypeError(ctxt);
3060 return(NULL);
3061 }
3062 obj = valuePop(ctxt);
3063 ret = obj->user;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003064 obj->user = NULL;
3065 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003066 return(ret);
3067}
3068
Owen Taylor3473f882001-02-23 17:55:21 +00003069/*
3070 * Macros for accessing the content. Those should be used only by the parser,
3071 * and not exported.
3072 *
3073 * Dirty macros, i.e. one need to make assumption on the context to use them
3074 *
3075 * CUR_PTR return the current pointer to the xmlChar to be parsed.
3076 * CUR returns the current xmlChar value, i.e. a 8 bit value
3077 * in ISO-Latin or UTF-8.
3078 * This should be used internally by the parser
3079 * only to compare to ASCII values otherwise it would break when
3080 * running with UTF-8 encoding.
3081 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
3082 * to compare on ASCII based substring.
3083 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3084 * strings within the parser.
3085 * CURRENT Returns the current char value, with the full decoding of
3086 * UTF-8 if we are using this mode. It returns an int.
3087 * NEXT Skip to the next character, this does the proper decoding
3088 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
3089 * It returns the pointer to the current xmlChar.
3090 */
3091
3092#define CUR (*ctxt->cur)
3093#define SKIP(val) ctxt->cur += (val)
3094#define NXT(val) ctxt->cur[(val)]
3095#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00003096#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3097
3098#define COPY_BUF(l,b,i,v) \
3099 if (l == 1) b[i++] = (xmlChar) v; \
3100 else i += xmlCopyChar(l,&b[i],v)
3101
3102#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00003103
Daniel Veillard45490ae2008-07-29 09:13:19 +00003104#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00003105 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00003106
3107#define CURRENT (*ctxt->cur)
3108#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
3109
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003110
3111#ifndef DBL_DIG
3112#define DBL_DIG 16
3113#endif
3114#ifndef DBL_EPSILON
3115#define DBL_EPSILON 1E-9
3116#endif
3117
3118#define UPPER_DOUBLE 1E9
3119#define LOWER_DOUBLE 1E-5
William M. Brackca797882007-05-11 14:45:53 +00003120#define LOWER_DOUBLE_EXP 5
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003121
3122#define INTEGER_DIGITS DBL_DIG
William M. Brackca797882007-05-11 14:45:53 +00003123#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003124#define EXPONENT_DIGITS (3 + 2)
3125
3126/**
3127 * xmlXPathFormatNumber:
3128 * @number: number to format
3129 * @buffer: output buffer
3130 * @buffersize: size of output buffer
3131 *
3132 * Convert the number into a string representation.
3133 */
3134static void
3135xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3136{
Daniel Veillardcda96922001-08-21 10:56:31 +00003137 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003138 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003139 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00003140 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003141 break;
3142 case -1:
3143 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00003144 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003145 break;
3146 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003147 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003148 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00003149 snprintf(buffer, buffersize, "NaN");
Nick Wellnhofer8813f392017-09-21 00:11:26 +02003150 } else if (number == 0) {
3151 /* Omit sign for negative zero. */
Aleksey Sanin49cc9752002-06-14 17:07:10 +00003152 snprintf(buffer, buffersize, "0");
Nick Wellnhofer7482f412017-06-01 22:00:19 +02003153 } else if ((number > INT_MIN) && (number < INT_MAX) &&
3154 (number == (int) number)) {
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003155 char work[30];
3156 char *ptr, *cur;
Daniel Veillardb3d14912005-09-04 20:47:39 +00003157 int value = (int) number;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003158
3159 ptr = &buffer[0];
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003160 if (value == 0) {
3161 *ptr++ = '0';
3162 } else {
Daniel Veillardb3d14912005-09-04 20:47:39 +00003163 snprintf(work, 29, "%d", value);
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003164 cur = &work[0];
Daniel Veillardb3d14912005-09-04 20:47:39 +00003165 while ((*cur) && (ptr - buffer < buffersize)) {
3166 *ptr++ = *cur++;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003167 }
3168 }
3169 if (ptr - buffer < buffersize) {
3170 *ptr = 0;
3171 } else if (buffersize > 0) {
3172 ptr--;
3173 *ptr = 0;
3174 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003175 } else {
William M. Brackca797882007-05-11 14:45:53 +00003176 /*
3177 For the dimension of work,
3178 DBL_DIG is number of significant digits
3179 EXPONENT is only needed for "scientific notation"
3180 3 is sign, decimal point, and terminating zero
3181 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3182 Note that this dimension is slightly (a few characters)
3183 larger than actually necessary.
3184 */
3185 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
Bjorn Reese70a9da52001-04-21 16:57:29 +00003186 int integer_place, fraction_place;
3187 char *ptr;
3188 char *after_fraction;
3189 double absolute_value;
3190 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003191
Bjorn Reese70a9da52001-04-21 16:57:29 +00003192 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003193
Bjorn Reese70a9da52001-04-21 16:57:29 +00003194 /*
3195 * First choose format - scientific or regular floating point.
3196 * In either case, result is in work, and after_fraction points
3197 * just past the fractional part.
3198 */
3199 if ( ((absolute_value > UPPER_DOUBLE) ||
3200 (absolute_value < LOWER_DOUBLE)) &&
3201 (absolute_value != 0.0) ) {
3202 /* Use scientific notation */
3203 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3204 fraction_place = DBL_DIG - 1;
Daniel Veillard11ce4002006-03-10 00:36:23 +00003205 size = snprintf(work, sizeof(work),"%*.*e",
Bjorn Reese70a9da52001-04-21 16:57:29 +00003206 integer_place, fraction_place, number);
Daniel Veillard11ce4002006-03-10 00:36:23 +00003207 while ((size > 0) && (work[size] != 'e')) size--;
Daniel Veillard11ce4002006-03-10 00:36:23 +00003208
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003209 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00003210 else {
3211 /* Use regular notation */
William M. Brackca797882007-05-11 14:45:53 +00003212 if (absolute_value > 0.0) {
3213 integer_place = (int)log10(absolute_value);
3214 if (integer_place > 0)
3215 fraction_place = DBL_DIG - integer_place - 1;
3216 else
3217 fraction_place = DBL_DIG - integer_place;
3218 } else {
3219 fraction_place = 1;
3220 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00003221 size = snprintf(work, sizeof(work), "%0.*f",
3222 fraction_place, number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003223 }
3224
Daniel Veillardb9e4d5b2013-07-22 13:21:31 +08003225 /* Remove leading spaces sometimes inserted by snprintf */
3226 while (work[0] == ' ') {
3227 for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3228 size--;
3229 }
3230
Bjorn Reese70a9da52001-04-21 16:57:29 +00003231 /* Remove fractional trailing zeroes */
William M. Brackca797882007-05-11 14:45:53 +00003232 after_fraction = work + size;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003233 ptr = after_fraction;
3234 while (*(--ptr) == '0')
3235 ;
3236 if (*ptr != '.')
3237 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00003238 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003239
3240 /* Finally copy result back to caller */
3241 size = strlen(work) + 1;
3242 if (size > buffersize) {
3243 work[buffersize - 1] = 0;
3244 size = buffersize;
3245 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00003246 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003247 }
3248 break;
3249 }
3250}
3251
Owen Taylor3473f882001-02-23 17:55:21 +00003252
3253/************************************************************************
3254 * *
3255 * Routines to handle NodeSets *
3256 * *
3257 ************************************************************************/
3258
3259/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003260 * xmlXPathOrderDocElems:
3261 * @doc: an input document
3262 *
3263 * Call this routine to speed up XPath computation on static documents.
3264 * This stamps all the element nodes with the document order
3265 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00003266 * field, the value stored is actually - the node number (starting at -1)
3267 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003268 *
William M. Brack08171912003-12-29 02:52:11 +00003269 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003270 * of error.
3271 */
3272long
3273xmlXPathOrderDocElems(xmlDocPtr doc) {
Nick Wellnhoferd422b952017-10-09 13:37:42 +02003274 ptrdiff_t count = 0;
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003275 xmlNodePtr cur;
3276
3277 if (doc == NULL)
3278 return(-1);
3279 cur = doc->children;
3280 while (cur != NULL) {
3281 if (cur->type == XML_ELEMENT_NODE) {
3282 cur->content = (void *) (-(++count));
3283 if (cur->children != NULL) {
3284 cur = cur->children;
3285 continue;
3286 }
3287 }
3288 if (cur->next != NULL) {
3289 cur = cur->next;
3290 continue;
3291 }
3292 do {
3293 cur = cur->parent;
3294 if (cur == NULL)
3295 break;
3296 if (cur == (xmlNodePtr) doc) {
3297 cur = NULL;
3298 break;
3299 }
3300 if (cur->next != NULL) {
3301 cur = cur->next;
3302 break;
3303 }
3304 } while (cur != NULL);
3305 }
Nick Wellnhoferd422b952017-10-09 13:37:42 +02003306 return((long) count);
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003307}
3308
3309/**
Owen Taylor3473f882001-02-23 17:55:21 +00003310 * xmlXPathCmpNodes:
3311 * @node1: the first node
3312 * @node2: the second node
3313 *
3314 * Compare two nodes w.r.t document order
3315 *
3316 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00003317 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00003318 */
3319int
3320xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3321 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00003322 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00003323 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003324 xmlNodePtr cur, root;
3325
3326 if ((node1 == NULL) || (node2 == NULL))
3327 return(-2);
3328 /*
3329 * a couple of optimizations which will avoid computations in most cases
3330 */
William M. Brackee0b9822007-03-07 08:15:01 +00003331 if (node1 == node2) /* trivial case */
3332 return(0);
Daniel Veillardedfd5882003-03-07 14:20:40 +00003333 if (node1->type == XML_ATTRIBUTE_NODE) {
3334 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00003335 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00003336 node1 = node1->parent;
3337 }
3338 if (node2->type == XML_ATTRIBUTE_NODE) {
3339 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00003340 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00003341 node2 = node2->parent;
3342 }
3343 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00003344 if (attr1 == attr2) {
3345 /* not required, but we keep attributes in order */
3346 if (attr1 != 0) {
3347 cur = attrNode2->prev;
3348 while (cur != NULL) {
3349 if (cur == attrNode1)
3350 return (1);
3351 cur = cur->prev;
3352 }
3353 return (-1);
3354 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00003355 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00003356 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00003357 if (attr2 == 1)
3358 return(1);
3359 return(-1);
3360 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003361 if ((node1->type == XML_NAMESPACE_DECL) ||
3362 (node2->type == XML_NAMESPACE_DECL))
3363 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00003364 if (node1 == node2->prev)
3365 return(1);
3366 if (node1 == node2->next)
3367 return(-1);
3368
3369 /*
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003370 * Speedup using document order if available.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00003371 */
3372 if ((node1->type == XML_ELEMENT_NODE) &&
3373 (node2->type == XML_ELEMENT_NODE) &&
Nick Wellnhoferd422b952017-10-09 13:37:42 +02003374 (0 > (ptrdiff_t) node1->content) &&
3375 (0 > (ptrdiff_t) node2->content) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003376 (node1->doc == node2->doc)) {
Nick Wellnhoferd422b952017-10-09 13:37:42 +02003377 ptrdiff_t l1, l2;
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003378
Nick Wellnhoferd422b952017-10-09 13:37:42 +02003379 l1 = -((ptrdiff_t) node1->content);
3380 l2 = -((ptrdiff_t) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00003381 if (l1 < l2)
3382 return(1);
3383 if (l1 > l2)
3384 return(-1);
3385 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003386
Daniel Veillard7216cfd2002-11-08 15:10:00 +00003387 /*
Owen Taylor3473f882001-02-23 17:55:21 +00003388 * compute depth to root
3389 */
3390 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
Nick Wellnhofera0051992016-06-28 14:19:58 +02003391 if (cur->parent == node1)
Owen Taylor3473f882001-02-23 17:55:21 +00003392 return(1);
3393 depth2++;
3394 }
3395 root = cur;
3396 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
Nick Wellnhofera0051992016-06-28 14:19:58 +02003397 if (cur->parent == node2)
Owen Taylor3473f882001-02-23 17:55:21 +00003398 return(-1);
3399 depth1++;
3400 }
3401 /*
3402 * Distinct document (or distinct entities :-( ) case.
3403 */
3404 if (root != cur) {
3405 return(-2);
3406 }
3407 /*
3408 * get the nearest common ancestor.
3409 */
3410 while (depth1 > depth2) {
3411 depth1--;
3412 node1 = node1->parent;
3413 }
3414 while (depth2 > depth1) {
3415 depth2--;
3416 node2 = node2->parent;
3417 }
3418 while (node1->parent != node2->parent) {
3419 node1 = node1->parent;
3420 node2 = node2->parent;
3421 /* should not happen but just in case ... */
3422 if ((node1 == NULL) || (node2 == NULL))
3423 return(-2);
3424 }
3425 /*
3426 * Find who's first.
3427 */
Daniel Veillardf49be472004-02-17 11:48:18 +00003428 if (node1 == node2->prev)
3429 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00003430 if (node1 == node2->next)
3431 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00003432 /*
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003433 * Speedup using document order if available.
Daniel Veillardf49be472004-02-17 11:48:18 +00003434 */
3435 if ((node1->type == XML_ELEMENT_NODE) &&
3436 (node2->type == XML_ELEMENT_NODE) &&
Nick Wellnhoferd422b952017-10-09 13:37:42 +02003437 (0 > (ptrdiff_t) node1->content) &&
3438 (0 > (ptrdiff_t) node2->content) &&
Daniel Veillardf49be472004-02-17 11:48:18 +00003439 (node1->doc == node2->doc)) {
Nick Wellnhoferd422b952017-10-09 13:37:42 +02003440 ptrdiff_t l1, l2;
Daniel Veillardf49be472004-02-17 11:48:18 +00003441
Nick Wellnhoferd422b952017-10-09 13:37:42 +02003442 l1 = -((ptrdiff_t) node1->content);
3443 l2 = -((ptrdiff_t) node2->content);
Daniel Veillardf49be472004-02-17 11:48:18 +00003444 if (l1 < l2)
3445 return(1);
3446 if (l1 > l2)
3447 return(-1);
3448 }
3449
Owen Taylor3473f882001-02-23 17:55:21 +00003450 for (cur = node1->next;cur != NULL;cur = cur->next)
3451 if (cur == node2)
3452 return(1);
3453 return(-1); /* assume there is no sibling list corruption */
3454}
3455
3456/**
3457 * xmlXPathNodeSetSort:
3458 * @set: the node set
3459 *
3460 * Sort the node set in document order
3461 */
3462void
3463xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Vojtech Fried3e031b72012-08-24 16:52:44 +08003464#ifndef WITH_TIM_SORT
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003465 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003466 xmlNodePtr tmp;
Vojtech Fried3e031b72012-08-24 16:52:44 +08003467#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003468
3469 if (set == NULL)
3470 return;
3471
Vojtech Fried3e031b72012-08-24 16:52:44 +08003472#ifndef WITH_TIM_SORT
3473 /*
3474 * Use the old Shell's sort implementation to sort the node-set
3475 * Timsort ought to be quite faster
3476 */
Owen Taylor3473f882001-02-23 17:55:21 +00003477 len = set->nodeNr;
3478 for (incr = len / 2; incr > 0; incr /= 2) {
3479 for (i = incr; i < len; i++) {
3480 j = i - incr;
3481 while (j >= 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003482#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003483 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3484 set->nodeTab[j + incr]) == -1)
3485#else
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003486 if (xmlXPathCmpNodes(set->nodeTab[j],
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003487 set->nodeTab[j + incr]) == -1)
3488#endif
3489 {
Owen Taylor3473f882001-02-23 17:55:21 +00003490 tmp = set->nodeTab[j];
3491 set->nodeTab[j] = set->nodeTab[j + incr];
3492 set->nodeTab[j + incr] = tmp;
3493 j -= incr;
3494 } else
3495 break;
3496 }
3497 }
3498 }
Vojtech Fried3e031b72012-08-24 16:52:44 +08003499#else /* WITH_TIM_SORT */
3500 libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3501#endif /* WITH_TIM_SORT */
Owen Taylor3473f882001-02-23 17:55:21 +00003502}
3503
3504#define XML_NODESET_DEFAULT 10
3505/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003506 * xmlXPathNodeSetDupNs:
3507 * @node: the parent node of the namespace XPath node
3508 * @ns: the libxml namespace declaration node.
3509 *
3510 * Namespace node in libxml don't match the XPath semantic. In a node set
3511 * the namespace nodes are duplicated and the next pointer is set to the
3512 * parent node in the XPath semantic.
3513 *
3514 * Returns the newly created object.
3515 */
3516static xmlNodePtr
3517xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3518 xmlNsPtr cur;
3519
3520 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3521 return(NULL);
3522 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3523 return((xmlNodePtr) ns);
3524
3525 /*
3526 * Allocate a new Namespace and fill the fields.
3527 */
3528 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3529 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003530 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003531 return(NULL);
3532 }
3533 memset(cur, 0, sizeof(xmlNs));
3534 cur->type = XML_NAMESPACE_DECL;
3535 if (ns->href != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003536 cur->href = xmlStrdup(ns->href);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003537 if (ns->prefix != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003538 cur->prefix = xmlStrdup(ns->prefix);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003539 cur->next = (xmlNsPtr) node;
3540 return((xmlNodePtr) cur);
3541}
3542
3543/**
3544 * xmlXPathNodeSetFreeNs:
3545 * @ns: the XPath namespace node found in a nodeset.
3546 *
William M. Brack08171912003-12-29 02:52:11 +00003547 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003548 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00003549 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003550 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00003551void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003552xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3553 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3554 return;
3555
3556 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3557 if (ns->href != NULL)
3558 xmlFree((xmlChar *)ns->href);
3559 if (ns->prefix != NULL)
3560 xmlFree((xmlChar *)ns->prefix);
3561 xmlFree(ns);
3562 }
3563}
3564
3565/**
Owen Taylor3473f882001-02-23 17:55:21 +00003566 * xmlXPathNodeSetCreate:
3567 * @val: an initial xmlNodePtr, or NULL
3568 *
3569 * Create a new xmlNodeSetPtr of type double and of value @val
3570 *
3571 * Returns the newly created object.
3572 */
3573xmlNodeSetPtr
3574xmlXPathNodeSetCreate(xmlNodePtr val) {
3575 xmlNodeSetPtr ret;
3576
3577 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3578 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003579 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003580 return(NULL);
3581 }
3582 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3583 if (val != NULL) {
3584 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3585 sizeof(xmlNodePtr));
3586 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003587 xmlXPathErrMemory(NULL, "creating nodeset\n");
3588 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003589 return(NULL);
3590 }
3591 memset(ret->nodeTab, 0 ,
3592 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3593 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003594 if (val->type == XML_NAMESPACE_DECL) {
3595 xmlNsPtr ns = (xmlNsPtr) val;
3596
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003597 /* TODO: Check memory error. */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003598 ret->nodeTab[ret->nodeNr++] =
3599 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3600 } else
3601 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003602 }
3603 return(ret);
3604}
3605
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003606/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003607 * xmlXPathNodeSetContains:
3608 * @cur: the node-set
3609 * @val: the node
3610 *
3611 * checks whether @cur contains @val
3612 *
3613 * Returns true (1) if @cur contains @val, false (0) otherwise
3614 */
3615int
3616xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3617 int i;
3618
Daniel Veillarda82b1822004-11-08 16:24:57 +00003619 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003620 if (val->type == XML_NAMESPACE_DECL) {
3621 for (i = 0; i < cur->nodeNr; i++) {
3622 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3623 xmlNsPtr ns1, ns2;
3624
3625 ns1 = (xmlNsPtr) val;
3626 ns2 = (xmlNsPtr) cur->nodeTab[i];
3627 if (ns1 == ns2)
3628 return(1);
3629 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3630 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3631 return(1);
3632 }
3633 }
3634 } else {
3635 for (i = 0; i < cur->nodeNr; i++) {
3636 if (cur->nodeTab[i] == val)
3637 return(1);
3638 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003639 }
3640 return(0);
3641}
3642
3643/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003644 * xmlXPathNodeSetAddNs:
3645 * @cur: the initial node set
3646 * @node: the hosting node
3647 * @ns: a the namespace node
3648 *
3649 * add a new namespace node to an existing NodeSet
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003650 *
3651 * Returns 0 in case of success and -1 in case of error
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003652 */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003653int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003654xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3655 int i;
3656
Daniel Veillard45490ae2008-07-29 09:13:19 +00003657
Daniel Veillarda82b1822004-11-08 16:24:57 +00003658 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3659 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003660 (node->type != XML_ELEMENT_NODE))
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003661 return(-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003662
William M. Brack08171912003-12-29 02:52:11 +00003663 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003664 /*
William M. Brack08171912003-12-29 02:52:11 +00003665 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003666 */
3667 for (i = 0;i < cur->nodeNr;i++) {
3668 if ((cur->nodeTab[i] != NULL) &&
3669 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00003670 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003671 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003672 return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003673 }
3674
3675 /*
3676 * grow the nodeTab if needed
3677 */
3678 if (cur->nodeMax == 0) {
3679 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3680 sizeof(xmlNodePtr));
3681 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003682 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003683 return(-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003684 }
3685 memset(cur->nodeTab, 0 ,
3686 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3687 cur->nodeMax = XML_NODESET_DEFAULT;
3688 } else if (cur->nodeNr == cur->nodeMax) {
3689 xmlNodePtr *temp;
3690
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003691 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3692 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003693 return(-1);
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003694 }
Chris Evansd7958b22011-03-23 08:13:06 +08003695 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003696 sizeof(xmlNodePtr));
3697 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003698 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003699 return(-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003700 }
Chris Evansd7958b22011-03-23 08:13:06 +08003701 cur->nodeMax *= 2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003702 cur->nodeTab = temp;
3703 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003704 /* TODO: Check memory error. */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003705 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003706 return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003707}
3708
3709/**
Owen Taylor3473f882001-02-23 17:55:21 +00003710 * xmlXPathNodeSetAdd:
3711 * @cur: the initial node set
3712 * @val: a new xmlNodePtr
3713 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003714 * add a new xmlNodePtr to an existing NodeSet
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003715 *
3716 * Returns 0 in case of success, and -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00003717 */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003718int
Owen Taylor3473f882001-02-23 17:55:21 +00003719xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3720 int i;
3721
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003722 if ((cur == NULL) || (val == NULL)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003723
William M. Brack08171912003-12-29 02:52:11 +00003724 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003725 /*
Shlomi Fishd5bd2a92016-04-03 05:14:44 +03003726 * prevent duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00003727 */
3728 for (i = 0;i < cur->nodeNr;i++)
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003729 if (cur->nodeTab[i] == val) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003730
3731 /*
3732 * grow the nodeTab if needed
3733 */
3734 if (cur->nodeMax == 0) {
3735 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3736 sizeof(xmlNodePtr));
3737 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003738 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003739 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003740 }
3741 memset(cur->nodeTab, 0 ,
3742 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3743 cur->nodeMax = XML_NODESET_DEFAULT;
3744 } else if (cur->nodeNr == cur->nodeMax) {
3745 xmlNodePtr *temp;
3746
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003747 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3748 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003749 return(-1);
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003750 }
Daniel Veillard0cbeb502010-11-15 12:06:29 +01003751 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003752 sizeof(xmlNodePtr));
3753 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003754 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003755 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003756 }
Daniel Veillard0cbeb502010-11-15 12:06:29 +01003757 cur->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003758 cur->nodeTab = temp;
3759 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003760 if (val->type == XML_NAMESPACE_DECL) {
3761 xmlNsPtr ns = (xmlNsPtr) val;
3762
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003763 /* TODO: Check memory error. */
Daniel Veillard45490ae2008-07-29 09:13:19 +00003764 cur->nodeTab[cur->nodeNr++] =
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003765 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3766 } else
3767 cur->nodeTab[cur->nodeNr++] = val;
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003768 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003769}
3770
3771/**
3772 * xmlXPathNodeSetAddUnique:
3773 * @cur: the initial node set
3774 * @val: a new xmlNodePtr
3775 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003776 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00003777 * when we are sure the node is not already in the set.
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003778 *
3779 * Returns 0 in case of success and -1 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +00003780 */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003781int
Owen Taylor3473f882001-02-23 17:55:21 +00003782xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003783 if ((cur == NULL) || (val == NULL)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003784
William M. Brack08171912003-12-29 02:52:11 +00003785 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003786 /*
3787 * grow the nodeTab if needed
3788 */
3789 if (cur->nodeMax == 0) {
3790 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3791 sizeof(xmlNodePtr));
3792 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003793 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003794 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003795 }
3796 memset(cur->nodeTab, 0 ,
3797 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3798 cur->nodeMax = XML_NODESET_DEFAULT;
3799 } else if (cur->nodeNr == cur->nodeMax) {
3800 xmlNodePtr *temp;
3801
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003802 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3803 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003804 return(-1);
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003805 }
Chris Evansd7958b22011-03-23 08:13:06 +08003806 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003807 sizeof(xmlNodePtr));
3808 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003809 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003810 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003811 }
3812 cur->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08003813 cur->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003814 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003815 if (val->type == XML_NAMESPACE_DECL) {
3816 xmlNsPtr ns = (xmlNsPtr) val;
3817
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003818 /* TODO: Check memory error. */
Daniel Veillard45490ae2008-07-29 09:13:19 +00003819 cur->nodeTab[cur->nodeNr++] =
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003820 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3821 } else
3822 cur->nodeTab[cur->nodeNr++] = val;
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003823 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003824}
3825
3826/**
3827 * xmlXPathNodeSetMerge:
3828 * @val1: the first NodeSet or NULL
3829 * @val2: the second NodeSet
3830 *
3831 * Merges two nodesets, all nodes from @val2 are added to @val1
3832 * if @val1 is NULL, a new set is created and copied from @val2
3833 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003834 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003835 */
3836xmlNodeSetPtr
3837xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003838 int i, j, initNr, skip;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003839 xmlNodePtr n1, n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003840
3841 if (val2 == NULL) return(val1);
3842 if (val1 == NULL) {
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003843 val1 = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00003844 if (val1 == NULL)
3845 return (NULL);
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003846#if 0
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003847 /*
3848 * TODO: The optimization won't work in every case, since
3849 * those nasty namespace nodes need to be added with
3850 * xmlXPathNodeSetDupNs() to the set; thus a pure
3851 * memcpy is not possible.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00003852 * If there was a flag on the nodesetval, indicating that
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003853 * some temporary nodes are in, that would be helpful.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003854 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00003855 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003856 * Optimization: Create an equally sized node-set
3857 * and memcpy the content.
3858 */
3859 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3860 if (val1 == NULL)
3861 return(NULL);
3862 if (val2->nodeNr != 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003863 if (val2->nodeNr == 1)
3864 *(val1->nodeTab) = *(val2->nodeTab);
3865 else {
3866 memcpy(val1->nodeTab, val2->nodeTab,
3867 val2->nodeNr * sizeof(xmlNodePtr));
3868 }
3869 val1->nodeNr = val2->nodeNr;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003870 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003871 return(val1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003872#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003873 }
3874
William M. Brack08171912003-12-29 02:52:11 +00003875 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003876 initNr = val1->nodeNr;
3877
3878 for (i = 0;i < val2->nodeNr;i++) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00003879 n2 = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00003880 /*
William M. Brack08171912003-12-29 02:52:11 +00003881 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00003882 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003883 skip = 0;
3884 for (j = 0; j < initNr; j++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003885 n1 = val1->nodeTab[j];
3886 if (n1 == n2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003887 skip = 1;
3888 break;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003889 } else if ((n1->type == XML_NAMESPACE_DECL) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +00003890 (n2->type == XML_NAMESPACE_DECL)) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003891 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3892 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3893 ((xmlNsPtr) n2)->prefix)))
3894 {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003895 skip = 1;
3896 break;
3897 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003898 }
3899 }
3900 if (skip)
3901 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00003902
3903 /*
3904 * grow the nodeTab if needed
3905 */
3906 if (val1->nodeMax == 0) {
3907 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3908 sizeof(xmlNodePtr));
3909 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003910 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003911 return(NULL);
3912 }
3913 memset(val1->nodeTab, 0 ,
3914 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3915 val1->nodeMax = XML_NODESET_DEFAULT;
3916 } else if (val1->nodeNr == val1->nodeMax) {
3917 xmlNodePtr *temp;
3918
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003919 if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3920 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3921 return(NULL);
3922 }
Chris Evansd7958b22011-03-23 08:13:06 +08003923 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003924 sizeof(xmlNodePtr));
3925 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003926 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003927 return(NULL);
3928 }
3929 val1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08003930 val1->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003931 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003932 if (n2->type == XML_NAMESPACE_DECL) {
3933 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003934
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003935 /* TODO: Check memory error. */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003936 val1->nodeTab[val1->nodeNr++] =
3937 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3938 } else
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003939 val1->nodeTab[val1->nodeNr++] = n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003940 }
3941
3942 return(val1);
3943}
3944
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003945
3946/**
3947 * xmlXPathNodeSetMergeAndClear:
3948 * @set1: the first NodeSet or NULL
3949 * @set2: the second NodeSet
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003950 *
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003951 * Merges two nodesets, all nodes from @set2 are added to @set1.
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003952 * Checks for duplicate nodes. Clears set2.
3953 *
3954 * Returns @set1 once extended or NULL in case of error.
3955 */
3956static xmlNodeSetPtr
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003957xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003958{
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003959 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003960 int i, j, initNbSet1;
3961 xmlNodePtr n1, n2;
3962
Daniel Veillard45490ae2008-07-29 09:13:19 +00003963 initNbSet1 = set1->nodeNr;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003964 for (i = 0;i < set2->nodeNr;i++) {
3965 n2 = set2->nodeTab[i];
3966 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003967 * Skip duplicates.
3968 */
3969 for (j = 0; j < initNbSet1; j++) {
3970 n1 = set1->nodeTab[j];
Daniel Veillard45490ae2008-07-29 09:13:19 +00003971 if (n1 == n2) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003972 goto skip_node;
3973 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3974 (n2->type == XML_NAMESPACE_DECL))
Daniel Veillard45490ae2008-07-29 09:13:19 +00003975 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003976 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3977 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3978 ((xmlNsPtr) n2)->prefix)))
3979 {
3980 /*
3981 * Free the namespace node.
3982 */
3983 set2->nodeTab[i] = NULL;
3984 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3985 goto skip_node;
3986 }
3987 }
3988 }
3989 /*
3990 * grow the nodeTab if needed
3991 */
3992 if (set1->nodeMax == 0) {
3993 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3994 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3995 if (set1->nodeTab == NULL) {
3996 xmlXPathErrMemory(NULL, "merging nodeset\n");
3997 return(NULL);
3998 }
3999 memset(set1->nodeTab, 0,
4000 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4001 set1->nodeMax = XML_NODESET_DEFAULT;
4002 } else if (set1->nodeNr >= set1->nodeMax) {
4003 xmlNodePtr *temp;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004004
Daniel Veillardcd852ad2012-07-30 10:12:18 +08004005 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4006 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4007 return(NULL);
4008 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004009 temp = (xmlNodePtr *) xmlRealloc(
Chris Evansd7958b22011-03-23 08:13:06 +08004010 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004011 if (temp == NULL) {
4012 xmlXPathErrMemory(NULL, "merging nodeset\n");
4013 return(NULL);
4014 }
4015 set1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08004016 set1->nodeMax *= 2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004017 }
Nick Wellnhofer9d08b342017-05-21 16:46:12 +02004018 set1->nodeTab[set1->nodeNr++] = n2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004019skip_node:
4020 {}
4021 }
4022 }
4023 set2->nodeNr = 0;
4024 return(set1);
4025}
4026
4027/**
4028 * xmlXPathNodeSetMergeAndClearNoDupls:
4029 * @set1: the first NodeSet or NULL
4030 * @set2: the second NodeSet
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004031 *
Haibo Huangcfd91dc2020-07-30 23:01:33 -07004032 * Merges two nodesets, all nodes from @set2 are added to @set1.
4033 * Doesn't check for duplicate nodes. Clears set2.
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004034 *
4035 * Returns @set1 once extended or NULL in case of error.
4036 */
4037static xmlNodeSetPtr
Haibo Huangcfd91dc2020-07-30 23:01:33 -07004038xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004039{
Haibo Huangcfd91dc2020-07-30 23:01:33 -07004040 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004041 int i;
4042 xmlNodePtr n2;
4043
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004044 for (i = 0;i < set2->nodeNr;i++) {
4045 n2 = set2->nodeTab[i];
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004046 if (set1->nodeMax == 0) {
4047 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4048 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4049 if (set1->nodeTab == NULL) {
4050 xmlXPathErrMemory(NULL, "merging nodeset\n");
4051 return(NULL);
4052 }
4053 memset(set1->nodeTab, 0,
4054 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4055 set1->nodeMax = XML_NODESET_DEFAULT;
4056 } else if (set1->nodeNr >= set1->nodeMax) {
4057 xmlNodePtr *temp;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004058
Daniel Veillardcd852ad2012-07-30 10:12:18 +08004059 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4060 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4061 return(NULL);
4062 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004063 temp = (xmlNodePtr *) xmlRealloc(
Chris Evansd7958b22011-03-23 08:13:06 +08004064 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004065 if (temp == NULL) {
4066 xmlXPathErrMemory(NULL, "merging nodeset\n");
4067 return(NULL);
4068 }
4069 set1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08004070 set1->nodeMax *= 2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004071 }
4072 set1->nodeTab[set1->nodeNr++] = n2;
4073 }
4074 }
4075 set2->nodeNr = 0;
4076 return(set1);
4077}
Daniel Veillard75be0132002-03-13 10:03:35 +00004078
4079/**
Owen Taylor3473f882001-02-23 17:55:21 +00004080 * xmlXPathNodeSetDel:
4081 * @cur: the initial node set
4082 * @val: an xmlNodePtr
4083 *
4084 * Removes an xmlNodePtr from an existing NodeSet
4085 */
4086void
4087xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4088 int i;
4089
4090 if (cur == NULL) return;
4091 if (val == NULL) return;
4092
4093 /*
William M. Brack08171912003-12-29 02:52:11 +00004094 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00004095 */
4096 for (i = 0;i < cur->nodeNr;i++)
4097 if (cur->nodeTab[i] == val) break;
4098
William M. Brack08171912003-12-29 02:52:11 +00004099 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00004100#ifdef DEBUG
Daniel Veillard45490ae2008-07-29 09:13:19 +00004101 xmlGenericError(xmlGenericErrorContext,
Owen Taylor3473f882001-02-23 17:55:21 +00004102 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4103 val->name);
4104#endif
4105 return;
4106 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004107 if ((cur->nodeTab[i] != NULL) &&
4108 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4109 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004110 cur->nodeNr--;
4111 for (;i < cur->nodeNr;i++)
4112 cur->nodeTab[i] = cur->nodeTab[i + 1];
4113 cur->nodeTab[cur->nodeNr] = NULL;
4114}
4115
4116/**
4117 * xmlXPathNodeSetRemove:
4118 * @cur: the initial node set
4119 * @val: the index to remove
4120 *
4121 * Removes an entry from an existing NodeSet list.
4122 */
4123void
4124xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4125 if (cur == NULL) return;
4126 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004127 if ((cur->nodeTab[val] != NULL) &&
4128 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4129 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00004130 cur->nodeNr--;
4131 for (;val < cur->nodeNr;val++)
4132 cur->nodeTab[val] = cur->nodeTab[val + 1];
4133 cur->nodeTab[cur->nodeNr] = NULL;
4134}
4135
4136/**
4137 * xmlXPathFreeNodeSet:
4138 * @obj: the xmlNodeSetPtr to free
4139 *
4140 * Free the NodeSet compound (not the actual nodes !).
4141 */
4142void
4143xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4144 if (obj == NULL) return;
4145 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004146 int i;
4147
William M. Brack08171912003-12-29 02:52:11 +00004148 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004149 for (i = 0;i < obj->nodeNr;i++)
4150 if ((obj->nodeTab[i] != NULL) &&
4151 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4152 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004153 xmlFree(obj->nodeTab);
4154 }
Owen Taylor3473f882001-02-23 17:55:21 +00004155 xmlFree(obj);
4156}
4157
4158/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004159 * xmlXPathNodeSetClearFromPos:
4160 * @set: the node set to be cleared
4161 * @pos: the start position to clear from
Daniel Veillard45490ae2008-07-29 09:13:19 +00004162 *
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004163 * Clears the list from temporary XPath objects (e.g. namespace nodes
4164 * are feed) starting with the entry at @pos, but does *not* free the list
4165 * itself. Sets the length of the list to @pos.
4166 */
4167static void
4168xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4169{
Nick Wellnhofer95a92492017-05-21 15:18:58 +02004170 if ((set == NULL) || (pos >= set->nodeNr))
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004171 return;
4172 else if ((hasNsNodes)) {
4173 int i;
4174 xmlNodePtr node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004175
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004176 for (i = pos; i < set->nodeNr; i++) {
4177 node = set->nodeTab[i];
4178 if ((node != NULL) &&
4179 (node->type == XML_NAMESPACE_DECL))
4180 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
Daniel Veillard45490ae2008-07-29 09:13:19 +00004181 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004182 }
4183 set->nodeNr = pos;
4184}
4185
4186/**
Nick Wellnhofer95a92492017-05-21 15:18:58 +02004187 * xmlXPathNodeSetClear:
4188 * @set: the node set to clear
4189 *
4190 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4191 * are feed), but does *not* free the list itself. Sets the length of the
4192 * list to 0.
4193 */
4194static void
4195xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4196{
4197 xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4198}
4199
4200/**
4201 * xmlXPathNodeSetKeepLast:
4202 * @set: the node set to be cleared
4203 *
4204 * Move the last node to the first position and clear temporary XPath objects
4205 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4206 * to 1.
4207 */
4208static void
4209xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4210{
4211 int i;
4212 xmlNodePtr node;
4213
4214 if ((set == NULL) || (set->nodeNr <= 1))
4215 return;
4216 for (i = 0; i < set->nodeNr - 1; i++) {
4217 node = set->nodeTab[i];
4218 if ((node != NULL) &&
4219 (node->type == XML_NAMESPACE_DECL))
4220 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4221 }
4222 set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4223 set->nodeNr = 1;
4224}
4225
4226/**
Owen Taylor3473f882001-02-23 17:55:21 +00004227 * xmlXPathFreeValueTree:
4228 * @obj: the xmlNodeSetPtr to free
4229 *
4230 * Free the NodeSet compound and the actual tree, this is different
4231 * from xmlXPathFreeNodeSet()
4232 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004233static void
Owen Taylor3473f882001-02-23 17:55:21 +00004234xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4235 int i;
4236
4237 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00004238
4239 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004240 for (i = 0;i < obj->nodeNr;i++) {
4241 if (obj->nodeTab[i] != NULL) {
4242 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4243 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4244 } else {
4245 xmlFreeNodeList(obj->nodeTab[i]);
4246 }
4247 }
4248 }
Owen Taylor3473f882001-02-23 17:55:21 +00004249 xmlFree(obj->nodeTab);
4250 }
Owen Taylor3473f882001-02-23 17:55:21 +00004251 xmlFree(obj);
4252}
4253
4254#if defined(DEBUG) || defined(DEBUG_STEP)
4255/**
4256 * xmlGenericErrorContextNodeSet:
4257 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00004258 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00004259 *
4260 * Quick display of a NodeSet
4261 */
4262void
4263xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4264 int i;
4265
4266 if (output == NULL) output = xmlGenericErrorContext;
4267 if (obj == NULL) {
4268 fprintf(output, "NodeSet == NULL !\n");
4269 return;
4270 }
4271 if (obj->nodeNr == 0) {
4272 fprintf(output, "NodeSet is empty\n");
4273 return;
4274 }
4275 if (obj->nodeTab == NULL) {
4276 fprintf(output, " nodeTab == NULL !\n");
4277 return;
4278 }
4279 for (i = 0; i < obj->nodeNr; i++) {
4280 if (obj->nodeTab[i] == NULL) {
4281 fprintf(output, " NULL !\n");
4282 return;
4283 }
4284 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4285 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4286 fprintf(output, " /");
4287 else if (obj->nodeTab[i]->name == NULL)
4288 fprintf(output, " noname!");
4289 else fprintf(output, " %s", obj->nodeTab[i]->name);
4290 }
4291 fprintf(output, "\n");
4292}
4293#endif
4294
4295/**
4296 * xmlXPathNewNodeSet:
4297 * @val: the NodePtr value
4298 *
4299 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4300 * it with the single Node @val
4301 *
4302 * Returns the newly created object.
4303 */
4304xmlXPathObjectPtr
4305xmlXPathNewNodeSet(xmlNodePtr val) {
4306 xmlXPathObjectPtr ret;
4307
4308 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4309 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004310 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004311 return(NULL);
4312 }
4313 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4314 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00004315 ret->boolval = 0;
Haibo Huangcfd91dc2020-07-30 23:01:33 -07004316 /* TODO: Check memory error. */
Owen Taylor3473f882001-02-23 17:55:21 +00004317 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00004318 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004319#ifdef XP_DEBUG_OBJ_USAGE
4320 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4321#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004322 return(ret);
4323}
4324
4325/**
4326 * xmlXPathNewValueTree:
4327 * @val: the NodePtr value
4328 *
4329 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4330 * it with the tree root @val
4331 *
4332 * Returns the newly created object.
4333 */
4334xmlXPathObjectPtr
4335xmlXPathNewValueTree(xmlNodePtr val) {
4336 xmlXPathObjectPtr ret;
4337
4338 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4339 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004340 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004341 return(NULL);
4342 }
4343 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4344 ret->type = XPATH_XSLT_TREE;
Elliott Hughes7fbecab2019-01-10 16:42:03 -08004345 ret->boolval = 1;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00004346 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00004347 ret->nodesetval = xmlXPathNodeSetCreate(val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004348#ifdef XP_DEBUG_OBJ_USAGE
4349 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4350#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004351 return(ret);
4352}
4353
4354/**
4355 * xmlXPathNewNodeSetList:
4356 * @val: an existing NodeSet
4357 *
4358 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4359 * it with the Nodeset @val
4360 *
4361 * Returns the newly created object.
4362 */
4363xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004364xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4365{
Owen Taylor3473f882001-02-23 17:55:21 +00004366 xmlXPathObjectPtr ret;
4367 int i;
4368
4369 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004370 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00004371 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004372 ret = xmlXPathNewNodeSet(NULL);
4373 else {
4374 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004375 if (ret) {
4376 for (i = 1; i < val->nodeNr; ++i) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07004377 /* TODO: Propagate memory error. */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004378 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4379 < 0) break;
4380 }
4381 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004382 }
Owen Taylor3473f882001-02-23 17:55:21 +00004383
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004384 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004385}
4386
4387/**
4388 * xmlXPathWrapNodeSet:
4389 * @val: the NodePtr value
4390 *
4391 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4392 *
4393 * Returns the newly created object.
4394 */
4395xmlXPathObjectPtr
4396xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4397 xmlXPathObjectPtr ret;
4398
4399 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4400 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004401 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004402 return(NULL);
4403 }
4404 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4405 ret->type = XPATH_NODESET;
4406 ret->nodesetval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004407#ifdef XP_DEBUG_OBJ_USAGE
4408 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4409#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004410 return(ret);
4411}
4412
4413/**
4414 * xmlXPathFreeNodeSetList:
4415 * @obj: an existing NodeSetList object
4416 *
4417 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4418 * the list contrary to xmlXPathFreeObject().
4419 */
4420void
4421xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4422 if (obj == NULL) return;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004423#ifdef XP_DEBUG_OBJ_USAGE
4424 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4425#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004426 xmlFree(obj);
4427}
4428
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004429/**
4430 * xmlXPathDifference:
4431 * @nodes1: a node-set
4432 * @nodes2: a node-set
4433 *
4434 * Implements the EXSLT - Sets difference() function:
4435 * node-set set:difference (node-set, node-set)
4436 *
4437 * Returns the difference between the two node sets, or nodes1 if
4438 * nodes2 is empty
4439 */
4440xmlNodeSetPtr
4441xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4442 xmlNodeSetPtr ret;
4443 int i, l1;
4444 xmlNodePtr cur;
4445
4446 if (xmlXPathNodeSetIsEmpty(nodes2))
4447 return(nodes1);
4448
Haibo Huangcfd91dc2020-07-30 23:01:33 -07004449 /* TODO: Check memory error. */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004450 ret = xmlXPathNodeSetCreate(NULL);
4451 if (xmlXPathNodeSetIsEmpty(nodes1))
4452 return(ret);
4453
4454 l1 = xmlXPathNodeSetGetLength(nodes1);
4455
4456 for (i = 0; i < l1; i++) {
4457 cur = xmlXPathNodeSetItem(nodes1, i);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004458 if (!xmlXPathNodeSetContains(nodes2, cur)) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07004459 /* TODO: Propagate memory error. */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004460 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4461 break;
4462 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004463 }
4464 return(ret);
4465}
4466
4467/**
4468 * xmlXPathIntersection:
4469 * @nodes1: a node-set
4470 * @nodes2: a node-set
4471 *
4472 * Implements the EXSLT - Sets intersection() function:
4473 * node-set set:intersection (node-set, node-set)
4474 *
4475 * Returns a node set comprising the nodes that are within both the
4476 * node sets passed as arguments
4477 */
4478xmlNodeSetPtr
4479xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4480 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4481 int i, l1;
4482 xmlNodePtr cur;
4483
Daniel Veillardf88d8492008-04-01 08:00:31 +00004484 if (ret == NULL)
4485 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004486 if (xmlXPathNodeSetIsEmpty(nodes1))
4487 return(ret);
4488 if (xmlXPathNodeSetIsEmpty(nodes2))
4489 return(ret);
4490
4491 l1 = xmlXPathNodeSetGetLength(nodes1);
4492
4493 for (i = 0; i < l1; i++) {
4494 cur = xmlXPathNodeSetItem(nodes1, i);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004495 if (xmlXPathNodeSetContains(nodes2, cur)) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07004496 /* TODO: Propagate memory error. */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004497 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4498 break;
4499 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004500 }
4501 return(ret);
4502}
4503
4504/**
4505 * xmlXPathDistinctSorted:
4506 * @nodes: a node-set, sorted by document order
4507 *
4508 * Implements the EXSLT - Sets distinct() function:
4509 * node-set set:distinct (node-set)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004510 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004511 * Returns a subset of the nodes contained in @nodes, or @nodes if
4512 * it is empty
4513 */
4514xmlNodeSetPtr
4515xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4516 xmlNodeSetPtr ret;
4517 xmlHashTablePtr hash;
4518 int i, l;
4519 xmlChar * strval;
4520 xmlNodePtr cur;
4521
4522 if (xmlXPathNodeSetIsEmpty(nodes))
4523 return(nodes);
4524
4525 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004526 if (ret == NULL)
4527 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004528 l = xmlXPathNodeSetGetLength(nodes);
4529 hash = xmlHashCreate (l);
4530 for (i = 0; i < l; i++) {
4531 cur = xmlXPathNodeSetItem(nodes, i);
4532 strval = xmlXPathCastNodeToString(cur);
4533 if (xmlHashLookup(hash, strval) == NULL) {
4534 xmlHashAddEntry(hash, strval, strval);
Haibo Huangcfd91dc2020-07-30 23:01:33 -07004535 /* TODO: Propagate memory error. */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004536 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4537 break;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004538 } else {
4539 xmlFree(strval);
4540 }
4541 }
Nick Wellnhofere03f0a12017-11-09 16:42:47 +01004542 xmlHashFree(hash, xmlHashDefaultDeallocator);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004543 return(ret);
4544}
4545
4546/**
4547 * xmlXPathDistinct:
4548 * @nodes: a node-set
4549 *
4550 * Implements the EXSLT - Sets distinct() function:
4551 * node-set set:distinct (node-set)
4552 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4553 * is called with the sorted node-set
4554 *
4555 * Returns a subset of the nodes contained in @nodes, or @nodes if
4556 * it is empty
4557 */
4558xmlNodeSetPtr
4559xmlXPathDistinct (xmlNodeSetPtr nodes) {
4560 if (xmlXPathNodeSetIsEmpty(nodes))
4561 return(nodes);
4562
4563 xmlXPathNodeSetSort(nodes);
4564 return(xmlXPathDistinctSorted(nodes));
4565}
4566
4567/**
4568 * xmlXPathHasSameNodes:
4569 * @nodes1: a node-set
4570 * @nodes2: a node-set
4571 *
4572 * Implements the EXSLT - Sets has-same-nodes function:
4573 * boolean set:has-same-node(node-set, node-set)
4574 *
4575 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4576 * otherwise
4577 */
4578int
4579xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4580 int i, l;
4581 xmlNodePtr cur;
4582
4583 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4584 xmlXPathNodeSetIsEmpty(nodes2))
4585 return(0);
4586
4587 l = xmlXPathNodeSetGetLength(nodes1);
4588 for (i = 0; i < l; i++) {
4589 cur = xmlXPathNodeSetItem(nodes1, i);
4590 if (xmlXPathNodeSetContains(nodes2, cur))
4591 return(1);
4592 }
4593 return(0);
4594}
4595
4596/**
4597 * xmlXPathNodeLeadingSorted:
4598 * @nodes: a node-set, sorted by document order
4599 * @node: a node
4600 *
4601 * Implements the EXSLT - Sets leading() function:
4602 * node-set set:leading (node-set, node-set)
4603 *
4604 * Returns the nodes in @nodes that precede @node in document order,
4605 * @nodes if @node is NULL or an empty node-set if @nodes
4606 * doesn't contain @node
4607 */
4608xmlNodeSetPtr
4609xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4610 int i, l;
4611 xmlNodePtr cur;
4612 xmlNodeSetPtr ret;
4613
4614 if (node == NULL)
4615 return(nodes);
4616
4617 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004618 if (ret == NULL)
4619 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004620 if (xmlXPathNodeSetIsEmpty(nodes) ||
4621 (!xmlXPathNodeSetContains(nodes, node)))
4622 return(ret);
4623
4624 l = xmlXPathNodeSetGetLength(nodes);
4625 for (i = 0; i < l; i++) {
4626 cur = xmlXPathNodeSetItem(nodes, i);
4627 if (cur == node)
4628 break;
Haibo Huangcfd91dc2020-07-30 23:01:33 -07004629 /* TODO: Propagate memory error. */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004630 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4631 break;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004632 }
4633 return(ret);
4634}
4635
4636/**
4637 * xmlXPathNodeLeading:
4638 * @nodes: a node-set
4639 * @node: a node
4640 *
4641 * Implements the EXSLT - Sets leading() function:
4642 * node-set set:leading (node-set, node-set)
4643 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4644 * is called.
4645 *
4646 * Returns the nodes in @nodes that precede @node in document order,
4647 * @nodes if @node is NULL or an empty node-set if @nodes
4648 * doesn't contain @node
4649 */
4650xmlNodeSetPtr
4651xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4652 xmlXPathNodeSetSort(nodes);
4653 return(xmlXPathNodeLeadingSorted(nodes, node));
4654}
4655
4656/**
4657 * xmlXPathLeadingSorted:
4658 * @nodes1: a node-set, sorted by document order
4659 * @nodes2: a node-set, sorted by document order
4660 *
4661 * Implements the EXSLT - Sets leading() function:
4662 * node-set set:leading (node-set, node-set)
4663 *
4664 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4665 * in document order, @nodes1 if @nodes2 is NULL or empty or
4666 * an empty node-set if @nodes1 doesn't contain @nodes2
4667 */
4668xmlNodeSetPtr
4669xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4670 if (xmlXPathNodeSetIsEmpty(nodes2))
4671 return(nodes1);
4672 return(xmlXPathNodeLeadingSorted(nodes1,
4673 xmlXPathNodeSetItem(nodes2, 1)));
4674}
4675
4676/**
4677 * xmlXPathLeading:
4678 * @nodes1: a node-set
4679 * @nodes2: a node-set
4680 *
4681 * Implements the EXSLT - Sets leading() function:
4682 * node-set set:leading (node-set, node-set)
4683 * @nodes1 and @nodes2 are sorted by document order, then
4684 * #exslSetsLeadingSorted is called.
4685 *
4686 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4687 * in document order, @nodes1 if @nodes2 is NULL or empty or
4688 * an empty node-set if @nodes1 doesn't contain @nodes2
4689 */
4690xmlNodeSetPtr
4691xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4692 if (xmlXPathNodeSetIsEmpty(nodes2))
4693 return(nodes1);
4694 if (xmlXPathNodeSetIsEmpty(nodes1))
4695 return(xmlXPathNodeSetCreate(NULL));
4696 xmlXPathNodeSetSort(nodes1);
4697 xmlXPathNodeSetSort(nodes2);
4698 return(xmlXPathNodeLeadingSorted(nodes1,
4699 xmlXPathNodeSetItem(nodes2, 1)));
4700}
4701
4702/**
4703 * xmlXPathNodeTrailingSorted:
4704 * @nodes: a node-set, sorted by document order
4705 * @node: a node
4706 *
4707 * Implements the EXSLT - Sets trailing() function:
4708 * node-set set:trailing (node-set, node-set)
4709 *
4710 * Returns the nodes in @nodes that follow @node in document order,
4711 * @nodes if @node is NULL or an empty node-set if @nodes
4712 * doesn't contain @node
4713 */
4714xmlNodeSetPtr
4715xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4716 int i, l;
4717 xmlNodePtr cur;
4718 xmlNodeSetPtr ret;
4719
4720 if (node == NULL)
4721 return(nodes);
4722
4723 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004724 if (ret == NULL)
4725 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004726 if (xmlXPathNodeSetIsEmpty(nodes) ||
4727 (!xmlXPathNodeSetContains(nodes, node)))
4728 return(ret);
4729
4730 l = xmlXPathNodeSetGetLength(nodes);
William M. Brack97ac8192007-06-06 17:19:24 +00004731 for (i = l - 1; i >= 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004732 cur = xmlXPathNodeSetItem(nodes, i);
4733 if (cur == node)
4734 break;
Haibo Huangcfd91dc2020-07-30 23:01:33 -07004735 /* TODO: Propagate memory error. */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004736 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4737 break;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004738 }
William M. Brack97ac8192007-06-06 17:19:24 +00004739 xmlXPathNodeSetSort(ret); /* bug 413451 */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004740 return(ret);
4741}
4742
4743/**
4744 * xmlXPathNodeTrailing:
4745 * @nodes: a node-set
4746 * @node: a node
4747 *
4748 * Implements the EXSLT - Sets trailing() function:
4749 * node-set set:trailing (node-set, node-set)
4750 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4751 * is called.
4752 *
4753 * Returns the nodes in @nodes that follow @node in document order,
4754 * @nodes if @node is NULL or an empty node-set if @nodes
4755 * doesn't contain @node
4756 */
4757xmlNodeSetPtr
4758xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4759 xmlXPathNodeSetSort(nodes);
4760 return(xmlXPathNodeTrailingSorted(nodes, node));
4761}
4762
4763/**
4764 * xmlXPathTrailingSorted:
4765 * @nodes1: a node-set, sorted by document order
4766 * @nodes2: a node-set, sorted by document order
4767 *
4768 * Implements the EXSLT - Sets trailing() function:
4769 * node-set set:trailing (node-set, node-set)
4770 *
4771 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4772 * in document order, @nodes1 if @nodes2 is NULL or empty or
4773 * an empty node-set if @nodes1 doesn't contain @nodes2
4774 */
4775xmlNodeSetPtr
4776xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4777 if (xmlXPathNodeSetIsEmpty(nodes2))
4778 return(nodes1);
4779 return(xmlXPathNodeTrailingSorted(nodes1,
4780 xmlXPathNodeSetItem(nodes2, 0)));
4781}
4782
4783/**
4784 * xmlXPathTrailing:
4785 * @nodes1: a node-set
4786 * @nodes2: a node-set
4787 *
4788 * Implements the EXSLT - Sets trailing() function:
4789 * node-set set:trailing (node-set, node-set)
4790 * @nodes1 and @nodes2 are sorted by document order, then
4791 * #xmlXPathTrailingSorted is called.
4792 *
4793 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4794 * in document order, @nodes1 if @nodes2 is NULL or empty or
4795 * an empty node-set if @nodes1 doesn't contain @nodes2
4796 */
4797xmlNodeSetPtr
4798xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4799 if (xmlXPathNodeSetIsEmpty(nodes2))
4800 return(nodes1);
4801 if (xmlXPathNodeSetIsEmpty(nodes1))
4802 return(xmlXPathNodeSetCreate(NULL));
4803 xmlXPathNodeSetSort(nodes1);
4804 xmlXPathNodeSetSort(nodes2);
4805 return(xmlXPathNodeTrailingSorted(nodes1,
4806 xmlXPathNodeSetItem(nodes2, 0)));
4807}
4808
Owen Taylor3473f882001-02-23 17:55:21 +00004809/************************************************************************
4810 * *
4811 * Routines to handle extra functions *
4812 * *
4813 ************************************************************************/
4814
4815/**
4816 * xmlXPathRegisterFunc:
4817 * @ctxt: the XPath context
4818 * @name: the function name
4819 * @f: the function implementation or NULL
4820 *
4821 * Register a new function. If @f is NULL it unregisters the function
4822 *
4823 * Returns 0 in case of success, -1 in case of error
4824 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00004825int
Owen Taylor3473f882001-02-23 17:55:21 +00004826xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4827 xmlXPathFunction f) {
4828 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4829}
4830
4831/**
4832 * xmlXPathRegisterFuncNS:
4833 * @ctxt: the XPath context
4834 * @name: the function name
4835 * @ns_uri: the function namespace URI
4836 * @f: the function implementation or NULL
4837 *
4838 * Register a new function. If @f is NULL it unregisters the function
4839 *
4840 * Returns 0 in case of success, -1 in case of error
4841 */
4842int
4843xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4844 const xmlChar *ns_uri, xmlXPathFunction f) {
4845 if (ctxt == NULL)
4846 return(-1);
4847 if (name == NULL)
4848 return(-1);
4849
4850 if (ctxt->funcHash == NULL)
4851 ctxt->funcHash = xmlHashCreate(0);
4852 if (ctxt->funcHash == NULL)
4853 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004854 if (f == NULL)
4855 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
Nick Wellnhofer13acadb2017-11-12 17:28:12 +01004856XML_IGNORE_PEDANTIC_WARNINGS
4857 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4858XML_POP_WARNINGS
Owen Taylor3473f882001-02-23 17:55:21 +00004859}
4860
4861/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00004862 * xmlXPathRegisterFuncLookup:
4863 * @ctxt: the XPath context
4864 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004865 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00004866 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004867 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00004868 */
4869void
4870xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4871 xmlXPathFuncLookupFunc f,
4872 void *funcCtxt) {
4873 if (ctxt == NULL)
4874 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004875 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004876 ctxt->funcLookupData = funcCtxt;
4877}
4878
4879/**
Owen Taylor3473f882001-02-23 17:55:21 +00004880 * xmlXPathFunctionLookup:
4881 * @ctxt: the XPath context
4882 * @name: the function name
4883 *
4884 * Search in the Function array of the context for the given
4885 * function.
4886 *
4887 * Returns the xmlXPathFunction or NULL if not found
4888 */
4889xmlXPathFunction
4890xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00004891 if (ctxt == NULL)
4892 return (NULL);
4893
4894 if (ctxt->funcLookupFunc != NULL) {
4895 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004896 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004897
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004898 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004899 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004900 if (ret != NULL)
4901 return(ret);
4902 }
Owen Taylor3473f882001-02-23 17:55:21 +00004903 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4904}
4905
4906/**
4907 * xmlXPathFunctionLookupNS:
4908 * @ctxt: the XPath context
4909 * @name: the function name
4910 * @ns_uri: the function namespace URI
4911 *
4912 * Search in the Function array of the context for the given
4913 * function.
4914 *
4915 * Returns the xmlXPathFunction or NULL if not found
4916 */
4917xmlXPathFunction
4918xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4919 const xmlChar *ns_uri) {
William M. Brackad0e67c2004-12-01 14:35:10 +00004920 xmlXPathFunction ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004921
Owen Taylor3473f882001-02-23 17:55:21 +00004922 if (ctxt == NULL)
4923 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004924 if (name == NULL)
4925 return(NULL);
4926
Thomas Broyerba4ad322001-07-26 16:55:21 +00004927 if (ctxt->funcLookupFunc != NULL) {
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004928 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004929
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004930 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004931 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004932 if (ret != NULL)
4933 return(ret);
4934 }
4935
4936 if (ctxt->funcHash == NULL)
4937 return(NULL);
4938
Nick Wellnhofer13acadb2017-11-12 17:28:12 +01004939XML_IGNORE_PEDANTIC_WARNINGS
4940 ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4941XML_POP_WARNINGS
William M. Brackad0e67c2004-12-01 14:35:10 +00004942 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004943}
4944
4945/**
4946 * xmlXPathRegisteredFuncsCleanup:
4947 * @ctxt: the XPath context
4948 *
4949 * Cleanup the XPath context data associated to registered functions
4950 */
4951void
4952xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4953 if (ctxt == NULL)
4954 return;
4955
4956 xmlHashFree(ctxt->funcHash, NULL);
4957 ctxt->funcHash = NULL;
4958}
4959
4960/************************************************************************
4961 * *
William M. Brack08171912003-12-29 02:52:11 +00004962 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00004963 * *
4964 ************************************************************************/
4965
4966/**
4967 * xmlXPathRegisterVariable:
4968 * @ctxt: the XPath context
4969 * @name: the variable name
4970 * @value: the variable value or NULL
4971 *
4972 * Register a new variable value. If @value is NULL it unregisters
4973 * the variable
4974 *
4975 * Returns 0 in case of success, -1 in case of error
4976 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00004977int
Owen Taylor3473f882001-02-23 17:55:21 +00004978xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4979 xmlXPathObjectPtr value) {
4980 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4981}
4982
4983/**
4984 * xmlXPathRegisterVariableNS:
4985 * @ctxt: the XPath context
4986 * @name: the variable name
4987 * @ns_uri: the variable namespace URI
4988 * @value: the variable value or NULL
4989 *
4990 * Register a new variable value. If @value is NULL it unregisters
4991 * the variable
4992 *
4993 * Returns 0 in case of success, -1 in case of error
4994 */
4995int
4996xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4997 const xmlChar *ns_uri,
4998 xmlXPathObjectPtr value) {
4999 if (ctxt == NULL)
5000 return(-1);
5001 if (name == NULL)
5002 return(-1);
5003
5004 if (ctxt->varHash == NULL)
5005 ctxt->varHash = xmlHashCreate(0);
5006 if (ctxt->varHash == NULL)
5007 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00005008 if (value == NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00005009 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
Nick Wellnhofere03f0a12017-11-09 16:42:47 +01005010 xmlXPathFreeObjectEntry));
Owen Taylor3473f882001-02-23 17:55:21 +00005011 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
Nick Wellnhofere03f0a12017-11-09 16:42:47 +01005012 (void *) value, xmlXPathFreeObjectEntry));
Owen Taylor3473f882001-02-23 17:55:21 +00005013}
5014
5015/**
5016 * xmlXPathRegisterVariableLookup:
5017 * @ctxt: the XPath context
5018 * @f: the lookup function
5019 * @data: the lookup data
5020 *
5021 * register an external mechanism to do variable lookup
5022 */
5023void
5024xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5025 xmlXPathVariableLookupFunc f, void *data) {
5026 if (ctxt == NULL)
5027 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00005028 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00005029 ctxt->varLookupData = data;
5030}
5031
5032/**
5033 * xmlXPathVariableLookup:
5034 * @ctxt: the XPath context
5035 * @name: the variable name
5036 *
5037 * Search in the Variable array of the context for the given
5038 * variable value.
5039 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00005040 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00005041 */
5042xmlXPathObjectPtr
5043xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5044 if (ctxt == NULL)
5045 return(NULL);
5046
5047 if (ctxt->varLookupFunc != NULL) {
5048 xmlXPathObjectPtr ret;
5049
5050 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5051 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00005052 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005053 }
5054 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5055}
5056
5057/**
5058 * xmlXPathVariableLookupNS:
5059 * @ctxt: the XPath context
5060 * @name: the variable name
5061 * @ns_uri: the variable namespace URI
5062 *
5063 * Search in the Variable array of the context for the given
Daniel Veillard45490ae2008-07-29 09:13:19 +00005064 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00005065 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00005066 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00005067 */
5068xmlXPathObjectPtr
5069xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5070 const xmlChar *ns_uri) {
5071 if (ctxt == NULL)
5072 return(NULL);
5073
5074 if (ctxt->varLookupFunc != NULL) {
5075 xmlXPathObjectPtr ret;
5076
5077 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5078 (ctxt->varLookupData, name, ns_uri);
5079 if (ret != NULL) return(ret);
5080 }
5081
5082 if (ctxt->varHash == NULL)
5083 return(NULL);
5084 if (name == NULL)
5085 return(NULL);
5086
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005087 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
Daniel Veillard8c357d52001-07-03 23:43:33 +00005088 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00005089}
5090
5091/**
5092 * xmlXPathRegisteredVariablesCleanup:
5093 * @ctxt: the XPath context
5094 *
5095 * Cleanup the XPath context data associated to registered variables
5096 */
5097void
5098xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5099 if (ctxt == NULL)
5100 return;
5101
Nick Wellnhofere03f0a12017-11-09 16:42:47 +01005102 xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
Owen Taylor3473f882001-02-23 17:55:21 +00005103 ctxt->varHash = NULL;
5104}
5105
5106/**
5107 * xmlXPathRegisterNs:
5108 * @ctxt: the XPath context
Daniel Veillarddb3ce962009-03-25 09:43:49 +00005109 * @prefix: the namespace prefix cannot be NULL or empty string
Owen Taylor3473f882001-02-23 17:55:21 +00005110 * @ns_uri: the namespace name
5111 *
5112 * Register a new namespace. If @ns_uri is NULL it unregisters
5113 * the namespace
5114 *
5115 * Returns 0 in case of success, -1 in case of error
5116 */
5117int
5118xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5119 const xmlChar *ns_uri) {
5120 if (ctxt == NULL)
5121 return(-1);
5122 if (prefix == NULL)
5123 return(-1);
Daniel Veillarddb3ce962009-03-25 09:43:49 +00005124 if (prefix[0] == 0)
5125 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00005126
5127 if (ctxt->nsHash == NULL)
5128 ctxt->nsHash = xmlHashCreate(10);
5129 if (ctxt->nsHash == NULL)
5130 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00005131 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00005132 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Nick Wellnhofere03f0a12017-11-09 16:42:47 +01005133 xmlHashDefaultDeallocator));
Daniel Veillard42766c02002-08-22 20:52:17 +00005134 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Nick Wellnhofere03f0a12017-11-09 16:42:47 +01005135 xmlHashDefaultDeallocator));
Owen Taylor3473f882001-02-23 17:55:21 +00005136}
5137
5138/**
5139 * xmlXPathNsLookup:
5140 * @ctxt: the XPath context
5141 * @prefix: the namespace prefix value
5142 *
5143 * Search in the namespace declaration array of the context for the given
5144 * namespace name associated to the given prefix
5145 *
5146 * Returns the value or NULL if not found
5147 */
5148const xmlChar *
5149xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5150 if (ctxt == NULL)
5151 return(NULL);
5152 if (prefix == NULL)
5153 return(NULL);
5154
5155#ifdef XML_XML_NAMESPACE
5156 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5157 return(XML_XML_NAMESPACE);
5158#endif
5159
Daniel Veillardc8f620b2001-04-30 20:31:33 +00005160 if (ctxt->namespaces != NULL) {
5161 int i;
5162
5163 for (i = 0;i < ctxt->nsNr;i++) {
5164 if ((ctxt->namespaces[i] != NULL) &&
5165 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5166 return(ctxt->namespaces[i]->href);
5167 }
5168 }
Owen Taylor3473f882001-02-23 17:55:21 +00005169
5170 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5171}
5172
5173/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005174 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00005175 * @ctxt: the XPath context
5176 *
5177 * Cleanup the XPath context data associated to registered variables
5178 */
5179void
5180xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5181 if (ctxt == NULL)
5182 return;
5183
Nick Wellnhofere03f0a12017-11-09 16:42:47 +01005184 xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
Owen Taylor3473f882001-02-23 17:55:21 +00005185 ctxt->nsHash = NULL;
5186}
5187
5188/************************************************************************
5189 * *
5190 * Routines to handle Values *
5191 * *
5192 ************************************************************************/
5193
William M. Brack08171912003-12-29 02:52:11 +00005194/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005195
5196/**
5197 * xmlXPathNewFloat:
5198 * @val: the double value
5199 *
5200 * Create a new xmlXPathObjectPtr of type double and of value @val
5201 *
5202 * Returns the newly created object.
5203 */
5204xmlXPathObjectPtr
5205xmlXPathNewFloat(double val) {
5206 xmlXPathObjectPtr ret;
5207
5208 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5209 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005210 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005211 return(NULL);
5212 }
5213 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5214 ret->type = XPATH_NUMBER;
5215 ret->floatval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005216#ifdef XP_DEBUG_OBJ_USAGE
5217 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5218#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005219 return(ret);
5220}
5221
5222/**
5223 * xmlXPathNewBoolean:
5224 * @val: the boolean value
5225 *
5226 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5227 *
5228 * Returns the newly created object.
5229 */
5230xmlXPathObjectPtr
5231xmlXPathNewBoolean(int val) {
5232 xmlXPathObjectPtr ret;
5233
5234 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5235 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005236 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005237 return(NULL);
5238 }
5239 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5240 ret->type = XPATH_BOOLEAN;
5241 ret->boolval = (val != 0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005242#ifdef XP_DEBUG_OBJ_USAGE
5243 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5244#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005245 return(ret);
5246}
5247
5248/**
5249 * xmlXPathNewString:
5250 * @val: the xmlChar * value
5251 *
5252 * Create a new xmlXPathObjectPtr of type string and of value @val
5253 *
5254 * Returns the newly created object.
5255 */
5256xmlXPathObjectPtr
5257xmlXPathNewString(const xmlChar *val) {
5258 xmlXPathObjectPtr ret;
5259
5260 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5261 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005262 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005263 return(NULL);
5264 }
5265 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5266 ret->type = XPATH_STRING;
5267 if (val != NULL)
5268 ret->stringval = xmlStrdup(val);
5269 else
5270 ret->stringval = xmlStrdup((const xmlChar *)"");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005271#ifdef XP_DEBUG_OBJ_USAGE
5272 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5273#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005274 return(ret);
5275}
5276
5277/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005278 * xmlXPathWrapString:
5279 * @val: the xmlChar * value
5280 *
5281 * Wraps the @val string into an XPath object.
5282 *
5283 * Returns the newly created object.
5284 */
5285xmlXPathObjectPtr
5286xmlXPathWrapString (xmlChar *val) {
5287 xmlXPathObjectPtr ret;
5288
5289 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5290 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005291 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005292 return(NULL);
5293 }
5294 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5295 ret->type = XPATH_STRING;
5296 ret->stringval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005297#ifdef XP_DEBUG_OBJ_USAGE
5298 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5299#endif
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005300 return(ret);
5301}
5302
5303/**
Owen Taylor3473f882001-02-23 17:55:21 +00005304 * xmlXPathNewCString:
5305 * @val: the char * value
5306 *
5307 * Create a new xmlXPathObjectPtr of type string and of value @val
5308 *
5309 * Returns the newly created object.
5310 */
5311xmlXPathObjectPtr
5312xmlXPathNewCString(const char *val) {
5313 xmlXPathObjectPtr ret;
5314
5315 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5316 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005317 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005318 return(NULL);
5319 }
5320 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5321 ret->type = XPATH_STRING;
5322 ret->stringval = xmlStrdup(BAD_CAST val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005323#ifdef XP_DEBUG_OBJ_USAGE
5324 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5325#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005326 return(ret);
5327}
5328
5329/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005330 * xmlXPathWrapCString:
5331 * @val: the char * value
5332 *
5333 * Wraps a string into an XPath object.
5334 *
5335 * Returns the newly created object.
5336 */
5337xmlXPathObjectPtr
5338xmlXPathWrapCString (char * val) {
5339 return(xmlXPathWrapString((xmlChar *)(val)));
5340}
5341
5342/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005343 * xmlXPathWrapExternal:
5344 * @val: the user data
5345 *
5346 * Wraps the @val data into an XPath object.
5347 *
5348 * Returns the newly created object.
5349 */
5350xmlXPathObjectPtr
5351xmlXPathWrapExternal (void *val) {
5352 xmlXPathObjectPtr ret;
5353
5354 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5355 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005356 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005357 return(NULL);
5358 }
5359 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5360 ret->type = XPATH_USERS;
5361 ret->user = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005362#ifdef XP_DEBUG_OBJ_USAGE
5363 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5364#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005365 return(ret);
5366}
5367
5368/**
Owen Taylor3473f882001-02-23 17:55:21 +00005369 * xmlXPathObjectCopy:
5370 * @val: the original object
5371 *
5372 * allocate a new copy of a given object
5373 *
5374 * Returns the newly created object.
5375 */
5376xmlXPathObjectPtr
5377xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5378 xmlXPathObjectPtr ret;
5379
5380 if (val == NULL)
5381 return(NULL);
5382
5383 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5384 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005385 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005386 return(NULL);
5387 }
5388 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005389#ifdef XP_DEBUG_OBJ_USAGE
5390 xmlXPathDebugObjUsageRequested(NULL, val->type);
5391#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005392 switch (val->type) {
5393 case XPATH_BOOLEAN:
5394 case XPATH_NUMBER:
5395 case XPATH_POINT:
5396 case XPATH_RANGE:
5397 break;
5398 case XPATH_STRING:
5399 ret->stringval = xmlStrdup(val->stringval);
5400 break;
5401 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00005402#if 0
5403/*
5404 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5405 this previous handling is no longer correct, and can cause some serious
5406 problems (ref. bug 145547)
5407*/
Owen Taylor3473f882001-02-23 17:55:21 +00005408 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005409 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005410 xmlNodePtr cur, tmp;
5411 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005412
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005413 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005414 top = xmlNewDoc(NULL);
5415 top->name = (char *)
5416 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005417 ret->user = top;
5418 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005419 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005420 cur = val->nodesetval->nodeTab[0]->children;
5421 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005422 tmp = xmlDocCopyNode(cur, top, 1);
5423 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005424 cur = cur->next;
5425 }
5426 }
William M. Bracke9449c52004-07-11 14:41:20 +00005427
Daniel Veillard9adc0462003-03-24 18:39:54 +00005428 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005429 } else
Owen Taylor3473f882001-02-23 17:55:21 +00005430 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005431 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00005432 break;
William M. Bracke9449c52004-07-11 14:41:20 +00005433#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005434 case XPATH_NODESET:
Haibo Huangcfd91dc2020-07-30 23:01:33 -07005435 /* TODO: Check memory error. */
Owen Taylor3473f882001-02-23 17:55:21 +00005436 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005437 /* Do not deallocate the copied tree value */
5438 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005439 break;
5440 case XPATH_LOCATIONSET:
5441#ifdef LIBXML_XPTR_ENABLED
5442 {
5443 xmlLocationSetPtr loc = val->user;
5444 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5445 break;
5446 }
5447#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00005448 case XPATH_USERS:
5449 ret->user = val->user;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005450 break;
Thomas Broyer47334c02001-10-07 16:41:52 +00005451 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00005452 xmlGenericError(xmlGenericErrorContext,
5453 "xmlXPathObjectCopy: unsupported type %d\n",
5454 val->type);
5455 break;
5456 }
5457 return(ret);
5458}
5459
5460/**
5461 * xmlXPathFreeObject:
5462 * @obj: the object to free
5463 *
5464 * Free up an xmlXPathObjectPtr object.
5465 */
5466void
5467xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5468 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005469 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00005470 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00005471#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005472 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005473 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00005474 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00005475 } else
5476#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005477 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
William M. Bracke9449c52004-07-11 14:41:20 +00005478 if (obj->nodesetval != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00005479 xmlXPathFreeValueTree(obj->nodesetval);
Daniel Veillard77851712001-02-27 21:54:07 +00005480 } else {
5481 if (obj->nodesetval != NULL)
5482 xmlXPathFreeNodeSet(obj->nodesetval);
5483 }
Owen Taylor3473f882001-02-23 17:55:21 +00005484#ifdef LIBXML_XPTR_ENABLED
5485 } else if (obj->type == XPATH_LOCATIONSET) {
5486 if (obj->user != NULL)
5487 xmlXPtrFreeLocationSet(obj->user);
5488#endif
5489 } else if (obj->type == XPATH_STRING) {
5490 if (obj->stringval != NULL)
5491 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005492 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005493#ifdef XP_DEBUG_OBJ_USAGE
5494 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5495#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00005496 xmlFree(obj);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005497}
Owen Taylor3473f882001-02-23 17:55:21 +00005498
Nick Wellnhofere03f0a12017-11-09 16:42:47 +01005499static void
5500xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
5501 xmlXPathFreeObject((xmlXPathObjectPtr) obj);
5502}
5503
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005504/**
5505 * xmlXPathReleaseObject:
5506 * @obj: the xmlXPathObjectPtr to free or to cache
5507 *
5508 * Depending on the state of the cache this frees the given
5509 * XPath object or stores it in the cache.
5510 */
5511static void
5512xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5513{
5514#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5515 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5516 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5517
5518#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5519
5520 if (obj == NULL)
5521 return;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005522 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005523 xmlXPathFreeObject(obj);
Daniel Veillard45490ae2008-07-29 09:13:19 +00005524 } else {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005525 xmlXPathContextCachePtr cache =
5526 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005527
5528 switch (obj->type) {
5529 case XPATH_NODESET:
5530 case XPATH_XSLT_TREE:
5531 if (obj->nodesetval != NULL) {
5532 if (obj->boolval) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00005533 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005534 * It looks like the @boolval is used for
5535 * evaluation if this an XSLT Result Tree Fragment.
5536 * TODO: Check if this assumption is correct.
5537 */
5538 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5539 xmlXPathFreeValueTree(obj->nodesetval);
5540 obj->nodesetval = NULL;
5541 } else if ((obj->nodesetval->nodeMax <= 40) &&
5542 (XP_CACHE_WANTS(cache->nodesetObjs,
5543 cache->maxNodeset)))
5544 {
5545 XP_CACHE_ADD(cache->nodesetObjs, obj);
5546 goto obj_cached;
5547 } else {
5548 xmlXPathFreeNodeSet(obj->nodesetval);
5549 obj->nodesetval = NULL;
5550 }
5551 }
5552 break;
5553 case XPATH_STRING:
5554 if (obj->stringval != NULL)
5555 xmlFree(obj->stringval);
5556
5557 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5558 XP_CACHE_ADD(cache->stringObjs, obj);
5559 goto obj_cached;
5560 }
5561 break;
5562 case XPATH_BOOLEAN:
5563 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5564 XP_CACHE_ADD(cache->booleanObjs, obj);
5565 goto obj_cached;
5566 }
5567 break;
5568 case XPATH_NUMBER:
5569 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5570 XP_CACHE_ADD(cache->numberObjs, obj);
5571 goto obj_cached;
5572 }
5573 break;
5574#ifdef LIBXML_XPTR_ENABLED
5575 case XPATH_LOCATIONSET:
5576 if (obj->user != NULL) {
5577 xmlXPtrFreeLocationSet(obj->user);
5578 }
5579 goto free_obj;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005580#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005581 default:
5582 goto free_obj;
5583 }
5584
5585 /*
5586 * Fallback to adding to the misc-objects slot.
5587 */
5588 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5589 XP_CACHE_ADD(cache->miscObjs, obj);
5590 } else
5591 goto free_obj;
5592
5593obj_cached:
5594
5595#ifdef XP_DEBUG_OBJ_USAGE
5596 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5597#endif
5598
5599 if (obj->nodesetval != NULL) {
5600 xmlNodeSetPtr tmpset = obj->nodesetval;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005601
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005602 /*
5603 * TODO: Due to those nasty ns-nodes, we need to traverse
5604 * the list and free the ns-nodes.
5605 * URGENT TODO: Check if it's actually slowing things down.
5606 * Maybe we shouldn't try to preserve the list.
5607 */
5608 if (tmpset->nodeNr > 1) {
5609 int i;
5610 xmlNodePtr node;
5611
5612 for (i = 0; i < tmpset->nodeNr; i++) {
5613 node = tmpset->nodeTab[i];
5614 if ((node != NULL) &&
5615 (node->type == XML_NAMESPACE_DECL))
5616 {
5617 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5618 }
5619 }
5620 } else if (tmpset->nodeNr == 1) {
5621 if ((tmpset->nodeTab[0] != NULL) &&
5622 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5623 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
Daniel Veillard45490ae2008-07-29 09:13:19 +00005624 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005625 tmpset->nodeNr = 0;
5626 memset(obj, 0, sizeof(xmlXPathObject));
5627 obj->nodesetval = tmpset;
5628 } else
5629 memset(obj, 0, sizeof(xmlXPathObject));
5630
5631 return;
5632
5633free_obj:
5634 /*
5635 * Cache is full; free the object.
Daniel Veillard45490ae2008-07-29 09:13:19 +00005636 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005637 if (obj->nodesetval != NULL)
5638 xmlXPathFreeNodeSet(obj->nodesetval);
5639#ifdef XP_DEBUG_OBJ_USAGE
5640 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5641#endif
5642 xmlFree(obj);
5643 }
5644 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005645}
5646
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005647
5648/************************************************************************
5649 * *
5650 * Type Casting Routines *
5651 * *
5652 ************************************************************************/
5653
5654/**
5655 * xmlXPathCastBooleanToString:
5656 * @val: a boolean
5657 *
5658 * Converts a boolean to its string value.
5659 *
5660 * Returns a newly allocated string.
5661 */
5662xmlChar *
5663xmlXPathCastBooleanToString (int val) {
5664 xmlChar *ret;
5665 if (val)
5666 ret = xmlStrdup((const xmlChar *) "true");
5667 else
5668 ret = xmlStrdup((const xmlChar *) "false");
5669 return(ret);
5670}
5671
5672/**
5673 * xmlXPathCastNumberToString:
5674 * @val: a number
5675 *
5676 * Converts a number to its string value.
5677 *
5678 * Returns a newly allocated string.
5679 */
5680xmlChar *
5681xmlXPathCastNumberToString (double val) {
5682 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00005683 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005684 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005685 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005686 break;
5687 case -1:
5688 ret = xmlStrdup((const xmlChar *) "-Infinity");
5689 break;
5690 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00005691 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005692 ret = xmlStrdup((const xmlChar *) "NaN");
Nick Wellnhofer8813f392017-09-21 00:11:26 +02005693 } else if (val == 0) {
5694 /* Omit sign for negative zero. */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005695 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005696 } else {
5697 /* could be improved */
5698 char buf[100];
Daniel Veillard11ce4002006-03-10 00:36:23 +00005699 xmlXPathFormatNumber(val, buf, 99);
5700 buf[99] = 0;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005701 ret = xmlStrdup((const xmlChar *) buf);
5702 }
5703 }
5704 return(ret);
5705}
5706
5707/**
5708 * xmlXPathCastNodeToString:
5709 * @node: a node
5710 *
5711 * Converts a node to its string value.
5712 *
5713 * Returns a newly allocated string.
5714 */
5715xmlChar *
5716xmlXPathCastNodeToString (xmlNodePtr node) {
William M. Brackd611c882007-05-31 05:07:17 +00005717xmlChar *ret;
5718 if ((ret = xmlNodeGetContent(node)) == NULL)
5719 ret = xmlStrdup((const xmlChar *) "");
5720 return(ret);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005721}
5722
5723/**
5724 * xmlXPathCastNodeSetToString:
5725 * @ns: a node-set
5726 *
5727 * Converts a node-set to its string value.
5728 *
5729 * Returns a newly allocated string.
5730 */
5731xmlChar *
5732xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5733 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5734 return(xmlStrdup((const xmlChar *) ""));
5735
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00005736 if (ns->nodeNr > 1)
5737 xmlXPathNodeSetSort(ns);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005738 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5739}
5740
5741/**
5742 * xmlXPathCastToString:
5743 * @val: an XPath object
5744 *
5745 * Converts an existing object to its string() equivalent
5746 *
Kasimier T. Buchcik50128ad2006-08-15 13:04:07 +00005747 * Returns the allocated string value of the object, NULL in case of error.
Daniel Veillard45490ae2008-07-29 09:13:19 +00005748 * It's up to the caller to free the string memory with xmlFree().
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005749 */
5750xmlChar *
5751xmlXPathCastToString(xmlXPathObjectPtr val) {
5752 xmlChar *ret = NULL;
5753
5754 if (val == NULL)
5755 return(xmlStrdup((const xmlChar *) ""));
5756 switch (val->type) {
5757 case XPATH_UNDEFINED:
5758#ifdef DEBUG_EXPR
5759 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5760#endif
5761 ret = xmlStrdup((const xmlChar *) "");
5762 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005763 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005764 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005765 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5766 break;
5767 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00005768 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005769 case XPATH_BOOLEAN:
5770 ret = xmlXPathCastBooleanToString(val->boolval);
5771 break;
5772 case XPATH_NUMBER: {
5773 ret = xmlXPathCastNumberToString(val->floatval);
5774 break;
5775 }
5776 case XPATH_USERS:
5777 case XPATH_POINT:
5778 case XPATH_RANGE:
5779 case XPATH_LOCATIONSET:
5780 TODO
5781 ret = xmlStrdup((const xmlChar *) "");
5782 break;
5783 }
5784 return(ret);
5785}
5786
5787/**
5788 * xmlXPathConvertString:
5789 * @val: an XPath object
5790 *
5791 * Converts an existing object to its string() equivalent
5792 *
5793 * Returns the new object, the old one is freed (or the operation
5794 * is done directly on @val)
5795 */
5796xmlXPathObjectPtr
5797xmlXPathConvertString(xmlXPathObjectPtr val) {
5798 xmlChar *res = NULL;
5799
5800 if (val == NULL)
5801 return(xmlXPathNewCString(""));
5802
5803 switch (val->type) {
5804 case XPATH_UNDEFINED:
5805#ifdef DEBUG_EXPR
5806 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5807#endif
5808 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005809 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005810 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005811 res = xmlXPathCastNodeSetToString(val->nodesetval);
5812 break;
5813 case XPATH_STRING:
5814 return(val);
5815 case XPATH_BOOLEAN:
5816 res = xmlXPathCastBooleanToString(val->boolval);
5817 break;
5818 case XPATH_NUMBER:
5819 res = xmlXPathCastNumberToString(val->floatval);
5820 break;
5821 case XPATH_USERS:
5822 case XPATH_POINT:
5823 case XPATH_RANGE:
5824 case XPATH_LOCATIONSET:
5825 TODO;
5826 break;
5827 }
5828 xmlXPathFreeObject(val);
5829 if (res == NULL)
5830 return(xmlXPathNewCString(""));
5831 return(xmlXPathWrapString(res));
5832}
5833
5834/**
5835 * xmlXPathCastBooleanToNumber:
5836 * @val: a boolean
5837 *
5838 * Converts a boolean to its number value
5839 *
5840 * Returns the number value
5841 */
5842double
5843xmlXPathCastBooleanToNumber(int val) {
5844 if (val)
5845 return(1.0);
5846 return(0.0);
5847}
5848
5849/**
5850 * xmlXPathCastStringToNumber:
5851 * @val: a string
5852 *
5853 * Converts a string to its number value
5854 *
5855 * Returns the number value
5856 */
5857double
5858xmlXPathCastStringToNumber(const xmlChar * val) {
5859 return(xmlXPathStringEvalNumber(val));
5860}
5861
5862/**
5863 * xmlXPathCastNodeToNumber:
5864 * @node: a node
5865 *
5866 * Converts a node to its number value
5867 *
5868 * Returns the number value
5869 */
5870double
5871xmlXPathCastNodeToNumber (xmlNodePtr node) {
5872 xmlChar *strval;
5873 double ret;
5874
5875 if (node == NULL)
Nick Wellnhofer8813f392017-09-21 00:11:26 +02005876 return(NAN);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005877 strval = xmlXPathCastNodeToString(node);
5878 if (strval == NULL)
Nick Wellnhofer8813f392017-09-21 00:11:26 +02005879 return(NAN);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005880 ret = xmlXPathCastStringToNumber(strval);
5881 xmlFree(strval);
5882
5883 return(ret);
5884}
5885
5886/**
5887 * xmlXPathCastNodeSetToNumber:
5888 * @ns: a node-set
5889 *
5890 * Converts a node-set to its number value
5891 *
5892 * Returns the number value
5893 */
5894double
5895xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5896 xmlChar *str;
5897 double ret;
5898
5899 if (ns == NULL)
Nick Wellnhofer8813f392017-09-21 00:11:26 +02005900 return(NAN);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005901 str = xmlXPathCastNodeSetToString(ns);
5902 ret = xmlXPathCastStringToNumber(str);
5903 xmlFree(str);
5904 return(ret);
5905}
5906
5907/**
5908 * xmlXPathCastToNumber:
5909 * @val: an XPath object
5910 *
5911 * Converts an XPath object to its number value
5912 *
5913 * Returns the number value
5914 */
5915double
5916xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5917 double ret = 0.0;
5918
5919 if (val == NULL)
Nick Wellnhofer8813f392017-09-21 00:11:26 +02005920 return(NAN);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005921 switch (val->type) {
5922 case XPATH_UNDEFINED:
Haibo Huangcfd91dc2020-07-30 23:01:33 -07005923#ifdef DEBUG_EXPR
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005924 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5925#endif
Nick Wellnhofer8813f392017-09-21 00:11:26 +02005926 ret = NAN;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005927 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005928 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005929 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005930 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5931 break;
5932 case XPATH_STRING:
5933 ret = xmlXPathCastStringToNumber(val->stringval);
5934 break;
5935 case XPATH_NUMBER:
5936 ret = val->floatval;
5937 break;
5938 case XPATH_BOOLEAN:
5939 ret = xmlXPathCastBooleanToNumber(val->boolval);
5940 break;
5941 case XPATH_USERS:
5942 case XPATH_POINT:
5943 case XPATH_RANGE:
5944 case XPATH_LOCATIONSET:
5945 TODO;
Nick Wellnhofer8813f392017-09-21 00:11:26 +02005946 ret = NAN;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005947 break;
5948 }
5949 return(ret);
5950}
5951
5952/**
5953 * xmlXPathConvertNumber:
5954 * @val: an XPath object
5955 *
5956 * Converts an existing object to its number() equivalent
5957 *
5958 * Returns the new object, the old one is freed (or the operation
5959 * is done directly on @val)
5960 */
5961xmlXPathObjectPtr
5962xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5963 xmlXPathObjectPtr ret;
5964
5965 if (val == NULL)
5966 return(xmlXPathNewFloat(0.0));
5967 if (val->type == XPATH_NUMBER)
5968 return(val);
5969 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5970 xmlXPathFreeObject(val);
5971 return(ret);
5972}
5973
5974/**
5975 * xmlXPathCastNumberToBoolean:
5976 * @val: a number
5977 *
5978 * Converts a number to its boolean value
5979 *
5980 * Returns the boolean value
5981 */
5982int
5983xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00005984 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005985 return(0);
5986 return(1);
5987}
5988
5989/**
5990 * xmlXPathCastStringToBoolean:
5991 * @val: a string
5992 *
5993 * Converts a string to its boolean value
5994 *
5995 * Returns the boolean value
5996 */
5997int
5998xmlXPathCastStringToBoolean (const xmlChar *val) {
5999 if ((val == NULL) || (xmlStrlen(val) == 0))
6000 return(0);
6001 return(1);
6002}
6003
6004/**
6005 * xmlXPathCastNodeSetToBoolean:
6006 * @ns: a node-set
6007 *
6008 * Converts a node-set to its boolean value
6009 *
6010 * Returns the boolean value
6011 */
6012int
6013xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6014 if ((ns == NULL) || (ns->nodeNr == 0))
6015 return(0);
6016 return(1);
6017}
6018
6019/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006020 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006021 * @val: an XPath object
6022 *
6023 * Converts an XPath object to its boolean value
6024 *
6025 * Returns the boolean value
6026 */
6027int
6028xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6029 int ret = 0;
6030
6031 if (val == NULL)
6032 return(0);
6033 switch (val->type) {
6034 case XPATH_UNDEFINED:
6035#ifdef DEBUG_EXPR
6036 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6037#endif
6038 ret = 0;
6039 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006040 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00006041 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006042 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6043 break;
6044 case XPATH_STRING:
6045 ret = xmlXPathCastStringToBoolean(val->stringval);
6046 break;
6047 case XPATH_NUMBER:
6048 ret = xmlXPathCastNumberToBoolean(val->floatval);
6049 break;
6050 case XPATH_BOOLEAN:
6051 ret = val->boolval;
6052 break;
6053 case XPATH_USERS:
6054 case XPATH_POINT:
6055 case XPATH_RANGE:
6056 case XPATH_LOCATIONSET:
6057 TODO;
6058 ret = 0;
6059 break;
6060 }
6061 return(ret);
6062}
6063
6064
6065/**
6066 * xmlXPathConvertBoolean:
6067 * @val: an XPath object
6068 *
6069 * Converts an existing object to its boolean() equivalent
6070 *
6071 * Returns the new object, the old one is freed (or the operation
6072 * is done directly on @val)
6073 */
6074xmlXPathObjectPtr
6075xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6076 xmlXPathObjectPtr ret;
6077
6078 if (val == NULL)
6079 return(xmlXPathNewBoolean(0));
6080 if (val->type == XPATH_BOOLEAN)
6081 return(val);
6082 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6083 xmlXPathFreeObject(val);
6084 return(ret);
6085}
6086
Owen Taylor3473f882001-02-23 17:55:21 +00006087/************************************************************************
6088 * *
6089 * Routines to handle XPath contexts *
6090 * *
6091 ************************************************************************/
6092
6093/**
6094 * xmlXPathNewContext:
6095 * @doc: the XML document
6096 *
6097 * Create a new xmlXPathContext
6098 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00006099 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00006100 */
6101xmlXPathContextPtr
6102xmlXPathNewContext(xmlDocPtr doc) {
6103 xmlXPathContextPtr ret;
6104
6105 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6106 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006107 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006108 return(NULL);
6109 }
6110 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6111 ret->doc = doc;
6112 ret->node = NULL;
6113
6114 ret->varHash = NULL;
6115
6116 ret->nb_types = 0;
6117 ret->max_types = 0;
6118 ret->types = NULL;
6119
6120 ret->funcHash = xmlHashCreate(0);
6121
6122 ret->nb_axis = 0;
6123 ret->max_axis = 0;
6124 ret->axis = NULL;
6125
6126 ret->nsHash = NULL;
6127 ret->user = NULL;
6128
6129 ret->contextSize = -1;
6130 ret->proximityPosition = -1;
6131
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006132#ifdef XP_DEFAULT_CACHE_ON
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006133 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006134 xmlXPathFreeContext(ret);
6135 return(NULL);
6136 }
6137#endif
6138
Daniel Veillard45490ae2008-07-29 09:13:19 +00006139 xmlXPathRegisterAllFunctions(ret);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006140
Owen Taylor3473f882001-02-23 17:55:21 +00006141 return(ret);
6142}
6143
6144/**
6145 * xmlXPathFreeContext:
6146 * @ctxt: the context to free
6147 *
6148 * Free up an xmlXPathContext
6149 */
6150void
6151xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006152 if (ctxt == NULL) return;
6153
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006154 if (ctxt->cache != NULL)
6155 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
Owen Taylor3473f882001-02-23 17:55:21 +00006156 xmlXPathRegisteredNsCleanup(ctxt);
6157 xmlXPathRegisteredFuncsCleanup(ctxt);
6158 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006159 xmlResetError(&ctxt->lastError);
Owen Taylor3473f882001-02-23 17:55:21 +00006160 xmlFree(ctxt);
6161}
6162
6163/************************************************************************
6164 * *
6165 * Routines to handle XPath parser contexts *
6166 * *
6167 ************************************************************************/
6168
6169#define CHECK_CTXT(ctxt) \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006170 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00006171 __xmlRaiseError(NULL, NULL, NULL, \
6172 NULL, NULL, XML_FROM_XPATH, \
6173 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6174 __FILE__, __LINE__, \
6175 NULL, NULL, NULL, 0, 0, \
6176 "NULL context pointer\n"); \
6177 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00006178 } \
6179
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006180#define CHECK_CTXT_NEG(ctxt) \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006181 if (ctxt == NULL) { \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006182 __xmlRaiseError(NULL, NULL, NULL, \
6183 NULL, NULL, XML_FROM_XPATH, \
6184 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6185 __FILE__, __LINE__, \
6186 NULL, NULL, NULL, 0, 0, \
6187 "NULL context pointer\n"); \
6188 return(-1); \
6189 } \
6190
Owen Taylor3473f882001-02-23 17:55:21 +00006191
6192#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00006193 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006194 (ctxt->doc->children == NULL)) { \
Daniel Veillard57b25162004-11-06 14:50:18 +00006195 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00006196 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00006197 }
Owen Taylor3473f882001-02-23 17:55:21 +00006198
6199
6200/**
6201 * xmlXPathNewParserContext:
6202 * @str: the XPath expression
6203 * @ctxt: the XPath context
6204 *
6205 * Create a new xmlXPathParserContext
6206 *
6207 * Returns the xmlXPathParserContext just allocated.
6208 */
6209xmlXPathParserContextPtr
6210xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6211 xmlXPathParserContextPtr ret;
6212
6213 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6214 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006215 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006216 return(NULL);
6217 }
6218 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6219 ret->cur = ret->base = str;
6220 ret->context = ctxt;
6221
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006222 ret->comp = xmlXPathNewCompExpr();
6223 if (ret->comp == NULL) {
6224 xmlFree(ret->valueTab);
6225 xmlFree(ret);
6226 return(NULL);
6227 }
Daniel Veillard4773df22004-01-23 13:15:13 +00006228 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6229 ret->comp->dict = ctxt->dict;
6230 xmlDictReference(ret->comp->dict);
6231 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006232
6233 return(ret);
6234}
6235
6236/**
6237 * xmlXPathCompParserContext:
6238 * @comp: the XPath compiled expression
6239 * @ctxt: the XPath context
6240 *
6241 * Create a new xmlXPathParserContext when processing a compiled expression
6242 *
6243 * Returns the xmlXPathParserContext just allocated.
6244 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006245static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006246xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6247 xmlXPathParserContextPtr ret;
6248
6249 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6250 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006251 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006252 return(NULL);
6253 }
6254 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6255
Owen Taylor3473f882001-02-23 17:55:21 +00006256 /* Allocate the value stack */
Daniel Veillard45490ae2008-07-29 09:13:19 +00006257 ret->valueTab = (xmlXPathObjectPtr *)
Owen Taylor3473f882001-02-23 17:55:21 +00006258 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006259 if (ret->valueTab == NULL) {
6260 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006261 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006262 return(NULL);
6263 }
Owen Taylor3473f882001-02-23 17:55:21 +00006264 ret->valueNr = 0;
6265 ret->valueMax = 10;
6266 ret->value = NULL;
Daniel Veillardf5048b32011-08-18 17:10:13 +08006267 ret->valueFrame = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006268
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006269 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006270 ret->comp = comp;
6271
Owen Taylor3473f882001-02-23 17:55:21 +00006272 return(ret);
6273}
6274
6275/**
6276 * xmlXPathFreeParserContext:
6277 * @ctxt: the context to free
6278 *
6279 * Free up an xmlXPathParserContext
6280 */
6281void
6282xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
Nick Wellnhoferc8519702017-05-27 15:26:11 +02006283 int i;
6284
Owen Taylor3473f882001-02-23 17:55:21 +00006285 if (ctxt->valueTab != NULL) {
Nick Wellnhoferc8519702017-05-27 15:26:11 +02006286 for (i = 0; i < ctxt->valueNr; i++) {
6287 if (ctxt->context)
6288 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6289 else
6290 xmlXPathFreeObject(ctxt->valueTab[i]);
6291 }
Owen Taylor3473f882001-02-23 17:55:21 +00006292 xmlFree(ctxt->valueTab);
6293 }
Daniel Veillard56de87e2005-02-16 00:22:29 +00006294 if (ctxt->comp != NULL) {
6295#ifdef XPATH_STREAMING
6296 if (ctxt->comp->stream != NULL) {
6297 xmlFreePatternList(ctxt->comp->stream);
6298 ctxt->comp->stream = NULL;
6299 }
6300#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006301 xmlXPathFreeCompExpr(ctxt->comp);
Daniel Veillard56de87e2005-02-16 00:22:29 +00006302 }
Owen Taylor3473f882001-02-23 17:55:21 +00006303 xmlFree(ctxt);
6304}
6305
6306/************************************************************************
6307 * *
6308 * The implicit core function library *
6309 * *
6310 ************************************************************************/
6311
Owen Taylor3473f882001-02-23 17:55:21 +00006312/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006313 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00006314 * @node: a node pointer
6315 *
6316 * Function computing the beginning of the string value of the node,
6317 * used to speed up comparisons
6318 *
6319 * Returns an int usable as a hash
6320 */
6321static unsigned int
6322xmlXPathNodeValHash(xmlNodePtr node) {
6323 int len = 2;
6324 const xmlChar * string = NULL;
6325 xmlNodePtr tmp = NULL;
6326 unsigned int ret = 0;
6327
6328 if (node == NULL)
6329 return(0);
6330
Daniel Veillard9adc0462003-03-24 18:39:54 +00006331 if (node->type == XML_DOCUMENT_NODE) {
6332 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6333 if (tmp == NULL)
6334 node = node->children;
6335 else
6336 node = tmp;
6337
6338 if (node == NULL)
6339 return(0);
6340 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006341
6342 switch (node->type) {
6343 case XML_COMMENT_NODE:
6344 case XML_PI_NODE:
6345 case XML_CDATA_SECTION_NODE:
6346 case XML_TEXT_NODE:
6347 string = node->content;
6348 if (string == NULL)
6349 return(0);
6350 if (string[0] == 0)
6351 return(0);
6352 return(((unsigned int) string[0]) +
6353 (((unsigned int) string[1]) << 8));
6354 case XML_NAMESPACE_DECL:
6355 string = ((xmlNsPtr)node)->href;
6356 if (string == NULL)
6357 return(0);
6358 if (string[0] == 0)
6359 return(0);
6360 return(((unsigned int) string[0]) +
6361 (((unsigned int) string[1]) << 8));
6362 case XML_ATTRIBUTE_NODE:
6363 tmp = ((xmlAttrPtr) node)->children;
6364 break;
6365 case XML_ELEMENT_NODE:
6366 tmp = node->children;
6367 break;
6368 default:
6369 return(0);
6370 }
6371 while (tmp != NULL) {
6372 switch (tmp->type) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006373 case XML_CDATA_SECTION_NODE:
6374 case XML_TEXT_NODE:
6375 string = tmp->content;
6376 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006377 default:
Nick Wellnhofer5af594d2017-10-07 14:54:45 +02006378 string = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006379 break;
6380 }
6381 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006382 if (len == 1) {
6383 return(ret + (((unsigned int) string[0]) << 8));
6384 }
6385 if (string[1] == 0) {
6386 len = 1;
6387 ret = (unsigned int) string[0];
6388 } else {
6389 return(((unsigned int) string[0]) +
6390 (((unsigned int) string[1]) << 8));
6391 }
6392 }
6393 /*
6394 * Skip to next node
6395 */
6396 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6397 if (tmp->children->type != XML_ENTITY_DECL) {
6398 tmp = tmp->children;
6399 continue;
6400 }
6401 }
6402 if (tmp == node)
6403 break;
6404
6405 if (tmp->next != NULL) {
6406 tmp = tmp->next;
6407 continue;
6408 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00006409
Daniel Veillardf06307e2001-07-03 10:35:50 +00006410 do {
6411 tmp = tmp->parent;
6412 if (tmp == NULL)
6413 break;
6414 if (tmp == node) {
6415 tmp = NULL;
6416 break;
6417 }
6418 if (tmp->next != NULL) {
6419 tmp = tmp->next;
6420 break;
6421 }
6422 } while (tmp != NULL);
6423 }
6424 return(ret);
6425}
6426
6427/**
6428 * xmlXPathStringHash:
6429 * @string: a string
6430 *
6431 * Function computing the beginning of the string value of the node,
6432 * used to speed up comparisons
6433 *
6434 * Returns an int usable as a hash
6435 */
6436static unsigned int
6437xmlXPathStringHash(const xmlChar * string) {
6438 if (string == NULL)
6439 return((unsigned int) 0);
6440 if (string[0] == 0)
6441 return(0);
6442 return(((unsigned int) string[0]) +
6443 (((unsigned int) string[1]) << 8));
6444}
6445
6446/**
Owen Taylor3473f882001-02-23 17:55:21 +00006447 * xmlXPathCompareNodeSetFloat:
6448 * @ctxt: the XPath Parser context
6449 * @inf: less than (1) or greater than (0)
6450 * @strict: is the comparison strict
6451 * @arg: the node set
6452 * @f: the value
6453 *
6454 * Implement the compare operation between a nodeset and a number
6455 * @ns < @val (1, 1, ...
6456 * @ns <= @val (1, 0, ...
6457 * @ns > @val (0, 1, ...
6458 * @ns >= @val (0, 0, ...
6459 *
6460 * If one object to be compared is a node-set and the other is a number,
6461 * then the comparison will be true if and only if there is a node in the
6462 * node-set such that the result of performing the comparison on the number
6463 * to be compared and on the result of converting the string-value of that
6464 * node to a number using the number function is true.
6465 *
6466 * Returns 0 or 1 depending on the results of the test.
6467 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006468static int
Owen Taylor3473f882001-02-23 17:55:21 +00006469xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6470 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6471 int i, ret = 0;
6472 xmlNodeSetPtr ns;
6473 xmlChar *str2;
6474
6475 if ((f == NULL) || (arg == NULL) ||
6476 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006477 xmlXPathReleaseObject(ctxt->context, arg);
6478 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006479 return(0);
6480 }
6481 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006482 if (ns != NULL) {
6483 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006484 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006485 if (str2 != NULL) {
6486 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006487 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006488 xmlFree(str2);
6489 xmlXPathNumberFunction(ctxt, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006490 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006491 ret = xmlXPathCompareValues(ctxt, inf, strict);
6492 if (ret)
6493 break;
6494 }
6495 }
Owen Taylor3473f882001-02-23 17:55:21 +00006496 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006497 xmlXPathReleaseObject(ctxt->context, arg);
6498 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006499 return(ret);
6500}
6501
6502/**
6503 * xmlXPathCompareNodeSetString:
6504 * @ctxt: the XPath Parser context
6505 * @inf: less than (1) or greater than (0)
6506 * @strict: is the comparison strict
6507 * @arg: the node set
6508 * @s: the value
6509 *
6510 * Implement the compare operation between a nodeset and a string
6511 * @ns < @val (1, 1, ...
6512 * @ns <= @val (1, 0, ...
6513 * @ns > @val (0, 1, ...
6514 * @ns >= @val (0, 0, ...
6515 *
6516 * If one object to be compared is a node-set and the other is a string,
6517 * then the comparison will be true if and only if there is a node in
6518 * the node-set such that the result of performing the comparison on the
6519 * string-value of the node and the other string is true.
6520 *
6521 * Returns 0 or 1 depending on the results of the test.
6522 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006523static int
Owen Taylor3473f882001-02-23 17:55:21 +00006524xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6525 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6526 int i, ret = 0;
6527 xmlNodeSetPtr ns;
6528 xmlChar *str2;
6529
6530 if ((s == NULL) || (arg == NULL) ||
6531 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006532 xmlXPathReleaseObject(ctxt->context, arg);
6533 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006534 return(0);
6535 }
6536 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006537 if (ns != NULL) {
6538 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006539 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006540 if (str2 != NULL) {
6541 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006542 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006543 xmlFree(str2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006544 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006545 ret = xmlXPathCompareValues(ctxt, inf, strict);
6546 if (ret)
6547 break;
6548 }
6549 }
Owen Taylor3473f882001-02-23 17:55:21 +00006550 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006551 xmlXPathReleaseObject(ctxt->context, arg);
6552 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006553 return(ret);
6554}
6555
6556/**
6557 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006558 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00006559 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006560 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00006561 * @arg2: the second node set object
6562 *
6563 * Implement the compare operation on nodesets:
6564 *
6565 * If both objects to be compared are node-sets, then the comparison
6566 * will be true if and only if there is a node in the first node-set
6567 * and a node in the second node-set such that the result of performing
Daniel Veillard45490ae2008-07-29 09:13:19 +00006568 * the comparison on the string-values of the two nodes is true.
Owen Taylor3473f882001-02-23 17:55:21 +00006569 * ....
6570 * When neither object to be compared is a node-set and the operator
6571 * is <=, <, >= or >, then the objects are compared by converting both
6572 * objects to numbers and comparing the numbers according to IEEE 754.
6573 * ....
6574 * The number function converts its argument to a number as follows:
6575 * - a string that consists of optional whitespace followed by an
6576 * optional minus sign followed by a Number followed by whitespace
6577 * is converted to the IEEE 754 number that is nearest (according
6578 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6579 * represented by the string; any other string is converted to NaN
6580 *
6581 * Conclusion all nodes need to be converted first to their string value
Daniel Veillard45490ae2008-07-29 09:13:19 +00006582 * and then the comparison must be done when possible
Owen Taylor3473f882001-02-23 17:55:21 +00006583 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006584static int
6585xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00006586 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6587 int i, j, init = 0;
6588 double val1;
6589 double *values2;
6590 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006591 xmlNodeSetPtr ns1;
6592 xmlNodeSetPtr ns2;
6593
6594 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006595 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6596 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006597 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006598 }
Owen Taylor3473f882001-02-23 17:55:21 +00006599 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006600 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6601 xmlXPathFreeObject(arg1);
6602 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006603 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006604 }
Owen Taylor3473f882001-02-23 17:55:21 +00006605
6606 ns1 = arg1->nodesetval;
6607 ns2 = arg2->nodesetval;
6608
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006609 if ((ns1 == NULL) || (ns1->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 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006614 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006615 xmlXPathFreeObject(arg1);
6616 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006617 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006618 }
Owen Taylor3473f882001-02-23 17:55:21 +00006619
6620 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6621 if (values2 == NULL) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07006622 /* TODO: Propagate memory error. */
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006623 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00006624 xmlXPathFreeObject(arg1);
6625 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006626 return(0);
6627 }
6628 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006629 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00006630 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00006631 continue;
6632 for (j = 0;j < ns2->nodeNr;j++) {
6633 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006634 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00006635 }
Daniel Veillardcda96922001-08-21 10:56:31 +00006636 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00006637 continue;
Daniel Veillard45490ae2008-07-29 09:13:19 +00006638 if (inf && strict)
Owen Taylor3473f882001-02-23 17:55:21 +00006639 ret = (val1 < values2[j]);
6640 else if (inf && !strict)
6641 ret = (val1 <= values2[j]);
6642 else if (!inf && strict)
6643 ret = (val1 > values2[j]);
6644 else if (!inf && !strict)
6645 ret = (val1 >= values2[j]);
6646 if (ret)
6647 break;
6648 }
6649 if (ret)
6650 break;
6651 init = 1;
6652 }
6653 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006654 xmlXPathFreeObject(arg1);
6655 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006656 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006657}
6658
6659/**
6660 * xmlXPathCompareNodeSetValue:
6661 * @ctxt: the XPath Parser context
6662 * @inf: less than (1) or greater than (0)
6663 * @strict: is the comparison strict
6664 * @arg: the node set
6665 * @val: the value
6666 *
6667 * Implement the compare operation between a nodeset and a value
6668 * @ns < @val (1, 1, ...
6669 * @ns <= @val (1, 0, ...
6670 * @ns > @val (0, 1, ...
6671 * @ns >= @val (0, 0, ...
6672 *
6673 * If one object to be compared is a node-set and the other is a boolean,
6674 * then the comparison will be true if and only if the result of performing
6675 * the comparison on the boolean and on the result of converting
6676 * the node-set to a boolean using the boolean function is true.
6677 *
6678 * Returns 0 or 1 depending on the results of the test.
6679 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006680static int
Owen Taylor3473f882001-02-23 17:55:21 +00006681xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6682 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6683 if ((val == NULL) || (arg == NULL) ||
6684 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6685 return(0);
6686
6687 switch(val->type) {
6688 case XPATH_NUMBER:
6689 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6690 case XPATH_NODESET:
6691 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006692 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00006693 case XPATH_STRING:
6694 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6695 case XPATH_BOOLEAN:
6696 valuePush(ctxt, arg);
6697 xmlXPathBooleanFunction(ctxt, 1);
6698 valuePush(ctxt, val);
6699 return(xmlXPathCompareValues(ctxt, inf, strict));
6700 default:
Nick Wellnhofercf60dbe2017-05-25 16:20:56 +02006701 xmlGenericError(xmlGenericErrorContext,
6702 "xmlXPathCompareNodeSetValue: Can't compare node set "
6703 "and object of type %d\n",
6704 val->type);
6705 xmlXPathReleaseObject(ctxt->context, arg);
6706 xmlXPathReleaseObject(ctxt->context, val);
6707 XP_ERROR0(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006708 }
6709 return(0);
6710}
6711
6712/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006713 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00006714 * @arg: the nodeset object argument
6715 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00006716 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006717 *
6718 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6719 * If one object to be compared is a node-set and the other is a string,
6720 * then the comparison will be true if and only if there is a node in
6721 * the node-set such that the result of performing the comparison on the
6722 * string-value of the node and the other string is true.
6723 *
6724 * Returns 0 or 1 depending on the results of the test.
6725 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006726static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006727xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006728{
Owen Taylor3473f882001-02-23 17:55:21 +00006729 int i;
6730 xmlNodeSetPtr ns;
6731 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006732 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00006733
6734 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00006735 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6736 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006737 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00006738 /*
6739 * A NULL nodeset compared with a string is always false
6740 * (since there is no node equal, and no node not equal)
6741 */
6742 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00006743 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00006744 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006745 for (i = 0; i < ns->nodeNr; i++) {
6746 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6747 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6748 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6749 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006750 if (neq)
6751 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006752 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00006753 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6754 if (neq)
6755 continue;
6756 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006757 } else if (neq) {
6758 if (str2 != NULL)
6759 xmlFree(str2);
6760 return (1);
6761 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006762 if (str2 != NULL)
6763 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006764 } else if (neq)
6765 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00006766 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006767 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006768}
6769
6770/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006771 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00006772 * @arg: the nodeset object argument
6773 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00006774 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006775 *
6776 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6777 * If one object to be compared is a node-set and the other is a number,
6778 * then the comparison will be true if and only if there is a node in
6779 * the node-set such that the result of performing the comparison on the
6780 * number to be compared and on the result of converting the string-value
6781 * of that node to a number using the number function is true.
6782 *
6783 * Returns 0 or 1 depending on the results of the test.
6784 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006785static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006786xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6787 xmlXPathObjectPtr arg, double f, int neq) {
6788 int i, ret=0;
6789 xmlNodeSetPtr ns;
6790 xmlChar *str2;
6791 xmlXPathObjectPtr val;
6792 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00006793
6794 if ((arg == NULL) ||
6795 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6796 return(0);
6797
William M. Brack0c022ad2002-07-12 00:56:01 +00006798 ns = arg->nodesetval;
6799 if (ns != NULL) {
6800 for (i=0;i<ns->nodeNr;i++) {
6801 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6802 if (str2 != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006803 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
William M. Brack0c022ad2002-07-12 00:56:01 +00006804 xmlFree(str2);
6805 xmlXPathNumberFunction(ctxt, 1);
6806 val = valuePop(ctxt);
6807 v = val->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006808 xmlXPathReleaseObject(ctxt->context, val);
William M. Brack0c022ad2002-07-12 00:56:01 +00006809 if (!xmlXPathIsNaN(v)) {
6810 if ((!neq) && (v==f)) {
6811 ret = 1;
6812 break;
6813 } else if ((neq) && (v!=f)) {
6814 ret = 1;
6815 break;
6816 }
William M. Brack32f0f712005-07-14 07:00:33 +00006817 } else { /* NaN is unequal to any value */
6818 if (neq)
6819 ret = 1;
William M. Brack0c022ad2002-07-12 00:56:01 +00006820 }
6821 }
6822 }
6823 }
6824
6825 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006826}
6827
6828
6829/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006830 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00006831 * @arg1: first nodeset object argument
6832 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00006833 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006834 *
William M. Brack0c022ad2002-07-12 00:56:01 +00006835 * Implement the equal / not equal operation on XPath nodesets:
6836 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00006837 * If both objects to be compared are node-sets, then the comparison
6838 * will be true if and only if there is a node in the first node-set and
6839 * a node in the second node-set such that the result of performing the
6840 * comparison on the string-values of the two nodes is true.
6841 *
6842 * (needless to say, this is a costly operation)
6843 *
6844 * Returns 0 or 1 depending on the results of the test.
6845 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006846static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006847xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00006848 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006849 unsigned int *hashs1;
6850 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00006851 xmlChar **values1;
6852 xmlChar **values2;
6853 int ret = 0;
6854 xmlNodeSetPtr ns1;
6855 xmlNodeSetPtr ns2;
6856
6857 if ((arg1 == NULL) ||
6858 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6859 return(0);
6860 if ((arg2 == NULL) ||
6861 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6862 return(0);
6863
6864 ns1 = arg1->nodesetval;
6865 ns2 = arg2->nodesetval;
6866
Daniel Veillard911f49a2001-04-07 15:39:35 +00006867 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006868 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006869 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006870 return(0);
6871
6872 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00006873 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00006874 */
William M. Brack0c022ad2002-07-12 00:56:01 +00006875 if (neq == 0)
6876 for (i = 0;i < ns1->nodeNr;i++)
6877 for (j = 0;j < ns2->nodeNr;j++)
6878 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6879 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006880
6881 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006882 if (values1 == NULL) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07006883 /* TODO: Propagate memory error. */
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006884 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006885 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006886 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006887 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6888 if (hashs1 == NULL) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07006889 /* TODO: Propagate memory error. */
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006890 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006891 xmlFree(values1);
6892 return(0);
6893 }
Owen Taylor3473f882001-02-23 17:55:21 +00006894 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6895 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6896 if (values2 == NULL) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07006897 /* TODO: Propagate memory error. */
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006898 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006899 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00006900 xmlFree(values1);
6901 return(0);
6902 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006903 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6904 if (hashs2 == NULL) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07006905 /* TODO: Propagate memory error. */
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006906 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006907 xmlFree(hashs1);
6908 xmlFree(values1);
6909 xmlFree(values2);
6910 return(0);
6911 }
Owen Taylor3473f882001-02-23 17:55:21 +00006912 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6913 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006914 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006915 for (j = 0;j < ns2->nodeNr;j++) {
6916 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006917 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006918 if (hashs1[i] != hashs2[j]) {
6919 if (neq) {
6920 ret = 1;
6921 break;
6922 }
6923 }
6924 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006925 if (values1[i] == NULL)
6926 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6927 if (values2[j] == NULL)
6928 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006929 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006930 if (ret)
6931 break;
6932 }
Owen Taylor3473f882001-02-23 17:55:21 +00006933 }
6934 if (ret)
6935 break;
6936 }
6937 for (i = 0;i < ns1->nodeNr;i++)
6938 if (values1[i] != NULL)
6939 xmlFree(values1[i]);
6940 for (j = 0;j < ns2->nodeNr;j++)
6941 if (values2[j] != NULL)
6942 xmlFree(values2[j]);
6943 xmlFree(values1);
6944 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006945 xmlFree(hashs1);
6946 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00006947 return(ret);
6948}
6949
William M. Brack0c022ad2002-07-12 00:56:01 +00006950static int
6951xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6952 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00006953 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00006954 /*
6955 *At this point we are assured neither arg1 nor arg2
6956 *is a nodeset, so we can just pick the appropriate routine.
6957 */
Owen Taylor3473f882001-02-23 17:55:21 +00006958 switch (arg1->type) {
6959 case XPATH_UNDEFINED:
6960#ifdef DEBUG_EXPR
6961 xmlGenericError(xmlGenericErrorContext,
6962 "Equal: undefined\n");
6963#endif
6964 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006965 case XPATH_BOOLEAN:
6966 switch (arg2->type) {
6967 case XPATH_UNDEFINED:
6968#ifdef DEBUG_EXPR
6969 xmlGenericError(xmlGenericErrorContext,
6970 "Equal: undefined\n");
6971#endif
6972 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006973 case XPATH_BOOLEAN:
6974#ifdef DEBUG_EXPR
6975 xmlGenericError(xmlGenericErrorContext,
6976 "Equal: %d boolean %d \n",
6977 arg1->boolval, arg2->boolval);
6978#endif
6979 ret = (arg1->boolval == arg2->boolval);
6980 break;
6981 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00006982 ret = (arg1->boolval ==
6983 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006984 break;
6985 case XPATH_STRING:
6986 if ((arg2->stringval == NULL) ||
6987 (arg2->stringval[0] == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00006988 else
Owen Taylor3473f882001-02-23 17:55:21 +00006989 ret = 1;
6990 ret = (arg1->boolval == ret);
6991 break;
6992 case XPATH_USERS:
6993 case XPATH_POINT:
6994 case XPATH_RANGE:
6995 case XPATH_LOCATIONSET:
6996 TODO
6997 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006998 case XPATH_NODESET:
6999 case XPATH_XSLT_TREE:
7000 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007001 }
7002 break;
7003 case XPATH_NUMBER:
7004 switch (arg2->type) {
7005 case XPATH_UNDEFINED:
7006#ifdef DEBUG_EXPR
7007 xmlGenericError(xmlGenericErrorContext,
7008 "Equal: undefined\n");
7009#endif
7010 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007011 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00007012 ret = (arg2->boolval==
7013 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00007014 break;
7015 case XPATH_STRING:
7016 valuePush(ctxt, arg2);
7017 xmlXPathNumberFunction(ctxt, 1);
7018 arg2 = valuePop(ctxt);
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +02007019 /* Falls through. */
Owen Taylor3473f882001-02-23 17:55:21 +00007020 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007021 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00007022 if (xmlXPathIsNaN(arg1->floatval) ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00007023 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00007024 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007025 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7026 if (xmlXPathIsInf(arg2->floatval) == 1)
7027 ret = 1;
7028 else
7029 ret = 0;
7030 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7031 if (xmlXPathIsInf(arg2->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;
7040 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7041 if (xmlXPathIsInf(arg1->floatval) == -1)
7042 ret = 1;
7043 else
7044 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007045 } else {
7046 ret = (arg1->floatval == arg2->floatval);
7047 }
Owen Taylor3473f882001-02-23 17:55:21 +00007048 break;
7049 case XPATH_USERS:
7050 case XPATH_POINT:
7051 case XPATH_RANGE:
7052 case XPATH_LOCATIONSET:
7053 TODO
7054 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007055 case XPATH_NODESET:
7056 case XPATH_XSLT_TREE:
7057 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007058 }
7059 break;
7060 case XPATH_STRING:
7061 switch (arg2->type) {
7062 case XPATH_UNDEFINED:
7063#ifdef DEBUG_EXPR
7064 xmlGenericError(xmlGenericErrorContext,
7065 "Equal: undefined\n");
7066#endif
7067 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007068 case XPATH_BOOLEAN:
7069 if ((arg1->stringval == NULL) ||
7070 (arg1->stringval[0] == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007071 else
Owen Taylor3473f882001-02-23 17:55:21 +00007072 ret = 1;
7073 ret = (arg2->boolval == ret);
7074 break;
7075 case XPATH_STRING:
7076 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7077 break;
7078 case XPATH_NUMBER:
7079 valuePush(ctxt, arg1);
7080 xmlXPathNumberFunction(ctxt, 1);
7081 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007082 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00007083 if (xmlXPathIsNaN(arg1->floatval) ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00007084 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00007085 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007086 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7087 if (xmlXPathIsInf(arg2->floatval) == 1)
7088 ret = 1;
7089 else
7090 ret = 0;
7091 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7092 if (xmlXPathIsInf(arg2->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;
7101 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7102 if (xmlXPathIsInf(arg1->floatval) == -1)
7103 ret = 1;
7104 else
7105 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007106 } else {
7107 ret = (arg1->floatval == arg2->floatval);
7108 }
Owen Taylor3473f882001-02-23 17:55:21 +00007109 break;
7110 case XPATH_USERS:
7111 case XPATH_POINT:
7112 case XPATH_RANGE:
7113 case XPATH_LOCATIONSET:
7114 TODO
7115 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007116 case XPATH_NODESET:
7117 case XPATH_XSLT_TREE:
7118 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007119 }
7120 break;
7121 case XPATH_USERS:
7122 case XPATH_POINT:
7123 case XPATH_RANGE:
7124 case XPATH_LOCATIONSET:
7125 TODO
7126 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007127 case XPATH_NODESET:
7128 case XPATH_XSLT_TREE:
7129 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007130 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007131 xmlXPathReleaseObject(ctxt->context, arg1);
7132 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007133 return(ret);
7134}
7135
William M. Brack0c022ad2002-07-12 00:56:01 +00007136/**
7137 * xmlXPathEqualValues:
7138 * @ctxt: the XPath Parser context
7139 *
7140 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7141 *
7142 * Returns 0 or 1 depending on the results of the test.
7143 */
7144int
7145xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7146 xmlXPathObjectPtr arg1, arg2, argtmp;
7147 int ret = 0;
7148
Daniel Veillard6128c012004-11-08 17:16:15 +00007149 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007150 arg2 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007151 arg1 = valuePop(ctxt);
7152 if ((arg1 == NULL) || (arg2 == NULL)) {
7153 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007154 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007155 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007156 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007157 XP_ERROR0(XPATH_INVALID_OPERAND);
7158 }
7159
7160 if (arg1 == arg2) {
7161#ifdef DEBUG_EXPR
7162 xmlGenericError(xmlGenericErrorContext,
7163 "Equal: by pointer\n");
7164#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00007165 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007166 return(1);
7167 }
7168
7169 /*
7170 *If either argument is a nodeset, it's a 'special case'
7171 */
7172 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7173 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7174 /*
7175 *Hack it to assure arg1 is the nodeset
7176 */
7177 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7178 argtmp = arg2;
7179 arg2 = arg1;
7180 arg1 = argtmp;
7181 }
7182 switch (arg2->type) {
7183 case XPATH_UNDEFINED:
7184#ifdef DEBUG_EXPR
7185 xmlGenericError(xmlGenericErrorContext,
7186 "Equal: undefined\n");
7187#endif
7188 break;
7189 case XPATH_NODESET:
7190 case XPATH_XSLT_TREE:
7191 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7192 break;
7193 case XPATH_BOOLEAN:
7194 if ((arg1->nodesetval == NULL) ||
7195 (arg1->nodesetval->nodeNr == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007196 else
William M. Brack0c022ad2002-07-12 00:56:01 +00007197 ret = 1;
7198 ret = (ret == arg2->boolval);
7199 break;
7200 case XPATH_NUMBER:
7201 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7202 break;
7203 case XPATH_STRING:
7204 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7205 break;
7206 case XPATH_USERS:
7207 case XPATH_POINT:
7208 case XPATH_RANGE:
7209 case XPATH_LOCATIONSET:
7210 TODO
7211 break;
7212 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007213 xmlXPathReleaseObject(ctxt->context, arg1);
7214 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007215 return(ret);
7216 }
7217
7218 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7219}
7220
7221/**
7222 * xmlXPathNotEqualValues:
7223 * @ctxt: the XPath Parser context
7224 *
7225 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7226 *
7227 * Returns 0 or 1 depending on the results of the test.
7228 */
7229int
7230xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7231 xmlXPathObjectPtr arg1, arg2, argtmp;
7232 int ret = 0;
7233
Daniel Veillard6128c012004-11-08 17:16:15 +00007234 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007235 arg2 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007236 arg1 = valuePop(ctxt);
7237 if ((arg1 == NULL) || (arg2 == NULL)) {
7238 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007239 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007240 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007241 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007242 XP_ERROR0(XPATH_INVALID_OPERAND);
7243 }
7244
7245 if (arg1 == arg2) {
7246#ifdef DEBUG_EXPR
7247 xmlGenericError(xmlGenericErrorContext,
7248 "NotEqual: by pointer\n");
7249#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007250 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007251 return(0);
7252 }
7253
7254 /*
7255 *If either argument is a nodeset, it's a 'special case'
7256 */
7257 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7258 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7259 /*
7260 *Hack it to assure arg1 is the nodeset
7261 */
7262 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7263 argtmp = arg2;
7264 arg2 = arg1;
7265 arg1 = argtmp;
7266 }
7267 switch (arg2->type) {
7268 case XPATH_UNDEFINED:
7269#ifdef DEBUG_EXPR
7270 xmlGenericError(xmlGenericErrorContext,
7271 "NotEqual: undefined\n");
7272#endif
7273 break;
7274 case XPATH_NODESET:
7275 case XPATH_XSLT_TREE:
7276 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7277 break;
7278 case XPATH_BOOLEAN:
7279 if ((arg1->nodesetval == NULL) ||
7280 (arg1->nodesetval->nodeNr == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007281 else
William M. Brack0c022ad2002-07-12 00:56:01 +00007282 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00007283 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00007284 break;
7285 case XPATH_NUMBER:
7286 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7287 break;
7288 case XPATH_STRING:
7289 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7290 break;
7291 case XPATH_USERS:
7292 case XPATH_POINT:
7293 case XPATH_RANGE:
7294 case XPATH_LOCATIONSET:
7295 TODO
7296 break;
7297 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007298 xmlXPathReleaseObject(ctxt->context, arg1);
7299 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007300 return(ret);
7301 }
7302
7303 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7304}
Owen Taylor3473f882001-02-23 17:55:21 +00007305
7306/**
7307 * xmlXPathCompareValues:
7308 * @ctxt: the XPath Parser context
7309 * @inf: less than (1) or greater than (0)
7310 * @strict: is the comparison strict
7311 *
Daniel Veillard45490ae2008-07-29 09:13:19 +00007312 * Implement the compare operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007313 * @arg1 < @arg2 (1, 1, ...
7314 * @arg1 <= @arg2 (1, 0, ...
7315 * @arg1 > @arg2 (0, 1, ...
7316 * @arg1 >= @arg2 (0, 0, ...
7317 *
7318 * When neither object to be compared is a node-set and the operator is
7319 * <=, <, >=, >, then the objects are compared by converted both objects
7320 * to numbers and comparing the numbers according to IEEE 754. The <
7321 * comparison will be true if and only if the first number is less than the
7322 * second number. The <= comparison will be true if and only if the first
7323 * number is less than or equal to the second number. The > comparison
7324 * will be true if and only if the first number is greater than the second
7325 * number. The >= comparison will be true if and only if the first number
7326 * is greater than or equal to the second number.
7327 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007328 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00007329 */
7330int
7331xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007332 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007333 xmlXPathObjectPtr arg1, arg2;
7334
Daniel Veillard6128c012004-11-08 17:16:15 +00007335 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007336 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007337 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007338 if ((arg1 == NULL) || (arg2 == NULL)) {
7339 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007340 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007341 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007342 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007343 XP_ERROR0(XPATH_INVALID_OPERAND);
7344 }
7345
William M. Brack0c022ad2002-07-12 00:56:01 +00007346 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7347 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
William M. Brackd6e347e2005-04-15 01:34:41 +00007348 /*
7349 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7350 * are not freed from within this routine; they will be freed from the
7351 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7352 */
William M. Brack0c022ad2002-07-12 00:56:01 +00007353 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7354 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007355 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007356 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00007357 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007358 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7359 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007360 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007361 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7362 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00007363 }
7364 }
7365 return(ret);
7366 }
7367
7368 if (arg1->type != XPATH_NUMBER) {
7369 valuePush(ctxt, arg1);
7370 xmlXPathNumberFunction(ctxt, 1);
7371 arg1 = valuePop(ctxt);
7372 }
7373 if (arg1->type != XPATH_NUMBER) {
7374 xmlXPathFreeObject(arg1);
7375 xmlXPathFreeObject(arg2);
7376 XP_ERROR0(XPATH_INVALID_OPERAND);
7377 }
7378 if (arg2->type != XPATH_NUMBER) {
7379 valuePush(ctxt, arg2);
7380 xmlXPathNumberFunction(ctxt, 1);
7381 arg2 = valuePop(ctxt);
7382 }
7383 if (arg2->type != XPATH_NUMBER) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007384 xmlXPathReleaseObject(ctxt->context, arg1);
7385 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007386 XP_ERROR0(XPATH_INVALID_OPERAND);
7387 }
7388 /*
7389 * Add tests for infinity and nan
7390 * => feedback on 3.4 for Inf and NaN
7391 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007392 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00007393 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007394 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007395 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007396 arg1i=xmlXPathIsInf(arg1->floatval);
7397 arg2i=xmlXPathIsInf(arg2->floatval);
7398 if (inf && strict) {
7399 if ((arg1i == -1 && arg2i != -1) ||
7400 (arg2i == 1 && arg1i != 1)) {
7401 ret = 1;
7402 } else if (arg1i == 0 && arg2i == 0) {
7403 ret = (arg1->floatval < arg2->floatval);
7404 } else {
7405 ret = 0;
7406 }
7407 }
7408 else if (inf && !strict) {
7409 if (arg1i == -1 || arg2i == 1) {
7410 ret = 1;
7411 } else if (arg1i == 0 && arg2i == 0) {
7412 ret = (arg1->floatval <= arg2->floatval);
7413 } else {
7414 ret = 0;
7415 }
7416 }
7417 else if (!inf && strict) {
7418 if ((arg1i == 1 && arg2i != 1) ||
7419 (arg2i == -1 && arg1i != -1)) {
7420 ret = 1;
7421 } else if (arg1i == 0 && arg2i == 0) {
7422 ret = (arg1->floatval > arg2->floatval);
7423 } else {
7424 ret = 0;
7425 }
7426 }
7427 else if (!inf && !strict) {
7428 if (arg1i == 1 || arg2i == -1) {
7429 ret = 1;
7430 } else if (arg1i == 0 && arg2i == 0) {
7431 ret = (arg1->floatval >= arg2->floatval);
7432 } else {
7433 ret = 0;
7434 }
7435 }
Daniel Veillard21458c82002-03-27 16:12:22 +00007436 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007437 xmlXPathReleaseObject(ctxt->context, arg1);
7438 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007439 return(ret);
7440}
7441
7442/**
7443 * xmlXPathValueFlipSign:
7444 * @ctxt: the XPath Parser context
7445 *
7446 * Implement the unary - operation on an XPath object
7447 * The numeric operators convert their operands to numbers as if
7448 * by calling the number function.
7449 */
7450void
7451xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007452 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007453 CAST_TO_NUMBER;
7454 CHECK_TYPE(XPATH_NUMBER);
Nick Wellnhofer8813f392017-09-21 00:11:26 +02007455 ctxt->value->floatval = -ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00007456}
7457
7458/**
7459 * xmlXPathAddValues:
7460 * @ctxt: the XPath Parser context
7461 *
7462 * Implement the add operation on XPath objects:
7463 * The numeric operators convert their operands to numbers as if
7464 * by calling the number function.
7465 */
7466void
7467xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7468 xmlXPathObjectPtr arg;
7469 double val;
7470
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007471 arg = valuePop(ctxt);
7472 if (arg == NULL)
7473 XP_ERROR(XPATH_INVALID_OPERAND);
7474 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007475 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007476 CAST_TO_NUMBER;
7477 CHECK_TYPE(XPATH_NUMBER);
7478 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00007479}
7480
7481/**
7482 * xmlXPathSubValues:
7483 * @ctxt: the XPath Parser context
7484 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007485 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007486 * The numeric operators convert their operands to numbers as if
7487 * by calling the number function.
7488 */
7489void
7490xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7491 xmlXPathObjectPtr arg;
7492 double val;
7493
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007494 arg = valuePop(ctxt);
7495 if (arg == NULL)
7496 XP_ERROR(XPATH_INVALID_OPERAND);
7497 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007498 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007499 CAST_TO_NUMBER;
7500 CHECK_TYPE(XPATH_NUMBER);
7501 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007502}
7503
7504/**
7505 * xmlXPathMultValues:
7506 * @ctxt: the XPath Parser context
7507 *
7508 * Implement the multiply operation on XPath objects:
7509 * The numeric operators convert their operands to numbers as if
7510 * by calling the number function.
7511 */
7512void
7513xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7514 xmlXPathObjectPtr arg;
7515 double val;
7516
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007517 arg = valuePop(ctxt);
7518 if (arg == NULL)
7519 XP_ERROR(XPATH_INVALID_OPERAND);
7520 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007521 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007522 CAST_TO_NUMBER;
7523 CHECK_TYPE(XPATH_NUMBER);
7524 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007525}
7526
7527/**
7528 * xmlXPathDivValues:
7529 * @ctxt: the XPath Parser context
7530 *
7531 * Implement the div operation on XPath objects @arg1 / @arg2:
7532 * The numeric operators convert their operands to numbers as if
7533 * by calling the number function.
7534 */
Haibo Huangcfd91dc2020-07-30 23:01:33 -07007535ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
Owen Taylor3473f882001-02-23 17:55:21 +00007536void
7537xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7538 xmlXPathObjectPtr arg;
7539 double val;
7540
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007541 arg = valuePop(ctxt);
7542 if (arg == NULL)
7543 XP_ERROR(XPATH_INVALID_OPERAND);
7544 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007545 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007546 CAST_TO_NUMBER;
7547 CHECK_TYPE(XPATH_NUMBER);
Nick Wellnhofer8813f392017-09-21 00:11:26 +02007548 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007549}
7550
7551/**
7552 * xmlXPathModValues:
7553 * @ctxt: the XPath Parser context
7554 *
7555 * Implement the mod operation on XPath objects: @arg1 / @arg2
7556 * The numeric operators convert their operands to numbers as if
7557 * by calling the number function.
7558 */
7559void
7560xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7561 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00007562 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00007563
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007564 arg = valuePop(ctxt);
7565 if (arg == NULL)
7566 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007567 arg2 = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007568 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007569 CAST_TO_NUMBER;
7570 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007571 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00007572 if (arg2 == 0)
Nick Wellnhofer8813f392017-09-21 00:11:26 +02007573 ctxt->value->floatval = NAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007574 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00007575 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007576 }
Owen Taylor3473f882001-02-23 17:55:21 +00007577}
7578
7579/************************************************************************
7580 * *
7581 * The traversal functions *
7582 * *
7583 ************************************************************************/
7584
Owen Taylor3473f882001-02-23 17:55:21 +00007585/*
7586 * A traversal function enumerates nodes along an axis.
7587 * Initially it must be called with NULL, and it indicates
7588 * termination on the axis by returning NULL.
7589 */
7590typedef xmlNodePtr (*xmlXPathTraversalFunction)
7591 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7592
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007593/*
7594 * xmlXPathTraversalFunctionExt:
7595 * A traversal function enumerates nodes along an axis.
7596 * Initially it must be called with NULL, and it indicates
7597 * termination on the axis by returning NULL.
7598 * The context node of the traversal is specified via @contextNode.
7599 */
7600typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7601 (xmlNodePtr cur, xmlNodePtr contextNode);
7602
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00007603/*
7604 * xmlXPathNodeSetMergeFunction:
7605 * Used for merging node sets in xmlXPathCollectAndTest().
7606 */
7607typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
Haibo Huangcfd91dc2020-07-30 23:01:33 -07007608 (xmlNodeSetPtr, xmlNodeSetPtr);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00007609
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007610
Owen Taylor3473f882001-02-23 17:55:21 +00007611/**
7612 * xmlXPathNextSelf:
7613 * @ctxt: the XPath Parser context
7614 * @cur: the current node in the traversal
7615 *
7616 * Traversal function for the "self" direction
7617 * The self axis contains just the context node itself
7618 *
7619 * Returns the next element following that axis
7620 */
7621xmlNodePtr
7622xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007623 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007624 if (cur == NULL)
7625 return(ctxt->context->node);
7626 return(NULL);
7627}
7628
7629/**
7630 * xmlXPathNextChild:
7631 * @ctxt: the XPath Parser context
7632 * @cur: the current node in the traversal
7633 *
7634 * Traversal function for the "child" direction
7635 * The child axis contains the children of the context node in document order.
7636 *
7637 * Returns the next element following that axis
7638 */
7639xmlNodePtr
7640xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007641 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007642 if (cur == NULL) {
7643 if (ctxt->context->node == NULL) return(NULL);
7644 switch (ctxt->context->node->type) {
7645 case XML_ELEMENT_NODE:
7646 case XML_TEXT_NODE:
7647 case XML_CDATA_SECTION_NODE:
7648 case XML_ENTITY_REF_NODE:
7649 case XML_ENTITY_NODE:
7650 case XML_PI_NODE:
7651 case XML_COMMENT_NODE:
7652 case XML_NOTATION_NODE:
7653 case XML_DTD_NODE:
7654 return(ctxt->context->node->children);
7655 case XML_DOCUMENT_NODE:
7656 case XML_DOCUMENT_TYPE_NODE:
7657 case XML_DOCUMENT_FRAG_NODE:
7658 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007659#ifdef LIBXML_DOCB_ENABLED
7660 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007661#endif
7662 return(((xmlDocPtr) ctxt->context->node)->children);
7663 case XML_ELEMENT_DECL:
7664 case XML_ATTRIBUTE_DECL:
7665 case XML_ENTITY_DECL:
7666 case XML_ATTRIBUTE_NODE:
7667 case XML_NAMESPACE_DECL:
7668 case XML_XINCLUDE_START:
7669 case XML_XINCLUDE_END:
7670 return(NULL);
7671 }
7672 return(NULL);
7673 }
7674 if ((cur->type == XML_DOCUMENT_NODE) ||
7675 (cur->type == XML_HTML_DOCUMENT_NODE))
7676 return(NULL);
7677 return(cur->next);
7678}
7679
7680/**
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00007681 * xmlXPathNextChildElement:
7682 * @ctxt: the XPath Parser context
7683 * @cur: the current node in the traversal
7684 *
7685 * Traversal function for the "child" direction and nodes of type element.
7686 * The child axis contains the children of the context node in document order.
7687 *
7688 * Returns the next element following that axis
7689 */
7690static xmlNodePtr
7691xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7692 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7693 if (cur == NULL) {
7694 cur = ctxt->context->node;
7695 if (cur == NULL) return(NULL);
7696 /*
7697 * Get the first element child.
7698 */
7699 switch (cur->type) {
7700 case XML_ELEMENT_NODE:
7701 case XML_DOCUMENT_FRAG_NODE:
7702 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7703 case XML_ENTITY_NODE:
7704 cur = cur->children;
7705 if (cur != NULL) {
7706 if (cur->type == XML_ELEMENT_NODE)
7707 return(cur);
7708 do {
7709 cur = cur->next;
7710 } while ((cur != NULL) &&
7711 (cur->type != XML_ELEMENT_NODE));
7712 return(cur);
7713 }
7714 return(NULL);
7715 case XML_DOCUMENT_NODE:
7716 case XML_HTML_DOCUMENT_NODE:
7717#ifdef LIBXML_DOCB_ENABLED
7718 case XML_DOCB_DOCUMENT_NODE:
7719#endif
7720 return(xmlDocGetRootElement((xmlDocPtr) cur));
7721 default:
7722 return(NULL);
7723 }
7724 return(NULL);
7725 }
7726 /*
7727 * Get the next sibling element node.
7728 */
7729 switch (cur->type) {
7730 case XML_ELEMENT_NODE:
7731 case XML_TEXT_NODE:
7732 case XML_ENTITY_REF_NODE:
7733 case XML_ENTITY_NODE:
7734 case XML_CDATA_SECTION_NODE:
7735 case XML_PI_NODE:
7736 case XML_COMMENT_NODE:
7737 case XML_XINCLUDE_END:
7738 break;
7739 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7740 default:
7741 return(NULL);
7742 }
7743 if (cur->next != NULL) {
7744 if (cur->next->type == XML_ELEMENT_NODE)
7745 return(cur->next);
7746 cur = cur->next;
7747 do {
7748 cur = cur->next;
7749 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7750 return(cur);
7751 }
7752 return(NULL);
7753}
7754
Daniel Veillard76516062012-09-11 14:02:08 +08007755#if 0
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00007756/**
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007757 * xmlXPathNextDescendantOrSelfElemParent:
7758 * @ctxt: the XPath Parser context
7759 * @cur: the current node in the traversal
7760 *
7761 * Traversal function for the "descendant-or-self" axis.
7762 * Additionally it returns only nodes which can be parents of
7763 * element nodes.
7764 *
7765 *
7766 * Returns the next element following that axis
7767 */
7768static xmlNodePtr
7769xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7770 xmlNodePtr contextNode)
7771{
7772 if (cur == NULL) {
7773 if (contextNode == NULL)
7774 return(NULL);
7775 switch (contextNode->type) {
7776 case XML_ELEMENT_NODE:
7777 case XML_XINCLUDE_START:
7778 case XML_DOCUMENT_FRAG_NODE:
7779 case XML_DOCUMENT_NODE:
7780#ifdef LIBXML_DOCB_ENABLED
7781 case XML_DOCB_DOCUMENT_NODE:
7782#endif
Daniel Veillardf8e3db02012-09-11 13:26:36 +08007783 case XML_HTML_DOCUMENT_NODE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007784 return(contextNode);
7785 default:
Daniel Veillard45490ae2008-07-29 09:13:19 +00007786 return(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007787 }
7788 return(NULL);
7789 } else {
7790 xmlNodePtr start = cur;
7791
7792 while (cur != NULL) {
7793 switch (cur->type) {
7794 case XML_ELEMENT_NODE:
7795 /* TODO: OK to have XInclude here? */
7796 case XML_XINCLUDE_START:
Daniel Veillard45490ae2008-07-29 09:13:19 +00007797 case XML_DOCUMENT_FRAG_NODE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007798 if (cur != start)
7799 return(cur);
7800 if (cur->children != NULL) {
7801 cur = cur->children;
7802 continue;
7803 }
7804 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007805 /* Not sure if we need those here. */
7806 case XML_DOCUMENT_NODE:
Daniel Veillard17970a72006-10-26 08:55:47 +00007807#ifdef LIBXML_DOCB_ENABLED
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007808 case XML_DOCB_DOCUMENT_NODE:
7809#endif
7810 case XML_HTML_DOCUMENT_NODE:
7811 if (cur != start)
7812 return(cur);
7813 return(xmlDocGetRootElement((xmlDocPtr) cur));
7814 default:
7815 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007816 }
7817
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007818next_sibling:
7819 if ((cur == NULL) || (cur == contextNode))
Daniel Veillard45490ae2008-07-29 09:13:19 +00007820 return(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007821 if (cur->next != NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00007822 cur = cur->next;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007823 } else {
7824 cur = cur->parent;
7825 goto next_sibling;
7826 }
7827 }
7828 }
7829 return(NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007830}
Daniel Veillard76516062012-09-11 14:02:08 +08007831#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007832
7833/**
Owen Taylor3473f882001-02-23 17:55:21 +00007834 * xmlXPathNextDescendant:
7835 * @ctxt: the XPath Parser context
7836 * @cur: the current node in the traversal
7837 *
7838 * Traversal function for the "descendant" direction
7839 * the descendant axis contains the descendants of the context node in document
7840 * order; a descendant is a child or a child of a child and so on.
7841 *
7842 * Returns the next element following that axis
7843 */
7844xmlNodePtr
7845xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007846 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007847 if (cur == NULL) {
7848 if (ctxt->context->node == NULL)
7849 return(NULL);
7850 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7851 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7852 return(NULL);
7853
7854 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7855 return(ctxt->context->doc->children);
7856 return(ctxt->context->node->children);
7857 }
7858
Daniel Veillard3e62adb2012-08-09 14:24:02 +08007859 if (cur->type == XML_NAMESPACE_DECL)
7860 return(NULL);
Daniel Veillard567e1b42001-08-01 15:53:47 +00007861 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007862 /*
7863 * Do not descend on entities declarations
7864 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00007865 if (cur->children->type != XML_ENTITY_DECL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007866 cur = cur->children;
7867 /*
7868 * Skip DTDs
7869 */
7870 if (cur->type != XML_DTD_NODE)
7871 return(cur);
7872 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00007873 }
7874
7875 if (cur == ctxt->context->node) return(NULL);
7876
Daniel Veillard68e9e742002-11-16 15:35:11 +00007877 while (cur->next != NULL) {
7878 cur = cur->next;
7879 if ((cur->type != XML_ENTITY_DECL) &&
7880 (cur->type != XML_DTD_NODE))
7881 return(cur);
7882 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00007883
Owen Taylor3473f882001-02-23 17:55:21 +00007884 do {
7885 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00007886 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00007887 if (cur == ctxt->context->node) return(NULL);
7888 if (cur->next != NULL) {
7889 cur = cur->next;
7890 return(cur);
7891 }
7892 } while (cur != NULL);
7893 return(cur);
7894}
7895
7896/**
7897 * xmlXPathNextDescendantOrSelf:
7898 * @ctxt: the XPath Parser context
7899 * @cur: the current node in the traversal
7900 *
7901 * Traversal function for the "descendant-or-self" direction
7902 * the descendant-or-self axis contains the context node and the descendants
7903 * of the context node in document order; thus the context node is the first
7904 * node on the axis, and the first child of the context node is the second node
7905 * on the axis
7906 *
7907 * Returns the next element following that axis
7908 */
7909xmlNodePtr
7910xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007911 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Nick Wellnhoferf6aaabc2015-03-08 16:05:26 +01007912 if (cur == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00007913 return(ctxt->context->node);
Nick Wellnhoferf6aaabc2015-03-08 16:05:26 +01007914
7915 if (ctxt->context->node == NULL)
7916 return(NULL);
7917 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7918 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7919 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007920
7921 return(xmlXPathNextDescendant(ctxt, cur));
7922}
7923
7924/**
7925 * xmlXPathNextParent:
7926 * @ctxt: the XPath Parser context
7927 * @cur: the current node in the traversal
7928 *
7929 * Traversal function for the "parent" direction
7930 * The parent axis contains the parent of the context node, if there is one.
7931 *
7932 * Returns the next element following that axis
7933 */
7934xmlNodePtr
7935xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007936 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007937 /*
7938 * the parent of an attribute or namespace node is the element
7939 * to which the attribute or namespace node is attached
7940 * Namespace handling !!!
7941 */
7942 if (cur == NULL) {
7943 if (ctxt->context->node == NULL) return(NULL);
7944 switch (ctxt->context->node->type) {
7945 case XML_ELEMENT_NODE:
7946 case XML_TEXT_NODE:
7947 case XML_CDATA_SECTION_NODE:
7948 case XML_ENTITY_REF_NODE:
7949 case XML_ENTITY_NODE:
7950 case XML_PI_NODE:
7951 case XML_COMMENT_NODE:
7952 case XML_NOTATION_NODE:
7953 case XML_DTD_NODE:
7954 case XML_ELEMENT_DECL:
7955 case XML_ATTRIBUTE_DECL:
7956 case XML_XINCLUDE_START:
7957 case XML_XINCLUDE_END:
7958 case XML_ENTITY_DECL:
7959 if (ctxt->context->node->parent == NULL)
7960 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007961 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007962 ((ctxt->context->node->parent->name[0] == ' ') ||
7963 (xmlStrEqual(ctxt->context->node->parent->name,
7964 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007965 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007966 return(ctxt->context->node->parent);
7967 case XML_ATTRIBUTE_NODE: {
7968 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7969
7970 return(att->parent);
7971 }
7972 case XML_DOCUMENT_NODE:
7973 case XML_DOCUMENT_TYPE_NODE:
7974 case XML_DOCUMENT_FRAG_NODE:
7975 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007976#ifdef LIBXML_DOCB_ENABLED
7977 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007978#endif
7979 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007980 case XML_NAMESPACE_DECL: {
7981 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007982
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007983 if ((ns->next != NULL) &&
7984 (ns->next->type != XML_NAMESPACE_DECL))
7985 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00007986 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007987 }
Owen Taylor3473f882001-02-23 17:55:21 +00007988 }
7989 }
7990 return(NULL);
7991}
7992
7993/**
7994 * xmlXPathNextAncestor:
7995 * @ctxt: the XPath Parser context
7996 * @cur: the current node in the traversal
7997 *
7998 * Traversal function for the "ancestor" direction
7999 * the ancestor axis contains the ancestors of the context node; the ancestors
8000 * of the context node consist of the parent of context node and the parent's
8001 * parent and so on; the nodes are ordered in reverse document order; thus the
8002 * parent is the first node on the axis, and the parent's parent is the second
8003 * node on the axis
8004 *
8005 * Returns the next element following that axis
8006 */
8007xmlNodePtr
8008xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008009 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008010 /*
8011 * the parent of an attribute or namespace node is the element
8012 * to which the attribute or namespace node is attached
8013 * !!!!!!!!!!!!!
8014 */
8015 if (cur == NULL) {
8016 if (ctxt->context->node == NULL) return(NULL);
8017 switch (ctxt->context->node->type) {
8018 case XML_ELEMENT_NODE:
8019 case XML_TEXT_NODE:
8020 case XML_CDATA_SECTION_NODE:
8021 case XML_ENTITY_REF_NODE:
8022 case XML_ENTITY_NODE:
8023 case XML_PI_NODE:
8024 case XML_COMMENT_NODE:
8025 case XML_DTD_NODE:
8026 case XML_ELEMENT_DECL:
8027 case XML_ATTRIBUTE_DECL:
8028 case XML_ENTITY_DECL:
8029 case XML_NOTATION_NODE:
8030 case XML_XINCLUDE_START:
8031 case XML_XINCLUDE_END:
8032 if (ctxt->context->node->parent == NULL)
8033 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008034 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00008035 ((ctxt->context->node->parent->name[0] == ' ') ||
8036 (xmlStrEqual(ctxt->context->node->parent->name,
8037 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008038 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008039 return(ctxt->context->node->parent);
8040 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008041 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00008042
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008043 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00008044 }
8045 case XML_DOCUMENT_NODE:
8046 case XML_DOCUMENT_TYPE_NODE:
8047 case XML_DOCUMENT_FRAG_NODE:
8048 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00008049#ifdef LIBXML_DOCB_ENABLED
8050 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00008051#endif
8052 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008053 case XML_NAMESPACE_DECL: {
8054 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008055
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008056 if ((ns->next != NULL) &&
8057 (ns->next->type != XML_NAMESPACE_DECL))
8058 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00008059 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00008060 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008061 }
Owen Taylor3473f882001-02-23 17:55:21 +00008062 }
8063 return(NULL);
8064 }
8065 if (cur == ctxt->context->doc->children)
8066 return((xmlNodePtr) ctxt->context->doc);
8067 if (cur == (xmlNodePtr) ctxt->context->doc)
8068 return(NULL);
8069 switch (cur->type) {
8070 case XML_ELEMENT_NODE:
8071 case XML_TEXT_NODE:
8072 case XML_CDATA_SECTION_NODE:
8073 case XML_ENTITY_REF_NODE:
8074 case XML_ENTITY_NODE:
8075 case XML_PI_NODE:
8076 case XML_COMMENT_NODE:
8077 case XML_NOTATION_NODE:
8078 case XML_DTD_NODE:
8079 case XML_ELEMENT_DECL:
8080 case XML_ATTRIBUTE_DECL:
8081 case XML_ENTITY_DECL:
8082 case XML_XINCLUDE_START:
8083 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008084 if (cur->parent == NULL)
8085 return(NULL);
8086 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00008087 ((cur->parent->name[0] == ' ') ||
8088 (xmlStrEqual(cur->parent->name,
8089 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008090 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008091 return(cur->parent);
8092 case XML_ATTRIBUTE_NODE: {
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008093 xmlAttrPtr att = (xmlAttrPtr) cur;
Owen Taylor3473f882001-02-23 17:55:21 +00008094
8095 return(att->parent);
8096 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008097 case XML_NAMESPACE_DECL: {
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008098 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008099
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008100 if ((ns->next != NULL) &&
8101 (ns->next->type != XML_NAMESPACE_DECL))
8102 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00008103 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008104 return(NULL);
8105 }
Owen Taylor3473f882001-02-23 17:55:21 +00008106 case XML_DOCUMENT_NODE:
8107 case XML_DOCUMENT_TYPE_NODE:
8108 case XML_DOCUMENT_FRAG_NODE:
8109 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00008110#ifdef LIBXML_DOCB_ENABLED
8111 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00008112#endif
8113 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008114 }
8115 return(NULL);
8116}
8117
8118/**
8119 * xmlXPathNextAncestorOrSelf:
8120 * @ctxt: the XPath Parser context
8121 * @cur: the current node in the traversal
8122 *
8123 * Traversal function for the "ancestor-or-self" direction
8124 * he ancestor-or-self axis contains the context node and ancestors of
8125 * the context node in reverse document order; thus the context node is
8126 * the first node on the axis, and the context node's parent the second;
8127 * parent here is defined the same as with the parent axis.
8128 *
8129 * Returns the next element following that axis
8130 */
8131xmlNodePtr
8132xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008133 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008134 if (cur == NULL)
8135 return(ctxt->context->node);
8136 return(xmlXPathNextAncestor(ctxt, cur));
8137}
8138
8139/**
8140 * xmlXPathNextFollowingSibling:
8141 * @ctxt: the XPath Parser context
8142 * @cur: the current node in the traversal
8143 *
8144 * Traversal function for the "following-sibling" direction
8145 * The following-sibling axis contains the following siblings of the context
8146 * node in document order.
8147 *
8148 * Returns the next element following that axis
8149 */
8150xmlNodePtr
8151xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008152 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008153 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8154 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8155 return(NULL);
8156 if (cur == (xmlNodePtr) ctxt->context->doc)
8157 return(NULL);
8158 if (cur == NULL)
8159 return(ctxt->context->node->next);
8160 return(cur->next);
8161}
8162
8163/**
8164 * xmlXPathNextPrecedingSibling:
8165 * @ctxt: the XPath Parser context
8166 * @cur: the current node in the traversal
8167 *
8168 * Traversal function for the "preceding-sibling" direction
8169 * The preceding-sibling axis contains the preceding siblings of the context
8170 * node in reverse document order; the first preceding sibling is first on the
8171 * axis; the sibling preceding that node is the second on the axis and so on.
8172 *
8173 * Returns the next element following that axis
8174 */
8175xmlNodePtr
8176xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008177 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008178 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8179 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8180 return(NULL);
8181 if (cur == (xmlNodePtr) ctxt->context->doc)
8182 return(NULL);
8183 if (cur == NULL)
8184 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008185 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8186 cur = cur->prev;
8187 if (cur == NULL)
8188 return(ctxt->context->node->prev);
8189 }
Owen Taylor3473f882001-02-23 17:55:21 +00008190 return(cur->prev);
8191}
8192
8193/**
8194 * xmlXPathNextFollowing:
8195 * @ctxt: the XPath Parser context
8196 * @cur: the current node in the traversal
8197 *
8198 * Traversal function for the "following" direction
8199 * The following axis contains all nodes in the same document as the context
8200 * node that are after the context node in document order, excluding any
8201 * descendants and excluding attribute nodes and namespace nodes; the nodes
8202 * are ordered in document order
8203 *
8204 * Returns the next element following that axis
8205 */
8206xmlNodePtr
8207xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008208 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008209 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
8210 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8211 return(cur->children);
8212
8213 if (cur == NULL) {
8214 cur = ctxt->context->node;
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008215 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardea90b892010-10-22 15:50:50 +02008216 cur = cur->parent;
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008217 } else if (cur->type == XML_NAMESPACE_DECL) {
8218 xmlNsPtr ns = (xmlNsPtr) cur;
8219
8220 if ((ns->next == NULL) ||
8221 (ns->next->type == XML_NAMESPACE_DECL))
8222 return (NULL);
8223 cur = (xmlNodePtr) ns->next;
8224 }
Daniel Veillard91d19752010-10-15 14:30:52 +02008225 }
Owen Taylor3473f882001-02-23 17:55:21 +00008226 if (cur == NULL) return(NULL) ; /* ERROR */
8227 if (cur->next != NULL) return(cur->next) ;
8228 do {
8229 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00008230 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00008231 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8232 if (cur->next != NULL) return(cur->next);
8233 } while (cur != NULL);
8234 return(cur);
8235}
8236
8237/*
8238 * xmlXPathIsAncestor:
8239 * @ancestor: the ancestor node
8240 * @node: the current node
8241 *
8242 * Check that @ancestor is a @node's ancestor
8243 *
8244 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8245 */
8246static int
8247xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8248 if ((ancestor == NULL) || (node == NULL)) return(0);
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008249 if (node->type == XML_NAMESPACE_DECL)
8250 return(0);
8251 if (ancestor->type == XML_NAMESPACE_DECL)
8252 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00008253 /* nodes need to be in the same document */
8254 if (ancestor->doc != node->doc) return(0);
8255 /* avoid searching if ancestor or node is the root node */
8256 if (ancestor == (xmlNodePtr) node->doc) return(1);
8257 if (node == (xmlNodePtr) ancestor->doc) return(0);
8258 while (node->parent != NULL) {
8259 if (node->parent == ancestor)
8260 return(1);
8261 node = node->parent;
8262 }
8263 return(0);
8264}
8265
8266/**
8267 * xmlXPathNextPreceding:
8268 * @ctxt: the XPath Parser context
8269 * @cur: the current node in the traversal
8270 *
8271 * Traversal function for the "preceding" direction
8272 * the preceding axis contains all nodes in the same document as the context
8273 * node that are before the context node in document order, excluding any
8274 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8275 * ordered in reverse document order
8276 *
8277 * Returns the next element following that axis
8278 */
8279xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00008280xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8281{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008282 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008283 if (cur == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008284 cur = ctxt->context->node;
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008285 if (cur->type == XML_ATTRIBUTE_NODE) {
8286 cur = cur->parent;
8287 } else if (cur->type == XML_NAMESPACE_DECL) {
8288 xmlNsPtr ns = (xmlNsPtr) cur;
8289
8290 if ((ns->next == NULL) ||
8291 (ns->next->type == XML_NAMESPACE_DECL))
8292 return (NULL);
8293 cur = (xmlNodePtr) ns->next;
8294 }
Daniel Veillardea90b892010-10-22 15:50:50 +02008295 }
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008296 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
Daniel Veillardf06307e2001-07-03 10:35:50 +00008297 return (NULL);
8298 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8299 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00008300 do {
8301 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008302 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8303 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008304 }
8305
8306 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008307 if (cur == NULL)
8308 return (NULL);
8309 if (cur == ctxt->context->doc->children)
8310 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008311 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00008312 return (cur);
8313}
8314
8315/**
8316 * xmlXPathNextPrecedingInternal:
8317 * @ctxt: the XPath Parser context
8318 * @cur: the current node in the traversal
8319 *
8320 * Traversal function for the "preceding" direction
8321 * the preceding axis contains all nodes in the same document as the context
8322 * node that are before the context node in document order, excluding any
8323 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8324 * ordered in reverse document order
Daniel Veillard45490ae2008-07-29 09:13:19 +00008325 * This is a faster implementation but internal only since it requires a
Daniel Veillardf06307e2001-07-03 10:35:50 +00008326 * state kept in the parser context: ctxt->ancestor.
8327 *
8328 * Returns the next element following that axis
8329 */
8330static xmlNodePtr
8331xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8332 xmlNodePtr cur)
8333{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008334 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008335 if (cur == NULL) {
8336 cur = ctxt->context->node;
8337 if (cur == NULL)
8338 return (NULL);
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008339 if (cur->type == XML_ATTRIBUTE_NODE) {
8340 cur = cur->parent;
8341 } else if (cur->type == XML_NAMESPACE_DECL) {
8342 xmlNsPtr ns = (xmlNsPtr) cur;
8343
8344 if ((ns->next == NULL) ||
8345 (ns->next->type == XML_NAMESPACE_DECL))
8346 return (NULL);
8347 cur = (xmlNodePtr) ns->next;
8348 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00008349 ctxt->ancestor = cur->parent;
8350 }
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008351 if (cur->type == XML_NAMESPACE_DECL)
8352 return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008353 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8354 cur = cur->prev;
8355 while (cur->prev == NULL) {
8356 cur = cur->parent;
8357 if (cur == NULL)
8358 return (NULL);
8359 if (cur == ctxt->context->doc->children)
8360 return (NULL);
8361 if (cur != ctxt->ancestor)
8362 return (cur);
8363 ctxt->ancestor = cur->parent;
8364 }
8365 cur = cur->prev;
8366 while (cur->last != NULL)
8367 cur = cur->last;
8368 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008369}
8370
8371/**
8372 * xmlXPathNextNamespace:
8373 * @ctxt: the XPath Parser context
8374 * @cur: the current attribute in the traversal
8375 *
8376 * Traversal function for the "namespace" direction
8377 * the namespace axis contains the namespace nodes of the context node;
8378 * the order of nodes on this axis is implementation-defined; the axis will
8379 * be empty unless the context node is an element
8380 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008381 * We keep the XML namespace node at the end of the list.
8382 *
Owen Taylor3473f882001-02-23 17:55:21 +00008383 * Returns the next element following that axis
8384 */
8385xmlNodePtr
8386xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008387 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008388 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Nick Wellnhofer82b73032016-04-30 17:53:10 +02008389 if (cur == NULL) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008390 if (ctxt->context->tmpNsList != NULL)
8391 xmlFree(ctxt->context->tmpNsList);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008392 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00008393 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008394 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00008395 if (ctxt->context->tmpNsList != NULL) {
8396 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8397 ctxt->context->tmpNsNr++;
8398 }
8399 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008400 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008401 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00008402 if (ctxt->context->tmpNsNr > 0) {
8403 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8404 } else {
8405 if (ctxt->context->tmpNsList != NULL)
8406 xmlFree(ctxt->context->tmpNsList);
8407 ctxt->context->tmpNsList = NULL;
8408 return(NULL);
8409 }
Owen Taylor3473f882001-02-23 17:55:21 +00008410}
8411
8412/**
8413 * xmlXPathNextAttribute:
8414 * @ctxt: the XPath Parser context
8415 * @cur: the current attribute in the traversal
8416 *
8417 * Traversal function for the "attribute" direction
8418 * TODO: support DTD inherited default attributes
8419 *
8420 * Returns the next element following that axis
8421 */
8422xmlNodePtr
8423xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008424 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00008425 if (ctxt->context->node == NULL)
8426 return(NULL);
8427 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8428 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008429 if (cur == NULL) {
8430 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8431 return(NULL);
8432 return((xmlNodePtr)ctxt->context->node->properties);
8433 }
8434 return((xmlNodePtr)cur->next);
8435}
8436
8437/************************************************************************
8438 * *
8439 * NodeTest Functions *
8440 * *
8441 ************************************************************************/
8442
Owen Taylor3473f882001-02-23 17:55:21 +00008443#define IS_FUNCTION 200
8444
Owen Taylor3473f882001-02-23 17:55:21 +00008445
8446/************************************************************************
8447 * *
8448 * Implicit tree core function library *
8449 * *
8450 ************************************************************************/
8451
8452/**
8453 * xmlXPathRoot:
8454 * @ctxt: the XPath Parser context
8455 *
8456 * Initialize the context to the root of the document
8457 */
8458void
8459xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008460 if ((ctxt == NULL) || (ctxt->context == NULL))
8461 return;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008462 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
Elliott Hughes7fbecab2019-01-10 16:42:03 -08008463 (xmlNodePtr) ctxt->context->doc));
Owen Taylor3473f882001-02-23 17:55:21 +00008464}
8465
8466/************************************************************************
8467 * *
8468 * The explicit core function library *
8469 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8470 * *
8471 ************************************************************************/
8472
8473
8474/**
8475 * xmlXPathLastFunction:
8476 * @ctxt: the XPath Parser context
8477 * @nargs: the number of arguments
8478 *
8479 * Implement the last() XPath function
8480 * number last()
8481 * The last function returns the number of nodes in the context node list.
8482 */
8483void
8484xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8485 CHECK_ARITY(0);
8486 if (ctxt->context->contextSize >= 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008487 valuePush(ctxt,
8488 xmlXPathCacheNewFloat(ctxt->context,
8489 (double) ctxt->context->contextSize));
Owen Taylor3473f882001-02-23 17:55:21 +00008490#ifdef DEBUG_EXPR
8491 xmlGenericError(xmlGenericErrorContext,
8492 "last() : %d\n", ctxt->context->contextSize);
8493#endif
8494 } else {
8495 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8496 }
8497}
8498
8499/**
8500 * xmlXPathPositionFunction:
8501 * @ctxt: the XPath Parser context
8502 * @nargs: the number of arguments
8503 *
8504 * Implement the position() XPath function
8505 * number position()
8506 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008507 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00008508 * will be equal to last().
8509 */
8510void
8511xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8512 CHECK_ARITY(0);
8513 if (ctxt->context->proximityPosition >= 0) {
8514 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008515 xmlXPathCacheNewFloat(ctxt->context,
8516 (double) ctxt->context->proximityPosition));
Owen Taylor3473f882001-02-23 17:55:21 +00008517#ifdef DEBUG_EXPR
8518 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8519 ctxt->context->proximityPosition);
8520#endif
8521 } else {
8522 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8523 }
8524}
8525
8526/**
8527 * xmlXPathCountFunction:
8528 * @ctxt: the XPath Parser context
8529 * @nargs: the number of arguments
8530 *
8531 * Implement the count() XPath function
8532 * number count(node-set)
8533 */
8534void
8535xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8536 xmlXPathObjectPtr cur;
8537
8538 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008539 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008540 ((ctxt->value->type != XPATH_NODESET) &&
8541 (ctxt->value->type != XPATH_XSLT_TREE)))
8542 XP_ERROR(XPATH_INVALID_TYPE);
8543 cur = valuePop(ctxt);
8544
Daniel Veillard911f49a2001-04-07 15:39:35 +00008545 if ((cur == NULL) || (cur->nodesetval == NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008546 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
Haibo Huangcfd91dc2020-07-30 23:01:33 -07008547 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008548 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8549 (double) cur->nodesetval->nodeNr));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008550 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008551}
8552
8553/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008554 * xmlXPathGetElementsByIds:
8555 * @doc: the document
8556 * @ids: a whitespace separated list of IDs
8557 *
8558 * Selects elements by their unique ID.
8559 *
8560 * Returns a node-set of selected elements.
8561 */
8562static xmlNodeSetPtr
8563xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8564 xmlNodeSetPtr ret;
8565 const xmlChar *cur = ids;
8566 xmlChar *ID;
8567 xmlAttrPtr attr;
8568 xmlNodePtr elem = NULL;
8569
Daniel Veillard7a985a12003-07-06 17:57:42 +00008570 if (ids == NULL) return(NULL);
8571
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008572 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00008573 if (ret == NULL)
8574 return(ret);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008575
William M. Brack76e95df2003-10-18 16:20:14 +00008576 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008577 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008578 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00008579 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008580
8581 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00008582 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00008583 /*
8584 * We used to check the fact that the value passed
8585 * was an NCName, but this generated much troubles for
8586 * me and Aleksey Sanin, people blatantly violated that
Haibo Huangcfd91dc2020-07-30 23:01:33 -07008587 * constraint, like Visa3D spec.
Daniel Veillard68cb4b22004-04-18 20:55:39 +00008588 * if (xmlValidateNCName(ID, 1) == 0)
8589 */
8590 attr = xmlGetID(doc, ID);
8591 if (attr != NULL) {
8592 if (attr->type == XML_ATTRIBUTE_NODE)
8593 elem = attr->parent;
8594 else if (attr->type == XML_ELEMENT_NODE)
8595 elem = (xmlNodePtr) attr;
8596 else
8597 elem = NULL;
Haibo Huangcfd91dc2020-07-30 23:01:33 -07008598 /* TODO: Check memory error. */
Daniel Veillard68cb4b22004-04-18 20:55:39 +00008599 if (elem != NULL)
8600 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00008601 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008602 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00008603 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008604
William M. Brack76e95df2003-10-18 16:20:14 +00008605 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008606 ids = cur;
8607 }
8608 return(ret);
8609}
8610
8611/**
Owen Taylor3473f882001-02-23 17:55:21 +00008612 * xmlXPathIdFunction:
8613 * @ctxt: the XPath Parser context
8614 * @nargs: the number of arguments
8615 *
8616 * Implement the id() XPath function
8617 * node-set id(object)
8618 * The id function selects elements by their unique ID
8619 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8620 * then the result is the union of the result of applying id to the
8621 * string value of each of the nodes in the argument node-set. When the
8622 * argument to id is of any other type, the argument is converted to a
8623 * string as if by a call to the string function; the string is split
8624 * into a whitespace-separated list of tokens (whitespace is any sequence
8625 * of characters matching the production S); the result is a node-set
8626 * containing the elements in the same document as the context node that
8627 * have a unique ID equal to any of the tokens in the list.
8628 */
8629void
8630xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008631 xmlChar *tokens;
8632 xmlNodeSetPtr ret;
8633 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00008634
8635 CHECK_ARITY(1);
8636 obj = valuePop(ctxt);
8637 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00008638 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008639 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00008640 int i;
8641
Haibo Huangcfd91dc2020-07-30 23:01:33 -07008642 /* TODO: Check memory error. */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008643 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008644
Daniel Veillard911f49a2001-04-07 15:39:35 +00008645 if (obj->nodesetval != NULL) {
8646 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008647 tokens =
8648 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8649 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
Haibo Huangcfd91dc2020-07-30 23:01:33 -07008650 /* TODO: Check memory error. */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008651 ret = xmlXPathNodeSetMerge(ret, ns);
8652 xmlXPathFreeNodeSet(ns);
8653 if (tokens != NULL)
8654 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00008655 }
Owen Taylor3473f882001-02-23 17:55:21 +00008656 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008657 xmlXPathReleaseObject(ctxt->context, obj);
8658 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00008659 return;
8660 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008661 obj = xmlXPathCacheConvertString(ctxt->context, obj);
Haibo Huangcfd91dc2020-07-30 23:01:33 -07008662 if (obj == NULL) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008663 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008664 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008665 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00008666 return;
8667}
8668
8669/**
8670 * xmlXPathLocalNameFunction:
8671 * @ctxt: the XPath Parser context
8672 * @nargs: the number of arguments
8673 *
8674 * Implement the local-name() XPath function
8675 * string local-name(node-set?)
8676 * The local-name function returns a string containing the local part
8677 * of the name of the node in the argument node-set that is first in
8678 * document order. If the node-set is empty or the first node has no
8679 * name, an empty string is returned. If the argument is omitted it
8680 * defaults to the context node.
8681 */
8682void
8683xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8684 xmlXPathObjectPtr cur;
8685
Daniel Veillarda82b1822004-11-08 16:24:57 +00008686 if (ctxt == NULL) return;
8687
Owen Taylor3473f882001-02-23 17:55:21 +00008688 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008689 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8690 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008691 nargs = 1;
8692 }
8693
8694 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008695 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008696 ((ctxt->value->type != XPATH_NODESET) &&
8697 (ctxt->value->type != XPATH_XSLT_TREE)))
8698 XP_ERROR(XPATH_INVALID_TYPE);
8699 cur = valuePop(ctxt);
8700
Daniel Veillard911f49a2001-04-07 15:39:35 +00008701 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008702 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008703 } else {
8704 int i = 0; /* Should be first in document order !!!!! */
8705 switch (cur->nodesetval->nodeTab[i]->type) {
8706 case XML_ELEMENT_NODE:
8707 case XML_ATTRIBUTE_NODE:
8708 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008709 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008710 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008711 else
8712 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008713 xmlXPathCacheNewString(ctxt->context,
8714 cur->nodesetval->nodeTab[i]->name));
Owen Taylor3473f882001-02-23 17:55:21 +00008715 break;
8716 case XML_NAMESPACE_DECL:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008717 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008718 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8719 break;
8720 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008721 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008722 }
8723 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008724 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008725}
8726
8727/**
8728 * xmlXPathNamespaceURIFunction:
8729 * @ctxt: the XPath Parser context
8730 * @nargs: the number of arguments
8731 *
8732 * Implement the namespace-uri() XPath function
8733 * string namespace-uri(node-set?)
8734 * The namespace-uri function returns a string containing the
8735 * namespace URI of the expanded name of the node in the argument
8736 * node-set that is first in document order. If the node-set is empty,
8737 * the first node has no name, or the expanded name has no namespace
8738 * URI, an empty string is returned. If the argument is omitted it
8739 * defaults to the context node.
8740 */
8741void
8742xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8743 xmlXPathObjectPtr cur;
8744
Daniel Veillarda82b1822004-11-08 16:24:57 +00008745 if (ctxt == NULL) return;
8746
Owen Taylor3473f882001-02-23 17:55:21 +00008747 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008748 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8749 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008750 nargs = 1;
8751 }
8752 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008753 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008754 ((ctxt->value->type != XPATH_NODESET) &&
8755 (ctxt->value->type != XPATH_XSLT_TREE)))
8756 XP_ERROR(XPATH_INVALID_TYPE);
8757 cur = valuePop(ctxt);
8758
Daniel Veillard911f49a2001-04-07 15:39:35 +00008759 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008760 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008761 } else {
8762 int i = 0; /* Should be first in document order !!!!! */
8763 switch (cur->nodesetval->nodeTab[i]->type) {
8764 case XML_ELEMENT_NODE:
8765 case XML_ATTRIBUTE_NODE:
8766 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008767 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008768 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008769 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008770 cur->nodesetval->nodeTab[i]->ns->href));
8771 break;
8772 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008773 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008774 }
8775 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008776 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008777}
8778
8779/**
8780 * xmlXPathNameFunction:
8781 * @ctxt: the XPath Parser context
8782 * @nargs: the number of arguments
8783 *
8784 * Implement the name() XPath function
8785 * string name(node-set?)
8786 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008787 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00008788 * order. The QName must represent the name with respect to the namespace
8789 * declarations in effect on the node whose name is being represented.
8790 * Typically, this will be the form in which the name occurred in the XML
8791 * source. This need not be the case if there are namespace declarations
8792 * in effect on the node that associate multiple prefixes with the same
8793 * namespace. However, an implementation may include information about
8794 * the original prefix in its representation of nodes; in this case, an
8795 * implementation can ensure that the returned string is always the same
8796 * as the QName used in the XML source. If the argument it omitted it
8797 * defaults to the context node.
8798 * Libxml keep the original prefix so the "real qualified name" used is
8799 * returned.
8800 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008801static void
Daniel Veillard04383752001-07-08 14:27:15 +00008802xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8803{
Owen Taylor3473f882001-02-23 17:55:21 +00008804 xmlXPathObjectPtr cur;
8805
8806 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008807 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8808 ctxt->context->node));
Daniel Veillard04383752001-07-08 14:27:15 +00008809 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008810 }
8811
8812 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00008813 if ((ctxt->value == NULL) ||
8814 ((ctxt->value->type != XPATH_NODESET) &&
8815 (ctxt->value->type != XPATH_XSLT_TREE)))
8816 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00008817 cur = valuePop(ctxt);
8818
Daniel Veillard911f49a2001-04-07 15:39:35 +00008819 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008820 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008821 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00008822 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00008823
Daniel Veillard04383752001-07-08 14:27:15 +00008824 switch (cur->nodesetval->nodeTab[i]->type) {
8825 case XML_ELEMENT_NODE:
8826 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008827 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008828 valuePush(ctxt,
8829 xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008830 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8831 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008832 valuePush(ctxt,
8833 xmlXPathCacheNewString(ctxt->context,
8834 cur->nodesetval->nodeTab[i]->name));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008835 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00008836 xmlChar *fullname;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008837
Daniel Veillardc00cda82003-04-07 10:22:39 +00008838 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8839 cur->nodesetval->nodeTab[i]->ns->prefix,
8840 NULL, 0);
8841 if (fullname == cur->nodesetval->nodeTab[i]->name)
8842 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8843 if (fullname == NULL) {
8844 XP_ERROR(XPATH_MEMORY_ERROR);
8845 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008846 valuePush(ctxt, xmlXPathCacheWrapString(
8847 ctxt->context, fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00008848 }
8849 break;
8850 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008851 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8852 cur->nodesetval->nodeTab[i]));
Daniel Veillard04383752001-07-08 14:27:15 +00008853 xmlXPathLocalNameFunction(ctxt, 1);
8854 }
Owen Taylor3473f882001-02-23 17:55:21 +00008855 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008856 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008857}
8858
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008859
8860/**
Owen Taylor3473f882001-02-23 17:55:21 +00008861 * xmlXPathStringFunction:
8862 * @ctxt: the XPath Parser context
8863 * @nargs: the number of arguments
8864 *
8865 * Implement the string() XPath function
8866 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00008867 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00008868 * - A node-set is converted to a string by returning the value of
8869 * the node in the node-set that is first in document order.
8870 * If the node-set is empty, an empty string is returned.
8871 * - A number is converted to a string as follows
Daniel Veillard45490ae2008-07-29 09:13:19 +00008872 * + NaN is converted to the string NaN
8873 * + positive zero is converted to the string 0
8874 * + negative zero is converted to the string 0
8875 * + positive infinity is converted to the string Infinity
8876 * + negative infinity is converted to the string -Infinity
Owen Taylor3473f882001-02-23 17:55:21 +00008877 * + if the number is an integer, the number is represented in
8878 * decimal form as a Number with no decimal point and no leading
8879 * zeros, preceded by a minus sign (-) if the number is negative
8880 * + otherwise, the number is represented in decimal form as a
8881 * Number including a decimal point with at least one digit
8882 * before the decimal point and at least one digit after the
8883 * decimal point, preceded by a minus sign (-) if the number
8884 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008885 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00008886 * before the decimal point; beyond the one required digit
8887 * after the decimal point there must be as many, but only as
8888 * many, more digits as are needed to uniquely distinguish the
8889 * number from all other IEEE 754 numeric values.
8890 * - The boolean false value is converted to the string false.
8891 * The boolean true value is converted to the string true.
8892 *
8893 * If the argument is omitted, it defaults to a node-set with the
8894 * context node as its only member.
8895 */
8896void
8897xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8898 xmlXPathObjectPtr cur;
8899
Daniel Veillarda82b1822004-11-08 16:24:57 +00008900 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008901 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008902 valuePush(ctxt,
8903 xmlXPathCacheWrapString(ctxt->context,
8904 xmlXPathCastNodeToString(ctxt->context->node)));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008905 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008906 }
8907
8908 CHECK_ARITY(1);
8909 cur = valuePop(ctxt);
8910 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008911 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00008912}
8913
8914/**
8915 * xmlXPathStringLengthFunction:
8916 * @ctxt: the XPath Parser context
8917 * @nargs: the number of arguments
8918 *
8919 * Implement the string-length() XPath function
8920 * number string-length(string?)
8921 * The string-length returns the number of characters in the string
8922 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8923 * the context node converted to a string, in other words the value
8924 * of the context node.
8925 */
8926void
8927xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8928 xmlXPathObjectPtr cur;
8929
8930 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008931 if ((ctxt == NULL) || (ctxt->context == NULL))
8932 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008933 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008934 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008935 } else {
8936 xmlChar *content;
8937
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008938 content = xmlXPathCastNodeToString(ctxt->context->node);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008939 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8940 xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00008941 xmlFree(content);
8942 }
8943 return;
8944 }
8945 CHECK_ARITY(1);
8946 CAST_TO_STRING;
8947 CHECK_TYPE(XPATH_STRING);
8948 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008949 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
Daniel Veillard45490ae2008-07-29 09:13:19 +00008950 xmlUTF8Strlen(cur->stringval)));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008951 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008952}
8953
8954/**
8955 * xmlXPathConcatFunction:
8956 * @ctxt: the XPath Parser context
8957 * @nargs: the number of arguments
8958 *
8959 * Implement the concat() XPath function
8960 * string concat(string, string, string*)
8961 * The concat function returns the concatenation of its arguments.
8962 */
8963void
8964xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8965 xmlXPathObjectPtr cur, newobj;
8966 xmlChar *tmp;
8967
Daniel Veillarda82b1822004-11-08 16:24:57 +00008968 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008969 if (nargs < 2) {
8970 CHECK_ARITY(2);
8971 }
8972
8973 CAST_TO_STRING;
8974 cur = valuePop(ctxt);
8975 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008976 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008977 return;
8978 }
8979 nargs--;
8980
8981 while (nargs > 0) {
8982 CAST_TO_STRING;
8983 newobj = valuePop(ctxt);
8984 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008985 xmlXPathReleaseObject(ctxt->context, newobj);
8986 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008987 XP_ERROR(XPATH_INVALID_TYPE);
8988 }
8989 tmp = xmlStrcat(newobj->stringval, cur->stringval);
8990 newobj->stringval = cur->stringval;
8991 cur->stringval = tmp;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008992 xmlXPathReleaseObject(ctxt->context, newobj);
Owen Taylor3473f882001-02-23 17:55:21 +00008993 nargs--;
8994 }
8995 valuePush(ctxt, cur);
8996}
8997
8998/**
8999 * xmlXPathContainsFunction:
9000 * @ctxt: the XPath Parser context
9001 * @nargs: the number of arguments
9002 *
9003 * Implement the contains() XPath function
9004 * boolean contains(string, string)
9005 * The contains function returns true if the first argument string
9006 * contains the second argument string, and otherwise returns false.
9007 */
9008void
9009xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9010 xmlXPathObjectPtr hay, needle;
9011
9012 CHECK_ARITY(2);
9013 CAST_TO_STRING;
9014 CHECK_TYPE(XPATH_STRING);
9015 needle = valuePop(ctxt);
9016 CAST_TO_STRING;
9017 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009018
Owen Taylor3473f882001-02-23 17:55:21 +00009019 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009020 xmlXPathReleaseObject(ctxt->context, hay);
9021 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009022 XP_ERROR(XPATH_INVALID_TYPE);
9023 }
9024 if (xmlStrstr(hay->stringval, needle->stringval))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009025 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009026 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009027 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9028 xmlXPathReleaseObject(ctxt->context, hay);
9029 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009030}
9031
9032/**
9033 * xmlXPathStartsWithFunction:
9034 * @ctxt: the XPath Parser context
9035 * @nargs: the number of arguments
9036 *
9037 * Implement the starts-with() XPath function
9038 * boolean starts-with(string, string)
9039 * The starts-with function returns true if the first argument string
9040 * starts with the second argument string, and otherwise returns false.
9041 */
9042void
9043xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9044 xmlXPathObjectPtr hay, needle;
9045 int n;
9046
9047 CHECK_ARITY(2);
9048 CAST_TO_STRING;
9049 CHECK_TYPE(XPATH_STRING);
9050 needle = valuePop(ctxt);
9051 CAST_TO_STRING;
9052 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009053
Owen Taylor3473f882001-02-23 17:55:21 +00009054 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009055 xmlXPathReleaseObject(ctxt->context, hay);
9056 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009057 XP_ERROR(XPATH_INVALID_TYPE);
9058 }
9059 n = xmlStrlen(needle->stringval);
9060 if (xmlStrncmp(hay->stringval, needle->stringval, n))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009061 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009062 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009063 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9064 xmlXPathReleaseObject(ctxt->context, hay);
9065 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009066}
9067
9068/**
9069 * xmlXPathSubstringFunction:
9070 * @ctxt: the XPath Parser context
9071 * @nargs: the number of arguments
9072 *
9073 * Implement the substring() XPath function
9074 * string substring(string, number, number?)
9075 * The substring function returns the substring of the first argument
9076 * starting at the position specified in the second argument with
9077 * length specified in the third argument. For example,
9078 * substring("12345",2,3) returns "234". If the third argument is not
9079 * specified, it returns the substring starting at the position specified
9080 * in the second argument and continuing to the end of the string. For
9081 * example, substring("12345",2) returns "2345". More precisely, each
9082 * character in the string (see [3.6 Strings]) is considered to have a
9083 * numeric position: the position of the first character is 1, the position
9084 * of the second character is 2 and so on. The returned substring contains
9085 * those characters for which the position of the character is greater than
9086 * or equal to the second argument and, if the third argument is specified,
9087 * less than the sum of the second and third arguments; the comparisons
9088 * and addition used for the above follow the standard IEEE 754 rules. Thus:
Daniel Veillard45490ae2008-07-29 09:13:19 +00009089 * - substring("12345", 1.5, 2.6) returns "234"
9090 * - substring("12345", 0, 3) returns "12"
9091 * - substring("12345", 0 div 0, 3) returns ""
9092 * - substring("12345", 1, 0 div 0) returns ""
9093 * - substring("12345", -42, 1 div 0) returns "12345"
9094 * - substring("12345", -1 div 0, 1 div 0) returns ""
Owen Taylor3473f882001-02-23 17:55:21 +00009095 */
9096void
9097xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9098 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009099 double le=0, in;
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009100 int i = 1, j = INT_MAX;
Owen Taylor3473f882001-02-23 17:55:21 +00009101
Owen Taylor3473f882001-02-23 17:55:21 +00009102 if (nargs < 2) {
9103 CHECK_ARITY(2);
9104 }
9105 if (nargs > 3) {
9106 CHECK_ARITY(3);
9107 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009108 /*
9109 * take care of possible last (position) argument
9110 */
Owen Taylor3473f882001-02-23 17:55:21 +00009111 if (nargs == 3) {
9112 CAST_TO_NUMBER;
9113 CHECK_TYPE(XPATH_NUMBER);
9114 len = valuePop(ctxt);
9115 le = len->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009116 xmlXPathReleaseObject(ctxt->context, len);
Owen Taylor3473f882001-02-23 17:55:21 +00009117 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009118
Owen Taylor3473f882001-02-23 17:55:21 +00009119 CAST_TO_NUMBER;
9120 CHECK_TYPE(XPATH_NUMBER);
9121 start = valuePop(ctxt);
9122 in = start->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009123 xmlXPathReleaseObject(ctxt->context, start);
Owen Taylor3473f882001-02-23 17:55:21 +00009124 CAST_TO_STRING;
9125 CHECK_TYPE(XPATH_STRING);
9126 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009127
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009128 if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
9129 i = INT_MAX;
9130 } else if (in >= 1.0) {
9131 i = (int)in;
9132 if (in - floor(in) >= 0.5)
9133 i += 1;
Daniel Veillard9e412302002-06-10 15:59:44 +00009134 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009135
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009136 if (nargs == 3) {
9137 double rin, rle, end;
Owen Taylor3473f882001-02-23 17:55:21 +00009138
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009139 rin = floor(in);
9140 if (in - rin >= 0.5)
9141 rin += 1.0;
Daniel Veillard9e412302002-06-10 15:59:44 +00009142
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009143 rle = floor(le);
9144 if (le - rle >= 0.5)
9145 rle += 1.0;
Owen Taylor3473f882001-02-23 17:55:21 +00009146
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009147 end = rin + rle;
9148 if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
9149 j = 1;
9150 } else if (end < INT_MAX) {
9151 j = (int)end;
9152 }
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009153 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009154
9155 if (i < j) {
9156 xmlChar *ret = xmlUTF8Strsub(str->stringval, i - 1, j - i);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009157 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009158 xmlFree(ret);
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009159 } else {
9160 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00009161 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009162
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009163 xmlXPathReleaseObject(ctxt->context, str);
Owen Taylor3473f882001-02-23 17:55:21 +00009164}
9165
9166/**
9167 * xmlXPathSubstringBeforeFunction:
9168 * @ctxt: the XPath Parser context
9169 * @nargs: the number of arguments
9170 *
9171 * Implement the substring-before() XPath function
9172 * string substring-before(string, string)
9173 * The substring-before function returns the substring of the first
9174 * argument string that precedes the first occurrence of the second
9175 * argument string in the first argument string, or the empty string
9176 * if the first argument string does not contain the second argument
9177 * string. For example, substring-before("1999/04/01","/") returns 1999.
9178 */
9179void
9180xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9181 xmlXPathObjectPtr str;
9182 xmlXPathObjectPtr find;
Daniel Veillardade10f22012-07-12 09:43:27 +08009183 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009184 const xmlChar *point;
9185 int offset;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009186
Owen Taylor3473f882001-02-23 17:55:21 +00009187 CHECK_ARITY(2);
9188 CAST_TO_STRING;
9189 find = valuePop(ctxt);
9190 CAST_TO_STRING;
9191 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009192
Daniel Veillardade10f22012-07-12 09:43:27 +08009193 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009194 if (target) {
9195 point = xmlStrstr(str->stringval, find->stringval);
9196 if (point) {
9197 offset = (int)(point - str->stringval);
Daniel Veillardade10f22012-07-12 09:43:27 +08009198 xmlBufAdd(target, str->stringval, offset);
Owen Taylor3473f882001-02-23 17:55:21 +00009199 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009200 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009201 xmlBufContent(target)));
9202 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009203 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009204 xmlXPathReleaseObject(ctxt->context, str);
9205 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009206}
9207
9208/**
9209 * xmlXPathSubstringAfterFunction:
9210 * @ctxt: the XPath Parser context
9211 * @nargs: the number of arguments
9212 *
9213 * Implement the substring-after() XPath function
9214 * string substring-after(string, string)
9215 * The substring-after function returns the substring of the first
9216 * argument string that follows the first occurrence of the second
9217 * argument string in the first argument string, or the empty stringi
9218 * if the first argument string does not contain the second argument
9219 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9220 * and substring-after("1999/04/01","19") returns 99/04/01.
9221 */
9222void
9223xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9224 xmlXPathObjectPtr str;
9225 xmlXPathObjectPtr find;
Daniel Veillardade10f22012-07-12 09:43:27 +08009226 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009227 const xmlChar *point;
9228 int offset;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009229
Owen Taylor3473f882001-02-23 17:55:21 +00009230 CHECK_ARITY(2);
9231 CAST_TO_STRING;
9232 find = valuePop(ctxt);
9233 CAST_TO_STRING;
9234 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009235
Daniel Veillardade10f22012-07-12 09:43:27 +08009236 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009237 if (target) {
9238 point = xmlStrstr(str->stringval, find->stringval);
9239 if (point) {
9240 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
Daniel Veillardade10f22012-07-12 09:43:27 +08009241 xmlBufAdd(target, &str->stringval[offset],
Owen Taylor3473f882001-02-23 17:55:21 +00009242 xmlStrlen(str->stringval) - offset);
9243 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009244 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009245 xmlBufContent(target)));
9246 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009247 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009248 xmlXPathReleaseObject(ctxt->context, str);
9249 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009250}
9251
9252/**
9253 * xmlXPathNormalizeFunction:
9254 * @ctxt: the XPath Parser context
9255 * @nargs: the number of arguments
9256 *
9257 * Implement the normalize-space() XPath function
9258 * string normalize-space(string?)
9259 * The normalize-space function returns the argument string with white
9260 * space normalized by stripping leading and trailing whitespace
9261 * and replacing sequences of whitespace characters by a single
9262 * space. Whitespace characters are the same allowed by the S production
9263 * in XML. If the argument is omitted, it defaults to the context
9264 * node converted to a string, in other words the value of the context node.
9265 */
9266void
9267xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9268 xmlXPathObjectPtr obj = NULL;
9269 xmlChar *source = NULL;
Daniel Veillardade10f22012-07-12 09:43:27 +08009270 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009271 xmlChar blank;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009272
Daniel Veillarda82b1822004-11-08 16:24:57 +00009273 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009274 if (nargs == 0) {
9275 /* Use current context node */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009276 valuePush(ctxt,
9277 xmlXPathCacheWrapString(ctxt->context,
9278 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00009279 nargs = 1;
9280 }
9281
9282 CHECK_ARITY(1);
9283 CAST_TO_STRING;
9284 CHECK_TYPE(XPATH_STRING);
9285 obj = valuePop(ctxt);
9286 source = obj->stringval;
9287
Daniel Veillardade10f22012-07-12 09:43:27 +08009288 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009289 if (target && source) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00009290
Owen Taylor3473f882001-02-23 17:55:21 +00009291 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00009292 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00009293 source++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009294
Owen Taylor3473f882001-02-23 17:55:21 +00009295 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9296 blank = 0;
9297 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00009298 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009299 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00009300 } else {
9301 if (blank) {
Daniel Veillardade10f22012-07-12 09:43:27 +08009302 xmlBufAdd(target, &blank, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00009303 blank = 0;
9304 }
Daniel Veillardade10f22012-07-12 09:43:27 +08009305 xmlBufAdd(target, source, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00009306 }
9307 source++;
9308 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009309 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009310 xmlBufContent(target)));
9311 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009312 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009313 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00009314}
9315
9316/**
9317 * xmlXPathTranslateFunction:
9318 * @ctxt: the XPath Parser context
9319 * @nargs: the number of arguments
9320 *
9321 * Implement the translate() XPath function
9322 * string translate(string, string, string)
9323 * The translate function returns the first argument string with
9324 * occurrences of characters in the second argument string replaced
9325 * by the character at the corresponding position in the third argument
9326 * string. For example, translate("bar","abc","ABC") returns the string
9327 * BAr. If there is a character in the second argument string with no
9328 * character at a corresponding position in the third argument string
9329 * (because the second argument string is longer than the third argument
9330 * string), then occurrences of that character in the first argument
9331 * string are removed. For example, translate("--aaa--","abc-","ABC")
9332 * returns "AAA". If a character occurs more than once in second
9333 * argument string, then the first occurrence determines the replacement
9334 * character. If the third argument string is longer than the second
9335 * argument string, then excess characters are ignored.
9336 */
9337void
9338xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00009339 xmlXPathObjectPtr str;
9340 xmlXPathObjectPtr from;
9341 xmlXPathObjectPtr to;
Daniel Veillardade10f22012-07-12 09:43:27 +08009342 xmlBufPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009343 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009344 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00009345 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009346 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00009347
Daniel Veillarde043ee12001-04-16 14:08:07 +00009348 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00009349
Daniel Veillarde043ee12001-04-16 14:08:07 +00009350 CAST_TO_STRING;
9351 to = valuePop(ctxt);
9352 CAST_TO_STRING;
9353 from = valuePop(ctxt);
9354 CAST_TO_STRING;
9355 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009356
Daniel Veillardade10f22012-07-12 09:43:27 +08009357 target = xmlBufCreate();
Daniel Veillarde043ee12001-04-16 14:08:07 +00009358 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009359 max = xmlUTF8Strlen(to->stringval);
9360 for (cptr = str->stringval; (ch=*cptr); ) {
9361 offset = xmlUTF8Strloc(from->stringval, cptr);
9362 if (offset >= 0) {
9363 if (offset < max) {
9364 point = xmlUTF8Strpos(to->stringval, offset);
9365 if (point)
Daniel Veillardade10f22012-07-12 09:43:27 +08009366 xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
Daniel Veillard97ac1312001-05-30 19:14:17 +00009367 }
9368 } else
Daniel Veillardade10f22012-07-12 09:43:27 +08009369 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
Daniel Veillard97ac1312001-05-30 19:14:17 +00009370
9371 /* Step to next character in input */
9372 cptr++;
9373 if ( ch & 0x80 ) {
9374 /* if not simple ascii, verify proper format */
9375 if ( (ch & 0xc0) != 0xc0 ) {
9376 xmlGenericError(xmlGenericErrorContext,
9377 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08009378 /* not asserting an XPath error is probably better */
Daniel Veillard97ac1312001-05-30 19:14:17 +00009379 break;
9380 }
9381 /* then skip over remaining bytes for this char */
9382 while ( (ch <<= 1) & 0x80 )
9383 if ( (*cptr++ & 0xc0) != 0x80 ) {
9384 xmlGenericError(xmlGenericErrorContext,
9385 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08009386 /* not asserting an XPath error is probably better */
Daniel Veillard97ac1312001-05-30 19:14:17 +00009387 break;
9388 }
9389 if (ch & 0x80) /* must have had error encountered */
9390 break;
9391 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00009392 }
Owen Taylor3473f882001-02-23 17:55:21 +00009393 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009394 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009395 xmlBufContent(target)));
9396 xmlBufFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009397 xmlXPathReleaseObject(ctxt->context, str);
9398 xmlXPathReleaseObject(ctxt->context, from);
9399 xmlXPathReleaseObject(ctxt->context, to);
Owen Taylor3473f882001-02-23 17:55:21 +00009400}
9401
9402/**
9403 * xmlXPathBooleanFunction:
9404 * @ctxt: the XPath Parser context
9405 * @nargs: the number of arguments
9406 *
9407 * Implement the boolean() XPath function
9408 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00009409 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00009410 * - a number is true if and only if it is neither positive or
9411 * negative zero nor NaN
9412 * - a node-set is true if and only if it is non-empty
9413 * - a string is true if and only if its length is non-zero
9414 */
9415void
9416xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9417 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00009418
9419 CHECK_ARITY(1);
9420 cur = valuePop(ctxt);
9421 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009422 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009423 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009424}
9425
9426/**
9427 * xmlXPathNotFunction:
9428 * @ctxt: the XPath Parser context
9429 * @nargs: the number of arguments
9430 *
9431 * Implement the not() XPath function
9432 * boolean not(boolean)
9433 * The not function returns true if its argument is false,
9434 * and false otherwise.
9435 */
9436void
9437xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9438 CHECK_ARITY(1);
9439 CAST_TO_BOOLEAN;
9440 CHECK_TYPE(XPATH_BOOLEAN);
9441 ctxt->value->boolval = ! ctxt->value->boolval;
9442}
9443
9444/**
9445 * xmlXPathTrueFunction:
9446 * @ctxt: the XPath Parser context
9447 * @nargs: the number of arguments
9448 *
9449 * Implement the true() XPath function
9450 * boolean true()
9451 */
9452void
9453xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9454 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009455 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009456}
9457
9458/**
9459 * xmlXPathFalseFunction:
9460 * @ctxt: the XPath Parser context
9461 * @nargs: the number of arguments
9462 *
9463 * Implement the false() XPath function
9464 * boolean false()
9465 */
9466void
9467xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9468 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009469 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009470}
9471
9472/**
9473 * xmlXPathLangFunction:
9474 * @ctxt: the XPath Parser context
9475 * @nargs: the number of arguments
9476 *
9477 * Implement the lang() XPath function
9478 * boolean lang(string)
9479 * The lang function returns true or false depending on whether the
9480 * language of the context node as specified by xml:lang attributes
9481 * is the same as or is a sublanguage of the language specified by
9482 * the argument string. The language of the context node is determined
9483 * by the value of the xml:lang attribute on the context node, or, if
9484 * the context node has no xml:lang attribute, by the value of the
9485 * xml:lang attribute on the nearest ancestor of the context node that
9486 * has an xml:lang attribute. If there is no such attribute, then lang
9487 * returns false. If there is such an attribute, then lang returns
9488 * true if the attribute value is equal to the argument ignoring case,
9489 * or if there is some suffix starting with - such that the attribute
9490 * value is equal to the argument ignoring that suffix of the attribute
9491 * value and ignoring case.
9492 */
9493void
9494xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009495 xmlXPathObjectPtr val = NULL;
9496 const xmlChar *theLang = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009497 const xmlChar *lang;
9498 int ret = 0;
9499 int i;
9500
9501 CHECK_ARITY(1);
9502 CAST_TO_STRING;
9503 CHECK_TYPE(XPATH_STRING);
9504 val = valuePop(ctxt);
9505 lang = val->stringval;
9506 theLang = xmlNodeGetLang(ctxt->context->node);
9507 if ((theLang != NULL) && (lang != NULL)) {
9508 for (i = 0;lang[i] != 0;i++)
9509 if (toupper(lang[i]) != toupper(theLang[i]))
9510 goto not_equal;
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009511 if ((theLang[i] == 0) || (theLang[i] == '-'))
9512 ret = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009513 }
9514not_equal:
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009515 if (theLang != NULL)
9516 xmlFree((void *)theLang);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009517
9518 xmlXPathReleaseObject(ctxt->context, val);
9519 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009520}
9521
9522/**
9523 * xmlXPathNumberFunction:
9524 * @ctxt: the XPath Parser context
9525 * @nargs: the number of arguments
9526 *
9527 * Implement the number() XPath function
9528 * number number(object?)
9529 */
9530void
9531xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9532 xmlXPathObjectPtr cur;
9533 double res;
9534
Daniel Veillarda82b1822004-11-08 16:24:57 +00009535 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009536 if (nargs == 0) {
9537 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009538 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
Owen Taylor3473f882001-02-23 17:55:21 +00009539 } else {
9540 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9541
9542 res = xmlXPathStringEvalNumber(content);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009543 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
Owen Taylor3473f882001-02-23 17:55:21 +00009544 xmlFree(content);
9545 }
9546 return;
9547 }
9548
9549 CHECK_ARITY(1);
9550 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009551 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00009552}
9553
9554/**
9555 * xmlXPathSumFunction:
9556 * @ctxt: the XPath Parser context
9557 * @nargs: the number of arguments
9558 *
9559 * Implement the sum() XPath function
9560 * number sum(node-set)
9561 * The sum function returns the sum of the values of the nodes in
9562 * the argument node-set.
9563 */
9564void
9565xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9566 xmlXPathObjectPtr cur;
9567 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009568 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00009569
9570 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009571 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009572 ((ctxt->value->type != XPATH_NODESET) &&
9573 (ctxt->value->type != XPATH_XSLT_TREE)))
9574 XP_ERROR(XPATH_INVALID_TYPE);
9575 cur = valuePop(ctxt);
9576
William M. Brack08171912003-12-29 02:52:11 +00009577 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009578 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9579 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00009580 }
9581 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009582 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9583 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009584}
9585
9586/**
9587 * xmlXPathFloorFunction:
9588 * @ctxt: the XPath Parser context
9589 * @nargs: the number of arguments
9590 *
9591 * Implement the floor() XPath function
9592 * number floor(number)
9593 * The floor function returns the largest (closest to positive infinity)
9594 * number that is not greater than the argument and that is an integer.
9595 */
9596void
9597xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9598 CHECK_ARITY(1);
9599 CAST_TO_NUMBER;
9600 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009601
Nick Wellnhofer4bebb032016-04-21 13:41:09 +02009602 ctxt->value->floatval = floor(ctxt->value->floatval);
Owen Taylor3473f882001-02-23 17:55:21 +00009603}
9604
9605/**
9606 * xmlXPathCeilingFunction:
9607 * @ctxt: the XPath Parser context
9608 * @nargs: the number of arguments
9609 *
9610 * Implement the ceiling() XPath function
9611 * number ceiling(number)
9612 * The ceiling function returns the smallest (closest to negative infinity)
9613 * number that is not less than the argument and that is an integer.
9614 */
9615void
9616xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Owen Taylor3473f882001-02-23 17:55:21 +00009617 CHECK_ARITY(1);
9618 CAST_TO_NUMBER;
9619 CHECK_TYPE(XPATH_NUMBER);
9620
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009621#ifdef _AIX
9622 /* Work around buggy ceil() function on AIX */
9623 ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
9624#else
Owen Taylor3473f882001-02-23 17:55:21 +00009625 ctxt->value->floatval = ceil(ctxt->value->floatval);
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009626#endif
Owen Taylor3473f882001-02-23 17:55:21 +00009627}
9628
9629/**
9630 * xmlXPathRoundFunction:
9631 * @ctxt: the XPath Parser context
9632 * @nargs: the number of arguments
9633 *
9634 * Implement the round() XPath function
9635 * number round(number)
9636 * The round function returns the number that is closest to the
9637 * argument and that is an integer. If there are two such numbers,
Nick Wellnhofer4bebb032016-04-21 13:41:09 +02009638 * then the one that is closest to positive infinity is returned.
Owen Taylor3473f882001-02-23 17:55:21 +00009639 */
9640void
9641xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9642 double f;
9643
9644 CHECK_ARITY(1);
9645 CAST_TO_NUMBER;
9646 CHECK_TYPE(XPATH_NUMBER);
9647
Nick Wellnhofer4bebb032016-04-21 13:41:09 +02009648 f = ctxt->value->floatval;
9649
Nick Wellnhofer8813f392017-09-21 00:11:26 +02009650 if ((f >= -0.5) && (f < 0.5)) {
9651 /* Handles negative zero. */
9652 ctxt->value->floatval *= 0.0;
Nick Wellnhofer4bebb032016-04-21 13:41:09 +02009653 }
9654 else {
9655 double rounded = floor(f);
9656 if (f - rounded >= 0.5)
9657 rounded += 1.0;
9658 ctxt->value->floatval = rounded;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009659 }
Owen Taylor3473f882001-02-23 17:55:21 +00009660}
9661
9662/************************************************************************
9663 * *
9664 * The Parser *
9665 * *
9666 ************************************************************************/
9667
9668/*
William M. Brack08171912003-12-29 02:52:11 +00009669 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00009670 * implementation.
9671 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009672static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009673static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009674static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009675static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00009676static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9677 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00009678
9679/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00009680 * xmlXPathCurrentChar:
9681 * @ctxt: the XPath parser context
9682 * @cur: pointer to the beginning of the char
9683 * @len: pointer to the length of the char read
9684 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009685 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00009686 * bytes in the input buffer.
9687 *
Daniel Veillard60087f32001-10-10 09:45:09 +00009688 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00009689 */
9690
9691static int
9692xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9693 unsigned char c;
9694 unsigned int val;
9695 const xmlChar *cur;
9696
9697 if (ctxt == NULL)
9698 return(0);
9699 cur = ctxt->cur;
9700
9701 /*
9702 * We are supposed to handle UTF8, check it's valid
9703 * From rfc2044: encoding of the Unicode values on UTF-8:
9704 *
9705 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9706 * 0000 0000-0000 007F 0xxxxxxx
9707 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
Daniel Veillard45490ae2008-07-29 09:13:19 +00009708 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
Daniel Veillard61d80a22001-04-27 17:13:01 +00009709 *
9710 * Check for the 0x110000 limit too
9711 */
9712 c = *cur;
9713 if (c & 0x80) {
9714 if ((cur[1] & 0xc0) != 0x80)
9715 goto encoding_error;
9716 if ((c & 0xe0) == 0xe0) {
9717
9718 if ((cur[2] & 0xc0) != 0x80)
9719 goto encoding_error;
9720 if ((c & 0xf0) == 0xf0) {
9721 if (((c & 0xf8) != 0xf0) ||
9722 ((cur[3] & 0xc0) != 0x80))
9723 goto encoding_error;
9724 /* 4-byte code */
9725 *len = 4;
9726 val = (cur[0] & 0x7) << 18;
9727 val |= (cur[1] & 0x3f) << 12;
9728 val |= (cur[2] & 0x3f) << 6;
9729 val |= cur[3] & 0x3f;
9730 } else {
9731 /* 3-byte code */
9732 *len = 3;
9733 val = (cur[0] & 0xf) << 12;
9734 val |= (cur[1] & 0x3f) << 6;
9735 val |= cur[2] & 0x3f;
9736 }
9737 } else {
9738 /* 2-byte code */
9739 *len = 2;
9740 val = (cur[0] & 0x1f) << 6;
9741 val |= cur[1] & 0x3f;
9742 }
9743 if (!IS_CHAR(val)) {
9744 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009745 }
Daniel Veillard61d80a22001-04-27 17:13:01 +00009746 return(val);
9747 } else {
9748 /* 1-byte code */
9749 *len = 1;
9750 return((int) *cur);
9751 }
9752encoding_error:
9753 /*
William M. Brack08171912003-12-29 02:52:11 +00009754 * If we detect an UTF8 error that probably means that the
9755 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00009756 * declaration header. Report the error and switch the encoding
9757 * to ISO-Latin-1 (if you don't like this policy, just declare the
9758 * encoding !)
9759 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00009760 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00009761 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009762}
9763
9764/**
Owen Taylor3473f882001-02-23 17:55:21 +00009765 * xmlXPathParseNCName:
9766 * @ctxt: the XPath Parser context
9767 *
9768 * parse an XML namespace non qualified name.
9769 *
9770 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9771 *
9772 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9773 * CombiningChar | Extender
9774 *
9775 * Returns the namespace name or NULL
9776 */
9777
9778xmlChar *
9779xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00009780 const xmlChar *in;
9781 xmlChar *ret;
9782 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009783
Daniel Veillarda82b1822004-11-08 16:24:57 +00009784 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00009785 /*
9786 * Accelerator for simple ASCII names
9787 */
9788 in = ctxt->cur;
9789 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9790 ((*in >= 0x41) && (*in <= 0x5A)) ||
9791 (*in == '_')) {
9792 in++;
9793 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9794 ((*in >= 0x41) && (*in <= 0x5A)) ||
9795 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00009796 (*in == '_') || (*in == '.') ||
9797 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00009798 in++;
9799 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9800 (*in == '[') || (*in == ']') || (*in == ':') ||
9801 (*in == '@') || (*in == '*')) {
9802 count = in - ctxt->cur;
9803 if (count == 0)
9804 return(NULL);
9805 ret = xmlStrndup(ctxt->cur, count);
9806 ctxt->cur = in;
9807 return(ret);
9808 }
9809 }
9810 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009811}
9812
Daniel Veillard2156a562001-04-28 12:24:34 +00009813
Owen Taylor3473f882001-02-23 17:55:21 +00009814/**
9815 * xmlXPathParseQName:
9816 * @ctxt: the XPath Parser context
Daniel Veillard45490ae2008-07-29 09:13:19 +00009817 * @prefix: a xmlChar **
Owen Taylor3473f882001-02-23 17:55:21 +00009818 *
9819 * parse an XML qualified name
9820 *
9821 * [NS 5] QName ::= (Prefix ':')? LocalPart
9822 *
9823 * [NS 6] Prefix ::= NCName
9824 *
9825 * [NS 7] LocalPart ::= NCName
9826 *
9827 * Returns the function returns the local part, and prefix is updated
9828 * to get the Prefix if any.
9829 */
9830
Daniel Veillard56a4cb82001-03-24 17:00:36 +00009831static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00009832xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9833 xmlChar *ret = NULL;
9834
9835 *prefix = NULL;
9836 ret = xmlXPathParseNCName(ctxt);
Daniel Veillard074f37e2008-09-01 13:38:22 +00009837 if (ret && CUR == ':') {
Owen Taylor3473f882001-02-23 17:55:21 +00009838 *prefix = ret;
9839 NEXT;
9840 ret = xmlXPathParseNCName(ctxt);
9841 }
9842 return(ret);
9843}
9844
9845/**
9846 * xmlXPathParseName:
9847 * @ctxt: the XPath Parser context
9848 *
9849 * parse an XML name
9850 *
9851 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9852 * CombiningChar | Extender
9853 *
9854 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9855 *
9856 * Returns the namespace name or NULL
9857 */
9858
9859xmlChar *
9860xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009861 const xmlChar *in;
9862 xmlChar *ret;
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009863 size_t count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009864
Daniel Veillarda82b1822004-11-08 16:24:57 +00009865 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009866 /*
9867 * Accelerator for simple ASCII names
9868 */
9869 in = ctxt->cur;
9870 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9871 ((*in >= 0x41) && (*in <= 0x5A)) ||
9872 (*in == '_') || (*in == ':')) {
9873 in++;
9874 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9875 ((*in >= 0x41) && (*in <= 0x5A)) ||
9876 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00009877 (*in == '_') || (*in == '-') ||
9878 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00009879 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00009880 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009881 count = in - ctxt->cur;
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009882 if (count > XML_MAX_NAME_LENGTH) {
9883 ctxt->cur = in;
9884 XP_ERRORNULL(XPATH_EXPR_ERROR);
9885 }
Daniel Veillard61d80a22001-04-27 17:13:01 +00009886 ret = xmlStrndup(ctxt->cur, count);
9887 ctxt->cur = in;
9888 return(ret);
9889 }
9890 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009891 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009892}
9893
Daniel Veillard61d80a22001-04-27 17:13:01 +00009894static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00009895xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009896 xmlChar buf[XML_MAX_NAMELEN + 5];
9897 int len = 0, l;
9898 int c;
9899
9900 /*
9901 * Handler for more complex cases
9902 */
9903 c = CUR_CHAR(l);
9904 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00009905 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9906 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00009907 (!IS_LETTER(c) && (c != '_') &&
Nick Wellnhofere2893902016-04-21 19:19:23 +02009908 ((!qualified) || (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009909 return(NULL);
9910 }
9911
9912 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9913 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9914 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00009915 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009916 (IS_COMBINING(c)) ||
9917 (IS_EXTENDER(c)))) {
9918 COPY_BUF(l,buf,len,c);
9919 NEXTL(l);
9920 c = CUR_CHAR(l);
9921 if (len >= XML_MAX_NAMELEN) {
9922 /*
9923 * Okay someone managed to make a huge name, so he's ready to pay
9924 * for the processing speed.
9925 */
9926 xmlChar *buffer;
9927 int max = len * 2;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009928
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009929 if (len > XML_MAX_NAME_LENGTH) {
9930 XP_ERRORNULL(XPATH_EXPR_ERROR);
9931 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00009932 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009933 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009934 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009935 }
9936 memcpy(buffer, buf, len);
9937 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9938 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00009939 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009940 (IS_COMBINING(c)) ||
9941 (IS_EXTENDER(c))) {
9942 if (len + 10 > max) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009943 xmlChar *tmp;
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009944 if (max > XML_MAX_NAME_LENGTH) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009945 xmlFree(buffer);
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009946 XP_ERRORNULL(XPATH_EXPR_ERROR);
9947 }
Daniel Veillard61d80a22001-04-27 17:13:01 +00009948 max *= 2;
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009949 tmp = (xmlChar *) xmlRealloc(buffer,
9950 max * sizeof(xmlChar));
9951 if (tmp == NULL) {
9952 xmlFree(buffer);
Daniel Veillard24505b02005-07-28 23:49:35 +00009953 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009954 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009955 buffer = tmp;
Daniel Veillard61d80a22001-04-27 17:13:01 +00009956 }
9957 COPY_BUF(l,buffer,len,c);
9958 NEXTL(l);
9959 c = CUR_CHAR(l);
9960 }
9961 buffer[len] = 0;
9962 return(buffer);
9963 }
9964 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009965 if (len == 0)
9966 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009967 return(xmlStrndup(buf, len));
9968}
Daniel Veillard3cd72402002-05-13 10:33:30 +00009969
9970#define MAX_FRAC 20
9971
Owen Taylor3473f882001-02-23 17:55:21 +00009972/**
9973 * xmlXPathStringEvalNumber:
9974 * @str: A string to scan
9975 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00009976 * [30a] Float ::= Number ('e' Digits?)?
9977 *
Owen Taylor3473f882001-02-23 17:55:21 +00009978 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard45490ae2008-07-29 09:13:19 +00009979 * | '.' Digits
Owen Taylor3473f882001-02-23 17:55:21 +00009980 * [31] Digits ::= [0-9]+
9981 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009982 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00009983 * In complement of the Number expression, this function also handles
9984 * negative values : '-' Number.
9985 *
9986 * Returns the double value.
9987 */
9988double
9989xmlXPathStringEvalNumber(const xmlChar *str) {
9990 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00009991 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009992 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009993 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009994 int exponent = 0;
9995 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009996#ifdef __GNUC__
9997 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00009998 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009999#endif
Daniel Veillardeca82812002-04-24 11:42:02 +000010000 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +000010001 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010002 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
Nick Wellnhofer8813f392017-09-21 00:11:26 +020010003 return(NAN);
Owen Taylor3473f882001-02-23 17:55:21 +000010004 }
10005 if (*cur == '-') {
10006 isneg = 1;
10007 cur++;
10008 }
Daniel Veillardb06c6142001-08-27 14:26:30 +000010009
10010#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010011 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010012 * tmp/temp is a workaround against a gcc compiler bug
10013 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010014 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010015 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010016 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010017 ret = ret * 10;
10018 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +000010019 ok = 1;
10020 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +000010021 temp = (double) tmp;
10022 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010023 }
Daniel Veillardb06c6142001-08-27 14:26:30 +000010024#else
Daniel Veillard7b416132002-03-07 08:36:03 +000010025 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010026 while ((*cur >= '0') && (*cur <= '9')) {
10027 ret = ret * 10 + (*cur - '0');
10028 ok = 1;
10029 cur++;
10030 }
10031#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010032
Owen Taylor3473f882001-02-23 17:55:21 +000010033 if (*cur == '.') {
Nick Wellnhofera8518682017-05-29 20:14:42 +020010034 int v, frac = 0, max;
Daniel Veillard3cd72402002-05-13 10:33:30 +000010035 double fraction = 0;
10036
Owen Taylor3473f882001-02-23 17:55:21 +000010037 cur++;
10038 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
Nick Wellnhofer8813f392017-09-21 00:11:26 +020010039 return(NAN);
Owen Taylor3473f882001-02-23 17:55:21 +000010040 }
Nick Wellnhofera8518682017-05-29 20:14:42 +020010041 while (*cur == '0') {
10042 frac = frac + 1;
10043 cur++;
10044 }
10045 max = frac + MAX_FRAC;
10046 while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
Daniel Veillard3cd72402002-05-13 10:33:30 +000010047 v = (*cur - '0');
10048 fraction = fraction * 10 + v;
10049 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010050 cur++;
10051 }
Nick Wellnhofera8518682017-05-29 20:14:42 +020010052 fraction /= pow(10.0, frac);
Daniel Veillard3cd72402002-05-13 10:33:30 +000010053 ret = ret + fraction;
10054 while ((*cur >= '0') && (*cur <= '9'))
10055 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010056 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010057 if ((*cur == 'e') || (*cur == 'E')) {
10058 cur++;
10059 if (*cur == '-') {
10060 is_exponent_negative = 1;
10061 cur++;
William M. Brack99127052004-05-24 02:52:28 +000010062 } else if (*cur == '+') {
10063 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010064 }
10065 while ((*cur >= '0') && (*cur <= '9')) {
Nick Wellnhoferf4029cd2016-04-21 16:37:26 +020010066 if (exponent < 1000000)
10067 exponent = exponent * 10 + (*cur - '0');
Bjorn Reese70a9da52001-04-21 16:57:29 +000010068 cur++;
10069 }
10070 }
William M. Brack76e95df2003-10-18 16:20:14 +000010071 while (IS_BLANK_CH(*cur)) cur++;
Nick Wellnhofer8813f392017-09-21 00:11:26 +020010072 if (*cur != 0) return(NAN);
Owen Taylor3473f882001-02-23 17:55:21 +000010073 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010074 if (is_exponent_negative) exponent = -exponent;
10075 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +000010076 return(ret);
10077}
10078
10079/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010080 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +000010081 * @ctxt: the XPath Parser context
10082 *
10083 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard45490ae2008-07-29 09:13:19 +000010084 * | '.' Digits
Owen Taylor3473f882001-02-23 17:55:21 +000010085 * [31] Digits ::= [0-9]+
10086 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010087 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +000010088 *
10089 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010090static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010091xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10092{
Owen Taylor3473f882001-02-23 17:55:21 +000010093 double ret = 0.0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010094 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010095 int exponent = 0;
10096 int is_exponent_negative = 0;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070010097 xmlXPathObjectPtr num;
Daniel Veillard7b416132002-03-07 08:36:03 +000010098#ifdef __GNUC__
10099 unsigned long tmp = 0;
10100 double temp;
10101#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010102
10103 CHECK_ERROR;
10104 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10105 XP_ERROR(XPATH_NUMBER_ERROR);
10106 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010107#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010108 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010109 * tmp/temp is a workaround against a gcc compiler bug
10110 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010111 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010112 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010113 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010114 ret = ret * 10;
10115 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010116 ok = 1;
10117 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +000010118 temp = (double) tmp;
10119 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010120 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010121#else
10122 ret = 0;
10123 while ((CUR >= '0') && (CUR <= '9')) {
10124 ret = ret * 10 + (CUR - '0');
10125 ok = 1;
10126 NEXT;
10127 }
10128#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010129 if (CUR == '.') {
Nick Wellnhofera8518682017-05-29 20:14:42 +020010130 int v, frac = 0, max;
Phil Shaferee32ad32010-11-03 20:53:55 +010010131 double fraction = 0;
10132
Owen Taylor3473f882001-02-23 17:55:21 +000010133 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010134 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10135 XP_ERROR(XPATH_NUMBER_ERROR);
10136 }
Nick Wellnhofera8518682017-05-29 20:14:42 +020010137 while (CUR == '0') {
10138 frac = frac + 1;
10139 NEXT;
10140 }
10141 max = frac + MAX_FRAC;
10142 while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
Phil Shaferee32ad32010-11-03 20:53:55 +010010143 v = (CUR - '0');
10144 fraction = fraction * 10 + v;
10145 frac = frac + 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010146 NEXT;
10147 }
Nick Wellnhofera8518682017-05-29 20:14:42 +020010148 fraction /= pow(10.0, frac);
Phil Shaferee32ad32010-11-03 20:53:55 +010010149 ret = ret + fraction;
10150 while ((CUR >= '0') && (CUR <= '9'))
10151 NEXT;
Owen Taylor3473f882001-02-23 17:55:21 +000010152 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010153 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010154 NEXT;
10155 if (CUR == '-') {
10156 is_exponent_negative = 1;
10157 NEXT;
William M. Brack99127052004-05-24 02:52:28 +000010158 } else if (CUR == '+') {
10159 NEXT;
10160 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010161 while ((CUR >= '0') && (CUR <= '9')) {
Nick Wellnhoferf4029cd2016-04-21 16:37:26 +020010162 if (exponent < 1000000)
10163 exponent = exponent * 10 + (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010164 NEXT;
10165 }
10166 if (is_exponent_negative)
10167 exponent = -exponent;
10168 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +000010169 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070010170 num = xmlXPathCacheNewFloat(ctxt->context, ret);
10171 if (num == NULL) {
10172 ctxt->error = XPATH_MEMORY_ERROR;
10173 } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
10174 NULL) == -1) {
10175 xmlXPathReleaseObject(ctxt->context, num);
10176 }
Owen Taylor3473f882001-02-23 17:55:21 +000010177}
10178
10179/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010180 * xmlXPathParseLiteral:
10181 * @ctxt: the XPath Parser context
10182 *
10183 * Parse a Literal
10184 *
10185 * [29] Literal ::= '"' [^"]* '"'
10186 * | "'" [^']* "'"
10187 *
10188 * Returns the value found or NULL in case of error
10189 */
10190static xmlChar *
10191xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10192 const xmlChar *q;
10193 xmlChar *ret = NULL;
10194
10195 if (CUR == '"') {
10196 NEXT;
10197 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010198 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010199 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010200 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010201 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010202 } else {
10203 ret = xmlStrndup(q, CUR_PTR - q);
10204 NEXT;
10205 }
10206 } else if (CUR == '\'') {
10207 NEXT;
10208 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010209 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010210 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010211 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010212 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010213 } else {
10214 ret = xmlStrndup(q, CUR_PTR - q);
10215 NEXT;
10216 }
10217 } else {
Daniel Veillard24505b02005-07-28 23:49:35 +000010218 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010219 }
10220 return(ret);
10221}
10222
10223/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010224 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +000010225 * @ctxt: the XPath Parser context
10226 *
10227 * Parse a Literal and push it on the stack.
10228 *
10229 * [29] Literal ::= '"' [^"]* '"'
10230 * | "'" [^']* "'"
10231 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010232 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +000010233 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010234static void
10235xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010236 const xmlChar *q;
10237 xmlChar *ret = NULL;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070010238 xmlXPathObjectPtr lit;
Owen Taylor3473f882001-02-23 17:55:21 +000010239
10240 if (CUR == '"') {
10241 NEXT;
10242 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010243 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +000010244 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010245 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010246 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10247 } else {
10248 ret = xmlStrndup(q, CUR_PTR - q);
10249 NEXT;
10250 }
10251 } else if (CUR == '\'') {
10252 NEXT;
10253 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010254 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +000010255 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010256 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010257 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10258 } else {
10259 ret = xmlStrndup(q, CUR_PTR - q);
10260 NEXT;
10261 }
10262 } else {
10263 XP_ERROR(XPATH_START_LITERAL_ERROR);
10264 }
10265 if (ret == NULL) return;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070010266 lit = xmlXPathCacheNewString(ctxt->context, ret);
10267 if (lit == NULL) {
10268 ctxt->error = XPATH_MEMORY_ERROR;
10269 } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
10270 NULL) == -1) {
10271 xmlXPathReleaseObject(ctxt->context, lit);
10272 }
Owen Taylor3473f882001-02-23 17:55:21 +000010273 xmlFree(ret);
10274}
10275
10276/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010277 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +000010278 * @ctxt: the XPath Parser context
10279 *
10280 * Parse a VariableReference, evaluate it and push it on the stack.
10281 *
10282 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +000010283 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +000010284 * of any of the types that are possible for the value of an expression,
10285 * and may also be of additional types not specified here.
10286 *
10287 * Early evaluation is possible since:
10288 * The variable bindings [...] used to evaluate a subexpression are
Daniel Veillard45490ae2008-07-29 09:13:19 +000010289 * always the same as those used to evaluate the containing expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010290 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010291 * [36] VariableReference ::= '$' QName
Owen Taylor3473f882001-02-23 17:55:21 +000010292 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010293static void
10294xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010295 xmlChar *name;
10296 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010297
10298 SKIP_BLANKS;
10299 if (CUR != '$') {
10300 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10301 }
10302 NEXT;
10303 name = xmlXPathParseQName(ctxt, &prefix);
10304 if (name == NULL) {
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020010305 xmlFree(prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010306 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10307 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010308 ctxt->comp->last = -1;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070010309 if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
10310 xmlFree(prefix);
10311 xmlFree(name);
10312 }
Owen Taylor3473f882001-02-23 17:55:21 +000010313 SKIP_BLANKS;
Daniel Veillardb3d14912005-09-04 20:47:39 +000010314 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
Daniel Veillard47881282012-09-07 14:24:50 +080010315 XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
Daniel Veillardb3d14912005-09-04 20:47:39 +000010316 }
Owen Taylor3473f882001-02-23 17:55:21 +000010317}
10318
10319/**
10320 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +000010321 * @name: a name string
10322 *
10323 * Is the name given a NodeType one.
10324 *
10325 * [38] NodeType ::= 'comment'
10326 * | 'text'
10327 * | 'processing-instruction'
10328 * | 'node'
10329 *
10330 * Returns 1 if true 0 otherwise
10331 */
10332int
10333xmlXPathIsNodeType(const xmlChar *name) {
10334 if (name == NULL)
10335 return(0);
10336
Daniel Veillard1971ee22002-01-31 20:29:19 +000010337 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +000010338 return(1);
10339 if (xmlStrEqual(name, BAD_CAST "text"))
10340 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010341 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +000010342 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010343 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +000010344 return(1);
10345 return(0);
10346}
10347
10348/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010349 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +000010350 * @ctxt: the XPath Parser context
10351 *
10352 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010353 * [17] Argument ::= Expr
Owen Taylor3473f882001-02-23 17:55:21 +000010354 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010355 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +000010356 * pushed on the stack
10357 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010358static void
10359xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010360 xmlChar *name;
10361 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010362 int nbargs = 0;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010363 int sort = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010364
10365 name = xmlXPathParseQName(ctxt, &prefix);
10366 if (name == NULL) {
Daniel Veillard074f37e2008-09-01 13:38:22 +000010367 xmlFree(prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010368 XP_ERROR(XPATH_EXPR_ERROR);
10369 }
10370 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010371#ifdef DEBUG_EXPR
10372 if (prefix == NULL)
10373 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10374 name);
10375 else
10376 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10377 prefix, name);
10378#endif
10379
Owen Taylor3473f882001-02-23 17:55:21 +000010380 if (CUR != '(') {
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020010381 xmlFree(name);
10382 xmlFree(prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010383 XP_ERROR(XPATH_EXPR_ERROR);
10384 }
10385 NEXT;
10386 SKIP_BLANKS;
10387
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010388 /*
10389 * Optimization for count(): we don't need the node-set to be sorted.
10390 */
10391 if ((prefix == NULL) && (name[0] == 'c') &&
10392 xmlStrEqual(name, BAD_CAST "count"))
10393 {
10394 sort = 0;
10395 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010396 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +000010397 if (CUR != ')') {
10398 while (CUR != 0) {
10399 int op1 = ctxt->comp->last;
10400 ctxt->comp->last = -1;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010401 xmlXPathCompileExpr(ctxt, sort);
Daniel Veillard074f37e2008-09-01 13:38:22 +000010402 if (ctxt->error != XPATH_EXPRESSION_OK) {
10403 xmlFree(name);
10404 xmlFree(prefix);
10405 return;
10406 }
Daniel Veillard71f9d732003-01-14 16:07:16 +000010407 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10408 nbargs++;
10409 if (CUR == ')') break;
10410 if (CUR != ',') {
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020010411 xmlFree(name);
10412 xmlFree(prefix);
Daniel Veillard71f9d732003-01-14 16:07:16 +000010413 XP_ERROR(XPATH_EXPR_ERROR);
10414 }
10415 NEXT;
10416 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010417 }
Owen Taylor3473f882001-02-23 17:55:21 +000010418 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070010419 if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
10420 xmlFree(prefix);
10421 xmlFree(name);
10422 }
Owen Taylor3473f882001-02-23 17:55:21 +000010423 NEXT;
10424 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010425}
10426
10427/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010428 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010429 * @ctxt: the XPath Parser context
10430 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010431 * [15] PrimaryExpr ::= VariableReference
Owen Taylor3473f882001-02-23 17:55:21 +000010432 * | '(' Expr ')'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010433 * | Literal
10434 * | Number
10435 * | FunctionCall
Owen Taylor3473f882001-02-23 17:55:21 +000010436 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010437 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010438 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010439static void
10440xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010441 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010442 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010443 else if (CUR == '(') {
10444 NEXT;
10445 SKIP_BLANKS;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010446 xmlXPathCompileExpr(ctxt, 1);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010447 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000010448 if (CUR != ')') {
10449 XP_ERROR(XPATH_EXPR_ERROR);
10450 }
10451 NEXT;
10452 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010453 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010454 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010455 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010456 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010457 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010458 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010459 }
10460 SKIP_BLANKS;
10461}
10462
10463/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010464 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010465 * @ctxt: the XPath Parser context
10466 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010467 * [20] FilterExpr ::= PrimaryExpr
10468 * | FilterExpr Predicate
Owen Taylor3473f882001-02-23 17:55:21 +000010469 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010470 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010471 * Square brackets are used to filter expressions in the same way that
10472 * they are used in location paths. It is an error if the expression to
10473 * be filtered does not evaluate to a node-set. The context node list
10474 * used for evaluating the expression in square brackets is the node-set
10475 * to be filtered listed in document order.
10476 */
10477
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010478static void
10479xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10480 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010481 CHECK_ERROR;
10482 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010483
Owen Taylor3473f882001-02-23 17:55:21 +000010484 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010485 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +000010486 SKIP_BLANKS;
10487 }
10488
Daniel Veillard45490ae2008-07-29 09:13:19 +000010489
Owen Taylor3473f882001-02-23 17:55:21 +000010490}
10491
10492/**
10493 * xmlXPathScanName:
10494 * @ctxt: the XPath Parser context
10495 *
10496 * Trickery: parse an XML name but without consuming the input flow
10497 * Needed to avoid insanity in the parser state.
10498 *
10499 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10500 * CombiningChar | Extender
10501 *
10502 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10503 *
10504 * [6] Names ::= Name (S Name)*
10505 *
10506 * Returns the Name parsed or NULL
10507 */
10508
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010509static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +000010510xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +000010511 int len = 0, l;
10512 int c;
Daniel Veillard03226812004-11-01 14:55:21 +000010513 const xmlChar *cur;
10514 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +000010515
Daniel Veillard03226812004-11-01 14:55:21 +000010516 cur = ctxt->cur;
10517
10518 c = CUR_CHAR(l);
10519 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10520 (!IS_LETTER(c) && (c != '_') &&
10521 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010522 return(NULL);
10523 }
10524
Daniel Veillard03226812004-11-01 14:55:21 +000010525 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10526 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10527 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000010528 (c == '_') || (c == ':') ||
Daniel Veillard03226812004-11-01 14:55:21 +000010529 (IS_COMBINING(c)) ||
10530 (IS_EXTENDER(c)))) {
10531 len += l;
10532 NEXTL(l);
10533 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +000010534 }
Daniel Veillard03226812004-11-01 14:55:21 +000010535 ret = xmlStrndup(cur, ctxt->cur - cur);
10536 ctxt->cur = cur;
10537 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +000010538}
10539
10540/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010541 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010542 * @ctxt: the XPath Parser context
10543 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010544 * [19] PathExpr ::= LocationPath
10545 * | FilterExpr
10546 * | FilterExpr '/' RelativeLocationPath
10547 * | FilterExpr '//' RelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000010548 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010549 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010550 * The / operator and // operators combine an arbitrary expression
10551 * and a relative location path. It is an error if the expression
10552 * does not evaluate to a node-set.
10553 * The / operator does composition in the same way as when / is
10554 * used in a location path. As in location paths, // is short for
10555 * /descendant-or-self::node()/.
10556 */
10557
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010558static void
10559xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010560 int lc = 1; /* Should we branch to LocationPath ? */
10561 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10562
10563 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010564 if ((CUR == '$') || (CUR == '(') ||
10565 (IS_ASCII_DIGIT(CUR)) ||
William M. Brackd1757ab2004-10-02 22:07:48 +000010566 (CUR == '\'') || (CUR == '"') ||
10567 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010568 lc = 0;
10569 } else if (CUR == '*') {
10570 /* relative or absolute location path */
10571 lc = 1;
10572 } else if (CUR == '/') {
10573 /* relative or absolute location path */
10574 lc = 1;
10575 } else if (CUR == '@') {
10576 /* relative abbreviated attribute location path */
10577 lc = 1;
10578 } else if (CUR == '.') {
10579 /* relative abbreviated attribute location path */
10580 lc = 1;
10581 } else {
10582 /*
10583 * Problem is finding if we have a name here whether it's:
10584 * - a nodetype
10585 * - a function call in which case it's followed by '('
10586 * - an axis in which case it's followed by ':'
10587 * - a element name
10588 * We do an a priori analysis here rather than having to
10589 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +000010590 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +000010591 * read/write/debug.
10592 */
10593 SKIP_BLANKS;
10594 name = xmlXPathScanName(ctxt);
10595 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10596#ifdef DEBUG_STEP
10597 xmlGenericError(xmlGenericErrorContext,
10598 "PathExpr: Axis\n");
10599#endif
10600 lc = 1;
10601 xmlFree(name);
10602 } else if (name != NULL) {
10603 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +000010604
Daniel Veillard45490ae2008-07-29 09:13:19 +000010605
Owen Taylor3473f882001-02-23 17:55:21 +000010606 while (NXT(len) != 0) {
10607 if (NXT(len) == '/') {
10608 /* element name */
10609#ifdef DEBUG_STEP
10610 xmlGenericError(xmlGenericErrorContext,
10611 "PathExpr: AbbrRelLocation\n");
10612#endif
10613 lc = 1;
10614 break;
William M. Brack76e95df2003-10-18 16:20:14 +000010615 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +000010616 /* ignore blanks */
10617 ;
Owen Taylor3473f882001-02-23 17:55:21 +000010618 } else if (NXT(len) == ':') {
10619#ifdef DEBUG_STEP
10620 xmlGenericError(xmlGenericErrorContext,
10621 "PathExpr: AbbrRelLocation\n");
10622#endif
10623 lc = 1;
10624 break;
10625 } else if ((NXT(len) == '(')) {
Brian C. Young01c35762017-04-03 12:46:02 -070010626 /* Node Type or Function */
Owen Taylor3473f882001-02-23 17:55:21 +000010627 if (xmlXPathIsNodeType(name)) {
10628#ifdef DEBUG_STEP
10629 xmlGenericError(xmlGenericErrorContext,
10630 "PathExpr: Type search\n");
10631#endif
10632 lc = 1;
Brian C. Young01c35762017-04-03 12:46:02 -070010633#ifdef LIBXML_XPTR_ENABLED
10634 } else if (ctxt->xptr &&
10635 xmlStrEqual(name, BAD_CAST "range-to")) {
10636 lc = 1;
10637#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010638 } else {
10639#ifdef DEBUG_STEP
10640 xmlGenericError(xmlGenericErrorContext,
10641 "PathExpr: function call\n");
10642#endif
10643 lc = 0;
10644 }
10645 break;
10646 } else if ((NXT(len) == '[')) {
10647 /* element name */
10648#ifdef DEBUG_STEP
10649 xmlGenericError(xmlGenericErrorContext,
10650 "PathExpr: AbbrRelLocation\n");
10651#endif
10652 lc = 1;
10653 break;
10654 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10655 (NXT(len) == '=')) {
10656 lc = 1;
10657 break;
10658 } else {
10659 lc = 1;
10660 break;
10661 }
10662 len++;
10663 }
10664 if (NXT(len) == 0) {
10665#ifdef DEBUG_STEP
10666 xmlGenericError(xmlGenericErrorContext,
10667 "PathExpr: AbbrRelLocation\n");
10668#endif
10669 /* element name */
10670 lc = 1;
10671 }
10672 xmlFree(name);
10673 } else {
William M. Brack08171912003-12-29 02:52:11 +000010674 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +000010675 XP_ERROR(XPATH_EXPR_ERROR);
10676 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000010677 }
Owen Taylor3473f882001-02-23 17:55:21 +000010678
10679 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010680 if (CUR == '/') {
10681 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10682 } else {
10683 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010684 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010685 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010686 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010687 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010688 CHECK_ERROR;
10689 if ((CUR == '/') && (NXT(1) == '/')) {
10690 SKIP(2);
10691 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010692
10693 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10694 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010695
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010696 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010697 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010698 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010699 }
10700 }
10701 SKIP_BLANKS;
10702}
10703
10704/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010705 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010706 * @ctxt: the XPath Parser context
10707 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010708 * [18] UnionExpr ::= PathExpr
10709 * | UnionExpr '|' PathExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010710 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010711 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010712 */
10713
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010714static void
10715xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10716 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010717 CHECK_ERROR;
10718 SKIP_BLANKS;
10719 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010720 int op1 = ctxt->comp->last;
10721 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010722
10723 NEXT;
10724 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010725 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010726
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010727 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10728
Owen Taylor3473f882001-02-23 17:55:21 +000010729 SKIP_BLANKS;
10730 }
Owen Taylor3473f882001-02-23 17:55:21 +000010731}
10732
10733/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010734 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010735 * @ctxt: the XPath Parser context
10736 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010737 * [27] UnaryExpr ::= UnionExpr
10738 * | '-' UnaryExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010739 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010740 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010741 */
10742
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010743static void
10744xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010745 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010746 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010747
10748 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +000010749 while (CUR == '-') {
10750 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010751 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010752 NEXT;
10753 SKIP_BLANKS;
10754 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010755
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010756 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010757 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010758 if (found) {
10759 if (minus)
10760 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10761 else
10762 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010763 }
10764}
10765
10766/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010767 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010768 * @ctxt: the XPath Parser context
10769 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010770 * [26] MultiplicativeExpr ::= UnaryExpr
10771 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10772 * | MultiplicativeExpr 'div' UnaryExpr
10773 * | MultiplicativeExpr 'mod' UnaryExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010774 * [34] MultiplyOperator ::= '*'
10775 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010776 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010777 */
10778
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010779static void
10780xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10781 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010782 CHECK_ERROR;
10783 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010784 while ((CUR == '*') ||
Owen Taylor3473f882001-02-23 17:55:21 +000010785 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10786 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10787 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010788 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010789
10790 if (CUR == '*') {
10791 op = 0;
10792 NEXT;
10793 } else if (CUR == 'd') {
10794 op = 1;
10795 SKIP(3);
10796 } else if (CUR == 'm') {
10797 op = 2;
10798 SKIP(3);
10799 }
10800 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010801 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010802 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010803 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010804 SKIP_BLANKS;
10805 }
10806}
10807
10808/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010809 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010810 * @ctxt: the XPath Parser context
10811 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010812 * [25] AdditiveExpr ::= MultiplicativeExpr
10813 * | AdditiveExpr '+' MultiplicativeExpr
10814 * | AdditiveExpr '-' MultiplicativeExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010815 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010816 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010817 */
10818
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010819static void
10820xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010821
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010822 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010823 CHECK_ERROR;
10824 SKIP_BLANKS;
10825 while ((CUR == '+') || (CUR == '-')) {
10826 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010827 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010828
10829 if (CUR == '+') plus = 1;
10830 else plus = 0;
10831 NEXT;
10832 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010833 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010834 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010835 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010836 SKIP_BLANKS;
10837 }
10838}
10839
10840/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010841 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010842 * @ctxt: the XPath Parser context
10843 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010844 * [24] RelationalExpr ::= AdditiveExpr
10845 * | RelationalExpr '<' AdditiveExpr
10846 * | RelationalExpr '>' AdditiveExpr
10847 * | RelationalExpr '<=' AdditiveExpr
10848 * | RelationalExpr '>=' AdditiveExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010849 *
10850 * A <= B > C is allowed ? Answer from James, yes with
10851 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10852 * which is basically what got implemented.
10853 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010854 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +000010855 * on the stack
10856 */
10857
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010858static void
10859xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10860 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010861 CHECK_ERROR;
10862 SKIP_BLANKS;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070010863 while ((CUR == '<') || (CUR == '>')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010864 int inf, strict;
10865 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010866
10867 if (CUR == '<') inf = 1;
10868 else inf = 0;
10869 if (NXT(1) == '=') strict = 0;
10870 else strict = 1;
10871 NEXT;
10872 if (!strict) NEXT;
10873 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010874 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010875 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010876 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +000010877 SKIP_BLANKS;
10878 }
10879}
10880
10881/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010882 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010883 * @ctxt: the XPath Parser context
10884 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010885 * [23] EqualityExpr ::= RelationalExpr
10886 * | EqualityExpr '=' RelationalExpr
10887 * | EqualityExpr '!=' RelationalExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010888 *
10889 * A != B != C is allowed ? Answer from James, yes with
10890 * (RelationalExpr = RelationalExpr) = RelationalExpr
10891 * (RelationalExpr != RelationalExpr) != RelationalExpr
10892 * which is basically what got implemented.
10893 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010894 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010895 *
10896 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010897static void
10898xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10899 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010900 CHECK_ERROR;
10901 SKIP_BLANKS;
10902 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010903 int eq;
10904 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010905
10906 if (CUR == '=') eq = 1;
10907 else eq = 0;
10908 NEXT;
10909 if (!eq) NEXT;
10910 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010911 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010912 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010913 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010914 SKIP_BLANKS;
10915 }
10916}
10917
10918/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010919 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010920 * @ctxt: the XPath Parser context
10921 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010922 * [22] AndExpr ::= EqualityExpr
10923 * | AndExpr 'and' EqualityExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010924 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010925 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010926 *
10927 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010928static void
10929xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10930 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010931 CHECK_ERROR;
10932 SKIP_BLANKS;
10933 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010934 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010935 SKIP(3);
10936 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010937 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010938 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010939 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010940 SKIP_BLANKS;
10941 }
10942}
10943
10944/**
Daniel Veillard591b4be2003-02-09 23:33:36 +000010945 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010946 * @ctxt: the XPath Parser context
10947 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010948 * [14] Expr ::= OrExpr
10949 * [21] OrExpr ::= AndExpr
10950 * | OrExpr 'or' AndExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010951 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010952 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +000010953 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010954static void
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010955xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -070010956 xmlXPathContextPtr xpctxt = ctxt->context;
10957
10958 if (xpctxt != NULL) {
Haibo Huangf0a546b2020-09-01 20:28:19 -070010959 if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
Haibo Huangcfd91dc2020-07-30 23:01:33 -070010960 XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
Haibo Huangf0a546b2020-09-01 20:28:19 -070010961 /*
10962 * Parsing a single '(' pushes about 10 functions on the call stack
10963 * before recursing!
10964 */
10965 xpctxt->depth += 10;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070010966 }
10967
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010968 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010969 CHECK_ERROR;
10970 SKIP_BLANKS;
10971 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010972 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010973 SKIP(2);
10974 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010975 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010976 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010977 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010978 SKIP_BLANKS;
10979 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010980 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010981 /* more ops could be optimized too */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010982 /*
10983 * This is the main place to eliminate sorting for
10984 * operations which don't require a sorted node-set.
10985 * E.g. count().
10986 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010987 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10988 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070010989
10990 if (xpctxt != NULL)
10991 xpctxt->depth -= 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010992}
10993
10994/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010995 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +000010996 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010997 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +000010998 *
10999 * [8] Predicate ::= '[' PredicateExpr ']'
Daniel Veillard45490ae2008-07-29 09:13:19 +000011000 * [9] PredicateExpr ::= Expr
Owen Taylor3473f882001-02-23 17:55:21 +000011001 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011002 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +000011003 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011004static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011005xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011006 int op1 = ctxt->comp->last;
11007
11008 SKIP_BLANKS;
11009 if (CUR != '[') {
11010 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11011 }
11012 NEXT;
11013 SKIP_BLANKS;
11014
11015 ctxt->comp->last = -1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011016 /*
11017 * This call to xmlXPathCompileExpr() will deactivate sorting
11018 * of the predicate result.
11019 * TODO: Sorting is still activated for filters, since I'm not
11020 * sure if needed. Normally sorting should not be needed, since
11021 * a filter can only diminish the number of items in a sequence,
11022 * but won't change its order; so if the initial sequence is sorted,
11023 * subsequent sorting is not needed.
11024 */
11025 if (! filter)
11026 xmlXPathCompileExpr(ctxt, 0);
11027 else
11028 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011029 CHECK_ERROR;
11030
11031 if (CUR != ']') {
11032 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11033 }
11034
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011035 if (filter)
11036 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11037 else
11038 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011039
11040 NEXT;
11041 SKIP_BLANKS;
11042}
11043
11044/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011045 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +000011046 * @ctxt: the XPath Parser context
11047 * @test: pointer to a xmlXPathTestVal
11048 * @type: pointer to a xmlXPathTypeVal
11049 * @prefix: placeholder for a possible name prefix
11050 *
11051 * [7] NodeTest ::= NameTest
11052 * | NodeType '(' ')'
11053 * | 'processing-instruction' '(' Literal ')'
11054 *
11055 * [37] NameTest ::= '*'
11056 * | NCName ':' '*'
11057 * | QName
11058 * [38] NodeType ::= 'comment'
11059 * | 'text'
11060 * | 'processing-instruction'
11061 * | 'node'
11062 *
William M. Brack08171912003-12-29 02:52:11 +000011063 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +000011064 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011065static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011066xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
Haibo Huangcfd91dc2020-07-30 23:01:33 -070011067 xmlXPathTypeVal *type, xmlChar **prefix,
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011068 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +000011069 int blanks;
11070
11071 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11072 STRANGE;
11073 return(NULL);
11074 }
William M. Brack78637da2003-07-31 14:47:38 +000011075 *type = (xmlXPathTypeVal) 0;
11076 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011077 *prefix = NULL;
11078 SKIP_BLANKS;
11079
11080 if ((name == NULL) && (CUR == '*')) {
11081 /*
11082 * All elements
11083 */
11084 NEXT;
11085 *test = NODE_TEST_ALL;
11086 return(NULL);
11087 }
11088
11089 if (name == NULL)
11090 name = xmlXPathParseNCName(ctxt);
11091 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011092 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011093 }
11094
William M. Brack76e95df2003-10-18 16:20:14 +000011095 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +000011096 SKIP_BLANKS;
11097 if (CUR == '(') {
11098 NEXT;
11099 /*
11100 * NodeType or PI search
11101 */
11102 if (xmlStrEqual(name, BAD_CAST "comment"))
11103 *type = NODE_TYPE_COMMENT;
11104 else if (xmlStrEqual(name, BAD_CAST "node"))
11105 *type = NODE_TYPE_NODE;
11106 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11107 *type = NODE_TYPE_PI;
11108 else if (xmlStrEqual(name, BAD_CAST "text"))
11109 *type = NODE_TYPE_TEXT;
11110 else {
11111 if (name != NULL)
11112 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000011113 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011114 }
11115
11116 *test = NODE_TEST_TYPE;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011117
Owen Taylor3473f882001-02-23 17:55:21 +000011118 SKIP_BLANKS;
11119 if (*type == NODE_TYPE_PI) {
11120 /*
11121 * Specific case: search a PI by name.
11122 */
Owen Taylor3473f882001-02-23 17:55:21 +000011123 if (name != NULL)
11124 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +000011125 name = NULL;
11126 if (CUR != ')') {
11127 name = xmlXPathParseLiteral(ctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000011128 CHECK_ERROR NULL;
Daniel Veillarded23b7d2002-05-27 12:16:02 +000011129 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +000011130 SKIP_BLANKS;
11131 }
Owen Taylor3473f882001-02-23 17:55:21 +000011132 }
11133 if (CUR != ')') {
11134 if (name != NULL)
11135 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000011136 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011137 }
11138 NEXT;
11139 return(name);
11140 }
11141 *test = NODE_TEST_NAME;
11142 if ((!blanks) && (CUR == ':')) {
11143 NEXT;
11144
11145 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011146 * Since currently the parser context don't have a
11147 * namespace list associated:
11148 * The namespace name for this prefix can be computed
11149 * only at evaluation time. The compilation is done
11150 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +000011151 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011152#if 0
Owen Taylor3473f882001-02-23 17:55:21 +000011153 *prefix = xmlXPathNsLookup(ctxt->context, name);
11154 if (name != NULL)
11155 xmlFree(name);
11156 if (*prefix == NULL) {
11157 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11158 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011159#else
11160 *prefix = name;
11161#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011162
11163 if (CUR == '*') {
11164 /*
11165 * All elements
11166 */
11167 NEXT;
11168 *test = NODE_TEST_ALL;
11169 return(NULL);
11170 }
11171
11172 name = xmlXPathParseNCName(ctxt);
11173 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011174 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011175 }
11176 }
11177 return(name);
11178}
11179
11180/**
11181 * xmlXPathIsAxisName:
11182 * @name: a preparsed name token
11183 *
11184 * [6] AxisName ::= 'ancestor'
11185 * | 'ancestor-or-self'
11186 * | 'attribute'
11187 * | 'child'
11188 * | 'descendant'
11189 * | 'descendant-or-self'
11190 * | 'following'
11191 * | 'following-sibling'
11192 * | 'namespace'
11193 * | 'parent'
11194 * | 'preceding'
11195 * | 'preceding-sibling'
11196 * | 'self'
11197 *
11198 * Returns the axis or 0
11199 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011200static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +000011201xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +000011202 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011203 switch (name[0]) {
11204 case 'a':
11205 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11206 ret = AXIS_ANCESTOR;
11207 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11208 ret = AXIS_ANCESTOR_OR_SELF;
11209 if (xmlStrEqual(name, BAD_CAST "attribute"))
11210 ret = AXIS_ATTRIBUTE;
11211 break;
11212 case 'c':
11213 if (xmlStrEqual(name, BAD_CAST "child"))
11214 ret = AXIS_CHILD;
11215 break;
11216 case 'd':
11217 if (xmlStrEqual(name, BAD_CAST "descendant"))
11218 ret = AXIS_DESCENDANT;
11219 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11220 ret = AXIS_DESCENDANT_OR_SELF;
11221 break;
11222 case 'f':
11223 if (xmlStrEqual(name, BAD_CAST "following"))
11224 ret = AXIS_FOLLOWING;
11225 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11226 ret = AXIS_FOLLOWING_SIBLING;
11227 break;
11228 case 'n':
11229 if (xmlStrEqual(name, BAD_CAST "namespace"))
11230 ret = AXIS_NAMESPACE;
11231 break;
11232 case 'p':
11233 if (xmlStrEqual(name, BAD_CAST "parent"))
11234 ret = AXIS_PARENT;
11235 if (xmlStrEqual(name, BAD_CAST "preceding"))
11236 ret = AXIS_PRECEDING;
11237 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11238 ret = AXIS_PRECEDING_SIBLING;
11239 break;
11240 case 's':
11241 if (xmlStrEqual(name, BAD_CAST "self"))
11242 ret = AXIS_SELF;
11243 break;
11244 }
11245 return(ret);
11246}
11247
11248/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011249 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +000011250 * @ctxt: the XPath Parser context
11251 *
11252 * [4] Step ::= AxisSpecifier NodeTest Predicate*
Daniel Veillard45490ae2008-07-29 09:13:19 +000011253 * | AbbreviatedStep
Owen Taylor3473f882001-02-23 17:55:21 +000011254 *
11255 * [12] AbbreviatedStep ::= '.' | '..'
11256 *
11257 * [5] AxisSpecifier ::= AxisName '::'
11258 * | AbbreviatedAxisSpecifier
11259 *
11260 * [13] AbbreviatedAxisSpecifier ::= '@'?
11261 *
11262 * Modified for XPtr range support as:
11263 *
11264 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11265 * | AbbreviatedStep
11266 * | 'range-to' '(' Expr ')' Predicate*
11267 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011268 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +000011269 * A location step of . is short for self::node(). This is
11270 * particularly useful in conjunction with //. For example, the
11271 * location path .//para is short for
11272 * self::node()/descendant-or-self::node()/child::para
11273 * and so will select all para descendant elements of the context
11274 * node.
11275 * Similarly, a location step of .. is short for parent::node().
11276 * For example, ../title is short for parent::node()/child::title
11277 * and so will select the title children of the parent of the context
11278 * node.
11279 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011280static void
11281xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011282#ifdef LIBXML_XPTR_ENABLED
11283 int rangeto = 0;
11284 int op2 = -1;
11285#endif
11286
Owen Taylor3473f882001-02-23 17:55:21 +000011287 SKIP_BLANKS;
11288 if ((CUR == '.') && (NXT(1) == '.')) {
11289 SKIP(2);
11290 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011291 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11292 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011293 } else if (CUR == '.') {
11294 NEXT;
11295 SKIP_BLANKS;
11296 } else {
11297 xmlChar *name = NULL;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070011298 xmlChar *prefix = NULL;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011299 xmlXPathTestVal test = (xmlXPathTestVal) 0;
William M. Brack78637da2003-07-31 14:47:38 +000011300 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011301 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011302 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +000011303
11304 /*
11305 * The modification needed for XPointer change to the production
11306 */
11307#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011308 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +000011309 name = xmlXPathParseNCName(ctxt);
11310 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011311 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000011312 xmlFree(name);
11313 SKIP_BLANKS;
11314 if (CUR != '(') {
11315 XP_ERROR(XPATH_EXPR_ERROR);
11316 }
11317 NEXT;
11318 SKIP_BLANKS;
11319
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011320 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011321 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +000011322 CHECK_ERROR;
11323
11324 SKIP_BLANKS;
11325 if (CUR != ')') {
11326 XP_ERROR(XPATH_EXPR_ERROR);
11327 }
11328 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011329 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000011330 goto eval_predicates;
11331 }
11332 }
11333#endif
Daniel Veillard2156a562001-04-28 12:24:34 +000011334 if (CUR == '*') {
11335 axis = AXIS_CHILD;
11336 } else {
11337 if (name == NULL)
11338 name = xmlXPathParseNCName(ctxt);
11339 if (name != NULL) {
11340 axis = xmlXPathIsAxisName(name);
11341 if (axis != 0) {
11342 SKIP_BLANKS;
11343 if ((CUR == ':') && (NXT(1) == ':')) {
11344 SKIP(2);
11345 xmlFree(name);
11346 name = NULL;
11347 } else {
11348 /* an element name can conflict with an axis one :-\ */
11349 axis = AXIS_CHILD;
11350 }
Owen Taylor3473f882001-02-23 17:55:21 +000011351 } else {
Owen Taylor3473f882001-02-23 17:55:21 +000011352 axis = AXIS_CHILD;
11353 }
Daniel Veillard2156a562001-04-28 12:24:34 +000011354 } else if (CUR == '@') {
11355 NEXT;
11356 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +000011357 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +000011358 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +000011359 }
Owen Taylor3473f882001-02-23 17:55:21 +000011360 }
11361
Daniel Veillard2f3523f2010-10-15 18:30:29 +020011362 if (ctxt->error != XPATH_EXPRESSION_OK) {
11363 xmlFree(name);
11364 return;
11365 }
Owen Taylor3473f882001-02-23 17:55:21 +000011366
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011367 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +000011368 if (test == 0)
11369 return;
11370
Daniel Veillarded6c5492005-07-23 15:00:22 +000011371 if ((prefix != NULL) && (ctxt->context != NULL) &&
11372 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11373 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11374 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11375 }
11376 }
Owen Taylor3473f882001-02-23 17:55:21 +000011377#ifdef DEBUG_STEP
11378 xmlGenericError(xmlGenericErrorContext,
11379 "Basis : computing new set\n");
11380#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011381
Owen Taylor3473f882001-02-23 17:55:21 +000011382#ifdef DEBUG_STEP
11383 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011384 if (ctxt->value == NULL)
11385 xmlGenericError(xmlGenericErrorContext, "no value\n");
11386 else if (ctxt->value->nodesetval == NULL)
11387 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11388 else
11389 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011390#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011391
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011392#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +000011393eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011394#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011395 op1 = ctxt->comp->last;
11396 ctxt->comp->last = -1;
11397
Owen Taylor3473f882001-02-23 17:55:21 +000011398 SKIP_BLANKS;
11399 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011400 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011401 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011402
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011403#ifdef LIBXML_XPTR_ENABLED
11404 if (rangeto) {
11405 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11406 } else
11407#endif
Haibo Huangcfd91dc2020-07-30 23:01:33 -070011408 if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11409 test, type, (void *)prefix, (void *)name) == -1) {
11410 xmlFree(prefix);
11411 xmlFree(name);
11412 }
Owen Taylor3473f882001-02-23 17:55:21 +000011413 }
11414#ifdef DEBUG_STEP
11415 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011416 if (ctxt->value == NULL)
11417 xmlGenericError(xmlGenericErrorContext, "no value\n");
11418 else if (ctxt->value->nodesetval == NULL)
11419 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11420 else
11421 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11422 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011423#endif
11424}
11425
11426/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011427 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011428 * @ctxt: the XPath Parser context
11429 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011430 * [3] RelativeLocationPath ::= Step
11431 * | RelativeLocationPath '/' Step
11432 * | AbbreviatedRelativeLocationPath
11433 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
Owen Taylor3473f882001-02-23 17:55:21 +000011434 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011435 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +000011436 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011437static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011438xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011439(xmlXPathParserContextPtr ctxt) {
11440 SKIP_BLANKS;
11441 if ((CUR == '/') && (NXT(1) == '/')) {
11442 SKIP(2);
11443 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011444 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11445 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011446 } else if (CUR == '/') {
11447 NEXT;
11448 SKIP_BLANKS;
11449 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011450 xmlXPathCompStep(ctxt);
Martin729601f2009-10-12 22:42:26 +020011451 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000011452 SKIP_BLANKS;
11453 while (CUR == '/') {
11454 if ((CUR == '/') && (NXT(1) == '/')) {
11455 SKIP(2);
11456 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011457 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +000011458 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011459 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011460 } else if (CUR == '/') {
11461 NEXT;
11462 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011463 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011464 }
11465 SKIP_BLANKS;
11466 }
11467}
11468
11469/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011470 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011471 * @ctxt: the XPath Parser context
11472 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011473 * [1] LocationPath ::= RelativeLocationPath
11474 * | AbsoluteLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011475 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
Daniel Veillard45490ae2008-07-29 09:13:19 +000011476 * | AbbreviatedAbsoluteLocationPath
11477 * [10] AbbreviatedAbsoluteLocationPath ::=
11478 * '//' RelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011479 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011480 * Compile a location path
11481 *
Owen Taylor3473f882001-02-23 17:55:21 +000011482 * // is short for /descendant-or-self::node()/. For example,
11483 * //para is short for /descendant-or-self::node()/child::para and
11484 * so will select any para element in the document (even a para element
11485 * that is a document element will be selected by //para since the
11486 * document element node is a child of the root node); div//para is
11487 * short for div/descendant-or-self::node()/child::para and so will
11488 * select all para descendants of div children.
11489 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011490static void
11491xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000011492 SKIP_BLANKS;
11493 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011494 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011495 } else {
11496 while (CUR == '/') {
11497 if ((CUR == '/') && (NXT(1) == '/')) {
11498 SKIP(2);
11499 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011500 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11501 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011502 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011503 } else if (CUR == '/') {
11504 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +000011505 SKIP_BLANKS;
11506 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +000011507 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +000011508 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011509 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011510 }
Martin729601f2009-10-12 22:42:26 +020011511 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000011512 }
11513 }
11514}
11515
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011516/************************************************************************
11517 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011518 * XPath precompiled expression evaluation *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011519 * *
11520 ************************************************************************/
11521
Daniel Veillardf06307e2001-07-03 10:35:50 +000011522static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011523xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11524
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011525#ifdef DEBUG_STEP
11526static void
Daniel Veillard074f37e2008-09-01 13:38:22 +000011527xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011528 int nbNodes)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011529{
Daniel Veillardf06307e2001-07-03 10:35:50 +000011530 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillard074f37e2008-09-01 13:38:22 +000011531 switch (op->value) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011532 case AXIS_ANCESTOR:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011533 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011534 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011535 case AXIS_ANCESTOR_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011536 xmlGenericError(xmlGenericErrorContext,
11537 "axis 'ancestors-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011538 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011539 case AXIS_ATTRIBUTE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011540 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011541 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011542 case AXIS_CHILD:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011543 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011544 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011545 case AXIS_DESCENDANT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011546 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011547 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011548 case AXIS_DESCENDANT_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011549 xmlGenericError(xmlGenericErrorContext,
11550 "axis 'descendant-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011551 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011552 case AXIS_FOLLOWING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011553 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011554 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011555 case AXIS_FOLLOWING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011556 xmlGenericError(xmlGenericErrorContext,
11557 "axis 'following-siblings' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011558 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011559 case AXIS_NAMESPACE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011560 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011561 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011562 case AXIS_PARENT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011563 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011564 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011565 case AXIS_PRECEDING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011566 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011567 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011568 case AXIS_PRECEDING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011569 xmlGenericError(xmlGenericErrorContext,
11570 "axis 'preceding-sibling' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011571 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011572 case AXIS_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011573 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011574 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011575 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011576 xmlGenericError(xmlGenericErrorContext,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011577 " context contains %d nodes\n", nbNodes);
Daniel Veillard074f37e2008-09-01 13:38:22 +000011578 switch (op->value2) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011579 case NODE_TEST_NONE:
11580 xmlGenericError(xmlGenericErrorContext,
11581 " searching for none !!!\n");
11582 break;
11583 case NODE_TEST_TYPE:
11584 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011585 " searching for type %d\n", op->value3);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011586 break;
11587 case NODE_TEST_PI:
11588 xmlGenericError(xmlGenericErrorContext,
11589 " searching for PI !!!\n");
11590 break;
11591 case NODE_TEST_ALL:
11592 xmlGenericError(xmlGenericErrorContext,
11593 " searching for *\n");
11594 break;
11595 case NODE_TEST_NS:
11596 xmlGenericError(xmlGenericErrorContext,
11597 " searching for namespace %s\n",
Daniel Veillard074f37e2008-09-01 13:38:22 +000011598 op->value5);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011599 break;
11600 case NODE_TEST_NAME:
11601 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011602 " searching for name %s\n", op->value5);
11603 if (op->value4)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011604 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011605 " with namespace %s\n", op->value4);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011606 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011607 }
11608 xmlGenericError(xmlGenericErrorContext, "Testing : ");
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011609}
11610#endif /* DEBUG_STEP */
11611
Haibo Huangcfd91dc2020-07-30 23:01:33 -070011612/**
11613 * xmlXPathNodeSetFilter:
11614 * @ctxt: the XPath Parser context
11615 * @set: the node set to filter
11616 * @filterOpIndex: the index of the predicate/filter op
11617 * @minPos: minimum position in the filtered set (1-based)
11618 * @maxPos: maximum position in the filtered set (1-based)
11619 * @hasNsNodes: true if the node set may contain namespace nodes
11620 *
11621 * Filter a node set, keeping only nodes for which the predicate expression
11622 * matches. Afterwards, keep only nodes between minPos and maxPos in the
11623 * filtered result.
11624 */
11625static void
11626xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
11627 xmlNodeSetPtr set,
11628 int filterOpIndex,
11629 int minPos, int maxPos,
11630 int hasNsNodes)
11631{
11632 xmlXPathContextPtr xpctxt;
11633 xmlNodePtr oldnode;
11634 xmlDocPtr olddoc;
11635 xmlXPathStepOpPtr filterOp;
11636 int oldcs, oldpp;
11637 int i, j, pos;
11638
11639 if ((set == NULL) || (set->nodeNr == 0))
11640 return;
11641
11642 /*
11643 * Check if the node set contains a sufficient number of nodes for
11644 * the requested range.
11645 */
11646 if (set->nodeNr < minPos) {
11647 xmlXPathNodeSetClear(set, hasNsNodes);
11648 return;
11649 }
11650
11651 xpctxt = ctxt->context;
11652 oldnode = xpctxt->node;
11653 olddoc = xpctxt->doc;
11654 oldcs = xpctxt->contextSize;
11655 oldpp = xpctxt->proximityPosition;
11656 filterOp = &ctxt->comp->steps[filterOpIndex];
11657
11658 xpctxt->contextSize = set->nodeNr;
11659
11660 for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
11661 xmlNodePtr node = set->nodeTab[i];
11662 int res;
11663
11664 xpctxt->node = node;
11665 xpctxt->proximityPosition = i + 1;
11666
11667 /*
11668 * Also set the xpath document in case things like
11669 * key() are evaluated in the predicate.
11670 *
11671 * TODO: Get real doc for namespace nodes.
11672 */
11673 if ((node->type != XML_NAMESPACE_DECL) &&
11674 (node->doc != NULL))
11675 xpctxt->doc = node->doc;
11676
11677 res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11678
11679 if (ctxt->error != XPATH_EXPRESSION_OK)
11680 goto exit;
11681 if (res < 0) {
11682 /* Shouldn't happen */
11683 xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11684 goto exit;
11685 }
11686
11687 if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11688 if (i != j) {
11689 set->nodeTab[j] = node;
11690 set->nodeTab[i] = NULL;
11691 }
11692
11693 j += 1;
11694 } else {
11695 /* Remove the entry from the initial node set. */
11696 set->nodeTab[i] = NULL;
11697 if (node->type == XML_NAMESPACE_DECL)
11698 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11699 }
11700
11701 if (res != 0) {
11702 if (pos == maxPos) {
11703 /* Clear remaining nodes and exit loop. */
11704 if (hasNsNodes) {
11705 for (i++; i < set->nodeNr; i++) {
11706 node = set->nodeTab[i];
11707 if ((node != NULL) &&
11708 (node->type == XML_NAMESPACE_DECL))
11709 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11710 }
11711 }
11712 break;
11713 }
11714
11715 pos += 1;
11716 }
11717 }
11718
11719 set->nodeNr = j;
11720
11721 /* If too many elements were removed, shrink table to preserve memory. */
11722 if ((set->nodeMax > XML_NODESET_DEFAULT) &&
11723 (set->nodeNr < set->nodeMax / 2)) {
11724 xmlNodePtr *tmp;
11725 int nodeMax = set->nodeNr;
11726
11727 if (nodeMax < XML_NODESET_DEFAULT)
11728 nodeMax = XML_NODESET_DEFAULT;
11729 tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
11730 nodeMax * sizeof(xmlNodePtr));
11731 if (tmp == NULL) {
11732 xmlXPathPErrMemory(ctxt, "shrinking nodeset\n");
11733 } else {
11734 set->nodeTab = tmp;
11735 set->nodeMax = nodeMax;
11736 }
11737 }
11738
11739exit:
11740 xpctxt->node = oldnode;
11741 xpctxt->doc = olddoc;
11742 xpctxt->contextSize = oldcs;
11743 xpctxt->proximityPosition = oldpp;
11744}
11745
11746#ifdef LIBXML_XPTR_ENABLED
11747/**
11748 * xmlXPathLocationSetFilter:
11749 * @ctxt: the XPath Parser context
11750 * @locset: the location set to filter
11751 * @filterOpIndex: the index of the predicate/filter op
11752 * @minPos: minimum position in the filtered set (1-based)
11753 * @maxPos: maximum position in the filtered set (1-based)
11754 *
11755 * Filter a location set, keeping only nodes for which the predicate
11756 * expression matches. Afterwards, keep only nodes between minPos and maxPos
11757 * in the filtered result.
11758 */
11759static void
11760xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
11761 xmlLocationSetPtr locset,
11762 int filterOpIndex,
11763 int minPos, int maxPos)
11764{
11765 xmlXPathContextPtr xpctxt;
11766 xmlNodePtr oldnode;
11767 xmlDocPtr olddoc;
11768 xmlXPathStepOpPtr filterOp;
11769 int oldcs, oldpp;
11770 int i, j, pos;
11771
11772 if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1))
11773 return;
11774
11775 xpctxt = ctxt->context;
11776 oldnode = xpctxt->node;
11777 olddoc = xpctxt->doc;
11778 oldcs = xpctxt->contextSize;
11779 oldpp = xpctxt->proximityPosition;
11780 filterOp = &ctxt->comp->steps[filterOpIndex];
11781
11782 xpctxt->contextSize = locset->locNr;
11783
11784 for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) {
11785 xmlNodePtr contextNode = locset->locTab[i]->user;
11786 int res;
11787
11788 xpctxt->node = contextNode;
11789 xpctxt->proximityPosition = i + 1;
11790
11791 /*
11792 * Also set the xpath document in case things like
11793 * key() are evaluated in the predicate.
11794 *
11795 * TODO: Get real doc for namespace nodes.
11796 */
11797 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11798 (contextNode->doc != NULL))
11799 xpctxt->doc = contextNode->doc;
11800
11801 res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11802
11803 if (ctxt->error != XPATH_EXPRESSION_OK)
11804 goto exit;
11805 if (res < 0) {
11806 /* Shouldn't happen */
11807 xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11808 goto exit;
11809 }
11810
11811 if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11812 if (i != j) {
11813 locset->locTab[j] = locset->locTab[i];
11814 locset->locTab[i] = NULL;
11815 }
11816
11817 j += 1;
11818 } else {
11819 /* Remove the entry from the initial location set. */
11820 xmlXPathFreeObject(locset->locTab[i]);
11821 locset->locTab[i] = NULL;
11822 }
11823
11824 if (res != 0) {
11825 if (pos == maxPos) {
11826 /* Clear remaining nodes and exit loop. */
11827 for (i++; i < locset->locNr; i++) {
11828 xmlXPathFreeObject(locset->locTab[i]);
11829 }
11830 break;
11831 }
11832
11833 pos += 1;
11834 }
11835 }
11836
11837 locset->locNr = j;
11838
11839 /* If too many elements were removed, shrink table to preserve memory. */
11840 if ((locset->locMax > XML_NODESET_DEFAULT) &&
11841 (locset->locNr < locset->locMax / 2)) {
11842 xmlXPathObjectPtr *tmp;
11843 int locMax = locset->locNr;
11844
11845 if (locMax < XML_NODESET_DEFAULT)
11846 locMax = XML_NODESET_DEFAULT;
11847 tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,
11848 locMax * sizeof(xmlXPathObjectPtr));
11849 if (tmp == NULL) {
11850 xmlXPathPErrMemory(ctxt, "shrinking locset\n");
11851 } else {
11852 locset->locTab = tmp;
11853 locset->locMax = locMax;
11854 }
11855 }
11856
11857exit:
11858 xpctxt->node = oldnode;
11859 xpctxt->doc = olddoc;
11860 xpctxt->contextSize = oldcs;
11861 xpctxt->proximityPosition = oldpp;
11862}
11863#endif /* LIBXML_XPTR_ENABLED */
11864
11865/**
11866 * xmlXPathCompOpEvalPredicate:
11867 * @ctxt: the XPath Parser context
11868 * @op: the predicate op
11869 * @set: the node set to filter
11870 * @minPos: minimum position in the filtered set (1-based)
11871 * @maxPos: maximum position in the filtered set (1-based)
11872 * @hasNsNodes: true if the node set may contain namespace nodes
11873 *
11874 * Filter a node set, keeping only nodes for which the sequence of predicate
11875 * expressions matches. Afterwards, keep only nodes between minPos and maxPos
11876 * in the filtered result.
11877 */
11878static void
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011879xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11880 xmlXPathStepOpPtr op,
11881 xmlNodeSetPtr set,
Haibo Huangcfd91dc2020-07-30 23:01:33 -070011882 int minPos, int maxPos,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011883 int hasNsNodes)
11884{
11885 if (op->ch1 != -1) {
11886 xmlXPathCompExprPtr comp = ctxt->comp;
11887 /*
11888 * Process inner predicates first.
11889 */
11890 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -070011891 xmlGenericError(xmlGenericErrorContext,
11892 "xmlXPathCompOpEvalPredicate: Expected a predicate\n");
11893 XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011894 }
Haibo Huangf0a546b2020-09-01 20:28:19 -070011895 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
Haibo Huangcfd91dc2020-07-30 23:01:33 -070011896 XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
11897 ctxt->context->depth += 1;
11898 xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
11899 1, set->nodeNr, hasNsNodes);
11900 ctxt->context->depth -= 1;
11901 CHECK_ERROR;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011902 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011903
Haibo Huangcfd91dc2020-07-30 23:01:33 -070011904 if (op->ch2 != -1)
11905 xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011906}
11907
11908static int
11909xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
Daniel Veillard45490ae2008-07-29 09:13:19 +000011910 xmlXPathStepOpPtr op,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011911 int *maxPos)
11912{
11913
11914 xmlXPathStepOpPtr exprOp;
11915
11916 /*
11917 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11918 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000011919
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011920 /*
11921 * If not -1, then ch1 will point to:
11922 * 1) For predicates (XPATH_OP_PREDICATE):
11923 * - an inner predicate operator
11924 * 2) For filters (XPATH_OP_FILTER):
Haibo Huangcfd91dc2020-07-30 23:01:33 -070011925 * - an inner filter operator OR
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011926 * - an expression selecting the node set.
11927 * E.g. "key('a', 'b')" or "(//foo | //bar)".
Daniel Veillard45490ae2008-07-29 09:13:19 +000011928 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011929 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11930 return(0);
11931
11932 if (op->ch2 != -1) {
11933 exprOp = &ctxt->comp->steps[op->ch2];
Daniel Veillard45490ae2008-07-29 09:13:19 +000011934 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011935 return(0);
11936
11937 if ((exprOp != NULL) &&
11938 (exprOp->op == XPATH_OP_VALUE) &&
11939 (exprOp->value4 != NULL) &&
11940 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11941 {
Nick Wellnhofera58331a2017-05-29 21:02:21 +020011942 double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11943
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011944 /*
11945 * We have a "[n]" predicate here.
11946 * TODO: Unfortunately this simplistic test here is not
11947 * able to detect a position() predicate in compound
11948 * expressions like "[@attr = 'a" and position() = 1],
11949 * and even not the usage of position() in
11950 * "[position() = 1]"; thus - obviously - a position-range,
11951 * like it "[position() < 5]", is also not detected.
11952 * Maybe we could rewrite the AST to ease the optimization.
11953 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000011954
Nick Wellnhofera58331a2017-05-29 21:02:21 +020011955 if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
11956 *maxPos = (int) floatval;
11957 if (floatval == (double) *maxPos)
11958 return(1);
11959 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011960 }
11961 return(0);
11962}
11963
11964static int
11965xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11966 xmlXPathStepOpPtr op,
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011967 xmlNodePtr * first, xmlNodePtr * last,
11968 int toBool)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011969{
11970
11971#define XP_TEST_HIT \
11972 if (hasAxisRange != 0) { \
11973 if (++pos == maxPos) { \
Daniel Veillard1bd45d12012-09-05 15:35:19 +080011974 if (addNode(seq, cur) < 0) \
11975 ctxt->error = XPATH_MEMORY_ERROR; \
11976 goto axis_range_end; } \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011977 } else { \
Daniel Veillard1bd45d12012-09-05 15:35:19 +080011978 if (addNode(seq, cur) < 0) \
11979 ctxt->error = XPATH_MEMORY_ERROR; \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011980 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011981
11982#define XP_TEST_HIT_NS \
11983 if (hasAxisRange != 0) { \
11984 if (++pos == maxPos) { \
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. Buchcik9bca9332006-06-19 10:26:42 +000011988 goto axis_range_end; } \
11989 } else { \
11990 hasNsNodes = 1; \
Daniel Veillard1bd45d12012-09-05 15:35:19 +080011991 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11992 ctxt->error = XPATH_MEMORY_ERROR; \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011993 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011994
11995 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11996 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11997 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11998 const xmlChar *prefix = op->value4;
11999 const xmlChar *name = op->value5;
12000 const xmlChar *URI = NULL;
12001
12002#ifdef DEBUG_STEP
12003 int nbMatches = 0, prevMatches = 0;
12004#endif
12005 int total = 0, hasNsNodes = 0;
12006 /* The popped object holding the context nodes */
12007 xmlXPathObjectPtr obj;
12008 /* The set of context nodes for the node tests */
12009 xmlNodeSetPtr contextSeq;
12010 int contextIdx;
12011 xmlNodePtr contextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012012 /* The final resulting node set wrt to all context nodes */
12013 xmlNodeSetPtr outSeq;
12014 /*
12015 * The temporary resulting node set wrt 1 context node.
12016 * Used to feed predicate evaluation.
12017 */
12018 xmlNodeSetPtr seq;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012019 xmlNodePtr cur;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012020 /* First predicate operator */
12021 xmlXPathStepOpPtr predOp;
12022 int maxPos; /* The requested position() (when a "[n]" predicate) */
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012023 int hasPredicateRange, hasAxisRange, pos;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012024 int breakOnFirstHit;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012025
12026 xmlXPathTraversalFunction next = NULL;
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012027 int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012028 xmlXPathNodeSetMergeFunction mergeAndClear;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012029 xmlNodePtr oldContextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012030 xmlXPathContextPtr xpctxt = ctxt->context;
12031
12032
12033 CHECK_TYPE0(XPATH_NODESET);
12034 obj = valuePop(ctxt);
12035 /*
12036 * Setup namespaces.
12037 */
12038 if (prefix != NULL) {
12039 URI = xmlXPathNsLookup(xpctxt, prefix);
12040 if (URI == NULL) {
12041 xmlXPathReleaseObject(xpctxt, obj);
12042 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12043 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012044 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012045 /*
12046 * Setup axis.
12047 *
12048 * MAYBE FUTURE TODO: merging optimizations:
12049 * - If the nodes to be traversed wrt to the initial nodes and
12050 * the current axis cannot overlap, then we could avoid searching
12051 * for duplicates during the merge.
12052 * But the question is how/when to evaluate if they cannot overlap.
12053 * Example: if we know that for two initial nodes, the one is
12054 * not in the ancestor-or-self axis of the other, then we could safely
12055 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12056 * the descendant-or-self axis.
12057 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012058 mergeAndClear = xmlXPathNodeSetMergeAndClear;
12059 switch (axis) {
12060 case AXIS_ANCESTOR:
12061 first = NULL;
12062 next = xmlXPathNextAncestor;
12063 break;
12064 case AXIS_ANCESTOR_OR_SELF:
12065 first = NULL;
12066 next = xmlXPathNextAncestorOrSelf;
12067 break;
12068 case AXIS_ATTRIBUTE:
12069 first = NULL;
12070 last = NULL;
12071 next = xmlXPathNextAttribute;
12072 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12073 break;
12074 case AXIS_CHILD:
12075 last = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012076 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12077 (type == NODE_TYPE_NODE))
12078 {
12079 /*
12080 * Optimization if an element node type is 'element'.
12081 */
12082 next = xmlXPathNextChildElement;
12083 } else
12084 next = xmlXPathNextChild;
12085 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12086 break;
12087 case AXIS_DESCENDANT:
12088 last = NULL;
12089 next = xmlXPathNextDescendant;
12090 break;
12091 case AXIS_DESCENDANT_OR_SELF:
12092 last = NULL;
12093 next = xmlXPathNextDescendantOrSelf;
12094 break;
12095 case AXIS_FOLLOWING:
12096 last = NULL;
12097 next = xmlXPathNextFollowing;
12098 break;
12099 case AXIS_FOLLOWING_SIBLING:
12100 last = NULL;
12101 next = xmlXPathNextFollowingSibling;
12102 break;
12103 case AXIS_NAMESPACE:
12104 first = NULL;
12105 last = NULL;
12106 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12107 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12108 break;
12109 case AXIS_PARENT:
12110 first = NULL;
12111 next = xmlXPathNextParent;
12112 break;
12113 case AXIS_PRECEDING:
12114 first = NULL;
12115 next = xmlXPathNextPrecedingInternal;
12116 break;
12117 case AXIS_PRECEDING_SIBLING:
12118 first = NULL;
12119 next = xmlXPathNextPrecedingSibling;
12120 break;
12121 case AXIS_SELF:
12122 first = NULL;
12123 last = NULL;
12124 next = xmlXPathNextSelf;
12125 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12126 break;
12127 }
12128
12129#ifdef DEBUG_STEP
Daniel Veillard074f37e2008-09-01 13:38:22 +000012130 xmlXPathDebugDumpStepAxis(op,
12131 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012132#endif
12133
12134 if (next == NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000012135 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012136 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012137 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012138 contextSeq = obj->nodesetval;
12139 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12140 xmlXPathReleaseObject(xpctxt, obj);
12141 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12142 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012143 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012144 /*
12145 * Predicate optimization ---------------------------------------------
12146 * If this step has a last predicate, which contains a position(),
12147 * then we'll optimize (although not exactly "position()", but only
12148 * the short-hand form, i.e., "[n]".
12149 *
12150 * Example - expression "/foo[parent::bar][1]":
Daniel Veillard45490ae2008-07-29 09:13:19 +000012151 *
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012152 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12153 * ROOT -- op->ch1
12154 * PREDICATE -- op->ch2 (predOp)
12155 * PREDICATE -- predOp->ch1 = [parent::bar]
12156 * SORT
12157 * COLLECT 'parent' 'name' 'node' bar
12158 * NODE
12159 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12160 *
12161 */
12162 maxPos = 0;
12163 predOp = NULL;
12164 hasPredicateRange = 0;
12165 hasAxisRange = 0;
12166 if (op->ch2 != -1) {
12167 /*
12168 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12169 */
12170 predOp = &ctxt->comp->steps[op->ch2];
12171 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12172 if (predOp->ch1 != -1) {
12173 /*
12174 * Use the next inner predicate operator.
12175 */
12176 predOp = &ctxt->comp->steps[predOp->ch1];
12177 hasPredicateRange = 1;
12178 } else {
12179 /*
12180 * There's no other predicate than the [n] predicate.
12181 */
12182 predOp = NULL;
12183 hasAxisRange = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012184 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012185 }
12186 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012187 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012188 /*
12189 * Axis traversal -----------------------------------------------------
12190 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012191 /*
12192 * 2.3 Node Tests
Daniel Veillard45490ae2008-07-29 09:13:19 +000012193 * - For the attribute axis, the principal node type is attribute.
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012194 * - For the namespace axis, the principal node type is namespace.
12195 * - For other axes, the principal node type is element.
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012196 *
12197 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012198 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012199 * select all element children of the context node
12200 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012201 oldContextNode = xpctxt->node;
12202 addNode = xmlXPathNodeSetAddUnique;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012203 outSeq = NULL;
12204 seq = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012205 contextNode = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012206 contextIdx = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012207
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012208
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012209 while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12210 (ctxt->error == XPATH_EXPRESSION_OK)) {
Nick Wellnhofer62270532012-08-19 19:42:38 +020012211 xpctxt->node = contextSeq->nodeTab[contextIdx++];
Daniel Veillard45490ae2008-07-29 09:13:19 +000012212
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012213 if (seq == NULL) {
12214 seq = xmlXPathNodeSetCreate(NULL);
12215 if (seq == NULL) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012216 /* TODO: Propagate memory error. */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012217 total = 0;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012218 goto error;
12219 }
12220 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012221 /*
12222 * Traverse the axis and test the nodes.
12223 */
12224 pos = 0;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012225 cur = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012226 hasNsNodes = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012227 do {
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012228 if (OP_LIMIT_EXCEEDED(ctxt, 1))
12229 goto error;
12230
Daniel Veillardf06307e2001-07-03 10:35:50 +000012231 cur = next(ctxt, cur);
12232 if (cur == NULL)
12233 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012234
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012235 /*
12236 * QUESTION TODO: What does the "first" and "last" stuff do?
12237 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012238 if ((first != NULL) && (*first != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012239 if (*first == cur)
12240 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012241 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012242#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012243 (xmlXPathCmpNodesExt(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012244#else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012245 (xmlXPathCmpNodes(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012246#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012247 {
12248 break;
12249 }
12250 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012251 if ((last != NULL) && (*last != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012252 if (*last == cur)
12253 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012254 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012255#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012256 (xmlXPathCmpNodesExt(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012257#else
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012258 (xmlXPathCmpNodes(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012259#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012260 {
12261 break;
12262 }
12263 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012264
12265 total++;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012266
Daniel Veillardf06307e2001-07-03 10:35:50 +000012267#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012268 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12269#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +000012270
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012271 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012272 case NODE_TEST_NONE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012273 total = 0;
12274 STRANGE
12275 goto error;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012276 case NODE_TEST_TYPE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012277 if (type == NODE_TYPE_NODE) {
12278 switch (cur->type) {
12279 case XML_DOCUMENT_NODE:
12280 case XML_HTML_DOCUMENT_NODE:
12281#ifdef LIBXML_DOCB_ENABLED
12282 case XML_DOCB_DOCUMENT_NODE:
12283#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +000012284 case XML_ELEMENT_NODE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012285 case XML_ATTRIBUTE_NODE:
12286 case XML_PI_NODE:
12287 case XML_COMMENT_NODE:
12288 case XML_CDATA_SECTION_NODE:
12289 case XML_TEXT_NODE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012290 XP_TEST_HIT
12291 break;
Nick Wellnhoferf39fd662016-04-27 03:01:16 +020012292 case XML_NAMESPACE_DECL: {
12293 if (axis == AXIS_NAMESPACE) {
12294 XP_TEST_HIT_NS
12295 } else {
Nick Wellnhofer6eb08942016-05-05 16:49:00 +020012296 hasNsNodes = 1;
Nick Wellnhoferf39fd662016-04-27 03:01:16 +020012297 XP_TEST_HIT
12298 }
12299 break;
12300 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012301 default:
12302 break;
12303 }
Nick Wellnhoferb2189572017-11-13 21:23:17 +010012304 } else if (cur->type == (xmlElementType) type) {
Daniel Veillard713434d2012-09-26 10:21:06 +080012305 if (cur->type == XML_NAMESPACE_DECL)
Kasimier T. Buchcik889b7622006-07-03 11:44:13 +000012306 XP_TEST_HIT_NS
12307 else
12308 XP_TEST_HIT
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012309 } else if ((type == NODE_TYPE_TEXT) &&
12310 (cur->type == XML_CDATA_SECTION_NODE))
12311 {
12312 XP_TEST_HIT
12313 }
12314 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012315 case NODE_TEST_PI:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012316 if ((cur->type == XML_PI_NODE) &&
12317 ((name == NULL) || xmlStrEqual(name, cur->name)))
12318 {
12319 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012320 }
12321 break;
12322 case NODE_TEST_ALL:
12323 if (axis == AXIS_ATTRIBUTE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012324 if (cur->type == XML_ATTRIBUTE_NODE)
12325 {
Nick Wellnhofere8de99f2013-08-05 01:26:25 +020012326 if (prefix == NULL)
12327 {
12328 XP_TEST_HIT
12329 } else if ((cur->ns != NULL) &&
12330 (xmlStrEqual(URI, cur->ns->href)))
12331 {
12332 XP_TEST_HIT
12333 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012334 }
12335 } else if (axis == AXIS_NAMESPACE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012336 if (cur->type == XML_NAMESPACE_DECL)
12337 {
12338 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012339 }
12340 } else {
12341 if (cur->type == XML_ELEMENT_NODE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012342 if (prefix == NULL)
12343 {
12344 XP_TEST_HIT
12345
Daniel Veillardf06307e2001-07-03 10:35:50 +000012346 } else if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012347 (xmlStrEqual(URI, cur->ns->href)))
12348 {
12349 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012350 }
12351 }
12352 }
12353 break;
12354 case NODE_TEST_NS:{
12355 TODO;
12356 break;
12357 }
12358 case NODE_TEST_NAME:
Daniel Veillardfe3970e2006-11-23 16:08:30 +000012359 if (axis == AXIS_ATTRIBUTE) {
12360 if (cur->type != XML_ATTRIBUTE_NODE)
12361 break;
12362 } else if (axis == AXIS_NAMESPACE) {
12363 if (cur->type != XML_NAMESPACE_DECL)
12364 break;
12365 } else {
12366 if (cur->type != XML_ELEMENT_NODE)
12367 break;
12368 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012369 switch (cur->type) {
12370 case XML_ELEMENT_NODE:
12371 if (xmlStrEqual(name, cur->name)) {
12372 if (prefix == NULL) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012373 if (cur->ns == NULL)
12374 {
12375 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012376 }
12377 } else {
12378 if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012379 (xmlStrEqual(URI, cur->ns->href)))
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012380 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012381 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012382 }
12383 }
12384 }
12385 break;
12386 case XML_ATTRIBUTE_NODE:{
12387 xmlAttrPtr attr = (xmlAttrPtr) cur;
12388
12389 if (xmlStrEqual(name, attr->name)) {
12390 if (prefix == NULL) {
12391 if ((attr->ns == NULL) ||
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012392 (attr->ns->prefix == NULL))
12393 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012394 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012395 }
12396 } else {
12397 if ((attr->ns != NULL) &&
12398 (xmlStrEqual(URI,
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012399 attr->ns->href)))
12400 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012401 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012402 }
12403 }
12404 }
12405 break;
12406 }
12407 case XML_NAMESPACE_DECL:
12408 if (cur->type == XML_NAMESPACE_DECL) {
12409 xmlNsPtr ns = (xmlNsPtr) cur;
12410
12411 if ((ns->prefix != NULL) && (name != NULL)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012412 && (xmlStrEqual(ns->prefix, name)))
12413 {
12414 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012415 }
12416 }
12417 break;
12418 default:
12419 break;
12420 }
12421 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012422 } /* switch(test) */
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012423 } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012424
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012425 goto apply_predicates;
12426
Daniel Veillard45490ae2008-07-29 09:13:19 +000012427axis_range_end: /* ----------------------------------------------------- */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012428 /*
12429 * We have a "/foo[n]", and position() = n was reached.
12430 * Note that we can have as well "/foo/::parent::foo[1]", so
12431 * a duplicate-aware merge is still needed.
12432 * Merge with the result.
12433 */
12434 if (outSeq == NULL) {
12435 outSeq = seq;
12436 seq = NULL;
12437 } else
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012438 /* TODO: Check memory error. */
12439 outSeq = mergeAndClear(outSeq, seq);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012440 /*
12441 * Break if only a true/false result was requested.
12442 */
12443 if (toBool)
12444 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012445 continue;
12446
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012447first_hit: /* ---------------------------------------------------------- */
12448 /*
12449 * Break if only a true/false result was requested and
12450 * no predicates existed and a node test succeeded.
12451 */
12452 if (outSeq == NULL) {
12453 outSeq = seq;
12454 seq = NULL;
12455 } else
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012456 /* TODO: Check memory error. */
12457 outSeq = mergeAndClear(outSeq, seq);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012458 break;
12459
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012460#ifdef DEBUG_STEP
12461 if (seq != NULL)
12462 nbMatches += seq->nodeNr;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012463#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012464
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012465apply_predicates: /* --------------------------------------------------- */
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012466 if (ctxt->error != XPATH_EXPRESSION_OK)
12467 goto error;
12468
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012469 /*
12470 * Apply predicates.
Daniel Veillard45490ae2008-07-29 09:13:19 +000012471 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012472 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12473 /*
12474 * E.g. when we have a "/foo[some expression][n]".
Daniel Veillardf8e3db02012-09-11 13:26:36 +080012475 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012476 /*
12477 * QUESTION TODO: The old predicate evaluation took into
12478 * account location-sets.
12479 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12480 * Do we expect such a set here?
12481 * All what I learned now from the evaluation semantics
12482 * does not indicate that a location-set will be processed
12483 * here, so this looks OK.
Daniel Veillardf8e3db02012-09-11 13:26:36 +080012484 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012485 /*
12486 * Iterate over all predicates, starting with the outermost
12487 * predicate.
12488 * TODO: Problem: we cannot execute the inner predicates first
12489 * since we cannot go back *up* the operator tree!
12490 * Options we have:
12491 * 1) Use of recursive functions (like is it currently done
12492 * via xmlXPathCompOpEval())
12493 * 2) Add a predicate evaluation information stack to the
12494 * context struct
12495 * 3) Change the way the operators are linked; we need a
12496 * "parent" field on xmlXPathStepOp
12497 *
12498 * For the moment, I'll try to solve this with a recursive
12499 * function: xmlXPathCompOpEvalPredicate().
Daniel Veillard45490ae2008-07-29 09:13:19 +000012500 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012501 if (hasPredicateRange != 0)
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012502 xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
12503 hasNsNodes);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012504 else
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012505 xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
12506 hasNsNodes);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012507
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012508 if (ctxt->error != XPATH_EXPRESSION_OK) {
12509 total = 0;
12510 goto error;
12511 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012512 }
12513
12514 if (seq->nodeNr > 0) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012515 /*
12516 * Add to result set.
12517 */
12518 if (outSeq == NULL) {
12519 outSeq = seq;
12520 seq = NULL;
12521 } else {
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012522 /* TODO: Check memory error. */
12523 outSeq = mergeAndClear(outSeq, seq);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012524 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012525
12526 if (toBool)
12527 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012528 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012529 }
12530
12531error:
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012532 if ((obj->boolval) && (obj->user != NULL)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012533 /*
12534 * QUESTION TODO: What does this do and why?
12535 * TODO: Do we have to do this also for the "error"
12536 * cleanup further down?
12537 */
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012538 ctxt->value->boolval = 1;
12539 ctxt->value->user = obj->user;
12540 obj->user = NULL;
12541 obj->boolval = 0;
12542 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012543 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012544
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012545 /*
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012546 * Ensure we return at least an empty set.
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012547 */
12548 if (outSeq == NULL) {
12549 if ((seq != NULL) && (seq->nodeNr == 0))
12550 outSeq = seq;
12551 else
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012552 /* TODO: Check memory error. */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012553 outSeq = xmlXPathNodeSetCreate(NULL);
12554 }
12555 if ((seq != NULL) && (seq != outSeq)) {
12556 xmlXPathFreeNodeSet(seq);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012557 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012558 /*
12559 * Hand over the result. Better to push the set also in
12560 * case of errors.
12561 */
12562 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12563 /*
12564 * Reset the context node.
12565 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012566 xpctxt->node = oldContextNode;
Nick Wellnhofer82b73032016-04-30 17:53:10 +020012567 /*
12568 * When traversing the namespace axis in "toBool" mode, it's
12569 * possible that tmpNsList wasn't freed.
12570 */
12571 if (xpctxt->tmpNsList != NULL) {
12572 xmlFree(xpctxt->tmpNsList);
12573 xpctxt->tmpNsList = NULL;
12574 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012575
12576#ifdef DEBUG_STEP
12577 xmlGenericError(xmlGenericErrorContext,
12578 "\nExamined %d nodes, found %d nodes at that step\n",
12579 total, nbMatches);
12580#endif
12581
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012582 return(total);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012583}
12584
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012585static int
12586xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12587 xmlXPathStepOpPtr op, xmlNodePtr * first);
12588
Daniel Veillardf06307e2001-07-03 10:35:50 +000012589/**
12590 * xmlXPathCompOpEvalFirst:
12591 * @ctxt: the XPath parser context with the compiled expression
12592 * @op: an XPath compiled operation
12593 * @first: the first elem found so far
12594 *
12595 * Evaluate the Precompiled XPath operation searching only the first
12596 * element in document order
12597 *
12598 * Returns the number of examined objects.
12599 */
12600static int
12601xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12602 xmlXPathStepOpPtr op, xmlNodePtr * first)
12603{
12604 int total = 0, cur;
12605 xmlXPathCompExprPtr comp;
12606 xmlXPathObjectPtr arg1, arg2;
12607
Daniel Veillard556c6682001-10-06 09:59:51 +000012608 CHECK_ERROR0;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012609 if (OP_LIMIT_EXCEEDED(ctxt, 1))
12610 return(0);
Haibo Huangf0a546b2020-09-01 20:28:19 -070012611 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012612 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12613 ctxt->context->depth += 1;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012614 comp = ctxt->comp;
12615 switch (op->op) {
12616 case XPATH_OP_END:
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012617 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012618 case XPATH_OP_UNION:
12619 total =
12620 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12621 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012622 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012623 if ((ctxt->value != NULL)
12624 && (ctxt->value->type == XPATH_NODESET)
12625 && (ctxt->value->nodesetval != NULL)
12626 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12627 /*
12628 * limit tree traversing to first node in the result
12629 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012630 /*
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012631 * OPTIMIZE TODO: This implicitly sorts
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012632 * the result, even if not needed. E.g. if the argument
12633 * of the count() function, no sorting is needed.
12634 * OPTIMIZE TODO: How do we know if the node-list wasn't
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012635 * already sorted?
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012636 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012637 if (ctxt->value->nodesetval->nodeNr > 1)
12638 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012639 *first = ctxt->value->nodesetval->nodeTab[0];
12640 }
12641 cur =
12642 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12643 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012644 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012645
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020012646 arg2 = valuePop(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012647 arg1 = valuePop(ctxt);
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020012648 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12649 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12650 xmlXPathReleaseObject(ctxt->context, arg1);
12651 xmlXPathReleaseObject(ctxt->context, arg2);
12652 XP_ERROR0(XPATH_INVALID_TYPE);
12653 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012654 if ((ctxt->context->opLimit != 0) &&
12655 (((arg1->nodesetval != NULL) &&
12656 (xmlXPathCheckOpLimit(ctxt,
12657 arg1->nodesetval->nodeNr) < 0)) ||
12658 ((arg2->nodesetval != NULL) &&
12659 (xmlXPathCheckOpLimit(ctxt,
12660 arg2->nodesetval->nodeNr) < 0)))) {
12661 xmlXPathReleaseObject(ctxt->context, arg1);
12662 xmlXPathReleaseObject(ctxt->context, arg2);
12663 break;
12664 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012665
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012666 /* TODO: Check memory error. */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012667 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12668 arg2->nodesetval);
12669 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012670 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012671 /* optimizer */
12672 if (total > cur)
12673 xmlXPathCompSwap(op);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012674 total += cur;
12675 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012676 case XPATH_OP_ROOT:
12677 xmlXPathRoot(ctxt);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012678 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012679 case XPATH_OP_NODE:
12680 if (op->ch1 != -1)
12681 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012682 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012683 if (op->ch2 != -1)
12684 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012685 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012686 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12687 ctxt->context->node));
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012688 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012689 case XPATH_OP_COLLECT:{
12690 if (op->ch1 == -1)
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012691 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012692
12693 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012694 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012695
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012696 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012697 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012698 }
12699 case XPATH_OP_VALUE:
12700 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012701 xmlXPathCacheObjectCopy(ctxt->context,
12702 (xmlXPathObjectPtr) op->value4));
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012703 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012704 case XPATH_OP_SORT:
12705 if (op->ch1 != -1)
12706 total +=
12707 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12708 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012709 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012710 if ((ctxt->value != NULL)
12711 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012712 && (ctxt->value->nodesetval != NULL)
12713 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012714 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012715 break;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012716#ifdef XP_OPTIMIZED_FILTER_FIRST
12717 case XPATH_OP_FILTER:
Marius Wachtler2ddecc22010-10-12 09:09:07 +020012718 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012719 break;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012720#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000012721 default:
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012722 total += xmlXPathCompOpEval(ctxt, op);
12723 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012724 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012725
12726 ctxt->context->depth -= 1;
12727 return(total);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012728}
12729
12730/**
12731 * xmlXPathCompOpEvalLast:
12732 * @ctxt: the XPath parser context with the compiled expression
12733 * @op: an XPath compiled operation
12734 * @last: the last elem found so far
12735 *
12736 * Evaluate the Precompiled XPath operation searching only the last
12737 * element in document order
12738 *
William M. Brack08171912003-12-29 02:52:11 +000012739 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +000012740 */
12741static int
12742xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12743 xmlNodePtr * last)
12744{
12745 int total = 0, cur;
12746 xmlXPathCompExprPtr comp;
12747 xmlXPathObjectPtr arg1, arg2;
12748
Daniel Veillard556c6682001-10-06 09:59:51 +000012749 CHECK_ERROR0;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012750 if (OP_LIMIT_EXCEEDED(ctxt, 1))
12751 return(0);
Haibo Huangf0a546b2020-09-01 20:28:19 -070012752 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012753 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12754 ctxt->context->depth += 1;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012755 comp = ctxt->comp;
12756 switch (op->op) {
12757 case XPATH_OP_END:
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012758 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012759 case XPATH_OP_UNION:
12760 total =
12761 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012762 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012763 if ((ctxt->value != NULL)
12764 && (ctxt->value->type == XPATH_NODESET)
12765 && (ctxt->value->nodesetval != NULL)
12766 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12767 /*
12768 * limit tree traversing to first node in the result
12769 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012770 if (ctxt->value->nodesetval->nodeNr > 1)
12771 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012772 *last =
12773 ctxt->value->nodesetval->nodeTab[ctxt->value->
12774 nodesetval->nodeNr -
12775 1];
12776 }
12777 cur =
12778 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012779 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012780 if ((ctxt->value != NULL)
12781 && (ctxt->value->type == XPATH_NODESET)
12782 && (ctxt->value->nodesetval != NULL)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012783 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012784 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012785
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020012786 arg2 = valuePop(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012787 arg1 = valuePop(ctxt);
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020012788 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12789 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12790 xmlXPathReleaseObject(ctxt->context, arg1);
12791 xmlXPathReleaseObject(ctxt->context, arg2);
12792 XP_ERROR0(XPATH_INVALID_TYPE);
12793 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012794 if ((ctxt->context->opLimit != 0) &&
12795 (((arg1->nodesetval != NULL) &&
12796 (xmlXPathCheckOpLimit(ctxt,
12797 arg1->nodesetval->nodeNr) < 0)) ||
12798 ((arg2->nodesetval != NULL) &&
12799 (xmlXPathCheckOpLimit(ctxt,
12800 arg2->nodesetval->nodeNr) < 0)))) {
12801 xmlXPathReleaseObject(ctxt->context, arg1);
12802 xmlXPathReleaseObject(ctxt->context, arg2);
12803 break;
12804 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012805
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012806 /* TODO: Check memory error. */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012807 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12808 arg2->nodesetval);
12809 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012810 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012811 /* optimizer */
12812 if (total > cur)
12813 xmlXPathCompSwap(op);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012814 total += cur;
12815 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012816 case XPATH_OP_ROOT:
12817 xmlXPathRoot(ctxt);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012818 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012819 case XPATH_OP_NODE:
12820 if (op->ch1 != -1)
12821 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012822 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012823 if (op->ch2 != -1)
12824 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012825 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012826 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12827 ctxt->context->node));
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012828 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012829 case XPATH_OP_COLLECT:{
12830 if (op->ch1 == -1)
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012831 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012832
12833 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012834 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012835
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012836 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012837 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012838 }
12839 case XPATH_OP_VALUE:
12840 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012841 xmlXPathCacheObjectCopy(ctxt->context,
12842 (xmlXPathObjectPtr) op->value4));
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012843 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012844 case XPATH_OP_SORT:
12845 if (op->ch1 != -1)
12846 total +=
12847 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12848 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012849 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012850 if ((ctxt->value != NULL)
12851 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012852 && (ctxt->value->nodesetval != NULL)
12853 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012854 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012855 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012856 default:
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012857 total += xmlXPathCompOpEval(ctxt, op);
12858 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012859 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012860
12861 ctxt->context->depth -= 1;
12862 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012863}
12864
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012865#ifdef XP_OPTIMIZED_FILTER_FIRST
12866static int
12867xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12868 xmlXPathStepOpPtr op, xmlNodePtr * first)
12869{
12870 int total = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012871 xmlXPathCompExprPtr comp;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012872 xmlNodeSetPtr set;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012873
12874 CHECK_ERROR0;
12875 comp = ctxt->comp;
12876 /*
12877 * Optimization for ()[last()] selection i.e. the last elem
12878 */
12879 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12880 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12881 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12882 int f = comp->steps[op->ch2].ch1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012883
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012884 if ((f != -1) &&
12885 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12886 (comp->steps[f].value5 == NULL) &&
12887 (comp->steps[f].value == 0) &&
12888 (comp->steps[f].value4 != NULL) &&
12889 (xmlStrEqual
12890 (comp->steps[f].value4, BAD_CAST "last"))) {
12891 xmlNodePtr last = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012892
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012893 total +=
12894 xmlXPathCompOpEvalLast(ctxt,
12895 &comp->steps[op->ch1],
12896 &last);
12897 CHECK_ERROR0;
12898 /*
12899 * The nodeset should be in document order,
12900 * Keep only the last value
12901 */
12902 if ((ctxt->value != NULL) &&
12903 (ctxt->value->type == XPATH_NODESET) &&
12904 (ctxt->value->nodesetval != NULL) &&
12905 (ctxt->value->nodesetval->nodeTab != NULL) &&
12906 (ctxt->value->nodesetval->nodeNr > 1)) {
Nick Wellnhofer95a92492017-05-21 15:18:58 +020012907 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012908 *first = *(ctxt->value->nodesetval->nodeTab);
12909 }
12910 return (total);
12911 }
12912 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012913
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012914 if (op->ch1 != -1)
12915 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12916 CHECK_ERROR0;
12917 if (op->ch2 == -1)
12918 return (total);
12919 if (ctxt->value == NULL)
12920 return (total);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012921
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012922#ifdef LIBXML_XPTR_ENABLED
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012923 /*
12924 * Hum are we filtering the result of an XPointer expression
12925 */
12926 if (ctxt->value->type == XPATH_LOCATIONSET) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012927 xmlLocationSetPtr locset = ctxt->value->user;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012928
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012929 if (locset != NULL) {
12930 xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1);
12931 if (locset->locNr > 0)
12932 *first = (xmlNodePtr) locset->locTab[0]->user;
12933 }
Elliott Hughes7fbecab2019-01-10 16:42:03 -080012934
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012935 return (total);
12936 }
12937#endif /* LIBXML_XPTR_ENABLED */
Daniel Veillard45490ae2008-07-29 09:13:19 +000012938
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012939 CHECK_TYPE0(XPATH_NODESET);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012940 set = ctxt->value->nodesetval;
12941 if (set != NULL) {
12942 xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
12943 if (set->nodeNr > 0)
12944 *first = set->nodeTab[0];
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012945 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012946
12947 return (total);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012948}
12949#endif /* XP_OPTIMIZED_FILTER_FIRST */
12950
Owen Taylor3473f882001-02-23 17:55:21 +000012951/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012952 * xmlXPathCompOpEval:
12953 * @ctxt: the XPath parser context with the compiled expression
12954 * @op: an XPath compiled operation
12955 *
12956 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000012957 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012958 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012959static int
12960xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
12961{
12962 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012963 int equal, ret;
12964 xmlXPathCompExprPtr comp;
12965 xmlXPathObjectPtr arg1, arg2;
12966
Daniel Veillard556c6682001-10-06 09:59:51 +000012967 CHECK_ERROR0;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012968 if (OP_LIMIT_EXCEEDED(ctxt, 1))
12969 return(0);
Haibo Huangf0a546b2020-09-01 20:28:19 -070012970 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012971 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12972 ctxt->context->depth += 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012973 comp = ctxt->comp;
12974 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012975 case XPATH_OP_END:
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012976 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012977 case XPATH_OP_AND:
12978 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012979 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012980 xmlXPathBooleanFunction(ctxt, 1);
12981 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012982 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012983 arg2 = valuePop(ctxt);
12984 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012985 if (ctxt->error) {
12986 xmlXPathFreeObject(arg2);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012987 break;
Daniel Veillard556c6682001-10-06 09:59:51 +000012988 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012989 xmlXPathBooleanFunction(ctxt, 1);
Elliott Hughes7fbecab2019-01-10 16:42:03 -080012990 if (ctxt->value != NULL)
12991 ctxt->value->boolval &= arg2->boolval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012992 xmlXPathReleaseObject(ctxt->context, arg2);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012993 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012994 case XPATH_OP_OR:
12995 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012996 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012997 xmlXPathBooleanFunction(ctxt, 1);
12998 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012999 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013000 arg2 = valuePop(ctxt);
13001 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013002 if (ctxt->error) {
13003 xmlXPathFreeObject(arg2);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013004 break;
Daniel Veillard556c6682001-10-06 09:59:51 +000013005 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013006 xmlXPathBooleanFunction(ctxt, 1);
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013007 if (ctxt->value != NULL)
13008 ctxt->value->boolval |= arg2->boolval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013009 xmlXPathReleaseObject(ctxt->context, arg2);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013010 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013011 case XPATH_OP_EQUAL:
13012 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013013 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013014 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013015 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000013016 if (op->value)
Daniel Veillard45490ae2008-07-29 09:13:19 +000013017 equal = xmlXPathEqualValues(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +000013018 else
13019 equal = xmlXPathNotEqualValues(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013020 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013021 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013022 case XPATH_OP_CMP:
13023 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013024 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013025 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013026 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013027 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013028 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013029 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013030 case XPATH_OP_PLUS:
13031 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013032 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013033 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013034 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013035 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013036 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013037 if (op->value == 0)
13038 xmlXPathSubValues(ctxt);
13039 else if (op->value == 1)
13040 xmlXPathAddValues(ctxt);
13041 else if (op->value == 2)
13042 xmlXPathValueFlipSign(ctxt);
13043 else if (op->value == 3) {
13044 CAST_TO_NUMBER;
13045 CHECK_TYPE0(XPATH_NUMBER);
13046 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013047 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013048 case XPATH_OP_MULT:
13049 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013050 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013051 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013052 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013053 if (op->value == 0)
13054 xmlXPathMultValues(ctxt);
13055 else if (op->value == 1)
13056 xmlXPathDivValues(ctxt);
13057 else if (op->value == 2)
13058 xmlXPathModValues(ctxt);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013059 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013060 case XPATH_OP_UNION:
13061 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013062 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013063 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013064 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013065
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020013066 arg2 = valuePop(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013067 arg1 = valuePop(ctxt);
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020013068 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13069 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13070 xmlXPathReleaseObject(ctxt->context, arg1);
13071 xmlXPathReleaseObject(ctxt->context, arg2);
13072 XP_ERROR0(XPATH_INVALID_TYPE);
13073 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013074 if ((ctxt->context->opLimit != 0) &&
13075 (((arg1->nodesetval != NULL) &&
13076 (xmlXPathCheckOpLimit(ctxt,
13077 arg1->nodesetval->nodeNr) < 0)) ||
13078 ((arg2->nodesetval != NULL) &&
13079 (xmlXPathCheckOpLimit(ctxt,
13080 arg2->nodesetval->nodeNr) < 0)))) {
13081 xmlXPathReleaseObject(ctxt->context, arg1);
13082 xmlXPathReleaseObject(ctxt->context, arg2);
13083 break;
13084 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013085
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013086 if ((arg1->nodesetval == NULL) ||
13087 ((arg2->nodesetval != NULL) &&
13088 (arg2->nodesetval->nodeNr != 0)))
13089 {
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013090 /* TODO: Check memory error. */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013091 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13092 arg2->nodesetval);
13093 }
13094
Daniel Veillardf06307e2001-07-03 10:35:50 +000013095 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013096 xmlXPathReleaseObject(ctxt->context, arg2);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013097 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013098 case XPATH_OP_ROOT:
13099 xmlXPathRoot(ctxt);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013100 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013101 case XPATH_OP_NODE:
13102 if (op->ch1 != -1)
13103 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013104 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013105 if (op->ch2 != -1)
13106 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013107 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013108 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13109 ctxt->context->node));
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013110 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013111 case XPATH_OP_COLLECT:{
13112 if (op->ch1 == -1)
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013113 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000013114
Daniel Veillardf06307e2001-07-03 10:35:50 +000013115 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013116 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013117
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013118 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013119 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013120 }
13121 case XPATH_OP_VALUE:
13122 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013123 xmlXPathCacheObjectCopy(ctxt->context,
13124 (xmlXPathObjectPtr) op->value4));
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013125 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013126 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000013127 xmlXPathObjectPtr val;
13128
Daniel Veillardf06307e2001-07-03 10:35:50 +000013129 if (op->ch1 != -1)
13130 total +=
13131 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013132 if (op->value5 == NULL) {
13133 val = xmlXPathVariableLookup(ctxt->context, op->value4);
Nick Wellnhofer3157cf42017-09-20 16:13:29 +020013134 if (val == NULL)
13135 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
Daniel Veillard556c6682001-10-06 09:59:51 +000013136 valuePush(ctxt, val);
13137 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013138 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013139
Daniel Veillardf06307e2001-07-03 10:35:50 +000013140 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13141 if (URI == NULL) {
13142 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013143 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13144 (char *) op->value4, (char *)op->value5);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080013145 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013146 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013147 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013148 val = xmlXPathVariableLookupNS(ctxt->context,
13149 op->value4, URI);
Nick Wellnhofer3157cf42017-09-20 16:13:29 +020013150 if (val == NULL)
13151 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
Daniel Veillard556c6682001-10-06 09:59:51 +000013152 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013153 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013154 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013155 }
13156 case XPATH_OP_FUNCTION:{
13157 xmlXPathFunction func;
13158 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000013159 int i;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013160 int frame;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013161
Daniel Veillardf5048b32011-08-18 17:10:13 +080013162 frame = xmlXPathSetFrame(ctxt);
Nick Wellnhofer03c67232013-12-20 00:01:53 +010013163 if (op->ch1 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013164 total +=
13165 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Nick Wellnhofer03c67232013-12-20 00:01:53 +010013166 if (ctxt->error != XPATH_EXPRESSION_OK) {
13167 xmlXPathPopFrame(ctxt, frame);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013168 break;
Nick Wellnhofer03c67232013-12-20 00:01:53 +010013169 }
13170 }
13171 if (ctxt->valueNr < ctxt->valueFrame + op->value) {
Daniel Veillard556c6682001-10-06 09:59:51 +000013172 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013173 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013174 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013175 xmlXPathPopFrame(ctxt, frame);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013176 break;
Daniel Veillard556c6682001-10-06 09:59:51 +000013177 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080013178 for (i = 0; i < op->value; i++) {
Daniel Veillard556c6682001-10-06 09:59:51 +000013179 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13180 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013181 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013182 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013183 xmlXPathPopFrame(ctxt, frame);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013184 break;
Daniel Veillard556c6682001-10-06 09:59:51 +000013185 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080013186 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013187 if (op->cache != NULL)
Nick Wellnhofer229d1f92016-08-22 13:21:57 +020013188 func = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013189 else {
13190 const xmlChar *URI = NULL;
13191
13192 if (op->value5 == NULL)
13193 func =
13194 xmlXPathFunctionLookup(ctxt->context,
13195 op->value4);
13196 else {
13197 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13198 if (URI == NULL) {
13199 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013200 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13201 (char *)op->value4, (char *)op->value5);
Daniel Veillardf5048b32011-08-18 17:10:13 +080013202 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080013203 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013204 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013205 }
13206 func = xmlXPathFunctionLookupNS(ctxt->context,
13207 op->value4, URI);
13208 }
13209 if (func == NULL) {
13210 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013211 "xmlXPathCompOpEval: function %s not found\n",
13212 (char *)op->value4);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013213 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013214 }
Nick Wellnhofer229d1f92016-08-22 13:21:57 +020013215 op->cache = func;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013216 op->cacheURI = (void *) URI;
13217 }
13218 oldFunc = ctxt->context->function;
13219 oldFuncURI = ctxt->context->functionURI;
13220 ctxt->context->function = op->value4;
13221 ctxt->context->functionURI = op->cacheURI;
13222 func(ctxt, op->value);
13223 ctxt->context->function = oldFunc;
13224 ctxt->context->functionURI = oldFuncURI;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013225 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
13226 (ctxt->valueNr != ctxt->valueFrame + 1))
13227 XP_ERROR0(XPATH_STACK_ERROR);
Daniel Veillardf5048b32011-08-18 17:10:13 +080013228 xmlXPathPopFrame(ctxt, frame);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013229 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013230 }
13231 case XPATH_OP_ARG:
Nick Wellnhofer07def302014-03-21 19:38:08 +010013232 if (op->ch1 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013233 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Nick Wellnhofer07def302014-03-21 19:38:08 +010013234 CHECK_ERROR0;
13235 }
William M. Brack72ee48d2003-12-30 08:30:19 +000013236 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013237 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000013238 CHECK_ERROR0;
13239 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013240 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013241 case XPATH_OP_PREDICATE:
13242 case XPATH_OP_FILTER:{
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013243 xmlNodeSetPtr set;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013244
13245 /*
13246 * Optimization for ()[1] selection i.e. the first elem
13247 */
13248 if ((op->ch1 != -1) && (op->ch2 != -1) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013249#ifdef XP_OPTIMIZED_FILTER_FIRST
13250 /*
13251 * FILTER TODO: Can we assume that the inner processing
13252 * will result in an ordered list if we have an
13253 * XPATH_OP_FILTER?
13254 * What about an additional field or flag on
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013255 * xmlXPathObject like @sorted ? This way we wouldn't need
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013256 * to assume anything, so it would be more robust and
13257 * easier to optimize.
13258 */
13259 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13260 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13261#else
13262 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13263#endif
13264 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013265 xmlXPathObjectPtr val;
13266
13267 val = comp->steps[op->ch2].value4;
13268 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13269 (val->floatval == 1.0)) {
13270 xmlNodePtr first = NULL;
13271
13272 total +=
13273 xmlXPathCompOpEvalFirst(ctxt,
13274 &comp->steps[op->ch1],
13275 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000013276 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013277 /*
13278 * The nodeset should be in document order,
13279 * Keep only the first value
13280 */
13281 if ((ctxt->value != NULL) &&
13282 (ctxt->value->type == XPATH_NODESET) &&
13283 (ctxt->value->nodesetval != NULL) &&
13284 (ctxt->value->nodesetval->nodeNr > 1))
Nick Wellnhofer95a92492017-05-21 15:18:58 +020013285 xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13286 1, 1);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013287 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013288 }
13289 }
13290 /*
13291 * Optimization for ()[last()] selection i.e. the last elem
13292 */
13293 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13294 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13295 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13296 int f = comp->steps[op->ch2].ch1;
13297
13298 if ((f != -1) &&
13299 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13300 (comp->steps[f].value5 == NULL) &&
13301 (comp->steps[f].value == 0) &&
13302 (comp->steps[f].value4 != NULL) &&
13303 (xmlStrEqual
13304 (comp->steps[f].value4, BAD_CAST "last"))) {
13305 xmlNodePtr last = NULL;
13306
13307 total +=
13308 xmlXPathCompOpEvalLast(ctxt,
13309 &comp->steps[op->ch1],
13310 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000013311 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013312 /*
13313 * The nodeset should be in document order,
13314 * Keep only the last value
13315 */
13316 if ((ctxt->value != NULL) &&
13317 (ctxt->value->type == XPATH_NODESET) &&
13318 (ctxt->value->nodesetval != NULL) &&
13319 (ctxt->value->nodesetval->nodeTab != NULL) &&
Nick Wellnhofer95a92492017-05-21 15:18:58 +020013320 (ctxt->value->nodesetval->nodeNr > 1))
13321 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013322 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013323 }
13324 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013325 /*
13326 * Process inner predicates first.
13327 * Example "index[parent::book][1]":
13328 * ...
13329 * PREDICATE <-- we are here "[1]"
13330 * PREDICATE <-- process "[parent::book]" first
13331 * SORT
13332 * COLLECT 'parent' 'name' 'node' book
13333 * NODE
13334 * ELEM Object is a number : 1
13335 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013336 if (op->ch1 != -1)
13337 total +=
13338 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013339 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013340 if (op->ch2 == -1)
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013341 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013342 if (ctxt->value == NULL)
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013343 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013344
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013345#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013346 /*
13347 * Hum are we filtering the result of an XPointer expression
13348 */
13349 if (ctxt->value->type == XPATH_LOCATIONSET) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013350 xmlLocationSetPtr locset = ctxt->value->user;
13351 xmlXPathLocationSetFilter(ctxt, locset, op->ch2,
13352 1, locset->locNr);
13353 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013354 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013355#endif /* LIBXML_XPTR_ENABLED */
13356
Daniel Veillardf06307e2001-07-03 10:35:50 +000013357 CHECK_TYPE0(XPATH_NODESET);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013358 set = ctxt->value->nodesetval;
13359 if (set != NULL)
13360 xmlXPathNodeSetFilter(ctxt, set, op->ch2,
13361 1, set->nodeNr, 1);
13362 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013363 }
13364 case XPATH_OP_SORT:
13365 if (op->ch1 != -1)
13366 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013367 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013368 if ((ctxt->value != NULL) &&
13369 (ctxt->value->type == XPATH_NODESET) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013370 (ctxt->value->nodesetval != NULL) &&
13371 (ctxt->value->nodesetval->nodeNr > 1))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013372 {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013373 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013374 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013375 break;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013376#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013377 case XPATH_OP_RANGETO:{
13378 xmlXPathObjectPtr range;
13379 xmlXPathObjectPtr res, obj;
13380 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000013381 xmlLocationSetPtr newlocset = NULL;
13382 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013383 xmlNodeSetPtr oldset;
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013384 xmlNodePtr oldnode = ctxt->context->node;
13385 int oldcs = ctxt->context->contextSize;
13386 int oldpp = ctxt->context->proximityPosition;
William M. Brack72ee48d2003-12-30 08:30:19 +000013387 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013388
Nick Wellnhoferd8083bf2016-06-25 12:35:50 +020013389 if (op->ch1 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013390 total +=
13391 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Nick Wellnhoferd8083bf2016-06-25 12:35:50 +020013392 CHECK_ERROR0;
13393 }
13394 if (ctxt->value == NULL) {
13395 XP_ERROR0(XPATH_INVALID_OPERAND);
13396 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013397 if (op->ch2 == -1)
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013398 break;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013399
William M. Brack08171912003-12-29 02:52:11 +000013400 if (ctxt->value->type == XPATH_LOCATIONSET) {
13401 /*
13402 * Extract the old locset, and then evaluate the result of the
13403 * expression for all the element in the locset. use it to grow
13404 * up a new locset.
13405 */
13406 CHECK_TYPE0(XPATH_LOCATIONSET);
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013407
13408 if ((ctxt->value->user == NULL) ||
13409 (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013410 break;
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013411
William M. Brack08171912003-12-29 02:52:11 +000013412 obj = valuePop(ctxt);
13413 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013414
William M. Brack08171912003-12-29 02:52:11 +000013415 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013416
William M. Brack08171912003-12-29 02:52:11 +000013417 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013418 /*
William M. Brack08171912003-12-29 02:52:11 +000013419 * Run the evaluation with a node list made of a
13420 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000013421 */
William M. Brackf7eb7942003-12-31 07:59:17 +000013422 ctxt->context->node = oldlocset->locTab[i]->user;
13423 ctxt->context->contextSize = oldlocset->locNr;
13424 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013425 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13426 ctxt->context->node);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013427 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013428
Daniel Veillardf06307e2001-07-03 10:35:50 +000013429 if (op->ch2 != -1)
13430 total +=
13431 xmlXPathCompOpEval(ctxt,
13432 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013433 if (ctxt->error != XPATH_EXPRESSION_OK) {
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013434 xmlXPtrFreeLocationSet(newlocset);
13435 goto rangeto_error;
William M. Brack2c19a7b2005-04-10 01:03:23 +000013436 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013437
Daniel Veillardf06307e2001-07-03 10:35:50 +000013438 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000013439 if (res->type == XPATH_LOCATIONSET) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000013440 xmlLocationSetPtr rloc =
William M. Brack72ee48d2003-12-30 08:30:19 +000013441 (xmlLocationSetPtr)res->user;
13442 for (j=0; j<rloc->locNr; j++) {
13443 range = xmlXPtrNewRange(
13444 oldlocset->locTab[i]->user,
13445 oldlocset->locTab[i]->index,
13446 rloc->locTab[j]->user2,
13447 rloc->locTab[j]->index2);
13448 if (range != NULL) {
13449 xmlXPtrLocationSetAdd(newlocset, range);
13450 }
13451 }
13452 } else {
13453 range = xmlXPtrNewRangeNodeObject(
13454 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13455 if (range != NULL) {
13456 xmlXPtrLocationSetAdd(newlocset,range);
13457 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013458 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013459
Daniel Veillardf06307e2001-07-03 10:35:50 +000013460 /*
13461 * Cleanup
13462 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013463 if (res != NULL) {
13464 xmlXPathReleaseObject(ctxt->context, res);
13465 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013466 if (ctxt->value == tmp) {
13467 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013468 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013469 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013470 }
William M. Brack72ee48d2003-12-30 08:30:19 +000013471 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000013472 CHECK_TYPE0(XPATH_NODESET);
13473 obj = valuePop(ctxt);
13474 oldset = obj->nodesetval;
William M. Brack08171912003-12-29 02:52:11 +000013475
13476 newlocset = xmlXPtrLocationSetCreate(NULL);
13477
13478 if (oldset != NULL) {
13479 for (i = 0; i < oldset->nodeNr; i++) {
13480 /*
13481 * Run the evaluation with a node list made of a single item
13482 * in the nodeset.
13483 */
13484 ctxt->context->node = oldset->nodeTab[i];
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013485 /*
13486 * OPTIMIZE TODO: Avoid recreation for every iteration.
13487 */
13488 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13489 ctxt->context->node);
William M. Brack08171912003-12-29 02:52:11 +000013490 valuePush(ctxt, tmp);
13491
13492 if (op->ch2 != -1)
13493 total +=
13494 xmlXPathCompOpEval(ctxt,
13495 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013496 if (ctxt->error != XPATH_EXPRESSION_OK) {
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013497 xmlXPtrFreeLocationSet(newlocset);
13498 goto rangeto_error;
William M. Brack2c19a7b2005-04-10 01:03:23 +000013499 }
William M. Brack08171912003-12-29 02:52:11 +000013500
William M. Brack08171912003-12-29 02:52:11 +000013501 res = valuePop(ctxt);
13502 range =
13503 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13504 res);
13505 if (range != NULL) {
13506 xmlXPtrLocationSetAdd(newlocset, range);
13507 }
13508
13509 /*
13510 * Cleanup
13511 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013512 if (res != NULL) {
13513 xmlXPathReleaseObject(ctxt->context, res);
13514 }
William M. Brack08171912003-12-29 02:52:11 +000013515 if (ctxt->value == tmp) {
13516 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013517 xmlXPathReleaseObject(ctxt->context, res);
William M. Brack08171912003-12-29 02:52:11 +000013518 }
William M. Brack08171912003-12-29 02:52:11 +000013519 }
13520 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013521 }
13522
13523 /*
13524 * The result is used as the new evaluation set.
13525 */
William M. Brack08171912003-12-29 02:52:11 +000013526 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013527rangeto_error:
13528 xmlXPathReleaseObject(ctxt->context, obj);
13529 ctxt->context->node = oldnode;
13530 ctxt->context->contextSize = oldcs;
13531 ctxt->context->proximityPosition = oldpp;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013532 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013533 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013534#endif /* LIBXML_XPTR_ENABLED */
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013535 default:
13536 xmlGenericError(xmlGenericErrorContext,
13537 "XPath: unknown precompiled operation %d\n", op->op);
13538 ctxt->error = XPATH_INVALID_OPERAND;
13539 break;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013540 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013541
13542 ctxt->context->depth -= 1;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013543 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013544}
13545
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013546/**
13547 * xmlXPathCompOpEvalToBoolean:
13548 * @ctxt: the XPath parser context
13549 *
13550 * Evaluates if the expression evaluates to true.
13551 *
13552 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13553 */
13554static int
13555xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013556 xmlXPathStepOpPtr op,
13557 int isPredicate)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013558{
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013559 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013560
13561start:
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013562 if (OP_LIMIT_EXCEEDED(ctxt, 1))
13563 return(0);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013564 /* comp = ctxt->comp; */
13565 switch (op->op) {
13566 case XPATH_OP_END:
13567 return (0);
13568 case XPATH_OP_VALUE:
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013569 resObj = (xmlXPathObjectPtr) op->value4;
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000013570 if (isPredicate)
13571 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13572 return(xmlXPathCastToBoolean(resObj));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013573 case XPATH_OP_SORT:
13574 /*
13575 * We don't need sorting for boolean results. Skip this one.
13576 */
13577 if (op->ch1 != -1) {
13578 op = &ctxt->comp->steps[op->ch1];
13579 goto start;
13580 }
13581 return(0);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013582 case XPATH_OP_COLLECT:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013583 if (op->ch1 == -1)
13584 return(0);
13585
13586 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13587 if (ctxt->error != XPATH_EXPRESSION_OK)
13588 return(-1);
13589
13590 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13591 if (ctxt->error != XPATH_EXPRESSION_OK)
13592 return(-1);
13593
13594 resObj = valuePop(ctxt);
13595 if (resObj == NULL)
13596 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013597 break;
13598 default:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013599 /*
13600 * Fallback to call xmlXPathCompOpEval().
13601 */
13602 xmlXPathCompOpEval(ctxt, op);
13603 if (ctxt->error != XPATH_EXPRESSION_OK)
13604 return(-1);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013605
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013606 resObj = valuePop(ctxt);
13607 if (resObj == NULL)
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000013608 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013609 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013610 }
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013611
13612 if (resObj) {
13613 int res;
13614
13615 if (resObj->type == XPATH_BOOLEAN) {
13616 res = resObj->boolval;
13617 } else if (isPredicate) {
13618 /*
13619 * For predicates a result of type "number" is handled
13620 * differently:
13621 * SPEC XPath 1.0:
13622 * "If the result is a number, the result will be converted
13623 * to true if the number is equal to the context position
13624 * and will be converted to false otherwise;"
13625 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000013626 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013627 } else {
13628 res = xmlXPathCastToBoolean(resObj);
13629 }
13630 xmlXPathReleaseObject(ctxt->context, resObj);
13631 return(res);
13632 }
13633
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013634 return(0);
13635}
13636
Daniel Veillard56de87e2005-02-16 00:22:29 +000013637#ifdef XPATH_STREAMING
13638/**
13639 * xmlXPathRunStreamEval:
13640 * @ctxt: the XPath parser context with the compiled expression
13641 *
13642 * Evaluate the Precompiled Streamable XPath expression in the given context.
13643 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013644static int
13645xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
13646 xmlXPathObjectPtr *resultSeq, int toBool)
13647{
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013648 int max_depth, min_depth;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013649 int from_root;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013650 int ret, depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013651 int eval_all_nodes;
William M. Brack12d37ab2005-02-21 13:54:07 +000013652 xmlNodePtr cur = NULL, limit = NULL;
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000013653 xmlStreamCtxtPtr patstream = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013654
13655 int nb_nodes = 0;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013656
13657 if ((ctxt == NULL) || (comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013658 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000013659 max_depth = xmlPatternMaxDepth(comp);
13660 if (max_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013661 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000013662 if (max_depth == -2)
13663 max_depth = 10000;
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013664 min_depth = xmlPatternMinDepth(comp);
13665 if (min_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013666 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000013667 from_root = xmlPatternFromRoot(comp);
13668 if (from_root < 0)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013669 return(-1);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000013670#if 0
13671 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
13672#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000013673
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013674 if (! toBool) {
13675 if (resultSeq == NULL)
13676 return(-1);
13677 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
13678 if (*resultSeq == NULL)
13679 return(-1);
13680 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000013681
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013682 /*
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000013683 * handle the special cases of "/" amd "." being matched
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013684 */
13685 if (min_depth == 0) {
13686 if (from_root) {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000013687 /* Select "/" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013688 if (toBool)
13689 return(1);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013690 /* TODO: Check memory error. */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013691 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013692 (xmlNodePtr) ctxt->doc);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013693 } else {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000013694 /* Select "self::node()" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013695 if (toBool)
13696 return(1);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013697 /* TODO: Check memory error. */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013698 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013699 }
13700 }
13701 if (max_depth == 0) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013702 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000013703 }
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013704
Daniel Veillard56de87e2005-02-16 00:22:29 +000013705 if (from_root) {
William M. Brack12d37ab2005-02-21 13:54:07 +000013706 cur = (xmlNodePtr)ctxt->doc;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013707 } else if (ctxt->node != NULL) {
13708 switch (ctxt->node->type) {
13709 case XML_ELEMENT_NODE:
13710 case XML_DOCUMENT_NODE:
13711 case XML_DOCUMENT_FRAG_NODE:
13712 case XML_HTML_DOCUMENT_NODE:
13713#ifdef LIBXML_DOCB_ENABLED
13714 case XML_DOCB_DOCUMENT_NODE:
13715#endif
13716 cur = ctxt->node;
13717 break;
13718 case XML_ATTRIBUTE_NODE:
13719 case XML_TEXT_NODE:
13720 case XML_CDATA_SECTION_NODE:
13721 case XML_ENTITY_REF_NODE:
13722 case XML_ENTITY_NODE:
13723 case XML_PI_NODE:
13724 case XML_COMMENT_NODE:
13725 case XML_NOTATION_NODE:
13726 case XML_DTD_NODE:
13727 case XML_DOCUMENT_TYPE_NODE:
13728 case XML_ELEMENT_DECL:
13729 case XML_ATTRIBUTE_DECL:
13730 case XML_ENTITY_DECL:
13731 case XML_NAMESPACE_DECL:
13732 case XML_XINCLUDE_START:
13733 case XML_XINCLUDE_END:
Daniel Veillard56de87e2005-02-16 00:22:29 +000013734 break;
13735 }
13736 limit = cur;
13737 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013738 if (cur == NULL) {
13739 return(0);
13740 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000013741
13742 patstream = xmlPatternGetStreamCtxt(comp);
13743 if (patstream == NULL) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013744 /*
13745 * QUESTION TODO: Is this an error?
13746 */
13747 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000013748 }
13749
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013750 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013751
Daniel Veillard56de87e2005-02-16 00:22:29 +000013752 if (from_root) {
13753 ret = xmlStreamPush(patstream, NULL, NULL);
13754 if (ret < 0) {
13755 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013756 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000013757 goto return_1;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013758 /* TODO: Check memory error. */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013759 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Daniel Veillard56de87e2005-02-16 00:22:29 +000013760 }
13761 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000013762 depth = 0;
13763 goto scan_children;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013764next_node:
Daniel Veillardd3ff7ef2006-02-27 19:43:17 +000013765 do {
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013766 if (ctxt->opLimit != 0) {
13767 if (ctxt->opCount >= ctxt->opLimit) {
13768 xmlGenericError(xmlGenericErrorContext,
13769 "XPath operation limit exceeded\n");
13770 xmlFreeStreamCtxt(patstream);
13771 return(-1);
13772 }
13773 ctxt->opCount++;
13774 }
13775
Daniel Veillard56de87e2005-02-16 00:22:29 +000013776 nb_nodes++;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013777
13778 switch (cur->type) {
13779 case XML_ELEMENT_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013780 case XML_TEXT_NODE:
13781 case XML_CDATA_SECTION_NODE:
13782 case XML_COMMENT_NODE:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013783 case XML_PI_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013784 if (cur->type == XML_ELEMENT_NODE) {
13785 ret = xmlStreamPush(patstream, cur->name,
Daniel Veillard56de87e2005-02-16 00:22:29 +000013786 (cur->ns ? cur->ns->href : NULL));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013787 } else if (eval_all_nodes)
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013788 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
13789 else
13790 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013791
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013792 if (ret < 0) {
13793 /* NOP. */
13794 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013795 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000013796 goto return_1;
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013797 if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
13798 < 0) {
13799 ctxt->lastError.domain = XML_FROM_XPATH;
13800 ctxt->lastError.code = XML_ERR_NO_MEMORY;
13801 }
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013802 }
13803 if ((cur->children == NULL) || (depth >= max_depth)) {
13804 ret = xmlStreamPop(patstream);
13805 while (cur->next != NULL) {
13806 cur = cur->next;
13807 if ((cur->type != XML_ENTITY_DECL) &&
13808 (cur->type != XML_DTD_NODE))
13809 goto next_node;
13810 }
13811 }
13812 default:
13813 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013814 }
13815
Daniel Veillard56de87e2005-02-16 00:22:29 +000013816scan_children:
Daniel Veillard3e62adb2012-08-09 14:24:02 +080013817 if (cur->type == XML_NAMESPACE_DECL) break;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013818 if ((cur->children != NULL) && (depth < max_depth)) {
13819 /*
Daniel Veillard45490ae2008-07-29 09:13:19 +000013820 * Do not descend on entities declarations
Daniel Veillard56de87e2005-02-16 00:22:29 +000013821 */
13822 if (cur->children->type != XML_ENTITY_DECL) {
13823 cur = cur->children;
13824 depth++;
13825 /*
13826 * Skip DTDs
13827 */
13828 if (cur->type != XML_DTD_NODE)
13829 continue;
13830 }
13831 }
13832
13833 if (cur == limit)
13834 break;
13835
13836 while (cur->next != NULL) {
13837 cur = cur->next;
13838 if ((cur->type != XML_ENTITY_DECL) &&
13839 (cur->type != XML_DTD_NODE))
13840 goto next_node;
13841 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000013842
Daniel Veillard56de87e2005-02-16 00:22:29 +000013843 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000013844 cur = cur->parent;
13845 depth--;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013846 if ((cur == NULL) || (cur == limit) ||
13847 (cur->type == XML_DOCUMENT_NODE))
Daniel Veillard56de87e2005-02-16 00:22:29 +000013848 goto done;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013849 if (cur->type == XML_ELEMENT_NODE) {
13850 ret = xmlStreamPop(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013851 } else if ((eval_all_nodes) &&
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013852 ((cur->type == XML_TEXT_NODE) ||
13853 (cur->type == XML_CDATA_SECTION_NODE) ||
13854 (cur->type == XML_COMMENT_NODE) ||
13855 (cur->type == XML_PI_NODE)))
13856 {
13857 ret = xmlStreamPop(patstream);
13858 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000013859 if (cur->next != NULL) {
13860 cur = cur->next;
13861 break;
13862 }
13863 } while (cur != NULL);
13864
13865 } while ((cur != NULL) && (depth >= 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013866
Daniel Veillard56de87e2005-02-16 00:22:29 +000013867done:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013868
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000013869#if 0
13870 printf("stream eval: checked %d nodes selected %d\n",
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013871 nb_nodes, retObj->nodesetval->nodeNr);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000013872#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013873
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000013874 if (patstream)
13875 xmlFreeStreamCtxt(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013876 return(0);
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000013877
13878return_1:
13879 if (patstream)
13880 xmlFreeStreamCtxt(patstream);
13881 return(1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000013882}
13883#endif /* XPATH_STREAMING */
13884
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013885/**
13886 * xmlXPathRunEval:
13887 * @ctxt: the XPath parser context with the compiled expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013888 * @toBool: evaluate to a boolean result
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013889 *
13890 * Evaluate the Precompiled XPath expression in the given context.
13891 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013892static int
13893xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
13894{
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013895 xmlXPathCompExprPtr comp;
13896
13897 if ((ctxt == NULL) || (ctxt->comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013898 return(-1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013899
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013900 ctxt->context->depth = 0;
13901
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013902 if (ctxt->valueTab == NULL) {
13903 /* Allocate the value stack */
Daniel Veillard45490ae2008-07-29 09:13:19 +000013904 ctxt->valueTab = (xmlXPathObjectPtr *)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013905 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
13906 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000013907 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013908 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013909 }
13910 ctxt->valueNr = 0;
13911 ctxt->valueMax = 10;
13912 ctxt->value = NULL;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013913 ctxt->valueFrame = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013914 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000013915#ifdef XPATH_STREAMING
13916 if (ctxt->comp->stream) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013917 int res;
13918
13919 if (toBool) {
13920 /*
13921 * Evaluation to boolean result.
13922 */
13923 res = xmlXPathRunStreamEval(ctxt->context,
13924 ctxt->comp->stream, NULL, 1);
13925 if (res != -1)
13926 return(res);
13927 } else {
Daniel Veillard45490ae2008-07-29 09:13:19 +000013928 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013929
13930 /*
13931 * Evaluation to a sequence.
13932 */
13933 res = xmlXPathRunStreamEval(ctxt->context,
13934 ctxt->comp->stream, &resObj, 0);
13935
13936 if ((res != -1) && (resObj != NULL)) {
13937 valuePush(ctxt, resObj);
13938 return(0);
13939 }
13940 if (resObj != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +000013941 xmlXPathReleaseObject(ctxt->context, resObj);
Daniel Veillard56de87e2005-02-16 00:22:29 +000013942 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013943 /*
13944 * QUESTION TODO: This falls back to normal XPath evaluation
13945 * if res == -1. Is this intended?
13946 */
Daniel Veillard56de87e2005-02-16 00:22:29 +000013947 }
13948#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013949 comp = ctxt->comp;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013950 if (comp->last < 0) {
Aleksey Sanin29b6f762002-05-05 06:59:57 +000013951 xmlGenericError(xmlGenericErrorContext,
13952 "xmlXPathRunEval: last is less than zero\n");
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013953 return(-1);
Aleksey Sanin29b6f762002-05-05 06:59:57 +000013954 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013955 if (toBool)
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013956 return(xmlXPathCompOpEvalToBoolean(ctxt,
13957 &comp->steps[comp->last], 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013958 else
13959 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
13960
13961 return(0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013962}
13963
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013964/************************************************************************
13965 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +000013966 * Public interfaces *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013967 * *
13968 ************************************************************************/
13969
13970/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000013971 * xmlXPathEvalPredicate:
13972 * @ctxt: the XPath context
13973 * @res: the Predicate Expression evaluation result
13974 *
13975 * Evaluate a predicate result for the current node.
13976 * A PredicateExpr is evaluated by evaluating the Expr and converting
13977 * the result to a boolean. If the result is a number, the result will
13978 * be converted to true if the number is equal to the position of the
13979 * context node in the context node list (as returned by the position
13980 * function) and will be converted to false otherwise; if the result
13981 * is not a number, then the result will be converted as if by a call
Daniel Veillard45490ae2008-07-29 09:13:19 +000013982 * to the boolean function.
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000013983 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013984 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000013985 */
13986int
13987xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000013988 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000013989 switch (res->type) {
13990 case XPATH_BOOLEAN:
13991 return(res->boolval);
13992 case XPATH_NUMBER:
13993 return(res->floatval == ctxt->proximityPosition);
13994 case XPATH_NODESET:
13995 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000013996 if (res->nodesetval == NULL)
13997 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000013998 return(res->nodesetval->nodeNr != 0);
13999 case XPATH_STRING:
14000 return((res->stringval != NULL) &&
14001 (xmlStrlen(res->stringval) != 0));
14002 default:
14003 STRANGE
14004 }
14005 return(0);
14006}
14007
14008/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014009 * xmlXPathEvaluatePredicateResult:
14010 * @ctxt: the XPath Parser context
14011 * @res: the Predicate Expression evaluation result
14012 *
14013 * Evaluate a predicate result for the current node.
14014 * A PredicateExpr is evaluated by evaluating the Expr and converting
14015 * the result to a boolean. If the result is a number, the result will
14016 * be converted to true if the number is equal to the position of the
14017 * context node in the context node list (as returned by the position
14018 * function) and will be converted to false otherwise; if the result
14019 * is not a number, then the result will be converted as if by a call
Daniel Veillard45490ae2008-07-29 09:13:19 +000014020 * to the boolean function.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014021 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014022 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014023 */
14024int
Daniel Veillard45490ae2008-07-29 09:13:19 +000014025xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014026 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014027 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014028 switch (res->type) {
14029 case XPATH_BOOLEAN:
14030 return(res->boolval);
14031 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000014032#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000014033 return((res->floatval == ctxt->context->proximityPosition) &&
14034 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000014035#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014036 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000014037#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014038 case XPATH_NODESET:
14039 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000014040 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000014041 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014042 return(res->nodesetval->nodeNr != 0);
14043 case XPATH_STRING:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014044 return((res->stringval != NULL) && (res->stringval[0] != 0));
William M. Brack08171912003-12-29 02:52:11 +000014045#ifdef LIBXML_XPTR_ENABLED
14046 case XPATH_LOCATIONSET:{
14047 xmlLocationSetPtr ptr = res->user;
14048 if (ptr == NULL)
14049 return(0);
14050 return (ptr->locNr != 0);
14051 }
14052#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014053 default:
14054 STRANGE
14055 }
14056 return(0);
14057}
14058
Daniel Veillard56de87e2005-02-16 00:22:29 +000014059#ifdef XPATH_STREAMING
14060/**
14061 * xmlXPathTryStreamCompile:
14062 * @ctxt: an XPath context
14063 * @str: the XPath expression
14064 *
14065 * Try to compile the XPath expression as a streamable subset.
14066 *
14067 * Returns the compiled expression or NULL if failed to compile.
14068 */
14069static xmlXPathCompExprPtr
14070xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14071 /*
14072 * Optimization: use streaming patterns when the XPath expression can
14073 * be compiled to a stream lookup
14074 */
14075 xmlPatternPtr stream;
14076 xmlXPathCompExprPtr comp;
14077 xmlDictPtr dict = NULL;
14078 const xmlChar **namespaces = NULL;
14079 xmlNsPtr ns;
14080 int i, j;
14081
14082 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14083 (!xmlStrchr(str, '@'))) {
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014084 const xmlChar *tmp;
14085
14086 /*
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014087 * We don't try to handle expressions using the verbose axis
Haibo Huangcfd91dc2020-07-30 23:01:33 -070014088 * specifiers ("::"), just the simplified form at this point.
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014089 * Additionally, if there is no list of namespaces available and
14090 * there's a ":" in the expression, indicating a prefixed QName,
14091 * then we won't try to compile either. xmlPatterncompile() needs
14092 * to have a list of namespaces at compilation time in order to
14093 * compile prefixed name tests.
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014094 */
14095 tmp = xmlStrchr(str, ':');
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014096 if ((tmp != NULL) &&
14097 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
Daniel Veillard45490ae2008-07-29 09:13:19 +000014098 return(NULL);
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014099
Daniel Veillard56de87e2005-02-16 00:22:29 +000014100 if (ctxt != NULL) {
14101 dict = ctxt->dict;
14102 if (ctxt->nsNr > 0) {
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000014103 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
Daniel Veillard56de87e2005-02-16 00:22:29 +000014104 if (namespaces == NULL) {
14105 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14106 return(NULL);
14107 }
14108 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14109 ns = ctxt->namespaces[j];
14110 namespaces[i++] = ns->href;
14111 namespaces[i++] = ns->prefix;
14112 }
14113 namespaces[i++] = NULL;
Daniel Veillard13cee4e2009-09-05 14:52:55 +020014114 namespaces[i] = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014115 }
14116 }
14117
Haibo Huangcfd91dc2020-07-30 23:01:33 -070014118 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces);
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014119 if (namespaces != NULL) {
14120 xmlFree((xmlChar **)namespaces);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014121 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014122 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14123 comp = xmlXPathNewCompExpr();
14124 if (comp == NULL) {
14125 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14126 return(NULL);
14127 }
14128 comp->stream = stream;
14129 comp->dict = dict;
14130 if (comp->dict)
14131 xmlDictReference(comp->dict);
14132 return(comp);
14133 }
14134 xmlFreePattern(stream);
14135 }
14136 return(NULL);
14137}
14138#endif /* XPATH_STREAMING */
14139
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014140static void
Haibo Huangcfd91dc2020-07-30 23:01:33 -070014141xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
14142 xmlXPathStepOpPtr op)
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014143{
Haibo Huangcfd91dc2020-07-30 23:01:33 -070014144 xmlXPathCompExprPtr comp = pctxt->comp;
14145 xmlXPathContextPtr ctxt;
14146
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014147 /*
14148 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14149 * internal representation.
14150 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014151
Nick Wellnhoferb4bcba22013-08-05 00:15:11 +020014152 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14153 (op->ch1 != -1) &&
14154 (op->ch2 == -1 /* no predicate */))
Nick Wellnhofer62270532012-08-19 19:42:38 +020014155 {
14156 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14157
14158 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14159 ((xmlXPathAxisVal) prevop->value ==
14160 AXIS_DESCENDANT_OR_SELF) &&
14161 (prevop->ch2 == -1) &&
14162 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14163 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14164 {
14165 /*
14166 * This is a "descendant-or-self::node()" without predicates.
14167 * Try to eliminate it.
14168 */
14169
14170 switch ((xmlXPathAxisVal) op->value) {
14171 case AXIS_CHILD:
14172 case AXIS_DESCENDANT:
14173 /*
14174 * Convert "descendant-or-self::node()/child::" or
14175 * "descendant-or-self::node()/descendant::" to
14176 * "descendant::"
14177 */
14178 op->ch1 = prevop->ch1;
14179 op->value = AXIS_DESCENDANT;
14180 break;
14181 case AXIS_SELF:
14182 case AXIS_DESCENDANT_OR_SELF:
14183 /*
14184 * Convert "descendant-or-self::node()/self::" or
14185 * "descendant-or-self::node()/descendant-or-self::" to
14186 * to "descendant-or-self::"
14187 */
14188 op->ch1 = prevop->ch1;
14189 op->value = AXIS_DESCENDANT_OR_SELF;
14190 break;
14191 default:
14192 break;
14193 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014194 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014195 }
Nick Wellnhofer62270532012-08-19 19:42:38 +020014196
Nick Wellnhofer839689a2016-04-27 18:00:12 +020014197 /* OP_VALUE has invalid ch1. */
14198 if (op->op == XPATH_OP_VALUE)
14199 return;
14200
Nick Wellnhofer62270532012-08-19 19:42:38 +020014201 /* Recurse */
Haibo Huangcfd91dc2020-07-30 23:01:33 -070014202 ctxt = pctxt->context;
14203 if (ctxt != NULL) {
Haibo Huangf0a546b2020-09-01 20:28:19 -070014204 if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
Haibo Huangcfd91dc2020-07-30 23:01:33 -070014205 return;
14206 ctxt->depth += 1;
14207 }
Nick Wellnhofer62270532012-08-19 19:42:38 +020014208 if (op->ch1 != -1)
Haibo Huangcfd91dc2020-07-30 23:01:33 -070014209 xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014210 if (op->ch2 != -1)
Haibo Huangcfd91dc2020-07-30 23:01:33 -070014211 xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
14212 if (ctxt != NULL)
14213 ctxt->depth -= 1;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014214}
14215
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014216/**
Daniel Veillard4773df22004-01-23 13:15:13 +000014217 * xmlXPathCtxtCompile:
14218 * @ctxt: an XPath context
14219 * @str: the XPath expression
14220 *
14221 * Compile an XPath expression
14222 *
14223 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14224 * the caller has to free the object.
14225 */
14226xmlXPathCompExprPtr
14227xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14228 xmlXPathParserContextPtr pctxt;
14229 xmlXPathCompExprPtr comp;
14230
Daniel Veillard56de87e2005-02-16 00:22:29 +000014231#ifdef XPATH_STREAMING
14232 comp = xmlXPathTryStreamCompile(ctxt, str);
14233 if (comp != NULL)
14234 return(comp);
14235#endif
14236
Daniel Veillard4773df22004-01-23 13:15:13 +000014237 xmlXPathInit();
14238
14239 pctxt = xmlXPathNewParserContext(str, ctxt);
William M. Brack11be2d02007-01-24 19:17:19 +000014240 if (pctxt == NULL)
14241 return NULL;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070014242 if (ctxt != NULL)
14243 ctxt->depth = 0;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014244 xmlXPathCompileExpr(pctxt, 1);
Daniel Veillard4773df22004-01-23 13:15:13 +000014245
14246 if( pctxt->error != XPATH_EXPRESSION_OK )
14247 {
14248 xmlXPathFreeParserContext(pctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000014249 return(NULL);
Daniel Veillard4773df22004-01-23 13:15:13 +000014250 }
14251
14252 if (*pctxt->cur != 0) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014253 /*
Daniel Veillard4773df22004-01-23 13:15:13 +000014254 * aleksey: in some cases this line prints *second* error message
14255 * (see bug #78858) and probably this should be fixed.
14256 * However, we are not sure that all error messages are printed
14257 * out in other places. It's not critical so we leave it as-is for now
14258 */
14259 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14260 comp = NULL;
14261 } else {
14262 comp = pctxt->comp;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070014263 if ((comp->nbStep > 1) && (comp->last >= 0)) {
14264 if (ctxt != NULL)
14265 ctxt->depth = 0;
14266 xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
14267 }
Daniel Veillard4773df22004-01-23 13:15:13 +000014268 pctxt->comp = NULL;
14269 }
14270 xmlXPathFreeParserContext(pctxt);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014271
Daniel Veillard4773df22004-01-23 13:15:13 +000014272 if (comp != NULL) {
14273 comp->expr = xmlStrdup(str);
14274#ifdef DEBUG_EVAL_COUNTS
14275 comp->string = xmlStrdup(str);
14276 comp->nb = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014277#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014278 }
Daniel Veillard4773df22004-01-23 13:15:13 +000014279 return(comp);
14280}
14281
14282/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014283 * xmlXPathCompile:
14284 * @str: the XPath expression
14285 *
14286 * Compile an XPath expression
14287 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000014288 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014289 * the caller has to free the object.
14290 */
14291xmlXPathCompExprPtr
14292xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000014293 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014294}
14295
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014296/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014297 * xmlXPathCompiledEvalInternal:
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014298 * @comp: the compiled XPath expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014299 * @ctxt: the XPath context
14300 * @resObj: the resulting XPath object or NULL
14301 * @toBool: 1 if only a boolean result is requested
Owen Taylor3473f882001-02-23 17:55:21 +000014302 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014303 * Evaluate the Precompiled XPath expression in the given context.
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014304 * The caller has to free @resObj.
Owen Taylor3473f882001-02-23 17:55:21 +000014305 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014306 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000014307 * the caller has to free the object.
14308 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014309static int
14310xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14311 xmlXPathContextPtr ctxt,
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014312 xmlXPathObjectPtr *resObjPtr,
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014313 int toBool)
14314{
Daniel Veillard45490ae2008-07-29 09:13:19 +000014315 xmlXPathParserContextPtr pctxt;
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014316 xmlXPathObjectPtr resObj;
Daniel Veillard81463942001-10-16 12:34:39 +000014317#ifndef LIBXML_THREAD_ENABLED
14318 static int reentance = 0;
14319#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014320 int res;
Owen Taylor3473f882001-02-23 17:55:21 +000014321
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014322 CHECK_CTXT_NEG(ctxt)
William M. Brackf13f77f2004-11-12 16:03:48 +000014323
14324 if (comp == NULL)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014325 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +000014326 xmlXPathInit();
14327
Daniel Veillard81463942001-10-16 12:34:39 +000014328#ifndef LIBXML_THREAD_ENABLED
14329 reentance++;
14330 if (reentance > 1)
14331 xmlXPathDisableOptimizer = 1;
14332#endif
14333
Daniel Veillardf06307e2001-07-03 10:35:50 +000014334#ifdef DEBUG_EVAL_COUNTS
14335 comp->nb++;
14336 if ((comp->string != NULL) && (comp->nb > 100)) {
14337 fprintf(stderr, "100 x %s\n", comp->string);
14338 comp->nb = 0;
14339 }
14340#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014341 pctxt = xmlXPathCompParserContext(comp, ctxt);
14342 res = xmlXPathRunEval(pctxt, toBool);
Owen Taylor3473f882001-02-23 17:55:21 +000014343
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014344 if (pctxt->error != XPATH_EXPRESSION_OK) {
14345 resObj = NULL;
14346 } else {
14347 resObj = valuePop(pctxt);
14348 if (resObj == NULL) {
Nick Wellnhofera07a4e92017-05-27 17:04:12 +020014349 if (!toBool)
14350 xmlGenericError(xmlGenericErrorContext,
14351 "xmlXPathCompiledEval: No result on the stack.\n");
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014352 } else if (pctxt->valueNr > 0) {
14353 xmlGenericError(xmlGenericErrorContext,
14354 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14355 pctxt->valueNr);
14356 }
Owen Taylor3473f882001-02-23 17:55:21 +000014357 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014358
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014359 if (resObjPtr)
14360 *resObjPtr = resObj;
14361 else
14362 xmlXPathReleaseObject(ctxt, resObj);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014363
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014364 pctxt->comp = NULL;
14365 xmlXPathFreeParserContext(pctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000014366#ifndef LIBXML_THREAD_ENABLED
14367 reentance--;
14368#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014369
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014370 return(res);
14371}
14372
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014373/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014374 * xmlXPathCompiledEval:
14375 * @comp: the compiled XPath expression
14376 * @ctx: the XPath context
14377 *
14378 * Evaluate the Precompiled XPath expression in the given context.
14379 *
14380 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14381 * the caller has to free the object.
14382 */
14383xmlXPathObjectPtr
14384xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14385{
14386 xmlXPathObjectPtr res = NULL;
14387
14388 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14389 return(res);
14390}
14391
14392/**
14393 * xmlXPathCompiledEvalToBoolean:
14394 * @comp: the compiled XPath expression
14395 * @ctxt: the XPath context
14396 *
14397 * Applies the XPath boolean() function on the result of the given
14398 * compiled expression.
14399 *
14400 * Returns 1 if the expression evaluated to true, 0 if to false and
14401 * -1 in API and internal errors.
14402 */
14403int
14404xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14405 xmlXPathContextPtr ctxt)
14406{
14407 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14408}
14409
14410/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014411 * xmlXPathEvalExpr:
14412 * @ctxt: the XPath Parser context
14413 *
14414 * Parse and evaluate an XPath expression in the given context,
14415 * then push the result on the context stack
14416 */
14417void
14418xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014419#ifdef XPATH_STREAMING
14420 xmlXPathCompExprPtr comp;
14421#endif
14422
Daniel Veillarda82b1822004-11-08 16:24:57 +000014423 if (ctxt == NULL) return;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014424
Daniel Veillard56de87e2005-02-16 00:22:29 +000014425#ifdef XPATH_STREAMING
14426 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14427 if (comp != NULL) {
14428 if (ctxt->comp != NULL)
14429 xmlXPathFreeCompExpr(ctxt->comp);
14430 ctxt->comp = comp;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014431 } else
14432#endif
14433 {
Haibo Huangcfd91dc2020-07-30 23:01:33 -070014434 if (ctxt->context != NULL)
14435 ctxt->context->depth = 0;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014436 xmlXPathCompileExpr(ctxt, 1);
Nick Wellnhoferaed407c2017-05-25 16:57:14 +020014437 CHECK_ERROR;
14438
14439 /* Check for trailing characters. */
14440 if (*ctxt->cur != 0)
14441 XP_ERROR(XPATH_EXPR_ERROR);
14442
Haibo Huangcfd91dc2020-07-30 23:01:33 -070014443 if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
14444 if (ctxt->context != NULL)
14445 ctxt->context->depth = 0;
14446 xmlXPathOptimizeExpression(ctxt,
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014447 &ctxt->comp->steps[ctxt->comp->last]);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070014448 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014449 }
Nick Wellnhoferaed407c2017-05-25 16:57:14 +020014450
Daniel Veillard45490ae2008-07-29 09:13:19 +000014451 xmlXPathRunEval(ctxt, 0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014452}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014453
14454/**
14455 * xmlXPathEval:
14456 * @str: the XPath expression
14457 * @ctx: the XPath context
14458 *
14459 * Evaluate the XPath Location Path in the given context.
14460 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014461 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014462 * the caller has to free the object.
14463 */
14464xmlXPathObjectPtr
14465xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14466 xmlXPathParserContextPtr ctxt;
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014467 xmlXPathObjectPtr res;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014468
William M. Brackf13f77f2004-11-12 16:03:48 +000014469 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014470
William M. Brackf13f77f2004-11-12 16:03:48 +000014471 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014472
14473 ctxt = xmlXPathNewParserContext(str, ctx);
William M. Brack11be2d02007-01-24 19:17:19 +000014474 if (ctxt == NULL)
14475 return NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014476 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014477
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014478 if (ctxt->error != XPATH_EXPRESSION_OK) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014479 res = NULL;
14480 } else {
14481 res = valuePop(ctxt);
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014482 if (res == NULL) {
14483 xmlGenericError(xmlGenericErrorContext,
14484 "xmlXPathCompiledEval: No result on the stack.\n");
14485 } else if (ctxt->valueNr > 0) {
14486 xmlGenericError(xmlGenericErrorContext,
14487 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14488 ctxt->valueNr);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014489 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014490 }
14491
Owen Taylor3473f882001-02-23 17:55:21 +000014492 xmlXPathFreeParserContext(ctxt);
14493 return(res);
14494}
14495
14496/**
Alex Bligh28876af2013-03-23 17:23:27 +000014497 * xmlXPathSetContextNode:
14498 * @node: the node to to use as the context node
14499 * @ctx: the XPath context
14500 *
14501 * Sets 'node' as the context node. The node must be in the same
14502 * document as that associated with the context.
14503 *
14504 * Returns -1 in case of error or 0 if successful
14505 */
14506int
14507xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
14508 if ((node == NULL) || (ctx == NULL))
14509 return(-1);
14510
14511 if (node->doc == ctx->doc) {
14512 ctx->node = node;
14513 return(0);
14514 }
14515 return(-1);
14516}
14517
14518/**
14519 * xmlXPathNodeEval:
14520 * @node: the node to to use as the context node
14521 * @str: the XPath expression
14522 * @ctx: the XPath context
14523 *
14524 * Evaluate the XPath Location Path in the given context. The node 'node'
14525 * is set as the context node. The context node is not restored.
14526 *
14527 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14528 * the caller has to free the object.
14529 */
14530xmlXPathObjectPtr
14531xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
14532 if (str == NULL)
14533 return(NULL);
14534 if (xmlXPathSetContextNode(node, ctx) < 0)
14535 return(NULL);
14536 return(xmlXPathEval(str, ctx));
14537}
14538
14539/**
Owen Taylor3473f882001-02-23 17:55:21 +000014540 * xmlXPathEvalExpression:
14541 * @str: the XPath expression
14542 * @ctxt: the XPath context
14543 *
Daniel Veillarddbb828f2017-08-28 20:38:53 +020014544 * Alias for xmlXPathEval().
Owen Taylor3473f882001-02-23 17:55:21 +000014545 *
14546 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14547 * the caller has to free the object.
14548 */
14549xmlXPathObjectPtr
14550xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
Nick Wellnhofer640a3682017-05-27 14:59:49 +020014551 return(xmlXPathEval(str, ctxt));
Owen Taylor3473f882001-02-23 17:55:21 +000014552}
14553
Daniel Veillard42766c02002-08-22 20:52:17 +000014554/************************************************************************
14555 * *
14556 * Extra functions not pertaining to the XPath spec *
14557 * *
14558 ************************************************************************/
14559/**
14560 * xmlXPathEscapeUriFunction:
14561 * @ctxt: the XPath Parser context
14562 * @nargs: the number of arguments
14563 *
14564 * Implement the escape-uri() XPath function
14565 * string escape-uri(string $str, bool $escape-reserved)
14566 *
14567 * This function applies the URI escaping rules defined in section 2 of [RFC
14568 * 2396] to the string supplied as $uri-part, which typically represents all
14569 * or part of a URI. The effect of the function is to replace any special
14570 * character in the string by an escape sequence of the form %xx%yy...,
14571 * where xxyy... is the hexadecimal representation of the octets used to
14572 * represent the character in UTF-8.
14573 *
14574 * The set of characters that are escaped depends on the setting of the
14575 * boolean argument $escape-reserved.
14576 *
14577 * If $escape-reserved is true, all characters are escaped other than lower
14578 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14579 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14580 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14581 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14582 * A-F).
14583 *
14584 * If $escape-reserved is false, the behavior differs in that characters
14585 * referred to in [RFC 2396] as reserved characters are not escaped. These
14586 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
Daniel Veillard45490ae2008-07-29 09:13:19 +000014587 *
Daniel Veillard42766c02002-08-22 20:52:17 +000014588 * [RFC 2396] does not define whether escaped URIs should use lower case or
14589 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14590 * compared using string comparison functions, this function must always use
14591 * the upper-case letters A-F.
Daniel Veillard45490ae2008-07-29 09:13:19 +000014592 *
Daniel Veillard42766c02002-08-22 20:52:17 +000014593 * Generally, $escape-reserved should be set to true when escaping a string
14594 * that is to form a single part of a URI, and to false when escaping an
14595 * entire URI or URI reference.
Daniel Veillard45490ae2008-07-29 09:13:19 +000014596 *
14597 * In the case of non-ascii characters, the string is encoded according to
Daniel Veillard42766c02002-08-22 20:52:17 +000014598 * utf-8 and then converted according to RFC 2396.
14599 *
14600 * Examples
Daniel Veillard45490ae2008-07-29 09:13:19 +000014601 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
Daniel Veillard42766c02002-08-22 20:52:17 +000014602 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14603 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14604 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14605 *
14606 */
Daniel Veillard118aed72002-09-24 14:13:13 +000014607static void
Daniel Veillard42766c02002-08-22 20:52:17 +000014608xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14609 xmlXPathObjectPtr str;
14610 int escape_reserved;
Daniel Veillardade10f22012-07-12 09:43:27 +080014611 xmlBufPtr target;
Daniel Veillard42766c02002-08-22 20:52:17 +000014612 xmlChar *cptr;
14613 xmlChar escape[4];
Daniel Veillard45490ae2008-07-29 09:13:19 +000014614
Daniel Veillard42766c02002-08-22 20:52:17 +000014615 CHECK_ARITY(2);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014616
Daniel Veillard42766c02002-08-22 20:52:17 +000014617 escape_reserved = xmlXPathPopBoolean(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014618
Daniel Veillard42766c02002-08-22 20:52:17 +000014619 CAST_TO_STRING;
14620 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014621
Daniel Veillardade10f22012-07-12 09:43:27 +080014622 target = xmlBufCreate();
Daniel Veillard45490ae2008-07-29 09:13:19 +000014623
Daniel Veillard42766c02002-08-22 20:52:17 +000014624 escape[0] = '%';
14625 escape[3] = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014626
Daniel Veillard42766c02002-08-22 20:52:17 +000014627 if (target) {
14628 for (cptr = str->stringval; *cptr; cptr++) {
14629 if ((*cptr >= 'A' && *cptr <= 'Z') ||
14630 (*cptr >= 'a' && *cptr <= 'z') ||
14631 (*cptr >= '0' && *cptr <= '9') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000014632 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
Daniel Veillard42766c02002-08-22 20:52:17 +000014633 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
14634 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000014635 (*cptr == '%' &&
Daniel Veillard42766c02002-08-22 20:52:17 +000014636 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14637 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14638 (cptr[1] >= '0' && cptr[1] <= '9')) &&
14639 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14640 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14641 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14642 (!escape_reserved &&
14643 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
14644 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
14645 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
14646 *cptr == ','))) {
Daniel Veillardade10f22012-07-12 09:43:27 +080014647 xmlBufAdd(target, cptr, 1);
Daniel Veillard42766c02002-08-22 20:52:17 +000014648 } else {
14649 if ((*cptr >> 4) < 10)
14650 escape[1] = '0' + (*cptr >> 4);
14651 else
14652 escape[1] = 'A' - 10 + (*cptr >> 4);
14653 if ((*cptr & 0xF) < 10)
14654 escape[2] = '0' + (*cptr & 0xF);
14655 else
14656 escape[2] = 'A' - 10 + (*cptr & 0xF);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014657
Daniel Veillardade10f22012-07-12 09:43:27 +080014658 xmlBufAdd(target, &escape[0], 3);
Daniel Veillard42766c02002-08-22 20:52:17 +000014659 }
14660 }
14661 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014662 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +080014663 xmlBufContent(target)));
14664 xmlBufFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014665 xmlXPathReleaseObject(ctxt->context, str);
Daniel Veillard42766c02002-08-22 20:52:17 +000014666}
14667
Owen Taylor3473f882001-02-23 17:55:21 +000014668/**
14669 * xmlXPathRegisterAllFunctions:
14670 * @ctxt: the XPath context
14671 *
14672 * Registers all default XPath functions in this context
14673 */
14674void
14675xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
14676{
14677 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
14678 xmlXPathBooleanFunction);
14679 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
14680 xmlXPathCeilingFunction);
14681 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
14682 xmlXPathCountFunction);
14683 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
14684 xmlXPathConcatFunction);
14685 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
14686 xmlXPathContainsFunction);
14687 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
14688 xmlXPathIdFunction);
14689 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
14690 xmlXPathFalseFunction);
14691 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
14692 xmlXPathFloorFunction);
14693 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
14694 xmlXPathLastFunction);
14695 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
14696 xmlXPathLangFunction);
14697 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
14698 xmlXPathLocalNameFunction);
14699 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
14700 xmlXPathNotFunction);
14701 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
14702 xmlXPathNameFunction);
14703 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
14704 xmlXPathNamespaceURIFunction);
14705 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
14706 xmlXPathNormalizeFunction);
14707 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
14708 xmlXPathNumberFunction);
14709 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
14710 xmlXPathPositionFunction);
14711 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
14712 xmlXPathRoundFunction);
14713 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
14714 xmlXPathStringFunction);
14715 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
14716 xmlXPathStringLengthFunction);
14717 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
14718 xmlXPathStartsWithFunction);
14719 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
14720 xmlXPathSubstringFunction);
14721 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
14722 xmlXPathSubstringBeforeFunction);
14723 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
14724 xmlXPathSubstringAfterFunction);
14725 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
14726 xmlXPathSumFunction);
14727 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
14728 xmlXPathTrueFunction);
14729 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
14730 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000014731
14732 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
14733 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
14734 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000014735}
14736
14737#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +000014738#define bottom_xpath
14739#include "elfgcchack.h"